ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

NocoBase 表达式表:为工作流动态表达式计算准备可配置规则的数据表方案

NocoBase 表达式表:为工作流动态表达式计算准备可配置规则的数据表方案 NocoBase 表达式表为工作流动态表达式计算准备可配置规则的数据表方案【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase表达式表Expression Collection是 NocoBase 数据建模体系中专门面向工作流动态表达式计算场景的一种表模板。它把计算规则/公式当作可管理的数据存表每行公式可以引用不同数据模型中的字段作为变量、可以指定不同的计算引擎再通过关联关系挂接到业务数据上最终由工作流中的动态计算节点在运行时按行加载并求值。读完本文你将掌握表达式模板表的创建方式、字段构成、业务数据与公式的关联设计以及动态计算节点在源码层面的执行链路。表达式表在数据建模中的定位在 NocoBase 的数据表类型体系中除了普通表、树表、日历表、视图表、SQL 表等常规形态外还存在若干为特定业务场景定制的表模板。数据建模概述的表类型说明中明确列出了这一行表达式表 —— 用于工作流的动态表达式场景。与普通业务表不同表达式表里存放的不是业务实体而是规则本身针对特定表数据模型的一条计算规则。这样做的价值在于把公式从工作流配置中抽离出来变成可以被增删改查、可以被按类别组织、可以随业务数据一起被查询加载的数据行从而实现同一套流程不同数据走不同公式的动态计算能力。创建表达式模板表在工作流内使用动态表达式运算节点之前需要先在数据表管理工具中创建一张表达式模板表用于存放不同的表达式。这张模板表由插件nocobase/plugin-workflow-dynamic-calculation的客户端代码以集合模板的形式注册其定义见 ExpressionCollectionTemplate.tsexport class ExpressionCollectionTemplate extends CollectionTemplate { name expression; title {{t(Expression collection)}}; order 4; color orange; default { createdBy: true, updatedBy: true, createdAt: true, updatedAt: true, fields: [ { name: engine, type: string, interface: radioGroup, uiSchema: { type: string, title: {{t(Calculation engine)}}, x-component: Radio.Group, enum: getOptions(), default: formula.js, }, }, { name: sourceCollection, type: string, interface: select, uiSchema: { type: string, title: {{t(Collection)}}, x-component: CollectionSelect, }, }, { name: expression, type: text, interface: expression, uiSchema: { type: string, title: {{t(Expression)}}, x-component: DynamicExpression, }, }, ], }; // ... }从这段模板定义ExpressionCollectionTemplate.ts#L13-L71可以读出表达式表的完整字段构成字段类型/界面说明enginestring / 单选按钮组Radio.Group指定该行公式使用的计算引擎选项来自nocobase/evaluators/client的getOptions()模板中的默认值为formula.jssourceCollectionstring / 数据表选择CollectionSelect指定该公式针对的数据表数据模型即公式的适用对象expressiontext / 表达式字段x-component: DynamicExpression表达式正文即计算规则的字符串表达createdBy/updatedBy/createdAt/updatedAt系统审计字段模板默认开启记录公式行的创建与修改痕迹值得注意的一个细节模板里表达式列使用的字段接口是expression这是一个由插件注册的自定义字段类型。服务端实现见 expression-field.tsexport class ExpressionField extends Field { get dataType() { return DataTypes.TEXT; } }ExpressionField继承自nocobase/database的Field落库数据类型为TEXT保证较长的公式字符串也能完整存储见 expression-field.ts#L16-L19。插件的load方法把该字段类型注册进数据库并同时向工作流插件注册dynamic-calculation指令这两处注册逻辑见 Plugin.ts#L17-L24async load() { this.db.registerFieldTypes({ expression: ExpressionField, }); const workflowPlugin this.app.getPluginWorkflowPlugin(WorkflowPlugin); workflowPlugin.registerInstruction(dynamic-calculation, DynamicCalculation); }也就是说表达式表字段类型expression与动态计算指令dynamic-calculation是同一个插件成对提供的能力前者负责规则的存储后者负责规则的运行时求值。版本提示当前仓库中 该插件的文档 frontmatter 已标注deprecated: true本插件已废弃。在使用表达式表 动态计算指令这套方案时请以你所使用的 NocoBase 版本中该插件的实际可用状态为准若插件不可用可参考下文的工作流计算节点作为静态表达式的替代。录入表达式数据创建好模板表后可以为该表添加一个表格区块录入若干条公式数据。理解方式上表达式模板表中每行数据都可以被理解为针对特定表数据模型的一个计算规则每行公式可以使用不同数据表的数据模型中的字段值作为变量因此一张表达式表可以同时服务于多个业务对象每行公式可以使用不同的计算引擎即engine列逐行指定同一张表内的各行规则互不干扰结合sourceCollection列标注规则所属的数据模型便于在流程中按数据源筛选加载。计算引擎决定了表达式支持的语法。按 工作流计算节点文档的说明目前支持的引擎有 Math.js 和 Formula.js二者都内置了常用的函数和数据操作方法另有一个字符串模板引擎用于简单的字符串拼接将表达式中的变量替换为对应值后返回拼接结果。两个引擎的关键差异是数组下标访问Math.js 的索引从1开始Formula.js 从0开始编写含数组下标的公式时需要特别注意。更多引擎细节可参考 计算引擎文档。将业务数据与公式关联创建好公式以后还需要将业务数据与公式进行关联。如果将每行业务数据直接关联到公式数据行会比较繁琐通常的关联设计是引入一层类似分类的元数据表用分类元数据表与公式表建立**多对一或一对一**关联——同一分类下的数据共享同一套公式再将业务数据与分类元数据建立多对一关联创建业务数据时只需指定特定的分类元数据后续流程中即可通过这条关联路径找到对应的公式数据使用。这种两级关联业务数据 → 分类 → 公式让公式的切换收敛到分类这一层新增一种计算口径只需新增一行公式数据并建立新的分类业务数据改挂新分类即可无需修改流程配置。流程中加载相应的数据以数据表事件为例创建一个工作流当订单创建时触发并需要预加载订单关联的商品数据和商品相关的表达式数据。这一步的意义在于把后续动态计算所需的变量订单明细、对应公式行提前装入流程上下文使动态计算节点执行时无需再发起额外查询也保证公式中引用的变量在求值时一定存在。加载完成后流程中接入动态计算节点。该节点对应的服务端指令实现见 DynamicCalculation.ts#L14-L37export class DynamicCalculation extends Instruction { async run(node: FlowNodeModel, prevJob, processor: Processor) { let { engine math.js, expression } node.config; let scope processor.getScope(node.id); const parsed parse(expression)(scope) ?? {}; engine parsed.engine; expression parsed.expression; scope parse(node.config.scope ?? )(scope) ?? {}; const evaluator Evaluator | undefinedevaluators.get(engine); try { const result evaluator expression ? evaluator(expression, scope) : null; return { result, status: JOB_STATUS.RESOLVED, }; } catch (e) { return { result: e.toString(), status: JOB_STATUS.ERROR, }; } } }从这段源码可以梳理出动态计算节点的完整执行链路它与表达式表方案的每个设计点一一对应引擎与表达式的来源是可动态解析的节点配置中的engine与expression先作为字面量取默认值engine默认为math.js注意这与表达式表模板中formula.js的默认值不同属于两处各自独立的默认随后parse(expression)(scope)允许配置本身引用流程上下文变量——这正是表达式存放在数据行、由流程按行加载后依然能保持动态性的关键作用域scope的组装processor.getScope(node.id)获取当前节点可见的流程变量前置节点结果、循环局部变量等再叠加节点配置中scope的解析结果。从表达式表预加载的公式行、商品数据即通过这条通道进入作用域按引擎求值evaluators.get(engine)从求值器注册表中取出对应引擎Math.js / Formula.js 等对表达式求值并返回JOB_STATUS.RESOLVED与计算结果错误处理若求值时变量不存在、类型不匹配或函数不存在指令捕获异常并返回JOB_STATUS.ERROR节点以出错状态提前终止错误信息写入节点结果便于在工作流执行记录中排查该指令的行为另有测试用例 instruction.test.ts 覆盖。与静态计算节点的分工在 NocoBase 工作流中还存在一个通用的计算Calculation节点用于对固定写在节点配置里的表达式求值同样支持 Math.js、Formula.js 与字符串模板引擎其典型用例如用 Formula.js 的SUMPRODUCT函数计算订单总价。两者的分工可以概括为计算节点规则内联在工作流配置中适合逻辑稳定、不随数据变化的计算表达式表 动态计算指令规则外置为数据行按业务数据经由分类等关联关系逐行选择公式适合同一流程、多套计算口径的运营化场景例如不同商品类别使用不同的计价公式。表达式表方案的本质是把计算规则纳入 NocoBase 的数据模型管理建表、录入、关联、查询使公式的维护从改流程配置变为维护数据这是其与静态计算节点的核心差异。小结表达式表通过expression集合模板创建包含engine、sourceCollection、expression三个核心字段及审计字段模板定义见 ExpressionCollectionTemplate.ts每行数据是一条针对特定数据模型的计算规则可逐行指定计算引擎变量来自流程上下文中预加载的数据业务数据建议经由分类元数据表与公式表两级关联避免逐行直接关联运行时由dynamic-calculation指令解析引擎与表达式、组装作用域并求值源码见 DynamicCalculation.ts指令与字段类型的注册见 Plugin.ts使用前提注意当前仓库中nocobase/plugin-workflow-dynamic-calculation已标记废弃落地前请确认目标版本中插件的可用状态并对照 工作流计算节点与 计算引擎文档选择适合的求值方式。【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表