带入变量根据数学公式自动计算出结果

931 阅读2分钟

业务场景

假设有一个长度数据,库里面存的值 单位是 m. 而A客户想让页面上显示的是km. 而B客户想让页面上显示cm. C客户…… 这种需求可能是动态变化的.所以不适合把转换公式写死在代码中. 而应该把公式放给用户自定义配置。然后代码里面读取用户自定义配置的公式.然后把数据带入公式之后计算出值再展示页面上。

前端

前端可借助第三方工具库完成

  • math.js
  • expr.js
  • 3xpr.js
  • math‑expression‑evaluator
  1. 以math.js为例
  • 官网示例

image.png

  • 带入变量的用法

math.evaluate('x*2+(x-1)/2', {x: 9}); // 22 假设用户输入的公式是x*2+(x-1)/2;其中x是变量。后面的括号里面是给变量x赋值。这样经过公式转换后得到结果22

实际项目中使用示例

  1. 封装一个根据公式获取值的函数
import { evaluate, round }from 'mathjs/lib/esm/number' ///lib/esm/number

/**
 * @description: 根据公式获取值
 * @param { Number } value 原始值
 * @param { String } equation 公式  eg: "x - 273.15"
 * @param { Number } decimals 保留的小数位
 * @param { string } valueKey 公式中代表原值的字符
 * @return { Number | null }
 */  
export function GetValueOfEvaluate(
  value: number | null | undefined, 
  equation: string, 
  decimals?: number,
  valueKey = 'x'
): number | null {
  const scope = {
    [valueKey]: value
  }

  // 输入的值可能不是number
  if(Tool.JudgeType(value) !== 'number') {
    return null
  }
   
  // evaluate是从mathjs中import导入的
  let evaluateValue = equation? evaluate(equation, scope) : value;

  // 可能输入的公式格式不对,计算出来的值不为number
  if(Tool.JudgeType(evaluateValue) !== 'number') {
    return null
  }else if(decimals || decimals === 0) {
    // 结果需要保留的小数位
    evaluateValue = Tool.NumberRoundTo(evaluateValue, decimals)
  }
  return evaluateValue
}
  1. 页面上提供公式配置的窗口

image.png

  1. 页面获取到数据是需要根据转换公式把值转换后显示给用户看;当用户在页面上修改值之后需要根据反转公式把用户的值转换为数据库里存的单位
// 1. 显示用,转换公式
// 单位转换
for(const key of Object.keys(data)) {
    if(UnitMapOfEquipmentInfoTableOfCalculateResult[key]) {
      const unit = ProjectConfig.unitConfig[UnitMapOfEquipmentInfoTableOfCalculateResult[key]];
      data[key] = Tool.GetValueOfEvaluate(data[key], unit.equation, unit.decimals);
    }
}

// 2. 存库用,反转公式
const insideUnit = ProjectConfig.unitConfig.lineInside;
const lineInside = Tool.GetValueOfEvaluate(lineObj?.inside, insideUnit.reverseEquation, insideUnit.decimals) ?? 0;

后端java

本司单位转换基本都在前端做。只有涉及到表格导出导入时才会需要后端自己做单位转换

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ExpressionEvaluator {
    public static void main(String[] args) {
        String expression = "2 + 3 * 4 - 6 / 2";
        double result = evaluateExpression(expression);
        System.out.println("Result: " + result);
    }

    public static double evaluateExpression(String expression) {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        try {
            Object result = engine.eval(expression);
            if (result instanceof Integer) {
                return (Integer) result;
            } else if (result instanceof Double) {
                return (Double) result;
            } else {
                throw new IllegalArgumentException("Invalid expression");
            }
        } catch (ScriptException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Invalid expression");
        }
    }
}