e18ddc85 by lxs Committed by lihua

数据定价更新

1 parent 9b765bc9
......@@ -52,11 +52,13 @@ const dictionaryData: any = ref([]);
const diseaseData: any = ref([]);
const qualityScoreData: any = ref({});
const disScore: any = ref([]);
const exportData: any = ref([]);
const buildInData: any = ref([]);
const dataUsage = ref({
field: '',
dictValue: ''
});
// 基础设置
const baseConfigFormRef = ref();
const baseConfigFormItems: any = ref([
......@@ -144,10 +146,10 @@ const dataTransactionPrice: any = ref('');
const setFormItems = (info = null) => {
let datas: any = info || flowDetail.value || {};
const dictData = datas.dictionaryJson ? JSON.parse(datas.dictionaryJson) : {};
const builtIndicators = datas.builtIndicators || buildInData.value || [];
const builtIndicators = datas.builtIndicators || [];
let buildData = {};
builtIndicators.map(item => {
buildData[`build_${item.guid}`] = item.isInputParameter != 'Y' ? changeNum(item.targetValue, 2) : item.targetValue != '' && item.targetValue != null ? parseFloat(item.targetValue).toFixed(2) : '';
buildData[`build_${item.guid}`] = item.targetValue;
});
datas = { ...datas, ...dictData, ...buildData };
baseConfigFormItems.value.map(item => {
......@@ -271,8 +273,10 @@ const getDetail = () => {
typeMap.value.modelGuid.unshift(mtem);
baseConfigFormItems.value[0].options.unshift(mtem);
};
getModelInfo(flowDetail.value.modelGuid);
getDataTypeList()
setTimeout(() => {
getModelInfo(flowDetail.value.modelGuid);
getDataTypeList()
}, 200)
}
}).catch(() => {
loading.value = false;
......@@ -309,7 +313,7 @@ const setDictFormItems = (dictList) => {
filterable: true,
required: true,
});
baseConfigFormRules.value[dictField] = { required: true, trigger: 'change', message: `请选择${dictName}` };
baseConfigFormRules.value[dictField] = [{ required: true, trigger: 'change', message: `请选择${dictName}` }];
dictName == '数据用途' && (dataUsage.value.field = dictField);
(() => {
if (typeMap.value[dictField] == undefined) {
......@@ -343,7 +347,7 @@ const setDiseaseFormItems = () => {
clearable: true,
required: true,
});
baseConfigFormRules.value.diseaseGuid = { required: true, trigger: 'change', message: "请选择所属疾病" };
baseConfigFormRules.value.diseaseGuid = [{ required: true, trigger: 'change', message: "请选择所属疾病" }];
if (typeMap.value['diseaseGuid'] == undefined) {
getDiseaseData();
} else {
......@@ -366,16 +370,44 @@ const setBuildInFormItems = (buildList) => {
buildList.map(b => {
const buildName = b.targetName;
const buildField = `build_${b.guid}`;
buildInData.value.push({
guid: b.guid,
targetName: buildName,
})
baseConfigFormItems.value.push({
label: buildName,
type: 'input',
placeholder: '',
field: buildField,
default: b.defaultValue || '',
default: changeNum(b.defaultValue, 2),
inputType: 'moneyNumber',
maxlength: 18,
clearable: true,
disabled: b.isInputParameter == 'Y'
disabled: b.isInputParameter != 'Y'
});
baseConfigFormRules.value[buildField] = { required: true, trigger: 'blur', message: `请填写${buildName}` };
baseConfigFormRules.value[buildField] = [
{ required: true, message: `请填写${buildName}`, trigger: 'blur' },
{
validator: (rule, value, callback) => {
if (value === '') {
callback(new Error(`请填写${buildName}`));
return;
}
const num = parseFloat(value);
if (isNaN(num)) {
callback(new Error('请输入有效的数字'));
return;
}
// 已自动保留两位小数,不需再验证小数位数
if (num < 0 || num > b.defaultValue) {
callback(new Error(`输入值必须在0到${b.defaultValue}之间`));
} else {
callback();
}
}, trigger: "blur",
},
]
})
};
......@@ -418,7 +450,7 @@ const setFormItemData = async () => {
// 添加数据字典
dictionaryList.length > 0 && await setDictFormItems(dictionaryList);
// 添加内置指标
// buildInList.length > 0 && await setBuildInFormItems(buildInList);
buildInList.length > 0 && await setBuildInFormItems(buildInList);
setTimeout(() => {
baseConfigFormRef.value.ruleFormRef?.clearValidate();
......@@ -784,34 +816,7 @@ const toPath = () => {
})
}
// 获取维度公式计算结果
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) => {
......@@ -827,151 +832,6 @@ const getTargetNum = (params) => {
});
}
// 生成报告内容
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.dictValue = 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 / 100;
tCustomize = `权重${parseFloat(t.weight || 1) / 100} * 模型评分${score}/100`;
} 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, "").trim();
// 2. 定义允许的数学运算符和函数
const allowedOperators = /[+\-*/%^() .\d]/;
const mathFunctions = ['sin', 'cos', 'tan', 'log', 'sqrt', 'abs', 'pow'];
// 3. 提取变量名
const variableRegex = /[\u4e00-\u9fa5a-zA-Z_][\u4e00-\u9fa5a-zA-Z0-9_]*/g;
const variableNames = [...new Set(modelFormula.match(variableRegex) || [])];
// 4. 构建变量映射
const variables = {};
variableNames.forEach(name => {
const dim = pData.find(d => d.dimensionalityName === name);
variables[name] = dim ? parseFloat(dim.sNum) || 0 : 0;
});
// 5. 替换变量为数值(考虑边界情况)
let expression = modelFormula;
Object.keys(variables).forEach(name => {
expression = expression.replace(new RegExp(name, 'g'), variables[name]);
});
// 6. 表达式规范化(不丢失括号)
expression = expression
.replace(/\s+/g, '') // 去空格
.replace(/\^/g, '**') // 幂运算转换
.replace(/"|'/g, '') // 去引号(不破坏括号)
.replace(/(\d)\(/g, '$1*(') // 处理隐式乘法
.replace(/\)\(/g, ')*('); // 括号间乘法
// 7. 验证括号配对
const balance = expression.split('').reduce((acc, char) => {
if (char === '(') acc++;
if (char === ')') acc--;
return acc;
}, 0);
if (balance !== 0) {
console.error('括号不匹配');
return NaN;
}
// 8. 安全计算
try {
const result = new Function('return ' + expression)();
const roundedResult = Math.round(parseFloat(result) * 100) / 100;
dataTransactionPrice.value = roundedResult.toFixed(2);
return roundedResult;
} catch (error) {
console.error('计算错误:', {
error,
original: modelFormula,
processed: expression
});
return NaN;
}
};
// 获取定价计算配置参数
const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
const modelName = typeMap.value.modelGuid.find(d => d.guid == baseConfigFormInfo.modelGuid)?.modelName || '';
......@@ -1001,15 +861,9 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
}
}
buildInData.value.map(item => {
let targetValue = baseConfigFormInfo[`build_${item.guid}`];
if (typeof targetValue === 'string') {
if (/^[+-]?\d{1,3}(,\d{3})*(\.\d{2})?$/.test(targetValue)) {
targetValue = parseFloat(targetValue.replace(/,/g, ''))
}
}
builtInTarget.push({
...item,
targetValue
targetValue: baseConfigFormInfo[`build_${item.guid}`],
})
})
params.dictionaryJson = Object.keys(dictionaryJson).length ? JSON.stringify(dictionaryJson) : '';
......@@ -1043,15 +897,16 @@ const getCalculateParams = (baseConfigFormObj, baseConfigFormInfo) => {
const getCalculatPrice = async (params) => {
try {
const res: any = await calculatPrice(params);
loading.value = false;
if (res.code === proxy.$passCode) {
const data = res.data || {};
return data; // 返回计算结果以便后续使用
} else {
proxy.$ElMessage.error(res.msg);
loading.value = false;
throw new Error(res.msg); // 抛出错误以便 catch 捕获
}
} catch (error) {
console.error('计算价格失败:', error);
loading.value = false;
throw error; // 重新抛出错误
}
......@@ -1071,9 +926,8 @@ const checkForm = (type) => {
// 显示结果
dataTransactionPrice.value = priceData.transactionPrice.toFixed(2);
if (type == 'calculate') {
loading.value = false;
} else if (type == 'export') {
if (type == 'export') {
loading.value = true;
const exportOut = {
one: priceData.one,
two: priceData.two,
......@@ -1102,6 +956,7 @@ const checkForm = (type) => {
...paramsInfo,
dataTransactionPrice: dataTransactionPrice.value,
}
loading.value = true;
savePrice(params).then((res: any) => {
loading.value = false;
if (res.code == proxy.$passCode) {
......@@ -1205,6 +1060,7 @@ onBeforeMount(() => {
}
})
onMounted(() => {
getModel()
})
</script>
<template>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!