Files
zgty-mas-m/nx/helper/calcAnalysisValue.js
2025-11-13 17:00:50 +08:00

407 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { create, all, number, pow } from 'mathjs'
const math = create(all)
math.config({
number: 'BigNumber',
precision: 64
})
export { math }
/*
* 计算当前样品分析值*/
export function calcAnalysisValue(group) {
try {
for (const g of group) {
for (const ele of g.fields) {
if (!ele.formula || ele.formula == '') continue
if (ele.valueTypeManual && ele.valueTypeManual == '1') continue
let formula = ele.formula
let formulas = formula.split('|')
let formulaVal = ''
let hasNullVal = false
formulas.forEach(f => {
let value = ''
if (f.charAt(0) === 'p') {
// let o = elementParamValueData.find((i) => 'p' + i.paramNo === f);
let o = findFieldInGroup(f, group, 'p')
value = o.value
} else if (f.charAt(0) === 'e') {
// let o = elementParamValueData.find((i) => 'e' + i.paramNo === f);
let o = findFieldInGroup(f, group, 'e')
value = o.value
} else if (f.charAt(0) === '<' || f.charAt(0) === '>') {
value = "'" + f + "'"
} else {
value = f
}
if (typeof value == 'undefined' || value == null) {
hasNullVal = true
return true
}
formulaVal += value
})
if (hasNullVal) {
ele.value = null
continue
}
let v
if (formulaVal.startsWith('Get')) {
//计算公式为Get开头的都是执行方法
v = eval(formulaVal)
} else {
v = math.evaluate(formulaVal).toString()
v = isFinite(v) ? v.toString() : ''
}
ele.value = handleRoundFiveNumber(v, ele.decimalPosition)
}
}
} catch (error) {
console.log(error)
}
}
// 根据样品和配置列计算分析值
export function calcRowAnalysisValue(row, columnObj, dynamicsColumns) {
if (!columnObj.paramNo) return
for (let i = 0; i < dynamicsColumns.length; i++) {
let curItem = dynamicsColumns[i]
if (curItem.fieldIndex === columnObj.fieldIndex) continue
let param = columnObj.fieldIndex.charAt(0) === 'p' ? 'p' + columnObj.paramNo : 'e' + columnObj.paramNo
if (curItem.formula && curItem.formula.includes(param)) {
let formula = curItem.formula
let formulas = formula.split('|')
let formulaVal = ''
formulas.forEach(f => {
if (f.charAt(0) === 'p') {
let o = dynamicsColumns.find(i => 'p' + i.paramNo === f)
formulaVal += row[o.fieldIndex]?.value ? row[o.fieldIndex].value : 0
} else if (f.charAt(0) === 'e') {
let o = dynamicsColumns.find(i => 'e' + i.paramNo === f)
formulaVal += row[o.fieldIndex]?.value ? row[o.fieldIndex].value : 0
} else {
formulaVal += f
}
})
let v
if (formulaVal.startsWith('Get')) {
formulaVal = formulaVal.replace(')', ",'" + row.conBaseSampleId + "')")
v = eval(formulaVal)
} else {
v = math.evaluate(formulaVal).toString()
v = isFinite(v) ? v : 0
}
row[curItem.fieldIndex].value = handleRoundFiveNumber(Number(v), row[curItem.fieldIndex].decimalPosition)
calcRowAnalysisValue(row, curItem, dynamicsColumns)
}
}
}
const findFieldInGroup = function (paramNo, group, p) {
for (const g of group) {
for (const f of g.fields) {
if (p + f.paramNo === paramNo) {
return f
}
}
}
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 ''
}
/** 处理数值数据:四舍六入奇进偶不进
* 1如果取小数的最后一位为55前为奇数进位为偶不进,五后非零就进一,五后皆零看奇偶,五前为偶应舍去,五前为奇要进一
* 2.5后不为0时就入为0时看5前奇进偶不进
* 3.四舍,六入
* 传入数值和保留位数
*/
export function handleRoundFiveNumber(number, fixed = 0) {
if (number == null || number === '' || isNaN(number)) return number
if (fixed === -1) return number
number = String(number)
//可以考虑清掉末尾的0暂时限制了不会有,因为传入数值末尾0是去掉的
const index = number.indexOf('.')
if (index == -1) {
if (fixed > 0) {
number += '.'
}
for (let i = 0; i < fixed; i++) {
number += '0'
}
//补0返回
return number
}
//取到保留小数位的下一位5.5555取保留俩位,那就是小数点后第三位
const indexFixed = index + fixed + 1
if (indexFixed >= number.length) {
//如果小数位数不够, 补0直接返回
const zerolen = indexFixed - number.length
for (let i = 0; i < zerolen; i++) {
number += '0'
}
return number
}
//取保留位数的后一位做判断以下是有5的判断
const endNumber = number.substr(indexFixed, 1)
if (endNumber != '5') {
//如果做判断的数不是五就按正常的四舍五入即忽略了5后面补0的那些由于是数字传进来0已经去掉此处不做处理
return Number(number).toFixed(fixed)
}
if (indexFixed != number.length - 1) {
//由于当前判断位不是最后一位而又去除了0那么后面后的位数应该直接入位五后不为0时入,由于会有小于五的四舍五入肯定不行那么只能截取到当前保留位数然后转成数字加上10的负fixed的次方即可
number = number.substring(0, indexFixed)
if (number.indexOf('-') != -1) {
//需要考虑到负数的情况
return (Number(number) - Number(Math.pow(10, -fixed))).toFixed(fixed)
}
return (Number(number) + Number(Math.pow(10, -fixed))).toFixed(fixed)
//return this.accAdd(number,Math.pow(10,-fixed))
}
//接下来就时五后没有值也就是0的需要看前面的奇入偶不入了取当前位的上一位
let twoNumber = number.substr(indexFixed - 1, 1)
if (twoNumber == '.') {
//取到小数点,再取一次,要取到小数点左边第一位
twoNumber = number.substr(indexFixed - 2, 1)
}
if ('13579'.indexOf(twoNumber) != -1) {
//奇进
number = number.substring(0, indexFixed)
if (number.indexOf('-') != -1) {
//需要考虑到负数的情况
return (Number(number) - Math.pow(10, -fixed)).toFixed(fixed)
}
return (Number(number) + Math.pow(10, -fixed)).toFixed(fixed)
}
//偶不进,将取值的当前位数,直接截取字符即可
return number.substr(0, indexFixed)
}
/**
** 除法函数,用来得到精确的除法结果
** 说明javascript的除法结果会有误差在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
** 调用accDiv(arg1,arg2)
** 返回值arg1除以arg2的精确结果
**/
function accDiv(arg1, arg2) {
var t1 = 0,
t2 = 0,
r1,
r2
try {
t1 = arg1.toString().split('.')[1].length
} catch (e) {}
try {
t2 = arg2.toString().split('.')[1].length
} catch (e) {}
r1 = Number(arg1.toString().replace('.', ''))
r2 = Number(arg2.toString().replace('.', ''))
return (r1 / r2) * pow(10, t2 - t1)
}
/**
** 乘法函数,用来得到精确的乘法结果
** 说明javascript的乘法结果会有误差在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
** 调用accMul(arg1,arg2)
** 返回值arg1乘以 arg2的精确结果
**/
function accMul(arg1, arg2) {
var m = 0,
s1 = arg1.toString(),
s2 = arg2.toString()
try {
m += s1.split('.')[1].length
} catch (e) {}
try {
m += s2.split('.')[1].length
} catch (e) {}
return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m)
}
/**
** 减法函数,用来得到精确的减法结果
** 说明javascript的减法结果会有误差在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
** 调用accSub(arg1,arg2)
** 返回值arg1加上arg2的精确结果
**/
function accSub(arg1, arg2) {
var r1, r2, m, n
try {
r1 = arg1.toString().split('.')[1].length
} catch (e) {
r1 = 0
}
try {
r2 = arg2.toString().split('.')[1].length
} catch (e) {
r2 = 0
}
m = Math.pow(10, Math.max(r1, r2)) //last modify by deeka //动态控制精度长度
n = r1 >= r2 ? r1 : r2
return ((arg1 * m - arg2 * m) / m).toFixed(n)
}
/**
** 加法函数,用来得到精确的加法结果
** 说明javascript的加法结果会有误差在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
** 调用accAdd(arg1,arg2)
** 返回值arg1加上arg2的精确结果
**/
function accAdd(arg1, arg2) {
var r1, r2, m, c
try {
r1 = arg1.toString().split('.')[1].length
} catch (e) {
r1 = 0
}
try {
r2 = arg2.toString().split('.')[1].length
} catch (e) {
r2 = 0
}
c = Math.abs(r1 - r2)
m = Math.pow(10, Math.max(r1, r2))
if (c > 0) {
var cm = Math.pow(10, c)
if (r1 > r2) {
arg1 = Number(arg1.toString().replace('.', ''))
arg2 = Number(arg2.toString().replace('.', '')) * cm
} else {
arg1 = Number(arg1.toString().replace('.', '')) * cm
arg2 = Number(arg2.toString().replace('.', ''))
}
} else {
arg1 = Number(arg1.toString().replace('.', ''))
arg2 = Number(arg2.toString().replace('.', ''))
}
return (arg1 + arg2) / m
}
// 通过配置项分组
export function groupByField(list, cupNumFieldIndex, groupKey = 'groupDictionaryBusinessKey') {
const groupMap = new Map()
list.unshift({ groupDictionaryBusinessKey: 'all', groupDictionaryBusinessName: '全部' })
for (const item of list) {
// 赋值杯号fieldindex
if (item.title === '杯号') {
cupNumFieldIndex.value = item.fieldIndex
}
const key = item[groupKey]
if (!key) continue // 跳过没有 group 的项(可选)
if (!groupMap.has(key)) {
groupMap.set(key, {
value: key,
label: item.groupDictionaryBusinessName, // 假设 title 在每个 item 中,且同组相同
fields: []
})
}
// 把当前项(或仅需要的部分)推入 fields
groupMap.get(key).fields.push(item)
}
// 转为数组
return Array.from(groupMap.values())
}
export function validateElementRange(fieldIndex, row, conRangeElementAnalysisList) {
if (!conRangeElementAnalysisList?.length) return null
const rangeElementAnalysis = conRangeElementAnalysisList.find(
ele => ele.dictionaryProjectId === row[fieldIndex]?.dicId && row[fieldIndex]['type'] === 'project'
)
if (!rangeElementAnalysis) return null
const val = row[fieldIndex]?.value
if (val == '' || val == null) return null
const value = Number(val)
let result = { promptType: '', promptMsg: '' }
switch (Number(rangeElementAnalysis.rangeType)) {
case 1:
//如果值小于最小警告值或者大于最大警告值,则校验不通过
if (value < rangeElementAnalysis.minimumWarningValue || value > rangeElementAnalysis.maximumWarningValue) {
result.promptType = 'warning'
result.promptMsg = `警告:值超出范围(${rangeElementAnalysis.minimumWarningValue} ~ ${rangeElementAnalysis.maximumWarningValue}`
}
break
case 2:
//如果值小于最小限制值或者大于最大限制值,则校验不通过
if (value < rangeElementAnalysis.minimumValue || value > rangeElementAnalysis.maximumValue) {
result.promptType = 'error'
result.promptMsg = `错误:值超出范围(${rangeElementAnalysis.minimumValue} ~ ${rangeElementAnalysis.maximumValue}`
}
break
case 3:
//如果值小于最小限制值或者大于最大限制值,则校验不通过
if (value < rangeElementAnalysis.minimumValue || value > rangeElementAnalysis.maximumValue) {
result.promptType = 'error'
result.promptMsg = `错误:值超出范围(${rangeElementAnalysis.minimumValue} ~ ${rangeElementAnalysis.maximumValue}`
} else if (
(rangeElementAnalysis.minimumValue < value && value < rangeElementAnalysis.minimumWarningValue) ||
(rangeElementAnalysis.maximumWarningValue < value && value <= rangeElementAnalysis.maximumValue)
) {
result.promptType = 'warning'
result.promptMsg = `警告:值超出范围(${rangeElementAnalysis.minimumWarningValue} ~ ${rangeElementAnalysis.maximumWarningValue}`
}
break
default:
return null
}
return result
}