title: 公式能力二期扩展 version: 1.0 date_created: 2026-06-13 last_updated: 2026-06-14 tags: ['formula', 'lookup', 'cross-object', 'debugger', 'function-market', 'condition-rule'] status: done complexity: high
公式能力 V1 已建立字段级公式体系,覆盖 CALC、AGGREGATE、CONDITIONAL、STORED/VIRTUAL、公式预览、语法校验、DAG 依赖分析、循环依赖检测和基础函数列表。下一阶段需要从“单对象字段计算”升级到“对象图公式 + 可观测性 + 可配置函数生态”,支撑更复杂的低代码业务规则。
本次变更规划以下能力:
| 能力 | 现状 |
|---|---|
| 公式领域模型 | FormulaConfig, AggregateConfig, ConditionConfig, FormulaType, FormulaMode |
| 表达式执行 | ExpressionExecutor, FormulaExecutionEngine |
| 聚合公式 | AggregateEngine, DbAggregateDataProvider |
| 依赖分析 | FormulaDependencyAnalyzer, DependencyAnalysisResult |
| 校验服务 | FormulaValidationService, FormulaPublishValidator |
| REST API | /api/ai/business/formula/validate, /preview, /dependency, /functions |
| 前端配置 | BusinessFieldPropertyPanel.vue 内嵌公式配置、校验和预览 |
| 前端 API | forge-admin-ui/src/api/formula.js |
/formula/functions 返回静态内置函数列表,无法治理函数状态、版本和市场来源。/formula/dependency 返回字段依赖信息,但没有图形化节点/边结构,也不覆盖跨对象依赖。ExecutionResult 只返回当前执行结果,不持久化执行日志,不支持运行后审计。优先级:P0
包含:
目标:
优先级:P1
包含:
目标:
优先级:P2
包含:
目标:
优先级:P3
包含:
目标:
FormulaType 新增 LOOKUP。customer.level、owner.realName。兼容 V1 配置,新增 lookup、crossObject、rule、functionRefs 元数据。
{
"type": "LOOKUP",
"mode": "VIRTUAL",
"expression": "",
"dependsOn": ["ownerUserId"],
"lookup": {
"relationCode": "customer_owner",
"targetObjectCode": "sys_user",
"sourceField": "ownerUserId",
"targetField": "id",
"returnField": "realName",
"notFoundValue": null
},
"crossObject": null,
"rule": null,
"functionRefs": []
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| relationCode | String | 是 | 对象关系编码 |
| targetObjectCode | String | 是 | 目标对象编码 |
| sourceField | String | 是 | 当前对象关联字段 |
| targetField | String | 是 | 目标对象匹配字段 |
| returnField | String | 是 | 返回字段 |
| notFoundValue | Object | 否 | 未命中时返回值 |
{
"path": "customer.level",
"relationCode": "order_customer",
"targetObjectCode": "crm_customer",
"returnField": "level",
"recomputeMode": "ASYNC"
}
{
"operator": "AND",
"children": [
{ "field": "amount", "op": "GT", "value": 1000 },
{ "field": "status", "op": "EQ", "value": "ACTIVE" }
]
}
生成表达式:
amount > 1000 && status == 'ACTIVE'
新增 Flyway 脚本,建议表名:ai_formula_execution_log。
核心字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| tenant_id | bigint | 租户 |
| trace_id | varchar(64) | 本次公式执行链路 ID |
| object_code | varchar(64) | 对象编码 |
| record_id | varchar(64) | 记录 ID |
| field_code | varchar(64) | 公式字段编码 |
| formula_type | varchar(32) | 公式类型 |
| formula_mode | varchar(32) | 计算模式 |
| expression | text | 表达式或配置摘要 |
| input_snapshot | json | 输入快照,脱敏后存储 |
| output_value | text | 输出值摘要 |
| success | tinyint | 是否成功 |
| error_message | text | 错误信息 |
| elapsed_ms | bigint | 耗时 |
| create_by | bigint | 创建人 |
| create_time | datetime | 创建时间 |
| create_dept | bigint | 创建部门 |
| update_by | bigint | 更新人 |
| update_time | datetime | 更新时间 |
建议新增:
ai_formula_functionai_formula_function_versionai_formula_function_install函数注册核心字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| function_code | varchar(64) | 函数编码 |
| display_name | varchar(128) | 展示名称 |
| category | varchar(64) | 分类 |
| source_type | varchar(32) | BUILTIN / SYSTEM / TENANT / MARKET |
| argument_schema | json | 参数 schema |
| return_type | varchar(32) | 返回类型 |
| example | text | 示例 |
| status | varchar(32) | ENABLED / DISABLED |
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/ai/business/formula/debug |
调试单公式或当前对象全部公式 |
请求示例:
{
"objectCode": "crm_order",
"fieldCode": "totalAmount",
"recordId": "1001",
"sampleValues": {
"price": 100,
"quantity": 3
},
"includeDependencyGraph": true
}
响应核心:
{
"success": true,
"traceId": "FML-20260613-0001",
"executionPlan": ["amount", "discount", "totalAmount"],
"steps": [
{
"fieldCode": "totalAmount",
"formulaType": "CALC",
"expression": "price * quantity",
"input": { "price": 100, "quantity": 3 },
"output": 300,
"elapsedMs": 4,
"success": true
}
],
"errors": []
}
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/ai/business/formula/log/page |
分页查询执行日志 |
| GET | /api/ai/business/formula/log/{id} |
查询日志详情 |
查询参数:
pageNumpageSizeobjectCoderecordIdfieldCodesuccesstraceIdbeginTimeendTime| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/ai/business/formula/dependency/graph |
返回依赖图 nodes / edges |
响应核心:
{
"valid": true,
"hasCycle": false,
"nodes": [
{ "id": "field:amount", "type": "FIELD", "label": "金额" },
{ "id": "formula:totalAmount", "type": "FORMULA", "label": "总金额" }
],
"edges": [
{ "source": "field:amount", "target": "formula:totalAmount", "type": "DEPENDS_ON" }
],
"cyclePath": []
}
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/ai/business/formula/function-market/page |
函数市场分页 |
| GET | /api/ai/business/formula/function-market/{functionCode} |
函数详情 |
| POST | /api/ai/business/formula/function-market/{functionCode}/install |
安装函数 |
| PUT | /api/ai/business/formula/functions/{functionCode}/enable |
启用函数 |
| PUT | /api/ai/business/formula/functions/{functionCode}/disable |
禁用函数 |
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/ai/business/formula/rule/compile |
规则 JSON 编译为表达式 |
| POST | /api/ai/business/formula/rule/validate |
校验规则 JSON 和生成表达式 |
修改 BusinessFieldPropertyPanel.vue:
FormulaConfigPanel.vueFormulaExpressionEditor.vueFormulaLookupPanel.vueFormulaCrossObjectPanel.vueFormulaConditionRuleDesigner.vueFormulaDebuggerPanel.vueFormulaDependencyGraph.vueFormulaExecutionLogDrawer.vue在对象设计器中增加公式工具入口:
这些入口应服务于当前对象上下文,默认带入 objectCode。
| 服务 | 责任 |
|---|---|
FormulaExecutionLogService |
执行日志落库、查询、脱敏 |
FormulaDebugService |
构建调试上下文、逐步执行、返回 trace |
FormulaDependencyGraphService |
将依赖分析结果转换为 nodes / edges |
FormulaLookupResolver |
解析 LOOKUP 配置并读取关联对象字段 |
FormulaCrossObjectResolver |
解析一跳跨对象路径和预取数据 |
FormulaObjectDependencyAnalyzer |
发布期将跨对象公式转换为对象图依赖并检测循环 |
CrossObjectRecomputeTaskService |
生成 STORED 跨对象公式待重算任务和幂等键 |
FormulaFunctionRegistry |
注册、查询、启停函数 |
FormulaFunctionMarketService |
市场函数安装和版本管理 |
ConditionRuleCompiler |
规则 JSON 转 Aviator 表达式 |
FormulaExecutionEngine 增加 step trace 输出能力。ExpressionExecutor 增加函数注册表集成。StoredFormulaRuntime 和 VirtualFormulaRuntime 接入日志服务。FormulaPublishValidator 增加 LOOKUP、跨对象路径、函数状态、条件规则校验。DbAggregateDataProvider 的批量查询经验复用到 LOOKUP / 跨对象 VIRTUAL 预取。| 风险 | 说明 | 缓解 |
|---|---|---|
| 跨对象 N+1 查询 | 列表查询时每行触发 LOOKUP | VIRTUAL 模式批量预取,限制一跳 |
| 跨对象循环依赖 | A 对象依赖 B,B 又依赖 A | 发布时对象图 DAG 校验 |
| 日志过大 | 成功公式大量执行导致日志膨胀 | 默认仅记录失败和调试日志,成功日志可配置采样 |
| 敏感数据泄露 | inputSnapshot 可能含敏感字段 | 字段敏感标记 + 统一脱敏器 |
| 自定义函数安全 | 函数可能执行危险逻辑 | 首期仅 Java Bean 注册,禁脚本 |
| 函数禁用兼容 | 旧公式引用被禁用函数 | 发布阻断,运行态给出明确错误 |
| 条件规则与表达式不一致 | UI JSON 和表达式双写漂移 | 保存时以 rule JSON 编译表达式,保留 expression 快照 |
FormulaExecutionLogServiceTestFormulaDebugServiceTestFormulaDependencyGraphServiceTestFormulaLookupResolverTestFormulaCrossObjectResolverTestFormulaObjectDependencyAnalyzerTestFormulaFunctionRegistryTestConditionRuleCompilerTestmvn -pl forge-framework/forge-plugin-parent/forge-plugin-generator -am testsource ~/.nvm/nvm.sh && nvm use v20.19.0 && pnpm --dir forge-admin-ui buildtax.amount, When 公式引用该函数并发布, Then 发布失败并提示函数未启用。amount > 1000 && status == 'ACTIVE' 并可预览。AiBusinessObjectRelation,还是允许显式 sourceField -> targetField 配置。