前言
大家好,我是小蚂蚁逸仙,《公式编辑器》能收到大家这么多的小星星,实在让本小蚂蚁受宠若惊。
原文中呢,部分些细节有些疏忽,可能讲的不是很透彻,以至于在某些问题上大家还是有点疑惑,再三思索,本小蚂蚁决定补一篇附录,用以专注于答复掘友门提出来的一些问题,并会对之进行持续更新。
另外,前段时间因为内人有了身孕,加之公事绕身,一直没能腾出时间,最近恰好有个新项目又用到了这部分的内容,所以决定借此良机把它做个封装,完工之后将会开放给大家。
问题集
好了,就跟大家唠这一块钱的,下面咱们进入正题:
1. 关于语法翻译
语法翻译这部分呢,有两个输入点,一个是参数集,这个是动态变化的,需要在公式进行运算的时候动态去获取;另一是公式集,这个是静态的。
关于参数集 我们稍微展开一下,我们在编辑器里编辑完公式之后,类似于下图中的 @单价
、@总量
等参数,在入库的时候我们存的其实都是它所在的表单组件的组件 id
,这样,我们在翻译的时候,就可以顺着组件 id
找到这个页面在使用的时候用户输入的值。
关于静态的公式集,我们是直接使用的公式库 @formulajs/formulajs
,这个大家直接 install
一下。
下面我看一下完整的核心代码:
// main.js
import * as Funcs from '@formulajs/formulajs/lib/cjs/index.cjs'
import { runScript } from './utils'
// 默认值公式计算
getRuleComputed (rule, values) {
// 用户编写的复合公式源码
const code = rule.newCode
// 解析并获取源码中用到的公式集里的计算公式
const formulaPtn = /(?<=\#)[A-Z]*(?=\()/g
const formulas = code.match(formulaPtn) || []
// 将源码中用到的公式、字段的前缀 #、@ 都替换成 this.
const runCode = `return (${code.replace(/[\#\@]/g, 'this.')})`
// 用获取到的公式名称构造出一个 function map
const useFuncs = Object.fromEntries(formulas.map(key => {
return [key, Funcs[key]]
}))
// 组合集成成一个统一 map,map 里包含了字段、公式
const envs = {
...useFuncs,
...values
}
// 执行
const res = runScript(runCode, envs)
if (res === 'script_error' ) return null
// 将执行结果返回
return res
}
工具函数集:
// utils.js
export function runScript (code, args) {
try {
const fn = new Function(code)
return fn.call(args)
} catch (error) {
return 'script_error'
}
}