fc97e0eb by lxs

数据定价更新

1 parent 3a72832b
...@@ -52,11 +52,13 @@ const dictionaryData: any = ref([]); ...@@ -52,11 +52,13 @@ const dictionaryData: any = ref([]);
52 const diseaseData: any = ref([]); 52 const diseaseData: any = ref([]);
53 const qualityScoreData: any = ref({}); 53 const qualityScoreData: any = ref({});
54 const disScore: any = ref([]); 54 const disScore: any = ref([]);
55 const exportData: any = ref([]); 55 const buildInData: any = ref([]);
56 const dataUsage = ref({ 56 const dataUsage = ref({
57 field: '', 57 field: '',
58 dictValue: '' 58 dictValue: ''
59 }); 59 });
60
61
60 // 基础设置 62 // 基础设置
61 const baseConfigFormRef = ref(); 63 const baseConfigFormRef = ref();
62 const baseConfigFormItems: any = ref([ 64 const baseConfigFormItems: any = ref([
...@@ -143,8 +145,13 @@ const tableLoading = ref(false); ...@@ -143,8 +145,13 @@ const tableLoading = ref(false);
143 const dataTransactionPrice: any = ref(''); 145 const dataTransactionPrice: any = ref('');
144 const setFormItems = (info = null) => { 146 const setFormItems = (info = null) => {
145 let datas: any = info || flowDetail.value || {}; 147 let datas: any = info || flowDetail.value || {};
146 const dData = datas.dictionaryJson ? JSON.parse(datas.dictionaryJson) : {}; 148 const dictData = datas.dictionaryJson ? JSON.parse(datas.dictionaryJson) : {};
147 datas = { ...datas, ...dData }; 149 const builtIndicators = datas.builtIndicators || [];
150 let buildData = {};
151 builtIndicators.map(item => {
152 buildData[`build_${item.guid}`] = item.targetValue;
153 });
154 datas = { ...datas, ...dictData, ...buildData };
148 baseConfigFormItems.value.map(item => { 155 baseConfigFormItems.value.map(item => {
149 item.default = datas[item.field] || ''; 156 item.default = datas[item.field] || '';
150 item.label == '数据用途' && (dataUsage.value.dictValue = datas[item.field] || ''); 157 item.label == '数据用途' && (dataUsage.value.dictValue = datas[item.field] || '');
...@@ -266,8 +273,10 @@ const getDetail = () => { ...@@ -266,8 +273,10 @@ const getDetail = () => {
266 typeMap.value.modelGuid.unshift(mtem); 273 typeMap.value.modelGuid.unshift(mtem);
267 baseConfigFormItems.value[0].options.unshift(mtem); 274 baseConfigFormItems.value[0].options.unshift(mtem);
268 }; 275 };
276 setTimeout(() => {
269 getModelInfo(flowDetail.value.modelGuid); 277 getModelInfo(flowDetail.value.modelGuid);
270 getDataTypeList() 278 getDataTypeList()
279 }, 200)
271 } 280 }
272 }).catch(() => { 281 }).catch(() => {
273 loading.value = false; 282 loading.value = false;
...@@ -304,7 +313,7 @@ const setDictFormItems = (dictList) => { ...@@ -304,7 +313,7 @@ const setDictFormItems = (dictList) => {
304 filterable: true, 313 filterable: true,
305 required: true, 314 required: true,
306 }); 315 });
307 baseConfigFormRules.value[dictField] = { required: true, trigger: 'change', message: `请选择${dictName}` }; 316 baseConfigFormRules.value[dictField] = [{ required: true, trigger: 'change', message: `请选择${dictName}` }];
308 dictName == '数据用途' && (dataUsage.value.field = dictField); 317 dictName == '数据用途' && (dataUsage.value.field = dictField);
309 (() => { 318 (() => {
310 if (typeMap.value[dictField] == undefined) { 319 if (typeMap.value[dictField] == undefined) {
...@@ -338,7 +347,7 @@ const setDiseaseFormItems = () => { ...@@ -338,7 +347,7 @@ const setDiseaseFormItems = () => {
338 clearable: true, 347 clearable: true,
339 required: true, 348 required: true,
340 }); 349 });
341 baseConfigFormRules.value.diseaseGuid = { required: true, trigger: 'change', message: "请选择所属疾病" }; 350 baseConfigFormRules.value.diseaseGuid = [{ required: true, trigger: 'change', message: "请选择所属疾病" }];
342 if (typeMap.value['diseaseGuid'] == undefined) { 351 if (typeMap.value['diseaseGuid'] == undefined) {
343 getDiseaseData(); 352 getDiseaseData();
344 } else { 353 } else {
...@@ -361,16 +370,44 @@ const setBuildInFormItems = (buildList) => { ...@@ -361,16 +370,44 @@ const setBuildInFormItems = (buildList) => {
361 buildList.map(b => { 370 buildList.map(b => {
362 const buildName = b.targetName; 371 const buildName = b.targetName;
363 const buildField = `build_${b.guid}`; 372 const buildField = `build_${b.guid}`;
373 buildInData.value.push({
374 guid: b.guid,
375 targetName: buildName,
376 })
364 baseConfigFormItems.value.push({ 377 baseConfigFormItems.value.push({
365 label: buildName, 378 label: buildName,
366 type: 'input', 379 type: 'input',
367 placeholder: '', 380 placeholder: '',
368 field: buildField, 381 field: buildField,
369 default: b.defaultValue || '', 382 default: changeNum(b.defaultValue, 2),
383 inputType: 'moneyNumber',
384 maxlength: 18,
370 clearable: true, 385 clearable: true,
371 disabled: b.isInputParameter == 'Y' 386 disabled: b.isInputParameter != 'Y'
372 }); 387 });
373 baseConfigFormRules.value[buildField] = { required: true, trigger: 'blur', message: `请填写${buildName}` }; 388 baseConfigFormRules.value[buildField] = [
389 { required: true, message: `请填写${buildName}`, trigger: 'blur' },
390 {
391 validator: (rule, value, callback) => {
392 if (value === '') {
393 callback(new Error(`请填写${buildName}`));
394 return;
395 }
396 const num = parseFloat(value);
397 if (isNaN(num)) {
398 callback(new Error('请输入有效的数字'));
399 return;
400 }
401
402 // 已自动保留两位小数,不需再验证小数位数
403 if (num < 0 || num > b.defaultValue) {
404 callback(new Error(`输入值必须在0到${b.defaultValue}之间`));
405 } else {
406 callback();
407 }
408 }, trigger: "blur",
409 },
410 ]
374 }) 411 })
375 }; 412 };
376 413
...@@ -413,7 +450,7 @@ const setFormItemData = async () => { ...@@ -413,7 +450,7 @@ const setFormItemData = async () => {
413 // 添加数据字典 450 // 添加数据字典
414 dictionaryList.length > 0 && await setDictFormItems(dictionaryList); 451 dictionaryList.length > 0 && await setDictFormItems(dictionaryList);
415 // 添加内置指标 452 // 添加内置指标
416 // buildInList.length > 0 && await setBuildInFormItems(buildInList); 453 buildInList.length > 0 && await setBuildInFormItems(buildInList);
417 454
418 setTimeout(() => { 455 setTimeout(() => {
419 baseConfigFormRef.value.ruleFormRef?.clearValidate(); 456 baseConfigFormRef.value.ruleFormRef?.clearValidate();
...@@ -476,6 +513,7 @@ const getModelConfig = (mGuid) => { ...@@ -476,6 +513,7 @@ const getModelConfig = (mGuid) => {
476 demandTableList.value = data.pricingDemandMenuRSVOS || []; 513 demandTableList.value = data.pricingDemandMenuRSVOS || [];
477 pricingTargetList.value = data.pricingTargetRSVOS || []; 514 pricingTargetList.value = data.pricingTargetRSVOS || [];
478 demandTableFieldAllNum.value = data.fieldCount || 0; 515 demandTableFieldAllNum.value = data.fieldCount || 0;
516 buildInData.value = [];
479 } 517 }
480 }) 518 })
481 } 519 }
...@@ -773,34 +811,7 @@ const toPath = () => { ...@@ -773,34 +811,7 @@ const toPath = () => {
773 }) 811 })
774 } 812 }
775 813
776 // 获取维度公式计算结果 814 // 获取疾病得分
777 const getSignatory = (row) => {
778 let formulaVal = 0;
779 const pricingTargetData = row.pricingTargetRSVOS || [];
780 if (!row.computationalFormula || row.computationalFormula == 'custom') {
781 let formula = row.customize;
782 // 遍历数组,检查 customize 是否包含对应的 targetName,若包含则替换为 tNum
783 pricingTargetData.forEach((item) => {
784 if (formula.includes(item.targetName)) {
785 formula = formula.replace(new RegExp(item.targetName, 'g'), item.tNum);
786 }
787 });
788 // 使用 eval 计算公式结果(注意:eval 存在安全风险,仅适用于受控环境)
789 try {
790 formulaVal = eval(formula);
791 } catch (error) {
792 console.error('公式计算错误:', error);
793 }
794 } else {
795 const formula = pricingTargetData.map(item => item.tNum);
796 if (row.computationalFormula == '3') {
797 formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) * parseFloat(currentValue), 1); // 初始值为1
798 } else {
799 formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) + parseFloat(currentValue), 0); // 初始值为0
800 }
801 }
802 return (Math.round(formulaVal * 100) / 100).toFixed(2);
803 };
804 const getTargetNum = (params) => { 815 const getTargetNum = (params) => {
805 // loading.value = true; 816 // loading.value = true;
806 getPriceResult(params).then((res: any) => { 817 getPriceResult(params).then((res: any) => {
...@@ -816,151 +827,6 @@ const getTargetNum = (params) => { ...@@ -816,151 +827,6 @@ const getTargetNum = (params) => {
816 }); 827 });
817 } 828 }
818 829
819 // 生成报告内容
820 const reporting = (formInfo) => {
821 let resultInfo: any = [];
822 const signatoryData = JSON.parse(JSON.stringify(modelData.value.pricingDimensionalityRSVOS || '[]'));
823 signatoryData.map((sign, s) => {
824 resultInfo.push({
825 dimensionalityName: sign.dimensionalityName,
826 computationalFormula: sign.computationalFormula,
827 customize: sign.customize,
828 pricingTargetRSVOS: []
829 });
830 const targets = sign.pricingTargetRSVOS || [];
831 const signTargets = targets.map(t => {
832 let tNum: any = 0, tCustomize = '';
833 if (t.targetType == '3') { // 指标类型-数据字典
834 const tName = dictionaryData.value.find(d => d.guid == t.guid) ? `dict_${t.guid}` : '';
835 if (tName) {
836 const pVal = typeMap.value[tName].find(t => t.value == formInfo[tName]);
837 const dictionary = t.dictionaryJson.find(d => d.name == pVal.label);
838 if (sign.computationalFormula == '1') {// 加权平均
839 tNum = parseFloat(t.weight) / 100 * parseFloat(dictionary?.value || t.defaultValue || 0);
840 tCustomize = `权重${parseFloat(t.weight) / 100} * 因子/默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
841 } else { // 其他
842 tNum = parseFloat(dictionary?.value || t.defaultValue || 0);
843 tCustomize = `默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
844 }
845 t.dictionaryName == '数据用途' && (dataUsage.value.dictValue = pVal.value || '');
846 }
847 } else if (t.targetType == '2') {// 指标类型-系统功能
848 if (t.functionName == '1') { // 功能名称-质量评价模型
849 const score = parseFloat(qualityScoreData.value.qualityScore || 0);
850 tNum = parseFloat(t.weight || 1) / 100 * score / 100;
851 tCustomize = `权重${parseFloat(t.weight || 1) / 100} * 模型评分${score}/100`;
852 } else if (t.functionName == '2') { // 功能名称-疾病管理
853 if (sign.computationalFormula == '1') {// 加权平均
854 const score = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
855 tNum = parseFloat(t.weight) / 100 * score;
856 tCustomize = `权重${parseFloat(t.weight) / 100} * 疾病得分${score}`;
857 } else { //其他
858 tNum = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
859 tCustomize = `疾病得分${tNum}`;
860 }
861 } else if (t.functionName == '3') {// 功能名称-需求表管理
862 const tData = tableData.value.find(f => f.demandTableGuid == t.demandTableGuid || f.guid == t.demandTableGuid);
863 if (tData) {
864 if (sign.computationalFormula == '1') {// 加权平均
865 tNum = parseFloat(t.weight) / 100 * (parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0));
866 tCustomize = `权重${parseFloat(t.weight) / 100} * 匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
867 } else { //其他
868 tNum = parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0);
869 tCustomize = `匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
870 }
871 }
872 }
873 } else { // 指标类型-系统内置
874 if (sign.computationalFormula == '1') {// 加权平均
875 tNum = parseFloat(t.weight) / 100 * parseFloat(t.defaultValue || 0);
876 tCustomize = `权重${parseFloat(t.weight) / 100} * 默认值${parseFloat(t.defaultValue || 0)}`;
877 } else { //其他
878 tNum = parseFloat(t.defaultValue || 0);
879 tCustomize = `默认值${parseFloat(t.defaultValue || 0)}`;
880 }
881 }
882 t.tNum = (Math.round(parseFloat(tNum) * 100) / 100).toFixed(2);
883 resultInfo[s].pricingTargetRSVOS.push({
884 targetName: t.targetName,
885 targetType: t.targetType,
886 functionName: t.functionName,
887 customize: tCustomize,
888 tNum: t.tNum,
889 })
890 return t;
891 })
892 sign.pricingTargetRSVOS = signTargets;
893 sign.sNum = getSignatory(sign);
894 resultInfo[s].sNum = sign.sNum;
895 })
896 // exportData.value = resultInfo;
897 return { signatoryData, resultInfo };
898 }
899
900 // 计算价格
901 const calculatePrice = (pData) => {
902 let modelFormula = modelData.value.modelFormula;
903 // 1. 移除所有干扰的引号(确保是数学表达式)
904 modelFormula = modelFormula.replace(/["']/g, "").trim();
905
906 // 2. 定义允许的数学运算符和函数
907 const allowedOperators = /[+\-*/%^() .\d]/;
908 const mathFunctions = ['sin', 'cos', 'tan', 'log', 'sqrt', 'abs', 'pow'];
909
910 // 3. 提取变量名
911 const variableRegex = /[\u4e00-\u9fa5a-zA-Z_][\u4e00-\u9fa5a-zA-Z0-9_]*/g;
912 const variableNames = [...new Set(modelFormula.match(variableRegex) || [])];
913
914 // 4. 构建变量映射
915 const variables = {};
916 variableNames.forEach(name => {
917 const dim = pData.find(d => d.dimensionalityName === name);
918 variables[name] = dim ? parseFloat(dim.sNum) || 0 : 0;
919 });
920
921 // 5. 替换变量为数值(考虑边界情况)
922 let expression = modelFormula;
923 Object.keys(variables).forEach(name => {
924 expression = expression.replace(new RegExp(name, 'g'), variables[name]);
925 });
926
927 // 6. 表达式规范化(不丢失括号)
928 expression = expression
929 .replace(/\s+/g, '') // 去空格
930 .replace(/\^/g, '**') // 幂运算转换
931 .replace(/"|'/g, '') // 去引号(不破坏括号)
932 .replace(/(\d)\(/g, '$1*(') // 处理隐式乘法
933 .replace(/\)\(/g, ')*('); // 括号间乘法
934
935 // 7. 验证括号配对
936 const balance = expression.split('').reduce((acc, char) => {
937 if (char === '(') acc++;
938 if (char === ')') acc--;
939 return acc;
940 }, 0);
941
942 if (balance !== 0) {
943 console.error('括号不匹配');
944 return NaN;
945 }
946
947 // 8. 安全计算
948 try {
949 const result = new Function('return ' + expression)();
950 const roundedResult = Math.round(parseFloat(result) * 100) / 100;
951
952 dataTransactionPrice.value = roundedResult.toFixed(2);
953 return roundedResult;
954 } catch (error) {
955 console.error('计算错误:', {
956 error,
957 original: modelFormula,
958 processed: expression
959 });
960 return NaN;
961 }
962 };
963
964 // 获取定价计算配置参数 830 // 获取定价计算配置参数
965 const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => { 831 const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
966 const modelName = typeMap.value.modelGuid.find(d => d.guid == baseConfigFormInfo.modelGuid)?.modelName || ''; 832 const modelName = typeMap.value.modelGuid.find(d => d.guid == baseConfigFormInfo.modelGuid)?.modelName || '';
...@@ -983,13 +849,20 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => { ...@@ -983,13 +849,20 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
983 const parentsData = baseConfigFormObj.getCascaderCheckedData(); 849 const parentsData = baseConfigFormObj.getCascaderCheckedData();
984 params.diseaseName = parentsData[0]?.label || ''; 850 params.diseaseName = parentsData[0]?.label || '';
985 } 851 }
986 let dictionaryJson = {}; 852 let dictionaryJson = {}, builtInTarget: any = [];
987 for (var b in baseConfigFormInfo) { 853 for (var b in baseConfigFormInfo) {
988 if (b.indexOf('dict_') > -1) { 854 if (b.indexOf('dict_') > -1) {
989 dictionaryJson[b] = baseConfigFormInfo[b]; 855 dictionaryJson[b] = baseConfigFormInfo[b];
990 } 856 }
991 } 857 }
858 buildInData.value.map(item => {
859 builtInTarget.push({
860 ...item,
861 targetValue: baseConfigFormInfo[`build_${item.guid}`],
862 })
863 })
992 params.dictionaryJson = Object.keys(dictionaryJson).length ? JSON.stringify(dictionaryJson) : ''; 864 params.dictionaryJson = Object.keys(dictionaryJson).length ? JSON.stringify(dictionaryJson) : '';
865 params.builtIndicators = builtInTarget;
993 let demandMatchingData: any = []; 866 let demandMatchingData: any = [];
994 tableData.value.map(item => { 867 tableData.value.map(item => {
995 demandMatchingData.push({ 868 demandMatchingData.push({
...@@ -1019,15 +892,16 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => { ...@@ -1019,15 +892,16 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
1019 const getCalculatPrice = async (params) => { 892 const getCalculatPrice = async (params) => {
1020 try { 893 try {
1021 const res: any = await calculatPrice(params); 894 const res: any = await calculatPrice(params);
895 loading.value = false;
1022 if (res.code === proxy.$passCode) { 896 if (res.code === proxy.$passCode) {
1023 const data = res.data || {}; 897 const data = res.data || {};
1024 return data; // 返回计算结果以便后续使用 898 return data; // 返回计算结果以便后续使用
1025 } else { 899 } else {
1026 proxy.$ElMessage.error(res.msg); 900 proxy.$ElMessage.error(res.msg);
1027 loading.value = false;
1028 throw new Error(res.msg); // 抛出错误以便 catch 捕获 901 throw new Error(res.msg); // 抛出错误以便 catch 捕获
1029 } 902 }
1030 } catch (error) { 903 } catch (error) {
904 console.error('计算价格失败:', error);
1031 loading.value = false; 905 loading.value = false;
1032 throw error; // 重新抛出错误 906 throw error; // 重新抛出错误
1033 } 907 }
...@@ -1047,9 +921,8 @@ const checkForm = (type) => { ...@@ -1047,9 +921,8 @@ const checkForm = (type) => {
1047 // 显示结果 921 // 显示结果
1048 dataTransactionPrice.value = priceData.transactionPrice.toFixed(2); 922 dataTransactionPrice.value = priceData.transactionPrice.toFixed(2);
1049 923
1050 if (type == 'calculate') { 924 if (type == 'export') {
1051 loading.value = false; 925 loading.value = true;
1052 } else if (type == 'export') {
1053 const exportOut = { 926 const exportOut = {
1054 one: priceData.one, 927 one: priceData.one,
1055 two: priceData.two, 928 two: priceData.two,
...@@ -1078,6 +951,7 @@ const checkForm = (type) => { ...@@ -1078,6 +951,7 @@ const checkForm = (type) => {
1078 ...paramsInfo, 951 ...paramsInfo,
1079 dataTransactionPrice: dataTransactionPrice.value, 952 dataTransactionPrice: dataTransactionPrice.value,
1080 } 953 }
954 loading.value = true;
1081 savePrice(params).then((res: any) => { 955 savePrice(params).then((res: any) => {
1082 loading.value = false; 956 loading.value = false;
1083 if (res.code == proxy.$passCode) { 957 if (res.code == proxy.$passCode) {
...@@ -1177,6 +1051,7 @@ onBeforeMount(() => { ...@@ -1177,6 +1051,7 @@ onBeforeMount(() => {
1177 } 1051 }
1178 }) 1052 })
1179 onMounted(() => { 1053 onMounted(() => {
1054 getModel()
1180 }) 1055 })
1181 </script> 1056 </script>
1182 <template> 1057 <template>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!