Files
workspace/code/fms/.workbuddy-ai/memory/2026-09-23.md
T
2026-09-23 16:54:54 +08:00

8.6 KiB
Raw Blame History

2026-09-23

梳理 fms-vue 的 workflow(只读调研,未改代码)

结论:前端只有「设计期」的流程配置器,运行期(审批中心)仍是占位页,后端 fms-api/src/main 零工作流代码。

  • 代码分布(约 2090 行 / 8 文件):fms-vue/src/views/system/workflow/
    • index.vue 流程定义列表(模块 v_wf_definition,只读,b_save_table 为空)
    • design.vue 设计页壳(?id= 读回 / 空草稿新增,读回失败回落空草稿)
    • designer/domain.js 领域模型适配 + 发布前校验(核心)
    • designer/constants.js 枚举 + 节点元数据(中文文案唯一出处;画布配色是字面量,SVG 不吃 CSS 变量,深色模式待办)
    • designer/nodes.js 7 个 LogicFlow 自定义节点(无 @logicflow/vue-node-registry,节点是原生 SVG)
    • WorkflowCanvas.vue / WorkflowDesigner.vue / WorkflowPropertyPanel.vue / WorkflowNodePanel.vue / WorkflowValidationPanel.vue / WorkflowToolbar.vue
    • designer/api.js 只读读回草稿(走 /data/loaddata,优先 published 版本)
  • 路由:/system/workflow(无 moduleId,靠菜单 menu.workflow)、/system/workflow/design(在 EXCLUDED_PATHS 内)、 /approval/{todo,initiated,done,cc} → views/approval/ApprovalPlaceholder.vue。
  • 三条铁律:① 领域草稿是唯一真相,画布模型只在编辑器内存在;② 画布持有结构真相、属性面板持有业务配置,互不回灌 (回灌会丢撤销栈与选中态);③ 校验是 validateWorkflowDomain(draft) 纯函数,实时重算,后端保存/发布时再校验一次。
  • 写入通道未实现:wf_* 不允许走 /data/saveobjt,必须走流程服务,所以工具栏只有撤销/缩放/查看草稿 JSON。
  • 已建好但未用:sql/fms_workflow.sql(13 张表)、fms_workflow_module.sql(视图 + s_module 注册)、 fms_workflow_menu.sql(菜单 workflow / approval*)、fms_workflow_mock.sql(expense_approval 样本, 覆盖 7 种节点类型 / 6 种审批方式 / 5 种审批人解析,可用来试设计器)。
  • 下一步方向见根目录《FMS审批流程交互重构设计.md》:默认改「钉钉式纵向节点卡片」,LogicFlow 降为高级模式, 两模式共用同一份草稿且 editorMode 不落库;补保存/校验/模拟/发布、审批人选择器、AND/OR 条件构造器、基本信息+绑定页签。

按该文档做了一轮前端重构(已落地,但方案随后被文档作废)

  • domain.js 升级 schemaVersion 2:草稿含 definition/version/bindings/nodes/edges,新增条件 AST(all/any)、 节点摘要、draftToSavePayload(拆平到 wf_* 各表)、卡片模式图操作(插入/删除/移动/复制)。
  • 新增组件:WorkflowModeTabs / WorkflowBasicPanel / WorkflowStepEditor / WorkflowStepCard / WorkflowStepInsert / WorkflowPropertyDrawer / WorkflowActorSelector / WorkflowConditionBuilder / WorkflowSimulationPanel / WorkflowCreateDialog;删除被取代的 WorkflowPropertyPanel.vue。
  • api.js 补草稿读取(含 wf_binding)、可绑定模块、模块 s_field、用户/部门只读查询与缓存, 以及保存/校验/模拟/发布/停用/版本列表的服务调用;http.js 补 get/put 导出。
  • WorkflowCanvas 关闭 LogicFlow 自带 history,撤销/重做改由草稿级快照栈统一负责。
  • 测试 tests/unit/workflow-domain.spec.js 从 0 建到 48 个用例。
  • 随后《FMS审批流程交互重构设计.md》被整体重写为《FMS审批流程设置器交互设计》(784→258 行), 明确作废"双编辑器"方案:流程树是唯一主编辑入口,并行/服务节点等拓扑只读保护、不用画布兜底。 上面这轮里 WorkflowModeTabs 的四页签、画布入口、WorkflowStepEditor 的"只认单链路"都要在二阶段改掉; 领域契约、属性抽屉、选择器、条件构造器、api 边界则保留。

