feat:计算公式映射

This commit is contained in:
houjunxiang
2026-01-30 21:01:30 +08:00
parent 13faa8d66c
commit 5d1d4b7232
3 changed files with 118 additions and 80 deletions

View File

@@ -1,14 +1,14 @@
// 在此不用配置接口前缀 // 在此不用配置接口前缀
const isDev = process.env.NODE_ENV === 'development' const isDev = process.env.NODE_ENV === 'development'
// 正式环境 // 正式环境
const BaseUrl = isDev ? 'http://172.17.19.29:48080/admin-api' : 'http://172.17.19.29:48080/admin-api' // const BaseUrl = isDev ? 'http://172.17.19.29:48080/admin-api' : 'http://172.17.19.29:48080/admin-api'
const upgradeBaseUrl = isDev ? 'http://172.17.19.29:48080/admin-api' : 'http://172.17.19.29:48080/admin-api' // const upgradeBaseUrl = isDev ? 'http://172.17.19.29:48080/admin-api' : 'http://172.17.19.29:48080/admin-api'
const websocketUrl = isDev ? 'ws://172.17.19.11:30330' : 'ws://172.17.19.11:30330' // const websocketUrl = isDev ? 'ws://172.17.19.11:30330' : 'ws://172.17.19.11:30330'
// 公司测试环境 // 公司测试环境
// const BaseUrl = isDev ? 'http://192.168.26.116:888/admin-api' : 'http://192.168.26.116:888/admin-api' const BaseUrl = isDev ? 'http://192.168.26.116:888/admin-api' : 'http://192.168.26.116:888/admin-api'
// const upgradeBaseUrl = isDev ? 'http://192.168.26.116:888/admin-api' : 'http://192.168.26.116:888/admin-api' const upgradeBaseUrl = isDev ? 'http://192.168.26.116:888/admin-api' : 'http://192.168.26.116:888/admin-api'
// const websocketUrl = isDev ? 'ws://192.168.26.116:888/ws' : 'ws://192.168.26.116:888/ws' const websocketUrl = isDev ? 'ws://192.168.26.116:888/ws' : 'ws://192.168.26.116:888/ws'
const tenantId = '1' const tenantId = '1'
export const clientId = 'zgty_lims' export const clientId = 'zgty_lims'

View File

