公式编辑器 —— 附录

587 阅读2分钟

前言

大家好,我是小蚂蚁逸仙,《公式编辑器》能收到大家这么多的小星星,实在让本小蚂蚁受宠若惊。

原文中呢,部分些细节有些疏忽,可能讲的不是很透彻,以至于在某些问题上大家还是有点疑惑,再三思索,本小蚂蚁决定补一篇附录,用以专注于答复掘友门提出来的一些问题,并会对之进行持续更新。

另外,前段时间因为内人有了身孕,加之公事绕身,一直没能腾出时间,最近恰好有个新项目又用到了这部分的内容,所以决定借此良机把它做个封装,完工之后将会开放给大家。

问题集

好了,就跟大家唠这一块钱的,下面咱们进入正题:

1. 关于语法翻译

语法翻译这部分呢,有两个输入点,一个是参数集,这个是动态变化的,需要在公式进行运算的时候动态去获取;另一是公式集,这个是静态的。

关于参数集 我们稍微展开一下,我们在编辑器里编辑完公式之后,类似于下图中的 @单价@总量等参数,在入库的时候我们存的其实都是它所在的表单组件的组件 id,这样,我们在翻译的时候,就可以顺着组件 id 找到这个页面在使用的时候用户输入的值。

image.png

image.png

关于静态的公式集,我们是直接使用的公式库 @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'
  }
  
}