ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

同质化业务单据统一处理流水线 · 完整方案

同质化业务单据统一处理流水线 · 完整方案 同质化业务单据统一处理流水线 · 完整方案问题ERP 中会议费、差旅费、招待费、合同、结算单等单据业务上不同、技术上同构——都是「单据头 N 张明细」的主从结构表格正如 DOC 元数据定义所刻画的。逐单烟囱式开发 大量重复的页面、装载、校验、保存、审批代码。方案主张一套内核 × 元数据定义差异 × 插件补个性。公共属性与公共方法装载/校验/保存/状态机/编号/权限/审计/转换/Agent 通道在内核统一实现一次单据间差异由DOC 元数据定义表达与具体业务强相关的个性逻辑差旅标准校验、招待费限额、合同条款联动、结算核销以插件挂接到内核的生命周期钩子上。新增一种单据 写一份 DOC 定义 可选挂几个插件内核与页面零改动。与现有资产的关系重要本方案不是从零另起而是站在既有体系之上补齐流水线——定义/编译/部署/装载回存已由cmx-doccmx-doc-model cmx-doc-store-pgloader/saver/cache/revision/hier_service与《20260826 业务单据 DOC 元数据实现设计方案》落地base fieldSet 复用、DocMetaView、回存八步管线、加法-only 部署插件底座已有cmx-plugin/cmx-plugin-sdk骨架/cmx-plugin-triggerTriggerBindingStoreRhai/Native Rust 双通道在 cmx-ontology 已有先例。本方案新增的是其上的单据业务内核挂钩子的统一流水线、通用前端页面、单据转换引擎、Agent 工具面四块。图形为内嵌 base64 SVGimg标签单文件自包含。本方案只做设计不改代码一切实施等你确认。目录核心思想总体架构统一单据模型DOC 定义一张新单据长什么样插件机制个性化怎么挂后端流水线装载与保存接口设计遵守硬约束 5前端一套通用单据页面单据间转换与 Agent 的交互横切能力编号 / 权限 / 审计 / 打印集群无状态与性能实施路线分期风险与边界1. 核心思想图 1· 一套内核 × 元数据定义差异 × 插件补个性三层分工各管各的层管什么变更成本统一内核一次实现主从装载/回存、公共校验、状态机审批、编号、权限、审计、附件、转换引擎、Agent 工具面平台级改动需下游验证DOC 元数据定义每单据一份 JSON字段、明细表、字典引用、必填/类型校验、布局、按钮、挂哪些插件换 JSON 即生效零代码插件按需挂接差旅标准、招待费限额、合同条款联动、结算核销……强业务逻辑独立开发部署不动内核判据一句话所有单据都需要的进内核能用声明表达的进定义只有该单据才有的进插件。2. 总体架构图 2· 单据统一处理流水线总体架构落到本工作区拓扑前端cmx-enterprise-portal中一套通用单据页面元数据驱动渲染cmx-data-comp 组件装配路由只换docType页面骨架由doc-crud-pages技能生成真源进cmx-container/assets/。入口cmx-portalservice :8080薄壳反代不做业务。单据内核服务落在model :8093cmx-biz承载业务内核复用cmx-doc的装载回存。内含定义中心DocMetaView 缓存 Arc 热切换、装载/回存管线、插件运行时Native Rust 注册表 Rhai 沙箱 Wasm 预留、转换引擎、Agent 工具面。协作引擎审批走 flow :8091表达式/联动求值走 rules :8094行列级数据权限走 dataauth :8098编号规则复用 cmx-codegen 编码引擎设计打印/报表走 report :8092。存储PG单据数据 定义台账 转换关系台账 审计Redis会话/幂等票据/分布式锁。进程无状态可水平扩。3. 统一单据模型图 3· 主从结构 公共块 统一状态机单据头 DocHeader每单一行。公共列doc_type / doc_no / status / biz_date / org / dept / applicant / currency / total_amount / source_ref / version / created_by / created_at …由base fieldSet统一注入既有机制业务字段来自各 DOC 定义。明细表 0…N 张由定义声明差旅行程费用行合同条款付款计划结算结算行扣款行。装载沿用「父批量驱动子」防 N1。横切公共块附件、审批轨迹、操作审计、打印模板、编号规则、数据权限——所有单据共享同一套表与实现。统一状态机draft → submitted → approving → approved → archived另有rejected回草稿/ voided。迁移入口只有内核一处提交即向 flow :8091 发起流程实例审批节点回调内核完成迁移。迁移前后暴露插件钩子如before_submit做完整性检查、on_state_change(approved)触发出账。Rust 侧的内核心智模型简化/// 运行时统一单据实例——所有单据类型共用这一个结构pubstructDocInstance{pubdef:ArcDocMetaView,// 该 docType 的定义投影只读热切换缓存pubheader:Row,// 动态行按定义收窄的字段集publines:IndexMapTableId,VecRow,// 明细表名 → 行集pubdirty:ChangeSet,// 差量新增/修改/删除行驱动差量回存pubstate:DocState,// 状态机当前态}4. DOC 定义一张新单据长什么样在既有 DOC 定义骨架§20260826 方案的定义层上本方案扩展四个声明区behaviors启用哪些公共行为、plugins挂接哪些插件到哪些钩子、ui通用页面布局提示与 slot、converts可转换到哪些下游。以差旅报销单为例示意字段从简{ kind: doc, code: TRAVEL_EXPENSE, name: 差旅费报销单, base: [fs.doc.common, fs.doc.money, fs.doc.approve], // 既有 base fieldSet 复用 header: { fields: [ { name: reason, label: 出差事由, type: text, required: true }, { name: trip_days, label: 出差天数, type: int, compute: sum(lines.trip.days) }, { name: advance, label: 已借款, type: money, readonly: true } ] }, lines: [ { table: trip, label: 行程明细, fields: [ /* 出发地/目的地/交通工具/days… */ ] }, { table: expense, label: 费用明细, fields: [ /* 费用类型(dict)/金额/税额/发票号… */ ] } ], behaviors: { numbering: LZ-{yyyy}{seq6}, attachment: true, approve_flow: FLOW_TRAVEL, print: tpl_travel_a4, dataauth: scope.dept }, plugins: [ { hook: validate, ref: native:travel_standard_check }, // 差旅标准Rust 插件 { hook: compute, ref: rhai:travel_amount.rhai }, // 金额汇总脚本插件 { hook: after_submit, ref: trigger:budget_occupy } // 预算占用异步触发器 ], ui: { layout: std-doc-page, slots: { header-extra: TravelStandardTip } }, // 个性 slot → 前端注册的微件 converts: [ { to: PAYMENT_REQ, rule: cv_travel_to_payment } ] }新增一张「会议费报销单」复制上面骨架改 code/字段/明细/插件引用即可——编译、部署加法-only、装载、页面、Agent 工具全部自动跟上。5. 插件机制个性化怎么挂图 4· 单据生命周期钩子内核发布固定插件点5.1 钩子清单同步钩子在请求内、按声明顺序执行阶段钩子典型用途装载before_load/after_load默认值注入、上游携带、补充展示字段编辑on_field_change/on_line_add/on_line_del/compute字段联动选人带部门、行税额重算、头金额汇总保存/提交validate/before_save/after_save/before_submit差旅标准、限额校验、预算占用、完整性检查状态/转换on_state_change/before_convert/after_convert/on_void出账、核销、携带默认值异步旁路领域事件 →cmx-plugin-trigger通知、出账、外部系统同步不阻塞主事务5.2 两种同步运行时 一条异步通道① Native Rust 插件性能与类型安全首选编译进引擎或经 cmx-plugin 动态注册usecmx_plugin_sdk::prelude::*;/// 差旅标准校验插件挂 validate 钩子pubstructTravelStandardCheck;#[async_trait]implDocPluginforTravelStandardCheck{fnmeta(self)-PluginMeta{PluginMeta::new(travel_standard_check,[validate])}asyncfnon_validate(self,ctx:mutDocCtx_)-PluginResult{letgradectx.host().employee_grade(ctx.doc.header.get_str(applicant)?).await?;for(i,row)inctx.doc.lines(expense)?.iter().enumerate(){letlimitctx.host().travel_limit(grade,row.get_str(fee_type)?).await?;ifrow.get_money(amount)?limit{// 结构化错误前端定位到具体行/列Agent 也能读懂ctx.reject(field_err!(expense,i,amount,超出差旅标准 {limit}));}}Ok(())}}要点插件只依赖cmx-plugin-sdk的DocCtx读写单据实例、host_calls 访问平台服务不直接摸 SQL/HTTP——保证插件可测试、可沙箱、可替换运行时。② Rhai 脚本插件轻逻辑/实施顾问可写热更新沙箱限步数防失控——沿用 cmx-ontology 已落地的 Rhai 通道模式// travel_amount.rhai —— compute 钩子行税额重算 头金额汇总 let total 0.0; for row in doc.lines(expense) { row.tax row.amount * tax_rate(row.fee_type); // host 函数 total row.amount row.tax; } doc.header.total_amount total - doc.header.advance;③ 异步触发器既有cmx-plugin-trigger/TriggerBindingStore领域事件doc.approved等经 outbox 出箱后投递绑定的触发器——预算占用、出账、消息通知等旁路动作走这里失败重试不影响已提交事务。Wasm 运行时预留SDK 的钩子签名保持「纯数据入、纯数据出 host_calls」未来第三方插件可编译为 Wasm 在沙箱运行接口不变。5.3 插件解析与治理定义里plugins[].ref按native:/rhai:/trigger:前缀路由到对应运行时找不到即部署期报错不是运行期。同钩子多插件按声明顺序串行validate全量收集错误不短路其余钩子失败即中断。插件与定义同版本管理定义发版携带脚本内容哈希防「定义与脚本漂移」。6. 后端流水线装载与保存图 5· POST /api/doc/save 一次调用的完整旅程白内核橙插件绿单事务装载GET /api/doc/detail鉴权 → 取 DocMetaView缓存→before_load→ 父批量驱动子装载既有 loader→ dataauth 行列过滤 →after_load→ 输出数据 元数据版本 可用动作按状态机计算。保存/提交图 5 的 ①~⑮关键设计幂等客户端携带client_tokenRedis 记票据重试不重号、不重单。差量回存前端只传 ChangeSet新增/修改/删除行复用既有 saver 八步管线乐观锁version冲突即拒并返回最新版本。编号在事务内首存/提交时经编号规则cmx-codegen取号与保存同事务失败回滚不跳号段式预取减少热点。错误结构化所有校验/插件错误统一为{table, row, field, code, msg}前端定位到单元格Agent 直接读懂并转述。提交 保存 before_submit 状态迁移 flow 发起同一入口不给绕行机会。// model :8093 · 统一保存入口示意一个 handler 服务所有单据类型asyncfndoc_save(State(app):StateApp,Json(req):JsonSaveReq)-ApiResultSaveResp{letdefapp.meta.doc_view(req.doc_type)?;// ArcDocMetaView 缓存热切换app.idempotent.check(req.client_token).await?;// 幂等票据letmutdocDocInstance::assemble(def,req.payload)?;// ③ 按定义收窄装配doc.validate_common()?;// ④ 必填/类型/字典/权限app.plugins.run(Hook::Validate,mutdoc).await?;// ⑤ 插件校验收集全部错误app.plugins.run(Hook::Compute,mutdoc).await?;// ⑥ 重算letrespapp.doc_store.save_tx(mutdoc,app).await?;// ⑦~⑫ 编号八步回存状态机审计outboxapp.plugins.run(Hook::AfterSave,mutdoc).await?;// ⑬Ok(Json(resp))// ⑮ 新版本号 联动结果}7. 接口设计遵守硬约束 5固定资源段、无可变路径段更新/删除/动作一律POST JSON body只读详情用GET query。一套接口服务所有单据类型docType是参数不是路径接口方法说明/api/doc/metaGET?docTypever定义投影字段/明细/布局/按钮/校验提示前端与 Agent 共用/api/doc/listPOST列表查询过滤/分页/排序在 body经 dataauth 过滤/api/doc/detailGET?docTypeid装载单据含可用动作/api/doc/savePOST草稿保存ChangeSet client_token/api/doc/submitPOST提交 保存 校验 发起审批/api/doc/actionPOST状态动作审批回调/驳回/作废/归档{docType,id,action,…}/api/doc/computePOST服务端联动求值字段变化 → 重算指令前端只呈现/api/doc/convertPOST下推转换{fromType,fromId,rule,selection}→ 目标草稿/api/doc/convert-traceGET?docTypeid上下游追溯链/api/doc/deletePOST删除草稿{docType,id,version}8. 前端一套通用单据页面图 6· 通用单据页面结构与四步渲染管线一个页面组件吃所有单据路由/doc-page?docTypeTRAVEL_EXPENSE。首屏拉/api/doc/meta通用渲染器用cmx-data-comp97 元素装配工具栏按可用动作渲染 表头表单 明细页签网格列定义走 CmxColumnModel 统一口径 附件 审批轨迹。个性化 声明式 slot定义ui.slots声明挂点工具栏扩展钮 / 表头个性区 / 明细列自定义渲染器前端注册同名微件组件没有 slot 的单据 100% 零前端代码。联动走服务端字段变化调/api/doc/compute前端只应用返回的补丁指令。口径唯一——UI、导入、Agent 三个入口的联动/校验结果完全一致。硬约束落实双主题通路UI5 色值一律var(--sap*, fallback)Neo 组件支持data-cmx-skin/data-cmx-skin-tone禁止硬编码色值页面骨架用doc-crud-pages技能生成产物真源进backend/cmx-container/assets/经publish-assets.sh发布——不直接改各仓web/下的发布产物。9. 单据间转换图 7· 映射规则元数据驱动的下推/上拉与核销台账转换引擎是内核统一实现差异全部进转换规则元数据{ code: cv_travel_req_to_expense, from: TRAVEL_REQ, to: TRAVEL_EXPENSE, precondition: from.status approved, // rules 表达式 header_map: [ { to: applicant, op: copy, from: applicant }, { to: reason, op: copy, from: reason }, { to: advance, op: expr, expr: from.advance_amount } ], line_map: [{ from_table: trip, to_table: trip, filter: line.remain_qty 0, // 仅未核销行可携带 mode: by_selection, // 按用户勾选携带亦支持 merge/split fields: [ { to: days, op: copy, from: days } ], writeoff: { qty: days } // 核销口径按天数 }] }关键机制核销台账来源单行 ↔ 目标单行的关联表记录已转数量/金额控超转、支持多次部分下推目标单作废时回冲核销量。追溯链合同 → 结算单 → 付款单、差旅申请 → 差旅报销 → 付款任一单可上查来源、下查去向/api/doc/convert-trace。产物是草稿转换只生成目标单草稿之后走同一套保存/校验/提交流水线——转换不绕过任何校验。个性转换逻辑挂before_convert/after_convert钩子如报销单携带时默认带出差旅标准。10. 与 Agent 的交互图 8· 元数据自动生成工具集 草稿两段式提交工具集自动生成内核把每个 docType 的 DOC 定义投影为一组doc.*工具 schemadoc.meta / doc.list / doc.draft_save / doc.submit / doc.convert / doc.trace字段、必填、字典枚举、校验提示全部来自定义——新单据上线Agent 零适配自动会用。两段式写入铁律Agent 只能doc.draft_save落草稿doc.submit必须携带用户确认产生的confirm_tokenIM/桌面端确认动作签发。Agent 永远无法未经人确认提交单据。同一管线Agent 调用与 UI 完全同路——同样的校验、插件、权限dataauth 按会话用户裁剪、审计actoragent, 关联会话与原始指令。结构化校验错误让 Agent 能精确转述「费用明细第 2 行金额超差旅标准」。典型会话「帮我报上周去上海的差旅」→ Agent 取 meta → 从对话/发票图片抽取字段 → 落草稿 → 返回摘要缺项 → 用户补发票并确认 → 提交进审批;「把 3 月未报销的差旅申请都下推成报销单」→ 逐单doc.convert产草稿 → 汇总清单等确认。通道桌面cmx-agent孤岛架构不变经 HTTP 调 portal 工具面与 IM 遥控既有 20260906 方案共用同一工具层。11. 横切能力编号 / 权限 / 审计 / 打印能力方案复用编号规则定义声明模板LZ-{yyyy}{seq6}事务内取号、段式预取防热点、作废不回收留审计cmx-codegen 编码引擎20260804 方案数据权限列表/详情统一经 dataauth 行列级裁剪字段级只读/脱敏在 meta 投影时下发dataauth :809820260831 体系审计谁在何时对哪单做了什么含 Agent 会话关联字段级变更留痕挂 revision既有 revision 审计表附件统一附件表挂doc_typedoc_id防篡改哈希公共块一次实现打印定义声明打印模板数据投影交 report :8092 渲染report 引擎12. 集群无状态与性能定义缓存 只读配置例外ArcDocMetaView进程内缓存 版本热切换arc-swap 原子替换旧版本引用归零整块释放——符合硬约束的「只读配置」豁免业务数据一律不进程内缓存。请求级 arena保存/装载管线的临时对象装配行、校验中间态、转换映射产物用 per-requestbumpaloworkspace 已预置 3.16 未启用承载响应后整块释放——正是《20260913 Arena 在企业 ERP 中的应用建议》的落点。幂等与锁幂等票据、跨节点互斥如同单并发提交全在 Redis定时任务如超时催办用SELECT … FOR UPDATE SKIP LOCKED可重入。进程内零业务状态节点可任意扩缩。性能要点父批量驱动子装载防 N1既有差量回存少写meta 接口带ver支持前端缓存协商列表查询强制走 dataauth 谓词下推到 SQL。13. 实施路线分期期内容验收P1 内核最小闭环cmx-biz单据内核统一模型 保存/装载管线复用 cmx-doc 状态机 幂等 结构化错误validate/compute/before_save/after_save四个钩子 Native 插件注册表用「会议费」单跑通 保存→提交→审批→归档 全链路cargo check/clippy 验证portalmodel 联调P2 通用页面前端通用单据页 slot 机制 /api/doc/meta投影 compute 联动doc-crud-pages 技能对齐会议费/差旅费两单共用同一页面切 docType 即换单据双主题过 ReviewP3 插件完备Rhai 沙箱运行时 异步触发器接通 plugin-trigger 插件治理版本哈希/部署期校验差旅标准校验Native 金额汇总Rhai 预算占用trigger三类插件各落一个P4 转换引擎映射规则元数据 核销台账 追溯链 convert 钩子差旅申请→报销、合同→结算 两条链路含部分下推与超转控制P5 Agent 工具面doc.* 工具 schema 生成器 草稿两段式 审计关联cmx-agent 自然语言完成一次报销草稿并经确认提交P6 迁移推广存量单据逐个迁到定义插件模式沉淀《单据接入手册》进技能新单据接入 ≤1 人日仅定义插件每期遵守Rust 验证只用cargo check/clippy改cmx-container公用库必做下游验证portal至少一个引擎新接口全部 POSTJSON/固定路径完成只汇报提交由你决定。14. 风险与边界内核蔓延警惕把个别单据的特殊逻辑「顺手」写进内核——判据坚持 §1 三层分工Review 把关。插件失控Rhai 沙箱必须限步数/限时/限 host 面插件错误必须结构化上抛禁止吞错;validate之外的钩子失败即中断事务。定义漂移定义、脚本、转换规则三者版本捆绑发布内容哈希部署期校验引用完整性。不是万能适用于「主从表格 审批」同构单据重交互的排程/图形化场景如电子表格 mega-sheet、本体图不硬套此流水线。性能兜底超大明细万行级走分页装载 服务端聚合禁一次全量进浏览器。一句话收束把「所有单据都一样的部分」做成一次性内核把「单据之间不一样的部分」压进一份 JSON 定义把「只有这张单据才有的部分」隔离成插件——此后每张新单据都只是一份定义加几个插件的事。本方案图形均为内嵌 base64 SVG单文件自包含。仅为设计方案未改任何代码实施按 §13 分期启动前等你确认。
返回列表