@@ -1,13 +1,90 @@
import { create, all, number, pow } from 'mathjs' import { create, all, number, pow } from 'mathjs'
import parseSafeArgs from './parseSafeArgs'
const math = create(all) const math = create(all)
math.config({ math.config({
number: 'BigNumber', number: 'BigNumber',
precision: 64 precision: 64
}) })
export { math } export { math }
const GetRecoveryRate = function (elementFormulaCode, value) {
// //读取conRecoveryRateList
const conRecoveryRateList = uni.getStorageSync('ConRecoveryRateList')
if (!conRecoveryRateList) return
let o = conRecoveryRateList.find(i => {
//console.log("取得的" + i + "回收率:" + i);
if (value === 0) {
return i.elementFormulaCode === elementFormulaCode && i.minValue === value
}
return i.elementFormulaCode === elementFormulaCode && i.minValue < value && value <= i.maxValue
})
// console.log(o);
const rate = o ? o.rate : 100
// console.log("取得的" + elementFormulaCode + "回收率:" + rate);
return rate
// console.log("执行方法GetRecoveryRate");
// return 100;
}
/*
* 根据硫值计算:支持碳、硝酸钾(滇中)
* 当S%<22%时,需加入淀粉的量=(75-S%*22*M)/12
* 当 S%>22%时,需加入硝酸钾的量=(S%*22*M-75)/4
* 当 S%==22%时硝酸钾为0淀粉为空
* sValueKey硫值对应的dicKey
* weightKey重量对应的dicKey
* percent计算参数
*
* 举例Get_C_KNO3_bySValue|(|p14|, |p2|, |>|)
* */
const Get_C_KNO3_bySValue = function (sValue, weight, operator) {
//判断sValue是数字
if (isNaN(sValue) || isNaN(weight)) {
return ''
}
let v = number(sValue)
const w = number(weight)
if (w === 0) return ''
v = v * 0.01
//当S%<22%时,需加入淀粉的量=(75-S%*22*M)/12
if (operator === '<' && v < 0.22) {
// return ( 75 - v * 22 * w )/12;
return accDiv(accSub(75, accMul(accMul(v, 22), w)), 12)
}
//S%>22%时,需加入硝酸钾的量=(S%*22*M-75)/4
if (operator === '>=' && v >= 0.22) {
//S%==22%时硝酸钾为0淀粉为空
if (v === 22) return 0
// return ( v * 22 * w - 75 ) + 44;
return accDiv(accSub(accMul(v, accMul(22, w)), 75), 4)
}
return ''
}
const Get_C_KNO3 = function (sValue, weight, operator) {
//判断sValue是数字
if (sValue === 0 || weight === 0) {
return ''
}
let S = number(sValue)
const W = number(weight)
if (W === 0) return ''
const V = ((W * S) / 100) * 22 - 75
if (operator === '<' && V < 0) {
return math.abs(V / 12)
}
if (operator === '>=' && V >= 0) {
return V / 4
}
return ''
}
const FORMULA_FUNCTIONS = {
GetRecoveryRate,
Get_C_KNO3_bySValue,
Get_C_KNO3
}
/* /*
* 计算当前样品分析值*/ * 计算当前样品分析值*/
export function calcAnalysisValue(group, externalFormData, taskIngredientsWay) { export function calcAnalysisValue(group, externalFormData, taskIngredientsWay) {
const MAX_ITERATIONS = 5 // 防止无限循环 const MAX_ITERATIONS = 5 // 防止无限循环
let iterations = 0 let iterations = 0
@@ -119,7 +196,13 @@ export function calcRowAnalysisValue(row, columnObj, dynamicsColumns, externalFo
let v let v
if (formulaVal.startsWith('Get_')) { if (formulaVal.startsWith('Get_')) {
if (taskIngredientsWay !== 'manual') continue if (taskIngredientsWay !== 'manual') continue
v = eval(formulaVal) const match = formulaVal.match(/^([a-zA-Z_]\w*)\((.*)\)$/)
const funcName = match[1]
const argsStr = match[2].trim()
const func = FORMULA_FUNCTIONS[funcName]
// 安全解析参数(支持数字、字符串)
const args = parseSafeArgs(argsStr)
v = func(...args)
} else if (formulaVal.startsWith('GetFrom')) { } else if (formulaVal.startsWith('GetFrom')) {
v = evaluateGetFromFormula(formulaVal, false, externalFormData) v = evaluateGetFromFormula(formulaVal, false, externalFormData)
} else { } else {
@@ -143,78 +226,6 @@ const findFieldInGroup = function (paramNo, group, p) {
return { value: null } return { value: null }
} }
const GetRecoveryRate = function (elementFormulaCode, value) {
// //读取conRecoveryRateList
const conRecoveryRateList = uni.getStorageSync('ConRecoveryRateList')
if (!conRecoveryRateList) return
let o = conRecoveryRateList.find(i => {
//console.log("取得的" + i + "回收率:" + i);
if (value === 0) {
return i.elementFormulaCode === elementFormulaCode && i.minValue === value
}
return i.elementFormulaCode === elementFormulaCode && i.minValue < value && value <= i.maxValue
})
// console.log(o);
const rate = o ? o.rate : 100
// console.log("取得的" + elementFormulaCode + "回收率:" + rate);
return rate
// console.log("执行方法GetRecoveryRate");
// return 100;
}
/*
* 根据硫值计算:支持碳、硝酸钾(滇中)
* 当S%<22%时,需加入淀粉的量=(75-S%*22*M)/12
* 当 S%>22%时,需加入硝酸钾的量=(S%*22*M-75)/4
* 当 S%==22%时硝酸钾为0淀粉为空
* sValueKey硫值对应的dicKey
* weightKey重量对应的dicKey
* percent计算参数
*
* 举例Get_C_KNO3_bySValue|(|p14|, |p2|, |>|)
* */
const Get_C_KNO3_bySValue = function (sValue, weight, operator) {
//判断sValue是数字
if (isNaN(sValue) || isNaN(weight)) {
return ''
}
let v = number(sValue)
const w = number(weight)
if (w === 0) return ''
v = v * 0.01
//当S%<22%时,需加入淀粉的量=(75-S%*22*M)/12
if (operator === '<' && v < 0.22) {
// return ( 75 - v * 22 * w )/12;
return accDiv(accSub(75, accMul(accMul(v, 22), w)), 12)
}
//S%>22%时,需加入硝酸钾的量=(S%*22*M-75)/4
if (operator === '>=' && v >= 0.22) {
//S%==22%时硝酸钾为0淀粉为空
if (v === 22) return 0
// return ( v * 22 * w - 75 ) + 44;
return accDiv(accSub(accMul(v, accMul(22, w)), 75), 4)
}
return ''
}
function Get_C_KNO3(sValue, weight, operator) {
//判断sValue是数字
if (sValue === 0 || weight === 0) {
return ''
}
let S = number(sValue)
const W = number(weight)
if (W === 0) return ''
const V = ((W * S) / 100) * 22 - 75
if (operator === '<' && V < 0) {
return math.abs(V / 12)
}
if (operator === '>=' && V >= 0) {
return V / 4
}
return ''
}
/** 处理数值数据:四舍六入奇进偶不进 /** 处理数值数据:四舍六入奇进偶不进
* 1如果取小数的最后一位为55前为奇数进位为偶不进,五后非零就进一,五后皆零看奇偶,五前为偶应舍去,五前为奇要进一 * 1如果取小数的最后一位为55前为奇数进位为偶不进,五后非零就进一,五后皆零看奇偶,五前为偶应舍去,五前为奇要进一
* 2.5后不为0时就入为0时看5前奇进偶不进 * 2.5后不为0时就入为0时看5前奇进偶不进

View File

@@ -0,0 +1,27 @@
export default function parseSafeArgs(argsStr) {
if (!argsStr.trim()) return []
// 将 ', ' 或 '(' 后的单引号字符串转换为合法 JSON 字符串
// 思路:匹配所有 '...' 并替换为 "..."
let jsonLike =
'[' +
argsStr
.replace(/\s*,\s*/g, ',') // 去掉参数间空格
.replace(/'/g, '"') + // 单引号 → 双引号
']'
try {
const parsed = JSON.parse(jsonLike)
// 确保数字不被转成字符串JSON 会自动处理)
return parsed.map(item => {
if (typeof item === 'string') {
// 如果是 '<' 或 '>',保留字符串
return item
}
return item // number
})
} catch (e) {
console.warn('Failed to parse args:', argsStr, e)
return []
}
}