d98bd724 by fanguang

Merge branch 'develop' of http://117.78.60.236:8000/csbr-daop/fe-data-asset-management into develop

2 parents 34c312ec 9f02fc59
......@@ -93,7 +93,6 @@ VITE_API_CIRCULATION_URL = http://192.168.6.22:29900/circulation
#数据加工交付
VITE_APP_DATA_DELIVERY = http://192.168.6.20:38052/
# 本地访问地址
# VITE_API_CIRCULATION_URL = http://localhost:9000/circulation
......
import request from "@/utils/request";
//获取需求表树形列表
export const getDemandTreeList = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-menu/page-list`,
method: "post",
data: params,
});
};
//获取所有需求表列表
export const getDemandAll = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-menu/get-list-data`,
method: "get",
params
});
};
//新增需求列表
export const saveDemandTree = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-menu/save`,
method: "post",
data: params,
});
};
//修改需求列表
export const updateDemandTree = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-menu/update`,
method: "post",
data: params,
});
};
// 删除需求列表
export const deleteDemandTree = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-menu/delete`,
method: "delete",
data: params,
});
};
//获取需求表
export const getDemandList = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-table/page-list`,
method: "post",
data: params,
});
};
//获取需求表详情
export const getDemandDetail = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-table/detail`,
method: "get",
params,
});
};
//新增需求表
export const saveDemand = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-table/save`,
method: "post",
data: params,
});
};
//修改需求表
export const updateDemand = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-table/update`,
method: "post",
data: params,
});
};
// 删除需求表
export const deleteDemand = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-demand-table/delete`,
method: "delete",
data: params,
});
};
// 获取疾病列表
export const getDiseaseList = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/disease-manage/page-list`,
method: "post",
data: params,
});
};
//获取所有疾病列表
export const getDiseaseAll = () => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/disease-manage/get-list-data`,
method: "post"
});
};
// 获取疾病详情
export const getDiseaseDetail = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/disease-manage/detail`,
method: "get",
params,
});
};
// 新增疾病
export const saveDisease = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/disease-manage/save`,
method: "post",
data: params,
});
};
// 修改疾病
export const updateDisease = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/disease-manage/update`,
method: "post",
data: params,
});
};
// 删除疾病
export const deleteDisease = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/disease-manage/delete`,
method: "delete",
data: params,
});
};
// 获取定价配置
export const getConfigureList = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-configure/page-list`,
method: "post",
data: params,
});
};
// 获取配置详情
export const getConfigureDetail = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-configure/detail`,
method: "get",
params,
});
};
// 新增配置
export const saveConfigure = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-configure/save`,
method: "post",
data: params,
});
};
// 修改配置
export const updateConfigure = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-configure/update`,
method: "post",
data: params,
});
};
// 删除配置
export const deleteConfigure = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-configure/delete`,
method: "delete",
data: params,
});
};
// 获取数据定价
export const getPriceList = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/page-list`,
method: "post",
data: params,
});
};
// 获取数据定价详情
export const getPriceDetail = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/detail`,
method: "get",
params,
});
};
// 新增数据定价
export const savePrice = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/save`,
method: "post",
data: params,
});
};
// 修改数据定价
export const updatePrice = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/update`,
method: "post",
data: params,
});
};
// 获取数据定价结果
export const getPriceResult = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/pricing-price`,
method: "post",
data: params,
});
};
// 删除数据定价
export const deletePrice = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/delete`,
method: "delete",
data: params,
});
};
// 获取数据资源目录
export const getDamCatalogList = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/dam-catalog-grounding/not-exclude-overview-page-list`,
method: "post",
data: params,
});
};
// 获取模型相关需求表
export const getModelDemand = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/pricing-model`,
method: "get",
params,
});
};
// 获取质量模型评分
export const getModelScore = (params) => {
return request({
url: `${import.meta.env.VITE_APP_QUALITY_BASEURL}/quality-analysis-report/get-quality-score-by-dam-guid`,
method: "get",
params,
});
};
export const exportModelScore = (params) => {
return request({
url: `${import.meta.env.VITE_API_NEW_PORTAL}/pricing-data/download-template`,
method: "post",
data: params,
responseType: 'blob'
});
};
import type { RouteRecordRaw } from 'vue-router'
function Layout() {
return import('@/layouts/index.vue')
}
const routes: RouteRecordRaw[] = [
{
path: '/data-pricing/pricing-manage',
component: Layout,
meta: {
title: '定价管理',
icon: 'ep:grid',
},
children: [
{
path: 'demand-manage',
name: 'demandManage',
component: () => import('@/views/data_pricing/demandManage.vue'),
meta: {
title: '需求表管理',
breadcrumb: false,
cache: true
},
},
{
path: 'import-file-demand-manage',
name: 'importFileDemandManage',
component: () => import('@/views/importFile.vue'),
meta: {
title: '导入数据-需求表管理',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true,
activeMenu: '/data-pricing/pricing-manage/demand-manage'
}
},
{
path: 'disease-manage',
name: 'diseaseManage',
component: () => import('@/views/data_pricing/diseaseManage.vue'),
meta: {
title: '疾病管理',
breadcrumb: false,
cache: true
},
},
{
path: 'import-file-disease',
name: 'importFileDisease',
component: () => import('@/views/importFile.vue'),
meta: {
title: '导入数据-疾病管理',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true,
activeMenu: '/data-pricing/pricing-manage/disease-manage'
}
},
{
path: 'price-config',
name: 'priceConfig',
component: () => import('@/views/data_pricing/priceConfig.vue'),
meta: {
title: '定价配置',
breadcrumb: false,
cache: true
},
},
{
path: 'price-model',
name: 'priceModel',
component: () => import('@/views/data_pricing/priceModel.vue'),
meta: {
title: '新增配置',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true,
editPage: true,
activeMenu: '/data-pricing/pricing-manage/price-config'
},
beforeEnter: (to, from) => {
if (to.query.guid) {
to.meta.title = `编辑-${to.query.name}`;
} else {
to.meta.title = `新增配置`;
}
}
},
{
path: 'price-calculate',
name: 'priceCalculate',
component: () => import('@/views/data_pricing/priceCalculate.vue'),
meta: {
title: '数据定价',
breadcrumb: false,
cache: true
}
},
{
path: 'calculate-config',
name: 'calculateConfig',
component: () => import('@/views/data_pricing/calculateConfig.vue'),
meta: {
title: '新增数据定价',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true,
editPage: true,
activeMenu: '/data-pricing/pricing-manage/price-calculate'
},
beforeEnter: (to, from) => {
if (to.query.guid) {
to.meta.title = `编辑-${to.query.name}`;
} else {
to.meta.title = `新增数据定价`;
}
}
},
],
},
]
export default routes
......@@ -10,6 +10,7 @@ import DataTrustedSpace from './modules/dataTrustedSpace';
import DataAssetRegistry from './modules/dataAssetRegistry';
import DataEntry from './modules/dataEntry';
import SecurityMenu from './modules/securityMenu';
import DataPricing from './modules/dataPricing';
import useSettingsStore from '@/store/modules/settings'
......@@ -110,9 +111,10 @@ const asyncRoutes: RouteRecordRaw[] = [
...DataEntry,
...SecurityMenu,
...DataMeta,
...DataQuality,
...DataQuality,
...DataInventory,
...DataTrustedSpace
...DataTrustedSpace,
...DataPricing
]
const constantRoutesByFilesystem = generatedRoutes.filter((item) => {
......
<route lang="yaml">
name: calculateConfig
</route>
<script lang="ts" setup name="calculateConfig">
import { ref, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import useUserStore from "@/store/modules/user";
import useDataAssetStore from "@/store/modules/dataAsset";
import { getAllFlowData } from '@/api/modules/queryService';
import { getDamCatalogList } from "@/api/modules/dataPricing";
import { getRegisterCatalogDetail, getDataResourceUpSummaryList, getRegisterCatalogTableDetail } from "@/api/modules/dataResourceUpService";
import { download } from '@/utils/common'
import {
getConfigureList,
getConfigureDetail,
getDiseaseAll,
getPriceDetail,
getDemandList,
getModelScore,
savePrice,
getModelDemand,
getPriceResult,
exportModelScore
} from '@/api/modules/dataPricing';
import { changeNum } from "@/utils/common";
import { merge } from 'lodash-es';
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
const userStore = useUserStore();
const assetStore = useDataAssetStore();
const fullPath = route.fullPath;
const userData = JSON.parse(localStorage.userData);
const guid = route.query.guid;
const priceName = route.query.name;
const loading = ref(false);
const flowDetail: any = ref({});
const typeMap: any = ref({});
const expand1 = ref(true)
const expand2 = ref(true)
const expand3 = ref(true)
const demandTableList: any = ref([]);
const pricingTargetList: any = ref([]);
const demandTableFieldAllNum = ref(0);
const resourceTableAllNum = ref(0);
const resourceTableFieldAllNum = ref(0);
const modelData: any = ref({});
const pricingDimensionalityData: any = ref([]);
const dictionaryData: any = ref([]);
const diseaseData: any = ref([]);
const qualityScoreData: any = ref({});
const disScore: any = ref([]);
const exportData: any = ref([]);
const dataUsage = ref('');
// 基础设置
const baseConfigFormRef = ref();
const baseConfigFormItems: any = ref([
{
label: '模型名称',
type: 'select',
placeholder: '请选择',
field: 'modelGuid',
default: '',
options: [],
props: {
label: "modelName",
value: "guid",
},
clearable: true,
filterable: true,
required: true
},
{
label: '数据资源',
type: 'select',
placeholder: '请选择',
field: 'dataResourceGuid',
default: '',
options: [],
props: {
label: "damName",
value: "damGuid",
},
clearable: true,
filterable: true,
required: true,
},
{
label: '所属主体',
type: 'input',
placeholder: '',
field: 'belongingEntityGuid',
default: '',
options: [],
clearable: true,
disabled: true
},
{
label: '所属主题',
type: 'tree-select',
placeholder: '请选择',
field: 'belongingTheme',
default: '',
options: [],
showAllLevels: false,
checkStrictly: false,//只能选择叶子节点。
lazy: false,
props: {
label: "label",
value: "value",
children: 'childDictList'
},
filterable: true,
clearable: true,
disabled: true
},
])
const baseConfigFormRules: any = ref({
modelGuid: [
{ required: true, trigger: 'change', message: "请选择模型名称" }
],
dataResourceGuid: [
{ required: true, trigger: 'change', message: "请选择数据资源" }
],
});
const baseConfigForm = ref({
items: baseConfigFormItems.value,
rules: baseConfigFormRules.value,
})
const tableFields: any = ref([
{ label: '需求表', field: 'demandTableName', type: 'input', width: 200, disabled: true },
{ label: '数据资源表', field: 'dataTableGuid', type: 'select', width: 200 },
{ label: '表描述', field: 'tableDescription', type: 'input', width: 200, disabled: true },
{ label: '需求表权重(%)', field: 'weightDemandTable', type: 'input', width: 140, disabled: true },
])
const expendTableRef = ref();
const tableData: any = ref([]);
const tableLoading = ref(false);
const dataTransactionPrice: any = ref('');
const setFormItems = (info = null) => {
let datas: any = info || flowDetail.value || {};
const dData = datas.dictionaryJson ? JSON.parse(datas.dictionaryJson) : {};
datas = { ...datas, ...dData };
baseConfigFormItems.value.map(item => {
item.default = datas[item.field] || '';
})
nextTick(() => {
baseConfigFormRef.value.ruleFormRef?.clearValidate();
})
}
/**
* 传入多个promise对象,当全部结束时取消Loading
* @param promises 传入多个promise对象,当全部结束时取消Loading
*/
const promiseList = (...promises: Promise<void>[]) => {
// loading方法全局封装成一个组件
!guid && (loading.value = true);
try {
Promise.all(promises).then(res => {
loading.value = false;
});
} catch (e) {
loading.value = false;
} finally {
!guid && (loading.value = false);
}
};
// 获取模型
const getModel = () => {
getConfigureList({ pageSize: -1, pageIndex: 1, bizState: 'Y' }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data.records || [];
typeMap.value.modelGuid = JSON.parse(JSON.stringify(data));
let item = baseConfigFormItems.value.find(item => item.field == 'modelGuid');
item && (item.options = data);
}
})
}
// 获取所有疾病数据
const getDiseaseData = () => {
getDiseaseAll().then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
typeMap.value.diseaseGuid = JSON.parse(JSON.stringify(data));
let item = baseConfigFormItems.value.find(item => item.field == 'diseaseGuid');
if (item) {
item.options = typeMap.value['diseaseGuid'];
if (guid) {
const diseaseData = typeMap.value.diseaseGuid.find(m => m.guid == flowDetail.value.diseaseGuid);
if (!diseaseData) {
item.options.unshift({
guid: flowDetail.value.diseaseGuid,
diseaseName: flowDetail.value.diseaseName
});
}
}
}
}
})
}
// 获取数据资源
const getDataCatalog = () => {
return getDamCatalogList({ damName: "", pageIndex: 1, pageSize: -1, bizApproveState: "Y" }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data.records || [];
typeMap.value.dataResourceGuid = JSON.parse(JSON.stringify(data));
let item = baseConfigFormItems.value.find(item => item.field == 'dataResourceGuid');
if (item) {
item.options = data;
if (guid) {
const rItem = typeMap.value.dataResourceGuid.find(m => m.damGuid == flowDetail.value.dataResourceGuid);
if (!rItem) {
const rtem = { damGuid: flowDetail.value.dataResourceGuid, damName: flowDetail.value.dataResourceName };
item.options.unshift(rtem);
typeMap.value.dataResourceGuid.unshift(rtem);
}
}
}
}
})
}
// 获取数据资源主题
const getSourceThem = (dictType, fieldName) => {
return getAllFlowData({ dictType }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
let item = baseConfigFormItems.value.find(item => item.field == fieldName);
item && (item.options = data);
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
// 获取数据字典
const getDataType = (dictType, fieldName) => {
getAllFlowData({ dictType }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
let item = baseConfigFormItems.value.find(item => item.field == fieldName);
item && (item.options = data);
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
// 获取详情
const getDetail = () => {
loading.value = true;
getPriceDetail({ guid }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || {};
flowDetail.value = data;
dataTransactionPrice.value = flowDetail.value.dataTransactionPrice;
dataUsage.value = data.dataUsage || '';
const mItem = typeMap.value.modelGuid.find(m => m.guid == flowDetail.value.modelGuid);
if (!mItem) {
const mtem = { guid: flowDetail.value.modelGuid, modelName: flowDetail.value.modelName };
typeMap.value.modelGuid.unshift(mtem);
baseConfigFormItems.value[0].options.unshift(mtem);
};
getModelInfo(flowDetail.value.modelGuid);
getDataTypeList()
}
}).catch(() => {
loading.value = false;
})
}
const getDataTypeList = () => {
if (guid) {
promiseList(
getDataCatalog(),
getSourceThem('数据资产目录主题名称', 'belongingTheme'),
getQuilityModelScore(flowDetail.value.dataResourceGuid)
)
} else {
promiseList(
getDataCatalog(),
getSourceThem('数据资产目录主题名称', 'belongingTheme'),
)
}
}
const setFormItemData = () => {
let dictionaryList: any = [], diseaseList: any = [];
pricingTargetList.value.map(item => {
switch (item.targetType) {
case '2':
item.functionName == '2' && diseaseList.push(item);
break;
case '3':
dictionaryList.push(item);
break;
default:
break;
}
})
dictionaryData.value = dictionaryList;
diseaseData.value = diseaseList;
if (diseaseList.length) {
const diseaseName = flowDetail.value.diseaseName || '';
const modelGuid = flowDetail.value.modelGuid || '';
// 获取疾病得分
if (diseaseName && modelGuid) {
getTargetNum({ diseaseName, guid: modelGuid });
}
}
baseConfigFormItems.value.splice(4);
for (var r in baseConfigFormRules.value) {
if (r != 'modelGuid' && r != 'dataResourceGuid') {
delete baseConfigFormRules.value[r];
}
}
// 添加所属疾病
if (diseaseList.length > 0) {
baseConfigFormItems.value.push({
label: '所属疾病',
type: 'cascader',
placeholder: '请选择',
field: 'diseaseGuid',
default: '',
options: [],
showAllLevels: false,
props: {
checkStrictly: true,
label: "diseaseName",
value: "guid",
children: 'childList',
emitPath: false
},
filterable: true,
clearable: true,
required: true,
});
baseConfigFormRules.value.diseaseGuid = { required: true, trigger: 'change', message: "请选择所属疾病" };
if (typeMap.value['diseaseGuid'] == undefined) {
getDiseaseData();
} else {
let item = baseConfigFormItems.value.find(item => item.field == 'diseaseGuid');
if (item) {
item.options = typeMap.value['diseaseGuid'];
const diseaseData = typeMap.value.diseaseGuid.find(m => m.guid == flowDetail.value.diseaseGuid);
if (!diseaseData) {
item.options.unshift({
guid: flowDetail.value.diseaseGuid,
diseaseName: flowDetail.value.diseaseName
});
}
}
}
}
// 添加数据字典
dictionaryList.map(d => {
const dictName = d.dictionaryName;
const dictField = `dict_${d.guid}`;
baseConfigFormItems.value.push({
label: dictName,
type: 'select',
placeholder: '请输入',
field: dictField,
default: '',
options: [],
clearable: true,
filterable: true,
required: true,
});
baseConfigFormRules.value[dictField] = { required: true, trigger: 'change', message: `请选择${dictName}` };
(() => {
if (typeMap.value[dictField] == undefined) {
getDataType(dictName, dictField)
} else {
let item = baseConfigFormItems.value.find(item => item.field == dictField);
item && (item.options = typeMap.value[dictField]);
}
})()
})
setTimeout(() => {
baseConfigFormRef.value.ruleFormRef?.clearValidate();
}, 100)
}
const setdemandTableData = (mGuid = '') => {
const tList = flowDetail.value.dataPricingDemandmatchingRQVOS || demandTableList.value || [];
let tDatas: any = [];
if (guid) {
if (mGuid) {
tDatas = mGuid == flowDetail.value.modelGuid ? tList : demandTableList.value || [];
} else {
tDatas = tList;
}
} else {
tDatas = tList;
}
setTableData(JSON.parse(JSON.stringify(tDatas)))
}
const setTableData = (dataArr) => {
tableData.value.splice(0);
dataArr.map((item, i) => {
const demInfo = pricingTargetList.value.find(t => t.demandTableGuid == (item.demandTableGuid || item.guid));
const demWeight = demInfo?.weight || '';
tableData.value.push({
...item,
demandTableName: item.demandTableName || item.menuName,
dataTableGuid: item.dataTableGuid || '',
tableDescription: item.tableDescription || '',
weightDemandTable: item.weightDemandTable ? parseFloat(item.weightDemandTable).toFixed(2) : (demWeight ? parseFloat(demWeight).toFixed(2) : ''),
dataFields: item.pricingDemandFieldRQVOS || [],
dataFieldsNum: item.dataFieldsNum || 0,
})
if ((item.demandTableGuid || item.guid)) {
const rGuid = item.demandTableGuid || item.guid;
const rIndex = i;
if (!guid || (guid && rGuid != (demInfo?.demandTableGuid || ''))) {
(() => {
getDemandField(rGuid, rIndex);
})()
}
}
})
resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
return accumulator + Number(currentValue.dataFieldsNum);
}, 0);
setTimeout(() => {
tableData.value.map(t => {
expendTableRef.value.toggleRowExpansion(t);
})
}, 200)
}
// 获取模型配置信息
const getModelConfig = (mGuid) => {
return getModelDemand({ guid: mGuid }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
demandTableList.value = data.pricingDemandMenuRSVOS || [];
pricingTargetList.value = data.pricingTargetRSVOS || [];
demandTableFieldAllNum.value = data.fieldCount || 0;
}
})
}
// 获取模型详情
const getModelDetail = (mGuid) => {
return getConfigureDetail({ guid: mGuid }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
modelData.value = data;
const pricingDimensionality = data.pricingDimensionalityRSVOS || [];
let tData: any = [];
pricingDimensionality.map(p => {
p.pricingTargetRSVOS.map(t => {
tData.push({ ...p, ...t })
})
})
pricingDimensionalityData.value = tData;
}
})
}
// 获取资源详情
const getResourceDetail = (sGuid, toPromise = true) => {
const detailData = getRegisterCatalogDetail(sGuid).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || {};
baseConfigFormItems.value.map(item => {
if (item.field == 'belongingEntityGuid') {
item.default = data.tenantName || '';
} else if (item.field == 'belongingTheme') {
item.default = data.subjectDomain || '';
}
})
const damCatalogTableInfo = data.damCatalogTableInfo || [];
const damOptions = damCatalogTableInfo.map(item => {
return {
...item,
label: item.tableName,
value: item.guid
}
})
tableData.value.map((item, i) => {
item.damDataTable = JSON.parse(JSON.stringify(damOptions));
if (guid && sGuid == flowDetail.value.dataResourceGuid) {
const sData = flowDetail.value.dataPricingDemandmatchingRQVOS?.find(s => s.demandTableGuid == item.demandTableGuid);
if (sData) {
item.dataTableGuid = sData.dataTableGuid;
item.dataFields.map(f => {
const fData = sData.pricingDemandFieldRQVOS.find(t => t.guid == f.guid);
f.enName = fData?.enName || '';
f.chName = fData?.chName || '';
});
item.tableDescription = sData.tableDescription || damOptions.find(t => t.guid == sData.dataTableGuid)?.tableDescription || '';
item.dataFieldsNum = item.dataFields.filter(item => item.chName != '' && item.chName != null).length;
resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
return accumulator + Number(currentValue.dataFieldsNum);
}, 0);
}
} else {
item.dataTableGuid = '';
item.dataFields.map(f => { f.enName = ''; f.chName = '' });
item.dataFieldsNum = 0;
item.tableDescription = '';
resourceTableFieldAllNum.value = 0;
}
const dGuid = item.dataTableGuid;
const rIndex = i;
(() => {
!toPromise && dGuid && setTableRowData(dGuid, rIndex)
})()
})
resourceTableAllNum.value = tableData.value.filter(item => item.dataTableGuid != '' && item.dataTableGuid != null).length;
}
});
if (toPromise) {
return detailData;
} else {
(() => detailData)()
}
}
// 获取质量模型评分
const getQuilityModelScore = (sGuid) => {
return getModelScore({ damGuid: sGuid }).then((res: any) => {
if (res.code === proxy.$passCode) {
const data = res.data || {};
qualityScoreData.value = data;
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
// 獲取模型相关信息
const getModelInfo = (mGuid) => {
const promises: any = [
getModelConfig(mGuid),
getModelDetail(mGuid)
];
try {
loading.value = true;
Promise.all(promises).then(res => {
loading.value = false;
setFormItemData();
if (guid && mGuid == flowDetail.value.modelGuid) {
dataTransactionPrice.value = flowDetail.value.dataTransactionPrice;
setTimeout(() => {
getResourceDetail(flowDetail.value.dataResourceGuid, false);
setFormItems();
setdemandTableData(mGuid);
}, 200);
} else {
setdemandTableData(mGuid);
}
});
} catch (e) {
loading.value = false;
}
}
// 获取数据资源管理信息
const getResourceInfo = (sGuid) => {
const promises: any = [getResourceDetail(sGuid), getQuilityModelScore(sGuid)];
try {
loading.value = true;
Promise.all(promises).then(res => {
loading.value = false;
});
} catch (e) {
loading.value = false;
}
}
const setTableRowData = (dGuid, rIndex) => {
let rowData = tableData.value[rIndex];
if (guid && dGuid == rowData.dataTableGuid) {
const sourceTableField = flowDetail.value.dataPricingDemandmatchingRQVOS?.find(s => dGuid == s.dataTableGuid);
const pricingDemandField = sourceTableField?.pricingDemandFieldRQVOS || [];
rowData.dataFields.map(f => {
f.chName = pricingDemandField.find(s => f.guid == s.guid)?.chName || ''
})
} else {
rowData.dataFields.map(f => f.chName = '')
}
const damData = rowData.damDataTable.find(item => item.guid == dGuid);
rowData.tableDescription = damData?.tableDescription || '';
rowData.dataFieldsNum = rowData.dataFields.filter(item => item.chName != '' && item.chName != null).length;
resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
return accumulator + Number(currentValue.dataFieldsNum);
}, 0);
resourceTableAllNum.value = tableData.value.filter(item => item.dataTableGuid != '' && item.dataTableGuid != null).length;
if (dGuid) {
tableLoading.value = true;
getRegisterCatalogTableDetail(dGuid).then((res: any) => {
tableLoading.value = false;
if (res.code == proxy.$passCode) {
const data = res.data || {};
const damTableField = data.damCatalogTableField || [];
const damFieldOptions = damTableField.map(d => {
return {
...d,
label: d.chName || '',
value: d.chName || ''
}
})
rowData.dataFields.map(t => {
t.damFieldTable = JSON.parse(JSON.stringify(damFieldOptions));
})
// console.log('rowData', rowData)
} else {
proxy.$ElMessage.error(res.msg);
}
}).catch(() => {
tableLoading.value = false;
})
}
}
const changeDatasource = () => {
baseConfigFormItems.value.map(item => {
if (item.field == 'belongingEntityGuid') {
item.default = '';
} else if (item.field == 'belongingTheme') {
item.default = '';
}
})
}
const cascaderChange = (val) => {
disScore.value = [];
if (val) {
const baseConfigFormObj = baseConfigFormRef.value;
const baseConfigFormInfo = baseConfigFormObj.formInline;
const parentsData = baseConfigFormObj.getCascaderCheckedData();
const diseaseName = parentsData[0]?.label || '';
const modelGuid = baseConfigFormInfo.modelGuid;
// 获取疾病得分
getTargetNum({ diseaseName, guid: modelGuid });
}
}
const selectChange = async (val, row, info) => {
dataTransactionPrice.value = '';
if (row.field == 'modelGuid') {
tableData.value = [];
demandTableFieldAllNum.value = 0;
resourceTableAllNum.value = 0;
resourceTableFieldAllNum.value = 0;
await setFormItems(info);
val && getModelInfo(val);
qualityScoreData.value = {};
baseConfigFormItems.value[1].default = '';
changeDatasource();
} else if (row.field == 'dataResourceGuid') {
await setFormItems(info);
qualityScoreData.value = {};
resourceTableAllNum.value = 0;
resourceTableFieldAllNum.value = 0;
if (val) {
getResourceInfo(val);
} else {
changeDatasource();
}
} else if (row.field == 'dataTableGuid') {
setTableRowData(val, info.$index)
} else if (row.field == 'chName') {
let tData = info.row;
if (val) {
const damData = tData.dataFields[row.index].damFieldTable.find(item => item.chName == val);
tData.dataFields[row.index].enName = damData?.enName || '';
} else {
tData.dataFields[row.index].enName = '';
}
tData.dataFieldsNum = tData.dataFields.filter(item => item.chName != '' && item.chName != null).length;
resourceTableFieldAllNum.value = tableData.value.reduce((accumulator, currentValue) => {
return accumulator + Number(currentValue.dataFieldsNum);
}, 0);
} else {
setFormItems(info);
}
}
// 获取需求表字段
const getDemandField = (rGuid, rIndex) => {
getDemandList({
pageSize: -1,
pageIndex: 1,
relationMenuGuid: rGuid,
bizState: 'Y'
}).then((res: any) => {
tableLoading.value = false;
if (res.code == proxy.$passCode) {
const data = res.data || {};
const fData = data.records || [];
const tFields = tableData.value[rIndex].dataFields;
const tData = fData.map(item => {
const iData = tFields.find(t => t.demandFieldGuid == item.guid) || {};
return {
...item,
fieldName: item.fieldName,
isRequired: item.isRequired,
chName: item.chName || '',
enName: item.enName || '',
...iData
}
});
tableData.value[rIndex].dataFields = tData;
// // 合并数组
// const arr1Map = new Map(fData.map(item => [item.guid, item]));
// const merged = tFields.map(item => {
// if (item.demandFieldGuid && arr1Map.has(item.demandFieldGuid)) {
// return merge({}, arr1Map.get(item.demandFieldGuid), item);
// }
// return item;
// });
// fData.forEach(item => {
// if (!tFields.some(x => x.demandFieldGuid === item.guid)) {
// merged.push(item);
// }
// });
// const tData = merged;
// tableData.value[rIndex].dataFields = tData;
} else {
proxy.$ElMessage.error(res.msg);
}
}).catch(() => {
tableLoading.value = false;
})
}
const toPath = () => {
userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
assetStore.set(true);
router.push({
name: 'priceCalculate',
})
}
// 获取维度公式计算结果
const getSignatory = (row) => {
let formulaVal = 0;
const pricingTargetData = row.pricingTargetRSVOS || [];
if (!row.computationalFormula || row.computationalFormula == 'custom') {
let formula = row.customize;
// 遍历数组,检查 customize 是否包含对应的 targetName,若包含则替换为 tNum
pricingTargetData.forEach((item) => {
if (formula.includes(item.targetName)) {
formula = formula.replace(new RegExp(item.targetName, 'g'), item.tNum);
}
});
// 使用 eval 计算公式结果(注意:eval 存在安全风险,仅适用于受控环境)
try {
formulaVal = eval(formula);
} catch (error) {
console.error('公式计算错误:', error);
}
} else {
const formula = pricingTargetData.map(item => item.tNum);
if (row.computationalFormula == '3') {
formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) * parseFloat(currentValue), 1); // 初始值为1
} else {
formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) + parseFloat(currentValue), 0); // 初始值为0
}
}
return (Math.round(formulaVal * 100) / 100).toFixed(2);
};
const getTargetNum = (params) => {
// loading.value = true;
getPriceResult(params).then((res: any) => {
// loading.value = false;
if (res.code === proxy.$passCode) {
const data = res.data || [];
disScore.value = data;
} else {
proxy.$ElMessage.error(res.msg);
}
}).catch(() => {
// loading.value = false;
});
}
// 生成报告内容
const reporting = (formInfo) => {
let resultInfo: any = [];
const signatoryData = JSON.parse(JSON.stringify(modelData.value.pricingDimensionalityRSVOS || '[]'));
signatoryData.map((sign, s) => {
resultInfo.push({
dimensionalityName: sign.dimensionalityName,
computationalFormula: sign.computationalFormula,
customize: sign.customize,
pricingTargetRSVOS: []
});
const targets = sign.pricingTargetRSVOS || [];
const signTargets = targets.map(t => {
let tNum: any = 0, tCustomize = '';
if (t.targetType == '3') { // 指标类型-数据字典
const tName = dictionaryData.value.find(d => d.guid == t.guid) ? `dict_${t.guid}` : '';
if (tName) {
const pVal = typeMap.value[tName].find(t => t.value == formInfo[tName]);
const dictionary = t.dictionaryJson.find(d => d.name == pVal.label);
if (sign.computationalFormula == '1') {// 加权平均
tNum = parseFloat(t.weight) / 100 * parseFloat(dictionary?.value || t.defaultValue || 0);
tCustomize = `权重${parseFloat(t.weight) / 100} * 因子/默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
} else { // 其他
tNum = parseFloat(dictionary?.value || t.defaultValue || 0);
tCustomize = `默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
}
t.dictionaryName == '数据用途' && (dataUsage.value = pVal.value || '');
}
} else if (t.targetType == '2') {// 指标类型-系统功能
if (t.functionName == '1') { // 功能名称-质量评价模型
const score = parseFloat(qualityScoreData.value.qualityScore || 0);
tNum = parseFloat(t.weight || 1) / 100 * score;
tCustomize = `权重${parseFloat(t.weight) / 100} * 模型评分${score}`;
} else if (t.functionName == '2') { // 功能名称-疾病管理
if (sign.computationalFormula == '1') {// 加权平均
const score = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
tNum = parseFloat(t.weight) / 100 * score;
tCustomize = `权重${parseFloat(t.weight) / 100} * 疾病得分${score}`;
} else { //其他
tNum = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
tCustomize = `疾病得分${tNum}`;
}
} else if (t.functionName == '3') {// 功能名称-需求表管理
const tData = tableData.value.find(f => f.demandTableGuid == t.demandTableGuid || f.guid == t.demandTableGuid);
if (tData) {
if (sign.computationalFormula == '1') {// 加权平均
tNum = parseFloat(t.weight) / 100 * (parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0));
tCustomize = `权重${parseFloat(t.weight) / 100} * 匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
} else { //其他
tNum = parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0);
tCustomize = `匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
}
}
}
} else { // 指标类型-系统内置
if (sign.computationalFormula == '1') {// 加权平均
tNum = parseFloat(t.weight) / 100 * parseFloat(t.defaultValue || 0);
tCustomize = `权重${parseFloat(t.weight) / 100} * 默认值${parseFloat(t.defaultValue || 0)}`;
} else { //其他
tNum = parseFloat(t.defaultValue || 0);
tCustomize = `默认值${parseFloat(t.defaultValue || 0)}`;
}
}
t.tNum = (Math.round(parseFloat(tNum) * 100) / 100).toFixed(2);
resultInfo[s].pricingTargetRSVOS.push({
targetName: t.targetName,
targetType: t.targetType,
functionName: t.functionName,
customize: tCustomize,
tNum: t.tNum,
})
return t;
})
sign.pricingTargetRSVOS = signTargets;
sign.sNum = getSignatory(sign);
resultInfo[s].sNum = sign.sNum;
})
// exportData.value = resultInfo;
return { signatoryData, resultInfo };
}
// 计算价格
const calculatePrice = (pData) => {
let modelFormula = modelData.value.modelFormula;
// 1. 移除所有干扰的引号(确保是数学表达式)
modelFormula = modelFormula.replace(/["']/g, "");
// 1. 提取变量名(中文、英文、数字、下划线)
const variableRegex = /[\u4e00-\u9fa5a-zA-Z_][\u4e00-\u9fa5a-zA-Z0-9_]*/g;
const variableNames = modelFormula.match(variableRegex) || [];
// 2. 去重
const uniqueVariables = [...new Set(variableNames)];
// 3. 构建变量映射 { 销售额: 2000, 成本: 500.5, ... }
const variables = {};
uniqueVariables.forEach(name => {
const dim = pData.find(d => d.dimensionalityName === name);
variables[name] = dim ? parseFloat(dim.sNum) : 0; // 找不到则默认为 0
});
// 4. 替换变量为数值(不加引号,确保是数字运算)
let expression = modelFormula;
uniqueVariables.forEach(name => {
expression = expression.replace(new RegExp(name, 'g'), variables[name]);
});
// 5. 安全计算(推荐 math.js,或 new Function)
try {
//如果用 eval,确保表达式格式正确
const resultNum = eval(expression);
dataTransactionPrice.value = (Math.round(parseFloat(resultNum) * 100) / 100).toFixed(2);
} catch (error) {
console.error('公式计算错误:', error);
return NaN;
}
};
// 计算结果和提交
const checkForm = (type) => {
const baseConfigFormObj = baseConfigFormRef.value;
const baseConfigFormEl = baseConfigFormObj.ruleFormRef;
const baseConfigFormInfo = baseConfigFormObj.formInline;
baseConfigFormEl.validate((valid, errorItem) => {
if (valid) {
if (type == 'calculate') {
const { signatoryData, resultInfo } = reporting(baseConfigFormInfo);
exportData.value = resultInfo;
calculatePrice(signatoryData);
} else if (type == 'export') {
const { signatoryData, resultInfo } = reporting(baseConfigFormInfo);
exportData.value = resultInfo;
!dataTransactionPrice.value && calculatePrice(signatoryData);
loading.value = true;
let exportOut: any = {};
// 估值对象信息
const damName = typeMap.value.dataResourceGuid.find(f => f.damGuid == baseConfigFormInfo.dataResourceGuid)?.damName || '';
exportOut.one = `${baseConfigFormInfo.belongingEntityGuid}拟了解其所持有的\"${damName}\"相关数据资源的价格,为此需对该行为涉及的数据资源在不同应用场景下,基于数据资源持有单位的性质、信息化程度、数据稀缺性、需求匹配等情况下,为上述经济行为提供定价参考依据。`;
exportOut.two = `估值对象:${baseConfigFormInfo.belongingEntityGuid}持有的\"${damName}\"`;
// 估值范围信息
const damNames = demandTableList.value.map(item => item.menuName)
let rangStr = `包含${damNames.join('、')}等${damNames.length}张表单,${damNames.length}张表共计${demandTableFieldAllNum.value}个字段`;
const dataTimeliness = pricingTargetList.value.find(p => p.dictionaryName == '时效性');
const dataTimelinessStr = dataTimeliness ? typeMap.value[`dict_${dataTimeliness.guid}`].find(f => f.value == baseConfigFormInfo[`dict_${dataTimeliness.guid}`])?.label || '' : '';
rangStr += dataTimelinessStr ? `,时间跨度为${dataTimelinessStr}的数据` : `的数据`;
damNames.length && (exportOut.two = `${exportOut.two}\n估值范围:${rangStr}`);
// 字典
let dictList: any = [], hasModelScore = false;
const dictStr = exportData.value.map(e => {
const targetList: any = [];
e.pricingTargetRSVOS.map(t => {
if (t.targetType == '2' && t.functionName == '1') {
hasModelScore = true;
} else {
targetList.push({
targetName: t.targetName,
tNum: t.tNum,
})
}
})
const targetStr = targetList.length ? targetList.map(t => `${t.targetName}为${changeNum(t.tNum, 2)}`).join('、') : '';
targetStr && dictList.push(`${e.dimensionalityName}为${changeNum(e.sNum, 2)},其中${targetStr}`);
return `${e.dimensionalityName}为${changeNum(e.sNum, 2)}`;
})
let dictListStr = `${dictStr.join(',')}。\n${dictList.join(';\n')}`
// 质量模型
if (hasModelScore) {
const largeCategoryScoreList = qualityScoreData.value.largeCategoryScoreList || [];
const largeCategoryScore = largeCategoryScoreList.map(q => `${q.largeCategoryName}方面得分为${changeNum(q.largeCategoryScore || 0, 2)}`);
dictListStr += largeCategoryScore.length ? `;\n数据的总体质量得分为${changeNum(qualityScoreData.value.qualityScore || 0, 2)}。其中${largeCategoryScore.join(',')}` : `;\n数据的总体质量得分为${changeNum(qualityScoreData.value.qualityScore || 0, 2)}。`
}
exportOut.three = `${baseConfigFormInfo.belongingEntityGuid}持有的\"${damName}\"的数据(患者人次)单价为${changeNum(dataTransactionPrice.value, 2)}元`;
exportOut.three = dictListStr ? `${exportOut.three};其中${dictListStr}` : `${exportOut.three}。`
exportModelScore(exportOut).then((res: any) => {
loading.value = false;
if (res && !res.msg) {
ElMessage({
type: "success",
message: '下载报告成功',
});
download(res, `数据定价报告.doc`, 'word');
} else {
res?.msg && ElMessage.error(res?.msg);
}
}).catch(() => {
loading.value = false;
ElMessage({
type: "error",
message: '下载报告请求失败',
});
})
} else {
const { signatoryData, resultInfo } = reporting(baseConfigFormInfo);
exportData.value = resultInfo;
!dataTransactionPrice.value && calculatePrice(signatoryData);
const modelName = typeMap.value.modelGuid.find(d => d.guid == baseConfigFormInfo.modelGuid)?.modelName || '';
const dataResourceName = typeMap.value.dataResourceGuid.find(d => d.damGuid == baseConfigFormInfo.dataResourceGuid)?.damName || '';
const diseaseGuid = baseConfigFormInfo.diseaseGuid || '';
let params: any = {
tenantGuid: userData.tenantGuid,
dataTransactionPrice: dataTransactionPrice.value,
modelGuid: baseConfigFormInfo.modelGuid,
modelName,
dataResourceGuid: baseConfigFormInfo.dataResourceGuid,
dataResourceName,
belongingEntityGuid: baseConfigFormInfo.belongingEntityGuid,
belongingTheme: baseConfigFormInfo.belongingTheme,
diseaseGuid,
diseaseName: '',
dataUsage: dataUsage.value
};
if (diseaseGuid) {
const parentsData = baseConfigFormObj.getCascaderCheckedData();
params.diseaseName = parentsData[0]?.label || '';
}
let dictionaryJson = {};
for (var b in baseConfigFormInfo) {
if (b.indexOf('dict_') > -1) {
dictionaryJson[b] = baseConfigFormInfo[b];
}
}
params.dictionaryJson = Object.keys(dictionaryJson).length ? JSON.stringify(dictionaryJson) : '';
let demandMatchingData: any = [];
tableData.value.map(item => {
demandMatchingData.push({
demandTableName: item.demandTableName,
demandTableGuid: item.demandTableGuid || item.guid, // 需求表guid
dataTableGuid: item.dataTableGuid, // 数据资源表guid
weightDemandTable: item.weightDemandTable,
dataFieldsNum: item.dataFieldsNum,
pricingDemandFieldRQVOS: item.dataFields.map(d => {
return {
demandFieldGuid: d.demandFieldGuid || d.guid, // 资源表字段guid
fieldName: d.fieldName,
enName: d.enName,
chName: d.chName,
isRequired: d.isRequired
}
})
})
});
params.dataPricingDemandmatchingRQVOS = demandMatchingData;
guid && (params.guid = guid);
loading.value = true;
savePrice(params).then((res: any) => {
loading.value = false;
if (res.code == proxy.$passCode) {
ElMessage({
type: "success",
message: guid ? '编辑数据定价成功' : '新增数据定价成功',
});
toPath()
} else {
proxy.$ElMessage.error(res.msg);
}
}).catch(() => {
loading.value = false;
});
}
} else {
expand1.value = true;
var obj = Object.keys(errorItem);
baseConfigFormEl.scrollToField(obj[0]);
}
})
}
const btnClick = async (btn, row: any = null) => {
const type = btn.value;
if (type == 'dim') {
baseConfigFormItems.value.at(-1).default += btn.name;
} else if (type == 'del-signatory') {
open('确定要删除该条维度数据吗?', 'warning');
} else if (type == 'expend') {
expendTableRef.value.toggleRowExpansion(row);
} else if (type == 'calculate' || type == 'submit') {
if (type == 'submit') {
ElMessageBox.confirm(dataTransactionPrice.value === '' ? '是否直接计算价格并提交' : '请确认当前数据交易价格是否为最新计算结果', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
checkForm(type);
}).catch(() => {
ElMessage.info('已取消提交操作');
});
} else {
checkForm(type);
}
} else if (type == 'export') {
ElMessageBox.confirm(dataTransactionPrice.value === '' ? '是否直接计算价格并下载' : '请确认当前数据交易价格是否为最新计算结果', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
checkForm(type);
}).catch(() => {
ElMessage.info('已取消下载操作');
});
} else if (type == 'cancel') {
ElMessageBox.confirm(
"当前页面尚未保存,确定关闭吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).then(() => {
toPath()
}).catch(() => {
ElMessage({
type: "info",
message: "已取消",
});
});
}
}
onActivated(() => {
let tab: any = userStore.tabbar.find((tab: any) => tab.fullPath === router.currentRoute.value.fullPath);
if (tab) {
switch (route.query.type) {
case 'create':
tab.meta.title = `新增数据定价`;
break;
case 'edit':
tab.meta.title = `编辑-${priceName}`;
break;
case 'detail':
tab.meta.title = `详情-${priceName}`;
break;
}
}
getModel()
})
onBeforeMount(() => {
if (guid) {
getDetail();
} else {
getDataTypeList();
getModel()
}
})
onMounted(() => {
})
</script>
<template>
<div class="container_wrap full" v-loading="loading">
<div class="content_main panel">
<ContentWrap id="contract-content-wrap" title="输入参数" expandSwicth style="margin-top: 15px" :isExpand="expand1"
@expand="(v) => expand1 = v">
<Form ref="baseConfigFormRef" formId="contract-content-form" :itemList="baseConfigForm.items"
:rules="baseConfigForm.rules" col="col3" @selectChange="selectChange" @cascaderChange="cascaderChange" />
</ContentWrap>
<ContentWrap id="contract-signatory-wrap" title="需求匹配" expandSwicth style="margin-top: 15px" :isExpand="expand2"
@expand="(v) => expand2 = v">
<div class="table_panel_wrap">
<div class="table_tool">
<div class="tool_title">
<div class="title_desc">
<span>需求表数量:</span>
<span class="text-num">{{ demandTableList.length }}</span>
<span>张,字段数:</span>
<span class="text-num">{{ demandTableFieldAllNum }}</span>
<span>匹配表数量:</span>
<span class="text-num">{{ resourceTableAllNum }}</span>
<span>张,字段数:</span>
<span class="text-num">{{ resourceTableFieldAllNum }}</span>
</div>
</div>
</div>
<div class="table_panel" v-loading="tableLoading">
<el-table ref="expendTableRef" border :data="tableData" row-key="demandTableName" tooltip-effect="light"
style="height: 100%;">
<el-table-column type="expand">
<template #default="props">
<div class="expand_panel">
<div class="table_tool">
<div class="tool_title">
<div class="title_desc">
<span>需求字段数:</span>
<span class="text-num">{{ props.row.dataFields.length }}</span>
<span>个,匹配字段数:</span>
<span class="text-num">{{ props.row.dataFieldsNum }}</span>
</div>
</div>
</div>
<el-table :data="props.row.dataFields" border>
<el-table-column label="序号" type="index" width="56" align="center" />
<el-table-column label="需求字段中文" prop="fieldName" class-name="edit-col">
<template #default="scope">
<el-input v-model.trim="scope.row.fieldName" placeholder="请输入" disabled />
</template>
</el-table-column>
<el-table-column label="匹配字段中文" prop="chName" class-name="edit-col">
<template #default="scope">
<el-select v-model="scope.row.chName" clearable filterable
@change="val => selectChange(val, { field: 'chName', index: scope.$index }, props)">
<el-option v-for="(opt, o) in scope.row.damFieldTable" :label="opt.label" :value="opt.value"
:key="o" />
</el-select>
</template>
</el-table-column>
<el-table-column label="匹配字段英文" prop="enName" class-name="edit-col">
<template #default="scope">
<el-input v-model.trim="scope.row.enName" placeholder="请输入" disabled />
</template>
</el-table-column>
<el-table-column label="是否必需字段" prop="isRequired" class-name="edit-col">
<template #default="scope">
<el-select v-model="scope.row.isRequired" disabled>
<el-option label="是" value="Y" />
<el-option label="否" value="N" />
</el-select>
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column label="序号" type="index" width="56" align="center" />
<el-table-column v-for="item in tableFields" :key="item.field" :label="item.label" :prop="item.field"
:width="item.width" :align="item.align" class-name="edit-col">
<template #default="scope">
<el-select v-if="item.type == 'select'" v-model="scope.row[item.field]" clearable filterable
@change="val => selectChange(val, item, scope)">
<el-option v-for="(opt, o) in scope.row.damDataTable" :label="opt.label" :value="opt.value"
:key="o" />
</el-select>
<el-input v-else v-model.trim="scope.row[item.field]" :disabled="item.disabled" placeholder="请输入"
clearable />
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="100">
<template #default="scope">
<el-button type="primary" link @click="btnClick({ value: 'expend' }, scope.row)">字段映射</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</ContentWrap>
<ContentWrap id="contract-content-wrap" title="输出结构" expandSwicth style="margin-top: 15px" :isExpand="expand3"
@expand="(v) => expand3 = v">
<el-form class="result-form">
<el-form-item class="flex-column" label="数据交易价格(元)">
<el-input v-model="dataTransactionPrice" placeholder="" disabled style="display: none;" />
<div class="result-price">{{ changeNum(dataTransactionPrice, 2) }}</div>
</el-form-item>
<el-form-item class="align-end" style="margin-bottom: 14px;">
<el-button type="primary" @click="btnClick({ value: 'calculate' })">开始计算</el-button>
<el-button @click="btnClick({ value: 'export' })">下载报告</el-button>
<span style="margin-left: 8px">输出结果报告查看</span>
</el-form-item>
</el-form>
</ContentWrap>
</div>
<div class="tool_btns">
<div class="btns">
<el-button @click="btnClick({ value: 'cancel' })">取消</el-button>
<el-button type="primary" @click="btnClick({ value: 'submit' })">提交</el-button>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.container_wrap {
overflow: hidden;
.content_main {
height: calc(100% - 45px);
overflow: hidden auto;
&.panel {
padding: 0 16px 16px;
}
:deep(.el-card) {
&#contract-signatory-wrap {
.card-body-content {
padding: 8px 16px;
}
}
}
.signatory-tags {
margin-bottom: 11px;
}
.table_panel_wrap {
margin-bottom: 4px;
.table_tool {
height: 36px;
display: flex;
justify-content: space-between;
align-items: center;
.tool_title {
width: 100%;
display: flex;
justify-content: start;
}
.title_desc {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
.text-num {
color: var(--el-color-primary);
margin: 0 8px;
}
}
}
.table_panel {
margin-bottom: 4px;
height: 392px;
:deep(.el-table) {
.el-table__cell {
&.edit-col {
padding: 4px 0;
.cell {
padding: 0 4px;
.el-cascader {
width: 100%;
height: 28px;
}
.el-input {
height: 28px;
}
}
}
.expand-icon {
color: #888;
margin-right: 8px;
vertical-align: text-bottom;
cursor: pointer;
}
}
.el-input.is-disabled .el-input__wrapper {
background-color: var(--el-disabled-bg-color);
}
.el-select__wrapper.is-disabled {
background-color: var(--el-disabled-bg-color);
}
}
.expand_panel {
padding: 6px;
margin: -6px 0;
background: #fff;
}
}
}
}
.btn-block {
width: 100%;
margin: 16px 0 8px;
}
.tool_btns {
height: 44px;
margin: 0 -8px;
display: flex;
justify-content: center;
align-items: center;
border-top: 1px solid #d9d9d9;
}
}
:deep(.el-form) {
&.result-form {
display: flex;
.el-form-item {
&.flex-column {
width: calc(33.33% - 6px);
margin-right: 8px;
display: flex;
flex-direction: column;
align-items: self-start;
.el-form-item__content {
width: 100%;
}
.result-price {
width: 100%;
height: 32px;
line-height: 32px;
padding: 1px 11px;
border-radius: 4px;
cursor: not-allowed;
color: var(--el-disabled-text-color);
background-color: var(--el-disabled-bg-color);
box-shadow: 0 0 0 1px var(--el-disabled-border-color) inset;
}
}
&.align-end {
align-self: flex-end;
}
}
}
.el-select__wrapper.is-disabled {
background-color: var(--el-disabled-bg-color);
}
}
</style>
<route lang="yaml">
name: demandManage
</route>
<script lang="ts" setup name="demandManage">
import { ref } from 'vue';
import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
import { ElMessage, ElMessageBox } from "element-plus";
import { CirclePlus, Search } from "@element-plus/icons-vue";
import { useRouter, useRoute } from "vue-router";
import { changeNum, getCurrentTime } from '@/utils/common';
import useUserStore from "@/store/modules/user";
import useCatchStore from "@/store/modules/catch";
import {
getDemandAll,
saveDemandTree,
updateDemandTree,
deleteDemandTree,
getDemandList,
saveDemand,
updateDemand,
deleteDemand,
} from '@/api/modules/dataPricing';
const router = useRouter();
const userStore = useUserStore()
const userData = JSON.parse(userStore.userData)
const { proxy } = getCurrentInstance() as any;
const cacheStore = useCatchStore()
/** 左侧标签列表管理 */
const treeInfoRef = ref();
const treeData = ref([]);
const treeInfo = ref({
id: "demand-tree",
filter: true,
editTreeItem: true,
queryValue: "",
loading: false,
className: 'tree-list-manage',
queryPlaceholder: "输入关键字搜索",
props: {
label: "menuName",
value: "guid",
children: 'childList',
},
prefix: {
type: 'prefixIcon'
},
lazy: false,
nodeKey: 'guid',
expendAll: true,
currentNodeKey: '',
expandOnNodeClick: false,
data: [],
});
const catalogData = ref([]);
const searchItemList = ref([
{
type: "select",
label: "",
field: "isRequired",
placeholder: "是否必选",
default: "",
options: [
{ label: '是', value: 'Y' },
{ label: '否', value: 'N' }
],
clearable: true,
style: {
width: '140px'
}
},
{
type: "input",
label: "",
field: "fieldName",
default: "",
placeholder: "字段名称",
clearable: true,
style: {
width: '230px'
}
},
]);
const lastClickNode: any = ref({});
const showTable = ref(false)
/** 记录正在提交审批流程的api,防止重复提交 */
const addDataPromise: any = ref();
const tableRef = ref();
const tableData: any = ref([]);
const selectRowData: any = ref([])
const currTableData: any = ref({});
const page: any = ref({
...commonPageConfig,
fieldName: '',
isRequired: '',
});
const tableFields: any = [
{ label: "字段名称", field: "fieldName" },
{ label: "是否必选", field: "isRequired", type: 'select' },
{ label: "排序", field: "orderNum", type: 'defaultValue' },
{ label: '启用状态', field: 'bizState', type: 'switch', activeText: '启用', inactiveText: '停用', activeValue: 'Y', inactiveValue: 'N' },
{ label: "创建时间", field: "createTime", type: 'defaultValue' },
]
const tableInfo: any = ref({
id: 'api-data-table',
rowKey: 'guid',
loading: false,
multiple: true,
fields: [
{ label: "字段名称", field: "fieldName", width: 200, align: "left", type: 'edit' },
{
label: "是否必选", field: "isRequired", width: 140, type: 'edit', getName: (scope) => {
return scope.row.isRequired == 'Y' ? '是' : '否'
}
},
{ label: "排序", field: "orderNum", width: 120, type: 'edit', dataTypeName: 'fieldType' },
{
label: '启用状态', field: 'bizState', type: 'edit', activeText: '启用', inactiveText: '停用', activeValue: 'Y', inactiveValue: 'N', switchWidth: 56, width: 96, align: 'center',
},
{ label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME, type: 'edit', dataTypeName: 'dateType' },
],
data: tableData.value,
editInfo: [],
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
isMore: false,
width: 120,
btns: (scope) => {
let btns: any[] = [];
if (scope.row.STATUS == 'edit') {
btns.push({
value: 'save', label: '保存', click: (scope) => {
if (addDataPromise.value) {
return;
}
// 调用新增数据的接口。
let params = { ...scope.row, tenantGuid: userData.tenantGuid };
params.relationMenuGuid = lastClickNode.value.guid;
delete params['ROWID'];
delete params['STATUS'];
delete params['STATE'];
delete params.dateType;
delete params.fieldType;
if (params.guid) {
addDataPromise.value = updateDemand(params).then((res: any) => {
addDataPromise.value = null;
if (res.code == proxy.$passCode) {
page.value.curr = 1;
getTableData();
proxy.$ElMessage.success('编辑数据保存成功');
} else {
proxy.$ElMessage.error(res.msg);
}
});
} else {
addDataPromise.value = saveDemand(params).then((res: any) => {
addDataPromise.value = null;
if (res.code == proxy.$passCode) {
page.value.curr = 1;
getTableData();
proxy.$ElMessage.success('新增数据保存成功');
} else {
proxy.$ElMessage.error(res.msg);
}
});
}
}
});
btns.push({
value: 'del', label: '删除', click: (scope) => {
proxy.$openMessageBox('确定要删除该条数据吗?', () => {
tableData.value.splice(0, 1);
proxy.$ElMessage.success("删除成功");
}, () => {
proxy.$ElMessage.info("已取消删除");
})
}
});
return btns;
}
btns.push({ value: 'edit', label: '编辑' });
btns.push({ value: 'del', label: '删除' });
return btns;
}
}
});
/** ---- 新增修改标签对话框配置------------- */
const formItems: any = ref([
{
label: '需求表名称',
type: 'input',
placeholder: '请输入',
field: 'menuName',
default: '',
maxlength: 20,
clearable: true,
required: true,
},
{
label: '是否为目录',
type: 'select',
field: 'isCatalog',
default: 'N',
options: [
{ label: '是', value: 'Y' },
{ label: '否', value: 'N' }
],
required: true,
},
{
label: '所属上级',
type: 'cascader',
placeholder: '请选择',
field: "parentGuid",
default: [],
options: [],
showAllLevels: false,
props: {
checkStrictly: true,
label: "menuName",
value: "guid",
children: 'childList',
emitPath: false
},
clearable: true,
filterable: true,
block: true
},
{
label: '排序',
type: 'input',
placeholder: '请输入',
field: 'orderNum',
default: '',
inputType: 'integerNumber',
maxlength: 6,
clearable: true,
},
])
const formRules = ref({
menuName: [
{ required: true, message: '请填写需求表名称', trigger: 'blur' }
],
isCatalog: [
{ required: true, message: '请选择是否为目录', trigger: 'change' }
]
});
/** 新建api标签对话框 */
const demScheduleLabelDialogInfo = ref({
visible: false,
size: 480,
direction: "column",
header: {
title: "",
},
type: '',
contents: [
{
type: 'form',
title: '',
formInfo: {
id: 'add-staff-form',
items: formItems.value,
rules: formRules.value
}
}
],
footer: {
btns: [
{ type: "default", label: "取消", value: "cancel" },
{ type: "primary", label: "确定", value: "submit" },
],
},
});
// 获取需求表树形数据
const getTreeData = () => {
getDemandAll({ isCatalog: '' }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
treeData.value = JSON.parse(JSON.stringify(data));
treeInfo.value.data = JSON.parse(JSON.stringify(data));
treeInfo.value.currentNodeKey = data[0]?.guid || "";
lastClickNode.value = data[0] || {};
nextTick(() => {
treeInfoRef.value?.setCurrentKey(treeInfo.value.currentNodeKey);
if (lastClickNode.value.isCatalog != 'Y') {
showTable.value = true;
page.value.curr = 1;
getTableData();
} else {
showTable.value = false;
}
})
} else {
proxy.$ElMessage.error(res.msg);
}
})
getCatalog();
}
const getCatalog = () => {
getDemandAll({ isCatalog: 'Y' }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
catalogData.value = JSON.parse(JSON.stringify(data));
}
})
}
/** 点击左侧节点 */
const nodeClick = (data) => {
lastClickNode.value = data || {};
if (data.isCatalog != 'Y') {
showTable.value = true;
page.value.curr = 1;
getTableData();
} else {
showTable.value = false;
}
}
const setRowData = (info: any = null) => {
const rowData: any = {
STATUS: 'edit',
STATE: "Running",
ROWID: '1',
dateType: 'datetime',
fieldType: 'int',
fieldName: info?.fieldName || '',
isRequired: info?.isRequired || 'N',
bizState: info?.bizState || 'Y',
createTime: info?.createTime || getCurrentTime(),
orderNum: info?.orderNum !== undefined ? info?.orderNum : tableData.value.length + 1
}
info && (rowData.guid = info.guid || '');
return rowData;
}
// 新增字段
const addField = () => {
if (tableData.value[0]?.STATUS == 'edit') {
proxy.$ElMessage.warning('请先保存正在编辑的行数据');
return;
}
// 支持新增数据,直接添加一行进行编辑。
const rowData = setRowData();
tableData.value.unshift(rowData);
nextTick(() => {
tableRef?.value?.tableRef?.setScrollTop(0);
})
}
// 批量删除
const batching = (type) => {
if (type == 'delete') {
if (selectRowData.value.length == 0) {
ElMessage({
type: 'error',
message: '请选择需要删除的数据',
})
return
}
open("此操作将永久删除, 是否继续?", "warning", true);
} else if (type == 'import') {
const info = {
dictionaryGuid: ''
}
cacheStore.setCatch('uploadSetting', info)
router.push(
{
name: 'importFileDemandManage',
query: {
isfileImport: '7'
}
}
);
}
}
const setFormItems = (info = null, type = '') => {
const datas: any = info || {};
formItems.value.map(item => {
if (item.field == 'isCatalog') {
item.default = datas[item.field] || 'N';
} else {
item.default = datas[item.field] || '';
}
})
}
const setCataLog = (dataArr, id, parentDisabled = false) => {
return dataArr.map(item => {
// 当前节点是否被禁选(自身匹配或父节点已禁选)
const isDisabled = parentDisabled || item.guid === id;
// 新节点基础属性
const newItem = {
...item,
disabled: isDisabled
};
// 递归处理子节点,并传递当前节点的禁选状态
if (item.childList && item.childList.length > 0) {
newItem.childList = setCataLog(item.childList, id, isDisabled);
}
return newItem;
})
}
/** 处理标签的操作按钮,编辑,删除 */
const handleTreeItemMenuClick = async (node, type) => {
let data = node.data;
lastClickNode.value = data;
if (type == "edit") {
await setFormItems(data);
if (data.isCatalog == 'Y') {
formItems.value[1].disabled = data.childList && data.childList.length > 0;
} else {
formItems.value[1].disabled = tableData.value && tableData.value.length > 0;
}
let cata = setCataLog(catalogData.value, data.guid);
formItems.value.at(-2).options = cata;
demScheduleLabelDialogInfo.value.contents[0].formInfo.items = formItems.value;
demScheduleLabelDialogInfo.value.header.title = "编辑需求表";
demScheduleLabelDialogInfo.value.type = 'edit';
demScheduleLabelDialogInfo.value.visible = true;
} else if (type == "delete") {
proxy.$openMessageBox('确定要删除该需求表吗?', () => {
deleteDemandTree([lastClickNode.value.guid]).then((res: any) => {
if (res.code == proxy.$passCode) {
getTreeData();
proxy.$ElMessage.success("删除该需求表成功");
} else {
proxy.$ElMessage.error(res.msg);
}
});
}, () => {
proxy.$ElMessage.info("已取消");
})
}
}
/** 新建分组对话框确定。 */
const demScheduleLabelDialogBtnClick = (btn, info) => {
if (btn.value == 'submit') {
let params = { ...info, parentGuid: info.parentGuid || '', tenantGuid: userData.tenantGuid };
if (demScheduleLabelDialogInfo.value.type == 'add') {
saveDemandTree(params).then((res: any) => {
if (res.code == proxy.$passCode) {
getTreeData();
proxy.$ElMessage({
type: 'success',
message: '新增需求表成功'
})
demScheduleLabelDialogInfo.value.visible = false;
} else {
proxy.$ElMessage({
type: 'error',
message: res.msg,
})
}
})
} else {
params.guid = lastClickNode.value.guid;
updateDemandTree(params).then((res: any) => {
if (res.code == proxy.$passCode) {
getTreeData();
proxy.$ElMessage({
type: 'success',
message: '编辑需求表成功'
})
demScheduleLabelDialogInfo.value.visible = false;
} else {
proxy.$ElMessage({
type: 'error',
message: res.msg,
})
}
})
}
} else if (btn.value == 'cancel') {
demScheduleLabelDialogInfo.value.visible = false;
}
};
const addTreeNode = async () => {
await setFormItems();
demScheduleLabelDialogInfo.value.header.title = '新建需求表';
formItems.value[1].disabled = false;
formItems.value.at(-2).options = catalogData.value;
demScheduleLabelDialogInfo.value.contents[0].formInfo.items = formItems.value;
demScheduleLabelDialogInfo.value.type = 'add';
demScheduleLabelDialogInfo.value.visible = true;
}
// 设置需求表表头
const setTableField = () => {
const editInfo = {};
tableFields.forEach(f => {
if (f.type == 'switch') {
editInfo[f.field] = {
label: f.label,
type: f.type,
field: f.field,
default: false,
activeText: '启用',
inactiveText: '停用',
activeValue: 'Y',
inactiveValue: 'N',
};
} else if (f.type == 'select') {
editInfo[f.field] = {
label: f.label,
type: f.type,
field: f.field,
default: '',
options: [
{ label: '是', value: 'Y' },
{ label: '否', value: 'N' }
],
clearable: true
}
} else if (f.type == 'defaultValue') {
editInfo[f.field] = {
label: f.label,
type: f.type,
field: f.field,
default: '',
clearable: true,
disabled: true,
}
} else {
editInfo[f.field] = {
label: f.label,
type: 'input',
field: f.field,
placeholder: f.isPrimary == 'Y' ? '主键自动生成' : '请输入',
default: '',
clearable: true
}
}
})
tableInfo.value.editInfo = editInfo;
}
const toSearch = (val: any = null, clear: boolean = false) => {
page.value.curr = 1;
if (clear) {
searchItemList.value.map((item) => (item.default = ""));
page.value.fieldName = '';
page.value.isRequired = '';
} else {
let info = val ? { ...val } : {};
searchItemList.value.map(item => {
info[item.field] = item.default;
})
page.value.fieldName = info.fieldName || '';
page.value.isRequired = info.isRequired || '';
}
getTableData();
};
// 获取表格数据
const getTableData = () => {
if (!lastClickNode.value?.guid) {
return;
}
tableInfo.value.loading = true;
getDemandList({
pageSize: page.value.limit,
pageIndex: page.value.curr,
relationMenuGuid: lastClickNode.value.guid,
fieldName: page.value.fieldName,
isRequired: page.value.isRequired,
}).then((res: any) => {
tableInfo.value.loading = false;
if (res.code == proxy.$passCode) {
const data = res.data || {};
tableData.value = data.records || [];
tableInfo.value.data = tableData.value;
tableInfo.value.page.limit = data.pageSize
tableInfo.value.page.curr = data.pageIndex
tableInfo.value.page.rows = data.totalRows
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
getTableData();
};
const tableSelectionChange = (val) => {
selectRowData.value = val;
};
const tableSwitchBeforeChange = (scope, field, callBack) => {
if (scope.row.STATUS == 'edit') {
callBack(true);
} else {
// proxy.$openMessageBox(`确定要更新该字段值吗?`, () => {
// const state = scope.row[field] == 'Y' ? 'N' : 'Y';
// let mdmModelData: any = {};
// mdmModelData[field] = state;
// let pkValue = scope.row[mergeFormItems.value[0].field];
// mdmModelData[mergeFormItems.value[0].field] = pkValue;
// updateMdmModelData({
// mdmModelTableGuid: props.modelConfigInfo.guid,
// mdmModelData: mdmModelData,
// pkValues: [pkValue]
// }).then((res: any) => {
// if (res.code == proxy.$passCode) {
// proxy.$ElMessage.success('该字段值更新成功');
// let firstData = tableData.value[0];
// getMainModelData().then((res: any) => {
// if (firstData && firstData.STATUS == 'edit') {
// tableData.value.unshift(firstData);
// }
// });
// callBack(true)
// } else {
// proxy.$ElMessage.error(res.msg);
// callBack(false)
// }
// });
// }, () => {
// callBack(false);
// })
}
}
const tableSwitchChange = (val, scope, field) => {
if (scope.row.STATUS == 'edit') {
tableData.value[scope.$index][field] = val;
}
}
const tableBtnClick = (scope, btn) => {
const type = btn.value;
const row = scope.row;
currTableData.value = row;
if (type === 'edit') { // 编辑
if (tableData.value.find(t => t.STATUS == 'edit')) {
proxy.$ElMessage.warning('请先保存正在编辑的行数据');
return;
}
const rowData = setRowData(row);
tableData.value[scope.$index] = rowData;
} else if (type === 'del') { // 删除
open('确定要删除该条数据吗?', 'warning');
}
};
const open = (msg, type, isBatch = false) => {
ElMessageBox.confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: type,
}).then(() => {
let guids = [currTableData.value.guid]
if (isBatch) {
guids = selectRowData.value.map(item => item.guid);
}
deleteDemand(guids).then((res: any) => {
if (res.code == proxy.$passCode) {
getTableData();
ElMessage({
type: "success",
message: "删除成功",
});
} else {
ElMessage({
type: "error",
message: res.msg,
});
}
});
});
};
onBeforeMount(() => {
getTreeData();
setTableField();
});
onActivated(() => {
})
</script>
<template>
<div class="container_wrap full flex">
<div class="aside_wrap">
<div class="aside_title">需求表列表</div>
<el-icon class="icon-add" color="#4fa1a4" @click="addTreeNode()">
<CirclePlus />
</el-icon>
<Tree ref="treeInfoRef" :treeInfo="treeInfo" @nodeClick="nodeClick" @itemMenuClick="handleTreeItemMenuClick" />
</div>
<div class="main_wrap">
<template v-if="showTable">
<div class="table_tool_wrap">
<div class="tools_btns">
<el-button type="primary" @click="addField" v-preReClick>添加</el-button>
<el-button @click="batching('import')" v-preReClick>批量导入</el-button>
<el-button @click="batching('delete')" v-preReClick>批量删除</el-button>
</div>
<div class="tools_serach">
<template v-for="(item, i) in searchItemList" :key="'s_' + i">
<el-select v-if="item.type == 'select'" v-model="item.default" :placeholder="item.placeholder"
:clearable="item.clearable" :style="item.style" @change="val => toSearch()">
<el-option v-for="(opt, o) in item.options" :label="opt.label" :value="opt.value" :key="o" />
</el-select>
<el-input v-else v-model.trim="item.default" :placeholder="item.placeholder" :suffix-icon="Search"
:clearable="item.clearable" :style="item.style" @change="val => toSearch()" />
</template>
</div>
</div>
<div class="table_panel_wrap">
<Table ref="tableRef" :tableInfo="tableInfo" @tableSelectionChange="tableSelectionChange"
@tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
</div>
</template>
<div class="card-noData" v-else>
<img src="@/assets/images/no-data.png" :style="{ width: '96px', height: '96px' }" />
<p>请选择需求表</p>
</div>
</div>
<!-- 添加编辑需求表的对话框 -->
<Dialog :dialogInfo="demScheduleLabelDialogInfo" @btnClick="demScheduleLabelDialogBtnClick" />
</div>
</template>
<style lang="scss" scoped>
.container_wrap {
padding: 0;
display: flex;
justify-content: space-between;
.aside_wrap {
width: 199px;
border-right: 1px solid #d9d9d9;
box-shadow: none;
.aside_title {
width: calc(100% - 32px);
display: inline-block;
}
.icon-add.el-icon {
width: 24px;
height: 24px;
vertical-align: middle;
cursor: pointer;
svg {
width: 24px;
height: 24px;
}
}
:deep(.tree_panel) {
height: 100%;
padding-top: 0;
.el-tree {
margin: 0;
height: calc(100% - 68px);
overflow: hidden auto;
}
}
}
.main_wrap {
padding: 0 8px;
height: auto;
flex: 1;
.table_tool_wrap {
width: 100%;
padding: 0 8px;
display: flex;
justify-content: space-between;
align-items: center;
.tools_btns {
padding: 0px 0 0;
}
.tools_serach {
width: 378px;
display: flex;
justify-content: space-between;
}
}
.table_panel_wrap {
width: 100%;
height: calc(100% - 44px);
padding: 0px 8px 0;
}
.card-noData {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
}
}
}
.row-dialog-content {
height: 300px;
.tools_btns {
margin-bottom: 8px;
}
}
:deep(.el-form) {
.select-input-long {
.el-form-item:first-child {
width: 67%;
margin-right: 0px;
}
.el-form-item:last-child {
width: 33%;
margin-right: 0px;
.item-label {
white-space: pre;
.required_mark::after {
content: '';
}
}
}
}
.select-input-long-reverse {
.el-form-item:first-child {
width: 100px;
margin-right: 0px;
}
.el-form-item:last-child {
width: calc(100% - 100px);
margin-right: 0px;
.item-label {
white-space: pre;
.required_mark::after {
content: '';
}
}
}
}
}
</style>
<route lang="yaml">
name: diseaseManage
</route>
<script lang="ts" setup name="diseaseManage">
import { ref } from 'vue';
import TableTools from '@/components/Tools/table_tools.vue';
import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
import { ElMessage, ElMessageBox } from "element-plus";
import { CirclePlus } from "@element-plus/icons-vue";
import { useRouter, useRoute } from "vue-router";
import useUserStore from "@/store/modules/user";
import useCatchStore from "@/store/modules/catch";
import {
getDiseaseAll,
getDiseaseList,
saveDisease,
updateDisease,
deleteDisease,
} from '@/api/modules/dataPricing';
import { changeNum } from '@/utils/common';
const router = useRouter();
const userStore = useUserStore()
const userData = JSON.parse(userStore.userData)
const { proxy } = getCurrentInstance() as any;
const cacheStore = useCatchStore()
const searchItemList = ref([
{
type: "input",
label: "",
field: "diseaseName",
default: "",
placeholder: "疾病名称",
clearable: true,
},
{
type: "select",
label: "",
field: "isChildrenDisease",
placeholder: "是否儿童",
default: "",
options: [
{ label: '是', value: 'Y' },
{ label: '否', value: 'N' }
],
clearable: true,
}
]);
const tableData: any = ref([]);
const selectRowData: any = ref([])
const currTableData: any = ref({});
const selectionTreeTableRef = ref();
const page: any = ref({
...commonPageConfig,
diseaseName: '',
isChildrenDisease: ''
});
const tableInfo = ref({
id: 'api-data-table',
rowKey: 'guid',
loading: false,
multiple: true,
fields: [
{ label: "疾病名称", field: "diseaseName", width: 200 },
{
label: "是否儿童疾病", field: "isChildrenDisease", width: 120, getName: (scope) => {
return scope.row.isChildrenDisease == 'Y' ? '是' : '否';
}
},
{ label: "发病率/患病率", field: "incidenceRate", width: 120 },
{
label: "因子", field: "factor", width: 100, align: 'right', getName: (scope) => {
return (scope.row.factor !== '' && scope.row.factor !== null) ? changeNum(scope.row.factor, 2) : '-';
}
},
{
label: "启用状态", field: "bizState", type: 'tag', width: 120, align: 'center', getName: (scope) => {
return scope.row.bizState == 'Y' ? '启用' : '停用';
}, tagType: (scope) => {
return scope.row.bizState == 'Y' ? 'success' : 'info';
}
},
{ label: "排序", field: "orderNum", width: 100, align: 'right', type: 'chnum' },
{ label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME },
],
data: tableData.value,
treeProps: {
children: 'childList',
hasChildren: 'hasChildren',
checkStrictly: false,
},
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
isMore: false,
width: 120,
btns: [
{ label: "编辑", value: "edit" },
{ label: "删除", value: "del" }
]
}
});
/** ---- 新增修改标签对话框配置------------- */
const catalogData = ref([]);
const formItems: any = ref([
{
label: '疾病名称',
type: 'input',
placeholder: '请输入',
field: 'diseaseName',
default: '',
maxlength: 50,
required: true,
clearable: true,
},
{
label: '所属上级',
type: 'cascader',
placeholder: '请选择',
field: "parentGuid",
default: [],
options: [],
showAllLevels: false,
props: {
checkStrictly: true,
label: "diseaseName",
children: 'childList',
value: "guid",
emitPath: false
},
clearable: true,
filterable: true,
},
{
label: '是否儿童疾病',
type: 'select',
placeholder: '请选择',
field: 'isChildrenDisease',
default: '',
options: [
{ label: '是', value: 'Y' },
{ label: '否', value: 'N' }
],
required: true,
clearable: true,
},
{
label: '启用状态',
type: 'switch',
field: 'bizState',
default: 'Y',
placeholder: '请选择',
activeValue: 'Y',
inactiveValue: 'N',
switchWidth: 32,
},
{
label: '发病率/患病率',
type: 'input',
placeholder: '请输入',
field: 'incidenceRate',
default: '',
maxlength: 20,
clearable: true,
required: true,
},
{
label: '因子',
type: 'input-group',
placeholder: '请输入',
field: 'in',
default: '',
children: [
{
label: '',
type: 'input',
placeholder: '请输入',
field: 'factor',
default: '',
inputType: 'factorNumber',
maxlength: 10,
clearable: true,
},
{
label: '',
type: 'checkbox',
placeholder: '下级同时修改',
desc: '',
field: 'juniorTogetherModify',
default: "N",
trueValue: 'Y',
falseValue: 'N',
}
],
},
{
label: '排序',
type: 'input',
placeholder: '由数字组成',
field: 'orderNum',
inputType: 'integerNumber',
default: '',
maxlength: 6,
clearable: true,
},
])
const formRules = ref({
diseaseName: [
{ required: true, message: '请填写疾病名称', trigger: 'blur' }
],
isChildrenDisease: [
{ required: true, message: '请选择是否儿童疾病', trigger: 'change' }
],
bizState: [
{ required: true, message: '请选择启用状态', trigger: 'change' }
],
incidenceRate: [
{ requires: true, message: '请填写发病率/患病率', trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
if (!value) {
callback(new Error("请填写发病率/患病率"));
} else {
if (drawerInfo.value.type.indexOf('edit') > -1 && currTableData.value.incidenceRate == value) {
callback();
return
}
let eMsg = '';
// 验证格式:数字、小数或分数
if (!/^[0-9]*\.?[0-9]*(\/[0-9]+\.?[0-9]*)?$/.test(value)) {
eMsg = '请输入有效的数字、小数或分数(如0.5或1/2)';
}
let numericValue;
// 处理分数
if (value.includes('/')) {
const parts = value.split('/');
if (parts.length !== 2) {
eMsg = '请输入有效的分数格式(如1/2)';
}
const numerator = parseFloat(parts[0]);
const denominator = parseFloat(parts[1]);
if (isNaN(numerator) || isNaN(denominator)) {
eMsg = '请输入有效的分数格式(如1/2)';
}
if (denominator === 0) {
eMsg = '请输入有效的分数格式(如1/2)';
}
numericValue = numerator / denominator;
} else {// 处理普通数字
numericValue = parseFloat(value);
if (isNaN(numericValue)) {
eMsg = '请输入有效的数字';
}
}
if (numericValue < 0) {
eMsg = '发病率必须大于等于0';
}
if (numericValue > 1) {
eMsg = '发病率必须小于或等于1';
}
if (eMsg) {
callback(new Error(eMsg));
} else {
callback();
}
}
},
trigger: "blur",
},
]
});
const formInfo = ref({
type: "form",
title: "",
col: "span",
formInfo: {
id: "add-disease-form",
readonly: false,
items: formItems.value,
rules: formRules.value,
},
});
const drawerInfo = ref({
visible: false,
direction: "rtl",
size: 480,
header: {
title: "新增",
},
type: "",
container: {
contents: [
formInfo.value
],
},
footer: {
visible: true,
btns: [
{ type: "default", label: "取消", value: "cancel" },
{ type: "primary", label: "保存", value: "submit" },
],
},
});
// 获取所有疾病数据
const getDiseaseData = () => {
getDiseaseAll().then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
catalogData.value = JSON.parse(JSON.stringify(data));
}
})
}
const toSearch = (val: any, clear: boolean = false) => {
page.value.curr = 1;
if (clear) {
searchItemList.value.map((item) => (item.default = ""));
page.value.diseaseName = '';
page.value.isChildrenDisease = '';
} else {
page.value.diseaseName = val.diseaseName || '';
page.value.isChildrenDisease = val.isChildrenDisease || '';
}
getTableData();
};
const getTableData = () => {
tableInfo.value.loading = true;
getDiseaseList({
tenantGuid: userData.tenantGuid,
pageSize: page.value.limit,
pageIndex: page.value.curr,
diseaseName: page.value.diseaseName,
isChildrenDisease: page.value.isChildrenDisease,
}).then((res: any) => {
tableInfo.value.loading = false;
if (res.code == proxy.$passCode) {
const data = res.data || {};
tableData.value = data.records || [];
tableInfo.value.data = data.records || []
tableInfo.value.page.limit = data.pageSize
tableInfo.value.page.curr = data.pageIndex
tableInfo.value.page.rows = data.totalRows
// formItems.value[1].options = data.records || [];
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
tableInfo.value.page.limit = page.value.limit;
tableInfo.value.page.curr = page.value.curr;
getTableData();
};
// 处理表格数据选中
const setSelect = (data, flag) => {
data.forEach((row: any) => {
selectionTreeTableRef.value.tableRef.toggleRowSelection(row, flag);
row.childList && setSelect(row.childList, flag);
});
}
const setCataLog = (dataArr, id, parentDisabled = false) => {
return dataArr.map(item => {
// 当前节点是否被禁选(自身匹配或父节点已禁选)
const isDisabled = parentDisabled || item.guid === id;
// 新节点基础属性
const newItem = {
...item,
disabled: isDisabled
};
// 递归处理子节点,并传递当前节点的禁选状态
if (item.childList && item.childList.length > 0) {
newItem.childList = setCataLog(item.childList, id, isDisabled);
}
return newItem;
})
}
const tableCheckboxSelectChange = (selectRows, row) => {
const check = selectRows.find(item => item.guid === row.guid);
row.childList && setSelect(row.childList, check ? true : false);
}
const checkAll = ref(false)
const tableCheckboxAllSelectChange = (selectRows) => {
checkAll.value = !checkAll.value;
setSelect(tableData.value, checkAll.value);
}
const tableSelectionChange = (val) => {
selectRowData.value = val;
};
const tableBtnClick = (scope, btn) => {
const type = btn.value;
const row = scope.row;
currTableData.value = row;
if (type === 'edit') { // 编辑
drawerInfo.value.visible = true;
drawerInfo.value.header.title = '编辑疾病';
let cata = setCataLog(catalogData.value, row.guid);
formItems.value.map(item => {
if (item.field == 'parentGuid') {
item.options = cata;
}
item.default = row[item.field] || '';
if (item.children) {
item.children.map(child => {
child.default = row[child.field] || '';
if (child.field == 'factor') {
child.default = (row[child.field] !== '' && row[child.field] !== null) ? changeNum(row[child.field], 2) : '';
}
})
}
if (item.inputType == 'integerNumber') {
item.default = typeof row[item.field] == 'number' ? row[item.field] : '';
}
});
drawerInfo.value.type = type;
} else if (type === 'del') { // 删除
open('确定要删除该条数据吗?', 'warning');
}
};
const open = (msg, type, isBatch = false) => {
ElMessageBox.confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: type,
}).then(() => {
let guids = [currTableData.value.guid]
if (isBatch) {
guids = [];
// 处理表格数据选中
const setGuids = (data) => {
data.forEach((row: any) => {
guids.push(row.guid);
row.childList && setGuids(row.childList);
});
}
setGuids(selectRowData.value);
}
deleteDisease(guids).then((res: any) => {
if (res.code == proxy.$passCode) {
getTableData();
getDiseaseData();
ElMessage({
type: "success",
message: "删除成功",
});
} else {
proxy.$ElMessage.error(res.msg);
}
});
});
};
const addDisease = () => {
formItems.value.map(item => {
if (item.field == 'bizState') {
item.default = 'Y';
} else {
if (item.field == 'parentGuid') {
item.options = catalogData.value;
}
item.default = '';
if (item.children) {
item.children.map(child => {
child.default = '';
})
}
}
});
drawerInfo.value.header.title = '新增疾病';
drawerInfo.value.type = 'add';
drawerInfo.value.visible = true;
}
// 批量删除
const batching = (type) => {
if (type == 'delete') {
if (selectRowData.value.length == 0) {
ElMessage({
type: 'error',
message: '请选择需要删除的数据',
})
return
}
open("此操作将永久删除, 是否继续?", "warning", true);
} else if (type == 'import') {
const info = {
dictionaryGuid: ''
}
cacheStore.setCatch('uploadSetting', info)
router.push(
{
name: 'importFileDisease',
query: {
isfileImport: '8'
}
}
);
}
}
const drawerBtnClick = async (btn, info) => {
if (btn.value == "submit") {
drawerInfo.value.footer.btns.map((item: any) => (item.disabled = true));
let params = { ...info, tenantGuid: userData.tenantGuid };
delete params.in;
if (drawerInfo.value.type == "add") {
saveDisease(params)
.then((res: any) => {
if (res.code == proxy.$passCode) {
getTableData();
getDiseaseData();
ElMessage({
type: "success",
message: "新增疾病成功",
});
drawerInfo.value.visible = false;
} else {
proxy.$ElMessage.error(res.msg);
drawerInfo.value.footer.btns.map(
(item: any) => delete item.disabled
);
}
})
.catch(() => {
drawerInfo.value.footer.btns.map((item: any) => delete item.disabled);
});
} else {
params.guid = currTableData.value.guid;
updateDisease(params)
.then((res: any) => {
if (res.code == proxy.$passCode) {
getTableData();
getDiseaseData();
ElMessage({
type: "success",
message: "编辑疾病成功",
});
drawerInfo.value.visible = false;
} else {
proxy.$ElMessage.error(res.msg);
drawerInfo.value.footer.btns.map(
(item: any) => delete item.disabled
);
}
})
.catch(() => {
drawerInfo.value.footer.btns.map((item: any) => delete item.disabled);
});
}
} else {
drawerInfo.value.footer.btns.map((item: any) => delete item.disabled);
nextTick(() => {
drawerInfo.value.visible = false;
});
}
};
onBeforeMount(() => {
getDiseaseData();
});
onActivated(() => {
})
</script>
<template>
<div class="container_wrap">
<div class="table_tool_wrap">
<TableTools :searchItems="searchItemList" :searchId="'data-source-search'" @search="toSearch" />
<div class="tools_btns">
<el-button type="primary" @click="addDisease" v-preReClick>新增</el-button>
<el-button @click="batching('import')" v-preReClick>批量导入</el-button>
<el-button @click="batching('delete')" v-preReClick>批量删除</el-button>
</div>
</div>
<div class="table_panel_wrap">
<Table ref="selectionTreeTableRef" :tableInfo="tableInfo" @tableCheckboxSelectChange="tableCheckboxSelectChange"
@tableCheckboxAllSelectChange="tableCheckboxAllSelectChange" @tableSelectionChange="tableSelectionChange"
@tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
</div>
<Drawer :drawerInfo="drawerInfo" @drawerBtnClick="drawerBtnClick" />
</div>
</template>
<style lang="scss" scoped>
.table_tool_wrap {
width: 100%;
height: 84px !important;
padding: 0 8px;
.tools_btns {
padding: 0px 0 0;
}
}
.table_panel_wrap {
width: 100%;
height: calc(100% - 84px);
padding: 0px 8px 0;
}
</style>
<route lang="yaml">
name: priceCalculate
</route>
<script lang="ts" setup name="priceCalculate">
import { ref } from 'vue';
import TableTools from '@/components/Tools/table_tools.vue';
import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
import { ElMessage, ElMessageBox } from "element-plus";
import { CirclePlus } from "@element-plus/icons-vue";
import { useRouter, useRoute } from "vue-router";
import useUserStore from "@/store/modules/user";
import useDataAssetStore from "@/store/modules/dataAsset";
import { getAllFlowData } from '@/api/modules/queryService';
import { changeNum } from "@/utils/common";
import {
getDiseaseAll,
getPriceList,
deletePrice,
} from '@/api/modules/dataPricing';
const router = useRouter();
const userStore = useUserStore()
const assetStore = useDataAssetStore();
const userData = JSON.parse(userStore.userData)
const { proxy } = getCurrentInstance() as any;
const searchItemList = ref([
{
type: "input",
label: "",
field: "dataResourceName",
default: "",
placeholder: "数据资源名称",
clearable: true,
},
{
type: "cascader",
label: "",
field: "diseaseName",
placeholder: "疾病名称",
default: "",
options: [],
showAllLevels: false,
props: {
checkStrictly: true,
label: "diseaseName",
value: "guid",
children: 'childList',
emitPath: false
},
filterable: true,
clearable: true,
}
]);
const typeMap: any = ref({});
const selectRowData: any = ref([])
const currTableData: any = ref({});
const page: any = ref({
...commonPageConfig,
dataResourceName: '',
diseaseName: ''
});
const tableField: any = ref([
{ label: "序号", type: "index", width: TableColumnWidth.INDEX, align: "center" },
{ label: "定价模型名称", field: "modelName", width: 200 },
{ label: "数据资源名称", field: "dataResourceName", width: 200 },
{ label: "疾病名称", field: "diseaseName", width: 200 },
{
label: "交易价格(元)", field: "dataTransactionPrice", width: 120, align: 'right', getName: (scope) => {
return scope.row.dataTransactionPrice ? changeNum(parseFloat(scope.row.dataTransactionPrice), 2) : '-';
}
},
{ label: "创建人", field: "createUserName", width: 120 },
{ label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME },
]);
const tableInfo = ref({
id: 'api-data-table',
rowKey: 'guid',
loading: false,
fields: tableField.value,
data: [],
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
isMore: false,
width: 120,
btns: [
{ label: "编辑", value: "edit" },
{ label: "删除", value: "del" }
]
}
});
const setTableField = () => {
tableField.value.splice(4, 0, {
label: "交易用途", field: "dataUsage", width: 120, getName: (scope) => {
return typeMap.value['dataUsage'].find((item) => item.value == scope.row['dataUsage'])?.label || '-';
}
});
tableInfo.value.fields = tableField.value;
}
// 获取所有疾病数据
const getDiseaseData = () => {
getDiseaseAll().then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
searchItemList.value[1].options = data;
}
})
}
// 获取数据字典
const getDataType = (dictType, fieldName) => {
getAllFlowData({ dictType }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
setTableField()
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
const toSearch = (val: any, clear: boolean = false) => {
page.value.curr = 1;
if (clear) {
searchItemList.value.map((item) => (item.default = ""));
page.value.dataResourceName = ''
page.value.diseaseName = '';
} else {
page.value.dataResourceName = val.dataResourceName || '';
page.value.diseaseName = val.diseaseName || '';
}
getTableData();
};
const getTableData = () => {
tableInfo.value.loading = true;
getPriceList({
pageSize: page.value.limit,
pageIndex: page.value.curr,
dataResourceName: page.value.dataResourceName,
diseaseName: page.value.diseaseName,
}).then((res: any) => {
tableInfo.value.loading = false;
if (res.code == proxy.$passCode) {
const data = res.data || {};
tableInfo.value.data = data.records || [];
tableInfo.value.page.limit = data.pageSize
tableInfo.value.page.curr = data.pageIndex
tableInfo.value.page.rows = data.totalRows
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
tableInfo.value.page.limit = page.value.limit;
tableInfo.value.page.curr = page.value.curr;
getTableData();
};
const tableBtnClick = (scope, btn) => {
const type = btn.value;
const row = scope.row;
currTableData.value = row;
if (type === 'edit') { // 编辑
router.push(
{
name: 'calculateConfig',
query: {
guid: row.guid,
name: row.modelName,
type: 'edit'
}
}
);
} else if (type === 'del') { // 删除
open('确定要删除该条数据吗?', 'warning');
}
};
const open = (msg, type, isBatch = false) => {
ElMessageBox.confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: type,
}).then(() => {
let guids = [currTableData.value.guid]
if (isBatch) {
guids = selectRowData.value
}
deletePrice(guids).then((res: any) => {
if (res.code == proxy.$passCode) {
getTableData();
ElMessage({
type: "success",
message: "删除成功",
});
} else {
proxy.$ElMessage.error(res.msg);
}
});
});
};
const addDisease = () => {
router.push(
{
name: 'calculateConfig',
query: {
type: 'create'
}
}
);
}
onBeforeMount(() => {
getDiseaseData();
getDataType('数据用途', 'dataUsage')
});
onActivated(() => {
if (assetStore.isRefresh) {//如果是首次加载,则不需要调用
toSearch(null, true);
assetStore.set(false);
}
})
</script>
<template>
<div class="container_wrap">
<div class="table_tool_wrap">
<TableTools :searchItems="searchItemList" :searchId="'data-source-search'" @search="toSearch" />
<div class="tools_btns">
<el-button type="primary" @click="addDisease" v-preReClick>新增</el-button>
</div>
</div>
<div class="table_panel_wrap">
<Table :tableInfo="tableInfo" @tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
</div>
</div>
</template>
<style lang="scss" scoped>
.table_tool_wrap {
width: 100%;
height: 84px !important;
padding: 0 8px;
.tools_btns {
padding: 0px 0 0;
}
}
.table_panel_wrap {
width: 100%;
height: calc(100% - 84px);
padding: 0px 8px 0;
}
</style>
<route lang="yaml">
name: priceConfig
</route>
<script lang="ts" setup name="priceConfig">
import { ref } from 'vue';
import TableTools from '@/components/Tools/table_tools.vue';
import { TableColumnWidth, commonPageConfig } from '@/utils/enum';
import { ElMessage, ElMessageBox } from "element-plus";
import { CirclePlus } from "@element-plus/icons-vue";
import { useRouter, useRoute } from "vue-router";
import useUserStore from "@/store/modules/user";
import useDataAssetStore from "@/store/modules/dataAsset";
import { getAllFlowData } from '@/api/modules/queryService';
import {
getConfigureList,
deleteConfigure,
} from '@/api/modules/dataPricing';
const router = useRouter();
const userStore = useUserStore()
const assetStore = useDataAssetStore();
const userData = JSON.parse(userStore.userData)
const { proxy } = getCurrentInstance() as any;
const searchItemList = ref([
{
type: "input",
label: "",
field: "modelName",
default: "",
placeholder: "定价模型名称",
clearable: true,
},
{
type: "select",
label: "",
field: "institutionType",
placeholder: "机构类型",
default: "",
options: [],
clearable: true,
}
]);
const typeMap = ref({});
const tableData: any = ref([]);
const selectRowData: any = ref([])
const currTableData: any = ref({});
const page: any = ref({
...commonPageConfig,
modelName: '',
institutionType: ''
});
const tableInfo = ref({
id: 'api-data-table',
rowKey: 'guid',
loading: false,
fields: [
{ label: "序号", type: "index", width: TableColumnWidth.INDEX, align: "center" },
{ label: "定价模型名称", field: "modelName", width: 200 },
{
label: "机构类型", field: "institutionType", width: 120, getName: (scope) => {
return filterVal(scope.row.institutionType, 'institutionType')
}
},
{
label: "启用状态", field: "bizState", type: 'tag', width: 120, align: 'center', getName: (scope) => {
return scope.row.bizState == 'Y' ? '启用' : '停用';
}, tagType: (scope) => {
return scope.row.bizState == 'Y' ? 'success' : 'info';
}
},
{ label: "创建人", field: "createUserName", width: 120 },
{ label: "创建时间", field: "createTime", width: TableColumnWidth.DATETIME },
],
data: tableData.value,
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
isMore: false,
width: 120,
btns: [
{ label: "编辑", value: "edit" },
{ label: "删除", value: "del" }
]
}
});
// 过滤
const filterVal = (val, name) => {
if(typeMap.value[name]){
const data = typeMap.value[name].find(item => item.value == val);
return data?.label || '--';
}
};
// 获取需求类型
const getDataType = (dictType, fieldName) => {
getAllFlowData({ dictType }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
let item = searchItemList.value.find(item => item.field == fieldName);
item && (item.options = data);
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
const toSearch = (val: any, clear: boolean = false) => {
page.value.curr = 1;
if (clear) {
searchItemList.value.map((item) => (item.default = ""));
page.value.modelName = '';
page.value.institutionType = '';
} else {
page.value.modelName = val.modelName || '';
page.value.institutionType = val.institutionType || '';
}
getTableData();
};
const getTableData = () => {
tableInfo.value.loading = true;
getConfigureList({
pageSize: page.value.limit,
pageIndex: page.value.curr,
modelName: page.value.modelName,
institutionType: page.value.institutionType,
}).then((res: any) => {
tableInfo.value.loading = false;
if (res.code == proxy.$passCode) {
const data = res.data || {};
tableInfo.value.data = data.records || []
tableInfo.value.page.limit = data.pageSize
tableInfo.value.page.curr = data.pageIndex
tableInfo.value.page.rows = data.totalRows
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
tableInfo.value.page.limit = page.value.limit;
tableInfo.value.page.curr = page.value.curr;
getTableData();
};
const tableBtnClick = (scope, btn) => {
const type = btn.value;
const row = scope.row;
currTableData.value = row;
if (type === 'edit') { // 编辑
router.push(
{
name: 'priceModel',
query: {
guid: row.guid,
name: row.modelName,
type
}
}
);
} else if (type === 'del') { // 删除
open('确定要删除该条数据吗?', 'warning');
}
};
const open = (msg, type, isBatch = false) => {
ElMessageBox.confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: type,
}).then(() => {
let guids = [currTableData.value.guid]
if (isBatch) {
guids = selectRowData.value
}
deleteConfigure(guids).then((res: any) => {
if (res.code == proxy.$passCode) {
getTableData();
ElMessage({
type: "success",
message: "删除成功",
});
} else {
proxy.$ElMessage.error(res.msg);
}
});
});
};
const addDisease = () => {
router.push(
{
name: 'priceModel',
query: {
type: 'create'
}
}
);
}
onBeforeMount(() => {
getDataType('机构类型', 'institutionType')
});
onActivated(() => {
if (assetStore.isRefresh) {//如果是首次加载,则不需要调用
toSearch(null, true);
assetStore.set(false);
}
})
</script>
<template>
<div class="container_wrap">
<div class="table_tool_wrap">
<TableTools :searchItems="searchItemList" :searchId="'data-source-search'" @search="toSearch" />
<div class="tools_btns">
<el-button type="primary" @click="addDisease" v-preReClick>新增</el-button>
</div>
</div>
<div class="table_panel_wrap">
<Table :tableInfo="tableInfo" @tablePageChange="tablePageChange" @tableBtnClick="tableBtnClick" />
</div>
</div>
</template>
<style lang="scss" scoped>
.table_tool_wrap {
width: 100%;
height: 84px !important;
padding: 0 8px;
.tools_btns {
padding: 0px 0 0;
}
}
.table_panel_wrap {
width: 100%;
height: calc(100% - 84px);
padding: 0px 8px 0;
}
</style>
<route lang="yaml">
name: priceModel
</route>
<script lang="ts" setup name="priceModel">
import { ref, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage, ElMessageBox, rowProps } from "element-plus";
import { Plus, CirclePlus, Guide } from "@element-plus/icons-vue";
import useUserStore from "@/store/modules/user";
import useDataAssetStore from "@/store/modules/dataAsset";
import { getAllFlowData } from '@/api/modules/queryService';
import { changeNum } from "@/utils/common";
import {
getDemandTreeList,
getConfigureDetail,
saveConfigure,
updateConfigure
} from '@/api/modules/dataPricing';
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
const userStore = useUserStore();
const assetStore = useDataAssetStore();
const fullPath = route.fullPath;
const userData = JSON.parse(localStorage.userData);
const guid = route.query.guid;
const modelName = route.query.name;
const loading = ref(false);
const flowDetail: any = ref({});
const typeMap: any = ref({});
const expand1 = ref(true)
const expand2 = ref(true)
// 基础设置
const baseConfigFormRef = ref();
const baseConfigFormItems: any = ref([
{
label: '模型名称',
type: 'input',
placeholder: '请输入',
field: 'modelName',
default: '',
clearable: true,
required: true
},
{
label: '机构类型',
type: 'select',
placeholder: '请选择',
field: 'institutionType',
default: '',
options: [],
clearable: true,
required: true,
},
{
label: '启用状态',
type: 'switch',
field: 'bizState',
default: 'Y',
placeholder: '请选择',
activeValue: 'Y',
inactiveValue: 'N',
switchWidth: 32,
},
{
label: '模型公式',
type: 'input',
placeholder: '请输入',
field: 'modelFormula',
default: '',
maxlength: 500,
clearable: true,
required: true,
block: true,
},
])
const baseConfigFormRules = ref({
modelName: [
{ required: true, trigger: 'blur', message: "请填写模型名称" }
],
institutionType: [
{ required: true, trigger: 'change', message: "请选择机构类型" }
],
modelFormula: [
{ required: true, trigger: 'change', message: "请填写模型公式" },
{
validator: (rule, value, callback) => {
validateFormula(value, callback);
},
trigger: 'blur'
}
],
});
const baseConfigForm = ref({
items: baseConfigFormItems.value,
rules: baseConfigFormRules.value,
})
// 校验模型公式
const validateFormula = (value, callback) => {
const baseConfigFormObj = baseConfigFormRef.value;
const baseConfigFormInfo = baseConfigFormObj.formInline;
const formula = value || baseConfigFormInfo.modelFormula;
if (!formula.trim()) {
callback(new Error('请输入模型公式'));
return;
}
const dimensions = signatoryTableList.value.map(s => s.dimensionalityName);
/* 第一步:检查维度是否存在 */
const dimMatches = [...formula.matchAll(/"([^"]+)"/g)];
for (const match of dimMatches) {
const dim = match[1]; // 获取引号内的内容
if (!dimensions.includes(dim)) {
callback(new Error(`维度"${dim}"不存在`));
return;
}
}
/* 第二步:检查维度间是否有运算符 */
if (/"([^"]+)"\s*"([^"]+)"/.test(formula)) {
callback(new Error('维度之间必须使用运算符连接'));
return;
}
/* 第三步:检查运算符使用是否合法 */
// 检查连续运算符
if (/([+\-*\/^]\s*){2,}/.test(formula.replace(/\s+/g, ''))) {
callback(new Error('不允许连续使用运算符'));
return;
}
// 检查运算符后无参数
if (/[+\-*\/^]\s*["(]*(\)|$)/.test(formula.replace(/\s+/g, ''))) {
callback(new Error('公式不完整'));
return;
}
/* 第四步:替换变量并校验公式结构 */
const dimMap = new Map();
dimMatches.forEach((match, i) => {
dimMap.set(match[0], `a${i + 1}`); // 创建维度到变量的映射
});
let formulaWithVars = formula;
dimMap.forEach((varName, dim) => {
formulaWithVars = formulaWithVars.split(dim).join(varName);
});
// 基础字符检查
const validChars = /^[\sa\d+\-*\/^().]+$/;
if (!validChars.test(formulaWithVars)) {
callback(new Error('公式包含非法字符'));
return;
}
/* 增强的括号匹配检查(支持多种括号类型)*/
const bracketPairs = {
'(': ')',
'[': ']',
'{': '}',
'<': '>'
};
const stack = [];
for (const char of formulaWithVars) {
if (bracketPairs[char]) {
stack.push(char);
} else if (Object.values(bracketPairs).includes(char)) {
if (stack.length === 0 || bracketPairs[stack.pop()] !== char) {
callback(new Error('括号使用不匹配或未正确闭合'));
return;
}
}
}
if (stack.length > 0) {
callback(new Error('括号使用不匹配或未正确闭合'));
return;
}
callback(); // 所有检查通过
};
// 维度设置
const currTableData: any = ref({});
const currSignatoryData: any = ref({});
const signatoryTableList: any = ref([]);
const pricingDimensionality: any = ref([]);
// 维度表单
const signatoryFormItems: any = ref([
{
label: '维度名称',
type: 'input',
placeholder: '请输入',
field: 'dimensionalityName',
default: '',
maxlength: 50,
clearable: true,
required: true,
},
{
label: '计算公式',
type: 'select',
placeholder: '请选择',
field: 'computationalFormula',
default: '',
options: [],
clearable: true,
required: true,
},
{
label: '权重(%)',
type: 'input',
placeholder: '请输入',
field: 'weight',
default: '',
inputType: 'factorNumber',
maxlength: 10,
clearable: true,
},
{
label: '启用状态',
type: 'switch',
field: 'invocationStatus',
default: 'Y',
placeholder: '请选择',
activeValue: 'Y',
inactiveValue: 'N',
switchWidth: 32,
},
{
label: '维度说明',
type: 'textarea',
placeholder: '请输入',
field: 'remark',
default: '',
maxlength: 500,
clearable: true,
block: true,
},
{
label: '自定义公式',
type: 'textarea',
placeholder: '请输入',
field: 'customize',
default: '',
maxlength: 500,
clearable: true,
block: true,
visible: false,
},
])
const signatoryFormRules = ref({
dimensionalityName: [
{
validator: (rule: any, value: any, callback: any) => {
if (!value) {
callback(new Error("请填写维度名称"));
} else {
if (drawerInfo.value.type.indexOf('edit') > -1 && currSignatoryData.value.dimensionalityName == value) {
callback();
return
}
const dimName = signatoryTableList.value.map(item => item.dimensionalityName);
if (dimName.indexOf(value) != -1) {
callback(new Error("该名称已存在"));
} else {
callback();
}
}
},
trigger: "blur",
},
],
computationalFormula: [
{ required: true, message: '请选择计算公式', trigger: 'change' }
],
});
// 指标表单
const treeData = ref([]);
const targetFormItems: any = ref([
{
label: '指标名称',
type: 'input',
placeholder: '请输入',
field: 'targetName',
default: '',
maxlength: 50,
clearable: true,
required: true,
},
{
label: '指标类型',
type: 'select',
placeholder: '请选择',
field: 'targetType',
default: '',
options: [],
clearable: true,
required: true,
},
{
label: '权重(%)',
type: 'input',
placeholder: '请输入',
field: 'weight',
default: '',
inputType: 'factorNumber',
maxlength: 10,
clearable: true,
required: true,
visible: false,
},
{
label: '是否展示',
type: 'switch',
field: 'isShow',
default: 'Y',
placeholder: '请选择',
activeValue: 'Y',
inactiveValue: 'N',
switchWidth: 32,
disabled: false,
style: {
width: 'calc(25% - 4px)',
'margin-left': '8px'
}
},
{
label: '是否输入参数',
type: 'switch',
field: 'isInputParameter',
default: 'Y',
placeholder: '请选择',
activeValue: 'Y',
inactiveValue: 'N',
switchWidth: 32,
style: {
width: 'calc(25% - 4px)'
}
},
{
label: '默认值',
type: 'input',
placeholder: '请输入',
field: 'defaultValue',
default: '',
inputType: 'factorNumber',
maxlength: 18,
clearable: true,
required: false
},
{
label: '选择字典',
type: 'select',
placeholder: '请选择',
field: 'dictionaryType',
default: '',
options: [],
clearable: true,
required: true,
visible: false,
},
{
label: '功能名称',
type: 'select',
placeholder: '请选择',
field: 'functionName',
default: '',
options: [],
clearable: true,
required: true,
visible: false,
},
{
label: '选择需求表',
type: 'select',
placeholder: '请选择',
field: 'demandTableGuid',
default: '',
options: [],
props: {
label: "menuName",
value: "guid",
},
filterable: true,
clearable: true,
required: true,
visible: false,
},
{
label: '公式设置',
type: 'textarea',
placeholder: '请输入',
field: 'formulaSetting',
default: '',
resize: 'vertical',
maxlength: 500,
clearable: true,
block: true,
required: true,
},
])
const targetFormRules = ref({
targetName: [
{
validator: (rule: any, value: any, callback: any) => {
if (!value) {
callback(new Error("请填写指标名称"));
} else {
if (drawerInfo.value.type.indexOf('edit') > -1 && currTableData.value.targetName == value) {
callback();
return
}
const dimName = currSignatoryData.value.tableInfo.data.map(item => item.targetName);
if (dimName.indexOf(value) != -1) {
callback(new Error("该名称已存在"));
} else {
callback();
}
}
},
trigger: "blur",
},
],
targetType: [
{ required: true, message: '请选择指标类型', trigger: 'change' }
],
dictionaryType: [
{ required: true, message: '请选择数据字典', trigger: 'change' }
],
functionName: [
{ required: true, message: '请选择功能名称', trigger: 'change' }
],
formulaSetting: [
{ required: true, message: '请填写公式设置', trigger: 'blur' }
],
demandTableGuid: [
{ required: true, message: '请选择需求表', trigger: 'change' }
],
weight: [
{ required: true, message: '请填写权重', trigger: 'change' },
{
validator: (rule: any, value: any, callback: any) => {
if (!value) {
callback(new Error("请填写权重"));
} else {
if (drawerInfo.value.type.indexOf('edit') > -1 && currTableData.value.weight == value) {
callback();
return
}
setTimeout(() => {
let formula: any = [];
if (drawerInfo.value.type.indexOf('edit') > -1) {
formula = currSignatoryData.value.tableInfo.data.map(p => p.targetName == currTableData.value.targetName ? value : p.weight || 0);
} else {
formula = currSignatoryData.value.tableInfo.data.map(p => p.weight || 0);
formula.push(value);
}
const isOver = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) + parseFloat(currentValue), 0); // 初始值为0
if (isOver > 100) {
callback(new Error("该维度权重和已超过100%,请重新填写"));
} else {
callback();
}
}, 200);
}
},
trigger: "blur",
},
],
defaultValue: [
{ required: true, message: '请填写默认值', trigger: 'blur' }
],
});
const dictionaryType = ref('');
const showFactorTable = ref(false);
const mergeRowCount: any = ref({});
const rowCount = {
level: { index: 0, rowspan: [] },
};
const mergeTableData = [
{ id: '1-1', level: '一级', grade: '甲等', factor: '' },
{ id: '1-2', level: '一级', grade: '乙等', factor: '' },
{ id: '1-3', level: '一级', grade: '丙等', factor: '' },
{ id: '2-1', level: '二级', grade: '甲等', factor: '' },
{ id: '2-2', level: '二级', grade: '乙等', factor: '' },
{ id: '2-3', level: '二级', grade: '丙等', factor: '' },
{ id: '3-1', level: '三级', grade: '甲等', factor: '' },
{ id: '3-2', level: '三级', grade: '乙等', factor: '' },
{ id: '3-3', level: '三级', grade: '丙等', factor: '' },
];
const tableData: any = ref([]);
// 抽屉内容
const contents = ref({
target: {
type: "form",
title: "",
col: "span",
formInfo: {
id: "add-dict-form",
readonly: false,
items: targetFormItems.value,
rules: targetFormRules.value,
},
},
signatory: {
type: "form",
title: "",
col: "span",
formInfo: {
id: "add-dict-form",
readonly: false,
items: signatoryFormItems.value,
rules: signatoryFormRules.value,
},
}
})
const drawerInfo: any = ref({
visible: false,
direction: "rtl",
size: 480,
header: {
title: "新增",
},
type: "",
container: {
contents: [],
},
footer: {
visible: true,
btns: [
{ type: "default", label: "取消", value: "cancel" },
{ type: "primary", label: "保存", value: "submit" },
],
},
});
const setTableField = (data) => {
tableData.value = [];
const dictionaryName = typeMap.value['dictionaryType'].find(item => item.value == dictionaryType.value)?.label || '';
const dictionaryJson = dictionaryName && dictionaryName == currTableData.value.dictionaryName ? (currTableData.value.dictionaryJson || []) : [];
if (dictionaryType.value == '1') {
const tData = JSON.parse(JSON.stringify(mergeTableData));
if (dictionaryJson.length) {
tData.map((item, i) => {
item.factor = dictionaryJson[i]?.value || '';
})
}
tableData.value = tData;
getMergeRow();
} else {
if (dictionaryJson.length) {
dictionaryJson.map(item => {
tableData.value.push({
label: item.name,
factor: item.value || '',
})
})
} else {
data.map((item: any) => {
tableData.value.push({
label: item.label,
factor: '',
})
})
}
}
}
const getDictionaryRuleData = () => {
const dictType: any = typeMap.value['dictionaryType'].find(item => item.value == dictionaryType.value)?.label || '';
getAllFlowData({ dictType }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
setTableField(data);
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
// 设置表单信息
const setFormItems = (info = null, type = '') => {
const datas: any = info || flowDetail.value || {};
if (type == 'target') {
targetFormItems.value.map(item => {
item.default = datas[item.field] || '';
if (item.field == 'functionName') {
item.visible = datas.targetType == '2'
} else if (item.field == 'dictionaryType') {
dictionaryType.value = datas[item.field] || '';
item.visible = datas.targetType == '3'
showFactorTable.value = datas.targetType == '3' && datas[item.field]
showFactorTable.value && getDictionaryRuleData();
} else if (item.field == 'formulaSetting') {
item.visible = datas.targetType == '2' && datas.functionName == '2'
} else if (item.field == 'demandTableGuid') {
item.visible = datas.targetType == '2' && datas.functionName == '3'
} else if (item.field == 'isShow' || item.field == 'isInputParameter') {
item.default = datas[item.field] || 'Y';
} else if (item.field == 'isShow') {
item.disabled = datas.targetType == '1'
} else if (item.field == 'defaultValue') {
item.required = datas.targetType == '1';
targetFormRules.value.defaultValue[0].required = datas.targetType == '1';
}
})
} else if (type == 'signatory') {
signatoryFormItems.value.map(item => {
if (item.field == 'invocationStatus') {
item.default = datas[item.field] || 'Y';
} else if (item.field == 'customize') {
item.default = datas[item.field] || '';
item.visible = datas.computationalFormula == 'custom'
} else {
item.default = datas[item.field] || '';
}
})
} else {
baseConfigFormItems.value.map(item => {
if (item.field == 'modelFormula') {
item.default = datas[item.field] || '';
} else {
item.default = datas[item.field] || '';
}
})
}
}
// 过滤
const setVal = (type, row) => {
let formulaText = '';
if (!row[type] || row[type] == 'custom') {
formulaText = row.customize;
} else {
const pricingTargetData = row.pricingTargetRSVOS || row.tableInfo?.data || [];
let formula: any = [];
if (pricingTargetData.length) {
pricingTargetData.map(item => {
if (row[type] == '1') {
formula.push(`${item.targetName}*${item.weight}%`)
} else {
formula.push(`${item.targetName}`)
}
})
if (row[type] == '3') {
formulaText = `公式=${formula.join('*')}`;
} else {
formulaText = `公式=${formula.join('+')}`;
}
}
}
row.customize = formulaText;
pricingDimensionality.value.find(item => {
if (item.dimensionalityName == row.dimensionalityName) {
item.customize = formulaText;
}
})
return formulaText;
};
/**
* 传入多个promise对象,当全部结束时取消Loading
* @param promises 传入多个promise对象,当全部结束时取消Loading
*/
const promiseList = (...promises: Promise<void>[]) => {
// loading方法全局封装成一个组件
loading.value = true;
try {
Promise.all(promises).then(res => {
if (guid) {
setFormItems();
setSignatoryData();
}
});
} catch (e) {
loading.value = false;
} finally {
loading.value = false;
}
};
// 获取数据字典
const getDataType = (dictType, fieldName) => {
return getAllFlowData({ dictType }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || [];
if (fieldName == 'computationalFormula') {
data.push({ label: '自定义', value: 'custom' })
typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
let item = signatoryFormItems.value.find(item => item.field == fieldName);
item && (item.options = data);
} else {
typeMap.value[fieldName] = JSON.parse(JSON.stringify(data));
if (fieldName == 'institutionType') {
let item = baseConfigFormItems.value.find(item => item.field == fieldName);
item && (item.options = data);
} else {
let item = targetFormItems.value.find(item => item.field == fieldName);
item && (item.options = data);
}
}
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
// 初始化维度表格信息
const setSignatoryTableInfo = (row, isEdit = false) => {
const pricingTarget = row.pricingTargetRSVOS || [];
const fieldList: any = [
{ label: "指标名称", field: "targetName", width: 200 },
{
label: "指标类型", field: "targetType", width: 120, getName: (scope) => {
return typeMap.value['targetType'].find(item => item.value == scope.row.targetType)?.label || '--';
}
},
{
label: "默认值", field: "defaultValue", width: 180, align: 'right', getName: (scope) => {
return changeNum(scope.row.defaultValue, 2) || '-'
}
},
{
label: "是否展示", field: "isShow", width: 100, getName: (scope) => {
return scope.row.isShow == 'Y' ? '是' : '否';
}
},
{
label: "是否输入参数", field: "isInputParameter", width: 140, getName: (scope) => {
return scope.row.isInputParameter == 'Y' ? '是' : '否';
}
}
];
row.computationalFormula == '1' && fieldList.splice(2, 0, { label: "权重(%)", field: "weight", width: 100 });
if (isEdit) {
const rIndex = signatoryTableList.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
rIndex != -1 && signatoryTableList.value.splice(rIndex, 1, { ...currSignatoryData.value, ...row, tableInfo: { ...currSignatoryData.value.tableInfo, fields: fieldList } });
const sIndex = pricingDimensionality.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
sIndex != -1 && pricingDimensionality.value.splice(sIndex, 1, { ...currSignatoryData.value, ...row, tableInfo: { ...currSignatoryData.value.tableInfo, fields: fieldList } });
} else {
const tData = {
id: `signatory-${signatoryTableList.value.length}`,
rowKey: '',
fields: fieldList,
data: pricingTarget,
showPage: false,
actionInfo: {
label: "操作",
type: "btn",
width: 120,
btns: [
{ label: "编辑", value: "edit" },
{ label: "删除", value: "del" }
]
}
};
signatoryTableList.value.push({
...row,
tableInfo: tData
});
}
}
// 设置维度指标数据
const setSignatoryData = () => {
const pricingData = flowDetail.value.pricingDimensionalityRSVOS || [];
pricingDimensionality.value = pricingData;
pricingData.map(item => {
const rows = item;
(() => {
setSignatoryTableInfo(rows);
})()
})
}
// 获取详情
const getModelDetail = () => {
loading.value = true;
getConfigureDetail({ guid }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data || {};
flowDetail.value = data;
getDataTypeList()
}
}).catch(() => {
loading.value = false;
})
}
const getDataTypeList = () => {
promiseList(
getTreeData(),
getDataType('机构类型', 'institutionType'),
getDataType('维度计算公式', 'computationalFormula'),
getDataType('维度指标类型', 'targetType'),
getDataType('系统功能', 'functionName'),
getDataType('选择字典', 'dictionaryType'),
)
}
// 获取需求表树形数据
const getTreeData = () => {
return getDemandTreeList({ pageIndex: 1, pageSize: 100000, isCatalog: 'N' }).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data?.records || [];
treeData.value = JSON.parse(JSON.stringify(data));
const item = targetFormItems.value.find(item => item.field == 'demandTableGuid');
item && (item.options = data);
} else {
proxy.$ElMessage.error(res.msg);
}
})
}
const selectChange = async (val, row, info) => {
if (row.field == 'computationalFormula') {
setFormItems(info, 'signatory');
} else if (row.field == 'targetType' || row.field == 'dictionaryType' || row.field == 'functionName') {
const tInfo = { ...currTableData.value, ...info };
await setFormItems(tInfo, 'target');
if (row.field == 'targetType') {
targetFormItems.value[3].default = val == '1' ? 'N' : 'Y';
}
}
}
const inputChange = (val, scope, field) => {
let row = scope.row;
let strArr = val.split(".");
if (strArr.length > 1) {
let right = strArr[1];
if (right === "" || right.length < 2) {
row[field] = val = parseFloat(val || 0).toFixed(2);
}
} else {
row[field] = val = parseFloat(val || 0).toFixed(2);
}
}
/** 输入框输入触发事件 */
const inputEventChange = (val, scope, field) => {
let row = scope.row;
row[field] = row[field].toString().replace(/[^\d.]/g, "")
row[field] = row[field].toString().replace(/\.{2,}/g, ".")
row[field] = row[field].toString().replace(".", "$#$").replace(/\./g, "").replace("$#$", ".")
row[field] = row[field].toString().replace(/^(\-)*(\d+)\.(\d\d\d\d\d\d).*$/, "$1$2.$3")
row[field] = row[field].toString().replace(/^\D*(\d{0,12}(?:\.\d{0,2})?).*$/g, "$1")
}
// 设置表格合并下标
const getMergeRow = () => {
mergeRowCount.value = JSON.parse(JSON.stringify(rowCount));
let list = tableData.value;
for (var i = 0; i < list.length; i++) {
if (i === 0) {
//第一个数据 默认合并1行,开始位置下标默认为0
for (var m in mergeRowCount.value) {
mergeRowCount.value[m].rowspan.push(1);
mergeRowCount.value[m].index = 0;
}
} else {
// 根据拥有子级数量进行合并1
for (var m in mergeRowCount.value) {
let mergeRow = mergeRowCount.value[m];
if (list[i][m] && list[i][m] === list[i - 1][m]) {
mergeRow.rowspan[mergeRow.index] += 1;
mergeRow.rowspan.push(0);
} else {
mergeRow.rowspan.push(1);
mergeRow.index = i;
}
}
}
}
}
// 表格行合并
const tableSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
if (columnIndex === 0) {
const mergeInfo = mergeRowCount.value.level;
const rowspan = mergeInfo.rowspan[rowIndex];
if (rowspan > 0) {
return {
rowspan,
colspan: 1,
};
} else {
return {
rowspan: 0,
colspan: 0,
};
}
}
}
const toPath = () => {
userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
assetStore.set(true);
router.push({
name: 'priceConfig',
})
}
const switchChange = (val, index) => {
pricingDimensionality.value[index].invocationStatus = val;
}
const btnClick = async (btn, row: any = null) => {
const type = btn.value;
if (type == 'dim') {
const baseConfigFormObj = baseConfigFormRef.value;
const baseConfigFormEl = baseConfigFormObj.ruleFormRef;
const baseConfigFormInfo = baseConfigFormObj.formInline;
await setFormItems(baseConfigFormInfo);
baseConfigFormItems.value.at(-1).default = baseConfigFormInfo.modelFormula ? `${baseConfigFormInfo.modelFormula}"${row.dimensionalityName}"` : `"${row.dimensionalityName}"`;
// 触发校验
setTimeout(() => {
baseConfigFormEl.validateField('modelFormula');
}, 200);
} else if (type == 'add-target') {
currSignatoryData.value = row;
currTableData.value = {};
const tData = currSignatoryData.value.tableInfo.data;
await setFormItems(null, 'target');
drawerInfo.value.type = type;
drawerInfo.value.header.title = '新增指标';
targetFormItems.value[2].visible = row.computationalFormula == '1';
targetFormItems.value.at(-2).options.map(o => {
const fData = tData.filter(t => t.targetType == '2' && t.functionName == '3');
o.disabled = fData.find(f => f.demandTableGuid == o.guid)? true: false;
});
drawerInfo.value.container.contents[0] = contents.value.target;
tableData.value = [];
drawerInfo.value.visible = true;
} else if (type == 'add-signatory') {
currSignatoryData.value = {};
currTableData.value = {};
showFactorTable.value = false;
await setFormItems(null, 'signatory');
drawerInfo.value.type = type;
drawerInfo.value.header.title = '新增维度';
drawerInfo.value.container.contents[0] = contents.value.signatory;
drawerInfo.value.visible = true;
} else if (type == 'edit-signatory') {
currSignatoryData.value = row;
currTableData.value = {};
showFactorTable.value = false;
await setFormItems(row, 'signatory');
drawerInfo.value.type = type;
drawerInfo.value.header.title = '编辑维度';
drawerInfo.value.container.contents[0] = contents.value.signatory;
drawerInfo.value.visible = true;
} else if (type == 'del-signatory') {
currSignatoryData.value = row;
open('确定要删除该条维度数据吗?', 'warning', 'signatory');
} else if (type == 'submit') {
const baseConfigFormObj = baseConfigFormRef.value;
const baseConfigFormEl = baseConfigFormObj.ruleFormRef;
const baseConfigFormInfo = baseConfigFormObj.formInline;
baseConfigFormEl.validate((valid, errorItem) => {
if (valid) {
const pricingDimensionalityData = pricingDimensionality.value.map((item, i) => {
item.orderNum = i + 1;
const pricingTargetData = item.pricingTargetRSVOS || item.pricingTargetRQVOS || [];
item.pricingTargetRQVOS = pricingTargetData.map((targetItem, t) => {
targetItem.orderNum = t + 1;
delete targetItem.tableInfo;
return targetItem;
})
delete item.pricingTargetRSVOS;
return item;
})
loading.value = true;
let params = {
...baseConfigFormInfo,
tenantGuid: userData.tenantGuid,
pricingDimensionalityRQVOS: pricingDimensionalityData,
};
if (guid) {
params.guid = guid
updateConfigure(params).then((res: any) => {
loading.value = false;
if (res.code == proxy.$passCode) {
ElMessage({
type: "success",
message: guid ? "编辑定价配置成功" : "新增定价配置成功",
});
toPath()
} else {
proxy.$ElMessage.error(res.msg);
}
}).catch(() => {
loading.value = false;
});
} else {
saveConfigure(params).then((res: any) => {
loading.value = false;
if (res.code == proxy.$passCode) {
ElMessage({
type: "success",
message: guid ? "编辑定价配置成功" : "新增定价配置成功",
});
toPath()
} else {
proxy.$ElMessage.error(res.msg);
}
}).catch(() => {
loading.value = false;
});
}
} else {
expand1.value = true;
var obj = Object.keys(errorItem);
baseConfigFormEl.scrollToField(obj[0]);
}
});
} else if (type == 'cancel') {
ElMessageBox.confirm(
"当前页面尚未保存,确定关闭吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).then(() => {
toPath()
}).catch(() => {
ElMessage({
type: "info",
message: "已取消",
});
});
}
}
const tableBtnClick = async (scope, btn, lData: any = null) => {
const type = btn.value;
const row = scope.row;
currTableData.value = row;
if (type === 'edit') { // 编辑
currSignatoryData.value = lData;
const tData = currSignatoryData.value.tableInfo.data;
await setFormItems(row, 'target');
drawerInfo.value.type = 'edit-target';
drawerInfo.value.header.title = '编辑指标';
targetFormItems.value[2].visible = lData.computationalFormula == '1';
targetFormItems.value.at(-2).options.map(o => {
const fData = tData.filter(t => t.targetType == '2' && t.functionName == '3');
o.disabled = fData.find(f => f.demandTableGuid == o.guid) ? true: false;
});
drawerInfo.value.container.contents[0] = contents.value.target;
drawerInfo.value.visible = true;
} else if (type === 'del') { // 删除
currSignatoryData.value = lData;
open('确定要删除该条数据吗?', 'warning', 'target');
}
};
const open = (msg, type, target) => {
ElMessageBox.confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: type,
}).then(() => {
if (target == 'signatory') {
const tIndex = signatoryTableList.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
tIndex != -1 && signatoryTableList.value.splice(tIndex, 1);
const sIndex = pricingDimensionality.value.findIndex(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
sIndex != -1 && pricingDimensionality.value.splice(sIndex, 1);
} else if (target == 'target') {
const signatoryRow = signatoryTableList.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
if (signatoryRow) {
const tIndex = signatoryRow.tableInfo.data.findIndex(t => t.targetName == currTableData.value.targetName);
tIndex != -1 && signatoryRow.tableInfo.data.splice(tIndex, 1);
}
const signatoryParams = pricingDimensionality.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
if (signatoryParams) {
const sIndex = signatoryParams.pricingTargetRSVOS.findIndex(s => s.targetName == currTableData.value.targetName);
sIndex != -1 && signatoryParams.pricingTargetRSVOS.splice(sIndex, 1);
}
}
});
};
const drawerBtnClick = async (btn, info) => {
if (btn.value == "submit") {
let params = { ...info };
if (drawerInfo.value.type == 'add-signatory') {// 新增维度
setSignatoryTableInfo(params);
pricingDimensionality.value.push({
...params,
pricingTargetRSVOS: []
})
} else if (drawerInfo.value.type == 'edit-signatory') {// 编辑维度
setSignatoryTableInfo(params, true);
} else if (drawerInfo.value.type == 'add-target') {// 新增指标
let factorFull = true;
const dictionaryData = tableData.value.map((d: any) => {
if (dictionaryType.value && !d.factor) {
factorFull = false;
}
if (dictionaryType.value == '1') {
return { name: `${d.level}${d.grade}`, value: d.factor || '' }
} else {
return { name: `${d.label}`, value: d.factor || '' }
}
})
if (dictionaryType.value && !factorFull) {
ElMessage({
type: "error",
message: '请完善字典因子',
});
return;
}
const dictionaryName = typeMap.value['dictionaryType'].find(item => item.value == params.dictionaryType)?.label || '';
const sArr = signatoryTableList.value.map(item => {
if (item.dimensionalityName == currSignatoryData.value.dimensionalityName) {
item.tableInfo.data.push({ ...params, dictionaryJson: dictionaryData, dictionaryName });
}
return item;
})
signatoryTableList.value = sArr;
let signatoryParams = pricingDimensionality.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
if (signatoryParams) {
const sData = signatoryParams.pricingTargetRSVOS.find(s => s.targetName == params.targetName)
!sData && signatoryParams.pricingTargetRSVOS.push({ ...params, dictionaryJson: dictionaryData, dictionaryName })
}
} else if (drawerInfo.value.type == 'edit-target') {// 编辑指标
let factorFull = true;
const dictionaryData = tableData.value.map((d: any) => {
if (dictionaryType.value && !d.factor) {
factorFull = false;
}
if (dictionaryType.value == '1') {
return { name: `${d.level}${d.grade}`, value: d.factor || '' }
} else {
return { name: `${d.label}`, value: d.factor || '' }
}
})
if (dictionaryType.value && !factorFull) {
ElMessage({
type: "error",
message: '请完善字典因子',
});
return;
}
const dictionaryName = typeMap.value['dictionaryType'].find(item => item.value == params.dictionaryType)?.label || '';
const sArr = signatoryTableList.value.map(item => {
if (item.dimensionalityName == currSignatoryData.value.dimensionalityName) {
const tIndex = item.tableInfo.data.findIndex(t => t.targetName == currTableData.value.targetName)
tIndex != -1 && item.tableInfo.data.splice(tIndex, 1, { ...params, dictionaryJson: dictionaryData, dictionaryName })
}
return item;
})
signatoryTableList.value = sArr;
let signatoryParams = pricingDimensionality.value.find(item => item.dimensionalityName == currSignatoryData.value.dimensionalityName);
if (signatoryParams) {
const sIndex = signatoryParams.pricingTargetRSVOS.findIndex(s => s.targetName == currTableData.value.targetName)
sIndex != -1 && signatoryParams.pricingTargetRSVOS.splice(sIndex, 1, { ...params, dictionaryJson: dictionaryData, dictionaryName })
}
}
drawerInfo.value.visible = false;
} else {
nextTick(() => {
drawerInfo.value.visible = false;
});
}
};
onActivated(() => {
let tab: any = userStore.tabbar.find((tab: any) => tab.fullPath === router.currentRoute.value.fullPath);
if (tab) {
switch (route.query.type) {
case 'create':
tab.meta.title = `新增定价配置`;
break;
case 'edit':
tab.meta.title = `编辑-${modelName}`;
break;
case 'detail':
tab.meta.title = `详情-${modelName}`;
break;
}
}
})
onBeforeMount(() => {
if (guid) {
getModelDetail();
} else {
getDataTypeList();
}
})
onMounted(() => {
})
</script>
<template>
<div class="container_wrap full" v-loading="loading">
<div class="content_main panel">
<ContentWrap id="contract-content-wrap" title="基础设置" expandSwicth style="margin-top: 15px" :isExpand="expand1"
@expand="(v) => expand1 = v">
<Form ref="baseConfigFormRef" formId="contract-content-form" :itemList="baseConfigForm.items"
:rules="baseConfigForm.rules" col="col3" />
<div class="signatory-tags" v-if="signatoryTableList.length">
<template v-for="(item, index) in signatoryTableList" :key="'tag_' + index">
<el-button v-if="item.invocationStatus == 'Y'" type="primary" @click="btnClick({ value: 'dim' }, item)">{{
item.dimensionalityName }}</el-button>
</template>
</div>
<div class="tips-text" style="color: #666; margin-bottom: 4px; font-size: 12px;">
备注:模型公式是维度名称与运算符组合,如("维度1"+"维度2")/("维度3"+"维度4")*10,维度名称要用英文引号(")包裹。维度名称在添加维度后才会在公式下展示!
</div>
</ContentWrap>
<ContentWrap id="contract-signatory-wrap" title="维度设置" expandSwicth style="margin-top: 15px" :isExpand="expand2"
@expand="(v) => expand2 = v">
<div class="table_panel_wrap" v-for="(item, index) in signatoryTableList" :key="'wrap_' + index">
<div class="table_tool">
<div class="tool_title">
<div class="title_text">{{ item.dimensionalityName }}</div>
<div class="title_desc"><ellipsis-tooltip :content="setVal('computationalFormula', item)"
refName="tooltipOver"></ellipsis-tooltip></div>
</div>
<div class="tool_btns">
<el-switch v-model="item.invocationStatus" inline-prompt active-value="Y" inactive-value="N"
active-text="启用" inactive-text="停用" @change="val => switchChange(val, index)"
style="margin-right: 8px;" />
<el-button type="primary" @click="btnClick({ value: 'edit-signatory' }, item)">编辑</el-button>
<el-button @click="btnClick({ value: 'del-signatory' }, item)">删除</el-button>
</div>
</div>
<div class="table_panel">
<Table :tableInfo="item.tableInfo" @tableBtnClick="(scope, btn) => tableBtnClick(scope, btn, item)" />
</div>
<el-button type="primary" :icon="CirclePlus" link
@click="btnClick({ value: 'add-target' }, item)">新增指标</el-button>
</div>
<el-button class="btn-block" plain size="large" @click="btnClick({ value: 'add-signatory' })">新增维度</el-button>
</ContentWrap>
</div>
<div class="tool_btns">
<div class="btns">
<el-button @click="btnClick({ value: 'cancel' })">取消</el-button>
<el-button type="primary" @click="btnClick({ value: 'submit' })">提交</el-button>
</div>
</div>
<Drawer :drawerInfo="drawerInfo" @drawerBtnClick="drawerBtnClick" @drawerSelectChange="selectChange">
<template v-if="showFactorTable">
<span class="required_mark" style="line-height: 21px;">字典值对应因子</span>
<div class="table_panel">
<el-table border :data="tableData" :span-method="tableSpanMethod" tooltip-effect="light" style="height: 100%;"
v-if="dictionaryType == '1'">
<el-table-column label="医院等级">
<el-table-column prop="level" label="级别" width="100" />
<el-table-column prop="grade" label="等次" width="100" />
</el-table-column>
<el-table-column prop="factor" label="因子" class-name="edit-col">
<template #default="scope">
<el-input v-model="scope.row.factor" placeholder="请输入"
@change="(val) => inputChange(val, scope, 'factor')"
@input="(val) => inputEventChange(val, scope, 'factor')" />
</template>
</el-table-column>
</el-table>
<el-table border :data="tableData" tooltip-effect="light" style="height: 100%;" v-else>
<el-table-column label="字典名称" prop="label" width="140" />
<el-table-column prop="factor" label="因子" class-name="edit-col">
<template #default="scope">
<el-input v-model="scope.row.factor" placeholder="请输入"
@change="(val) => inputChange(val, scope, 'factor')"
@input="(val) => inputEventChange(val, scope, 'factor')" />
</template>
</el-table-column>
</el-table>
</div>
</template>
</Drawer>
</div>
</template>
<style scoped lang="scss">
.container_wrap {
overflow: hidden;
.content_main {
height: calc(100% - 45px);
overflow: hidden auto;
&.panel {
padding: 0 16px 16px;
}
:deep(.el-card) {
&#contract-signatory-wrap {
.card-body-content {
padding: 8px 16px;
}
}
}
.signatory-tags {
margin-top: 2px;
margin-bottom: 11px;
}
.table_panel_wrap {
margin-bottom: 4px;
.table_tool {
height: 36px;
display: flex;
justify-content: space-between;
align-items: center;
.tool_title {
display: flex;
justify-content: start;
flex: 1;
}
.title_text {
font-weight: 600;
margin-right: 8px;
}
.title_desc {
color: #b2b2b2;
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.tool_btns {
margin: 0;
border: none;
}
}
.table_panel {
margin-bottom: 4px;
height: 212px;
}
}
}
.btn-block {
width: 100%;
margin: 16px 0 8px;
}
.tool_btns {
height: 44px;
margin: 0 -8px;
display: flex;
justify-content: center;
align-items: center;
border-top: 1px solid #d9d9d9;
}
}
:deep(.el-drawer) {
.table_panel {
th {
text-align: center;
}
.el-table__cell {
&.edit-col {
padding: 4px 0;
.cell {
padding: 0 4px;
.el-input {
height: 28px;
}
}
}
}
}
}
</style>
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!