二阶段:阶段 0 + 阶段 1(树图适配与保护,已完成)

  • 阶段 0 锁定了网关/分支汇合契约(写进 domain.js "流程树投影"段注释):一个条件块 = 一个 exclusive_gateway; 出边按 b_priority 升序判断;恰有一条 condition: null 的「其他情况」且固定最后; 各分支在"最近公共后继"汇合作为 next,无公共后继则 next 为 null;分支优先级投影内连续唯一。
  • 修掉上一轮遗留的两个真实缺陷:① b_priority 曾用全局序号,改为按来源节点归一化 1..n (normalizeEdgePriorities / outgoingEdgesOf);② 网关校验只查"至少一条默认出口", 现在查唯一性、≥2 条分支、普通连线不得带条件、优先级重复提示。
  • 新增 workflowDraftToTree / workflowTreeToDraft / treeSignature / TREE_NODE_TYPES。 投影不可表达时返回 {ok:false, reason}(并行网关、服务节点、环、缺/重复默认出口、交叉边、不可达节点)。
  • 踩过的坑:一开始给普通节点加了"必须只有一条入线",结果"分支后公共审批"(汇合点 3 条入线)被误判成不可表达; 文档 §5.2.6 只约束出边。入度不限制后,环必须单独用 findCycle 拦,否则构树递归不终止。
  • 测试 48 → 79 个(新增树投影/编译往返/不支持拓扑 fixtures/校验扩展/优先级归一化); pnpm 层面:npx oxlint 0 warning、vite build --outDir dist-verify 通过。
  • 下一步是阶段 2(递归流程树 UI:WorkflowTreeEditor/WorkflowTreeNode/WorkflowBranchGroup/WorkflowNodeInsert, 移除"只能编辑单链路"与"切换到高级画布"),以及 §5.3 的分支图操作(插入/重排/删除/复制条件块)尚未实现。

全部回滚(用户要求:恢复到改动前的代码)

用户决定不做这两轮重构,要求把 workflow 相关代码恢复到最初状态。已全部还原并验证:

  • 能用 git 恢复的:fms-vue/src/services/http.js(去掉我加的 get/put)、 fms-vue/src/views/system/workflow/index.vue —— 两个文件都是已跟踪文件,git restore 回到 HEAD。
  • git 救不回来的(未跟踪文件,只能按上下文重写): design.vue、designer/{constants.js,domain.js,api.js,index.js,WorkflowCanvas.vue,WorkflowDesigner.vue, WorkflowToolbar.vue,WorkflowPropertyPanel.vue},以及 sql/fms_workflow_mock.sql 里我改的 3 处 (连线条件改回单叶子 AST 形状 + 注释)。还原后行数与原始完全一致(domain.js 369、constants.js 173、 WorkflowPropertyPanel.vue 435、design.vue 61 …),只有 WorkflowToolbar.vue 差 2 行 —— 当初只读到它的前 60 行, 末尾样式块是按上下文重建的。
  • 删除的:我新增的 10 个组件(ActorSelector/BasicPanel/ConditionBuilder/CreateDialog/ModeTabs/ PropertyDrawer/SimulationPanel/StepCard/StepEditor/StepInsert)与 tests/unit/workflow-domain.spec.js。
  • 没动过的(修改时间早于本次会话,保持原样):designer/nodes.js、designer/WorkflowNodePanel.vue、 designer/WorkflowValidationPanel.vue。
  • 验证:oxlint src/views/system/workflow 0 warning;vite build --outDir dist-verify 通过; git status 里我改过的文件已不再显示为 modified。
  • 回滚前的完整实现已备份到 D:\workspace\code\fms-workflow-refactor-backup-20260923\(仓库外,25 个文件), 需要时可取回;放在仓库外是为了不污染 git status(.workbuddy-ai 未被 gitignore)。
  • 教训:这个仓库里 workflow 相关文件大多未进 git,改动前必须先备份;git restore 对未跟踪文件无效, 连 IDE 本地历史和悬空 git 对象里都没有副本。

回滚后又补的两件事

  1. workflow/index.vue 的新增/设计按钮:git restore 时它被退到了 HEAD 的 18 行空壳, 而工作区那版(76 行,含工具条「新增」+ 表格「设计」行操作 + 「批量删除」占位)是未提交改动, 被一并冲掉了。已按原内容写回 76 行版本。 → 记进 MEMORY:这个文件虽然被跟踪,但工作区版本比 HEAD 新,别直接 git restore。
  2. 画布「一键整理」(dagre 自动布局):见 MEMORY.md 的同名小节。装了 @logicflow/layout@2.1.5, 改了 WorkflowCanvas.vue(注册插件 + autoLayout() + 兜底 dagre.lf)、WorkflowToolbar.vue(按钮)、 WorkflowDesigner.vue(接线 + 反馈提示);新增 tests/unit/workflow-canvas-layout.spec.js(2 个用例,真跑布局)。 验证:oxlint 0 warning、vite build 通过、design 分包 407→500 kB(走深路径导入,elkjs 未进包)。