Files
workspace/code/fms/FMS审批流程设置器二次重构实施文档.md
T
2026-09-23 16:54:54 +08:00

310 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FMS 审批流程设置器二次重构实施文档
> 本文承接《FMS审批流程交互重构设计.md》,记录现有 FMS 流程设置器已经完成的部分,以及接下来应基于当前代码推进的第二阶段改造。目标交互参考 `D:\workspace\code\test\Workflow-Vue3`,尤其是纵向审批主线、递归条件分支、节点间添加按钮、右侧抽屉和错误定位。
>
> **这是增量重构,不是从零重做。** 先保留已经建立的 FMS 领域草稿、审批规则、条件 AST、校验和 API 边界,再把目前只支持单链路的卡片编辑器扩展为完整的钉钉式流程树。树是编辑视图,FMS 的节点/连线仍是执行配置来源。
## 1. 本阶段要解决的问题
目前已经具备可用的 FMS 流程领域模型和一版编辑器骨架,但用户体验仍是“线性步骤卡片 + 另一个 LogicFlow 画布”。二阶段的重点不是继续丰富画布,而是让审批、抄送和条件分支都能在同一棵纵向流程树里配置。
### 1.1 本次交互决策
- **采用钉钉式流程树作为 FMS 审批设置的主交互,不把高级画布作为本次普通管理员的编辑入口。** 这项选择是本次重构的明确目标,不是待 AI 自行比较后再决定的选项。
- 借鉴的是审批配置的操作方式:纵向主线、节点间“+”、条件分支并列展开、分支内递归、属性抽屉、校验问题定位和缩放;不是逐像素仿钉钉,也不是复制 `Workflow-Vue3` 的实现。
- 视觉遵循 FMS 现有主题、控件和组件规范;领域数据仍用 FMS 的节点、连线、审批人规则和条件 AST。
- 这不等于永久禁止高级画布。只有当真实业务流程无法由已支持的流程树表达,且对应拓扑已有后端执行、校验和模拟语义,并通过无损读写验收后,才单独评估是否增加高级编辑器。不得为了“以后可能用到”而维持两个未完成的编辑模式。
完成后,管理员在一个连续页面内即可:
1. 看见开始、审批、抄送、条件分支和结束节点;
2. 在节点之间点“+”选择审批人、抄送人或条件分支;
3. 展开并编辑各条件分支,分支内允许继续添加节点或嵌套分支;
4. 在节点属性抽屉中配置审批人、审批方式和条件;
5. 从错误提示定位到具体节点/分支,校验并保存草稿。
本阶段不改变工作流表结构、实例运行语义、权限和审计规则;也不把参考项目的旧 JSON 结构写入数据库。
## 2. 现状盘点:保留与改造
下表按当前 `fms-vue/src/views/system/workflow` 代码盘点。后续开发应在此基础上修改,避免重复实现已具备的能力。
| 当前文件/能力 | 当前状态 | 二阶段处理 |
| --- | --- | --- |
| `design.vue` | 已有新建向导入口、按流程编码加载草稿、离开未保存确认 | 保留;新建定义仍需服务端持久化接通后才能获得真实版本 ID |
| `designer/domain.js` | 已有 schemaVersion 2、表行与领域草稿转换、条件 AST、摘要、单链路操作和图校验 | 保留既有转换;增加扁平 FMS 图与递归流程树的双向适配、分支结构操作和 round-trip 测试 |
| `WorkflowDesigner.vue` | 已持有统一领域草稿、撤销/重做、节点/连线属性抽屉、选择器数据和版本/校验状态 | 保留草稿所有权、撤销栈、属性编辑和服务缺失提示;移除编辑器模式状态及画布同步逻辑 |
| `WorkflowModeTabs.vue` | 当前包含“基本信息 / 流程步骤 / 高级画布 / 版本记录”四个页签 | 移除“流程步骤 / 高级画布”二选一;流程树作为唯一主编辑区。基本信息和版本记录改为顶部入口、抽屉或对话框,不挤占流程画布 |
| `WorkflowStepEditor.vue` | 只识别单链路;遇到分支时提示切换画布;只调用线性插入、移动、复制和删除 | 改为递归流程树容器,不得再因条件分支拒绝编辑 |
| `WorkflowStepCard.vue` | 已能显示审批/抄送摘要、标签、错误状态和节点操作 | 保留并按参考项目调整视觉层级;开始/结束作为固定节点,条件分支使用独立分支卡片 |
| `WorkflowStepInsert.vue` | 目前直接显示“添加审批人”和“添加抄送”两个按钮 | 改为中心圆形“+”按钮,点击弹出“审批人 / 抄送人 / 条件分支”菜单 |
| `WorkflowPropertyDrawer.vue` | 已有节点名称、审批人规则、审批方式、驳回策略、时限、行为和连线条件编辑 | 保留 FMS 字段和控件;根据节点类型展示内容;条件分支优先级、分支删除等放到分支卡片/分支属性区 |
| `WorkflowActorSelector.vue` | 已有 FMS 审批人来源选择能力 | 保留;组织角色、岗位等主数据未接入时继续明确提示,不伪造候选项 |
| `WorkflowConditionBuilder.vue` | 已有结构化 AST、字段/操作符/值控件;空条件可表达默认出口 | 保留作为单分支条件编辑器;补足用户可理解的“其他情况”默认分支体验,并处理嵌套条件编辑能力的限制提示 |
| `WorkflowValidationPanel.vue` | 已能列出错误/警告并按节点定位 | 保留校验逻辑;改成流程画布上的错误计数入口 + 抽屉/弹窗列表,释放横向分支展示空间 |
| `WorkflowCanvas.vue`、`WorkflowNodePanel.vue`、`nodes.js` | 已有 LogicFlow 画布和节点面板,`WorkflowDesigner` 当前会同步图与领域草稿 | 不作为本阶段的主编辑入口;移除页面入口及同步路径。确认无其他引用后再决定是否清理文件/依赖 |
| `designer/api.js` | 已有表读取、字段和用户候选项查询,也定义了保存/校验/模拟/发布服务调用 | 保留当前“服务未接入则明确失败”的保护;不要把 404 当成功。新建、保存、校验、发布需与后端接口逐项验收 |
| `tests/unit/workflow-domain.spec.js` | 已覆盖领域行转换、画布转换、线性操作和发布校验 | 保留原测试;追加流程树、分支、默认出口、分支汇合和不支持拓扑测试 |
### 2.1 现状中的两个实际缺口
- 当前 `WorkflowStepEditor.vue` 的分支保护会把用户导向高级画布;二阶段必须改成在同一个流程树里编辑条件分支。
- 新建向导的确认目前只创建内存中的 `WorkflowDraft`;若后端创建/保存服务尚不可用,界面必须保持“未保存/服务未接入”,不能显示真实保存成功。
## 3. 参考项目如何用在 FMS
### 3.1 优先参考的源码
| 参考文件 | 需要借鉴的内容 |
| --- | --- |
| `D:\workspace\code\test\Workflow-Vue3\src\views\setting.vue` | 顶部流程标题/发布入口、中央流程设置区、缩放控制的页面组织 |
| `D:\workspace\code\test\Workflow-Vue3\src\components\nodeWrap.vue` | 普通节点沿 `childNode` 递归;条件节点展开多个横向分支;支路内继续递归;分支排序和配置错误提示 |
| `D:\workspace\code\test\Workflow-Vue3\src\components\addNode.vue` | 节点之间圆形“+”按钮和审批人/抄送人/条件分支弹出菜单 |
| `D:\workspace\code\test\Workflow-Vue3\src\components\drawer\approverDrawer.vue` | 审批方式与审批人设置按需出现在右侧抽屉 |
| `D:\workspace\code\test\Workflow-Vue3\src\components\drawer\copyerDrawer.vue` | 抄送人独立配置,不混入审批方式 |
| `D:\workspace\code\test\Workflow-Vue3\src\components\drawer\conditionDrawer.vue` | 条件项编辑、优先级变更和业务字段选择 |
| `D:\workspace\code\test\Workflow-Vue3\src\components\dialog\errorDialog.vue` | 发布/校验错误汇总,再定位到具体节点 |
| `D:\workspace\code\test\Workflow-Vue3\src\css\workflow.css` | 纵向连线、条件横向框、节点悬浮边框、背景层和缩放布局的视觉参考 |
参考项目采用递归 UI JSON;FMS 不能原样照搬。FMS 页面可以构造临时的递归树投影,但最终变更必须回写当前 `WorkflowDraft.nodes / edges`,审批人仍进入 `actorRules`,条件仍使用 AST。
### 3.2 样式借鉴边界
借鉴形态和空间关系,不复制实现:
- 用 FMS 自己的 `<Button>`、`<Drawer>`、`<Popover>`、`<Tag>` 和 Lucide 图标;
- 样式优先用现有主题变量,如 `--fms-background`、`--fms-card`、`--fms-border`、`--fms-primary`、`--fms-danger`;
- 不复制参考项目的 Element UI、Ant Design 图标字体、远程图片、私有图标字体或整份 `workflow.css`;
- 节点配色、圆角和阴影遵循 FMS 已有设计语言,只借鉴参考项目的浅灰流程底色、白色节点卡片、清晰连线和悬浮强调。
## 4. 二阶段目标页面
```text
┌─────────────────────────────────────────────────────────────────────┐
│ ← 返回 流程名称 [草稿] 撤销 重做 校验 保存 发布 │
│ 基本信息 版本记录(入口,不切换流程编辑器) │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ● 开始 / 谁可以发起 │
│ │ │
│ (+) │
│ ┌────────────────────┐ │
│ │ 部门负责人审批 │ │
│ │ 审批人:部门负责人 │ │
│ └────────────────────┘ │
│ │ │
│ (+) │
│ ┌──── 条件分支:按优先级匹配 ────┐ │
│ │ 金额 > 10000 │ 其他情况 │ │
│ │ 财务审批 │ 抄送财务 │ │
│ └──────────────┴────────────────┘ │
│ │ │
│ 流程结束 │
│ [−] 100% [+] [适应流程] │
└─────────────────────────────────────────────────────────────────────┘
```
- **一个主编辑视图**:进入流程后直接看到流程树;不再用页签在“线性步骤”和“高级画布”间切换。
- **基本信息/版本记录**:从顶部按钮打开对应抽屉、弹窗或只读详情;不改变当前流程树编辑上下文。
- **校验反馈**:工具栏显示错误/警告计数;点击后打开可关闭的错误列表。点击一项后关闭列表、滚动至对应节点、突出显示并按需打开属性抽屉。
- **属性编辑**:沿用右侧抽屉,节点主体点击后打开;窄屏时抽屉改为全屏或接近全屏。
- **缩放控制**:固定在流程舞台右下角或右上角,不遮住分支卡片;建议按参考项目 50%–300%、每次 10% 缩放,另有“适应流程”。
## 5. 流程树与 FMS 领域草稿的适配
### 5.1 内存树形结构
只在流程编辑视图中使用下列概念结构,不直接当持久化契约:
```ts
type FlowItem =
| { kind: 'step'; nodeKey: string; next: FlowItem | null }
| {
kind: 'branch';
gatewayKey: string;
branches: Array<{
edgeKey: string;
label: string;
priority: number;
condition: ConditionAst | null;
child: FlowItem | null;
}>;
next: FlowItem | null;
};
```
`step` 映射 FMS 的开始、人工审批、抄送和结束节点;`branch` 映射 `exclusive_gateway` 与它的出边。`child` 是该分支专属路径,`next` 是各分支汇合后的公共后续。
### 5.2 适配约束
1. 新增 `workflowDraftToTree(draft)` 和 `workflowTreeToDraft(tree, baseDraft)` 一类的纯函数,集中处理转换;Vue 组件只发操作意图,不自己拼 `edges`。
2. 每个条件块对应一个 `exclusive_gateway`;每个分支对应一条网关出边。条件 AST 放在边上,边优先级稳定地表达匹配顺序。
3. 一个条件块必须有且仅有一个 `condition: null` 的“其他情况”边;它在 UI 中固定为最后一项,不能被删除、编辑成普通条件或拖到前面。
4. 条件分支最少有一个显式条件和一个默认分支。新增分支时生成空条件并显示错误状态;发布校验必须阻止空条件被误当默认分支。
5. 各分支专属路径的末端连接到公共 `next`。若某分支没有子节点,则它直接连到公共后续节点并保留自身条件。
6. 扩展 `validateWorkflowDomain`:开始、人工审批和抄送节点在本阶段支持的树形流程中必须恰有一条出边;结束节点没有出边;条件网关至少两条出边且恰有一个默认出口;普通连线不得携带条件;分支优先级在树投影中必须连续且唯一,写回时按此顺序生成边的 `b_priority`。
7. 对已有领域图构树时,必须识别唯一开始点、gateway 出边、条件边、默认出口和分支汇合点。遇到并行网关、服务节点、环、交叉边或无法唯一识别汇合的拓扑,返回明确的不支持状态,不显示一个可写的简化树。
8. 树编辑完成必须写回同一份领域草稿,`wf_node`、`wf_edge`、`wf_actor_rule` 及版本 checksum 语义保持不变。不新增 `childNode` 持久化 JSON、卡片顺序表或审批人固定列。
### 5.3 分支图操作规则
- 插入条件块:`A → B` 变为 `A → gateway → case paths → B`;各 case 的出边优先级和 AST 必须同时更新。
- 在某个分支中插入节点:只在该分支专属路径上将 `X → Y` 改为 `X → 新节点 → Y`。
- 在分支框之后添加节点:这是所有分支共用的后续,树的 `next` 指向该节点;不能错误地把它插入某一个分支。
- 调整条件优先级:只交换显式条件顺序,默认分支仍在最后;同步更新边优先级和卡片编号。
- 删除条件块:先展示每个分支及其子节点数量;用户确认后将网关整体移除,并按明确的保留路径策略连接前后节点。不得直接丢弃分支配置。
- 删除分支:如果有子树必须二次确认;剩余分支不足两条时不允许留下无意义 gateway。
## 6. 页面与组件改造清单
### 6.1 `WorkflowDesigner.vue`
- 保留领域草稿、撤销/重做、数据选择器、校验、抽屉编辑、未保存拦截和服务失败提示。
- 移除 `EDITOR_MODES.CANVAS` / `mode` 分支、`canvasRef`、`onGraphChange`、`onDragNode` 和画布文本镜像逻辑。
- `WorkflowValidationPanel` 改为可开关的 Drawer/Modal;错误定位调用流程树暴露的 `focusNode(nodeKey)`,包含 edge 错误时定位 gateway/条件分支。
- 在工具栏增加“流程信息”“版本记录”入口,保留基础信息数据和版本列表逻辑,但不要再由页签卸载/切换主编辑器。
- 结构变更继续通过 `commit(nextDraft)` 入撤销栈;树组件卸载/重建不应清空历史。
### 6.2 流程树组件
建议把当前 `WorkflowStepEditor.vue` 改成 `WorkflowTreeEditor.vue`(或保留文件名但彻底替换内部逻辑),再拆出:
```text
WorkflowTreeEditor.vue 树投影、滚动舞台、快捷定位
WorkflowTreeNode.vue 普通节点递归与节点间插入入口
WorkflowBranchGroup.vue 条件横向分支、优先级、每个分支的子树和公共后续
WorkflowNodeInsert.vue 圆形“+”与审批/抄送/分支菜单
WorkflowTreeNodeCard.vue 开始、审批、抄送、结束摘要卡片
```
可以合并组件以控制复杂度,但“树转换逻辑不能散落在递归组件里”这条边界必须保留。组件操作通过 `emit('operation', payload)` 上报,纯图操作由 `domain.js` 生成 `nextDraft`。
### 6.3 `domain.js` 和常量
- 保留 `rowsToWorkflowDraft`、`draftToSavePayload`、`validateWorkflowDomain`、摘要函数及条件 AST 工具。
- 保留 `inspectLinear` 和线性操作用于迁移测试或单链路快捷逻辑,但它不能再决定“是否允许进入流程树”。
- 新增树投影、结构签名、gateway 分支解析、分支插入/重排/删除/复制操作。
- 扩展错误结构,使错误可包含 `nodeKey`、`edgeKey`/`gatewayKey` 和分支优先级,供 UI 稳定定位。
- 不要为了 UI 顺序变更节点主键;`nodeKey`、`edgeKey` 在本版本内必须稳定。
### 6.4 插入菜单、卡片、属性抽屉
- `WorkflowStepInsert.vue` 改为一个“+”按钮和 `Popover` 菜单,操作项为审批人、抄送人、条件分支。
- `WorkflowStepCard.vue` 可复用摘要计算,但条件块要独立渲染“条件名 + 条件摘要 + 优先级 + 错误态”。
- `WorkflowPropertyDrawer.vue` 继续复用;审批人/抄送人选择仍通过 FMS `WorkflowActorSelector`,条件值仍通过 `WorkflowConditionBuilder`。
- 条件分支的“其他情况”在卡片文案中明确说明,不要求管理员打开抽屉填写一条空 AST。
## 7. 视觉规范:贴近参考项目,同时遵循 FMS
### 7.1 页面和节点外观
- 流程舞台使用 FMS 背景 token 的浅灰层次;画布内容按树的自然高度展开,不再绘制 LogicFlow 网格。
- 普通节点采用白底、有轻阴影、细边框和小圆角卡片;节点类型用小图标/色条区分,不使用参考项目的私有字体图标。
- 节点 hover/selected 使用 `--fms-primary` 边框和轻微光环;错误使用 `--fms-danger`;警告使用 `--fms-warning`。
- 参考项目节点宽约 220px。FMS 摘要更长,初版节点卡片可从 260px 左右起步;分支列设合理最小宽度,不随窄屏无限压缩文字。
- 标题与摘要分层:标题行展示图标、名称、类型和操作入口;正文展示审批人/抄送人、审批方式、时限等摘要,最多 2–3 行后截断。
- 开始/结束节点做轻量端点,不画成普通审批卡片;开始节点可显示发起范围摘要,结束节点固定显示“流程结束”。
### 7.2 连线、分支和按钮
- 单链路使用居中竖向细线;节点间添加按钮落在线上,按钮尺寸和弹出菜单的点击面积满足 FMS 控件规范。
- 条件块外框按参考项目呈横向分支:分支列顶部/底部连接线清楚,分支内流程独立纵向排列,分支后公共节点位于整个条件块下方中线。
- 多分支超出视口时横向滚动舞台;不缩小分支卡片到不可读,也不让浏览器整页出现横向滚动。
- 条件块顶部显示“添加条件”操作;分支头显示名称、优先级、条件摘要、移动操作和错误状态。
- 分支连接线优先用稳定的 CSS 结构/伪元素实现;分支数量动态变化时若 CSS 不可靠,可单独使用 SVG 画连接线,但不能因此恢复通用图画布。
### 7.3 缩放与响应式
- 借鉴 `setting.vue` 的 50%–300% 缩放区间和步进交互,但缩放状态只属于视图,不改变节点/连线语义。
- 缩放容器设置清楚的 `transform-origin`,同时测量内容宽高;不能只缩放 CSS 视觉却留下错误的滚动区域。
- “适应流程”以主流程和分支总宽度为基准;长流程可垂直滚动,宽分支可水平滚动。
- 小屏布局时保留分支的横向结构并让舞台滚动;属性抽屉占满可用宽度;工具栏按钮折入更多菜单。
- 缩放、滚动、弹窗打开/关闭、窗口 resize 后,错误定位仍要把目标卡片滚动到可视区域。
## 8. 分阶段实施和回归
### 阶段 0:基线确认
1. 阅读《FMS审批流程交互重构设计.md》、本文件和《FMS工作流与审批设计.md》;本文件决定二阶段的增量执行顺序。
2. 记录现有单链路草稿样例、审批人规则和条件 AST;执行现有工作流领域测试,确认重构前基线。
3. 确认 `exclusive_gateway` 的运行语义和边优先级;确认条件支路合流是否被流程服务支持。若后端尚未实现,先锁定接口契约,不在前端猜运行规则。
### 阶段 1:树图适配和保护
1. 先实现 FMS 图 → 树投影和树 → FMS 图转换纯函数。
2. 使用固定 fixtures 覆盖:线性流程、两个条件、三条件排序、分支内多个步骤、分支后公共审批、嵌套条件、无默认出口、重复默认出口、并行/环/交叉边。
3. 对不支持的拓扑返回只读保护提示,不允许 UI 提交修改后的扁平草稿。
4. 确认加载→构树→不编辑→编图→保存载荷的节点/边/规则语义一致后,再做页面组件。
### 阶段 2:递归流程树 UI
1. 移除 `WorkflowStepEditor` 的“只能编辑单链路”分支和“切换到高级画布”按钮。
2. 加入递归节点、条件分支组、公共后续和新的“+”菜单。
3. 接入选中状态、属性抽屉、错误标记和校验面板定位。
4. 对插入、删除、复制、移动、重排和撤销/重做补上确认与回归测试。
### 阶段 3:钉钉式样式与页面收口
1. 按本文件第 7 节调整舞台、线条、节点卡片、条件列和缩放工具。
2. 将固定右栏错误面板改为可收起/弹出的校验列表,保证宽分支有足够空间。
3. 基本信息、版本记录保持可访问,但不让其与主编辑器形成“流程步骤/高级画布”模式切换。
4. 完成常规 1440×900、1366×768 和窄屏浏览器的截图/人工走查。
### 阶段 4:清理旧入口与验收
1. 全局搜索 `WorkflowCanvas`、`EDITOR_MODES.CANVAS`、`WorkflowModeTabs` 及 LogicFlow 适配器引用。
2. 先删除页面入口和死掉的状态同步;确认所有引用后再清理组件与依赖,不直接批量删除未知文件。
3. 保存/发布服务缺失时维持明确提示;接服务后验证版本只读、并发、幂等和服务端校验。
4. 执行工作流单测、前端构建和人工交互验收。
## 9. 必测场景
### 领域图和树之间
- `开始 → 审批 → 结束` 往返不改变任何节点/边编码或配置。
- 插入条件后有“条件 A / 其他情况”两条路径;每条路径可添加审批或抄送。
- 条件分支之后添加公共审批节点,两个 case 都能正确汇入该节点。
- 条件路径中继续插入第二层条件,保存重开后嵌套层级不变。
- 变更条件优先级只更改显式分支次序,默认分支一直在末尾。
- 空条件、缺失字段、重复默认边和无出口节点能被准确报错。
- 遇到不支持的并行、服务、循环或交叉拓扑时,不呈现可覆盖保存的简化树。
### 页面交互
- “+”菜单正确插入三种类型,并将焦点打开到新节点属性配置。
- 点击节点摘要打开对应抽屉;审批和抄送不显示彼此无关的字段。
- 删除有子节点的分支前显示影响范围;取消操作完全不改草稿。
- 校验列表定位到嵌套分支中的节点;缩放和滚动后仍能看到高亮目标。
- 撤销/重做覆盖树结构和节点配置;切换基本信息/版本列表后返回,草稿和滚动体验合理。
- 发布版本只读;服务缺失或发布失败不会显示成功状态。
## 10. 验收命令和完成标准
在 `fms-vue` 目录执行:
```powershell
pnpm exec vitest run tests/unit/workflow-domain.spec.js
pnpm test
pnpm build
```
若改动涉及全局格式或 lint,再补:
```powershell
pnpm lint
pnpm fmt:check
```
完成标准不是“有一个看起来像流程图的页面”,而是管理员不切换编辑模式就能配置完整的审批树;编辑器始终准确维护 FMS 节点/连线草稿;无法安全表达的旧图被保护;界面风格与参考项目接近,但不破坏 FMS 组件和主题体系。
## 11. 不要做的事
- 不要重写或替换 `WorkflowDraft`、版本状态和 `wf_*` 领域表。
- 不要把参考项目的 `nodeConfig.childNode` JSON 当成新的数据库契约。
- 不要在组件模板里直接增删 `draft.edges`;结构修改必须集中在领域操作函数。
- 不要把条件 AST 空值、默认分支和普通“条件未填”混为一谈。
- 不要让一个条件 gateway 出现多个默认出口,也不要通过分支显示顺序隐式代替 `b_priority`。
- 不要在后端服务未接入时伪造保存、模拟、校验或发布成功。
- 不要未检查全项目依赖引用就删除 LogicFlow 包或共享组件。
- 不要复制参考项目的旧 UI 组件、私有图片、远程 icon 或 Element UI 样式;只在 FMS 组件体系下复现交互和视觉结构。