e18ddc85 by lxs Committed by lihua

数据定价更新

1 parent 9b765bc9
...@@ -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([
...@@ -144,10 +146,10 @@ const dataTransactionPrice: any = ref(''); ...@@ -144,10 +146,10 @@ 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 dictData = datas.dictionaryJson ? JSON.parse(datas.dictionaryJson) : {}; 148 const dictData = datas.dictionaryJson ? JSON.parse(datas.dictionaryJson) : {};
147 const builtIndicators = datas.builtIndicators || buildInData.value || []; 149 const builtIndicators = datas.builtIndicators || [];
148 let buildData = {}; 150 let buildData = {};
149 builtIndicators.map(item => { 151 builtIndicators.map(item => {
150 buildData[`build_${item.guid}`] = item.isInputParameter != 'Y' ? changeNum(item.targetValue, 2) : item.targetValue != '' && item.targetValue != null ? parseFloat(item.targetValue).toFixed(2) : ''; 152 buildData[`build_${item.guid}`] = item.targetValue;
151 }); 153 });
152 datas = { ...datas, ...dictData, ...buildData }; 154 datas = { ...datas, ...dictData, ...buildData };
153 baseConfigFormItems.value.map(item => { 155 baseConfigFormItems.value.map(item => {
...@@ -271,8 +273,10 @@ const getDetail = () => { ...@@ -271,8 +273,10 @@ const getDetail = () => {
271 typeMap.value.modelGuid.unshift(mtem); 273 typeMap.value.modelGuid.unshift(mtem);
272 baseConfigFormItems.value[0].options.unshift(mtem); 274 baseConfigFormItems.value[0].options.unshift(mtem);
273 }; 275 };
276 setTimeout(() => {
274 getModelInfo(flowDetail.value.modelGuid); 277 getModelInfo(flowDetail.value.modelGuid);
275 getDataTypeList() 278 getDataTypeList()
279 }, 200)
276 } 280 }
277 }).catch(() => { 281 }).catch(() => {
278 loading.value = false; 282 loading.value = false;
...@@ -309,7 +313,7 @@ const setDictFormItems = (dictList) => { ...@@ -309,7 +313,7 @@ const setDictFormItems = (dictList) => {
309 filterable: true, 313 filterable: true,
310 required: true, 314 required: true,
311 }); 315 });
312 baseConfigFormRules.value[dictField] = { required: true, trigger: 'change', message: `请选择${dictName}` }; 316 baseConfigFormRules.value[dictField] = [{ required: true, trigger: 'change', message: `请选择${dictName}` }];
313 dictName == '数据用途' && (dataUsage.value.field = dictField); 317 dictName == '数据用途' && (dataUsage.value.field = dictField);
314 (() => { 318 (() => {
315 if (typeMap.value[dictField] == undefined) { 319 if (typeMap.value[dictField] == undefined) {
...@@ -343,7 +347,7 @@ const setDiseaseFormItems = () => { ...@@ -343,7 +347,7 @@ const setDiseaseFormItems = () => {
343 clearable: true, 347 clearable: true,
344 required: true, 348 required: true,
345 }); 349 });
346 baseConfigFormRules.value.diseaseGuid = { required: true, trigger: 'change', message: "请选择所属疾病" }; 350 baseConfigFormRules.value.diseaseGuid = [{ required: true, trigger: 'change', message: "请选择所属疾病" }];
347 if (typeMap.value['diseaseGuid'] == undefined) { 351 if (typeMap.value['diseaseGuid'] == undefined) {
348 getDiseaseData(); 352 getDiseaseData();
349 } else { 353 } else {
...@@ -366,16 +370,44 @@ const setBuildInFormItems = (buildList) => { ...@@ -366,16 +370,44 @@ const setBuildInFormItems = (buildList) => {
366 buildList.map(b => { 370 buildList.map(b => {
367 const buildName = b.targetName; 371 const buildName = b.targetName;
368 const buildField = `build_${b.guid}`; 372 const buildField = `build_${b.guid}`;
373 buildInData.value.push({
374 guid: b.guid,
375 targetName: buildName,
376 })
369 baseConfigFormItems.value.push({ 377 baseConfigFormItems.value.push({
370 label: buildName, 378 label: buildName,
371 type: 'input', 379 type: 'input',
372 placeholder: '', 380 placeholder: '',
373 field: buildField, 381 field: buildField,
374 default: b.defaultValue || '', 382 default: changeNum(b.defaultValue, 2),
383 inputType: 'moneyNumber',
384 maxlength: 18,
375 clearable: true, 385 clearable: true,
376 disabled: b.isInputParameter == 'Y' 386 disabled: b.isInputParameter != 'Y'
377 }); 387 });
378 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 ]
379 }) 411 })
380 }; 412 };
381 413
...@@ -418,7 +450,7 @@ const setFormItemData = async () => { ...@@ -418,7 +450,7 @@ const setFormItemData = async () => {
418 // 添加数据字典 450 // 添加数据字典
419 dictionaryList.length > 0 && await setDictFormItems(dictionaryList); 451 dictionaryList.length > 0 && await setDictFormItems(dictionaryList);
420 // 添加内置指标 452 // 添加内置指标
421 // buildInList.length > 0 && await setBuildInFormItems(buildInList); 453 buildInList.length > 0 && await setBuildInFormItems(buildInList);
422 454
423 setTimeout(() => { 455 setTimeout(() => {
424 baseConfigFormRef.value.ruleFormRef?.clearValidate(); 456 baseConfigFormRef.value.ruleFormRef?.clearValidate();
...@@ -784,34 +816,7 @@ const toPath = () => { ...@@ -784,34 +816,7 @@ const toPath = () => {
784 }) 816 })
785 } 817 }
786 818
787 // 获取维度公式计算结果 819 // 获取疾病得分
788 const getSignatory = (row) => {
789 let formulaVal = 0;
790 const pricingTargetData = row.pricingTargetRSVOS || [];
791 if (!row.computationalFormula || row.computationalFormula == 'custom') {
792 let formula = row.customize;
793 // 遍历数组,检查 customize 是否包含对应的 targetName,若包含则替换为 tNum
794 pricingTargetData.forEach((item) => {
795 if (formula.includes(item.targetName)) {
796 formula = formula.replace(new RegExp(item.targetName, 'g'), item.tNum);
797 }
798 });
799 // 使用 eval 计算公式结果(注意:eval 存在安全风险,仅适用于受控环境)
800 try {
801 formulaVal = eval(formula);
802 } catch (error) {
803 console.error('公式计算错误:', error);
804 }
805 } else {
806 const formula = pricingTargetData.map(item => item.tNum);
807 if (row.computationalFormula == '3') {
808 formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) * parseFloat(currentValue), 1); // 初始值为1
809 } else {
810 formulaVal = formula.reduce((accumulator, currentValue) => parseFloat(accumulator) + parseFloat(currentValue), 0); // 初始值为0
811 }
812 }
813 return (Math.round(formulaVal * 100) / 100).toFixed(2);
814 };
815 const getTargetNum = (params) => { 820 const getTargetNum = (params) => {
816 // loading.value = true; 821 // loading.value = true;
817 getPriceResult(params).then((res: any) => { 822 getPriceResult(params).then((res: any) => {
...@@ -827,151 +832,6 @@ const getTargetNum = (params) => { ...@@ -827,151 +832,6 @@ const getTargetNum = (params) => {
827 }); 832 });
828 } 833 }
829 834
830 // 生成报告内容
831 const reporting = (formInfo) => {
832 let resultInfo: any = [];
833 const signatoryData = JSON.parse(JSON.stringify(modelData.value.pricingDimensionalityRSVOS || '[]'));
834 signatoryData.map((sign, s) => {
835 resultInfo.push({
836 dimensionalityName: sign.dimensionalityName,
837 computationalFormula: sign.computationalFormula,
838 customize: sign.customize,
839 pricingTargetRSVOS: []
840 });
841 const targets = sign.pricingTargetRSVOS || [];
842 const signTargets = targets.map(t => {
843 let tNum: any = 0, tCustomize = '';
844 if (t.targetType == '3') { // 指标类型-数据字典
845 const tName = dictionaryData.value.find(d => d.guid == t.guid) ? `dict_${t.guid}` : '';
846 if (tName) {
847 const pVal = typeMap.value[tName].find(t => t.value == formInfo[tName]);
848 const dictionary = t.dictionaryJson.find(d => d.name == pVal.label);
849 if (sign.computationalFormula == '1') {// 加权平均
850 tNum = parseFloat(t.weight) / 100 * parseFloat(dictionary?.value || t.defaultValue || 0);
851 tCustomize = `权重${parseFloat(t.weight) / 100} * 因子/默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
852 } else { // 其他
853 tNum = parseFloat(dictionary?.value || t.defaultValue || 0);
854 tCustomize = `默认值${parseFloat(dictionary?.value || t.defaultValue || 0)}`;
855 }
856 t.dictionaryName == '数据用途' && (dataUsage.value.dictValue = pVal.value || '');
857 }
858 } else if (t.targetType == '2') {// 指标类型-系统功能
859 if (t.functionName == '1') { // 功能名称-质量评价模型
860 const score = parseFloat(qualityScoreData.value.qualityScore || 0);
861 tNum = parseFloat(t.weight || 1) / 100 * score / 100;
862 tCustomize = `权重${parseFloat(t.weight || 1) / 100} * 模型评分${score}/100`;
863 } else if (t.functionName == '2') { // 功能名称-疾病管理
864 if (sign.computationalFormula == '1') {// 加权平均
865 const score = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
866 tNum = parseFloat(t.weight) / 100 * score;
867 tCustomize = `权重${parseFloat(t.weight) / 100} * 疾病得分${score}`;
868 } else { //其他
869 tNum = parseFloat(disScore.value.find(d => d.guid == t.guid)?.factor || 0);
870 tCustomize = `疾病得分${tNum}`;
871 }
872 } else if (t.functionName == '3') {// 功能名称-需求表管理
873 const tData = tableData.value.find(f => f.demandTableGuid == t.demandTableGuid || f.guid == t.demandTableGuid);
874 if (tData) {
875 if (sign.computationalFormula == '1') {// 加权平均
876 tNum = parseFloat(t.weight) / 100 * (parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0));
877 tCustomize = `权重${parseFloat(t.weight) / 100} * 匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
878 } else { //其他
879 tNum = parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0);
880 tCustomize = `匹配率/默认值${parseFloat(tData.dataFieldsNum) / tData.dataFields.length || parseFloat(t.defaultValue || 0)}`;
881 }
882 }
883 }
884 } else { // 指标类型-系统内置
885 if (sign.computationalFormula == '1') {// 加权平均
886 tNum = parseFloat(t.weight) / 100 * parseFloat(t.defaultValue || 0);
887 tCustomize = `权重${parseFloat(t.weight) / 100} * 默认值${parseFloat(t.defaultValue || 0)}`;
888 } else { //其他
889 tNum = parseFloat(t.defaultValue || 0);
890 tCustomize = `默认值${parseFloat(t.defaultValue || 0)}`;
891 }
892 }
893 t.tNum = (Math.round(parseFloat(tNum) * 100) / 100).toFixed(2);
894 resultInfo[s].pricingTargetRSVOS.push({
895 targetName: t.targetName,
896 targetType: t.targetType,
897 functionName: t.functionName,
898 customize: tCustomize,
899 tNum: t.tNum,
900 })
901 return t;
902 })
903 sign.pricingTargetRSVOS = signTargets;
904 sign.sNum = getSignatory(sign);
905 resultInfo[s].sNum = sign.sNum;
906 })
907 // exportData.value = resultInfo;
908 return { signatoryData, resultInfo };
909 }
910
911 // 计算价格
912 const calculatePrice = (pData) => {
913 let modelFormula = modelData.value.modelFormula;
914 // 1. 移除所有干扰的引号(确保是数学表达式)
915 modelFormula = modelFormula.replace(/["']/g, "").trim();
916
917 // 2. 定义允许的数学运算符和函数
918 const allowedOperators = /[+\-*/%^() .\d]/;
919 const mathFunctions = ['sin', 'cos', 'tan', 'log', 'sqrt', 'abs', 'pow'];
920
921 // 3. 提取变量名
922 const variableRegex = /[\u4e00-\u9fa5a-zA-Z_][\u4e00-\u9fa5a-zA-Z0-9_]*/g;
923 const variableNames = [...new Set(modelFormula.match(variableRegex) || [])];
924
925 // 4. 构建变量映射
926 const variables = {};
927 variableNames.forEach(name => {
928 const dim = pData.find(d => d.dimensionalityName === name);
929 variables[name] = dim ? parseFloat(dim.sNum) || 0 : 0;
930 });
931
932 // 5. 替换变量为数值(考虑边界情况)
933 let expression = modelFormula;
934 Object.keys(variables).forEach(name => {
935 expression = expression.replace(new RegExp(name, 'g'), variables[name]);
936 });
937
938 // 6. 表达式规范化(不丢失括号)
939 expression = expression
940 .replace(/\s+/g, '') // 去空格
941 .replace(/\^/g, '**') // 幂运算转换
942 .replace(/"|'/g, '') // 去引号(不破坏括号)
943 .replace(/(\d)\(/g, '$1*(') // 处理隐式乘法
944 .replace(/\)\(/g, ')*('); // 括号间乘法
945
946 // 7. 验证括号配对
947 const balance = expression.split('').reduce((acc, char) => {
948 if (char === '(') acc++;
949 if (char === ')') acc--;
950 return acc;
951 }, 0);
952
953 if (balance !== 0) {
954 console.error('括号不匹配');
955 return NaN;
956 }
957
958 // 8. 安全计算
959 try {
960 const result = new Function('return ' + expression)();
961 const roundedResult = Math.round(parseFloat(result) * 100) / 100;
962
963 dataTransactionPrice.value = roundedResult.toFixed(2);
964 return roundedResult;
965 } catch (error) {
966 console.error('计算错误:', {
967 error,
968 original: modelFormula,
969 processed: expression
970 });
971 return NaN;
972 }
973 };
974
975 // 获取定价计算配置参数 835 // 获取定价计算配置参数
976 const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => { 836 const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
977 const modelName = typeMap.value.modelGuid.find(d => d.guid == baseConfigFormInfo.modelGuid)?.modelName || ''; 837 const modelName = typeMap.value.modelGuid.find(d => d.guid == baseConfigFormInfo.modelGuid)?.modelName || '';
...@@ -1001,15 +861,9 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => { ...@@ -1001,15 +861,9 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
1001 } 861 }
1002 } 862 }
1003 buildInData.value.map(item => { 863 buildInData.value.map(item => {
1004 let targetValue = baseConfigFormInfo[`build_${item.guid}`];
1005 if (typeof targetValue === 'string') {
1006 if (/^[+-]?\d{1,3}(,\d{3})*(\.\d{2})?$/.test(targetValue)) {
1007 targetValue = parseFloat(targetValue.replace(/,/g, ''))
1008 }
1009 }
1010 builtInTarget.push({ 864 builtInTarget.push({
1011 ...item, 865 ...item,
1012 targetValue 866 targetValue: baseConfigFormInfo[`build_${item.guid}`],
1013 }) 867 })
1014 }) 868 })
1015 params.dictionaryJson = Object.keys(dictionaryJson).length ? JSON.stringify(dictionaryJson) : ''; 869 params.dictionaryJson = Object.keys(dictionaryJson).length ? JSON.stringify(dictionaryJson) : '';
...@@ -1043,15 +897,16 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => { ...@@ -1043,15 +897,16 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
1043 const getCalculatPrice = async (params) => { 897 const getCalculatPrice = async (params) => {
1044 try { 898 try {
1045 const res: any = await calculatPrice(params); 899 const res: any = await calculatPrice(params);
900 loading.value = false;
1046 if (res.code === proxy.$passCode) { 901 if (res.code === proxy.$passCode) {
1047 const data = res.data || {}; 902 const data = res.data || {};
1048 return data; // 返回计算结果以便后续使用 903 return data; // 返回计算结果以便后续使用
1049 } else { 904 } else {
1050 proxy.$ElMessage.error(res.msg); 905 proxy.$ElMessage.error(res.msg);
1051 loading.value = false;
1052 throw new Error(res.msg); // 抛出错误以便 catch 捕获 906 throw new Error(res.msg); // 抛出错误以便 catch 捕获
1053 } 907 }
1054 } catch (error) { 908 } catch (error) {
909 console.error('计算价格失败:', error);
1055 loading.value = false; 910 loading.value = false;
1056 throw error; // 重新抛出错误 911 throw error; // 重新抛出错误
1057 } 912 }
...@@ -1071,9 +926,8 @@ const checkForm = (type) => { ...@@ -1071,9 +926,8 @@ const checkForm = (type) => {
1071 // 显示结果 926 // 显示结果
1072 dataTransactionPrice.value = priceData.transactionPrice.toFixed(2); 927 dataTransactionPrice.value = priceData.transactionPrice.toFixed(2);
1073 928
1074 if (type == 'calculate') { 929 if (type == 'export') {
1075 loading.value = false; 930 loading.value = true;
1076 } else if (type == 'export') {
1077 const exportOut = { 931 const exportOut = {
1078 one: priceData.one, 932 one: priceData.one,
1079 two: priceData.two, 933 two: priceData.two,
...@@ -1102,6 +956,7 @@ const checkForm = (type) => { ...@@ -1102,6 +956,7 @@ const checkForm = (type) => {
1102 ...paramsInfo, 956 ...paramsInfo,
1103 dataTransactionPrice: dataTransactionPrice.value, 957 dataTransactionPrice: dataTransactionPrice.value,
1104 } 958 }
959 loading.value = true;
1105 savePrice(params).then((res: any) => { 960 savePrice(params).then((res: any) => {
1106 loading.value = false; 961 loading.value = false;
1107 if (res.code == proxy.$passCode) { 962 if (res.code == proxy.$passCode) {
...@@ -1205,6 +1060,7 @@ onBeforeMount(() => { ...@@ -1205,6 +1060,7 @@ onBeforeMount(() => {
1205 } 1060 }
1206 }) 1061 })
1207 onMounted(() => { 1062 onMounted(() => {
1063 getModel()
1208 }) 1064 })
1209 </script> 1065 </script>
1210 <template> 1066 <template>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!