20260923165454

This commit is contained in:
oneao committed 2026-09-23 16:54:54 +08:00
1 parent 0abe3706c8
commit e6935b8fa4
173 files changed
+14975 -2295

No files matched your search

@@ -0,0 +1,91 @@
# 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 未进包)。
+48
View File
@@ -44,6 +44,54 @@
- 模块元数据不由接口下发,前端读本地 schema JSON,改元数据无需重启后端。
- `DbUtils` 是 SQL 唯一出口:标识符加 `[]`,`validateReadOnlySql()` 只允许查询。
## 工作流流程设置器(fms-vue/src/views/system/workflow)
- **代码现状 = 原始版本(2026-09-23 曾被重构,应用户要求已全部回滚)**:
草稿是 `schemaVersion: 1`(`{definitionId, name, nodes, edges}`),编辑器是
`WorkflowDesigner` + `WorkflowCanvas`(LogicFlow) + `WorkflowPropertyPanel` 三件套,
节点坐标挂在 `node.x/y`,条件存单个叶子 `{field, operator, value}`,
写入通道未实现(工具栏只有撤销/缩放/查看草稿 JSON)。
**不要以为仓库里已经有卡片模式/流程树/条件构造器 —— 那些都被回滚了。**
回滚前的完整实现留在 `D:\workspace\code\fms-workflow-refactor-backup-20260923\`(仓库外,含 `http.js` 的 get/put、
`tests/unit/workflow-domain.spec.js`、改过 AST 形状的 mock SQL),需要时可取回。
- **文档是目标,不是现状**:`FMS审批流程设置器交互设计.md`(旧名 `FMS审批流程交互重构设计.md`,
已整体重写为 258 行)要求把设计器改成钉钉式递归流程树,并**明确作废**"线性卡片 + LogicFlow 高级模式"
双编辑器方案(§3.2 不再用画布兜底,并行/服务节点等拓扑只读保护);
`FMS审批流程设置器二次重构实施文档.md` 给出增量执行顺序(§1.1 的交互决策已锁定,不必再问);
`FMS工作流与审批设计.md` 管表结构与运行语义(其 §19 的画布选型是旧方案)。
参考交互项目:`D:\workspace\code\test\Workflow-Vue3`(只借交互,不复制代码/Element UI/私有字体)。
- **这些文件未进 git**:`design.vue`、`designer/`(除 `index.vue` 外全部)、`sql/fms_workflow_mock.sql`
都是未跟踪文件 —— 改它们之前先备份,`git restore` 救不回来(本地历史里也没有)。
- **`workflow/index.vue` 要小心**:它虽然被 git 跟踪,但**工作区版本比 HEAD 新**(新增按钮、表格「设计」行操作
都是未提交改动)。直接 `git restore` 会退回 HEAD 的 18 行空壳,把按钮冲掉 —— 要恢复就用带按钮的 76 行版本。
- 表结构已建好:`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-api/src/main` 目前零工作流代码**:保存/校验/模拟/发布都要走流程服务,接口 404 时必须
明确提示"服务未接入",绝不伪造成功。
- 若将来重新做树形重构,踩过的坑:① `b_priority` 是**同一来源节点内**的判断顺序,不是全表序号;
② 校验只约束**出边**,入边不能锁成 1(分支汇合点天生多条入线);③ 环要单独拦,否则递归不终止;
④ 默认出口(`condition: null`)必须唯一且固定最后。
### 画布「一键整理」(dagre 自动布局,2026-09-23 已落地)
- 依赖 **`@logicflow/layout@2.1.5`**(peer 正好是 `@logicflow/core ^2.2.5`)。注意 dagre **不在**
`@logicflow/extension` 里(那只有一个标注"未完善"的 AutoLayout)。
- 必须**深路径导入** `import { Dagre } from '@logicflow/layout/es/dagre'`:包入口同时导出 `elkLayout`,
从入口引会把 elkjs 打进产物(实测走深路径只 +92 kB,走入口会 +1MB 以上)。包没有 `exports` 字段,深路径可用。
- 注册方式:`new LogicFlow({ plugins: [Dagre] })`,调用 `lf.extension.dagre.layout({...})`。
插件实例由 `installPlugin` 的"非静态插件"分支创建(`Dagre` 只有 `static pluginName` + `render`,没有 `install`)。
- **坑**:插件靠 `ToolOverlay` 的 `componentDidMount` → `triggerToolRender` 调用 `render(lf)` 才拿到
`this.lf`;拿不到时 `layout()` 会**直接抛错**(它的 try/catch 只包住 applyDagreLayout)。
所以 `autoLayout()` 里先兜底 `if (!dagre.lf) dagre.lf = lf`,并用 try/catch + 「坐标是否变化」判断结果
—— 插件失败时只打 console.error,不能假定成功。
- 布局走 `lf.renderRawData()` 整图重渲染:**会丢选中态**,但节点/连线 **id 保留**(`processEdges` 只改路径字段),
所以上层按 nodeKey/edgeKey 回填审批人与条件仍然成立。坐标变化由实例的 `history` 自动记录(deepObserve + debounce)。
- 布局后**必须 `snapshot()`** 把新坐标 emit 给上层,否则草稿里的 x/y 还是旧的。
- 参数:`rankdir: 'TB'`(审批流程纵向)、`align: 'UL'`、`nodesep: 60`、`ranksep: 80`、`isDefaultAnchor: true`(重算连线路径)。
- 测试:`tests/unit/workflow-canvas-layout.spec.js`(jsdom 挂载画布真跑一次布局;需给 `SVGElement.prototype.getBBox` 打桩,
否则 LogicFlow 的 autoWrap 文本测量会挂)。
## 环境坑(本机特有)
- **编译/测试 fms-api 唯一可行命令**(start.cmd 里的 JDK/Maven 路径都是坏的):