407 lines
14 KiB
JavaScript
407 lines
14 KiB
JavaScript
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,如果取小数的最后一位为5,5前为奇数进位,为偶不进,五后非零就进一,五后皆零看奇偶,五前为偶应舍去,五前为奇要进一
|
||
* 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
|
||
}
|