776753f3 by lxs

新增数据定价

1 parent 812d6345
1 import request from "@/utils/request";
2
3 //获取需求表树形列表
4 export const getDemandTreeList = (params) => {
5 return request({
6 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-menu/page-list`,
7 method: "post",
8 data: params,
9 });
10 };
11
12 //获取所有需求表列表
13 export const getDemandAll = (params) => {
14 return request({
15 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-menu/get-list-data`,
16 method: "get",
17 params
18 });
19 };
20
21 //新增需求列表
22 export const saveDemandTree = (params) => {
23 return request({
24 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-menu/save`,
25 method: "post",
26 data: params,
27 });
28 };
29
30 //修改需求列表
31 export const updateDemandTree = (params) => {
32 return request({
33 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-menu/update`,
34 method: "post",
35 data: params,
36 });
37 };
38
39 // 删除需求列表
40 export const deleteDemandTree = (params) => {
41 return request({
42 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-menu/delete`,
43 method: "delete",
44 data: params,
45 });
46 };
47
48 //获取需求表
49 export const getDemandList = (params) => {
50 return request({
51 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-table/page-list`,
52 method: "post",
53 data: params,
54 });
55 };
56
57 //获取需求表详情
58 export const getDemandDetail = (params) => {
59 return request({
60 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-table/detail`,
61 method: "get",
62 params,
63 });
64 };
65
66 //新增需求表
67 export const saveDemand = (params) => {
68 return request({
69 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-table/save`,
70 method: "post",
71 data: params,
72 });
73 };
74
75 //修改需求表
76 export const updateDemand = (params) => {
77 return request({
78 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-table/update`,
79 method: "post",
80 data: params,
81 });
82 };
83
84 // 删除需求表
85 export const deleteDemand = (params) => {
86 return request({
87 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-demand-table/delete`,
88 method: "delete",
89 data: params,
90 });
91 };
92
93 // 获取疾病列表
94 export const getDiseaseList = (params) => {
95 return request({
96 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/disease-manage/page-list`,
97 method: "post",
98 data: params,
99 });
100 };
101
102 //获取所有疾病列表
103 export const getDiseaseAll = () => {
104 return request({
105 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/disease-manage/get-list-data`,
106 method: "post"
107 });
108 };
109
110 // 获取疾病详情
111 export const getDiseaseDetail = (params) => {
112 return request({
113 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/disease-manage/detail`,
114 method: "get",
115 params,
116 });
117 };
118
119 // 新增疾病
120 export const saveDisease = (params) => {
121 return request({
122 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/disease-manage/save`,
123 method: "post",
124 data: params,
125 });
126 };
127
128 // 修改疾病
129 export const updateDisease = (params) => {
130 return request({
131 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/disease-manage/update`,
132 method: "post",
133 data: params,
134 });
135 };
136
137 // 删除疾病
138 export const deleteDisease = (params) => {
139 return request({
140 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/disease-manage/delete`,
141 method: "delete",
142 data: params,
143 });
144 };
145
146 // 获取定价配置
147 export const getConfigureList = (params) => {
148 return request({
149 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-configure/page-list`,
150 method: "post",
151 data: params,
152 });
153 };
154
155 // 获取配置详情
156 export const getConfigureDetail = (params) => {
157 return request({
158 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-configure/detail`,
159 method: "get",
160 params,
161 });
162 };
163
164 // 新增配置
165 export const saveConfigure = (params) => {
166 return request({
167 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-configure/save`,
168 method: "post",
169 data: params,
170 });
171 };
172
173 // 修改配置
174 export const updateConfigure = (params) => {
175 return request({
176 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-configure/update`,
177 method: "post",
178 data: params,
179 });
180 };
181
182 // 删除配置
183 export const deleteConfigure = (params) => {
184 return request({
185 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-configure/delete`,
186 method: "delete",
187 data: params,
188 });
189 };
190
191 // 获取数据定价
192 export const getPriceList = (params) => {
193 return request({
194 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/page-list`,
195 method: "post",
196 data: params,
197 });
198 };
199
200 // 获取数据定价详情
201 export const getPriceDetail = (params) => {
202 return request({
203 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/detail`,
204 method: "get",
205 params,
206 });
207 };
208
209 // 新增数据定价
210 export const savePrice = (params) => {
211 return request({
212 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/save`,
213 method: "post",
214 data: params,
215 });
216 };
217
218 // 修改数据定价
219 export const updatePrice = (params) => {
220 return request({
221 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/update`,
222 method: "post",
223 data: params,
224 });
225 };
226
227 // 获取数据定价结果
228 export const getPriceResult = (params) => {
229 return request({
230 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/pricing-price`,
231 method: "post",
232 data: params,
233 });
234 };
235
236 // 删除数据定价
237 export const deletePrice = (params) => {
238 return request({
239 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/delete`,
240 method: "delete",
241 data: params,
242 });
243 };
244
245 // 获取数据资源目录
246 export const getDamCatalogList = (params) => {
247 return request({
248 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/dam-catalog-grounding/not-exclude-overview-page-list`,
249 method: "post",
250 data: params,
251 });
252 };
253
254 // 获取模型相关需求表
255 export const getModelDemand = (params) => {
256 return request({
257 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/pricing-model`,
258 method: "get",
259 params,
260 });
261 };
262
263 // 获取质量模型评分
264 export const getModelScore = (params) => {
265 return request({
266 url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/get-quality-score-by-dam-guid`,
267 method: "get",
268 params,
269 });
270 };
271
272 export const exportModelScore = (params) => {
273 return request({
274 url: `${import.meta.env.VITE_APP_PROCESS_BASIC_URL}/pricing-data/download-template`,
275 method: "post",
276 data: params,
277 responseType: 'blob'
278 });
279 };
1 import type { RouteRecordRaw } from 'vue-router'
2
3 function Layout() {
4 return import('@/layouts/index.vue')
5 }
6
7 const routes: RouteRecordRaw[] = [
8 {
9 path: '/data-pricing/pricing-manage',
10 component: Layout,
11 meta: {
12 title: '定价管理',
13 icon: 'ep:grid',
14 },
15 children: [
16 {
17 path: 'demand-manage',
18 name: 'demandManage',
19 component: () => import('@/views/data_pricing/demandManage.vue'),
20 meta: {
21 title: '需求表管理',
22 breadcrumb: false,
23 cache: true
24 },
25 },
26 {
27 path: 'import-file-demand-manage',
28 name: 'importFileDemandManage',
29 component: () => import('@/views/importFile.vue'),
30 meta: {
31 title: '导入数据-需求表管理',
32 sidebar: false,
33 breadcrumb: false,
34 cache: true,
35 reuse: true,
36 activeMenu: '/data-pricing/pricing-manage/demand-manage'
37 }
38 },
39 {
40 path: 'disease-manage',
41 name: 'diseaseManage',
42 component: () => import('@/views/data_pricing/diseaseManage.vue'),
43 meta: {
44 title: '疾病管理',
45 breadcrumb: false,
46 cache: true
47 },
48 },
49 {
50 path: 'import-file-disease',
51 name: 'importFileDisease',
52 component: () => import('@/views/importFile.vue'),
53 meta: {
54 title: '导入数据-疾病管理',
55 sidebar: false,
56 breadcrumb: false,
57 cache: true,
58 reuse: true,
59 activeMenu: '/data-pricing/pricing-manage/disease-manage'
60 }
61 },
62 {
63 path: 'price-config',
64 name: 'priceConfig',
65 component: () => import('@/views/data_pricing/priceConfig.vue'),
66 meta: {
67 title: '定价配置',
68 breadcrumb: false,
69 cache: true
70 },
71 },
72 {
73 path: 'price-model',
74 name: 'priceModel',
75 component: () => import('@/views/data_pricing/priceModel.vue'),
76 meta: {
77 title: '新增配置',
78 sidebar: false,
79 breadcrumb: false,
80 cache: true,
81 reuse: true,
82 editPage: true,
83 activeMenu: '/data-pricing/pricing-manage/price-config'
84 },
85 beforeEnter: (to, from) => {
86 if (to.query.guid) {
87 to.meta.title = `编辑-${to.query.name}`;
88 } else {
89 to.meta.title = `新增配置`;
90 }
91 }
92 },
93 {
94 path: 'price-calculate',
95 name: 'priceCalculate',
96 component: () => import('@/views/data_pricing/priceCalculate.vue'),
97 meta: {
98 title: '数据定价',
99 breadcrumb: false,
100 cache: true
101 }
102 },
103 {
104 path: 'calculate-config',
105 name: 'calculateConfig',
106 component: () => import('@/views/data_pricing/calculateConfig.vue'),
107 meta: {
108 title: '新增数据定价',
109 sidebar: false,
110 breadcrumb: false,
111 cache: true,
112 reuse: true,
113 editPage: true,
114 activeMenu: '/data-pricing/pricing-manage/price-calculate'
115 },
116 beforeEnter: (to, from) => {
117 if (to.query.guid) {
118 to.meta.title = `编辑-${to.query.name}`;
119 } else {
120 to.meta.title = `新增数据定价`;
121 }
122 }
123 },
124 ],
125 },
126 ]
127
128 export default routes
...@@ -10,6 +10,7 @@ import DataTrustedSpace from './modules/dataTrustedSpace'; ...@@ -10,6 +10,7 @@ import DataTrustedSpace from './modules/dataTrustedSpace';
10 import DataAssetRegistry from './modules/dataAssetRegistry'; 10 import DataAssetRegistry from './modules/dataAssetRegistry';
11 import DataEntry from './modules/dataEntry'; 11 import DataEntry from './modules/dataEntry';
12 import SecurityMenu from './modules/securityMenu'; 12 import SecurityMenu from './modules/securityMenu';
13 import DataPricing from './modules/dataPricing';
13 14
14 import useSettingsStore from '@/store/modules/settings' 15 import useSettingsStore from '@/store/modules/settings'
15 16
...@@ -112,7 +113,8 @@ const asyncRoutes: RouteRecordRaw[] = [ ...@@ -112,7 +113,8 @@ const asyncRoutes: RouteRecordRaw[] = [
112 ...DataMeta, 113 ...DataMeta,
113 ...DataQuality, 114 ...DataQuality,
114 ...DataInventory, 115 ...DataInventory,
115 ...DataTrustedSpace 116 ...DataTrustedSpace,
117 ...DataPricing
116 ] 118 ]
117 119
118 const constantRoutesByFilesystem = generatedRoutes.filter((item) => { 120 const constantRoutesByFilesystem = generatedRoutes.filter((item) => {
......
1 <route lang="yaml">
2 name: calculateConfig
3 </route>
4 <script lang="ts" setup name="calculateConfig">
5 import { ref, onMounted } from "vue";
6 import { useRouter, useRoute } from "vue-router";
7 import { ElMessage, ElMessageBox } from "element-plus";
8 import useUserStore from "@/store/modules/user";
9 import useDataAssetStore from "@/store/modules/dataResource";
10 import { getAllFlowData } from '@/api/modules/configService';
11 import { getDamCatalogList } from "@/api/modules/dataPricing";
12 import { getRegisterCatalogDetail, getDataResourceUpSummaryList, getRegisterCatalogTableDetail } from "@/api/modules/dataResourceUpService";
13 import { download } from '@/utils/common'
14 import {
15 getConfigureList,
16 getConfigureDetail,
17 getDiseaseAll,
18 getPriceDetail,
19 getDemandList,
20 getModelScore,
21 savePrice,
22 getModelDemand,
23 getPriceResult,
24 exportModelScore
25 } from '@/api/modules/dataPricing';
26 import { changeNum } from "@/utils/common";
27 import { merge } from 'lodash-es';
28
29 const { proxy } = getCurrentInstance() as any;
30 const router = useRouter();
31 const route = useRoute();
32 const userStore = useUserStore();
33 const assetStore = useDataAssetStore();
34 const fullPath = route.fullPath;
35 const userData = JSON.parse(localStorage.userData);
36 const guid = route.query.guid;
37 const priceName = route.query.name;
38 const loading = ref(false);
39 const flowDetail: any = ref({});
40 const typeMap: any = ref({});
41 const expand1 = ref(true)
42 const expand2 = ref(true)
43 const expand3 = ref(true)
44 const demandTableList: any = ref([]);
45 const pricingTargetList: any = ref([]);
46 const demandTableFieldAllNum = ref(0);
47 const resourceTableAllNum = ref(0);
48 const resourceTableFieldAllNum = ref(0);
49 const modelData: any = ref({});
50 const pricingDimensionalityData: any = ref([]);
51 const dictionaryData: any = ref([]);
52 const diseaseData: any = ref([]);
53 const qualityScoreData: any = ref({});
54 const disScore: any = ref([]);
55 const exportData: any = ref([]);
56 const dataUsage = ref('');
57 // 基础设置
58 const baseConfigFormRef = ref();
59 const baseConfigFormItems: any = ref([
60 {
61 label: '模型名称',
62 type: 'select',
63 placeholder: '请选择',
64 field: 'modelGuid',
65 default: '',
66 options: [],
67 props: {
68 label: "modelName",
69 value: "guid",
70 },
71 clearable: true,
72 filterable: true,
73 required: true
74 },
75 {
76 label: '数据资源',
77 type: 'select',
78 placeholder: '请选择',
79 field: 'dataResourceGuid',
80 default: '',
81 options: [],
82 props: {
83 label: "damName",
84 value: "damGuid",
85 },
86 clearable: true,
87 filterable: true,
88 required: true,
89 },
90 {
91 label: '所属主体',
92 type: 'input',
93 placeholder: '',
94 field: 'belongingEntityGuid',
95 default: '',
96 options: [],
97 clearable: true,
98 disabled: true
99 },
100 {
101 label: '所属主题',
102 type: 'tree-select',
103 placeholder: '请选择',
104 field: 'belongingTheme',
105 default: '',
106 options: [],
107 showAllLevels: false,
108 checkStrictly: false,//只能选择叶子节点。
109 lazy: false,
110 props: {
111 label: "label",
112 value: "value",
113 children: 'childDictList'
114 },
115 filterable: true,
116 clearable: true,
117 disabled: true
118 },
119 ])
120 const baseConfigFormRules: any = ref({
121 modelGuid: [
122 { required: true, trigger: 'change', message: "请选择模型名称" }
123 ],
124 dataResourceGuid: [
125 { required: true, trigger: 'change', message: "请选择数据资源" }
126 ],
127 });
128 const baseConfigForm = ref({
129 items: baseConfigFormItems.value,
130 rules: baseConfigFormRules.value,
131 })
132 const tableFields: any = ref([
133 { label: '需求表', field: 'demandTableName', type: 'input', width: 200, disabled: true },
134 { label: '数据资源表', field: 'dataTableGuid', type: 'select', width: 200 },
135 { label: '表描述', field: 'tableDescription', type: 'input', width: 200, disabled: true },
136 { label: '需求表权重(%)', field: 'weightDemandTable', type: 'input', width: 140, disabled: true },
137 ])
138 const expendTableRef = ref();
139 const tableData: any = ref([]);
140 const tableLoading = ref(false);
141 const dataTransactionPrice: any = ref('');
142 const setFormItems = (info = null) => {
143 let datas: any = info || flowDetail.value || {};
144 const dData = datas.dictionaryJson ? JSON.parse(datas.dictionaryJson) : {};
145 datas = { ...datas, ...dData };
146 baseConfigFormItems.value.map(item => {
147 item.default = datas[item.field] || '';
148 })
149 nextTick(() => {
150 baseConfigFormRef.value.ruleFormRef?.clearValidate();
151 })
152 }
153 /**
154 * 传入多个promise对象,当全部结束时取消Loading
155 * @param promises 传入多个promise对象,当全部结束时取消Loading
156 */
157 const promiseList = (...promises: Promise<void>[]) => {
158 // loading方法全局封装成一个组件
159 !guid && (loading.value = true);
160 try {
161 Promise.all(promises).then(res => {
162 loading.value = false;
163 });
164 } catch (e) {
165 loading.value = false;
166 } finally {
167 !guid && (loading.value = false);
168 }
169 };
170 // 获取模型
171 const getModel = () => {
172 getConfigureList({ pageSize: -1, pageIndex: 1, bizState: 'Y' }).then((res: any) => {
173 if (res.code == proxy.$passCode) {
174 const data = res.data.records || [];
175 typeMap.value.modelGuid = JSON.parse(JSON.stringify(data));
176 let item = baseConfigFormItems.value.find(item => item.field == 'modelGuid');
177 item && (item.options = data);
178 }
179 })
180 }
181 // 获取所有疾病数据
182 const getDiseaseData = () => {
183 getDiseaseAll().then((res: any) => {
184 if (res.code == proxy.$passCode) {
185 const data = res.data || [];
186 typeMap.value.diseaseGuid = JSON.parse(JSON.stringify(data));
187 let item = baseConfigFormItems.value.find(item => item.field == 'diseaseGuid');
188 if (item) {
189 item.options = typeMap.value['diseaseGuid'];
190 if (guid) {
191 const diseaseData = typeMap.value.diseaseGuid.find(m => m.guid == flowDetail.value.diseaseGuid);
192 if (!diseaseData) {
193 item.options.unshift({
194 guid: flowDetail.value.diseaseGuid,
195 diseaseName: flowDetail.value.diseaseName
196 });
197 }
198 }
199 }
200 }
201 })
202 }
203 // 获取数据资源
204 const getDataCatalog = () => {
205 return getDamCatalogList({ damName: "", pageIndex: 1, pageSize: -1, bizApproveState: "Y" }).then((res: any) => {
206 if (res.code == proxy.$passCode) {
207 const data = res.data.records || [];
208 typeMap.value.dataResourceGuid = JSON.parse(JSON.stringify(data));
209 let item = baseConfigFormItems.value.find(item => item.field == 'dataResourceGuid');
210 if (item) {
211 item.options = data;
212 if (guid) {
213 const rItem = typeMap.value.dataResourceGuid.find(m => m.damGuid == flowDetail.value.dataResourceGuid);
214 if (!rItem) {
215 const rtem = { damGuid: flowDetail.value.dataResourceGuid, damName: flowDetail.value.dataResourceName };
216 item.options.unshift(rtem);
217 typeMap.value.dataResourceGuid.unshift(rtem);
218 }
219 }
220 }
221 }
222 })
223 }
224 // 获取数据资源主题
225 const getSourceThem = (dictType, fieldName) => {
226 return getAllFlowData(dictType).then((res: any) => {
227 if (res.code == proxy.$passCode) {
228 const data = res.data || [];
229 typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
230 let item = baseConfigFormItems.value.find(item => item.field == fieldName);
231 item && (item.options = data);
232 } else {
233 proxy.$ElMessage.error(res.msg);
234 }
235 })
236 }
237 // 获取数据字典
238 const getDataType = (dictType, fieldName) => {
239 getAllFlowData(dictType).then((res: any) => {
240 if (res.code == proxy.$passCode) {
241 const data = res.data || [];
242 typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
243 let item = baseConfigFormItems.value.find(item => item.field == fieldName);
244 item && (item.options = data);
245 } else {
246 proxy.$ElMessage.error(res.msg);
247 }
248 })
249 }
250 // 获取详情
251 const getDetail = () => {
252 loading.value = true;
253 getPriceDetail({ guid }).then((res: any) => {
254 if (res.code == proxy.$passCode) {
255 const data = res.data || {};
256 flowDetail.value = data;
257 dataTransactionPrice.value = flowDetail.value.dataTransactionPrice;
258 dataUsage.value = data.dataUsage || '';
259 const mItem = typeMap.value.modelGuid.find(m => m.guid == flowDetail.value.modelGuid);
260 if (!mItem) {
261 const mtem = { guid: flowDetail.value.modelGuid, modelName: flowDetail.value.modelName };
262 typeMap.value.modelGuid.unshift(mtem);
263 baseConfigFormItems.value[0].options.unshift(mtem);
264 };
265 getModelInfo(flowDetail.value.modelGuid);
266 getDataTypeList()
267 }
268 }).catch(() => {
269 loading.value = false;
270 })
271 }
272 const getDataTypeList = () => {
273 if (guid) {
274 promiseList(
275 getDataCatalog(),
276 getSourceThem('数据资产目录主题名称', 'belongingTheme'),
277 getQuilityModelScore(flowDetail.value.dataResourceGuid)
278 )
279 } else {
280 promiseList(
281 getDataCatalog(),
282 getSourceThem('数据资产目录主题名称', 'belongingTheme'),
283 )
284 }
285 }
286 const setFormItemData = () => {
287 let dictionaryList: any = [], diseaseList: any = [];
288 pricingTargetList.value.map(item => {
289 switch (item.targetType) {
290 case '2':
291 item.functionName == '2' && diseaseList.push(item);
292 break;
293 case '3':
294 dictionaryList.push(item);
295 break;
296 default:
297 break;
298 }
299 })
300 dictionaryData.value = dictionaryList;
301 diseaseData.value = diseaseList;
302 if (diseaseList.length) {
303 const diseaseName = flowDetail.value.diseaseName || '';
304 const modelGuid = flowDetail.value.modelGuid || '';
305 // 获取疾病得分
306 if (diseaseName && modelGuid) {
307 getTargetNum({ diseaseName, guid: modelGuid });
308 }
309 }
310 baseConfigFormItems.value.splice(4);
311 for (var r in baseConfigFormRules.value) {
312 if (r != 'modelGuid' && r != 'dataResourceGuid') {
313 delete baseConfigFormRules.value[r];
314 }
315 }
316 // 添加所属疾病
317 if (diseaseList.length > 0) {
318 baseConfigFormItems.value.push({
319 label: '所属疾病',
320 type: 'cascader',
321 placeholder: '请选择',
322 field: 'diseaseGuid',
323 default: '',
324 options: [],
325 showAllLevels: false,
326 props: {
327 checkStrictly: true,
328 label: "diseaseName",
329 value: "guid",
330 children: 'childList',
331 emitPath: false
332 },
333 filterable: true,
334 clearable: true,
335 required: true,
336 });
337 baseConfigFormRules.value.diseaseGuid = { required: true, trigger: 'change', message: "请选择所属疾病" };
338 if (typeMap.value['diseaseGuid'] == undefined) {
339 getDiseaseData();
340 } else {
341 let item = baseConfigFormItems.value.find(item => item.field == 'diseaseGuid');
342 if (item) {
343 item.options = typeMap.value['diseaseGuid'];
344 const diseaseData = typeMap.value.diseaseGuid.find(m => m.guid == flowDetail.value.diseaseGuid);
345 if (!diseaseData) {
346 item.options.unshift({
347 guid: flowDetail.value.diseaseGuid,
348 diseaseName: flowDetail.value.diseaseName
349 });
350 }
351 }
352 }
353 }
354 // 添加数据字典
355 dictionaryList.map(d => {
356 const dictName = d.dictionaryName;
357 const dictField = `dict_${d.guid}`;
358 baseConfigFormItems.value.push({
359 label: dictName,
360 type: 'select',
361 placeholder: '请输入',
362 field: dictField,
363 default: '',
364 options: [],
365 clearable: true,
366 filterable: true,
367 required: true,
368 });
369 baseConfigFormRules.value[dictField] = { required: true, trigger: 'change', message: `请选择${dictName}` };
370 (() => {
371 if (typeMap.value[dictField] == undefined) {
372 getDataType(dictName, dictField)
373 } else {
374 let item = baseConfigFormItems.value.find(item => item.field == dictField);
375 item && (item.options = typeMap.value[dictField]);
376 }
377 })()
378 })
379 setTimeout(() => {
380 baseConfigFormRef.value.ruleFormRef?.clearValidate();
381 }, 100)
382 }
383
384 const setdemandTableData = (mGuid = '') => {
385 const tList = flowDetail.value.dataPricingDemandmatchingRQVOS || demandTableList.value || [];
386 let tDatas: any = [];
387 if (guid) {
388 if (mGuid) {
389 tDatas = mGuid == flowDetail.value.modelGuid ? tList : demandTableList.value || [];
390 } else {
391 tDatas = tList;
392 }
393 } else {
394 tDatas = tList;
395 }
396 setTableData(JSON.parse(JSON.stringify(tDatas)))
397 }
398
399 const setTableData = (dataArr) => {
400 tableData.value.splice(0);
401 dataArr.map((item, i) => {
402 const demInfo = pricingTargetList.value.find(t => t.demandTableGuid == (item.demandTableGuid || item.guid));
403 const demWeight = demInfo?.weight || '';
404 tableData.value.push({
405 ...item,
406 demandTableName: item.demandTableName || item.menuName,
407 dataTableGuid: item.dataTableGuid || '',
408 tableDescription: item.tableDescription || '',
409 weightDemandTable: item.weightDemandTable ? parseFloat(item.weightDemandTable).toFixed(2) : (demWeight ? parseFloat(demWeight).toFixed(2) : ''),
410 dataFields: item.pricingDemandFieldRQVOS || [],
411 dataFieldsNum: item.dataFieldsNum || 0,
412 })
413 if ((item.demandTableGuid || item.guid)) {
414 const rGuid = item.demandTableGuid || item.guid;
415 const rIndex = i;
416 if (!guid || (guid && rGuid != (demInfo?.demandTableGuid || ''))) {
417 (() => {
418 getDemandField(rGuid, rIndex);
419 })()
420 }
421 }
422 })
423 resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
424 return accumulator + Number(currentValue.dataFieldsNum);
425 }, 0);
426 setTimeout(() => {
427 tableData.value.map(t => {
428 expendTableRef.value.toggleRowExpansion(t);
429 })
430 }, 200)
431 }
432 // 获取模型配置信息
433 const getModelConfig = (mGuid) => {
434 return getModelDemand({ guid: mGuid }).then((res: any) => {
435 if (res.code == proxy.$passCode) {
436 const data = res.data || [];
437 demandTableList.value = data.pricingDemandMenuRSVOS || [];
438 pricingTargetList.value = data.pricingTargetRSVOS || [];
439 demandTableFieldAllNum.value = data.fieldCount || 0;
440 }
441 })
442 }
443 // 获取模型详情
444 const getModelDetail = (mGuid) => {
445 return getConfigureDetail({ guid: mGuid }).then((res: any) => {
446 if (res.code == proxy.$passCode) {
447 const data = res.data || [];
448 modelData.value = data;
449 const pricingDimensionality = data.pricingDimensionalityRSVOS || [];
450 let tData: any = [];
451 pricingDimensionality.map(p => {
452 p.pricingTargetRSVOS.map(t => {
453 tData.push({ ...p, ...t })
454 })
455 })
456 pricingDimensionalityData.value = tData;
457 }
458 })
459 }
460 // 获取资源详情
461 const getResourceDetail = (sGuid, toPromise = true) => {
462 const detailData = getRegisterCatalogDetail(sGuid).then((res: any) => {
463 if (res.code == proxy.$passCode) {
464 const data = res.data || {};
465 baseConfigFormItems.value.map(item => {
466 if (item.field == 'belongingEntityGuid') {
467 item.default = data.tenantName || '';
468 } else if (item.field == 'belongingTheme') {
469 item.default = data.subjectDomain || '';
470 }
471 })
472 const damCatalogTableInfo = data.damCatalogTableInfo || [];
473 const damOptions = damCatalogTableInfo.map(item => {
474 return {
475 ...item,
476 label: item.tableName,
477 value: item.guid
478 }
479 })
480 tableData.value.map((item, i) => {
481 item.damDataTable = JSON.parse(JSON.stringify(damOptions));
482 if (guid && sGuid == flowDetail.value.dataResourceGuid) {
483 const sData = flowDetail.value.dataPricingDemandmatchingRQVOS?.find(s => s.demandTableGuid == item.demandTableGuid);
484 if (sData) {
485 item.dataTableGuid = sData.dataTableGuid;
486 item.dataFields.map(f => {
487 const fData = sData.pricingDemandFieldRQVOS.find(t => t.guid == f.guid);
488 f.enName = fData?.enName || '';
489 f.chName = fData?.chName || '';
490 });
491 item.tableDescription = sData.tableDescription || damOptions.find(t => t.guid == sData.dataTableGuid)?.tableDescription || '';
492 item.dataFieldsNum = item.dataFields.filter(item => item.chName != '' && item.chName != null).length;
493 resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
494 return accumulator + Number(currentValue.dataFieldsNum);
495 }, 0);
496 }
497 } else {
498 item.dataTableGuid = '';
499 item.dataFields.map(f => { f.enName = ''; f.chName = '' });
500 item.dataFieldsNum = 0;
501 item.tableDescription = '';
502 resourceTableFieldAllNum.value = 0;
503 }
504 const dGuid = item.dataTableGuid;
505 const rIndex = i;
506 (() => {
507 !toPromise && dGuid && setTableRowData(dGuid, rIndex)
508 })()
509 })
510 resourceTableAllNum.value = tableData.value.filter(item => item.dataTableGuid != '' && item.dataTableGuid != null).length;
511 }
512 });
513 if (toPromise) {
514 return detailData;
515 } else {
516 (() => detailData)()
517 }
518 }
519 // 获取质量模型评分
520 const getQuilityModelScore = (sGuid) => {
521 return getModelScore({ damGuid: sGuid }).then((res: any) => {
522 if (res.code === proxy.$passCode) {
523 const data = res.data || {};
524 qualityScoreData.value = data;
525 } else {
526 proxy.$ElMessage.error(res.msg);
527 }
528 })
529 }
530 // 獲取模型相关信息
531 const getModelInfo = (mGuid) => {
532 const promises: any = [
533 getModelConfig(mGuid),
534 getModelDetail(mGuid)
535 ];
536 try {
537 loading.value = true;
538 Promise.all(promises).then(res => {
539 loading.value = false;
540 setFormItemData();
541 if (guid && mGuid == flowDetail.value.modelGuid) {
542 dataTransactionPrice.value = flowDetail.value.dataTransactionPrice;
543 setTimeout(() => {
544 getResourceDetail(flowDetail.value.dataResourceGuid, false);
545 setFormItems();
546 setdemandTableData(mGuid);
547 }, 200);
548 } else {
549 setdemandTableData(mGuid);
550 }
551 });
552 } catch (e) {
553 loading.value = false;
554 }
555 }
556 // 获取数据资源管理信息
557 const getResourceInfo = (sGuid) => {
558 const promises: any = [getResourceDetail(sGuid), getQuilityModelScore(sGuid)];
559 try {
560 loading.value = true;
561 Promise.all(promises).then(res => {
562 loading.value = false;
563 });
564 } catch (e) {
565 loading.value = false;
566 }
567 }
568 const setTableRowData = (dGuid, rIndex) => {
569 let rowData = tableData.value[rIndex];
570 if (guid && dGuid == rowData.dataTableGuid) {
571 const sourceTableField = flowDetail.value.dataPricingDemandmatchingRQVOS?.find(s => dGuid == s.dataTableGuid);
572 const pricingDemandField = sourceTableField?.pricingDemandFieldRQVOS || [];
573 rowData.dataFields.map(f => {
574 f.chName = pricingDemandField.find(s => f.guid == s.guid)?.chName || ''
575 })
576 } else {
577 rowData.dataFields.map(f => f.chName = '')
578 }
579 const damData = rowData.damDataTable.find(item => item.guid == dGuid);
580 rowData.tableDescription = damData?.tableDescription || '';
581 rowData.dataFieldsNum = rowData.dataFields.filter(item => item.chName != '' && item.chName != null).length;
582 resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
583 return accumulator + Number(currentValue.dataFieldsNum);
584 }, 0);
585 resourceTableAllNum.value = tableData.value.filter(item => item.dataTableGuid != '' && item.dataTableGuid != null).length;
586 if (dGuid) {
587 tableLoading.value = true;
588 getRegisterCatalogTableDetail(dGuid).then((res: any) => {
589 tableLoading.value = false;
590 if (res.code == proxy.$passCode) {
591 const data = res.data || {};
592 const damTableField = data.damCatalogTableField || [];
593 const damFieldOptions = damTableField.map(d => {
594 return {
595 ...d,
596 label: d.chName || '',
597 value: d.chName || ''
598 }
599 })
600 rowData.dataFields.map(t => {
601 t.damFieldTable = JSON.parse(JSON.stringify(damFieldOptions));
602 })
603 // console.log('rowData', rowData)
604 } else {
605 proxy.$ElMessage.error(res.msg);
606 }
607 }).catch(() => {
608 tableLoading.value = false;
609 })
610 }
611 }
612
613 const changeDatasource = () => {
614 baseConfigFormItems.value.map(item => {
615 if (item.field == 'belongingEntityGuid') {
616 item.default = '';
617 } else if (item.field == 'belongingTheme') {
618 item.default = '';
619 }
620 })
621 }
622 const cascaderChange = (val) => {
623 disScore.value = [];
624 if (val) {
625 const baseConfigFormObj = baseConfigFormRef.value;
626 const baseConfigFormInfo = baseConfigFormObj.formInline;
627 const parentsData = baseConfigFormObj.getCascaderCheckedData();
628 const diseaseName = parentsData[0]?.label || '';
629 const modelGuid = baseConfigFormInfo.modelGuid;
630 // 获取疾病得分
631 getTargetNum({ diseaseName, guid: modelGuid });
632 }
633 }
634 const selectChange = async (val, row, info) => {
635 dataTransactionPrice.value = '';
636 if (row.field == 'modelGuid') {
637 tableData.value = [];
638 demandTableFieldAllNum.value = 0;
639 resourceTableAllNum.value = 0;
640 resourceTableFieldAllNum.value = 0;
641 await setFormItems(info);
642 val && getModelInfo(val);
643 qualityScoreData.value = {};
644 baseConfigFormItems.value[1].default = '';
645 changeDatasource();
646 } else if (row.field == 'dataResourceGuid') {
647 await setFormItems(info);
648 qualityScoreData.value = {};
649 resourceTableAllNum.value = 0;
650 resourceTableFieldAllNum.value = 0;
651 if (val) {
652 getResourceInfo(val);
653 } else {
654 changeDatasource();
655 }
656 } else if (row.field == 'dataTableGuid') {
657 setTableRowData(val, info.$index)
658 } else if (row.field == 'chName') {
659 let tData = info.row;
660 if (val) {
661 const damData = tData.dataFields[row.index].damFieldTable.find(item => item.chName == val);
662 tData.dataFields[row.index].enName = damData?.enName || '';
663 } else {
664 tData.dataFields[row.index].enName = '';
665 }
666 tData.dataFieldsNum = tData.dataFields.filter(item => item.chName != '' && item.chName != null).length;
667 resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
668 return accumulator + Number(currentValue.dataFieldsNum);
669 }, 0);
670 } else {
671 setFormItems(info);
672 }
673 }
674 // 获取需求表字段
675 const getDemandField = (rGuid, rIndex) => {
676 getDemandList({
677 pageSize: -1,
678 pageIndex: 1,
679 relationMenuGuid: rGuid,
680 bizState: 'Y'
681 }).then((res: any) => {
682 tableLoading.value = false;
683 if (res.code == proxy.$passCode) {
684 const data = res.data || {};
685 const fData = data.records || [];
686 const tFields = tableData.value[rIndex].dataFields;
687 const tData = fData.map(item => {
688 const iData = tFields.find(t => t.demandFieldGuid == item.guid) || {};
689 return {
690 ...item,
691 fieldName: item.fieldName,
692 isRequired: item.isRequired,
693 chName: item.chName || '',
694 enName: item.enName || '',
695 ...iData
696 }
697 });
698 tableData.value[rIndex].dataFields = tData;
699 // // 合并数组
700 // const arr1Map = new Map(fData.map(item => [item.guid, item]));
701
702 // const merged = tFields.map(item => {
703 // if (item.demandFieldGuid && arr1Map.has(item.demandFieldGuid)) {
704 // return merge({}, arr1Map.get(item.demandFieldGuid), item);
705 // }
706 // return item;
707 // });
708
709 // fData.forEach(item => {
710 // if (!tFields.some(x => x.demandFieldGuid === item.guid)) {
711 // merged.push(item);
712 // }
713 // });
714
715 // const tData = merged;
716 // tableData.value[rIndex].dataFields = tData;
717
718 } else {
719 proxy.$ElMessage.error(res.msg);
720 }
721 }).catch(() => {
722 tableLoading.value = false;
723 })
724 }
725 const toPath = () => {
726 userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
727 assetStore.set(true);
728 router.push({
729 name: 'priceCalculate',
730 })
731 }
732 // 获取维度公式计算结果
733 const getSignatory = (row) => {
734 let formulaVal = 0;
735 const pricingTargetData = row.pricingTargetRSVOS || [];
736 if (!row.computationalFormula || row.computationalFormula == 'custom') {
737 let formula = row.customize;
738 // 遍历数组,检查 customize 是否包含对应的 targetName,若包含则替换为 tNum
739 pricingTargetData.forEach((item) => {
740 if (formula.includes(item.targetName)) {
741 formula = formula.replace(new RegExp(item.targetName, 'g'), item.tNum);
742 }
743 });
744 // 使用 eval 计算公式结果(注意:eval 存在安全风险,仅适用于受控环境)
745 try {
746 formulaVal = eval(formula);
747 } catch (error) {
748 console.error('公式计算错误:', error);
749 }
750 } else {
751 const formula = pricingTargetData.map(item => item.tNum);
752 if (row.computationalFormula == '3') {
753 formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) * parseFloat(currentValue), 1); // 初始值为1
754 } else {
755 formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) + parseFloat(currentValue), 0); // 初始值为0
756 }
757 }
758 return (Math.round(formulaVal * 100) / 100).toFixed(2);
759 };
760 const getTargetNum = (params) => {
761 // loading.value = true;
762 getPriceResult(params).then((res: any) => {
763 // loading.value = false;
764 if (res.code === proxy.$passCode) {
765 const data = res.data || [];
766 disScore.value = data;
767 } else {
768 proxy.$ElMessage.error(res.msg);
769 }
770 }).catch(() => {
771 // loading.value = false;
772 });
773 }
774
775 // 生成报告内容
776 const reporting = (formInfo) => {
777 let resultInfo: any = [];
778 const signatoryData = JSON.parse(JSON.stringify(modelData.value.pricingDimensionalityRSVOS || '[]'));
779 signatoryData.map((sign, s) => {
780 resultInfo.push({
781 dimensionalityName: sign.dimensionalityName,
782 computationalFormula: sign.computationalFormula,
783 customize: sign.customize,
784 pricingTargetRSVOS: []
785 });
786 const targets = sign.pricingTargetRSVOS || [];
787 const signTargets = targets.map(t => {
788 let tNum: any = 0, tCustomize = '';
789 if (t.targetType == '3') { // 指标类型-数据字典
790 const tName = dictionaryData.value.find(d => d.guid == t.guid) ? `dict_${t.guid}` : '';
791 if (tName) {
792 const pVal = typeMap.value[tName].find(t => t.value == formInfo[tName]);
793 const dictionary = t.dictionaryJson.find(d => d.name == pVal.label);
794 if (sign.computationalFormula == '1') {// 加权平均
795 tNum = parseFloat(t.weight) / 100 * parseFloat(dictionary?.value || t.defaultValue || 0);
796 tCustomize = `权重${parseFloat(t.weight) / 100} * 因子/默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
797 } else { // 其他
798 tNum = parseFloat(dictionary?.value || t.defaultValue || 0);
799 tCustomize = `默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
800 }
801 t.dictionaryName == '数据用途' && (dataUsage.value = pVal.value || '');
802 }
803 } else if (t.targetType == '2') {// 指标类型-系统功能
804 if (t.functionName == '1') { // 功能名称-质量评价模型
805 const score = parseFloat(qualityScoreData.value.qualityScore || 0);
806 tNum = parseFloat(t.weight || 1) / 100 * score;
807 tCustomize = `权重${parseFloat(t.weight) / 100} * 模型评分${score}`;
808 } else if (t.functionName == '2') { // 功能名称-疾病管理
809 if (sign.computationalFormula == '1') {// 加权平均
810 const score = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
811 tNum = parseFloat(t.weight) / 100 * score;
812 tCustomize = `权重${parseFloat(t.weight) / 100} * 疾病得分${score}`;
813 } else { //其他
814 tNum = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
815 tCustomize = `疾病得分${tNum}`;
816 }
817 } else if (t.functionName == '3') {// 功能名称-需求表管理
818 const tData = tableData.value.find(f => f.demandTableGuid == t.demandTableGuid || f.guid == t.demandTableGuid);
819 if (tData) {
820 if (sign.computationalFormula == '1') {// 加权平均
821 tNum = parseFloat(t.weight) / 100 * (parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0));
822 tCustomize = `权重${parseFloat(t.weight) / 100} * 匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
823 } else { //其他
824 tNum = parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0);
825 tCustomize = `匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
826 }
827 }
828 }
829 } else { // 指标类型-系统内置
830 if (sign.computationalFormula == '1') {// 加权平均
831 tNum = parseFloat(t.weight) / 100 * parseFloat(t.defaultValue || 0);
832 tCustomize = `权重${parseFloat(t.weight) / 100} * 默认值${parseFloat(t.defaultValue || 0)}`;
833 } else { //其他
834 tNum = parseFloat(t.defaultValue || 0);
835 tCustomize = `默认值${parseFloat(t.defaultValue || 0)}`;
836 }
837 }
838 t.tNum = (Math.round(parseFloat(tNum) * 100) / 100).toFixed(2);
839 resultInfo[s].pricingTargetRSVOS.push({
840 targetName: t.targetName,
841 targetType: t.targetType,
842 functionName: t.functionName,
843 customize: tCustomize,
844 tNum: t.tNum,
845 })
846 return t;
847 })
848 sign.pricingTargetRSVOS = signTargets;
849 sign.sNum = getSignatory(sign);
850 resultInfo[s].sNum = sign.sNum;
851 })
852 // exportData.value = resultInfo;
853 return { signatoryData, resultInfo };
854 }
855
856 // 计算价格
857 const calculatePrice = (pData) => {
858 let modelFormula = modelData.value.modelFormula;
859 // 1. 移除所有干扰的引号(确保是数学表达式)
860 modelFormula = modelFormula.replace(/["']/g, "");
861
862 // 1. 提取变量名(中文、英文、数字、下划线)
863 const variableRegex = /[\u4e00-\u9fa5a-zA-Z_][\u4e00-\u9fa5a-zA-Z0-9_]*/g;
864 const variableNames = modelFormula.match(variableRegex) || [];
865
866 // 2. 去重
867 const uniqueVariables = [...new Set(variableNames)];
868
869 // 3. 构建变量映射 { 销售额: 2000, 成本: 500.5, ... }
870 const variables = {};
871 uniqueVariables.forEach(name => {
872 const dim = pData.find(d => d.dimensionalityName === name);
873 variables[name] = dim ? parseFloat(dim.sNum) : 0; // 找不到则默认为 0
874 });
875
876 // 4. 替换变量为数值(不加引号,确保是数字运算)
877 let expression = modelFormula;
878 uniqueVariables.forEach(name => {
879 expression = expression.replace(new RegExp(name, 'g'), variables[name]);
880 });
881
882 // 5. 安全计算(推荐 math.js,或 new Function)
883 try {
884 //如果用 eval,确保表达式格式正确
885 const resultNum = eval(expression);
886
887 dataTransactionPrice.value = (Math.round(parseFloat(resultNum) * 100) / 100).toFixed(2);
888 } catch (error) {
889 console.error('公式计算错误:', error);
890 return NaN;
891 }
892 };
893
894 // 计算结果和提交
895 const checkForm = (type) => {
896 const baseConfigFormObj = baseConfigFormRef.value;
897 const baseConfigFormEl = baseConfigFormObj.ruleFormRef;
898 const baseConfigFormInfo = baseConfigFormObj.formInline;
899 baseConfigFormEl.validate((valid, errorItem) => {
900 if (valid) {
901 if (type == 'calculate') {
902 const { signatoryData, resultInfo } = reporting(baseConfigFormInfo);
903 exportData.value = resultInfo;
904 calculatePrice(signatoryData);
905 } else if (type == 'export') {
906 const { signatoryData, resultInfo } = reporting(baseConfigFormInfo);
907 exportData.value = resultInfo;
908 !dataTransactionPrice.value && calculatePrice(signatoryData);
909 loading.value = true;
910 let exportOut: any = {};
911 // 估值对象信息
912 const damName = typeMap.value.dataResourceGuid.find(f => f.damGuid == baseConfigFormInfo.dataResourceGuid)?.damName || '';
913 exportOut.one = `${baseConfigFormInfo.belongingEntityGuid}拟了解其所持有的\"${damName}\"相关数据资源的价格,为此需对该行为涉及的数据资源在不同应用场景下,基于数据资源持有单位的性质、信息化程度、数据稀缺性、需求匹配等情况下,为上述经济行为提供定价参考依据。`;
914 exportOut.two = `估值对象:${baseConfigFormInfo.belongingEntityGuid}持有的\"${damName}\"`;
915 // 估值范围信息
916 const damNames = demandTableList.value.map(item => item.menuName)
917 let rangStr = `包含${damNames.join('、')}等${damNames.length}张表单,${damNames.length}张表共计${demandTableFieldAllNum.value}个字段`;
918 const dataTimeliness = pricingTargetList.value.find(p => p.dictionaryName == '时效性');
919 const dataTimelinessStr = dataTimeliness ? typeMap.value[`dict_${dataTimeliness.guid}`].find(f => f.value == baseConfigFormInfo[`dict_${dataTimeliness.guid}`])?.label || '' : '';
920 rangStr += dataTimelinessStr ? `,时间跨度为${dataTimelinessStr}的数据` : `的数据`;
921 damNames.length && (exportOut.two = `${exportOut.two}\n估值范围:${rangStr}`);
922 // 字典
923 let dictList: any = [], hasModelScore = false;
924 const dictStr = exportData.value.map(e => {
925 const targetList: any = [];
926 e.pricingTargetRSVOS.map(t => {
927 if (t.targetType == '2' && t.functionName == '1') {
928 hasModelScore = true;
929 } else {
930 targetList.push({
931 targetName: t.targetName,
932 tNum: t.tNum,
933 })
934 }
935 })
936 const targetStr = targetList.length ? targetList.map(t => `${t.targetName}为${changeNum(t.tNum, 2)}`).join('、') : '';
937 targetStr && dictList.push(`${e.dimensionalityName}为${changeNum(e.sNum, 2)},其中${targetStr}`);
938 return `${e.dimensionalityName}为${changeNum(e.sNum, 2)}`;
939 })
940 let dictListStr = `${dictStr.join(',')}。\n${dictList.join(';\n')}`
941 // 质量模型
942 if (hasModelScore) {
943 const largeCategoryScoreList = qualityScoreData.value.largeCategoryScoreList || [];
944 const largeCategoryScore = largeCategoryScoreList.map(q => `${q.largeCategoryName}方面得分为${changeNum(q.largeCategoryScore || 0, 2)}`);
945 dictListStr += largeCategoryScore.length ? `;\n数据的总体质量得分为${changeNum(qualityScoreData.value.qualityScore || 0, 2)}。其中${largeCategoryScore.join(',')}` : `;\n数据的总体质量得分为${changeNum(qualityScoreData.value.qualityScore || 0, 2)}。`
946 }
947 exportOut.three = `${baseConfigFormInfo.belongingEntityGuid}持有的\"${damName}\"的数据(患者人次)单价为${changeNum(dataTransactionPrice.value, 2)}元`;
948 exportOut.three = dictListStr ? `${exportOut.three};其中${dictListStr}` : `${exportOut.three}。`
949 exportModelScore(exportOut).then((res: any) => {
950 loading.value = false;
951 if (res && !res.msg) {
952 ElMessage({
953 type: "success",
954 message: '下载报告成功',
955 });
956 download(res, `数据定价报告.doc`, 'word');
957 } else {
958 res?.msg && ElMessage.error(res?.msg);
959 }
960 }).catch(() => {
961 loading.value = false;
962 ElMessage({
963 type: "error",
964 message: '下载报告请求失败',
965 });
966 })
967 } else {
968 const { signatoryData, resultInfo } = reporting(baseConfigFormInfo);
969 exportData.value = resultInfo;
970 !dataTransactionPrice.value && calculatePrice(signatoryData);
971 const modelName = typeMap.value.modelGuid.find(d => d.guid == baseConfigFormInfo.modelGuid)?.modelName || '';
972 const dataResourceName = typeMap.value.dataResourceGuid.find(d => d.damGuid == baseConfigFormInfo.dataResourceGuid)?.damName || '';
973 const diseaseGuid = baseConfigFormInfo.diseaseGuid || '';
974 let params: any = {
975 tenantGuid: userData.tenantGuid,
976 dataTransactionPrice: dataTransactionPrice.value,
977 modelGuid: baseConfigFormInfo.modelGuid,
978 modelName,
979 dataResourceGuid: baseConfigFormInfo.dataResourceGuid,
980 dataResourceName,
981 belongingEntityGuid: baseConfigFormInfo.belongingEntityGuid,
982 belongingTheme: baseConfigFormInfo.belongingTheme,
983 diseaseGuid,
984 diseaseName: '',
985 dataUsage: dataUsage.value
986 };
987 if (diseaseGuid) {
988 const parentsData = baseConfigFormObj.getCascaderCheckedData();
989 params.diseaseName = parentsData[0]?.label || '';
990 }
991 let dictionaryJson = {};
992 for (var b in baseConfigFormInfo) {
993 if (b.indexOf('dict_') > -1) {
994 dictionaryJson[b] = baseConfigFormInfo[b];
995 }
996 }
997 params.dictionaryJson = Object.keys(dictionaryJson).length ? JSON.stringify(dictionaryJson) : '';
998 let demandMatchingData: any = [];
999 tableData.value.map(item => {
1000 demandMatchingData.push({
1001 demandTableName: item.demandTableName,
1002 demandTableGuid: item.demandTableGuid || item.guid, // 需求表guid
1003 dataTableGuid: item.dataTableGuid, // 数据资源表guid
1004 weightDemandTable: item.weightDemandTable,
1005 dataFieldsNum: item.dataFieldsNum,
1006 pricingDemandFieldRQVOS: item.dataFields.map(d => {
1007 return {
1008 demandFieldGuid: d.demandFieldGuid || d.guid, // 资源表字段guid
1009 fieldName: d.fieldName,
1010 enName: d.enName,
1011 chName: d.chName,
1012 isRequired: d.isRequired
1013 }
1014 })
1015 })
1016 });
1017 params.dataPricingDemandmatchingRQVOS = demandMatchingData;
1018 guid && (params.guid = guid);
1019 loading.value = true;
1020 savePrice(params).then((res: any) => {
1021 loading.value = false;
1022 if (res.code == proxy.$passCode) {
1023 ElMessage({
1024 type: "success",
1025 message: guid ? '编辑数据定价成功' : '新增数据定价成功',
1026 });
1027 toPath()
1028 } else {
1029 proxy.$ElMessage.error(res.msg);
1030 }
1031 }).catch(() => {
1032 loading.value = false;
1033 });
1034 }
1035 } else {
1036 expand1.value = true;
1037 var obj = Object.keys(errorItem);
1038 baseConfigFormEl.scrollToField(obj[0]);
1039 }
1040 })
1041 }
1042 const btnClick = async (btn, row: any = null) => {
1043 const type = btn.value;
1044 if (type == 'dim') {
1045 baseConfigFormItems.value.at(-1).default += btn.name;
1046 } else if (type == 'del-signatory') {
1047 open('确定要删除该条维度数据吗?', 'warning');
1048 } else if (type == 'expend') {
1049 expendTableRef.value.toggleRowExpansion(row);
1050 } else if (type == 'calculate' || type == 'submit') {
1051 if (type == 'submit') {
1052 ElMessageBox.confirm(dataTransactionPrice.value === '' ? '是否直接计算价格并提交' : '请确认当前数据交易价格是否为最新计算结果', '提示', {
1053 confirmButtonText: '确定',
1054 cancelButtonText: '取消',
1055 type: 'warning',
1056 }).then(() => {
1057 checkForm(type);
1058 }).catch(() => {
1059 ElMessage.info('已取消提交操作');
1060 });
1061 } else {
1062 checkForm(type);
1063 }
1064 } else if (type == 'export') {
1065 ElMessageBox.confirm(dataTransactionPrice.value === '' ? '是否直接计算价格并下载' : '请确认当前数据交易价格是否为最新计算结果', '提示', {
1066 confirmButtonText: '确定',
1067 cancelButtonText: '取消',
1068 type: 'warning',
1069 }).then(() => {
1070 checkForm(type);
1071 }).catch(() => {
1072 ElMessage.info('已取消下载操作');
1073 });
1074 } else if (type == 'cancel') {
1075 ElMessageBox.confirm(
1076 "当前页面尚未保存,确定关闭吗?",
1077 "提示",
1078 {
1079 confirmButtonText: "确定",
1080 cancelButtonText: "取消",
1081 type: "warning",
1082 }
1083 ).then(() => {
1084 toPath()
1085 }).catch(() => {
1086 ElMessage({
1087 type: "info",
1088 message: "已取消",
1089 });
1090 });
1091 }
1092 }
1093 onActivated(() => {
1094 let tab: any = userStore.tabbar.find((tab: any) => tab.fullPath === router.currentRoute.value.fullPath);
1095 if (tab) {
1096 switch (route.query.type) {
1097 case 'create':
1098 tab.meta.title = `新增数据定价`;
1099 break;
1100 case 'edit':
1101 tab.meta.title = `编辑-${priceName}`;
1102 break;
1103 case 'detail':
1104 tab.meta.title = `详情-${priceName}`;
1105 break;
1106 }
1107 }
1108 getModel()
1109 })
1110 onBeforeMount(() => {
1111 if (guid) {
1112 getDetail();
1113 } else {
1114 getDataTypeList();
1115 getModel()
1116 }
1117 })
1118 onMounted(() => {
1119 })
1120 </script>
1121 <template>
1122 <div class="container_wrap full" v-loading="loading">
1123 <div class="content_main panel">
1124 <ContentWrap id="contract-content-wrap" title="输入参数" expandSwicth style="margin-top: 15px" :isExpand="expand1"
1125 @expand="(v) => expand1 = v">
1126 <Form ref="baseConfigFormRef" formId="contract-content-form" :itemList="baseConfigForm.items"
1127 :rules="baseConfigForm.rules" col="col3" @selectChange="selectChange" @cascaderChange="cascaderChange" />
1128 </ContentWrap>
1129 <ContentWrap id="contract-signatory-wrap" title="需求匹配" expandSwicth style="margin-top: 15px" :isExpand="expand2"
1130 @expand="(v) => expand2 = v">
1131 <div class="table_panel_wrap">
1132 <div class="table_tool">
1133 <div class="tool_title">
1134 <div class="title_desc">
1135 <span>需求表数量:</span>
1136 <span class="text-num">{{ demandTableList.length }}</span>
1137 <span>张,字段数:</span>
1138 <span class="text-num">{{ demandTableFieldAllNum }}</span>
1139 <span>匹配表数量:</span>
1140 <span class="text-num">{{ resourceTableAllNum }}</span>
1141 <span>张,字段数:</span>
1142 <span class="text-num">{{ resourceTableFieldAllNum }}</span>
1143 </div>
1144 </div>
1145 </div>
1146 <div class="table_panel" v-loading="tableLoading">
1147 <el-table ref="expendTableRef" border :data="tableData" row-key="demandTableName" tooltip-effect="light"
1148 style="height: 100%;">
1149 <el-table-column type="expand">
1150 <template #default="props">
1151 <div class="expand_panel">
1152 <div class="table_tool">
1153 <div class="tool_title">
1154 <div class="title_desc">
1155 <span>需求字段数:</span>
1156 <span class="text-num">{{ props.row.dataFields.length }}</span>
1157 <span>个,匹配字段数:</span>
1158 <span class="text-num">{{ props.row.dataFieldsNum }}</span>
1159 </div>
1160 </div>
1161 </div>
1162 <el-table :data="props.row.dataFields" border>
1163 <el-table-column label="序号" type="index" width="56" align="center" />
1164 <el-table-column label="需求字段中文" prop="fieldName" class-name="edit-col">
1165 <template #default="scope">
1166 <el-input v-model.trim="scope.row.fieldName" placeholder="请输入" disabled />
1167 </template>
1168 </el-table-column>
1169 <el-table-column label="匹配字段中文" prop="chName" class-name="edit-col">
1170 <template #default="scope">
1171 <el-select v-model="scope.row.chName" clearable filterable
1172 @change="val => selectChange(val, { field: 'chName', index: scope.$index }, props)">
1173 <el-option v-for="(opt, o) in scope.row.damFieldTable" :label="opt.label" :value="opt.value"
1174 :key="o" />
1175 </el-select>
1176 </template>
1177 </el-table-column>
1178 <el-table-column label="匹配字段英文" prop="enName" class-name="edit-col">
1179 <template #default="scope">
1180 <el-input v-model.trim="scope.row.enName" placeholder="请输入" disabled />
1181 </template>
1182 </el-table-column>
1183 <el-table-column label="是否必需字段" prop="isRequired" class-name="edit-col">
1184 <template #default="scope">
1185 <el-select v-model="scope.row.isRequired" disabled>
1186 <el-option label="是" value="Y" />
1187 <el-option label="否" value="N" />
1188 </el-select>
1189 </template>
1190 </el-table-column>
1191 </el-table>
1192 </div>
1193 </template>
1194 </el-table-column>
1195 <el-table-column label="序号" type="index" width="56" align="center" />
1196 <el-table-column v-for="item in tableFields" :key="item.field" :label="item.label" :prop="item.field"
1197 :width="item.width" :align="item.align" class-name="edit-col">
1198 <template #default="scope">
1199 <el-select v-if="item.type == 'select'" v-model="scope.row[item.field]" clearable filterable
1200 @change="val => selectChange(val, item, scope)">
1201 <el-option v-for="(opt, o) in scope.row.damDataTable" :label="opt.label" :value="opt.value"
1202 :key="o" />
1203 </el-select>
1204 <el-input v-else v-model.trim="scope.row[item.field]" :disabled="item.disabled" placeholder="请输入"
1205 clearable />
1206 </template>
1207 </el-table-column>
1208 <el-table-column label="操作" fixed="right" width="100">
1209 <template #default="scope">
1210 <el-button type="primary" link @click="btnClick({ value: 'expend' }, scope.row)">字段映射</el-button>
1211 </template>
1212 </el-table-column>
1213 </el-table>
1214 </div>
1215 </div>
1216 </ContentWrap>
1217 <ContentWrap id="contract-content-wrap" title="输出结构" expandSwicth style="margin-top: 15px" :isExpand="expand3"
1218 @expand="(v) => expand3 = v">
1219 <el-form class="result-form">
1220 <el-form-item class="flex-column" label="数据交易价格(元)">
1221 <el-input v-model="dataTransactionPrice" placeholder="" disabled style="display: none;" />
1222 <div class="result-price">{{ changeNum(dataTransactionPrice, 2) }}</div>
1223 </el-form-item>
1224 <el-form-item class="align-end" style="margin-bottom: 14px;">
1225 <el-button type="primary" @click="btnClick({ value: 'calculate' })">开始计算</el-button>
1226 <el-button @click="btnClick({ value: 'export' })">下载报告</el-button>
1227 <span style="margin-left: 8px">输出结果报告查看</span>
1228 </el-form-item>
1229 </el-form>
1230 </ContentWrap>
1231 </div>
1232 <div class="tool_btns">
1233 <div class="btns">
1234 <el-button @click="btnClick({ value: 'cancel' })">取消</el-button>
1235 <el-button type="primary" @click="btnClick({ value: 'submit' })">提交</el-button>
1236 </div>
1237 </div>
1238 </div>
1239 </template>
1240 <style scoped lang="scss">
1241 .container_wrap {
1242 overflow: hidden;
1243
1244 .content_main {
1245 height: calc(100% - 45px);
1246 overflow: hidden auto;
1247
1248 &.panel {
1249 padding: 0 16px 16px;
1250 }
1251
1252 :deep(.el-card) {
1253 &#contract-signatory-wrap {
1254 .card-body-content {
1255 padding: 8px 16px;
1256 }
1257 }
1258 }
1259
1260 .signatory-tags {
1261 margin-bottom: 11px;
1262 }
1263
1264 .table_panel_wrap {
1265 margin-bottom: 4px;
1266
1267 .table_tool {
1268 height: 36px;
1269 display: flex;
1270 justify-content: space-between;
1271 align-items: center;
1272
1273 .tool_title {
1274 width: 100%;
1275 display: flex;
1276 justify-content: start;
1277 }
1278
1279 .title_desc {
1280 overflow: hidden;
1281 white-space: nowrap;
1282 text-overflow: ellipsis;
1283
1284 .text-num {
1285 color: var(--el-color-primary);
1286 margin: 0 8px;
1287 }
1288 }
1289 }
1290
1291 .table_panel {
1292 margin-bottom: 4px;
1293 height: 392px;
1294
1295 :deep(.el-table) {
1296 .el-table__cell {
1297 &.edit-col {
1298 padding: 4px 0;
1299
1300 .cell {
1301 padding: 0 4px;
1302
1303 .el-cascader {
1304 width: 100%;
1305 height: 28px;
1306 }
1307
1308 .el-input {
1309 height: 28px;
1310 }
1311 }
1312 }
1313
1314 .expand-icon {
1315 color: #888;
1316 margin-right: 8px;
1317 vertical-align: text-bottom;
1318 cursor: pointer;
1319 }
1320 }
1321
1322 .el-input.is-disabled .el-input__wrapper {
1323 background-color: var(--el-disabled-bg-color);
1324 }
1325
1326 .el-select__wrapper.is-disabled {
1327 background-color: var(--el-disabled-bg-color);
1328 }
1329 }
1330
1331 .expand_panel {
1332 padding: 6px;
1333 margin: -6px 0;
1334 background: #fff;
1335 }
1336 }
1337 }
1338 }
1339
1340 .btn-block {
1341 width: 100%;
1342 margin: 16px 0 8px;
1343 }
1344
1345 .tool_btns {
1346 height: 44px;
1347 margin: 0 -8px;
1348 display: flex;
1349 justify-content: center;
1350 align-items: center;
1351 border-top: 1px solid #d9d9d9;
1352 }
1353 }
1354
1355 :deep(.el-form) {
1356 &.result-form {
1357 display: flex;
1358
1359 .el-form-item {
1360 &.flex-column {
1361 width: calc(33.33% - 6px);
1362 margin-right: 8px;
1363 display: flex;
1364 flex-direction: column;
1365 align-items: self-start;
1366
1367 .el-form-item__content {
1368 width: 100%;
1369 }
1370
1371 .result-price {
1372 width: 100%;
1373 height: 32px;
1374 line-height: 32px;
1375 padding: 1px 11px;
1376 border-radius: 4px;
1377 cursor: not-allowed;
1378 color: var(--el-disabled-text-color);
1379 background-color: var(--el-disabled-bg-color);
1380 box-shadow: 0 0 0 1px var(--el-disabled-border-color) inset;
1381 }
1382 }
1383
1384 &.align-end {
1385 align-self: flex-end;
1386 }
1387 }
1388 }
1389
1390 .el-select__wrapper.is-disabled {
1391 background-color: var(--el-disabled-bg-color);
1392 }
1393 }
1394 </style>
1 <route lang="yaml">
2 name: demandManage
3 </route>
4
5 <script lang="ts" setup name="demandManage">
6 import { ref } from 'vue';
7 import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
8 import { ElMessage, ElMessageBox } from "element-plus";
9 import { CirclePlus, Search } from "@element-plus/icons-vue";
10 import { useRouter, useRoute } from "vue-router";
11 import { changeNum, getCurrentTime } from '@/utils/common';
12 import useUserStore from "@/store/modules/user";
13 import useCatchStore from "@/store/modules/catch";
14 import {
15 getDemandAll,
16 saveDemandTree,
17 updateDemandTree,
18 deleteDemandTree,
19 getDemandList,
20 saveDemand,
21 updateDemand,
22 deleteDemand,
23 } from '@/api/modules/dataPricing';
24
25 const router = useRouter();
26 const userStore = useUserStore()
27 const userData = JSON.parse(userStore.userData)
28 const { proxy } = getCurrentInstance() as any;
29 const cacheStore = useCatchStore()
30
31 /** 左侧标签列表管理 */
32 const treeInfoRef = ref();
33 const treeData = ref([]);
34 const treeInfo = ref({
35 id: "demand-tree",
36 filter: true,
37 editTreeItem: true,
38 queryValue: "",
39 loading: false,
40 className: 'tree-list-manage',
41 queryPlaceholder: "输入关键字搜索",
42 props: {
43 label: "menuName",
44 value: "guid",
45 children: 'childList',
46 },
47 prefix: {
48 type: 'prefixIcon'
49 },
50 lazy: false,
51 nodeKey: 'guid',
52 expendAll: true,
53 currentNodeKey: '',
54 expandOnNodeClick: false,
55 data: [],
56 });
57
58 const catalogData = ref([]);
59 const searchItemList = ref([
60 {
61 type: "select",
62 label: "",
63 field: "isRequired",
64 placeholder: "是否必选",
65 default: "",
66 options: [
67 { label: '是', value: 'Y' },
68 { label: '否', value: 'N' }
69 ],
70 clearable: true,
71 style: {
72 width: '140px'
73 }
74 },
75 {
76 type: "input",
77 label: "",
78 field: "fieldName",
79 default: "",
80 placeholder: "字段名称",
81 clearable: true,
82 style: {
83 width: '230px'
84 }
85 },
86 ]);
87
88 const lastClickNode: any = ref({});
89 const showTable = ref(false)
90 /** 记录正在提交审批流程的api,防止重复提交 */
91 const addDataPromise: any = ref();
92 const tableRef = ref();
93 const tableData: any = ref([]);
94 const selectRowData: any = ref([])
95 const currTableData: any = ref({});
96 const page: any = ref({
97 ...commonPageConfig,
98 fieldName: '',
99 isRequired: '',
100 });
101 const tableFields: any = [
102 { label: "字段名称", field: "fieldName" },
103 { label: "是否必选", field: "isRequired", type: 'select' },
104 { label: "排序", field: "orderNum", type: 'defaultValue' },
105 { label: '启用状态', field: 'bizState', type: 'switch', activeText: '启用', inactiveText: '停用', activeValue: 'Y', inactiveValue: 'N' },
106 { label: "创建时间", field: "createTime", type: 'defaultValue' },
107 ]
108 const tableInfo: any = ref({
109 id: 'api-data-table',
110 rowKey: 'guid',
111 loading: false,
112 multiple: true,
113 fields: [
114 { label: "字段名称", field: "fieldName", width: 200, align: "left", type: 'edit' },
115 {
116 label: "是否必选", field: "isRequired", width: 140, type: 'edit', getName: (scope) => {
117 return scope.row.isRequired == 'Y' ? '是' : '否'
118 }
119 },
120 { label: "排序", field: "orderNum", width: 120, type: 'edit', dataTypeName: 'fieldType' },
121 {
122 label: '启用状态', field: 'bizState', type: 'edit', activeText: '启用', inactiveText: '停用', activeValue: 'Y', inactiveValue: 'N', switchWidth: 56, width: 96, align: 'center',
123 },
124 { label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME, type: 'edit', dataTypeName: 'dateType' },
125 ],
126 data: tableData.value,
127 editInfo: [],
128 page: {
129 type: "normal",
130 rows: 0,
131 ...page.value,
132 },
133 actionInfo: {
134 label: "操作",
135 type: "btn",
136 isMore: false,
137 width: 120,
138 btns: (scope) => {
139 let btns: any[] = [];
140 if (scope.row.STATUS == 'edit') {
141 btns.push({
142 value: 'save', label: '保存', click: (scope) => {
143 if (addDataPromise.value) {
144 return;
145 }
146 // 调用新增数据的接口。
147 let params = { ...scope.row, tenantGuid: userData.tenantGuid };
148 params.relationMenuGuid = lastClickNode.value.guid;
149 delete params['ROWID'];
150 delete params['STATUS'];
151 delete params['STATE'];
152 delete params.dateType;
153 delete params.fieldType;
154 if (params.guid) {
155 addDataPromise.value = updateDemand(params).then((res: any) => {
156 addDataPromise.value = null;
157 if (res.code == proxy.$passCode) {
158 page.value.curr = 1;
159 getTableData();
160 proxy.$ElMessage.success('编辑数据保存成功');
161 } else {
162 proxy.$ElMessage.error(res.msg);
163 }
164 });
165 } else {
166 addDataPromise.value = saveDemand(params).then((res: any) => {
167 addDataPromise.value = null;
168 if (res.code == proxy.$passCode) {
169 page.value.curr = 1;
170 getTableData();
171 proxy.$ElMessage.success('新增数据保存成功');
172 } else {
173 proxy.$ElMessage.error(res.msg);
174 }
175 });
176 }
177 }
178 });
179 btns.push({
180 value: 'del', label: '删除', click: (scope) => {
181 proxy.$openMessageBox('确定要删除该条数据吗?', () => {
182 tableData.value.splice(0, 1);
183 proxy.$ElMessage.success("删除成功");
184 }, () => {
185 proxy.$ElMessage.info("已取消删除");
186 })
187 }
188 });
189 return btns;
190 }
191 btns.push({ value: 'edit', label: '编辑' });
192 btns.push({ value: 'del', label: '删除' });
193 return btns;
194 }
195 }
196 });
197
198 /** ---- 新增修改标签对话框配置------------- */
199 const formItems: any = ref([
200 {
201 label: '需求表名称',
202 type: 'input',
203 placeholder: '请输入',
204 field: 'menuName',
205 default: '',
206 maxlength: 20,
207 clearable: true,
208 required: true,
209 },
210 {
211 label: '是否为目录',
212 type: 'select',
213 field: 'isCatalog',
214 default: 'N',
215 options: [
216 { label: '是', value: 'Y' },
217 { label: '否', value: 'N' }
218 ],
219 required: true,
220 },
221 {
222 label: '所属上级',
223 type: 'cascader',
224 placeholder: '请选择',
225 field: "parentGuid",
226 default: [],
227 options: [],
228 showAllLevels: false,
229 props: {
230 checkStrictly: true,
231 label: "menuName",
232 value: "guid",
233 children: 'childList',
234 emitPath: false
235 },
236 clearable: true,
237 filterable: true,
238 block: true
239 },
240 {
241 label: '排序',
242 type: 'input',
243 placeholder: '请输入',
244 field: 'orderNum',
245 default: '',
246 inputType: 'integerNumber',
247 maxlength: 6,
248 clearable: true,
249 },
250 ])
251
252 const formRules = ref({
253 menuName: [
254 { required: true, message: '请填写需求表名称', trigger: 'blur' }
255 ],
256 isCatalog: [
257 { required: true, message: '请选择是否为目录', trigger: 'change' }
258 ]
259 });
260
261 /** 新建api标签对话框 */
262 const demScheduleLabelDialogInfo = ref({
263 visible: false,
264 size: 480,
265 direction: "column",
266 header: {
267 title: "",
268 },
269 type: '',
270 contents: [
271 {
272 type: 'form',
273 title: '',
274 formInfo: {
275 id: 'add-staff-form',
276 items: formItems.value,
277 rules: formRules.value
278 }
279 }
280 ],
281 footer: {
282 btns: [
283 { type: "default", label: "取消", value: "cancel" },
284 { type: "primary", label: "确定", value: "submit" },
285 ],
286 },
287 });
288
289 // 获取需求表树形数据
290 const getTreeData = () => {
291 getDemandAll({ isCatalog: '' }).then((res: any) => {
292 if (res.code == proxy.$passCode) {
293 const data = res.data || [];
294 treeData.value = JSON.parse(JSON.stringify(data));
295 treeInfo.value.data = JSON.parse(JSON.stringify(data));
296 treeInfo.value.currentNodeKey = data[0]?.guid || "";
297 lastClickNode.value = data[0] || {};
298 nextTick(() => {
299 treeInfoRef.value?.setCurrentKey(treeInfo.value.currentNodeKey);
300 if (lastClickNode.value.isCatalog != 'Y') {
301 showTable.value = true;
302 page.value.curr = 1;
303 getTableData();
304 } else {
305 showTable.value = false;
306 }
307 })
308 } else {
309 proxy.$ElMessage.error(res.msg);
310 }
311 })
312 getCatalog();
313 }
314
315 const getCatalog = () => {
316 getDemandAll({ isCatalog: 'Y' }).then((res: any) => {
317 if (res.code == proxy.$passCode) {
318 const data = res.data || [];
319 catalogData.value = JSON.parse(JSON.stringify(data));
320 }
321 })
322 }
323
324 /** 点击左侧节点 */
325 const nodeClick = (data) => {
326 lastClickNode.value = data || {};
327 if (data.isCatalog != 'Y') {
328 showTable.value = true;
329 page.value.curr = 1;
330 getTableData();
331 } else {
332 showTable.value = false;
333 }
334 }
335
336 const setRowData = (info: any = null) => {
337 const rowData: any = {
338 STATUS: 'edit',
339 STATE: "Running",
340 ROWID: '1',
341 dateType: 'datetime',
342 fieldType: 'int',
343 fieldName: info?.fieldName || '',
344 isRequired: info?.isRequired || 'N',
345 bizState: info?.bizState || 'Y',
346 createTime: info?.createTime || getCurrentTime(),
347 orderNum: info?.orderNum !== undefined ? info?.orderNum : tableData.value.length + 1
348 }
349 info && (rowData.guid = info.guid || '');
350 return rowData;
351 }
352
353 // 新增字段
354 const addField = () => {
355 if (tableData.value[0]?.STATUS == 'edit') {
356 proxy.$ElMessage.warning('请先保存正在编辑的行数据');
357 return;
358 }
359 // 支持新增数据,直接添加一行进行编辑。
360 const rowData = setRowData();
361 tableData.value.unshift(rowData);
362 nextTick(() => {
363 tableRef?.value?.tableRef?.setScrollTop(0);
364 })
365 }
366
367 // 批量删除
368 const batching = (type) => {
369 if (type == 'delete') {
370 if (selectRowData.value.length == 0) {
371 ElMessage({
372 type: 'error',
373 message: '请选择需要删除的数据',
374 })
375 return
376 }
377 open("此操作将永久删除, 是否继续?", "warning", true);
378 } else if (type == 'import') {
379 const info = {
380 dictionaryGuid: ''
381 }
382 cacheStore.setCatch('uploadSetting', info)
383 router.push(
384 {
385 name: 'importFileDemandManage',
386 query: {
387 isfileImport: '7'
388 }
389 }
390 );
391 }
392 }
393
394 const setFormItems = (info = null, type = '') => {
395 const datas: any = info || {};
396 formItems.value.map(item => {
397 if (item.field == 'isCatalog') {
398 item.default = datas[item.field] || 'N';
399 } else {
400 item.default = datas[item.field] || '';
401 }
402 })
403 }
404
405 const setCataLog = (dataArr, id, parentDisabled = false) => {
406 return dataArr.map(item => {
407 // 当前节点是否被禁选(自身匹配或父节点已禁选)
408 const isDisabled = parentDisabled || item.guid === id;
409 // 新节点基础属性
410 const newItem = {
411 ...item,
412 disabled: isDisabled
413 };
414
415 // 递归处理子节点,并传递当前节点的禁选状态
416 if (item.childList && item.childList.length > 0) {
417 newItem.childList = setCataLog(item.childList, id, isDisabled);
418 }
419 return newItem;
420 })
421 }
422
423 /** 处理标签的操作按钮,编辑,删除 */
424 const handleTreeItemMenuClick = async (node, type) => {
425 let data = node.data;
426 lastClickNode.value = data;
427 if (type == "edit") {
428 await setFormItems(data);
429 if (data.isCatalog == 'Y') {
430 formItems.value[1].disabled = data.childList && data.childList.length > 0;
431 } else {
432 formItems.value[1].disabled = tableData.value && tableData.value.length > 0;
433 }
434 let cata = setCataLog(catalogData.value, data.guid);
435 formItems.value.at(-2).options = cata;
436 demScheduleLabelDialogInfo.value.contents[0].formInfo.items = formItems.value;
437 demScheduleLabelDialogInfo.value.header.title = "编辑需求表";
438 demScheduleLabelDialogInfo.value.type = 'edit';
439 demScheduleLabelDialogInfo.value.visible = true;
440 } else if (type == "delete") {
441 proxy.$openMessageBox('确定要删除该需求表吗?', () => {
442 deleteDemandTree([lastClickNode.value.guid]).then((res: any) => {
443 if (res.code == proxy.$passCode) {
444 getTreeData();
445 proxy.$ElMessage.success("删除该需求表成功");
446 } else {
447 proxy.$ElMessage.error(res.msg);
448 }
449 });
450 }, () => {
451 proxy.$ElMessage.info("已取消");
452 })
453 }
454 }
455 /** 新建分组对话框确定。 */
456 const demScheduleLabelDialogBtnClick = (btn, info) => {
457 if (btn.value == 'submit') {
458 let params = { ...info, parentGuid: info.parentGuid || '', tenantGuid: userData.tenantGuid };
459 if (demScheduleLabelDialogInfo.value.type == 'add') {
460 saveDemandTree(params).then((res: any) => {
461 if (res.code == proxy.$passCode) {
462 getTreeData();
463 proxy.$ElMessage({
464 type: 'success',
465 message: '新增需求表成功'
466 })
467 demScheduleLabelDialogInfo.value.visible = false;
468 } else {
469 proxy.$ElMessage({
470 type: 'error',
471 message: res.msg,
472 })
473 }
474 })
475 } else {
476 params.guid = lastClickNode.value.guid;
477 updateDemandTree(params).then((res: any) => {
478 if (res.code == proxy.$passCode) {
479 getTreeData();
480 proxy.$ElMessage({
481 type: 'success',
482 message: '编辑需求表成功'
483 })
484 demScheduleLabelDialogInfo.value.visible = false;
485 } else {
486 proxy.$ElMessage({
487 type: 'error',
488 message: res.msg,
489 })
490 }
491 })
492 }
493 } else if (btn.value == 'cancel') {
494 demScheduleLabelDialogInfo.value.visible = false;
495 }
496 };
497
498 const addTreeNode = async () => {
499 await setFormItems();
500 demScheduleLabelDialogInfo.value.header.title = '新建需求表';
501 formItems.value[1].disabled = false;
502 formItems.value.at(-2).options = catalogData.value;
503 demScheduleLabelDialogInfo.value.contents[0].formInfo.items = formItems.value;
504 demScheduleLabelDialogInfo.value.type = 'add';
505 demScheduleLabelDialogInfo.value.visible = true;
506 }
507
508 // 设置需求表表头
509 const setTableField = () => {
510 const editInfo = {};
511 tableFields.forEach(f => {
512 if (f.type == 'switch') {
513 editInfo[f.field] = {
514 label: f.label,
515 type: f.type,
516 field: f.field,
517 default: false,
518 activeText: '启用',
519 inactiveText: '停用',
520 activeValue: 'Y',
521 inactiveValue: 'N',
522 };
523 } else if (f.type == 'select') {
524 editInfo[f.field] = {
525 label: f.label,
526 type: f.type,
527 field: f.field,
528 default: '',
529 options: [
530 { label: '是', value: 'Y' },
531 { label: '否', value: 'N' }
532 ],
533 clearable: true
534 }
535 } else if (f.type == 'defaultValue') {
536 editInfo[f.field] = {
537 label: f.label,
538 type: f.type,
539 field: f.field,
540 default: '',
541 clearable: true,
542 disabled: true,
543 }
544 } else {
545 editInfo[f.field] = {
546 label: f.label,
547 type: 'input',
548 field: f.field,
549 placeholder: f.isPrimary == 'Y' ? '主键自动生成' : '请输入',
550 default: '',
551 clearable: true
552 }
553 }
554 })
555 tableInfo.value.editInfo = editInfo;
556 }
557
558 const toSearch = (val: any = null, clear: boolean = false) => {
559 page.value.curr = 1;
560 if (clear) {
561 searchItemList.value.map((item) => (item.default = ""));
562 page.value.fieldName = '';
563 page.value.isRequired = '';
564 } else {
565 let info = val ? { ...val } : {};
566 searchItemList.value.map(item => {
567 info[item.field] = item.default;
568 })
569 page.value.fieldName = info.fieldName || '';
570 page.value.isRequired = info.isRequired || '';
571 }
572 getTableData();
573 };
574
575 // 获取表格数据
576 const getTableData = () => {
577 if (!lastClickNode.value?.guid) {
578 return;
579 }
580 tableInfo.value.loading = true;
581 getDemandList({
582 pageSize: page.value.limit,
583 pageIndex: page.value.curr,
584 relationMenuGuid: lastClickNode.value.guid,
585 fieldName: page.value.fieldName,
586 isRequired: page.value.isRequired,
587 }).then((res: any) => {
588 tableInfo.value.loading = false;
589 if (res.code == proxy.$passCode) {
590 const data = res.data || {};
591 tableData.value = data.records || [];
592 tableInfo.value.data = tableData.value;
593 tableInfo.value.page.limit = data.pageSize
594 tableInfo.value.page.curr = data.pageIndex
595 tableInfo.value.page.rows = data.totalRows
596 } else {
597 proxy.$ElMessage.error(res.msg);
598 }
599 })
600 }
601
602 const tablePageChange = (info) => {
603 page.value.curr = Number(info.curr);
604 page.value.limit = Number(info.limit);
605 getTableData();
606 };
607
608 const tableSelectionChange = (val) => {
609 selectRowData.value = val;
610 };
611
612 const tableSwitchBeforeChange = (scope, field, callBack) => {
613 if (scope.row.STATUS == 'edit') {
614 callBack(true);
615 } else {
616 // proxy.$openMessageBox(`确定要更新该字段值吗?`, () => {
617 // const state = scope.row[field] == 'Y' ? 'N' : 'Y';
618 // let mdmModelData: any = {};
619 // mdmModelData[field] = state;
620 // let pkValue = scope.row[mergeFormItems.value[0].field];
621 // mdmModelData[mergeFormItems.value[0].field] = pkValue;
622 // updateMdmModelData({
623 // mdmModelTableGuid: props.modelConfigInfo.guid,
624 // mdmModelData: mdmModelData,
625 // pkValues: [pkValue]
626 // }).then((res: any) => {
627 // if (res.code == proxy.$passCode) {
628 // proxy.$ElMessage.success('该字段值更新成功');
629 // let firstData = tableData.value[0];
630 // getMainModelData().then((res: any) => {
631 // if (firstData && firstData.STATUS == 'edit') {
632 // tableData.value.unshift(firstData);
633 // }
634 // });
635 // callBack(true)
636 // } else {
637 // proxy.$ElMessage.error(res.msg);
638 // callBack(false)
639 // }
640 // });
641 // }, () => {
642 // callBack(false);
643 // })
644 }
645 }
646
647 const tableSwitchChange = (val, scope, field) => {
648 if (scope.row.STATUS == 'edit') {
649 tableData.value[scope.$index][field] = val;
650 }
651 }
652
653 const tableBtnClick = (scope, btn) => {
654 const type = btn.value;
655 const row = scope.row;
656 currTableData.value = row;
657 if (type === 'edit') { // 编辑
658 if (tableData.value.find(t => t.STATUS == 'edit')) {
659 proxy.$ElMessage.warning('请先保存正在编辑的行数据');
660 return;
661 }
662 const rowData = setRowData(row);
663 tableData.value[scope.$index] = rowData;
664 } else if (type === 'del') { // 删除
665 open('确定要删除该条数据吗?', 'warning');
666 }
667 };
668
669 const open = (msg, type, isBatch = false) => {
670 ElMessageBox.confirm(msg, "提示", {
671 confirmButtonText: "确定",
672 cancelButtonText: "取消",
673 type: type,
674 }).then(() => {
675 let guids = [currTableData.value.guid]
676 if (isBatch) {
677 guids = selectRowData.value.map(item => item.guid);
678 }
679 deleteDemand(guids).then((res: any) => {
680 if (res.code == proxy.$passCode) {
681 getTableData();
682 ElMessage({
683 type: "success",
684 message: "删除成功",
685 });
686 } else {
687 ElMessage({
688 type: "error",
689 message: res.msg,
690 });
691 }
692 });
693 });
694 };
695
696 onBeforeMount(() => {
697 getTreeData();
698 setTableField();
699 });
700
701 onActivated(() => {
702
703 })
704
705 </script>
706
707 <template>
708 <div class="container_wrap full flex">
709 <div class="aside_wrap">
710 <div class="aside_title">需求表列表</div>
711 <el-icon class="icon-add" color="#4fa1a4" @click="addTreeNode()">
712 <CirclePlus />
713 </el-icon>
714 <Tree ref="treeInfoRef" :treeInfo="treeInfo" @nodeClick="nodeClick" @itemMenuClick="handleTreeItemMenuClick" />
715 </div>
716 <div class="main_wrap">
717 <template v-if="showTable">
718 <div class="table_tool_wrap">
719 <div class="tools_btns">
720 <el-button type="primary" @click="addField" v-preReClick>添加</el-button>
721 <el-button @click="batching('import')" v-preReClick>批量导入</el-button>
722 <el-button @click="batching('delete')" v-preReClick>批量删除</el-button>
723 </div>
724 <div class="tools_serach">
725 <template v-for="(item, i) in searchItemList" :key="'s_' + i">
726 <el-select v-if="item.type == 'select'" v-model="item.default" :placeholder="item.placeholder"
727 :clearable="item.clearable" :style="item.style" @change="val => toSearch()">
728 <el-option v-for="(opt, o) in item.options" :label="opt.label" :value="opt.value" :key="o" />
729 </el-select>
730 <el-input v-else v-model.trim="item.default" :placeholder="item.placeholder" :suffix-icon="Search"
731 :clearable="item.clearable" :style="item.style" @change="val => toSearch()" />
732 </template>
733 </div>
734 </div>
735 <div class="table_panel_wrap">
736 <Table ref="tableRef" :tableInfo="tableInfo" @tableSelectionChange="tableSelectionChange"
737 @tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
738 </div>
739 </template>
740 <div class="card-noData" v-else>
741 <img src="@/assets/images/no-data.png" :style="{ width: '96px', height: '96px' }" />
742 <p>请选择需求表</p>
743 </div>
744 </div>
745 <!-- 添加编辑需求表的对话框 -->
746 <Dialog :dialogInfo="demScheduleLabelDialogInfo" @btnClick="demScheduleLabelDialogBtnClick" />
747 </div>
748 </template>
749
750 <style lang="scss" scoped>
751 .container_wrap {
752 padding: 0;
753 display: flex;
754 justify-content: space-between;
755
756 .aside_wrap {
757 width: 199px;
758 border-right: 1px solid #d9d9d9;
759 box-shadow: none;
760
761 .aside_title {
762 width: calc(100% - 32px);
763 display: inline-block;
764 }
765
766 .icon-add.el-icon {
767 width: 24px;
768 height: 24px;
769 vertical-align: middle;
770 cursor: pointer;
771
772 svg {
773 width: 24px;
774 height: 24px;
775 }
776 }
777
778 :deep(.tree_panel) {
779 height: 100%;
780 padding-top: 0;
781
782 .el-tree {
783 margin: 0;
784 height: calc(100% - 68px);
785 overflow: hidden auto;
786 }
787 }
788
789 }
790
791 .main_wrap {
792 padding: 0 8px;
793 height: auto;
794 flex: 1;
795
796 .table_tool_wrap {
797 width: 100%;
798 padding: 0 8px;
799 display: flex;
800 justify-content: space-between;
801 align-items: center;
802
803 .tools_btns {
804 padding: 0px 0 0;
805 }
806
807 .tools_serach {
808 width: 378px;
809 display: flex;
810 justify-content: space-between;
811 }
812 }
813
814 .table_panel_wrap {
815 width: 100%;
816 height: calc(100% - 44px);
817 padding: 0px 8px 0;
818 }
819
820 .card-noData {
821 position: absolute;
822 top: 50%;
823 left: 50%;
824 transform: translate(-50%, -50%);
825 display: flex;
826 flex-direction: column;
827 align-items: center;
828 }
829 }
830 }
831
832 .row-dialog-content {
833 height: 300px;
834
835 .tools_btns {
836 margin-bottom: 8px;
837 }
838 }
839
840 :deep(.el-form) {
841 .select-input-long {
842 .el-form-item:first-child {
843 width: 67%;
844 margin-right: 0px;
845 }
846
847 .el-form-item:last-child {
848 width: 33%;
849 margin-right: 0px;
850
851 .item-label {
852 white-space: pre;
853
854 .required_mark::after {
855 content: '';
856 }
857 }
858 }
859 }
860
861 .select-input-long-reverse {
862 .el-form-item:first-child {
863 width: 100px;
864 margin-right: 0px;
865 }
866
867 .el-form-item:last-child {
868 width: calc(100% - 100px);
869 margin-right: 0px;
870
871 .item-label {
872 white-space: pre;
873
874 .required_mark::after {
875 content: '';
876 }
877 }
878 }
879 }
880 }
881 </style>
1 <route lang="yaml">
2 name: diseaseManage
3 </route>
4
5 <script lang="ts" setup name="diseaseManage">
6 import { ref } from 'vue';
7 import TableTools from '@/components/Tools/table_tools.vue';
8 import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
9 import { ElMessage, ElMessageBox } from "element-plus";
10 import { CirclePlus } from "@element-plus/icons-vue";
11 import { useRouter, useRoute } from "vue-router";
12 import useUserStore from "@/store/modules/user";
13 import useCatchStore from "@/store/modules/catch";
14 import {
15 getDiseaseAll,
16 getDiseaseList,
17 saveDisease,
18 updateDisease,
19 deleteDisease,
20 } from '@/api/modules/dataPricing';
21 import { changeNum } from '@/utils/common';
22
23 const router = useRouter();
24 const userStore = useUserStore()
25 const userData = JSON.parse(userStore.userData)
26 const { proxy } = getCurrentInstance() as any;
27 const cacheStore = useCatchStore()
28
29 const searchItemList = ref([
30 {
31 type: "input",
32 label: "",
33 field: "diseaseName",
34 default: "",
35 placeholder: "疾病名称",
36 clearable: true,
37 },
38 {
39 type: "select",
40 label: "",
41 field: "isChildrenDisease",
42 placeholder: "是否儿童",
43 default: "",
44 options: [
45 { label: '是', value: 'Y' },
46 { label: '否', value: 'N' }
47 ],
48 clearable: true,
49 }
50 ]);
51
52 const tableData: any = ref([]);
53 const selectRowData: any = ref([])
54 const currTableData: any = ref({});
55 const selectionTreeTableRef = ref();
56 const page: any = ref({
57 ...commonPageConfig,
58 diseaseName: '',
59 isChildrenDisease: ''
60 });
61 const tableInfo = ref({
62 id: 'api-data-table',
63 rowKey: 'guid',
64 loading: false,
65 multiple: true,
66 fields: [
67 { label: "疾病名称", field: "diseaseName", width: 200 },
68 {
69 label: "是否儿童疾病", field: "isChildrenDisease", width: 120, getName: (scope) => {
70 return scope.row.isChildrenDisease == 'Y' ? '是' : '否';
71 }
72 },
73 { label: "发病率/患病率", field: "incidenceRate", width: 120 },
74 {
75 label: "因子", field: "factor", width: 100, align: 'right', getName: (scope) => {
76 return (scope.row.factor !== '' && scope.row.factor !== null) ? changeNum(scope.row.factor, 2) : '-';
77 }
78 },
79 {
80 label: "启用状态", field: "bizState", type: 'tag', width: 120, align: 'center', getName: (scope) => {
81 return scope.row.bizState == 'Y' ? '启用' : '停用';
82 }, tagType: (scope) => {
83 return scope.row.bizState == 'Y' ? 'success' : 'info';
84 }
85 },
86 { label: "排序", field: "orderNum", width: 100, align: 'right', type: 'chnum' },
87 { label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME },
88 ],
89 data: tableData.value,
90 treeProps: {
91 children: 'childList',
92 hasChildren: 'hasChildren',
93 checkStrictly: false,
94 },
95 page: {
96 type: "normal",
97 rows: 0,
98 ...page.value,
99 },
100 actionInfo: {
101 label: "操作",
102 type: "btn",
103 isMore: false,
104 width: 120,
105 btns: [
106 { label: "编辑", value: "edit" },
107 { label: "删除", value: "del" }
108 ]
109 }
110 });
111
112 /** ---- 新增修改标签对话框配置------------- */
113 const catalogData = ref([]);
114 const formItems: any = ref([
115 {
116 label: '疾病名称',
117 type: 'input',
118 placeholder: '请输入',
119 field: 'diseaseName',
120 default: '',
121 maxlength: 50,
122 required: true,
123 clearable: true,
124 },
125 {
126 label: '所属上级',
127 type: 'cascader',
128 placeholder: '请选择',
129 field: "parentGuid",
130 default: [],
131 options: [],
132 showAllLevels: false,
133 props: {
134 checkStrictly: true,
135 label: "diseaseName",
136 children: 'childList',
137 value: "guid",
138 emitPath: false
139 },
140 clearable: true,
141 filterable: true,
142 },
143 {
144 label: '是否儿童疾病',
145 type: 'select',
146 placeholder: '请选择',
147 field: 'isChildrenDisease',
148 default: '',
149 options: [
150 { label: '是', value: 'Y' },
151 { label: '否', value: 'N' }
152 ],
153 required: true,
154 clearable: true,
155 },
156 {
157 label: '启用状态',
158 type: 'switch',
159 field: 'bizState',
160 default: 'Y',
161 placeholder: '请选择',
162 activeValue: 'Y',
163 inactiveValue: 'N',
164 switchWidth: 32,
165 },
166 {
167 label: '发病率/患病率',
168 type: 'input',
169 placeholder: '请输入',
170 field: 'incidenceRate',
171 default: '',
172 maxlength: 20,
173 clearable: true,
174 required: true,
175 },
176 {
177 label: '因子',
178 type: 'input-group',
179 placeholder: '请输入',
180 field: 'in',
181 default: '',
182 children: [
183 {
184 label: '',
185 type: 'input',
186 placeholder: '请输入',
187 field: 'factor',
188 default: '',
189 inputType: 'factorNumber',
190 maxlength: 10,
191 clearable: true,
192 },
193 {
194 label: '',
195 type: 'checkbox',
196 placeholder: '下级同时修改',
197 desc: '',
198 field: 'juniorTogetherModify',
199 default: "N",
200 trueValue: 'Y',
201 falseValue: 'N',
202 }
203 ],
204 },
205 {
206 label: '排序',
207 type: 'input',
208 placeholder: '由数字组成',
209 field: 'orderNum',
210 inputType: 'integerNumber',
211 default: '',
212 maxlength: 6,
213 clearable: true,
214 },
215 ])
216 const formRules = ref({
217 diseaseName: [
218 { required: true, message: '请填写疾病名称', trigger: 'blur' }
219 ],
220 isChildrenDisease: [
221 { required: true, message: '请选择是否儿童疾病', trigger: 'change' }
222 ],
223 bizState: [
224 { required: true, message: '请选择启用状态', trigger: 'change' }
225 ],
226 incidenceRate: [
227 { requires: true, message: '请填写发病率/患病率', trigger: 'blur' },
228 {
229 validator: (rule: any, value: any, callback: any) => {
230 if (!value) {
231 callback(new Error("请填写发病率/患病率"));
232 } else {
233 if (drawerInfo.value.type.indexOf('edit') > -1 && currTableData.value.incidenceRate == value) {
234 callback();
235 return
236 }
237 let eMsg = '';
238 // 验证格式:数字、小数或分数
239 if (!/^[0-9]*\.?[0-9]*(\/[0-9]+\.?[0-9]*)?$/.test(value)) {
240 eMsg = '请输入有效的数字、小数或分数(如0.5或1/2)';
241 }
242
243 let numericValue;
244
245 // 处理分数
246 if (value.includes('/')) {
247 const parts = value.split('/');
248 if (parts.length !== 2) {
249 eMsg = '请输入有效的分数格式(如1/2)';
250 }
251
252 const numerator = parseFloat(parts[0]);
253 const denominator = parseFloat(parts[1]);
254
255 if (isNaN(numerator) || isNaN(denominator)) {
256 eMsg = '请输入有效的分数格式(如1/2)';
257 }
258
259 if (denominator === 0) {
260 eMsg = '请输入有效的分数格式(如1/2)';
261 }
262
263 numericValue = numerator / denominator;
264 } else {// 处理普通数字
265 numericValue = parseFloat(value);
266 if (isNaN(numericValue)) {
267 eMsg = '请输入有效的数字';
268 }
269 }
270
271 if (numericValue < 0) {
272 eMsg = '发病率必须大于等于0';
273 }
274
275 if (numericValue > 1) {
276 eMsg = '发病率必须小于或等于1';
277 }
278 if (eMsg) {
279 callback(new Error(eMsg));
280 } else {
281 callback();
282 }
283 }
284 },
285 trigger: "blur",
286 },
287 ]
288 });
289 const formInfo = ref({
290 type: "form",
291 title: "",
292 col: "span",
293 formInfo: {
294 id: "add-disease-form",
295 readonly: false,
296 items: formItems.value,
297 rules: formRules.value,
298 },
299 });
300
301 const drawerInfo = ref({
302 visible: false,
303 direction: "rtl",
304 size: 480,
305 header: {
306 title: "新增",
307 },
308 type: "",
309 container: {
310 contents: [
311 formInfo.value
312 ],
313 },
314 footer: {
315 visible: true,
316 btns: [
317 { type: "default", label: "取消", value: "cancel" },
318 { type: "primary", label: "保存", value: "submit" },
319 ],
320 },
321 });
322
323 // 获取所有疾病数据
324 const getDiseaseData = () => {
325 getDiseaseAll().then((res: any) => {
326 if (res.code == proxy.$passCode) {
327 const data = res.data || [];
328 catalogData.value = JSON.parse(JSON.stringify(data));
329 }
330 })
331 }
332
333 const toSearch = (val: any, clear: boolean = false) => {
334 page.value.curr = 1;
335 if (clear) {
336 searchItemList.value.map((item) => (item.default = ""));
337 page.value.diseaseName = '';
338 page.value.isChildrenDisease = '';
339 } else {
340 page.value.diseaseName = val.diseaseName || '';
341 page.value.isChildrenDisease = val.isChildrenDisease || '';
342 }
343 getTableData();
344 };
345
346 const getTableData = () => {
347 tableInfo.value.loading = true;
348 getDiseaseList({
349 tenantGuid: userData.tenantGuid,
350 pageSize: page.value.limit,
351 pageIndex: page.value.curr,
352 diseaseName: page.value.diseaseName,
353 isChildrenDisease: page.value.isChildrenDisease,
354 }).then((res: any) => {
355 tableInfo.value.loading = false;
356 if (res.code == proxy.$passCode) {
357 const data = res.data || {};
358 tableData.value = data.records || [];
359 tableInfo.value.data = data.records || []
360 tableInfo.value.page.limit = data.pageSize
361 tableInfo.value.page.curr = data.pageIndex
362 tableInfo.value.page.rows = data.totalRows
363 // formItems.value[1].options = data.records || [];
364 } else {
365 proxy.$ElMessage.error(res.msg);
366 }
367 })
368 }
369
370 const tablePageChange = (info) => {
371 page.value.curr = Number(info.curr);
372 page.value.limit = Number(info.limit);
373 tableInfo.value.page.limit = page.value.limit;
374 tableInfo.value.page.curr = page.value.curr;
375 getTableData();
376 };
377
378 // 处理表格数据选中
379 const setSelect = (data, flag) => {
380 data.forEach((row: any) => {
381 selectionTreeTableRef.value.tableRef.toggleRowSelection(row, flag);
382 row.childList && setSelect(row.childList, flag);
383 });
384 }
385
386 const setCataLog = (dataArr, id, parentDisabled = false) => {
387 return dataArr.map(item => {
388 // 当前节点是否被禁选(自身匹配或父节点已禁选)
389 const isDisabled = parentDisabled || item.guid === id;
390 // 新节点基础属性
391 const newItem = {
392 ...item,
393 disabled: isDisabled
394 };
395
396 // 递归处理子节点,并传递当前节点的禁选状态
397 if (item.childList && item.childList.length > 0) {
398 newItem.childList = setCataLog(item.childList, id, isDisabled);
399 }
400 return newItem;
401 })
402 }
403
404 const tableCheckboxSelectChange = (selectRows, row) => {
405 const check = selectRows.find(item => item.guid === row.guid);
406 row.childList && setSelect(row.childList, check ? true : false);
407 }
408
409 const checkAll = ref(false)
410 const tableCheckboxAllSelectChange = (selectRows) => {
411 checkAll.value = !checkAll.value;
412 setSelect(tableData.value, checkAll.value);
413 }
414
415 const tableSelectionChange = (val) => {
416 selectRowData.value = val;
417 };
418
419 const tableBtnClick = (scope, btn) => {
420 const type = btn.value;
421 const row = scope.row;
422 currTableData.value = row;
423 if (type === 'edit') { // 编辑
424 drawerInfo.value.visible = true;
425 drawerInfo.value.header.title = '编辑疾病';
426 let cata = setCataLog(catalogData.value, row.guid);
427 formItems.value.map(item => {
428 if (item.field == 'parentGuid') {
429 item.options = cata;
430 }
431 item.default = row[item.field] || '';
432 if (item.children) {
433 item.children.map(child => {
434 child.default = row[child.field] || '';
435 if (child.field == 'factor') {
436 child.default = (row[child.field] !== '' && row[child.field] !== null) ? changeNum(row[child.field], 2) : '';
437 }
438 })
439 }
440 if (item.inputType == 'integerNumber') {
441 item.default = typeof row[item.field] == 'number' ? row[item.field] : '';
442 }
443 });
444 drawerInfo.value.type = type;
445 } else if (type === 'del') { // 删除
446 open('确定要删除该条数据吗?', 'warning');
447 }
448 };
449
450 const open = (msg, type, isBatch = false) => {
451 ElMessageBox.confirm(msg, "提示", {
452 confirmButtonText: "确定",
453 cancelButtonText: "取消",
454 type: type,
455 }).then(() => {
456 let guids = [currTableData.value.guid]
457 if (isBatch) {
458 guids = [];
459 // 处理表格数据选中
460 const setGuids = (data) => {
461 data.forEach((row: any) => {
462 guids.push(row.guid);
463 row.childList && setGuids(row.childList);
464 });
465 }
466 setGuids(selectRowData.value);
467 }
468 deleteDisease(guids).then((res: any) => {
469 if (res.code == proxy.$passCode) {
470 getTableData();
471 getDiseaseData();
472 ElMessage({
473 type: "success",
474 message: "删除成功",
475 });
476 } else {
477 proxy.$ElMessage.error(res.msg);
478 }
479 });
480 });
481 };
482
483 const addDisease = () => {
484 formItems.value.map(item => {
485 if (item.field == 'bizState') {
486 item.default = 'Y';
487 } else {
488 if (item.field == 'parentGuid') {
489 item.options = catalogData.value;
490 }
491 item.default = '';
492 if (item.children) {
493 item.children.map(child => {
494 child.default = '';
495 })
496 }
497 }
498 });
499 drawerInfo.value.header.title = '新增疾病';
500 drawerInfo.value.type = 'add';
501 drawerInfo.value.visible = true;
502
503 }
504 // 批量删除
505 const batching = (type) => {
506 if (type == 'delete') {
507 if (selectRowData.value.length == 0) {
508 ElMessage({
509 type: 'error',
510 message: '请选择需要删除的数据',
511 })
512 return
513 }
514 open("此操作将永久删除, 是否继续?", "warning", true);
515 } else if (type == 'import') {
516 const info = {
517 dictionaryGuid: ''
518 }
519 cacheStore.setCatch('uploadSetting', info)
520 router.push(
521 {
522 name: 'importFileDisease',
523 query: {
524 isfileImport: '8'
525 }
526 }
527 );
528 }
529 }
530
531
532 const drawerBtnClick = async (btn, info) => {
533 if (btn.value == "submit") {
534 drawerInfo.value.footer.btns.map((item: any) => (item.disabled = true));
535 let params = { ...info, tenantGuid: userData.tenantGuid };
536 delete params.in;
537 if (drawerInfo.value.type == "add") {
538 saveDisease(params)
539 .then((res: any) => {
540 if (res.code == proxy.$passCode) {
541 getTableData();
542 getDiseaseData();
543 ElMessage({
544 type: "success",
545 message: "新增疾病成功",
546 });
547 drawerInfo.value.visible = false;
548 } else {
549 proxy.$ElMessage.error(res.msg);
550 drawerInfo.value.footer.btns.map(
551 (item: any) => delete item.disabled
552 );
553 }
554 })
555 .catch(() => {
556 drawerInfo.value.footer.btns.map((item: any) => delete item.disabled);
557 });
558 } else {
559 params.guid = currTableData.value.guid;
560 updateDisease(params)
561 .then((res: any) => {
562 if (res.code == proxy.$passCode) {
563 getTableData();
564 getDiseaseData();
565 ElMessage({
566 type: "success",
567 message: "编辑疾病成功",
568 });
569 drawerInfo.value.visible = false;
570 } else {
571 proxy.$ElMessage.error(res.msg);
572 drawerInfo.value.footer.btns.map(
573 (item: any) => delete item.disabled
574 );
575 }
576 })
577 .catch(() => {
578 drawerInfo.value.footer.btns.map((item: any) => delete item.disabled);
579 });
580 }
581 } else {
582 drawerInfo.value.footer.btns.map((item: any) => delete item.disabled);
583 nextTick(() => {
584 drawerInfo.value.visible = false;
585 });
586 }
587 };
588
589 onBeforeMount(() => {
590 getDiseaseData();
591 });
592
593 onActivated(() => {
594
595 })
596
597 </script>
598
599 <template>
600 <div class="container_wrap">
601 <div class="table_tool_wrap">
602 <TableTools :searchItems="searchItemList" :searchId="'data-source-search'" @search="toSearch" />
603 <div class="tools_btns">
604 <el-button type="primary" @click="addDisease" v-preReClick>新增</el-button>
605 <el-button @click="batching('import')" v-preReClick>批量导入</el-button>
606 <el-button @click="batching('delete')" v-preReClick>批量删除</el-button>
607 </div>
608 </div>
609 <div class="table_panel_wrap">
610 <Table ref="selectionTreeTableRef" :tableInfo="tableInfo" @tableCheckboxSelectChange="tableCheckboxSelectChange"
611 @tableCheckboxAllSelectChange="tableCheckboxAllSelectChange" @tableSelectionChange="tableSelectionChange"
612 @tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
613 </div>
614 <Drawer :drawerInfo="drawerInfo" @drawerBtnClick="drawerBtnClick" />
615 </div>
616 </template>
617
618 <style lang="scss" scoped>
619 .table_tool_wrap {
620 width: 100%;
621 height: 84px !important;
622 padding: 0 8px;
623
624 .tools_btns {
625 padding: 0px 0 0;
626 }
627 }
628
629 .table_panel_wrap {
630 width: 100%;
631 height: calc(100% - 84px);
632 padding: 0px 8px 0;
633 }
634 </style>
1 <route lang="yaml">
2 name: priceCalculate
3 </route>
4
5 <script lang="ts" setup name="priceCalculate">
6 import { ref } from 'vue';
7 import TableTools from '@/components/Tools/table_tools.vue';
8 import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
9 import { ElMessage, ElMessageBox } from "element-plus";
10 import { CirclePlus } from "@element-plus/icons-vue";
11 import { useRouter, useRoute } from "vue-router";
12 import useUserStore from "@/store/modules/user";
13 import useDataAssetStore from "@/store/modules/dataResource";
14 import { getAllFlowData } from '@/api/modules/configService';
15 import { changeNum } from "@/utils/common";
16 import {
17 getDiseaseAll,
18 getPriceList,
19 deletePrice,
20 } from '@/api/modules/dataPricing';
21
22 const router = useRouter();
23 const userStore = useUserStore()
24 const assetStore = useDataAssetStore();
25 const userData = JSON.parse(userStore.userData)
26 const { proxy } = getCurrentInstance() as any;
27
28 const searchItemList = ref([
29 {
30 type: "input",
31 label: "",
32 field: "dataResourceName",
33 default: "",
34 placeholder: "数据资源名称",
35 clearable: true,
36 },
37 {
38 type: "cascader",
39 label: "",
40 field: "diseaseName",
41 placeholder: "疾病名称",
42 default: "",
43 options: [],
44 showAllLevels: false,
45 props: {
46 checkStrictly: true,
47 label: "diseaseName",
48 value: "guid",
49 children: 'childList',
50 emitPath: false
51 },
52 filterable: true,
53 clearable: true,
54 }
55 ]);
56
57 const typeMap: any = ref({});
58 const selectRowData: any = ref([])
59 const currTableData: any = ref({});
60 const page: any = ref({
61 ...commonPageConfig,
62 dataResourceName: '',
63 diseaseName: ''
64 });
65 const tableField: any = ref([
66 { label: "序号", type: "index", width: TableColumnWidth.INDEX, align: "center" },
67 { label: "定价模型名称", field: "modelName", width: 200 },
68 { label: "数据资源名称", field: "dataResourceName", width: 200 },
69 { label: "疾病名称", field: "diseaseName", width: 200 },
70 {
71 label: "交易价格(元)", field: "dataTransactionPrice", width: 120, align: 'right', getName: (scope) => {
72 return scope.row.dataTransactionPrice ? changeNum(parseFloat(scope.row.dataTransactionPrice), 2) : '-';
73 }
74 },
75 { label: "创建人", field: "createUserName", width: 120 },
76 { label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME },
77 ]);
78 const tableInfo = ref({
79 id: 'api-data-table',
80 rowKey: 'guid',
81 loading: false,
82 fields: tableField.value,
83 data: [],
84 page: {
85 type: "normal",
86 rows: 0,
87 ...page.value,
88 },
89 actionInfo: {
90 label: "操作",
91 type: "btn",
92 isMore: false,
93 width: 120,
94 btns: [
95 { label: "编辑", value: "edit" },
96 { label: "删除", value: "del" }
97 ]
98 }
99 });
100
101 const setTableField = () => {
102 tableField.value.splice(4, 0, {
103 label: "交易用途", field: "dataUsage", width: 120, getName: (scope) => {
104 return typeMap.value['dataUsage'].find((item) => item.value == scope.row['dataUsage'])?.label || '-';
105 }
106 });
107 tableInfo.value.fields = tableField.value;
108 }
109
110 // 获取所有疾病数据
111 const getDiseaseData = () => {
112 getDiseaseAll().then((res: any) => {
113 if (res.code == proxy.$passCode) {
114 const data = res.data || [];
115 searchItemList.value[1].options = data;
116 }
117 })
118 }
119
120 // 获取数据字典
121 const getDataType = (dictType, fieldName) => {
122 getAllFlowData(dictType).then((res: any) => {
123 if (res.code == proxy.$passCode) {
124 const data = res.data || [];
125 typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
126 setTableField()
127 } else {
128 proxy.$ElMessage.error(res.msg);
129 }
130 })
131 }
132
133 const toSearch = (val: any, clear: boolean = false) => {
134 page.value.curr = 1;
135 if (clear) {
136 searchItemList.value.map((item) => (item.default = ""));
137 page.value.dataResourceName = ''
138 page.value.diseaseName = '';
139 } else {
140 page.value.dataResourceName = val.dataResourceName || '';
141 page.value.diseaseName = val.diseaseName || '';
142 }
143 getTableData();
144 };
145
146 const getTableData = () => {
147 tableInfo.value.loading = true;
148 getPriceList({
149 pageSize: page.value.limit,
150 pageIndex: page.value.curr,
151 dataResourceName: page.value.dataResourceName,
152 diseaseName: page.value.diseaseName,
153 }).then((res: any) => {
154 tableInfo.value.loading = false;
155 if (res.code == proxy.$passCode) {
156 const data = res.data || {};
157 tableInfo.value.data = data.records || [];
158 tableInfo.value.page.limit = data.pageSize
159 tableInfo.value.page.curr = data.pageIndex
160 tableInfo.value.page.rows = data.totalRows
161 } else {
162 proxy.$ElMessage.error(res.msg);
163 }
164 })
165 }
166
167 const tablePageChange = (info) => {
168 page.value.curr = Number(info.curr);
169 page.value.limit = Number(info.limit);
170 tableInfo.value.page.limit = page.value.limit;
171 tableInfo.value.page.curr = page.value.curr;
172 getTableData();
173 };
174
175 const tableBtnClick = (scope, btn) => {
176 const type = btn.value;
177 const row = scope.row;
178 currTableData.value = row;
179 if (type === 'edit') { // 编辑
180 router.push(
181 {
182 name: 'calculateConfig',
183 query: {
184 guid: row.guid,
185 name: row.modelName,
186 type: 'edit'
187 }
188 }
189 );
190 } else if (type === 'del') { // 删除
191 open('确定要删除该条数据吗?', 'warning');
192 }
193 };
194
195 const open = (msg, type, isBatch = false) => {
196 ElMessageBox.confirm(msg, "提示", {
197 confirmButtonText: "确定",
198 cancelButtonText: "取消",
199 type: type,
200 }).then(() => {
201 let guids = [currTableData.value.guid]
202 if (isBatch) {
203 guids = selectRowData.value
204 }
205 deletePrice(guids).then((res: any) => {
206 if (res.code == proxy.$passCode) {
207 getTableData();
208 ElMessage({
209 type: "success",
210 message: "删除成功",
211 });
212 } else {
213 proxy.$ElMessage.error(res.msg);
214 }
215 });
216 });
217 };
218
219 const addDisease = () => {
220 router.push(
221 {
222 name: 'calculateConfig',
223 query: {
224 type: 'create'
225 }
226 }
227 );
228 }
229
230 onBeforeMount(() => {
231 getDiseaseData();
232 getDataType('数据用途', 'dataUsage')
233 });
234
235 onActivated(() => {
236 if (assetStore.isRefresh) {//如果是首次加载,则不需要调用
237 toSearch(null, true);
238 assetStore.set(false);
239 }
240 })
241
242 </script>
243
244 <template>
245 <div class="container_wrap">
246 <div class="table_tool_wrap">
247 <TableTools :searchItems="searchItemList" :searchId="'data-source-search'" @search="toSearch" />
248 <div class="tools_btns">
249 <el-button type="primary" @click="addDisease" v-preReClick>新增</el-button>
250 </div>
251 </div>
252 <div class="table_panel_wrap">
253 <Table :tableInfo="tableInfo" @tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
254 </div>
255 </div>
256 </template>
257
258 <style lang="scss" scoped>
259 .table_tool_wrap {
260 width: 100%;
261 height: 84px !important;
262 padding: 0 8px;
263
264 .tools_btns {
265 padding: 0px 0 0;
266 }
267 }
268
269 .table_panel_wrap {
270 width: 100%;
271 height: calc(100% - 84px);
272 padding: 0px 8px 0;
273 }
274 </style>
1 <route lang="yaml">
2 name: priceConfig
3 </route>
4
5 <script lang="ts" setup name="priceConfig">
6 import { ref } from 'vue';
7 import TableTools from '@/components/Tools/table_tools.vue';
8 import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
9 import { ElMessage, ElMessageBox } from "element-plus";
10 import { CirclePlus } from "@element-plus/icons-vue";
11 import { useRouter, useRoute } from "vue-router";
12 import useUserStore from "@/store/modules/user";
13 import useDataAssetStore from "@/store/modules/dataResource";
14 import { getAllFlowData } from '@/api/modules/configService';
15 import {
16 getConfigureList,
17 deleteConfigure,
18 } from '@/api/modules/dataPricing';
19
20 const router = useRouter();
21 const userStore = useUserStore()
22 const assetStore = useDataAssetStore();
23 const userData = JSON.parse(userStore.userData)
24 const { proxy } = getCurrentInstance() as any;
25
26 const searchItemList = ref([
27 {
28 type: "input",
29 label: "",
30 field: "modelName",
31 default: "",
32 placeholder: "定价模型名称",
33 clearable: true,
34 },
35 {
36 type: "select",
37 label: "",
38 field: "institutionType",
39 placeholder: "机构类型",
40 default: "",
41 options: [],
42 clearable: true,
43 }
44 ]);
45
46 const typeMap = ref({});
47 const tableData: any = ref([]);
48 const selectRowData: any = ref([])
49 const currTableData: any = ref({});
50 const page: any = ref({
51 ...commonPageConfig,
52 modelName: '',
53 institutionType: ''
54 });
55 const tableInfo = ref({
56 id: 'api-data-table',
57 rowKey: 'guid',
58 loading: false,
59 fields: [
60 { label: "序号", type: "index", width: TableColumnWidth.INDEX, align: "center" },
61 { label: "定价模型名称", field: "modelName", width: 200 },
62 {
63 label: "机构类型", field: "institutionType", width: 120, getName: (scope) => {
64 return filterVal(scope.row.institutionType, 'institutionType')
65 }
66 },
67 {
68 label: "启用状态", field: "bizState", type: 'tag', width: 120, align: 'center', getName: (scope) => {
69 return scope.row.bizState == 'Y' ? '启用' : '停用';
70 }, tagType: (scope) => {
71 return scope.row.bizState == 'Y' ? 'success' : 'info';
72 }
73 },
74 { label: "创建人", field: "createUserName", width: 120 },
75 { label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME },
76 ],
77 data: tableData.value,
78 page: {
79 type: "normal",
80 rows: 0,
81 ...page.value,
82 },
83 actionInfo: {
84 label: "操作",
85 type: "btn",
86 isMore: false,
87 width: 120,
88 btns: [
89 { label: "编辑", value: "edit" },
90 { label: "删除", value: "del" }
91 ]
92 }
93 });
94
95 // 过滤
96 const filterVal = (val, name) => {
97 if(typeMap.value[name]){
98 const data = typeMap.value[name].find(item => item.value == val);
99 return data?.label || '--';
100 }
101 };
102
103 // 获取需求类型
104 const getDataType = (dictType, fieldName) => {
105 getAllFlowData(dictType).then((res: any) => {
106 if (res.code == proxy.$passCode) {
107 const data = res.data || [];
108 typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
109 let item = searchItemList.value.find(item => item.field == fieldName);
110 item && (item.options = data);
111 } else {
112 proxy.$ElMessage.error(res.msg);
113 }
114 })
115 }
116
117 const toSearch = (val: any, clear: boolean = false) => {
118 page.value.curr = 1;
119 if (clear) {
120 searchItemList.value.map((item) => (item.default = ""));
121 page.value.modelName = '';
122 page.value.institutionType = '';
123 } else {
124 page.value.modelName = val.modelName || '';
125 page.value.institutionType = val.institutionType || '';
126 }
127 getTableData();
128 };
129
130 const getTableData = () => {
131 tableInfo.value.loading = true;
132 getConfigureList({
133 pageSize: page.value.limit,
134 pageIndex: page.value.curr,
135 modelName: page.value.modelName,
136 institutionType: page.value.institutionType,
137 }).then((res: any) => {
138 tableInfo.value.loading = false;
139 if (res.code == proxy.$passCode) {
140 const data = res.data || {};
141 tableInfo.value.data = data.records || []
142 tableInfo.value.page.limit = data.pageSize
143 tableInfo.value.page.curr = data.pageIndex
144 tableInfo.value.page.rows = data.totalRows
145 } else {
146 proxy.$ElMessage.error(res.msg);
147 }
148 })
149 }
150
151 const tablePageChange = (info) => {
152 page.value.curr = Number(info.curr);
153 page.value.limit = Number(info.limit);
154 tableInfo.value.page.limit = page.value.limit;
155 tableInfo.value.page.curr = page.value.curr;
156 getTableData();
157 };
158
159 const tableBtnClick = (scope, btn) => {
160 const type = btn.value;
161 const row = scope.row;
162 currTableData.value = row;
163 if (type === 'edit') { // 编辑
164 router.push(
165 {
166 name: 'priceModel',
167 query: {
168 guid: row.guid,
169 name: row.modelName,
170 type
171 }
172 }
173 );
174 } else if (type === 'del') { // 删除
175 open('确定要删除该条数据吗?', 'warning');
176 }
177 };
178
179 const open = (msg, type, isBatch = false) => {
180 ElMessageBox.confirm(msg, "提示", {
181 confirmButtonText: "确定",
182 cancelButtonText: "取消",
183 type: type,
184 }).then(() => {
185 let guids = [currTableData.value.guid]
186 if (isBatch) {
187 guids = selectRowData.value
188 }
189 deleteConfigure(guids).then((res: any) => {
190 if (res.code == proxy.$passCode) {
191 getTableData();
192 ElMessage({
193 type: "success",
194 message: "删除成功",
195 });
196 } else {
197 proxy.$ElMessage.error(res.msg);
198 }
199 });
200 });
201 };
202
203 const addDisease = () => {
204 router.push(
205 {
206 name: 'priceModel',
207 query: {
208 type: 'create'
209 }
210 }
211 );
212 }
213
214 onBeforeMount(() => {
215 getDataType('机构类型', 'institutionType')
216 });
217
218 onActivated(() => {
219 if (assetStore.isRefresh) {//如果是首次加载,则不需要调用
220 toSearch(null, true);
221 assetStore.set(false);
222 }
223 })
224
225 </script>
226
227 <template>
228 <div class="container_wrap">
229 <div class="table_tool_wrap">
230 <TableTools :searchItems="searchItemList" :searchId="'data-source-search'" @search="toSearch" />
231 <div class="tools_btns">
232 <el-button type="primary" @click="addDisease" v-preReClick>新增</el-button>
233 </div>
234 </div>
235 <div class="table_panel_wrap">
236 <Table :tableInfo="tableInfo" @tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
237 </div>
238 </div>
239 </template>
240
241 <style lang="scss" scoped>
242 .table_tool_wrap {
243 width: 100%;
244 height: 84px !important;
245 padding: 0 8px;
246
247 .tools_btns {
248 padding: 0px 0 0;
249 }
250 }
251
252 .table_panel_wrap {
253 width: 100%;
254 height: calc(100% - 84px);
255 padding: 0px 8px 0;
256 }
257 </style>
1 <route lang="yaml">
2 name: priceModel
3 </route>
4
5 <script lang="ts" setup name="priceModel">
6 import { ref, onMounted } from "vue";
7 import { useRouter, useRoute } from "vue-router";
8 import { ElMessage, ElMessageBox, rowProps } from "element-plus";
9 import { Plus, CirclePlus, Guide } from "@element-plus/icons-vue";
10 import useUserStore from "@/store/modules/user";
11 import useDataAssetStore from "@/store/modules/dataResource";
12 import { getAllFlowData } from '@/api/modules/configService';
13 import { changeNum } from "@/utils/common";
14 import {
15 getDemandTreeList,
16 getConfigureDetail,
17 saveConfigure,
18 updateConfigure
19 } from '@/api/modules/dataPricing';
20
21 const { proxy } = getCurrentInstance() as any;
22 const router = useRouter();
23 const route = useRoute();
24 const userStore = useUserStore();
25 const assetStore = useDataAssetStore();
26 const fullPath = route.fullPath;
27 const userData = JSON.parse(localStorage.userData);
28 const guid = route.query.guid;
29 const modelName = route.query.name;
30
31 const loading = ref(false);
32 const flowDetail: any = ref({});
33 const typeMap: any = ref({});
34 const expand1 = ref(true)
35 const expand2 = ref(true)
36
37 // 基础设置
38 const baseConfigFormRef = ref();
39 const baseConfigFormItems: any = ref([
40 {
41 label: '模型名称',
42 type: 'input',
43 placeholder: '请输入',
44 field: 'modelName',
45 default: '',
46 clearable: true,
47 required: true
48 },
49 {
50 label: '机构类型',
51 type: 'select',
52 placeholder: '请选择',
53 field: 'institutionType',
54 default: '',
55 options: [],
56 clearable: true,
57 required: true,
58 },
59 {
60 label: '启用状态',
61 type: 'switch',
62 field: 'bizState',
63 default: 'Y',
64 placeholder: '请选择',
65 activeValue: 'Y',
66 inactiveValue: 'N',
67 switchWidth: 32,
68 },
69 {
70 label: '模型公式',
71 type: 'input',
72 placeholder: '请输入',
73 field: 'modelFormula',
74 default: '',
75 maxlength: 500,
76 clearable: true,
77 required: true,
78 block: true,
79 },
80 ])
81 const baseConfigFormRules = ref({
82 modelName: [
83 { required: true, trigger: 'blur', message: "请填写模型名称" }
84 ],
85 institutionType: [
86 { required: true, trigger: 'change', message: "请选择机构类型" }
87 ],
88 modelFormula: [
89 { required: true, trigger: 'change', message: "请填写模型公式" },
90 {
91 validator: (rule, value, callback) => {
92 validateFormula(value, callback);
93 },
94 trigger: 'blur'
95 }
96 ],
97 });
98 const baseConfigForm = ref({
99 items: baseConfigFormItems.value,
100 rules: baseConfigFormRules.value,
101 })
102
103
104 // 校验模型公式
105 const validateFormula = (value, callback) => {
106 const baseConfigFormObj = baseConfigFormRef.value;
107 const baseConfigFormInfo = baseConfigFormObj.formInline;
108 const formula = value || baseConfigFormInfo.modelFormula;
109
110 if (!formula.trim()) {
111 callback(new Error('请输入模型公式'));
112 return;
113 }
114
115 const dimensions = signatoryTableList.value.map(s => s.dimensionalityName);
116
117 /* 第一步:检查维度是否存在 */
118 const dimMatches = [...formula.matchAll(/"([^"]+)"/g)];
119 for (const match of dimMatches) {
120 const dim = match[1]; // 获取引号内的内容
121 if (!dimensions.includes(dim)) {
122 callback(new Error(`维度"${dim}"不存在`));
123 return;
124 }
125 }
126
127 /* 第二步:检查维度间是否有运算符 */
128 if (/"([^"]+)"\s*"([^"]+)"/.test(formula)) {
129 callback(new Error('维度之间必须使用运算符连接'));
130 return;
131 }
132
133 /* 第三步:检查运算符使用是否合法 */
134 // 检查连续运算符
135 if (/([+\-*\/^]\s*){2,}/.test(formula.replace(/\s+/g, ''))) {
136 callback(new Error('不允许连续使用运算符'));
137 return;
138 }
139 // 检查运算符后无参数
140 if (/[+\-*\/^]\s*["(]*(\)|$)/.test(formula.replace(/\s+/g, ''))) {
141 callback(new Error('公式不完整'));
142 return;
143 }
144
145 /* 第四步:替换变量并校验公式结构 */
146 const dimMap = new Map();
147 dimMatches.forEach((match, i) => {
148 dimMap.set(match[0], `a${i + 1}`); // 创建维度到变量的映射
149 });
150
151 let formulaWithVars = formula;
152 dimMap.forEach((varName, dim) => {
153 formulaWithVars = formulaWithVars.split(dim).join(varName);
154 });
155
156 // 基础字符检查
157 const validChars = /^[\sa\d+\-*\/^().]+$/;
158 if (!validChars.test(formulaWithVars)) {
159 callback(new Error('公式包含非法字符'));
160 return;
161 }
162
163 /* 增强的括号匹配检查(支持多种括号类型)*/
164 const bracketPairs = {
165 '(': ')',
166 '[': ']',
167 '{': '}',
168 '<': '>'
169 };
170 const stack = [];
171
172 for (const char of formulaWithVars) {
173 if (bracketPairs[char]) {
174 stack.push(char);
175 } else if (Object.values(bracketPairs).includes(char)) {
176 if (stack.length === 0 || bracketPairs[stack.pop()] !== char) {
177 callback(new Error('括号使用不匹配或未正确闭合'));
178 return;
179 }
180 }
181 }
182
183 if (stack.length > 0) {
184 callback(new Error('括号使用不匹配或未正确闭合'));
185 return;
186 }
187
188 callback(); // 所有检查通过
189 };
190
191 // 维度设置
192 const currTableData: any = ref({});
193 const currSignatoryData: any = ref({});
194 const signatoryTableList: any = ref([]);
195 const pricingDimensionality: any = ref([]);
196
197 // 维度表单
198 const signatoryFormItems: any = ref([
199 {
200 label: '维度名称',
201 type: 'input',
202 placeholder: '请输入',
203 field: 'dimensionalityName',
204 default: '',
205 maxlength: 50,
206 clearable: true,
207 required: true,
208 },
209 {
210 label: '计算公式',
211 type: 'select',
212 placeholder: '请选择',
213 field: 'computationalFormula',
214 default: '',
215 options: [],
216 clearable: true,
217 required: true,
218 },
219 {
220 label: '权重(%)',
221 type: 'input',
222 placeholder: '请输入',
223 field: 'weight',
224 default: '',
225 inputType: 'factorNumber',
226 maxlength: 10,
227 clearable: true,
228 },
229 {
230 label: '启用状态',
231 type: 'switch',
232 field: 'invocationStatus',
233 default: 'Y',
234 placeholder: '请选择',
235 activeValue: 'Y',
236 inactiveValue: 'N',
237 switchWidth: 32,
238 },
239 {
240 label: '维度说明',
241 type: 'textarea',
242 placeholder: '请输入',
243 field: 'remark',
244 default: '',
245 maxlength: 500,
246 clearable: true,
247 block: true,
248 },
249 {
250 label: '自定义公式',
251 type: 'textarea',
252 placeholder: '请输入',
253 field: 'customize',
254 default: '',
255 maxlength: 500,
256 clearable: true,
257 block: true,
258 visible: false,
259 },
260 ])
261 const signatoryFormRules = ref({
262 dimensionalityName: [
263 {
264 validator: (rule: any, value: any, callback: any) => {
265 if (!value) {
266 callback(new Error("请填写维度名称"));
267 } else {
268 if (drawerInfo.value.type.indexOf('edit') > -1 && currSignatoryData.value.dimensionalityName == value) {
269 callback();
270 return
271 }
272 const dimName = signatoryTableList.value.map(item => item.dimensionalityName);
273 if (dimName.indexOf(value) != -1) {
274 callback(new Error("该名称已存在"));
275 } else {
276 callback();
277 }
278 }
279 },
280 trigger: "blur",
281 },
282 ],
283 computationalFormula: [
284 { required: true, message: '请选择计算公式', trigger: 'change' }
285 ],
286 });
287
288 // 指标表单
289 const treeData = ref([]);
290 const targetFormItems: any = ref([
291 {
292 label: '指标名称',
293 type: 'input',
294 placeholder: '请输入',
295 field: 'targetName',
296 default: '',
297 maxlength: 50,
298 clearable: true,
299 required: true,
300 },
301 {
302 label: '指标类型',
303 type: 'select',
304 placeholder: '请选择',
305 field: 'targetType',
306 default: '',
307 options: [],
308 clearable: true,
309 required: true,
310 },
311 {
312 label: '权重(%)',
313 type: 'input',
314 placeholder: '请输入',
315 field: 'weight',
316 default: '',
317 inputType: 'factorNumber',
318 maxlength: 10,
319 clearable: true,
320 required: true,
321 visible: false,
322 },
323 {
324 label: '是否展示',
325 type: 'switch',
326 field: 'isShow',
327 default: 'Y',
328 placeholder: '请选择',
329 activeValue: 'Y',
330 inactiveValue: 'N',
331 switchWidth: 32,
332 disabled: false,
333 style: {
334 width: 'calc(25% - 4px)',
335 'margin-left': '8px'
336 }
337 },
338 {
339 label: '是否输入参数',
340 type: 'switch',
341 field: 'isInputParameter',
342 default: 'Y',
343 placeholder: '请选择',
344 activeValue: 'Y',
345 inactiveValue: 'N',
346 switchWidth: 32,
347 style: {
348 width: 'calc(25% - 4px)'
349 }
350 },
351 {
352 label: '默认值',
353 type: 'input',
354 placeholder: '请输入',
355 field: 'defaultValue',
356 default: '',
357 inputType: 'factorNumber',
358 maxlength: 18,
359 clearable: true,
360 required: false
361 },
362 {
363 label: '选择字典',
364 type: 'select',
365 placeholder: '请选择',
366 field: 'dictionaryType',
367 default: '',
368 options: [],
369 clearable: true,
370 required: true,
371 visible: false,
372 },
373 {
374 label: '功能名称',
375 type: 'select',
376 placeholder: '请选择',
377 field: 'functionName',
378 default: '',
379 options: [],
380 clearable: true,
381 required: true,
382 visible: false,
383 },
384 {
385 label: '选择需求表',
386 type: 'select',
387 placeholder: '请选择',
388 field: 'demandTableGuid',
389 default: '',
390 options: [],
391 props: {
392 label: "menuName",
393 value: "guid",
394 },
395 filterable: true,
396 clearable: true,
397 required: true,
398 visible: false,
399 },
400 {
401 label: '公式设置',
402 type: 'textarea',
403 placeholder: '请输入',
404 field: 'formulaSetting',
405 default: '',
406 resize: 'vertical',
407 maxlength: 500,
408 clearable: true,
409 block: true,
410 required: true,
411 },
412 ])
413 const targetFormRules = ref({
414 targetName: [
415 {
416 validator: (rule: any, value: any, callback: any) => {
417 if (!value) {
418 callback(new Error("请填写指标名称"));
419 } else {
420 if (drawerInfo.value.type.indexOf('edit') > -1 && currTableData.value.targetName == value) {
421 callback();
422 return
423 }
424 const dimName = currSignatoryData.value.tableInfo.data.map(item => item.targetName);
425 if (dimName.indexOf(value) != -1) {
426 callback(new Error("该名称已存在"));
427 } else {
428 callback();
429 }
430 }
431 },
432 trigger: "blur",
433 },
434 ],
435 targetType: [
436 { required: true, message: '请选择指标类型', trigger: 'change' }
437 ],
438 dictionaryType: [
439 { required: true, message: '请选择数据字典', trigger: 'change' }
440 ],
441 functionName: [
442 { required: true, message: '请选择功能名称', trigger: 'change' }
443 ],
444 formulaSetting: [
445 { required: true, message: '请填写公式设置', trigger: 'blur' }
446 ],
447 demandTableGuid: [
448 { required: true, message: '请选择需求表', trigger: 'change' }
449 ],
450 weight: [
451 { required: true, message: '请填写权重', trigger: 'change' },
452 {
453 validator: (rule: any, value: any, callback: any) => {
454 if (!value) {
455 callback(new Error("请填写权重"));
456 } else {
457 if (drawerInfo.value.type.indexOf('edit') > -1 && currTableData.value.weight == value) {
458 callback();
459 return
460 }
461 setTimeout(() => {
462 let formula: any = [];
463 if (drawerInfo.value.type.indexOf('edit') > -1) {
464 formula = currSignatoryData.value.tableInfo.data.map(p => p.targetName == currTableData.value.targetName ? value : p.weight || 0);
465 } else {
466 formula = currSignatoryData.value.tableInfo.data.map(p => p.weight || 0);
467 formula.push(value);
468 }
469 const isOver = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) + parseFloat(currentValue), 0); // 初始值为0
470 if (isOver > 100) {
471 callback(new Error("该维度权重和已超过100%,请重新填写"));
472 } else {
473 callback();
474 }
475 }, 200);
476 }
477 },
478 trigger: "blur",
479 },
480 ],
481 defaultValue: [
482 { required: true, message: '请填写默认值', trigger: 'blur' }
483 ],
484 });
485
486 const dictionaryType = ref('');
487 const showFactorTable = ref(false);
488 const mergeRowCount: any = ref({});
489 const rowCount = {
490 level: { index: 0, rowspan: [] },
491 };
492 const mergeTableData = [
493 { id: '1-1', level: '一级', grade: '甲等', factor: '' },
494 { id: '1-2', level: '一级', grade: '乙等', factor: '' },
495 { id: '1-3', level: '一级', grade: '丙等', factor: '' },
496 { id: '2-1', level: '二级', grade: '甲等', factor: '' },
497 { id: '2-2', level: '二级', grade: '乙等', factor: '' },
498 { id: '2-3', level: '二级', grade: '丙等', factor: '' },
499 { id: '3-1', level: '三级', grade: '甲等', factor: '' },
500 { id: '3-2', level: '三级', grade: '乙等', factor: '' },
501 { id: '3-3', level: '三级', grade: '丙等', factor: '' },
502 ];
503 const tableData: any = ref([]);
504
505 // 抽屉内容
506 const contents = ref({
507 target: {
508 type: "form",
509 title: "",
510 col: "span",
511 formInfo: {
512 id: "add-dict-form",
513 readonly: false,
514 items: targetFormItems.value,
515 rules: targetFormRules.value,
516 },
517 },
518 signatory: {
519 type: "form",
520 title: "",
521 col: "span",
522 formInfo: {
523 id: "add-dict-form",
524 readonly: false,
525 items: signatoryFormItems.value,
526 rules: signatoryFormRules.value,
527 },
528 }
529 })
530 const drawerInfo: any = ref({
531 visible: false,
532 direction: "rtl",
533 size: 480,
534 header: {
535 title: "新增",
536 },
537 type: "",
538 container: {
539 contents: [],
540 },
541 footer: {
542 visible: true,
543 btns: [
544 { type: "default", label: "取消", value: "cancel" },
545 { type: "primary", label: "保存", value: "submit" },
546 ],
547 },
548 });
549
550 const setTableField = (data) => {
551 tableData.value = [];
552 const dictionaryName = typeMap.value['dictionaryType'].find(item => item.value == dictionaryType.value)?.label || '';
553 const dictionaryJson = dictionaryName && dictionaryName == currTableData.value.dictionaryName ? (currTableData.value.dictionaryJson || []) : [];
554 if (dictionaryType.value == '1') {
555 const tData = JSON.parse(JSON.stringify(mergeTableData));
556 if (dictionaryJson.length) {
557 tData.map((item, i) => {
558 item.factor = dictionaryJson[i]?.value || '';
559 })
560 }
561 tableData.value = tData;
562 getMergeRow();
563 } else {
564 if (dictionaryJson.length) {
565 dictionaryJson.map(item => {
566 tableData.value.push({
567 label: item.name,
568 factor: item.value || '',
569 })
570 })
571 } else {
572 data.map((item: any) => {
573 tableData.value.push({
574 label: item.label,
575 factor: '',
576 })
577 })
578 }
579 }
580 }
581
582 const getDictionaryRuleData = () => {
583 const dictRow: any = typeMap.value['dictionaryType'].find(item => item.value == dictionaryType.value);
584 getAllFlowData(dictRow?.label).then((res: any) => {
585 if (res.code == proxy.$passCode) {
586 const data = res.data || [];
587 setTableField(data);
588 } else {
589 proxy.$ElMessage.error(res.msg);
590 }
591 })
592 }
593
594 // 设置表单信息
595 const setFormItems = (info = null, type = '') => {
596 const datas: any = info || flowDetail.value || {};
597 if (type == 'target') {
598 targetFormItems.value.map(item => {
599 item.default = datas[item.field] || '';
600 if (item.field == 'functionName') {
601 item.visible = datas.targetType == '2'
602 } else if (item.field == 'dictionaryType') {
603 dictionaryType.value = datas[item.field] || '';
604 item.visible = datas.targetType == '3'
605 showFactorTable.value = datas.targetType == '3' && datas[item.field]
606 showFactorTable.value && getDictionaryRuleData();
607 } else if (item.field == 'formulaSetting') {
608 item.visible = datas.targetType == '2' && datas.functionName == '2'
609 } else if (item.field == 'demandTableGuid') {
610 item.visible = datas.targetType == '2' && datas.functionName == '3'
611 } else if (item.field == 'isShow' || item.field == 'isInputParameter') {
612 item.default = datas[item.field] || 'Y';
613 } else if (item.field == 'isShow') {
614 item.disabled = datas.targetType == '1'
615 } else if (item.field == 'defaultValue') {
616 item.required = datas.targetType == '1';
617 targetFormRules.value.defaultValue[0].required = datas.targetType == '1';
618 }
619 })
620 } else if (type == 'signatory') {
621 signatoryFormItems.value.map(item => {
622 if (item.field == 'invocationStatus') {
623 item.default = datas[item.field] || 'Y';
624 } else if (item.field == 'customize') {
625 item.default = datas[item.field] || '';
626 item.visible = datas.computationalFormula == 'custom'
627 } else {
628 item.default = datas[item.field] || '';
629 }
630 })
631 } else {
632 baseConfigFormItems.value.map(item => {
633 if (item.field == 'modelFormula') {
634 item.default = datas[item.field] || '';
635 } else {
636 item.default = datas[item.field] || '';
637 }
638 })
639 }
640 }
641
642 // 过滤
643 const setVal = (type, row) => {
644 let formulaText = '';
645 if (!row[type] || row[type] == 'custom') {
646 formulaText = row.customize;
647 } else {
648 const pricingTargetData = row.pricingTargetRSVOS || row.tableInfo?.data || [];
649 let formula: any = [];
650 if (pricingTargetData.length) {
651 pricingTargetData.map(item => {
652 if (row[type] == '1') {
653 formula.push(`${item.targetName}*${item.weight}%`)
654 } else {
655 formula.push(`${item.targetName}`)
656 }
657 })
658 if (row[type] == '3') {
659 formulaText = `公式=${formula.join('*')}`;
660 } else {
661 formulaText = `公式=${formula.join('+')}`;
662 }
663 }
664 }
665 row.customize = formulaText;
666 pricingDimensionality.value.find(item => {
667 if (item.dimensionalityName == row.dimensionalityName) {
668 item.customize = formulaText;
669 }
670 })
671 return formulaText;
672 };
673
674 /**
675 * 传入多个promise对象,当全部结束时取消Loading
676 * @param promises 传入多个promise对象,当全部结束时取消Loading
677 */
678 const promiseList = (...promises: Promise<void>[]) => {
679 // loading方法全局封装成一个组件
680 loading.value = true;
681 try {
682 Promise.all(promises).then(res => {
683 if (guid) {
684 setFormItems();
685 setSignatoryData();
686 }
687 });
688 } catch (e) {
689 loading.value = false;
690 } finally {
691 loading.value = false;
692 }
693 };
694
695 // 获取数据字典
696 const getDataType = (dictType, fieldName) => {
697 return getAllFlowData(dictType).then((res: any) => {
698 if (res.code == proxy.$passCode) {
699 const data = res.data || [];
700 if (fieldName == 'computationalFormula') {
701 data.push({ label: '自定义', value: 'custom' })
702 typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
703 let item = signatoryFormItems.value.find(item => item.field == fieldName);
704 item && (item.options = data);
705 } else {
706 typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
707 if (fieldName == 'institutionType') {
708 let item = baseConfigFormItems.value.find(item => item.field == fieldName);
709 item && (item.options = data);
710 } else {
711 let item = targetFormItems.value.find(item => item.field == fieldName);
712 item && (item.options = data);
713 }
714 }
715 } else {
716 proxy.$ElMessage.error(res.msg);
717 }
718 })
719 }
720
721 // 初始化维度表格信息
722 const setSignatoryTableInfo = (row, isEdit = false) => {
723 const pricingTarget = row.pricingTargetRSVOS || [];
724 const fieldList: any = [
725 { label: "指标名称", field: "targetName", width: 200 },
726 {
727 label: "指标类型", field: "targetType", width: 120, getName: (scope) => {
728 return typeMap.value['targetType'].find(item => item.value == scope.row.targetType)?.label || '--';
729 }
730 },
731 {
732 label: "默认值", field: "defaultValue", width: 180, align: 'right', getName: (scope) => {
733 return changeNum(scope.row.defaultValue, 2) || '-'
734 }
735 },
736 {
737 label: "是否展示", field: "isShow", width: 100, getName: (scope) => {
738 return scope.row.isShow == 'Y' ? '是' : '否';
739 }
740 },
741 {
742 label: "是否输入参数", field: "isInputParameter", width: 140, getName: (scope) => {
743 return scope.row.isInputParameter == 'Y' ? '是' : '否';
744 }
745 }
746 ];
747 row.computationalFormula == '1' && fieldList.splice(2, 0, { label: "权重(%)", field: "weight", width: 100 });
748 if (isEdit) {
749 const rIndex = signatoryTableList.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
750 rIndex != -1 && signatoryTableList.value.splice(rIndex, 1, { ...currSignatoryData.value, ...row, tableInfo: { ...currSignatoryData.value.tableInfo, fields: fieldList } });
751 const sIndex = pricingDimensionality.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
752 sIndex != -1 && pricingDimensionality.value.splice(sIndex, 1, { ...currSignatoryData.value, ...row, tableInfo: { ...currSignatoryData.value.tableInfo, fields: fieldList } });
753 } else {
754 const tData = {
755 id: `signatory-${signatoryTableList.value.length}`,
756 rowKey: '',
757 fields: fieldList,
758 data: pricingTarget,
759 showPage: false,
760 actionInfo: {
761 label: "操作",
762 type: "btn",
763 width: 120,
764 btns: [
765 { label: "编辑", value: "edit" },
766 { label: "删除", value: "del" }
767 ]
768 }
769 };
770 signatoryTableList.value.push({
771 ...row,
772 tableInfo: tData
773 });
774 }
775 }
776
777 // 设置维度指标数据
778 const setSignatoryData = () => {
779 const pricingData = flowDetail.value.pricingDimensionalityRSVOS || [];
780 pricingDimensionality.value = pricingData;
781 pricingData.map(item => {
782 const rows = item;
783 (() => {
784 setSignatoryTableInfo(rows);
785 })()
786 })
787 }
788
789 // 获取详情
790 const getModelDetail = () => {
791 loading.value = true;
792 getConfigureDetail({ guid }).then((res: any) => {
793 if (res.code == proxy.$passCode) {
794 const data = res.data || {};
795 flowDetail.value = data;
796 getDataTypeList()
797 }
798 }).catch(() => {
799 loading.value = false;
800 })
801 }
802
803 const getDataTypeList = () => {
804 promiseList(
805 getTreeData(),
806 getDataType('机构类型', 'institutionType'),
807 getDataType('维度计算公式', 'computationalFormula'),
808 getDataType('维度指标类型', 'targetType'),
809 getDataType('系统功能', 'functionName'),
810 getDataType('选择字典', 'dictionaryType'),
811 )
812 }
813
814 // 获取需求表树形数据
815 const getTreeData = () => {
816 return getDemandTreeList({ pageIndex: 1, pageSize: 100000, isCatalog: 'N' }).then((res: any) => {
817 if (res.code == proxy.$passCode) {
818 const data = res.data?.records || [];
819 treeData.value = JSON.parse(JSON.stringify(data));
820 const item = targetFormItems.value.find(item => item.field == 'demandTableGuid');
821 item && (item.options = data);
822 } else {
823 proxy.$ElMessage.error(res.msg);
824 }
825 })
826 }
827
828 const selectChange = async (val, row, info) => {
829 if (row.field == 'computationalFormula') {
830 setFormItems(info, 'signatory');
831 } else if (row.field == 'targetType' || row.field == 'dictionaryType' || row.field == 'functionName') {
832 const tInfo = { ...currTableData.value, ...info };
833 await setFormItems(tInfo, 'target');
834 if (row.field == 'targetType') {
835 targetFormItems.value[3].default = val == '1' ? 'N' : 'Y';
836 }
837 }
838 }
839
840 const inputChange = (val, scope, field) => {
841 let row = scope.row;
842 let strArr = val.split(".");
843 if (strArr.length > 1) {
844 let right = strArr[1];
845 if (right === "" || right.length < 2) {
846 row[field] = val = parseFloat(val || 0).toFixed(2);
847 }
848 } else {
849 row[field] = val = parseFloat(val || 0).toFixed(2);
850 }
851 }
852
853 /** 输入框输入触发事件 */
854 const inputEventChange = (val, scope, field) => {
855 let row = scope.row;
856 row[field] = row[field].toString().replace(/[^\d.]/g, "")
857 row[field] = row[field].toString().replace(/\.{2,}/g, ".")
858 row[field] = row[field].toString().replace(".", "$#$").replace(/\./g, "").replace("$#$", ".")
859 row[field] = row[field].toString().replace(/^(\-)*(\d+)\.(\d\d\d\d\d\d).*$/, "$1$2.$3")
860 row[field] = row[field].toString().replace(/^\D*(\d{0,12}(?:\.\d{0,2})?).*$/g, "$1")
861 }
862
863 // 设置表格合并下标
864 const getMergeRow = () => {
865 mergeRowCount.value = JSON.parse(JSON.stringify(rowCount));
866 let list = tableData.value;
867 for (var i = 0; i < list.length; i++) {
868 if (i === 0) {
869 //第一个数据 默认合并1行,开始位置下标默认为0
870 for (var m in mergeRowCount.value) {
871 mergeRowCount.value[m].rowspan.push(1);
872 mergeRowCount.value[m].index = 0;
873 }
874 } else {
875 // 根据拥有子级数量进行合并1
876 for (var m in mergeRowCount.value) {
877 let mergeRow = mergeRowCount.value[m];
878 if (list[i][m] && list[i][m] === list[i - 1][m]) {
879 mergeRow.rowspan[mergeRow.index] += 1;
880 mergeRow.rowspan.push(0);
881 } else {
882 mergeRow.rowspan.push(1);
883 mergeRow.index = i;
884 }
885 }
886 }
887 }
888 }
889 // 表格行合并
890 const tableSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
891 if (columnIndex === 0) {
892 const mergeInfo = mergeRowCount.value.level;
893 const rowspan = mergeInfo.rowspan[rowIndex];
894 if (rowspan > 0) {
895 return {
896 rowspan,
897 colspan: 1,
898 };
899 } else {
900 return {
901 rowspan: 0,
902 colspan: 0,
903 };
904 }
905 }
906 }
907
908 const toPath = () => {
909 userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
910 assetStore.set(true);
911 router.push({
912 name: 'priceConfig',
913 })
914 }
915
916 const switchChange = (val, index) => {
917 pricingDimensionality.value[index].invocationStatus = val;
918 }
919
920 const btnClick = async (btn, row: any = null) => {
921 const type = btn.value;
922 if (type == 'dim') {
923 const baseConfigFormObj = baseConfigFormRef.value;
924 const baseConfigFormEl = baseConfigFormObj.ruleFormRef;
925 const baseConfigFormInfo = baseConfigFormObj.formInline;
926 await setFormItems(baseConfigFormInfo);
927 baseConfigFormItems.value.at(-1).default = baseConfigFormInfo.modelFormula ? `${baseConfigFormInfo.modelFormula}"${row.dimensionalityName}"` : `"${row.dimensionalityName}"`;
928 // 触发校验
929 setTimeout(() => {
930 baseConfigFormEl.validateField('modelFormula');
931 }, 200);
932 } else if (type == 'add-target') {
933 currSignatoryData.value = row;
934 currTableData.value = {};
935 const tData = currSignatoryData.value.tableInfo.data;
936 await setFormItems(null, 'target');
937 drawerInfo.value.type = type;
938 drawerInfo.value.header.title = '新增指标';
939 targetFormItems.value[2].visible = row.computationalFormula == '1';
940 targetFormItems.value.at(-2).options.map(o => {
941 const fData = tData.filter(t => t.targetType == '2' && t.functionName == '3');
942 o.disabled = fData.find(f => f.demandTableGuid == o.guid)? true: false;
943 });
944 drawerInfo.value.container.contents[0] = contents.value.target;
945 tableData.value = [];
946 drawerInfo.value.visible = true;
947 } else if (type == 'add-signatory') {
948 currSignatoryData.value = {};
949 currTableData.value = {};
950 showFactorTable.value = false;
951 await setFormItems(null, 'signatory');
952 drawerInfo.value.type = type;
953 drawerInfo.value.header.title = '新增维度';
954 drawerInfo.value.container.contents[0] = contents.value.signatory;
955 drawerInfo.value.visible = true;
956 } else if (type == 'edit-signatory') {
957 currSignatoryData.value = row;
958 currTableData.value = {};
959 showFactorTable.value = false;
960 await setFormItems(row, 'signatory');
961 drawerInfo.value.type = type;
962 drawerInfo.value.header.title = '编辑维度';
963 drawerInfo.value.container.contents[0] = contents.value.signatory;
964 drawerInfo.value.visible = true;
965 } else if (type == 'del-signatory') {
966 currSignatoryData.value = row;
967 open('确定要删除该条维度数据吗?', 'warning', 'signatory');
968 } else if (type == 'submit') {
969 const baseConfigFormObj = baseConfigFormRef.value;
970 const baseConfigFormEl = baseConfigFormObj.ruleFormRef;
971 const baseConfigFormInfo = baseConfigFormObj.formInline;
972 baseConfigFormEl.validate((valid, errorItem) => {
973 if (valid) {
974 const pricingDimensionalityData = pricingDimensionality.value.map((item, i) => {
975 item.orderNum = i + 1;
976 const pricingTargetData = item.pricingTargetRSVOS || item.pricingTargetRQVOS || [];
977 item.pricingTargetRQVOS = pricingTargetData.map((targetItem, t) => {
978 targetItem.orderNum = t + 1;
979 delete targetItem.tableInfo;
980 return targetItem;
981 })
982 delete item.pricingTargetRSVOS;
983 return item;
984 })
985 loading.value = true;
986 let params = {
987 ...baseConfigFormInfo,
988 tenantGuid: userData.tenantGuid,
989 pricingDimensionalityRQVOS: pricingDimensionalityData,
990 };
991 if (guid) {
992 params.guid = guid
993 updateConfigure(params).then((res: any) => {
994 loading.value = false;
995 if (res.code == proxy.$passCode) {
996 ElMessage({
997 type: "success",
998 message: guid ? "编辑定价配置成功" : "新增定价配置成功",
999 });
1000 toPath()
1001 } else {
1002 proxy.$ElMessage.error(res.msg);
1003 }
1004 }).catch(() => {
1005 loading.value = false;
1006 });
1007 } else {
1008 saveConfigure(params).then((res: any) => {
1009 loading.value = false;
1010 if (res.code == proxy.$passCode) {
1011 ElMessage({
1012 type: "success",
1013 message: guid ? "编辑定价配置成功" : "新增定价配置成功",
1014 });
1015 toPath()
1016 } else {
1017 proxy.$ElMessage.error(res.msg);
1018 }
1019 }).catch(() => {
1020 loading.value = false;
1021 });
1022 }
1023 } else {
1024 expand1.value = true;
1025 var obj = Object.keys(errorItem);
1026 baseConfigFormEl.scrollToField(obj[0]);
1027 }
1028 });
1029 } else if (type == 'cancel') {
1030 ElMessageBox.confirm(
1031 "当前页面尚未保存,确定关闭吗?",
1032 "提示",
1033 {
1034 confirmButtonText: "确定",
1035 cancelButtonText: "取消",
1036 type: "warning",
1037 }
1038 ).then(() => {
1039 toPath()
1040 }).catch(() => {
1041 ElMessage({
1042 type: "info",
1043 message: "已取消",
1044 });
1045 });
1046 }
1047 }
1048
1049 const tableBtnClick = async (scope, btn, lData: any = null) => {
1050 const type = btn.value;
1051 const row = scope.row;
1052 currTableData.value = row;
1053 if (type === 'edit') { // 编辑
1054 currSignatoryData.value = lData;
1055 const tData = currSignatoryData.value.tableInfo.data;
1056 await setFormItems(row, 'target');
1057 drawerInfo.value.type = 'edit-target';
1058 drawerInfo.value.header.title = '编辑指标';
1059 targetFormItems.value[2].visible = lData.computationalFormula == '1';
1060 targetFormItems.value.at(-2).options.map(o => {
1061 const fData = tData.filter(t => t.targetType == '2' && t.functionName == '3');
1062 o.disabled = fData.find(f => f.demandTableGuid == o.guid) ? true: false;
1063 });
1064 drawerInfo.value.container.contents[0] = contents.value.target;
1065 drawerInfo.value.visible = true;
1066 } else if (type === 'del') { // 删除
1067 currSignatoryData.value = lData;
1068 open('确定要删除该条数据吗?', 'warning', 'target');
1069 }
1070 };
1071
1072
1073 const open = (msg, type, target) => {
1074 ElMessageBox.confirm(msg, "提示", {
1075 confirmButtonText: "确定",
1076 cancelButtonText: "取消",
1077 type: type,
1078 }).then(() => {
1079 if (target == 'signatory') {
1080 const tIndex = signatoryTableList.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
1081 tIndex != -1 && signatoryTableList.value.splice(tIndex, 1);
1082 const sIndex = pricingDimensionality.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
1083 sIndex != -1 && pricingDimensionality.value.splice(sIndex, 1);
1084 } else if (target == 'target') {
1085 const signatoryRow = signatoryTableList.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
1086 if (signatoryRow) {
1087 const tIndex = signatoryRow.tableInfo.data.findIndex(t => t.targetName == currTableData.value.targetName);
1088 tIndex != -1 && signatoryRow.tableInfo.data.splice(tIndex, 1);
1089 }
1090 const signatoryParams = pricingDimensionality.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
1091 if (signatoryParams) {
1092 const sIndex = signatoryParams.pricingTargetRSVOS.findIndex(s => s.targetName == currTableData.value.targetName);
1093 sIndex != -1 && signatoryParams.pricingTargetRSVOS.splice(sIndex, 1);
1094 }
1095 }
1096 });
1097 };
1098 const drawerBtnClick = async (btn, info) => {
1099 if (btn.value == "submit") {
1100 let params = { ...info };
1101 if (drawerInfo.value.type == 'add-signatory') {// 新增维度
1102 setSignatoryTableInfo(params);
1103 pricingDimensionality.value.push({
1104 ...params,
1105 pricingTargetRSVOS: []
1106 })
1107 } else if (drawerInfo.value.type == 'edit-signatory') {// 编辑维度
1108 setSignatoryTableInfo(params, true);
1109 } else if (drawerInfo.value.type == 'add-target') {// 新增指标
1110 let factorFull = true;
1111 const dictionaryData = tableData.value.map((d: any) => {
1112 if (dictionaryType.value && !d.factor) {
1113 factorFull = false;
1114 }
1115 if (dictionaryType.value == '1') {
1116 return { name: `${d.level}${d.grade}`, value: d.factor || '' }
1117 } else {
1118 return { name: `${d.label}`, value: d.factor || '' }
1119 }
1120 })
1121 if (dictionaryType.value && !factorFull) {
1122 ElMessage({
1123 type: "error",
1124 message: '请完善字典因子',
1125 });
1126 return;
1127 }
1128 const dictionaryName = typeMap.value['dictionaryType'].find(item => item.value == params.dictionaryType)?.label || '';
1129 const sArr = signatoryTableList.value.map(item => {
1130 if (item.dimensionalityName == currSignatoryData.value.dimensionalityName) {
1131 item.tableInfo.data.push({ ...params, dictionaryJson: dictionaryData, dictionaryName });
1132 }
1133 return item;
1134 })
1135 signatoryTableList.value = sArr;
1136 let signatoryParams = pricingDimensionality.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
1137 if (signatoryParams) {
1138 const sData = signatoryParams.pricingTargetRSVOS.find(s => s.targetName == params.targetName)
1139 !sData && signatoryParams.pricingTargetRSVOS.push({ ...params, dictionaryJson: dictionaryData, dictionaryName })
1140 }
1141 } else if (drawerInfo.value.type == 'edit-target') {// 编辑指标
1142 let factorFull = true;
1143 const dictionaryData = tableData.value.map((d: any) => {
1144 if (dictionaryType.value && !d.factor) {
1145 factorFull = false;
1146 }
1147 if (dictionaryType.value == '1') {
1148 return { name: `${d.level}${d.grade}`, value: d.factor || '' }
1149 } else {
1150 return { name: `${d.label}`, value: d.factor || '' }
1151 }
1152 })
1153 if (dictionaryType.value && !factorFull) {
1154 ElMessage({
1155 type: "error",
1156 message: '请完善字典因子',
1157 });
1158 return;
1159 }
1160 const dictionaryName = typeMap.value['dictionaryType'].find(item => item.value == params.dictionaryType)?.label || '';
1161 const sArr = signatoryTableList.value.map(item => {
1162 if (item.dimensionalityName == currSignatoryData.value.dimensionalityName) {
1163 const tIndex = item.tableInfo.data.findIndex(t => t.targetName == currTableData.value.targetName)
1164 tIndex != -1 && item.tableInfo.data.splice(tIndex, 1, { ...params, dictionaryJson: dictionaryData, dictionaryName })
1165 }
1166 return item;
1167 })
1168 signatoryTableList.value = sArr;
1169 let signatoryParams = pricingDimensionality.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
1170 if (signatoryParams) {
1171 const sIndex = signatoryParams.pricingTargetRSVOS.findIndex(s => s.targetName == currTableData.value.targetName)
1172 sIndex != -1 && signatoryParams.pricingTargetRSVOS.splice(sIndex, 1, { ...params, dictionaryJson: dictionaryData, dictionaryName })
1173 }
1174 }
1175 drawerInfo.value.visible = false;
1176 } else {
1177 nextTick(() => {
1178 drawerInfo.value.visible = false;
1179 });
1180 }
1181 };
1182
1183 onActivated(() => {
1184 let tab: any = userStore.tabbar.find((tab: any) => tab.fullPath === router.currentRoute.value.fullPath);
1185 if (tab) {
1186 switch (route.query.type) {
1187 case 'create':
1188 tab.meta.title = `新增定价配置`;
1189 break;
1190 case 'edit':
1191 tab.meta.title = `编辑-${modelName}`;
1192 break;
1193 case 'detail':
1194 tab.meta.title = `详情-${modelName}`;
1195 break;
1196 }
1197 }
1198 })
1199
1200 onBeforeMount(() => {
1201 if (guid) {
1202 getModelDetail();
1203 } else {
1204 getDataTypeList();
1205 }
1206 })
1207
1208 onMounted(() => {
1209 })
1210 </script>
1211
1212 <template>
1213 <div class="container_wrap full" v-loading="loading">
1214 <div class="content_main panel">
1215 <ContentWrap id="contract-content-wrap" title="基础设置" expandSwicth style="margin-top: 15px" :isExpand="expand1"
1216 @expand="(v) => expand1 = v">
1217 <Form ref="baseConfigFormRef" formId="contract-content-form" :itemList="baseConfigForm.items"
1218 :rules="baseConfigForm.rules" col="col3" />
1219 <div class="signatory-tags" v-if="signatoryTableList.length">
1220 <template v-for="(item, index) in signatoryTableList" :key="'tag_' + index">
1221 <el-button v-if="item.invocationStatus == 'Y'" type="primary" @click="btnClick({ value: 'dim' }, item)">{{
1222 item.dimensionalityName }}</el-button>
1223 </template>
1224 </div>
1225 <div class="tips-text" style="color: #666; margin-bottom: 4px; font-size: 12px;">
1226 备注:模型公式是维度名称与运算符组合,如("维度1"+"维度2")/("维度3"+"维度4")*10,维度名称要用英文引号(")包裹。维度名称在添加维度后才会在公式下展示!
1227 </div>
1228 </ContentWrap>
1229 <ContentWrap id="contract-signatory-wrap" title="维度设置" expandSwicth style="margin-top: 15px" :isExpand="expand2"
1230 @expand="(v) => expand2 = v">
1231 <div class="table_panel_wrap" v-for="(item, index) in signatoryTableList" :key="'wrap_' + index">
1232 <div class="table_tool">
1233 <div class="tool_title">
1234 <div class="title_text">{{ item.dimensionalityName }}</div>
1235 <div class="title_desc"><ellipsis-tooltip :content="setVal('computationalFormula', item)"
1236 refName="tooltipOver"></ellipsis-tooltip></div>
1237 </div>
1238 <div class="tool_btns">
1239 <el-switch v-model="item.invocationStatus" inline-prompt active-value="Y" inactive-value="N"
1240 active-text="启用" inactive-text="停用" @change="val => switchChange(val, index)"
1241 style="margin-right: 8px;" />
1242 <el-button type="primary" @click="btnClick({ value: 'edit-signatory' }, item)">编辑</el-button>
1243 <el-button @click="btnClick({ value: 'del-signatory' }, item)">删除</el-button>
1244 </div>
1245 </div>
1246 <div class="table_panel">
1247 <Table :tableInfo="item.tableInfo" @tableBtnClick="(scope, btn) => tableBtnClick(scope, btn, item)" />
1248 </div>
1249 <el-button type="primary" :icon="CirclePlus" link
1250 @click="btnClick({ value: 'add-target' }, item)">新增指标</el-button>
1251 </div>
1252 <el-button class="btn-block" plain size="large" @click="btnClick({ value: 'add-signatory' })">新增维度</el-button>
1253 </ContentWrap>
1254 </div>
1255 <div class="tool_btns">
1256 <div class="btns">
1257 <el-button @click="btnClick({ value: 'cancel' })">取消</el-button>
1258 <el-button type="primary" @click="btnClick({ value: 'submit' })">提交</el-button>
1259 </div>
1260 </div>
1261 <Drawer :drawerInfo="drawerInfo" @drawerBtnClick="drawerBtnClick" @drawerSelectChange="selectChange">
1262 <template v-if="showFactorTable">
1263 <span class="required_mark" style="line-height: 21px;">字典值对应因子</span>
1264 <div class="table_panel">
1265 <el-table border :data="tableData" :span-method="tableSpanMethod" tooltip-effect="light" style="height: 100%;"
1266 v-if="dictionaryType == '1'">
1267 <el-table-column label="医院等级">
1268 <el-table-column prop="level" label="级别" width="100" />
1269 <el-table-column prop="grade" label="等次" width="100" />
1270 </el-table-column>
1271 <el-table-column prop="factor" label="因子" class-name="edit-col">
1272 <template #default="scope">
1273 <el-input v-model="scope.row.factor" placeholder="请输入"
1274 @change="(val) => inputChange(val, scope, 'factor')"
1275 @input="(val) => inputEventChange(val, scope, 'factor')" />
1276 </template>
1277 </el-table-column>
1278 </el-table>
1279 <el-table border :data="tableData" tooltip-effect="light" style="height: 100%;" v-else>
1280 <el-table-column label="字典名称" prop="label" width="140" />
1281 <el-table-column prop="factor" label="因子" class-name="edit-col">
1282 <template #default="scope">
1283 <el-input v-model="scope.row.factor" placeholder="请输入"
1284 @change="(val) => inputChange(val, scope, 'factor')"
1285 @input="(val) => inputEventChange(val, scope, 'factor')" />
1286 </template>
1287 </el-table-column>
1288 </el-table>
1289 </div>
1290 </template>
1291 </Drawer>
1292 </div>
1293 </template>
1294
1295 <style scoped lang="scss">
1296 .container_wrap {
1297 overflow: hidden;
1298
1299 .content_main {
1300 height: calc(100% - 45px);
1301 overflow: hidden auto;
1302
1303 &.panel {
1304 padding: 0 16px 16px;
1305 }
1306
1307 :deep(.el-card) {
1308 &#contract-signatory-wrap {
1309 .card-body-content {
1310 padding: 8px 16px;
1311 }
1312 }
1313 }
1314
1315 .signatory-tags {
1316 margin-top: 2px;
1317 margin-bottom: 11px;
1318 }
1319
1320 .table_panel_wrap {
1321 margin-bottom: 4px;
1322
1323 .table_tool {
1324 height: 36px;
1325 display: flex;
1326 justify-content: space-between;
1327 align-items: center;
1328
1329 .tool_title {
1330 display: flex;
1331 justify-content: start;
1332 flex: 1;
1333 }
1334
1335 .title_text {
1336 font-weight: 600;
1337 margin-right: 8px;
1338 }
1339
1340 .title_desc {
1341 color: #b2b2b2;
1342 flex: 1;
1343 overflow: hidden;
1344 white-space: nowrap;
1345 text-overflow: ellipsis;
1346 }
1347
1348 .tool_btns {
1349 margin: 0;
1350 border: none;
1351 }
1352 }
1353
1354 .table_panel {
1355 margin-bottom: 4px;
1356 height: 212px;
1357 }
1358 }
1359 }
1360
1361 .btn-block {
1362 width: 100%;
1363 margin: 16px 0 8px;
1364
1365 }
1366
1367 .tool_btns {
1368 height: 44px;
1369 margin: 0 -8px;
1370 display: flex;
1371 justify-content: center;
1372 align-items: center;
1373 border-top: 1px solid #d9d9d9;
1374 }
1375 }
1376
1377 :deep(.el-drawer) {
1378 .table_panel {
1379 th {
1380 text-align: center;
1381 }
1382
1383 .el-table__cell {
1384 &.edit-col {
1385 padding: 4px 0;
1386
1387 .cell {
1388 padding: 0 4px;
1389
1390 .el-input {
1391 height: 28px;
1392 }
1393 }
1394 }
1395 }
1396 }
1397 }
1398 </style>
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!