status: done created: 2026-06-17 complexity: 🔴复杂
当前流程设计器基于 bpmn-js 17.11(标准 BPMN 建模器),交互范式是自由拖拽、palette 拖拽添加节点、手动画线。这种范式对非技术人员不友好,学习成本高。
钉钉/企业微信的审批流程设计器采用纵向自上而下、点击"+"号添加节点、卡片式节点、自动连线的交互范式,更符合审批场景的直觉操作。
前端入口:
forge-admin-ui/src/views/flow/design.vue(3124行)— 流程设计页面,集成 FlowModeler + NodePropertiesPanel + AI面板forge-admin-ui/src/views/flow/model.vue(1350行)— 流程模型管理列表,跳转到 design.vueforge-admin-ui/src/views/flow/todo.vue / done.vue / started.vue / monitor.vue — 流程审批页,使用 ProcessDiagramViewer / InteractiveProcessDiagram 查看流程图前端组件:
forge-admin-ui/src/components/bpmn/FlowModeler.vue(1307行)— BPMN 建模器主组件,封装 bpmn-jsforge-admin-ui/src/components/bpmn/BpmnModeler.vue(620行)— 基础 BPMN 建模器forge-admin-ui/src/components/bpmn/NodePropertiesPanel.vue(2655行)— 节点配置侧边面板forge-admin-ui/src/components/bpmn/CustomRenderer.js(311行)— 自定义 SVG 渲染器forge-admin-ui/src/components/bpmn/ProcessDiagramViewer.vue(754行)— 流程图查看器forge-admin-ui/src/components/bpmn/InteractiveProcessDiagram.vue(666行)— 交互式流程图查看器forge-admin-ui/src/components/bpmn/flowable-moddle.json(234行)— Flowable BPMN 扩展属性定义forge-admin-ui/src/components/bpmn/UserSelectModal.vue(317行)— 用户选择弹窗forge-admin-ui/src/components/bpmn/AutoLayout.js / CanvasBackground.js / Minimap.vue / QuickActionRing.vue / ShortcutsBar.vue — 辅助组件前端 API:
forge-admin-ui/src/api/flow.js(564行)— 流程相关 API,与后端交互的统一入口前端依赖:
forge-admin-ui/package.json:30 — "bpmn-js": "^17.11.1"forge-admin-ui/package.json:31 — "bpmn-js-properties-panel": "^5.23.0"后端(本次不改,仅列出相关模块):
forge/forge-framework/forge-plugin-parent/forge-plugin-flow/ — Flowable 流程引擎插件/api/flow/*,接收和返回 BPMN XML设计器内核(FlowModeler.vue:308-408):
bpmn-js 的 BpmnModeler 实例flowable-moddle.json 作为 moddle 扩展importXML / saveXML 与后端交互selection.changed / element.changed / commandStack.changed 等事件节点配置(NodePropertiesPanel.vue:936-985):
properties reactive 对象包含完整字段:taskType / assignee / assigneeExpr / candidateUsers / candidateGroups / multiInstanceType / completionCondition / passRate / allowApprove 等 30+ 字段extractPropertiesFromElement(1562行)从 BPMN businessObject 读取属性applyPropertiesToElement 将配置写回 BPMN 元素flowable:assigneeType 判断 spel/custom/静态变量;解析 flowable:assignee 提取 ${user_xxx} 用户ID流程查看器(ProcessDiagramViewer.vue / InteractiveProcessDiagram.vue):
getProcessDiagramInfo(processInstanceId) 获取 { bpmnXml, nodeStatuses }diagramBase64 图片 + 节点位置叠加状态指示器design.vue 数据流:
bpmnXml ref(578行)存储 BPMN XML 字符串loadModel(920行)从后端加载 res.data.bpmnXml 赋值handleSaveDraft / handleDeploy 调用 modelerRef.value?.getXML(true) 获取 XML 提交streamFlowGenerate,AI 返回 BPMN XMLflowable:assigneeType 标识 + ${user_xxx} 格式 + 静态变量 + SPEL 表达式四种分支,转换层必须完整复刻bpmn-js / bpmn-js-properties-panel / inherits-browser<bpmndi:BPMNDiagram> 图形信息,否则 Flowable 管理界面无法显示| 规则 | 说明 |
|---|---|
| start 节点不可删除 | 每个流程必须有且仅有一个发起人节点 |
| end 节点不可删除 | 每个流程至少有一个结束节点 |
| 线性链中节点可上下移动 | 分支内节点不可跨分支移动 |
| 删除审批节点自动连接前后 | 保持流程链路完整 |
| 删除分支内节点使分支为空时删除整条分支 | 分支至少保留一个节点 |
| 条件分支至少 2 条 | 删除到 2 条时禁止继续删除 |
| 并行/包容分支至少 2 条 | 同上 |
| 条件分支必须有一条默认分支 | 默认分支对应 BPMN default flow |
| 规则 | 说明 |
|---|---|
| taskType=assignee 时 assignee 必填 | 保存时校验 |
| taskType=candidateUsers 时 candidateUsers 不能为空 | 保存时校验 |
| taskType=candidateGroups 时 candidateGroups 不能为空 | 保存时校验 |
| assignee=custom 时必须选择用户 | ${user_xxx} 格式 |
| assignee=spel 时 assigneeExpr 必填 | SPEL 表达式 |
| multiInstanceType≠none 时 completionCondition 必选 | all/any/ratio |
| completionCondition=ratio 时 passRate 必填 | 1-100 整数 |
| JSON | BPMN |
|---|---|
| multiInstanceType=parallel | <multiInstanceLoopCharacteristics isSequential="false"> |
| multiInstanceType=sequential | <multiInstanceLoopCharacteristics isSequential="true"> |
| completionCondition=all (passRate=100) | <completionCondition>${nrOfCompletedInstances/nrOfInstances == 1}</completionCondition> |
| completionCondition=any (passRate=1) | <completionCondition>${nrOfCompletedInstances >= 1}</completionCondition> |
| completionCondition=ratio (passRate=N) | <completionCondition>${nrOfCompletedInstances/nrOfInstances >= N/100}</completionCondition> |
| 规则 | 说明 |
|---|---|
| 无法识别的 BPMN 元素 → advanced 节点 | rawXml 保留原始 XML 片段 |
| advanced 节点 JSON→XML 时原样回写 rawXml | 保证无损往返 |
| 边界事件(BoundaryEvent)→ 附加到父节点的 advanced 信息 | 不单独显示为节点 |
| 子流程内部未识别元素 → advanced 兜底 | 子流程本身正常映射 |
| XML→JSON→XML 往返语义等价 | 节点数量、类型、属性一致,坐标可不同 |
本次改造不涉及数据库变更,后端 Flowable 接口和数据格式完全不变。
| 操作 | 表名 | 字段/索引 | 说明 |
|---|---|---|---|
| — | — | — | 无数据库变更 |
本次改造不涉及后端接口变更,前端与后端的交互格式(BPMN XML)不变。
| 操作 | 接口 | 方法 | 变更内容 |
|---|---|---|---|
| — | — | — | 无接口变更 |
前端内部数据流变更(对后端透明):
GET /api/flow/model/{id} 返回 bpmnXml → 前端 BpmnToJsonConverter.convert(xml) → flowJsonPUT /api/flow/model 提交 bpmnXml ← 前端 JsonToBpmnConverter.convert(flowJson) ← flowJsonGET /api/flow/task/diagram-info/{processInstanceId} 返回 bpmnXml + nodeStatuses → 前端转换 + 状态叠加forge-admin-ui/src/components/flow-designer/
├── DingFlowDesigner.vue # 设计器主组件
├── canvas/
│ ├── FlowCanvas.vue # 画布容器(缩放/平移/快捷键)
│ ├── NodeCard.vue # 通用节点卡片(HTML渲染)
│ ├── NodeAdder.vue # "+"号添加器
│ └── ConnectorLayer.vue # SVG 连线覆盖层
├── nodes/
│ ├── StartNode.vue # 发起人节点
│ ├── ApproverNode.vue # 审批人节点
│ ├── CarbonCopyNode.vue # 抄送人节点
│ ├── ConditionNode.vue # 条件分支节点
│ ├── ParallelNode.vue # 并行分支节点
│ ├── InclusiveNode.vue # 包容分支节点
│ ├── ServiceNode.vue # 服务任务节点
│ ├── ScriptNode.vue # 脚本任务节点
│ ├── SubProcessNode.vue # 子流程节点
│ ├── CallActivityNode.vue # 调用活动节点
│ ├── EndNode.vue # 结束节点
│ └── AdvancedNode.vue # 高级节点兜底
├── panel/
│ ├── NodeConfigDrawer.vue # 右侧配置抽屉容器
│ ├── ApproverConfig.vue # 审批人配置
│ ├── ConditionConfig.vue # 条件分支配置
│ ├── MultiInstanceConfig.vue # 会签配置
│ ├── ListenerConfig.vue # 监听器配置
│ ├── FormPermissionConfig.vue # 表单权限配置
│ └── ServiceConfig.vue # 服务/脚本/子流程配置
├── viewer/
│ ├── DingFlowViewer.vue # 钉钉样式查看器
│ └── NodeStatusBadge.vue # 节点状态徽章
├── converter/
│ ├── BpmnToJsonConverter.js # BPMN XML → JSON
│ ├── JsonToBpmnConverter.js # JSON → BPMN XML
│ ├── AutoLayout.js # 图形坐标自动布局
│ └── flowable-moddle.json # Flowable 扩展定义(迁移自 bpmn/)
└── composables/
├── useFlowTree.js # 节点树操作(增删改查/移动)
├── useFlowHistory.js # 撤销/重做
└── useFlowZoom.js # 缩放/平移
| 文件 | 原因 |
|---|---|
components/bpmn/FlowModeler.vue |
被 DingFlowDesigner 替代 |
components/bpmn/BpmnModeler.vue |
被 DingFlowDesigner 替代 |
components/bpmn/CustomRenderer.js |
不再需要 bpmn-js 自定义渲染 |
components/bpmn/CanvasBackground.js |
钉钉样式不需要画布背景 |
components/bpmn/AutoLayout.js |
改用 converter/AutoLayout.js |
components/bpmn/NodePropertiesPanel.vue |
配置逻辑迁移到 panel/ |
components/bpmn/Minimap.vue |
钉钉样式不需要小地图 |
components/bpmn/QuickActionRing.vue |
改用 NodeAdder |
components/bpmn/ShortcutsBar.vue |
钉钉样式不需要快捷操作栏 |
components/bpmn/ProcessDiagramViewer.vue |
被 DingFlowViewer 替代 |
components/bpmn/InteractiveProcessDiagram.vue |
被 DingFlowViewer 替代 |
components/bpmn/flowable-moddle.json |
迁移到 converter/ |
| 文件 | 说明 |
|---|---|
components/bpmn/UserSelectModal.vue |
用户选择弹窗,配置抽屉复用 |
components/flow/FlowTimeline.vue |
流程时间轴,不变 |
components/flow/FlowStats.vue / FlowModelStats.vue |
流程统计,不变 |
components/flow/SignaturePad.vue |
手写签名,不变 |
| 文件 | 改动内容 |
|---|---|
views/flow/design.vue |
替换 FlowModeler→DingFlowDesigner,替换 NodePropertiesPanel→NodeConfigDrawer,bpmnXml→flowJson,加载/保存/AI 逻辑适配 |
views/flow/todo.vue |
替换 ProcessDiagramViewer→DingFlowViewer |
views/flow/done.vue |
替换 ProcessDiagramViewer→DingFlowViewer |
views/flow/started.vue |
替换 ProcessDiagramViewer→DingFlowViewer |
views/flow/monitor.vue |
替换 ProcessDiagramViewer→DingFlowViewer |
package.json |
移除 bpmn-js / bpmn-js-properties-panel / inherits-browser 依赖 |
⚠️ 本次改造不涉及资金/状态流转/权限变更,但涉及流程定义数据格式转换,需确保转换无损。
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| BPMN→JSON→XML 往返不等价 | 已有流程模型编辑后部署可能丢失配置 | 转换层完整复刻 NodePropertiesPanel 的读写逻辑;编写往返测试用例;advanced 节点 rawXml 兜底 |
| UserTask 属性映射遗漏 | 审批人/会签配置丢失 | 逐字段对照 flowable-moddle.json 的 24 个属性,确保双向转换完整覆盖 |
| 图形坐标生成错误 | Flowable 管理界面流程图显示异常 | 自动布局算法生成标准 BPMNDiagram;保存后用 Flowable 管理界面验证 |
| 分支汇合点识别错误 | 分支流程结构错乱 | 分支链跟踪算法 + 多入节点检测;复杂分支场景测试用例 |
| 移除 bpmn-js 后其他模块引用 | 编译错误 | 全局搜索 bpmn-js 引用,确认仅在 bpmn/ 目录下使用 |
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| 已有复杂 BPMN 模型(循环/跳转/多入节点)无法转为树形 JSON | 加载到设计器后结构错乱 | advanced 节点兜底,保留 rawXml;加载时检测复杂结构并提示用户 |
| AI 生成的 BPMN XML 格式不规范 | XML→JSON 转换失败 | 转换失败时保留原始 XML 展示在 AI 面板,提示用户手动修正 |
| 子流程内部复杂结构 | 子流程编辑后内部丢失 | 子流程整体映射为 subProcess 节点,内部未识别元素走 advanced 兜底 |
决策:采用 nodes + edges 有向图结构,而非纯树形结构。
原因:
节点结构:
{
id: 'node_1',
nodeType: 'approver', // start|approver|carbonCopy|condition|parallel|inclusive|service|script|subProcess|callActivity|end|advanced
name: '部门经理审批',
bpmnElementId: 'Task_1',
bpmnElementType: 'bpmn:UserTask',
rawXml: null, // advanced 节点兜底
config: { /* 各节点类型独有配置 */ }
}
连线结构:
{
id: 'edge_1',
source: 'node_1',
target: 'node_2',
bpmnElementId: 'Flow_1',
conditionType: 'expression', // 仅排他/包容网关出线
condition: '${days > 3}',
isDefault: false,
branchId: 'b1' // 分支标识,布局用
}
决策:节点用 HTML div 卡片,连线用 SVG path 覆盖层。
原因:
架构:
FlowCanvas.vue (position: relative, overflow: hidden)
├─ transform 层 (scale + translate)
│ ├─ HTML 节点层 (absolute 定位,坐标来自布局算法)
│ └─ SVG 连线层 (absolute, pointer-events: none,贝塞尔曲线)
└─ 工具栏覆盖层 (absolute, 不受 transform 影响)
| 钉钉 nodeType | BPMN elementType | 说明 |
|---|---|---|
start |
bpmn:StartEvent |
发起人节点 |
approver |
bpmn:UserTask |
审批人节点 |
carbonCopy |
bpmn:ServiceTask + flowable:type=cc |
抄送人节点 |
condition |
bpmn:ExclusiveGateway |
条件分支 |
parallel |
bpmn:ParallelGateway |
并行分支 |
inclusive |
bpmn:InclusiveGateway |
包容分支 |
service |
bpmn:ServiceTask |
服务任务 |
script |
bpmn:ScriptTask |
脚本任务 |
subProcess |
bpmn:SubProcess |
子流程 |
callActivity |
bpmn:CallActivity |
调用活动 |
end |
bpmn:EndEvent |
结束节点 |
advanced |
任意 | 兜底:保留 rawXml |
决策:将 NodePropertiesPanel.vue(2655行)按 Tab 拆分为独立组件,零功能丢失。
迁移映射:
| 现有 properties 字段 | 迁移到 | 组件 |
|---|---|---|
| taskType / assignee / assigneeExpr / candidateUsers / candidateGroups / assigneeUserName / candidateUserNames / candidateGroupNames | 基本信息 Tab | ApproverConfig.vue |
| multiInstanceType / completionCondition / passRate | 会签配置 Tab | MultiInstanceConfig.vue |
| allowApprove / allowReject / allowDelegate / allowReturn / allowTerminate / requireSignature / requireComment | 操作权限 Tab | ApproverConfig.vue |
| formType / formKey / formJson / formUrl + 字段权限 | 表单权限 Tab | FormPermissionConfig.vue |
| taskListeners / executionListeners | 监听器 Tab | ListenerConfig.vue |
| priority / dueDate | 基本信息 Tab | ApproverConfig.vue |
| implementationType / implementation / async | 服务配置 | ServiceConfig.vue |
| script / scriptFormat | 脚本配置 | ServiceConfig.vue |
| hasCondition / conditionType / condition / isDefault | 条件配置 | ConditionConfig.vue |
| initiator | 发起人配置 | ApproverConfig.vue |
| endType | 结束配置 | ApproverConfig.vue |
UserTask 属性提取(复刻 NodePropertiesPanel.vue:1562-1640):
flowable:assigneeType:
'spel' → taskType='assignee', assignee='spel', assigneeExpr=值'${user_xxx}' → taskType='assignee', assignee='custom''${initiator}' / '${initiatorLeader}' / '${deptManager}' / '${hr}' → taskType='assignee', assignee=原值flowable:candidateUsers → taskType='candidateUsers',逗号分隔转数组flowable:candidateGroups → taskType='candidateGroups',逗号分隔转数组<multiInstanceLoopCharacteristics>:
isSequential=true → multiInstanceType='sequential'isSequential=false → multiInstanceType='parallel'completionCondition → 解析 passRate:
== 1 → all (100%)>= 1 → any (1人)>= 0.N → ratio (N%)<extensionElements> 下的 flowable:taskListener / flowable:executionListenerflowable:formKey / flowable:formJson / flowable:formUrlflowable:allowApprove 等 6 个操作权限布尔值网关分支跟踪算法:
1. 找到网关的所有出边 sequenceFlow
2. 每条出边生成一个 branch:
- conditionExpression → branches[].condition
- flowable:default → isDefault=true
3. 跟踪每条分支的后续节点链,直到遇到汇合点(多条分支汇聚到同一节点)
4. 汇合点标记为 mergeNode
function traceBranch(headNodeId, allEdges):
chain = [headNodeId]
current = headNodeId
loop:
nextEdges = edges.filter(e => e.source == current)
if nextEdges.length != 1: break
next = nextEdges[0].target
if hasMultipleInputs(next): break
chain.push(next)
current = next
return chain
UserTask 属性写入:
flowable:assignee='${user_xxx}'flowable:assignee=assigneeExpr, flowable:assigneeType='spel'flowable:candidateUsers='id1,id2'flowable:candidateGroups='roleId1,roleId2'<multiInstanceLoopCharacteristics isSequential="false"> + completionCondition 按 passRate 生成<extensionElements><flowable:taskListener .../></extensionElements>flowable:allowApprove="true" 属性图形坐标自动布局:
布局参数:
NODE_WIDTH = 180, NODE_HEIGHT = 70
V_GAP = 60, H_GAP = 40, BRANCH_WIDTH = 220
算法:
1. 从 start 节点开始,y=0
2. 线性链:y 递增 NODE_HEIGHT + V_GAP,x 居中
3. 遇到分支节点:计算各分支宽度(递归)→ 分支横向并排 → 每条分支内部递归布局
4. 汇合节点:x 回到中线
5. 连线坐标:source 底边中点 → target 顶边中点
6. 生成 <BPMNDiagram> + <BPMNShape> + <BPMNEdge>
现有数据流:
后端 → bpmnXml(字符串) → FlowModeler → bpmn-js 内部模型 → 保存时 getXML() → bpmnXml → 后端
新数据流:
后端 → bpmnXml(字符串) → BpmnToJsonConverter → flowJson(JSON) → DingFlowDesigner
↓
保存时 JsonToBpmnConverter → bpmnXml → 后端
关键改动:
bpmnXml ref → flowJson refloadModel:bpmnXml = res.data.bpmnXml → flowJson = BpmnToJsonConverter.convert(res.data.bpmnXml)handleSaveDraft:modelerRef.getXML() → JsonToBpmnConverter.convert(flowJson)BpmnToJsonConverter.convert(aiXml) → flowJsonDingFlowViewer 替代 ProcessDiagramViewer + InteractiveProcessDiagram:
getProcessDiagramInfo(processInstanceId) 获取 { bpmnXml, nodeStatuses }BpmnToJsonConverter.convert(bpmnXml) → flowJson节点状态映射:
| 节点状态 | 图标 | 卡片边框 | 连线颜色 | 动画 |
|---|---|---|---|---|
| completed | check-circle | 绿色 #10b981 |
绿色实线 | 无 |
| running | sync | 蓝色 #3b82f6 |
— | 脉冲发光 |
| pending | circle-outline | 灰色 #cbd5e1 |
灰色虚线 | 无 |
| rejected | cancel | 红色 #ef4444 |
红色虚线 | 无 |
| skipped | dash | 灰色 #94a3b8 |
灰色虚线 | 无 |
| Task | 状态 | 实际改动文件 | 备注 |
|---|---|---|---|
| Task 0 目录骨架与依赖确认 | done (2026-06-17) | forge-admin-ui/src/components/flow-designer/{index.js, canvas/, nodes/, panel/, viewer/, converter/, composables/, constants/, utils/} 共 9 个占位 index.js |
不新增依赖;旧 components/bpmn/ 不动 |
| Task 1 XML 解析工具与节点类型识别 | done (2026-06-17) | converter/xml-utils.js、constants/node-types.js、3 个 tests 文件、vitest.config.js、package.json(+vitest 2.1.9 / jsdom 25 / @vitest/ui) |
TDD:3 spec / 39 用例通过;不依赖 bpmn-js / moddle |
| Task 2 BPMN→JSON 转换器(基础节点) | done (2026-06-17) | converter/bpmn-to-json.js + 4 个 spec |
16 用例通过;advanced 节点 rawXml 兜底 |
| Task 3 UserTask 完整属性提取 | done (2026-06-17) | converter/user-task-parser.js + 4 个 spec |
27 用例通过;assignee / multiInstance / listener / 7 权限 / form 全覆盖 |
| Task 4 网关分支与汇合识别 | done (2026-06-17) | converter/branch-parser.js + spec |
7 用例通过;branchId 单调分配 + default 标记 + mergeNode |
| Task 5 JSON→BPMN + 自动布局 | done (2026-06-17) | converter/json-to-bpmn.js + user-task-writer.js + layout-algorithm.js + completion-condition.js + xml-escape.js + 4 个 spec |
25 用例通过(含 4 用例 roundtrip);BPMNPlane.bpmnElement 强制指向 process(修正 pitfalls #8) |
| Task 6 端到端往返测试 | done* (2026-06-17) | converter/__tests__/roundtrip.spec.js |
4 用例:线性 / 排他分支 / 会签 ratio / 三种 completionCondition;fixture 文件待 Phase 6 集成测试需要时再补 |
| Task 7 useFlowDesigner Composable | done (2026-06-17) | composables/useFlowDesigner.js + flow-designer-helpers.js + utils/id-generator.js + constants/default-configs.js + 3 个 spec |
29 用例通过;CRUD + 查询 + 整体加载;deletePlain 笛卡儿重连保留入边语义;deleteGateway 递归删除分支链 |
| Task 8 useFlowHistory | done (2026-06-17) | composables/useFlowHistory.js + spec |
13 用例通过;JSON 快照命令栈 + maxStack + Ctrl/Cmd+Z/Y/Shift+Z 键盘绑定 |
| Task 9 FlowCanvas + viewport | done (2026-06-17) | composables/useCanvasViewport.js + canvas/FlowCanvas.vue + 2 个 spec |
18 用例通过;锚点缩放公式 + 4 种平移触发 + transform 容器;鼠标交互留 Phase 9 端到端 |
| Task 10 画布布局引擎 | done (2026-06-17) | canvas/layout-engine.js + spec |
8 用例通过;复用 converter/layout-algorithm + 边类型识别 + canvasBounds |
| Task 11 SVG 连线层 | done (2026-06-17) | utils/path-builder.js + canvas/EdgePath.vue + canvas/EdgeLayer.vue + 3 spec |
24 用例通过;4 种 path 类型 + 5 种状态箭头 + "默认" 标签 |
| Task 12 节点添加菜单 | done (2026-06-17) | constants/node-menu.js + canvas/AddNodeButton.vue + canvas/AddNodePopover.vue + spec |
7 用例通过;3 分组 9 节点类型;click outside 自包含实现 |
| Task 13-17 Phase 4 节点组件 | done (2026-06-17) | nodes/NodeCard.vue + 11 节点卡片 + canvas/{BranchHeader,MergeNode,NodeContextMenu,NodeRenderer}.vue + utils/approver-summary.js + 3 spec |
51 用例通过;NodeCard 基类复用样式;NodeRenderer 12 种类型调度 + 兜底;approver-summary 覆盖 4 种 assignee 模式 + 多实例 |
| Task 18-25 Phase 5 配置抽屉 | done (2026-06-17) | panel/NodeConfigDrawer.vue + BasicConfig.vue + 11 个节点专属配置 + 5 个子表单 + config-renderer-map.js + spec |
5 用例通过;19 个 Vue 组件;ApproverConfig 拆 5 Tab;ConditionConfig 处理网关出边 |
| Task 26-27 Phase 6 主组件集成 | done (2026-06-17) | flow-designer/DingFlowDesigner.vue + __tests__/ + views/flow/{design,template}.vue 替换 import 与使用 |
8 用例通过;接口 1:1 兼容 FlowModeler;pitfalls #7 防回环 + #8 不再是问题;端到端可见里程碑 ✓ |
| 阶段累计:Phase 0-6 完成 | 31 spec / 275 用例通过 | — | 进入 Phase 7(DingFlowViewer 查看器) |
| Task 28-29 Phase 7 流程查看器 | done (2026-06-17) | viewer/{DingFlowViewer.vue, NodeStatusBadge.vue, NodeDetailPopover.vue} + 2 个 spec |
8 用例通过;接口与 ProcessDiagramViewer 兼容(processInstanceId / compact)+ 直接 bpmnXml 模式;nodeInstanceList → nodeStatusMap 映射 + 节点点击弹出详情 |
| 阶段累计:Phase 0-7 完成 | 33 spec / 283 用例通过 | — | 进入 Phase 8(todo / done / started / monitor 入口替换) |
| Task 30-31 Phase 8 入口替换 | done (2026-06-17) | views/flow/{todo,done,started,monitor}.vue + components/ai-form/AiCrudFlowDetail.vue 5 处 import 改为 DingFlowViewer |
业务模板零修改(仅替换 import 路径,局部变量名 ProcessDiagramViewer 保留);lint 本次变更文件零错误;全量单测 33/283 通过 |
| 阶段累计:Phase 0-8 完成 | 33 spec / 283 用例通过 | — | 进入 Phase 9(移除 bpmn-js + 构建冒烟) |
| Task 32-34 Phase 9 收尾 | done (2026-06-17) | 移除 bpmn-js 等 7 依赖 + 删除 components/bpmn/ 14 文件 + UserSelectModal 迁 common/ + version.vue 直接 bpmn-js → DingFlowViewer + design.vue NodePropertiesPanel 死代码清理 | pnpm build 成功(52.27s,DingFlowDesigner 独立 chunk 47KB/gzip 13.58KB);全量单测 33/283 通过;lint 本次变更零错误 |
| 🎉 变更完成:Phase 0-9 全部 done | 33 spec / 283 用例 / 35 Task | — | 端到端可见 + 构建冒烟 + 依赖清理全部通过 |
待 /review 阶段填写。