import { roundForObj } from '@sc/util'; import evaluate from 'evaluator.js'; // 关键字组 export interface IKeywordItem { optionCode: string; // 选项号 coe: string; // 系数 *1.29 keyword: string; unit: string; } export interface IInfoPriceMain { classCode: string; // 别名编码 0749B01D01 expString: string; // 表达式 :X*(1+(A-1)+(B-1)+(C-1)) basePrice: string; // 基价 } /* eslint-disable import/prefer-default-export */ const replaceAll = (FindText: RegExp | string, RepText: string, str: string): string => { const regExp = new RegExp(FindText, 'g'); return str.replace(regExp, RepText); }; /** * 计算材料价 * infoPrice:主表的数据 * keywordItems : 关键字列表 */ export const calcMaterialExp = (infoPrice: IInfoPriceMain, keywordItems: IKeywordItem[]) => { const preCodeLength = 5; // 别名编码位数,可能要改成5位或6位 const decimal = 2; // 小数位数 const groupStr = infoPrice.classCode.substr(preCodeLength); let { expString } = infoPrice; // 计算式 const matchKeywords: IKeywordItem[] = []; try { if (groupStr.length > 0) { let startIndex = 0; while (groupStr.length > startIndex) { const option = groupStr.substr(startIndex, 3); // 获取A01这样的编号 const group = keywordItems.find(item => item.optionCode === option); if (group) { // 运距=15km 这种类型的要特殊处理 暂时没有办法处理~ 没法从编号中获取具体要加减多少 const operator = group.coe.charAt(0); // 加 减 乘的操作 const coeNumber = parseFloat(group.coe.substr(1)); // 要代入计算的系数 let replaceStr = ''; if (operator === '*') { // 乘法时,自减1 replaceStr = `${coeNumber - 1}`; } else { // + 或者 - 操作符时,使用 (+10) 或者 (-10)来替换, replaceStr = `(${group.coe})`; } expString = replaceAll(option.charAt(0), replaceStr, expString); matchKeywords.push(group); } startIndex += 3; } // 替换基价 expString = replaceAll('X', infoPrice.basePrice, expString); // 没找到的按0处理 expString = replaceAll(/[a-zA-Z]/, '0', expString); return { price: roundForObj(evaluate(expString), decimal), matchKeywords }; } } catch (error) { throw new Error('计算失败,表达式有误'); } return { price: roundForObj(infoPrice.basePrice, decimal), matchKeywords }; };