低代码公式引擎&公式编辑器

939 阅读3分钟

公式编辑器&公式引擎

运行截图

img.png

公式编辑器

创建编辑器

FormulaEditor 基于 codemirror/EditorView 扩展

const containerRef = shallowRef<HTMLDivElement>();

const instance = new FormulaEditor(containerRef, {
      extensions: createExtensions({
        /** 自定义关键字 */
        keywords: [],
         /** 自定义函数名 */
        functions: ['SUM'],
        /** 自定义变量 value:字段全路径 */
        variables: [
          {label: '用户', value: 'user', type: 'object', category: 'field'},
          {label: '用户.名称', value: 'user.name', type: 'string', category: 'field'},
          {label: '用户.年龄', value: 'user.age', type: 'number', category: 'field'},
          {label: '用户.组织', value: 'user.org', type: 'number', category: 'field'},
          {label: '用户.组织.名称', value: 'user.org.name', type: 'text', category: 'field'},
        ],
         /** 自定义提示 默认的变量匹配规则是{},所以value必须包含在{}中 */
        hints: [
          {label: '用户', value: '{user}', type: 'variable', detail: '用户',
          children: [
            {label: '名称', value: '{user.name}', type: 'text', detail: '用户的名称'},
            {label: '年龄', value: '{user.age}', type: 'variable', detail: '用户的年龄, number类型'},
            {label: '组织', value: '{user.org}', type: 'class', detail: '用户的组件',
              children: [
                {label: '名称', value: '{user.org.name}', type: 'text', detail: '组件名称'},
              ]
            },
          ]
          },
        ]
      })
    });

编辑器实例方法

名称类型说明
getValue()获取编辑器内容
setValue(value: string)设置编辑器内容,会覆盖原内容
insertValue(value: string, isTemplate: boolean)插入内容, isTemplate插入的内容是否需要按模板解析
setDisabled(disabled: boolean)禁用编辑器
setPlaceholder(placeholder: string)设置占位文本
setStyle(style: object)设置编辑器样式
reloadExtension(extension: Extension)刷新插件
focus()编辑器获取焦点
dispose()销毁编辑器

自定义变量匹配规则

通过 createVariablePlugin(variables, regexp) 方法创建自定义匹配规则

/** 定义成 {{ }} 匹配变量 */
const variableExtension = createVariablePlugin(
        [
          {label: '用户', value: 'user', type: 'object', category: 'field'},
          {label: '用户.名称', value: 'user.name', type: 'string', category: 'field'},
          {label: '用户.年龄', value: 'user.age', type: 'number', category: 'field'},
          {label: '用户.组织', value: 'user.org', type: 'number', category: 'field'},
          {label: '用户.组织.名称', value: 'user.org.name', type: 'text', category: 'field'},
        ],
        /{{(.+?)}}/g
    );
    
const containerRef = shallowRef<HTMLDivElement>();

const instance = new FormulaEditor(containerRef, {
    extensions: [variableExtension]
})

公式引擎

创建解析引擎

const formulaEngine = new FormulaEngine({
     /** 注入自定义函数 key为函数名 */
     functions: {
        'GETUSERNAME': function(users) {
          if(!users || !Array.isArray(users)) return ''
          return users.map(user=> user.name).join(',')
        },
      },
      /** 全局变量 */
      scopeData: {},
    });
    /** 执行公式 */
    const res = formulaEngine.exec(formulaStr, variableData);

自定义变量匹配规则

覆盖 variableToken。 name 固定为 VARIABLE

const formulaEngine = new FormulaEngine({
      functions: {
        'GETUSERNAME': function(users) {
          if(!users || !Array.isArray(users)) return ''
          return users.map(user=> user.name).join(',')
        },
      },
      scopeData: {},
      variableToken: {
        name: "VARIABLE",
        pattern: /{{.*?}}/,
      }
    });

解析引擎实例方法

名称类型说明
registerFunctions(fus: Record<string, Function>)注册自定义函数
exec(expression: string, scopeData?: object, autoMerge?: boolean)执行公式,expression为公式字符串,scopeData为变量数据,autoMerge是否和全局变量合并,否则覆盖全局变量
dispose()销毁重置

解析引擎内置函数

  • 日期函数
名称类型说明使用示例
TODAY()返回当前时间戳TODAY()
...
  • 逻辑函数
名称类型说明使用示例
AND(...args)并且,每一项参数为真则返回真,有一项为假返回假AND(3>2, 2>1, 1>1) => false
OR(...args)或者,有一项为真则返回真,全部为假返回假OR(3>2, 1>2, 1>1) => true
FALSE()总是返回假FALSE()
TRUE()总是返回真TRUE()
IF(logic, p1, p2)条件判断,为真返回p1,否则返回p2IF(3>4, 1, 2) => 2
NOT(logic)结果取反NOT(3>4) => true
XOR(...args)异或,每一项都相同返回假,有一项不同则返回真XOR(a>10,b>10)
  • 数学函数
名称类型说明使用示例
ADD(a,b,n?)两数相加,为保留小数位ADD(1.5, 2.41, 1) => 3.9
...
  • 文本函数
名称类型说明使用示例
JOIN(arr, separator)数组拼接成字符串, separator为拼接符号JOIN(['a','b', 'c'], '-') => 'a-b-c'
...