material.ts 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { roundForObj } from '@sc/util';
  2. import evaluate from 'evaluator.js';
  3. // 关键字组
  4. export interface IKeywordItem {
  5. optionCode: string; // 选项号
  6. coe: string; // 系数 *1.29
  7. keyword: string;
  8. unit: string;
  9. }
  10. export interface IInfoPriceMain {
  11. classCode: string; // 别名编码 0749B01D01
  12. expString: string; // 表达式 :X*(1+(A-1)+(B-1)+(C-1))
  13. basePrice: string; // 基价
  14. }
  15. /* eslint-disable import/prefer-default-export */
  16. const replaceAll = (FindText: RegExp | string, RepText: string, str: string): string => {
  17. const regExp = new RegExp(FindText, 'g');
  18. return str.replace(regExp, RepText);
  19. };
  20. /**
  21. * 计算材料价
  22. * infoPrice:主表的数据
  23. * keywordItems : 关键字列表
  24. */
  25. export const calcMaterialExp = (infoPrice: IInfoPriceMain, keywordItems: IKeywordItem[]) => {
  26. const preCodeLength = 5; // 别名编码位数,可能要改成5位或6位
  27. const decimal = 2; // 小数位数
  28. const groupStr = infoPrice.classCode.substr(preCodeLength);
  29. let { expString } = infoPrice; // 计算式
  30. const matchKeywords: IKeywordItem[] = [];
  31. try {
  32. if (groupStr.length > 0) {
  33. let startIndex = 0;
  34. while (groupStr.length > startIndex) {
  35. const option = groupStr.substr(startIndex, 3); // 获取A01这样的编号
  36. const group = keywordItems.find(item => item.optionCode === option);
  37. if (group) {
  38. // 运距=15km 这种类型的要特殊处理 暂时没有办法处理~ 没法从编号中获取具体要加减多少
  39. const operator = group.coe.charAt(0); // 加 减 乘的操作
  40. const coeNumber = parseFloat(group.coe.substr(1)); // 要代入计算的系数
  41. let replaceStr = '';
  42. if (operator === '*') {
  43. // 乘法时,自减1
  44. replaceStr = `${coeNumber - 1}`;
  45. } else {
  46. // + 或者 - 操作符时,使用 (+10) 或者 (-10)来替换,
  47. replaceStr = `(${group.coe})`;
  48. }
  49. expString = replaceAll(option.charAt(0), replaceStr, expString);
  50. matchKeywords.push(group);
  51. }
  52. startIndex += 3;
  53. }
  54. // 替换基价
  55. expString = replaceAll('X', infoPrice.basePrice, expString);
  56. // 没找到的按0处理
  57. expString = replaceAll(/[a-zA-Z]/, '0', expString);
  58. return { price: roundForObj(evaluate(expString), decimal), matchKeywords };
  59. }
  60. } catch (error) {
  61. throw new Error('计算失败,表达式有误');
  62. }
  63. return { price: roundForObj(infoPrice.basePrice, decimal), matchKeywords };
  64. };