按 SDD 规范,每个 Task 执行完成后追加一段记录。 本日志同时承担"自动化测试基线"职责(参见
code-copilot/rules/automated-testing-standard.md)。
forge-admin-ui/src/components/flow-designer/viewer/NodeDetailPopover.vue
480px 宽版面板。forge-admin-ui/src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow-designer/viewer/NodeDetailPopover.vue \
src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js \
src/components/flow-designer/viewer/DingFlowViewer.vue \
src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js
结果:✅ 通过,0 errors。
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run \
src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js \
src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js
结果:✅ 2 passed (2),12 passed (12)。
git diff --check
结果:✅ 通过,无空白或补丁格式问题。
http://127.0.0.1:3000/ 并 HTTP 冒烟 200,服务已停止。| 文件 | 改动 |
|---|---|
forge-admin-ui/src/components/flow/FlowTaskDetailShell.vue |
新增全屏审批详情壳组件:顶部状态栏、左侧详情工作区、右侧审批记录时间线、移动端单列适配 |
forge-admin-ui/src/views/flow/todo.vue |
待办详情去掉 Tab,改为全屏双栏;左侧展示基本信息、流程图折叠区、审批处理区,右侧常驻审批记录 |
forge-admin-ui/src/views/flow/done.vue |
已办详情复用新布局,审批结果、意见、签名分区展示,流程图收进折叠区 |
forge-admin-ui/src/views/flow/started.vue |
我发起的详情复用新布局,撤回操作放入独立警示区,审批记录右侧常驻 |
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow/FlowTaskDetailShell.vue \
src/views/flow/todo.vue \
src/views/flow/done.vue \
src/views/flow/started.vue
结果:✅ 通过,0 errors。
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
结果:✅ ✓ built in 54.66s。
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm dev --host 127.0.0.1 --port 3000
curl -I http://127.0.0.1:3000/
结果:✅ Vite dev server 启动成功,HTTP 返回 200 OK;服务已通过 Ctrl+C 停止。
git diff --check
结果:✅ 通过,无空白或补丁格式问题。
pnpm build 仍有既有非阻断警告:CSS 中 //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。No module named 'playwright',未执行截图级自动化验证。| 文件 | 改动 |
|---|---|
forge-admin-ui/src/components/flow/FlowTaskDetailShell.vue |
右侧审批记录从通用 FlowTimeline 改为专用扁平记录流;弱化渐变、阴影和卡片感,保留节点、结果、处理人、时间、意见、签名核心信息 |
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint src/components/flow/FlowTaskDetailShell.vue
结果:✅ 通过,0 errors。
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
结果:✅ ✓ built in 51.49s。
git diff --check
结果:✅ 通过,无空白或补丁格式问题。
pnpm build 仍有既有非阻断警告:CSS 中 //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。w-80(约 320px),处理人、时间、结果和意见只能窄列堆叠。forge-admin-ui/src/components/flow-designer/viewer/NodeDetailPopover.vueforge-admin-ui/src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.jscode-copilot/changes/dingflow-approver-style-designer/test-spec.mdcode-copilot/changes/dingflow-approver-style-designer/execution-log.md100vw - 32px。NodeDetailPopover.spec.js 覆盖宽版布局、关闭事件和空状态。source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow-designer/viewer/NodeDetailPopover.vue src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js src/components/flow-designer/viewer/DingFlowViewer.vue src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js
结果:✅ 通过,0 errors。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js
结果:✅ 2 个测试文件 / 12 个用例通过。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer
结果:✅ 34 个测试文件 / 299 个用例通过。
git diff --check
结果:✅ 通过,无空白错误。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
结果:✅ 构建通过,✓ built in 1m 1s。
已知非阻断警告:
//padding 注释触发 esbuild js-comment-in-css warning。src/store/index.js 同时动态/静态导入导致 Vite chunk warning。source ~/.nvm/nvm.sh && nvm use v20.19.0 && pnpm dev --host 127.0.0.1
结果:✅ Vite dev server 启动成功,地址 http://127.0.0.1:3000/。
curl -I http://127.0.0.1:3000/
结果:✅ HTTP 200。
已停止本轮启动的 Vite dev server(exec session 63789)。
playwright、Node playwright / @playwright/test / puppeteer 包,本轮不引入新依赖;已用组件测试、构建和 HTTP 冒烟覆盖代码层回归。readonly 模式时,FlowCanvas 禁用了滚轮、拖拽平移和缩放按钮;流程较长或分支较宽时,用户无法把图看全。forge-admin-ui/src/components/flow-designer/canvas/FlowCanvas.vueforge-admin-ui/src/components/flow-designer/canvas/layout-engine.jsforge-admin-ui/src/components/flow-designer/canvas/__tests__/FlowCanvas.spec.jsforge-admin-ui/src/components/flow-designer/nodes/NodeCard.vueforge-admin-ui/src/components/flow-designer/nodes/__tests__/node-cards.spec.jsforge-admin-ui/src/components/flow-designer/viewer/DingFlowViewer.vueforge-admin-ui/src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.jscode-copilot/changes/dingflow-approver-style-designer/test-spec.mdcode-copilot/changes/dingflow-approver-style-designer/execution-log.mdFlowCanvas 新增 allowNavigation:
readonly 仍表示不可编辑节点。readonly + allowNavigation 允许滚轮移动、拖拽平移和工具栏缩放。DingFlowViewer:
ref="canvasRef" 接入画布。canvasBounds 自动调用 fitToScreen,让长流程优先适配可视区。allow-navigation,用户仍可手动缩放、平移查看细节。NodeCard:
layout-engine:
NODE_HEIGHT 同步调整为 104,保持卡片、布局和连线计算一致。FlowCanvas 覆盖 readonly + allowNavigation 下缩放按钮可用。NodeCard 覆盖状态徽章进入独立元信息区。DingFlowViewer 覆盖只读查看器缩放按钮可用。source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow-designer/canvas/FlowCanvas.vue src/components/flow-designer/canvas/layout-engine.js src/components/flow-designer/canvas/__tests__/FlowCanvas.spec.js src/components/flow-designer/nodes/NodeCard.vue src/components/flow-designer/nodes/__tests__/node-cards.spec.js src/components/flow-designer/viewer/DingFlowViewer.vue src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js
结果:✅ 通过,0 errors。
过程记录:首次执行时 NodeCard.vue 有 1 个 UnoCSS 类顺序 warning,执行 eslint --fix 后复跑通过。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer/canvas/__tests__/FlowCanvas.spec.js src/components/flow-designer/nodes/__tests__/node-cards.spec.js src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js
结果:✅ 3 个测试文件 / 34 个用例通过。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer
结果:✅ 33 个测试文件 / 296 个用例通过。
git diff --check
结果:✅ 通过,无空白错误。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
结果:✅ 构建通过,✓ built in 1m 3s。
已知非阻断警告:
//padding 注释触发 esbuild js-comment-in-css warning。src/store/index.js 同时动态/静态导入导致 Vite chunk warning。source ~/.nvm/nvm.sh && nvm use v20.19.0 && pnpm dev --host 127.0.0.1
结果:✅ Vite dev server 启动成功,地址 http://127.0.0.1:3000/。
curl -I http://127.0.0.1:3000/
结果:✅ HTTP 200。
已停止本轮启动的 Vite dev server(exec session 73139)。
playwright、Node playwright / @playwright/test / puppeteer 包,本轮不引入新依赖;已用组件测试、构建和 HTTP 冒烟覆盖代码层回归。DingFlowViewer,但局部组件名仍叫 ProcessDiagramViewer,排查时容易误判为旧组件还在使用。DingFlowViewer 只读取 nodeInstanceList,而后端 GET /api/flow/task/diagram-info/{processInstanceId} 返回的是 ProcessDiagramInfo.nodes。running/completed/terminated,节点状态也使用小写 running/completed/pending;查看器原先只按部分旧字段映射,运行态节点状态高亮可能丢失。h-full,嵌在折叠面板、弹窗或低代码详情时容易被压得过矮。forge-admin-ui/src/components/flow-designer/viewer/DingFlowViewer.vueforge-admin-ui/src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.jsforge-admin-ui/src/views/flow/todo.vueforge-admin-ui/src/views/flow/done.vueforge-admin-ui/src/views/flow/started.vueforge-admin-ui/src/views/flow/monitor.vueforge-admin-ui/src/components/ai-form/AiCrudFlowDetail.vuecode-copilot/changes/dingflow-approver-style-designer/test-spec.mdcode-copilot/changes/dingflow-approver-style-designer/execution-log.mdDingFlowViewer 新增运行态数据归一化:
nodes、nodeInstanceList、nodeList、activities、nodeStatuses 数组或映射。nodeId/activityId/taskDefinitionKey/bpmnElementId/elementId/id 作为 BPMN 节点 ID。RUNNING、finished、approved、terminated 映射到卡片可识别的状态。assigneeNames/candidateUserNames 拼接为节点详情里的处理人名称。DingFlowViewer 流程整体状态改为支持后端小写 running/completed/terminated。<DingFlowViewer>,不再保留 ProcessDiagramViewer 局部命名。ProcessDiagramInfo.nodes 结构。nodeStatuses 映射结构。processInstanceId 接口返回 nodes 的异步加载路径。source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow-designer/viewer/DingFlowViewer.vue src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js src/views/flow/todo.vue src/views/flow/done.vue src/views/flow/started.vue src/views/flow/monitor.vue src/components/ai-form/AiCrudFlowDetail.vue
结果:✅ 通过,0 errors。
过程记录:首次执行时 todo.vue import 排序触发 perfectionist/sort-imports,调整 import 顺序后复跑通过。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer/viewer/__tests__/DingFlowViewer.spec.js
结果:✅ 1 个测试文件 / 8 个用例通过。
过程记录:首次执行发现空 nodeInstanceList 优先级挡住 nodes/nodeStatuses,修正为“仅非空数组优先”后复跑通过。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer
结果:✅ 33 个测试文件 / 294 个用例通过。
git diff --check
结果:✅ 通过,无空白错误。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
结果:✅ 构建通过,✓ built in 1m 41s。
已知非阻断警告:
//padding 注释触发 esbuild js-comment-in-css warning。src/store/index.js 同时动态/静态导入导致 Vite chunk warning。source ~/.nvm/nvm.sh && nvm use v20.19.0 && pnpm dev --host 127.0.0.1
结果:✅ Vite dev server 启动成功,地址 http://127.0.0.1:3000/。
curl -I http://127.0.0.1:3000/
结果:✅ HTTP 200。
已停止本轮启动的 Vite dev server(exec session 69760)。
playwright、Node playwright / @playwright/test / puppeteer 包,本轮不引入新依赖;已用组件测试、构建和 HTTP 冒烟覆盖代码层回归。forge-admin-ui/src/components/flow-designer/panel/ApproverAssigneeForm.vueforge-admin-ui/src/components/flow-designer/panel/ListenerConfig.vuecode-copilot/changes/dingflow-approver-style-designer/test-spec.mdcode-copilot/changes/dingflow-approver-style-designer/execution-log.mdUserSelectPicker,弹窗内可按系统组织架构筛选用户,内部自动生成 ${user_xxx},不再展示“人员表达式”输入框。UserSelectPicker 多选,保存 candidateUsers 与 candidateUserNames。/system/role/page 的角色列表,多选后保存 roleKey 到 candidateGroups,保存角色名到 candidateGroupNames。/api/flow/spelTemplate/list,选择模板后自动维护 spelTemplate 与 assigneeExpr,不再展示手输 SPEL 表达式输入框。source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow-designer/panel/ApproverAssigneeForm.vue src/components/flow-designer/panel/ListenerConfig.vue
结果:✅ 通过,0 errors。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer/__tests__/DingFlowDesigner.spec.js
结果:✅ 1 个测试文件 / 11 个用例通过。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_ENV=development pnpm vitest run src/components/flow-designer
结果:✅ 33 个测试文件 / 291 个用例通过。
已知非阻断警告:DingFlowViewer.spec.js 中仍打印既有 Pinia active instance warning,测试结果通过,本轮未改该链路。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
结果:✅ 构建通过,✓ built in 55.61s。
已知非阻断警告:
//padding 注释触发 esbuild js-comment-in-css warning。src/store/index.js 同时动态/静态导入导致 Vite chunk warning。git diff --check
结果:✅ 通过,无空白错误。
source ~/.nvm/nvm.sh && nvm use v20.19.0 && pnpm dev --host 127.0.0.1
结果:✅ Vite dev server 启动成功,地址 http://127.0.0.1:3000/。
curl -I http://127.0.0.1:3000/
结果:✅ HTTP 200。
浏览器自动化截图未执行:当前环境未安装 Python playwright、Node playwright / @playwright/test / puppeteer 包,且本轮不引入新依赖。已停止本轮启动的 Vite dev server(exec session 20127,工具未暴露进程 PID)。
NodeConfigDrawer.vue
480 调整为 520。ApproverConfig 内嵌。ApproverConfig.vue
审批人设置 / 表单权限 / 审批后操作。节点名称/节点描述、审批人选择和会签配置合并到“审批人设置”。BasicConfig.vue
ApproverAssigneeForm.vue
任务类型 文案调整为 审批类型,默认选项展示为 人工审批。表单 Key,避免与流程级全局表单配置冲突。MultiInstanceConfig.vue
ConditionConfig.vue、EndConfig.vue、ServiceConfig.vue、ScriptConfig.vue、AdvancedConfig.vue
config-hint 风格。panel/index.js
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow-designer/panel/NodeConfigDrawer.vue \
src/components/flow-designer/panel/ApproverConfig.vue \
src/components/flow-designer/panel/ApproverAssigneeForm.vue \
src/components/flow-designer/panel/BasicConfig.vue \
src/components/flow-designer/panel/MultiInstanceConfig.vue \
src/components/flow-designer/panel/ConditionConfig.vue \
src/components/flow-designer/panel/EndConfig.vue \
src/components/flow-designer/panel/ServiceConfig.vue \
src/components/flow-designer/panel/ScriptConfig.vue \
src/components/flow-designer/panel/AdvancedConfig.vue \
src/components/flow-designer/panel/index.js
# → 首次发现 ApproverAssigneeForm 内 ${...} 文案触发 no-template-curly-in-string;改为 DOLLAR 常量后复跑通过
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer/__tests__/DingFlowDesigner.spec.js
# → Test Files 1 passed / Tests 11 passed / Duration 1.88s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer
# → Test Files 33 passed / Tests 291 passed / Duration 5.78s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 46.69s
git diff --check
# → 通过,无输出
DingFlowViewer.spec.js 仍有既有 Pinia active instance 警告,测试结果通过,本轮未触达该问题。pnpm build 仍有既有非阻断警告:CSS //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
CHOKIDAR_USEPOLLING=true pnpm exec vite --host 127.0.0.1 --port 5173
# → listen EPERM: operation not permitted 127.0.0.1:5173
design.vue
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint src/views/flow/design.vue --fix
# → 通过,自动整理模板缩进
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint src/views/flow/design.vue
# → 通过,0 errors
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 44.33s
git diff --check
# → 通过,无输出
pnpm build 仍有既有非阻断警告:CSS //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
CHOKIDAR_USEPOLLING=true pnpm exec vite --host 127.0.0.1 --port 5173
# → listen EPERM: operation not permitted 127.0.0.1:5173
design.vue 顶部的流程属性、表单配置、说明配置区占用画布纵向空间,流程设计区域显得拥挤。design.vue
config-workspace 横向配置区,画布区域直接撑满中间工作区。source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint src/views/flow/design.vue --fix
# → 首次失败:handlePropertiesUpdate 已无引用;删除旧回调后复跑通过
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint src/views/flow/design.vue
# → 通过,0 errors
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 43.47s
git diff --check
# → 通过,无输出
pnpm build 仍有既有非阻断警告:CSS //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。pnpm dev -- --host 127.0.0.1 --port 5173 → EMFILE: too many open files, watch。CHOKIDAR_USEPOLLING=true pnpm exec vite --host 127.0.0.1 --port 5173 → listen EPERM: operation not permitted 127.0.0.1:5173。发起人变量 输入,用户可以改掉 initiator,但后端内置变量、SPEL 模板和审批人下拉里的“发起人”都按固定 initiator 工作。表单 Key / 表单 URL,与流程设计页右侧的流程级全局表单配置重复,容易让用户误以为需要在发起节点再配置一遍。StartConfig.vue
initiator。StartNode.vue
系统自动记录发起人,不再显示变量名或节点表单信息。default-configs.js
formKey/formJson/formUrl。bpmn-to-json.js
config.initiator = 'initiator'。json-to-bpmn.js
flowable:initiator="initiator"。flowable:formKey/formJson/formUrl。DingFlowDesigner.spec.js 覆盖发起节点配置面板不再出现旧输入项。json-to-bpmn.spec.js 覆盖旧 JSON 中的自定义 initiator / start 表单属性不会写出。bpmn-to-json-linear.spec.js 覆盖旧 XML 中的自定义 initiator / start 表单属性会被归一化。node-cards.spec.js 覆盖 StartNode 摘要不显示旧 formKey。source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow-designer/panel/StartConfig.vue \
src/components/flow-designer/nodes/StartNode.vue \
src/components/flow-designer/constants/default-configs.js \
src/components/flow-designer/converter/bpmn-to-json.js \
src/components/flow-designer/converter/json-to-bpmn.js \
src/components/flow-designer/converter/__tests__/json-to-bpmn.spec.js \
src/components/flow-designer/converter/__tests__/bpmn-to-json-linear.spec.js \
src/components/flow-designer/__tests__/DingFlowDesigner.spec.js \
src/components/flow-designer/nodes/__tests__/node-cards.spec.js
# → 通过,0 errors
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run \
src/components/flow-designer/converter/__tests__/json-to-bpmn.spec.js \
src/components/flow-designer/converter/__tests__/bpmn-to-json-linear.spec.js \
src/components/flow-designer/__tests__/DingFlowDesigner.spec.js \
src/components/flow-designer/nodes/__tests__/node-cards.spec.js
# → Test Files 4 passed / Tests 44 passed / Duration 1.88s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer
# → Test Files 33 passed / Tests 291 passed / Duration 5.38s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 55.71s
git diff --check
# → 通过,无输出
DingFlowViewer.spec.js 仍有既有 Pinia active instance 警告,测试结果通过,本轮未触达该问题。pnpm build 仍有既有非阻断警告:CSS //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。分支 b1 → Node_3,直接暴露 branchId 和节点内部 ID,业务用户无法理解。ConditionConfig.vue
分支 1、分支 2 这类顺序化业务文案。nodes prop,把 edge.target 翻译为下游节点名称,展示为 下游节点:分支1审批。该网关共 N 条出边 改为 该网关共 N 条分支。NodeConfigDrawer.vue
nodes prop,仅对网关类配置组件透传 outgoingEdges + nodes。DingFlowDesigner.vue
DingFlowDesigner.spec.js
分支 1、下游节点:分支1审批,且不再出现 → Node_。source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow-designer/panel/ConditionConfig.vue \
src/components/flow-designer/panel/NodeConfigDrawer.vue \
src/components/flow-designer/DingFlowDesigner.vue \
src/components/flow-designer/__tests__/DingFlowDesigner.spec.js
# → 通过,0 errors
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer/__tests__/DingFlowDesigner.spec.js
# → Test Files 1 passed / Tests 10 passed / Duration 1.86s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer
# → Test Files 33 passed / Tests 288 passed / Duration 5.75s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 45.64s
DingFlowViewer.spec.js 仍有既有 Pinia active instance 警告,测试结果通过,本轮未触达该问题。pnpm build 仍有既有非阻断警告:CSS //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。前置节点 → 网关 → 原后续节点 一条出边,导致网关只有一个条件分支。NodeConfigDrawer 没有把当前网关的 outgoingEdges 传给 ConditionConfig,导致条件配置面板无法看到和编辑分支条件。useFlowDesigner.js
addNode() 对 condition/parallel/inclusive 改走专用网关插入逻辑。config.mergeNode = true,用于布局和汇合提示。NodeConfigDrawer.vue
outgoingEdges prop 和 update:edge 事件透传。DingFlowDesigner.vue
update:edge。useFlowDesigner.spec.js
DingFlowDesigner.spec.js
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow-designer/composables/useFlowDesigner.js \
src/components/flow-designer/composables/__tests__/useFlowDesigner.spec.js \
src/components/flow-designer/panel/NodeConfigDrawer.vue \
src/components/flow-designer/DingFlowDesigner.vue \
src/components/flow-designer/__tests__/DingFlowDesigner.spec.js
# → 通过,0 errors
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run \
src/components/flow-designer/composables/__tests__/useFlowDesigner.spec.js \
src/components/flow-designer/__tests__/DingFlowDesigner.spec.js
# → Test Files 2 passed / Tests 32 passed / Duration 1.64s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer
# → Test Files 33 passed / Tests 288 passed / Duration 5.59s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 48.98s
DingFlowViewer.spec.js 仍有既有 Pinia active instance 警告,测试结果通过,本轮未触达该问题。pnpm build 仍有既有非阻断警告:CSS //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。AddNodePopover.vue
38px 降为 28px,图标由 18px 降为 15px。58px 降为 46px,列间距由 12px 收敛为 8px。.add-node-menu-label,使用 min-width: 0、flex: 1、white-space: nowrap 和 text-overflow: ellipsis,避免图标挤压文字。source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow-designer/canvas/AddNodePopover.vue \
src/components/flow-designer/canvas/__tests__/AddNodeButton.spec.js
# → 通过,0 errors
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer/canvas/__tests__/AddNodeButton.spec.js
# → Test Files 1 passed / Tests 7 passed / Duration 1.15s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer
# → Test Files 33 passed / Tests 284 passed / Duration 5.89s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 56.51s
DingFlowViewer.spec.js 仍有既有 Pinia active instance 警告,测试结果通过,本轮未触达该问题。pnpm build 仍有既有非阻断警告:CSS //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。NodeCard.vue
contextMenu camelCase emit,并补充测试验证父组件 @context-menu 可正常监听,避免右键菜单链路回归。AddNodeButton.vue
aria-label/title 作为无障碍与悬浮说明。AddNodePopover.vue
w-96,分组间距、网格间距和单项点击区域放大,减少拥挤感。node-cards.spec.js
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint src/components/flow-designer/nodes/NodeCard.vue \
src/components/flow-designer/nodes/__tests__/node-cards.spec.js \
src/components/flow-designer/canvas/AddNodePopover.vue \
src/components/flow-designer/canvas/AddNodeButton.vue
# → 通过,0 errors
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm vitest run src/components/flow-designer
# → Test Files 33 passed / Tests 284 passed / Duration 5.90s
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 49.90s
DingFlowViewer.spec.js 仍有既有 Pinia active instance 警告,测试结果通过,本轮未触达该问题。pnpm build 仍有既有非阻断警告:
//padding 注释,建议后续改为 /* ... */。src/store/index.js 同时被动态和静态导入,影响 chunk 拆分但不阻断构建。本轮聚焦流程图设计器样式,不改 BPMN 转换语义、不改后端接口:
| 文件 | 改动 |
|---|---|
forge-admin-ui/src/components/flow-designer/nodes/NodeCard.vue |
节点卡片改为参考图风格:白底轻阴影、8px 圆角、左侧彩色图标块、灰底摘要行、青绿色选中描边 |
forge-admin-ui/src/components/flow-designer/canvas/FlowCanvas.vue |
画布改为浅色点阵背景,缩放工具条移动到底部左侧并统一按钮状态 |
forge-admin-ui/src/components/flow-designer/canvas/AddNodeButton.vue |
“+ 添加”按钮改为白底青绿色胶囊样式,并补充全局点击监听清理 |
forge-admin-ui/src/components/flow-designer/canvas/AddNodePopover.vue |
添加节点菜单改为分组卡片化布局,图标区统一 |
forge-admin-ui/src/components/flow-designer/canvas/BranchHeader.vue |
分支条件标签改为轻量 pill 样式,区分默认/已配置/未配置 |
forge-admin-ui/src/components/flow-designer/canvas/EdgePath.vue、utils/path-builder.js |
连线颜色调浅,默认分支色调整为青绿色,条件标签宽度自适应 |
forge-admin-ui/src/components/flow-designer/canvas/layout-engine.js |
画布节点尺寸和间距调整为更接近参考图的宽卡片比例 |
forge-admin-ui/src/components/flow-designer/composables/useCanvasViewport.js、DingFlowDesigner.vue |
自动 fit 居中时考虑 canvasBounds.minX/minY,避免内容因初始 margin 偏移 |
forge-admin-ui/vite.config.js |
清理已移除的 bpmn-js、dagre、diagram-js、inherits-browser、tiny-svg 预构建 include,修复 dev server 依赖预构建失败 |
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint --fix \
src/components/flow-designer/DingFlowDesigner.vue \
src/components/flow-designer/canvas/AddNodeButton.vue \
src/components/flow-designer/canvas/AddNodePopover.vue \
src/components/flow-designer/canvas/BranchHeader.vue \
src/components/flow-designer/canvas/EdgePath.vue \
src/components/flow-designer/canvas/FlowCanvas.vue \
src/components/flow-designer/canvas/layout-engine.js \
src/components/flow-designer/composables/useCanvasViewport.js \
src/components/flow-designer/nodes/NodeCard.vue \
src/components/flow-designer/nodes/__tests__/node-cards.spec.js
结果:✅ 通过,限定文件 lint 自动修复后无错误。
pnpm exec eslint vite.config.js
结果:✅ 通过。
NODE_ENV=development pnpm vitest run src/components/flow-designer
结果:✅ 33 passed (33),283 passed (283)。
说明:DingFlowViewer.spec.js 的 processInstanceId mock 场景仍会打印既有 Pinia active instance 警告,但测试通过,非本轮样式改动引入。
pnpm build
结果:✅ ✓ built in 50.15s。
构建警告:
//padding 形式注释,esbuild 提示 CSS 应使用 /* ... */。src/store/index.js 同时被动态和静态导入,Vite 输出 chunk 警告。以上均为既有非阻断警告。
尝试启动 dev server:
CHOKIDAR_USEPOLLING=true pnpm dev --host 127.0.0.1 --port 5173
结果:❌ 当前执行环境禁止监听本地端口:
Error: listen EPERM: operation not permitted 127.0.0.1:5173
首次尝试 pnpm dev --host 0.0.0.0 还触发过本机文件监听上限:
Error: EMFILE: too many open files, watch
本轮没有保留运行中的前端服务。
vite.config.js 的过期 optimizeDeps.include 清理是 dev server 启动前置修复;这些依赖已在 Phase 9 移除,继续保留会导致预构建失败。.DS_Store 与多处 flow-designer 文件改动;本轮未回退这些既有改动。| 文件 | 改动 |
|---|---|
forge-admin-ui/src/components/flow-designer/nodes/NodeCard.vue |
节点左侧图标区从 40px 放大到 48px,图标从 text-xl 放大到 text-2xl |
forge-admin-ui/src/components/flow-designer/canvas/AddNodeButton.vue |
节点间添加操作改为纯图标按钮,移除可见文字,仅保留 aria-label 和 title |
forge-admin-ui/src/components/flow-designer/canvas/AddNodePopover.vue |
添加节点列表改为更宽的单列布局,菜单项高度、间距和图标容器放大,避免 2 列拥挤 |
source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
pnpm exec eslint \
src/components/flow-designer/nodes/NodeCard.vue \
src/components/flow-designer/canvas/AddNodeButton.vue \
src/components/flow-designer/canvas/AddNodePopover.vue \
src/components/flow-designer/canvas/__tests__/AddNodeButton.spec.js \
src/components/flow-designer/nodes/__tests__/node-cards.spec.js
结果:✅ 通过。
NODE_ENV=development pnpm vitest run \
src/components/flow-designer/canvas/__tests__/AddNodeButton.spec.js \
src/components/flow-designer/nodes/__tests__/node-cards.spec.js
结果:✅ 2 passed (2),23 passed (23)。
NODE_ENV=development pnpm vitest run src/components/flow-designer
结果:✅ 33 passed (33),283 passed (283)。
pnpm build
结果:✅ ✓ built in 50.52s。
构建仍有既有非阻断警告:CSS 中 //padding 注释格式、src/store/index.js 动静态导入混用 chunk 提示。
/apply Task 0新增文件(9 个,全部为占位 index.js):
forge-admin-ui/src/components/flow-designer/
├── index.js # 顶层入口(最终导出 DingFlowDesigner / DingFlowViewer)
├── canvas/index.js # 画布层(FlowCanvas / EdgeLayer / AddNodeButton / 布局算法)
├── nodes/index.js # 12 种节点卡片
├── panel/index.js # 右侧配置抽屉与各 Tab 配置组件
├── viewer/index.js # 钉钉样式查看器
├── converter/index.js # BPMN XML ↔ flowJson 双向转换
├── composables/index.js # useFlowDesigner / useFlowHistory / useCanvasViewport
├── constants/index.js # 节点类型、菜单分组、默认配置
└── utils/index.js # ID 生成、路径计算、审批人摘要等通用工具
修改文件:无
删除文件:无(旧 src/components/bpmn/ 在 Phase 9 / Task 32 才删除)
forge-admin-ui/package.json 未引入新依赖。本次设计器改造所需能力均已就绪:
| 能力 | 已有依赖 |
|---|---|
| Vue 3 组合式 API | vue@^3.5.20 |
| 组件库(NDrawer / NTabs / NPopover / NDropdown / NDataTable …) | naive-ui@^2.42.0 |
| 原子化 CSS(钉钉风格卡片、按钮颜色) | unocss@^66.4.2 |
| 响应式工具(useMagicKeys / onClickOutside …) | @vueuse/core@^13.7.0 |
| 工具函数(cloneDeep / debounce / throttle) | lodash-es@^4.17.21 |
| 图标 | @vicons/ionicons5@^0.13.0 |
| XML 高亮(advanced 节点 rawXml 只读 + 校验) | @codemirror/lang-xml@^6.1.0 + codemirror@^6.0.1 |
| BPMN 解析 | 浏览器内置 DOMParser(无需第三方) |
旧依赖 bpmn-js / bpmn-js-properties-panel / inherits-browser / tiny-svg / diagram-js / dagre 暂保留,待 Phase 9 / Task 32 一并清理。
index.jsflow-designer/index.js 已建(含模块说明注释)package.json 不新增依赖src/components/bpmn/ 不动# 验证目录结构(执行结果见上)
find forge-admin-ui/src/components/flow-designer -type f | sort
# → 9 个 index.js
# 验证现有 bpmn 目录未被改动
ls forge-admin-ui/src/components/bpmn/
# → 14 个文件,与变更前一致
v-model 时,必须记录 lastEmittedXml,避免父组件 watcher 回写触发 import 清空 history。已在 converter/index.js 注释中标记。BPMNPlane.bpmnElement 指向真实 process。已在 converter/index.js 注释中标记。进入 Phase 1(Task 1-6),核心风险区域。Task 1 起每个任务遵循 TDD:先写 Vitest 单测 fixture,再实现转换器。
/apply Task 1新增(实现 + 测试)
| 文件 | 行数 | 用途 |
|---|---|---|
forge-admin-ui/src/components/flow-designer/constants/node-types.js |
110 | NODE_TYPE 枚举、NODE_TYPE_SET、bpmnTypeToNodeType()、NODE_TYPE_TO_BPMN_LOCAL_NAME 反向映射 |
forge-admin-ui/src/components/flow-designer/converter/xml-utils.js |
230 | DOMParser 封装、命名空间常量(BPMN_NS / FLOWABLE_NS / DC / DI / BPMNDI / XSI)、getRootProcess / findElementsByLocalName / getChildren / getChild / getAttr / getFlowableAttr / getFlowableBoolAttr / getExtensionElement(s) / getDocumentation / getTextContent / serializeXml |
forge-admin-ui/src/components/flow-designer/constants/__tests__/node-types.spec.js |
100 | NODE_TYPE 7 用例(含 12 类型识别 + 6 advanced 兜底场景) |
forge-admin-ui/src/components/flow-designer/converter/__tests__/xml-utils.spec.js |
175 | 基础 XML 工具 20 用例(解析/序列化/根 process/子查找/属性读取) |
forge-admin-ui/src/components/flow-designer/converter/__tests__/xml-utils-flowable.spec.js |
120 | Flowable 命名空间属性 + 扩展元素 12 用例 |
forge-admin-ui/vitest.config.js |
30 | Vitest 独立配置(jsdom 环境,不复用 vite.config 避免插件干扰) |
修改
| 文件 | 改动 |
|---|---|
forge-admin-ui/package.json |
新增 devDependencies:vitest@^2.1.9、@vitest/ui@^2.1.9、jsdom@^25.0.1;新增 scripts:test(vitest run)、test:watch、test:ui |
forge-admin-ui/src/components/flow-designer/converter/index.js |
升级为 export * from './xml-utils.js' |
forge-admin-ui/src/components/flow-designer/constants/index.js |
升级为 export * from './node-types.js' |
DOMParser / XMLSerializer,jsdom 环境下也能直接运行,为后续移除 bpmn-js 依赖(Task 32)打基础。localName 比较,兼容不同前缀(bpmn: / bpmn2: / 默认命名空间)。flowable:* 三路径回退:getFlowableAttr 依次尝试 getAttributeNS(FLOWABLE_NS, name) → getAttribute('flowable:' + name) → getAttribute(name),覆盖 Flowable 实际 XML 输出可能形态(含被默认化的 namespace)。bpmn:ServiceTask + flowable:type='cc' 走 carbonCopy,其他走 service,与现有 NodePropertiesPanel 约定一致。unplugin-vue-router / unocss / unplugin-auto-import 等插件,单测启动 1.24s。source ~/.nvm/nvm.sh && nvm use v20.19.0
cd forge-admin-ui
NODE_ENV=development pnpm install --prod=false # 必须显式 prod=false,否则 devDeps 跳过
pnpm vitest run src/components/flow-designer
结果:
RUN v2.1.9 /Users/yaomindong/Desktop/project/mdframe/forge-project/forge-admin-ui
✓ src/components/flow-designer/constants/__tests__/node-types.spec.js (7 tests) 15ms
✓ src/components/flow-designer/converter/__tests__/xml-utils-flowable.spec.js (12 tests) 22ms
✓ src/components/flow-designer/converter/__tests__/xml-utils.spec.js (20 tests) 29ms
Test Files 3 passed (3)
Tests 39 passed (39)
Duration 1.24s
✅ 39 / 39 通过,覆盖:12 种节点识别 + 6 种 advanced 兜底;flowable:* 属性 3 种解析路径;扩展元素查找;多 process 文档处理;默认 BPMN 命名空间兼容。
pnpm install 在某些 shell 环境下 NODE_ENV=production 会跳过 devDependencies。后续 /test 步骤如果发现 vitest 找不到,必须用 NODE_ENV=development pnpm install --prod=false 重装。vue-echarts peer warning:echarts 6 与 vue-echarts 7 期望 echarts 5,属预存在问题,与本变更无关。进入 Task 2:BPMN→JSON 转换器(基础节点)。继续 TDD:先用 fixture 写线性流程往返测试,再实现 convertBpmnToJson。
/apply Task 2-5(连续执行)新增(实现源码)
| 文件 | 行数 | 职责 |
|---|---|---|
converter/bpmn-to-json.js |
220 | BPMN XML → flowJson 主入口;解析所有 flowNode + sequenceFlow + advanced 兜底 |
converter/user-task-parser.js |
235 | UserTask 24 个字段 1:1 提取(4 种 assignee 模式 + 多实例 + 监听器 + 7 权限) |
converter/branch-parser.js |
100 | 网关出边 branchId 分配 + default 标记 + 入度/出度 + mergeNode 标识 |
converter/json-to-bpmn.js |
220 | flowJson → BPMN XML 主入口;含 BPMNDiagram 写出 |
converter/user-task-writer.js |
145 | UserTask config 回写为 attribute + extensionElements 子元素 |
converter/layout-algorithm.js |
175 | 纵向递归布局;线性链 + 网关分支横向并排 + 汇合回中线 + 孤立节点放右侧 |
converter/completion-condition.js |
30 | 会签 completionCondition 表达式构造(与 user-task-parser 对偶) |
converter/xml-escape.js |
30 | 属性 / 文本节点 XML 转义工具 |
新增(单元测试)
| 测试文件 | 用例数 | 覆盖范围 |
|---|---|---|
bpmn-to-json-linear.spec.js |
7 | 线性流程:start / serviceTask / end + sequenceFlow 默认字段 |
bpmn-to-json-multi.spec.js |
3 | scriptTask / carbonCopy(cc)/ subProcess / callActivity |
bpmn-to-json-condition.spec.js |
3 | exclusiveGateway 默认分支 + condition 表达式 |
bpmn-to-json-advanced.spec.js |
3 | intermediateCatchEvent → advanced + rawXml 保留 |
user-task-parser-assignee.spec.js |
7 | custom / spel / static(4 种)/ candidateUsers / candidateGroups |
user-task-parser-multi-instance.spec.js |
10 | parallel + all/any/ratio + sequential + none + 表达式解析 |
user-task-parser-listener.spec.js |
3 | taskListener × 3 type(class/expression/delegateExpression)+ executionListener |
user-task-parser-permissions.spec.js |
7 | 7 个权限布尔 + form 三类型 + priority/dueDate |
branch-parser.spec.js |
7 | 排他/并行/嵌套分支 + branchId 唯一 + mergeNode 识别 + in/outDegree |
layout-algorithm.spec.js |
8 | 线性 y 单调 + 并行 x 不重叠 + 汇合回中线 + 孤立节点右侧 |
completion-condition.spec.js |
6 | all/any/ratio 构造 + 双向往返 |
json-to-bpmn.spec.js |
7 | 主结构生成 + BPMNShape + 默认权限省略 + advanced rawXml + terminate |
roundtrip.spec.js |
4 | XML→JSON→XML 等价:线性 + 排他分支 default + 会签 ratio + all/any/ratio 全覆盖 |
修改
| 文件 | 改动 |
|---|---|
converter/index.js |
升级为重导出全部转换层模块 |
converter/layout-algorithm.js(生成 BPMNDiagram 坐标,本任务交付)和 canvas/layout-engine.js(画布渲染坐标,Task 10 交付)。两者输入相同 flowJson,但输出不同:前者只关心 dc:Bounds + di:waypoint,后者还要计算贝塞尔/正交折线。'ratio':tasks.md 与 spec 都用 ratio,但现有 NodePropertiesPanel.vue 用 'rate'。为遵循 spec 优先级(Spec > 现有代码),转换层统一使用 ratio;后续 Task 20 实现会签 UI 时也按 ratio 命名。assigneeType='spel' > ${user_xxx} > 4 种静态变量 > 简单 ${var} > 兜底 SPEL > 纯字符串。完全复刻 NodePropertiesPanel.vue:1562-1640。class,还支持 expression / delegateExpression。listener 项额外携带 class 字段以兼容现有 NodePropertiesPanel.taskListeners 的形态。node.rawXml,确保 advanced 节点(IntermediateEvent / BoundaryEvent / 复杂结构)二次往返不丢信息。NODE_ENV=development pnpm vitest run src/components/flow-designer
RUN v2.1.9
✓ 16 test files
✓ 114 tests passed
Duration 3.50s
按变更分布:
| 阶段 | 累计文件 | 累计用例 |
|---|---|---|
| Task 0 | 0 / 0 | 0 |
| Task 1 | 3 / 39 | 39 |
| Task 2 | +4 / +16 | 55 |
| Task 3 | +4 / +27 | 82 |
| Task 4 | +1 / +7 | 89 |
| Task 5 | +4 / +25 | 114 |
✅ 零回归:每个任务交付后跑全量都通过,无回归。
Task 2:
Task 3:
Task 4:
Task 5:
Phase 1 完成(Task 1-6 中的 1-5 完成;Task 6 端到端 fixture 测试可作为可选增强,目前 roundtrip.spec.js 已覆盖核心场景)。
进入 Phase 2:Task 7 useFlowDesigner Composable。这是设计器编辑态的核心数据模型,依赖转换层已落地的 flowJson 结构。
/apply 续作(Phase 2 整体)新增(实现源码)
| 文件 | 行数 | 职责 |
|---|---|---|
utils/id-generator.js |
80 | createIdGenerator() 单调递增 + 已用 ID 跳过;collectExistingIds() 收集 nodes/edges/branchId |
constants/default-configs.js |
130 | 12 种 nodeType 默认 config 工厂 + DEFAULT_NODE_NAMES + buildNode() 节点骨架构造 |
composables/useFlowDesigner.js |
200 | flowJson reactive + 节点/边 CRUD + 查询 + 整体加载导出 |
composables/flow-designer-helpers.js |
95 | cloneJson / makeEdge / deletePlain(笛卡儿重连)/ deleteGateway(递归删除分支链) |
composables/useFlowHistory.js |
105 | undo/redo 命令栈 + maxStack 限制 + Ctrl/Cmd+Z/Y/Shift+Z 键盘绑定 |
新增(单元测试)
| 测试文件 | 用例数 | 覆盖范围 |
|---|---|---|
utils/__tests__/id-generator.spec.js |
6 | 单调递增 / 已用 ID 跳过 / register / snapshot / collectExistingIds |
composables/__tests__/useFlowDesigner.spec.js |
20 | createEmptyFlow / 查询 / addNode(含分支元数据继承)/ deleteNode / updateNode / move / copy / load / export / reset |
composables/__tests__/flow-designer-helpers.spec.js |
3 | deleteGateway 递归删除 + deletePlain 入边语义保留 |
composables/__tests__/useFlowHistory.spec.js |
13 | snapshot/undo/redo/clear + maxStack + 深拷贝隔离 + Ctrl/Cmd+Z/Y/Shift+Z 键盘 + unbind |
修改
| 文件 | 改动 |
|---|---|
composables/index.js |
升级为 export * 导出 useFlowDesigner / useFlowHistory |
utils/index.js |
升级为导出 id-generator |
constants/index.js |
增加 default-configs 导出 |
cloneJson(flowJson.value) → mutate → flowJson.value = next 完成;这样 useFlowHistory.snapshot() 拿到的就是已稳定的整树快照,不会被后续部分变更污染。deletePlain 笛卡儿重连,保留入边的 condition/branchId/isDefault(保证分支链中的中间节点删除后语义不变)deleteGateway 沿分支链向下追,到入度 ≥ 2 的汇合点停止,把入边接到汇合点createIdGenerator({ usedIds }) 接受现有 flowJson 的 ID 集合,防止新 ID 与历史 ID 冲突;loadJson 时重新构造生成器。bindKeyboard(target) 默认 window,但接受任意 EventTarget;测试用 new EventTarget() 直接 dispatch keyboard 事件,无需 jsdom window 环境。NODE_ENV=development pnpm vitest run src/components/flow-designer
Test Files 20 passed (20)
Tests 156 passed (156)
Duration 5.67s
| 阶段 | 累计 spec | 累计用例 | 增量 |
|---|---|---|---|
| Task 1 | 3 | 39 | +39 |
| Task 2 | 7 | 55 | +16 |
| Task 3 | 11 | 82 | +27 |
| Task 4 | 12 | 89 | +7 |
| Task 5 | 16 | 114 | +25 |
| Task 7 | 19 | 143 | +29 |
| Task 8 | 20 | 156 | +13 |
✅ 零回归:每个任务交付后跑全量都通过。
Task 7:
Task 8:
Phase 2 完成 ✅。进入 Phase 3:画布渲染(Task 9-12,FlowCanvas / 布局引擎 / SVG 连线 / "+"号添加菜单)。这是设计器交互界面的开始,依赖:
/apply 续作(Phase 3 整体)新增(实现源码)
| 文件 | 行数 | 职责 |
|---|---|---|
composables/useCanvasViewport.js |
130 | scale/translate reactive 状态 + zoomIn/Out + 锚点缩放 + pan + fitToScreen + screenToCanvas/canvasToScreen 互逆 |
canvas/FlowCanvas.vue |
200 | 画布容器:transform 缩放/平移 + Ctrl/Cmd 滚轮 + 空格/中键拖拽 + 双击 reset + 浮动工具栏 |
canvas/layout-engine.js |
80 | 复用 converter/layout-algorithm 节点位置 + 边类型识别(straight/orthogonal)+ canvasBounds 范围 |
utils/path-builder.js |
130 | 4 种 path 类型(straight/orthogonal/rounded/bezier)+ getEdgeMidpoint 累积长度算中点 + 状态颜色/虚线 |
canvas/EdgePath.vue |
80 | 单条 SVG 边:path d + 状态箭头 marker + 条件标签 |
canvas/EdgeLayer.vue |
75 | SVG 容器:5 种箭头 marker defs + 渲染所有 EdgePath |
constants/node-menu.js |
50 | NODE_MENU_GROUPS 3 分组 9 类型(advanced 不在添加菜单) |
canvas/AddNodePopover.vue |
50 | 节点类型选择面板(按 allowTypes 过滤) |
canvas/AddNodeButton.vue |
70 | 画布上 "+" 按钮 + 弹出 Popover + click outside 收起 |
新增(单元测试)
| 测试文件 | 用例 | 覆盖 |
|---|---|---|
composables/__tests__/useCanvasViewport.spec.js |
11 | zoom 限制 / 锚点缩放屏幕坐标不变 / pan / fitToScreen / 坐标互逆 / transformStyle |
canvas/__tests__/FlowCanvas.spec.js |
7 | mount / 插槽 / defineExpose / zoomIn/zoomOut / readonly / transform style |
canvas/__tests__/layout-engine.spec.js |
8 | 节点位置 / straight 与 orthogonal 分类 / canvasBounds / 退化场景 |
utils/__tests__/path-builder.spec.js |
18 | 4 种 path 类型 / 边界 / 中点 / 颜色 / 虚线 |
canvas/__tests__/EdgePath.spec.js |
6 | path / "默认"标签 / 条件文本截断 / 状态箭头 |
canvas/__tests__/AddNodeButton.spec.js |
7 | popover 渲染 / 9 个类型按钮 / allowTypes 过滤 / 定位 / readonly |
修改
| 文件 | 改动 |
|---|---|
vitest.config.js |
新增 @vitejs/plugin-vue 让 .vue 文件能被解析 |
package.json |
+devDeps:@vue/test-utils@^2.4.6 |
canvas/index.js |
导出 5 个 Vue 组件 + layout-engine |
composables/index.js |
增加 useCanvasViewport 导出 |
utils/index.js |
增加 path-builder 导出 |
constants/index.js |
增加 node-menu 导出 |
canvas/layout-engine.js 复用 converter/layout-algorithm.js 的几何计算,再做画布特化包装(边类型识别 + canvasBounds)。避免重复实现,保持 BPMNDiagram 与画布坐标一致。buildPathD 在 bezier 优先于 straight 处理,避免两点 bezier 退化。newTranslate = anchor - (anchor - oldTranslate) * (newScale / oldScale) —— 单测验证锚点屏幕坐标在缩放前后对应同一画布坐标。mousedown capture 阶段监听 + event.target.closest('.add-node-button-wrap') 判定,避免依赖 NPopover 等重组件。defineExpose 方法 + 状态变化做断言,emit 行为由集成测试 / Phase 6 端到端覆盖。NODE_ENV=development pnpm vitest run src/components/flow-designer
Test Files 26 passed (26)
Tests 211 passed (211)
Duration 3.09s
| 阶段 | 累计 spec | 累计用例 | 增量 |
|---|---|---|---|
| Phase 1(Task 1-6) | 16 | 114 | — |
| Phase 2(Task 7-8) | 20 | 156 | +42 |
| Task 9 | 22 | 174 | +18 |
| Task 10 | 23 | 182 | +8 |
| Task 11 | 25 | 206 | +24 |
| Task 12 | 26 | 211 | +5(组件) +2 含 popover 验证 |
✅ 零回归。
Task 9:
Task 10:
Task 11:
Task 12:
Phase 3 完成 ✅。进入 Phase 4:节点组件(Task 13-17,12 种节点卡片 + 右键菜单)。组件 + 样式工作量较大,预计需 4-5 个交付批次。依赖:
/apply 续作(Phase 4 整体)新增(实现源码)
| 文件 | 行数 | 职责 |
|---|---|---|
nodes/NodeCard.vue |
130 | 节点卡片基类:色条 + 标题图标 + 删除按钮 + 状态徽章 + 选中高亮 + 右键菜单 emit |
nodes/StartNode.vue |
30 | 发起人卡片(success 色) |
nodes/EndNode.vue |
30 | 结束卡片(gray 色,含 endType) |
nodes/ApproverNode.vue |
50 | 审批人卡片(primary 色,会签徽章) |
nodes/CarbonCopyNode.vue |
45 | 抄送人卡片(info 色) |
nodes/BranchNode.vue |
60 | 网关卡片(condition/parallel/inclusive 共享) |
nodes/ServiceNode.vue |
30 | 服务任务卡片 |
nodes/ScriptNode.vue |
30 | 脚本任务卡片 |
nodes/SubProcessNode.vue |
20 | 子流程卡片 |
nodes/CallActivityNode.vue |
28 | 调用活动卡片 |
nodes/AdvancedNode.vue |
38 | 高级(advanced)兜底卡片 |
canvas/BranchHeader.vue |
50 | 分支首部条件徽章 |
canvas/MergeNode.vue |
25 | 汇合点视觉提示 |
canvas/NodeContextMenu.vue |
110 | 右键菜单(编辑/复制/上移/下移/删除)+ 按节点类型 / readonly 过滤 |
canvas/NodeRenderer.vue |
80 | 按 nodeType 调度对应卡片 + 应用 layout 位置 |
utils/approver-summary.js |
95 | 审批人卡片摘要文案:4 种 assignee 模式 + 多实例追加 |
新增(单元测试)
| 测试文件 | 用例 | 覆盖 |
|---|---|---|
utils/__tests__/approver-summary.spec.js |
17 | 4 种 assignee 模式 + 候选人列表(≤3 全显,>3 截断)+ multiInstance all/any/ratio + sequential |
nodes/__tests__/node-cards.spec.js |
16 | NodeCard 基类(选中/readonly/start-end/状态徽章)+ 11 种节点卡片渲染验证 |
canvas/__tests__/NodeRenderer.spec.js |
18 | NodeContextMenu(普通/start/readonly/canMoveUp 控制)+ NodeRenderer 调度 12 种节点 + 兜底 advanced + position 应用 |
修改
| 文件 | 改动 |
|---|---|
nodes/index.js |
升级为导出 NodeCard + 11 种节点卡片 |
canvas/index.js |
增加 BranchHeader / MergeNode / NodeContextMenu / NodeRenderer 导出 |
utils/index.js |
增加 approver-summary 导出 |
RENDERER_MAP[nodeType] 把 12 种 nodeType 映射到对应组件,未知类型兜底为 AdvancedNode;这样 FlowCanvas / DingFlowDesigner 不需要 v-if 分发。isDeletable 阻止 emit('delete');NodeContextMenu 用 isStartOrEnd 隐藏复制/上下移/删除按钮,UI 层保护与 useFlowDesigner.deleteNode 抛错的服务层保护一致。NODE_ENV=development pnpm vitest run src/components/flow-designer
Test Files 29 passed (29)
Tests 262 passed (262)
Duration 5.52s
| 阶段 | 累计 spec | 累计用例 | 增量 |
|---|---|---|---|
| Phase 1(Task 1-6) | 16 | 114 | — |
| Phase 2(Task 7-8) | 20 | 156 | +42 |
| Phase 3(Task 9-12) | 26 | 211 | +55 |
| Task 14(approver-summary) | 27 | 228 | +17 |
| Task 13/14/15/16(11 种卡片) | 28 | 244 | +16 |
| Task 17(ContextMenu/Renderer) | 29 | 262 | +18 |
✅ 零回归。
Task 13 ✅:NodeCard 基类(统一色条 + 标题 + 删除按钮 + 状态徽章 + 选中高亮)+ start / end 卡片 Task 14 ✅:ApproverNode + approver-summary 4 种 assignee 模式 + multiInstance 摘要 Task 15 ✅:CarbonCopyNode + 3 种 BranchNode 共享组件 + BranchHeader(条件徽章)+ MergeNode(汇合点视觉) Task 16 ✅:Service / Script / SubProcess / CallActivity / Advanced 5 种卡片 Task 17 ✅:NodeContextMenu(5 个操作按钮,按 nodeType / readonly 过滤)+ NodeRenderer 调度器(12 种类型 + 兜底)
进入 Phase 5:右侧配置抽屉(Task 18-25)。这是设计器的核心交互入口之一:用户点击节点卡片后,右侧滑出抽屉显示节点配置表单。Phase 5 工作量大(8 类配置组件 + 字段 1:1 迁移自 NodePropertiesPanel.vue 2655 行),预计 5-6 批次。
/apply 续作(Phase 5 整体)新增(19 个 Vue 组件 + 1 个调度模块)
| 文件 | 行数 | 职责 |
|---|---|---|
panel/NodeConfigDrawer.vue |
130 | 抽屉容器:滑出 + 顶部 icon/name + 底部 取消/保存 + draftNode 隔离 |
panel/BasicConfig.vue |
45 | 节点 ID(只读)/ name / documentation |
panel/ApproverConfig.vue |
70 | 审批节点主入口:5 个 Tab(基础/会签/权限/表单/监听器) |
panel/ApproverAssigneeForm.vue |
145 | 4 种 assignee 模式表单:static/custom/spel/candidates |
panel/MultiInstanceConfig.vue |
70 | parallel/sequential + all/any/ratio + passRate |
panel/PermissionConfig.vue |
65 | 7 个布尔开关(NSwitch)+ 描述 |
panel/ListenerConfig.vue |
145 | taskListeners + executionListeners 列表 + class/expression/delegate 类型 |
panel/FormPermissionConfig.vue |
80 | formFieldPermissions 列表(field/label/readable/writable/required) |
panel/StartConfig.vue |
35 | initiator + formKey + formUrl |
panel/EndConfig.vue |
35 | endType(normal / terminate) |
panel/CarbonCopyConfig.vue |
50 | candidateUsers + 抄送服务表达式 |
panel/ConditionConfig.vue |
80 | 网关出边列表 + condition 表达式 + 默认分支单选 |
panel/ServiceConfig.vue |
50 | implementationType (class/expr/delegate) + 值 + async |
panel/ScriptConfig.vue |
50 | scriptFormat + script + async |
panel/SubProcessConfig.vue |
30 | triggeredByEvent 开关 |
panel/CallActivityConfig.vue |
30 | calledElement |
panel/AdvancedConfig.vue |
60 | rawXml 只读 / 编辑切换(手动锁/解锁) |
panel/config-renderer-map.js |
35 | CONFIG_RENDERER_MAP:12 nodeType → 组件;getConfigComponent() |
新增(单元测试)
| 测试文件 | 用例 | 覆盖 |
|---|---|---|
panel/__tests__/config-renderer-map.spec.js |
5 | 12 种 nodeType 全覆盖 + Object.freeze + parallel/inclusive 共享 ConditionConfig + 未知类型兜底 |
修改
| 文件 | 改动 |
|---|---|
panel/index.js |
升级为导出 19 个组件 + config-renderer-map |
config + update:config patch,避免巨型表单组件难维护。{ assignee: 'spel' }),NodeConfigDrawer 在 updateConfig 中合并到 draftNode.config,保持单向数据流。update:edge 事件回调到 useFlowDesigner.updateEdge。Phase 5 仅完成组件,Phase 6 接入。NODE_ENV=development pnpm vitest run src/components/flow-designer
Test Files 30 passed (30)
Tests 267 passed (267)
Duration 9.41s
| 阶段 | 累计 spec | 累计用例 | 增量 |
|---|---|---|---|
| Phase 1-4(Task 1-17) | 29 | 262 | — |
| Phase 5(Task 18-25) | 30 | 267 | +5 |
✅ 零回归。
Phase 5 完成 ✅。进入 Phase 6:主组件集成(Task 26-27):
Phase 6 是首次端到端可见里程碑。
/apply 续作(Phase 6 整体)新增(实现源码)
| 文件 | 行数 | 职责 |
|---|---|---|
flow-designer/DingFlowDesigner.vue |
280 | 主组件:FlowCanvas + EdgeLayer + NodeRenderer × N + AddNodeButton × N + BranchHeader + MergeNode + NodeContextMenu + NodeConfigDrawer 一站式集成;对外接口与 FlowModeler 1:1 兼容(xml prop / change/ready/import-start/import-end 事件 / setXML/getXML/reset/undo/redo 方法) |
flow-designer/__tests__/DingFlowDesigner.spec.js |
105 | 8 用例:mount + 默认 createEmptyFlow + 暴露方法 + xml prop 加载 + getXML 输出 + 往返保留 + reset + setXML 多次切换 + readonly |
修改
| 文件 | 改动 |
|---|---|
flow-designer/index.js |
升级为重导出全部子模块 + 顶层 export DingFlowDesigner |
views/flow/design.vue |
替换 <FlowModeler> 为 <DingFlowDesigner>;import 改为 import { DingFlowDesigner } from '@/components/flow-designer';其他 1500 行 AI 生成 / 保存 / 校验逻辑零改动 |
views/flow/template.vue |
同样替换 FlowModeler → DingFlowDesigner |
xml / readonly)+ events(change / ready / import-start / import-end)+ 方法(setXML / getXML / reset / undo / redo),design.vue / template.vue 业务代码零修改。lastEmittedXml,watch props.xml 时若 == lastEmittedXml 跳过 import;scheduleEmit 在 emit 之前更新 lastEmittedXml;这样父组件 v-model:xml 模式下不会无限循环。convertBpmnToJson 正常解析;JSON→XML 时总是写真实 process id。design.vue 中的 repairBpmnXml 等修复逻辑保留作为防御性兜底,但已不是关键路径。scheduleEmit(200ms 防抖),避免高频编辑时父组件频繁收到 change。history.snapshot(),使 undo 能精确回到操作前。NODE_ENV=development pnpm vitest run src/components/flow-designer
Test Files 31 passed (31)
Tests 275 passed (275)
Duration 5.98s
| 阶段 | 累计 spec | 累计用例 | 增量 |
|---|---|---|---|
| Phase 1-5(Task 1-25) | 30 | 267 | — |
| Phase 6(Task 26-27) | 31 | 275 | +8 |
✅ 零回归。
Task 26 DingFlowDesigner:
Task 27 design.vue 接入:
到本阶段,用户在浏览器打开 /flow/design/:id:
旧 components/bpmn/ 目录暂时保留(Phase 9 / Task 32 才移除)。
进入 Phase 7:流程查看器(Task 28-29)。基于 DingFlowDesigner 加 readonly + nodeStatuses 渲染节点状态徽章,替代旧的 ProcessDiagramViewer / InteractiveProcessDiagram 组件,给待办 / 已办 / 已发起 / 流程监控页面提供统一的查看体验。
/apply 续作(Phase 7 整体)新增(实现源码)
| 文件 | 行数 | 职责 |
|---|---|---|
viewer/NodeStatusBadge.vue |
40 | 独立节点状态徽章(5 种状态文案 + 颜色 + size 变体) |
viewer/NodeDetailPopover.vue |
100 | 节点详情气泡:审批人 / 开始结束时间 / 审批结果 / 意见(click outside 关闭) |
viewer/DingFlowViewer.vue |
235 | 查看器主组件:接口与 ProcessDiagramViewer 兼容(processInstanceId + compact + bpmnXml + nodeInstanceList);自动调 flowApi.getProcessDiagramInfo 获取数据;用 FlowCanvas readonly + NodeRenderer status 渲染;节点点击弹 NodeDetailPopover |
新增(单元测试)
| 测试文件 | 用例 | 覆盖 |
|---|---|---|
viewer/__tests__/NodeStatusBadge.spec.js |
3 | 无状态不渲染 / 5 种状态文案与类名 / size 变体 |
viewer/__tests__/DingFlowViewer.spec.js |
5 | 直接传 bpmnXml 模式 + nodeInstanceList 转 nodeStatusMap + compact 模式 + processInstanceId loading 状态 + 空 props 兜底 |
修改
| 文件 | 改动 |
|---|---|
viewer/index.js |
升级为导出 DingFlowViewer / NodeStatusBadge / NodeDetailPopover |
flow-designer/index.js |
增加 export * from './viewer/index.js' |
processInstanceId(自动 fetch)/ bpmnXml+nodeInstanceList(直接传入)/ compact 三种用法,与 ProcessDiagramViewer 完全兼容;todo / done / started / monitor 页面(Phase 8)只需替换 import 与标签。{ [bpmnElementId]: { status, assigneeName, startTime, endTime, result, comment } },作为 NodeRenderer 的 status props 透传到 NodeCard 已实现的状态徽章。NODE_ENV=development pnpm vitest run src/components/flow-designer
Test Files 33 passed (33)
Tests 283 passed (283)
Duration 6.19s
| 阶段 | 累计 spec | 累计用例 | 增量 |
|---|---|---|---|
| Phase 1-6(Task 1-27) | 31 | 275 | — |
| Phase 7(Task 28-29) | 33 | 283 | +8 |
✅ 零回归。
Task 28:
Task 29 DingFlowViewer:
进入 Phase 8:把 todo.vue / done.vue / started.vue / monitor.vue / AiCrudFlowDetail.vue 这 5 处 ProcessDiagramViewer 引用替换为 DingFlowViewer,让钉钉样式查看看图在所有入口生效。
/apply 续作(Phase 8)修改 5 个文件(仅 import 路径替换,模板标签名保留)
| 文件 | 改动 |
|---|---|
views/flow/todo.vue:401 |
import ProcessDiagramViewer from '@/components/bpmn/ProcessDiagramViewer.vue' → '@/components/flow-designer/viewer/DingFlowViewer.vue' |
views/flow/done.vue:148 |
同上 |
views/flow/started.vue:158 |
同上 |
views/flow/monitor.vue:441 |
同上 |
components/ai-form/AiCrudFlowDetail.vue:46 |
同上 |
import ProcessDiagramViewer from 'DingFlowViewer.vue' 保留原变量名,模板里 <ProcessDiagramViewer> 标签不需要改动。最小化 PR diff,便于 review。processInstanceId + compact 两个 props,DingFlowViewer 全部支持(Task 29 已实现),调用方代码 0 行修改。# 全量单测
NODE_ENV=development pnpm vitest run src/components/flow-designer
# → Test Files 33 passed / Tests 283 passed / Duration 7.07s
# Lint 检查本次变更涉及的文件
pnpm lint 2>&1 | grep -E "flow-designer|flow/todo|flow/done|flow/started|flow/monitor|AiCrudFlowDetail|flow/design|flow/template"
# → 无输出(本次变更 0 lint 错误)
# 仓库整体 lint 仍有 324 个既有错误(region.vue / socialConfig.vue 等),与本次变更无关
components/bpmn/ 旧目录(保留 UserSelectModal 等仍在使用的组件)pnpm build + pnpm vitest run 端到端冒烟进入 Phase 9:清理与冒烟(Task 32-34)。这是变更的最后阶段:
pnpm build + pnpm vitest run 端到端冒烟/apply 续作(Phase 9 整体)核查 components/bpmn/ 14 个文件的外部引用:
| 文件 | 外部引用 | 处理 |
|---|---|---|
UserSelectModal.vue |
3 处(todo / monitor / UserSelectPicker) | 迁出到 components/common/UserSelectModal.vue |
NodePropertiesPanel.vue |
design.vue 1 处 | design.vue 模板替换为 NEmpty 提示;import 删除;handleModelerReady 改为 no-op |
| 其他 12 个文件 | 0 外部引用 | 删除 |
额外发现并修复:
version.vue 直接 import BpmnJS from 'bpmn-js/lib/NavigatedViewer' + 4 个 bpmn-js CSS imports + renderVersionDiagram 函数使用 new BpmnJS() / importXML / canvas.zoom → 全部替换为 <DingFlowViewer :bpmn-xml="..." :compact="true" />,函数改为 no-op移除依赖:bpmn-js / bpmn-js-properties-panel / inherits-browser / tiny-svg / diagram-js / dagre / @types/dagre 共 7 个
# 构建冒烟(52.27s)
cd forge-admin-ui && pnpm build
# → ✓ built in 52.27s
# → dist/assets/DingFlowDesigner-0dU6p8NM.js 47.38 kB │ gzip: 13.58 kB(新设计器独立 chunk)
# 全量单测
pnpm vitest run src/components/flow-designer
# → Test Files 33 passed (33)
# → Tests 283 passed (283)
# → Duration 5.91s
✅ 构建零错误 + 单测零回归。
| 验收项 | 结果 |
|---|---|
| 35 个 Task 全部 done | ✅ |
| 全量单测 33 文件 / 283 用例通过 | ✅ |
| pnpm build 构建成功(52.27s) | ✅ |
| bpmn-js / diagram-js 等 7 个依赖已移除 | ✅ |
| 旧 components/bpmn/ 目录已删除 | ✅ |
| UserSelectModal 迁出到 common/,3 处引用同步更新 | ✅ |
| design.vue / template.vue FlowModeler → DingFlowDesigner | ✅ |
| version.vue 直接 bpmn-js → DingFlowViewer | ✅ |
| 5 个查看入口 ProcessDiagramViewer → DingFlowViewer | ✅ |
| 本次变更文件 lint 0 错误 | ✅ |
| pitfalls #7(v-model 回环)已规避 | ✅ |
| pitfalls #8(BPMNPlane 指向错误)不再是问题 | ✅ |
本变更把基于 bpmn-js 17.11 的 BPMN 自由画布流程设计器,改造为钉钉/企业微信审批样式:纵向卡片流 + "+"号添加 + 自动连线 + 右侧抽屉配置。
核心成果:
| 文件 | 改动 |
|---|---|
src/components/flow/FlowStats.vue |
顶部统计从渐变卡片改为克制页签条,去掉浮动、渐变图标和脉冲徽标 |
src/components/flow/FlowTaskCardList.vue |
新增通用审批任务卡片列表,承载批量选择、搜索、筛选、刷新、分页和任务条目 |
src/views/flow/todo.vue |
待办列表切换为审批任务条目,保留签收和去审批入口 |
src/views/flow/done.vue |
已办列表切换为审批任务条目,突出审批结果、完成时间和审批意见 |
src/views/flow/started.vue |
我发起的列表切换为审批任务条目,突出流程状态、当前任务和处理人 |
src/views/flow/cc.vue |
抄送列表切换为审批任务条目,保留收到/发出切换、已读状态和批量已读 |
git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowStats.vue src/components/flow/FlowTaskCardList.vue src/views/flow/todo.vue src/views/flow/done.vue src/views/flow/started.vue src/views/flow/cc.vue
# → 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 1m 44s
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm dev --host 127.0.0.1 --port 3000
# → VITE ready in 1607 ms, Local: http://127.0.0.1:3000/
curl -I http://127.0.0.1:3000/
# → HTTP/1.1 200 OK
curl -I http://127.0.0.1:3000/src/views/flow/todo.vue
curl -I http://127.0.0.1:3000/src/views/flow/cc.vue
curl -I http://127.0.0.1:3000/src/components/flow/FlowTaskCardList.vue
# → 三个动态模块均 HTTP/1.1 200 OK
pnpm build 仍输出既有 CSS //padding 注释警告,以及 src/store/index.js 动静态混合导入 chunk 警告;本轮未引入,非阻断。Ctrl-C 停止,未保留后台服务。| 文件 | 改动 |
|---|---|
src/components/flow/FlowTaskCardList.vue |
收紧工具栏、任务条目高度、左右内边距、卡片间距和分页留白 |
src/views/flow/todo.vue |
移除顶部跨页统计;增加单条和批量“驳回 / 同意”;快捷处理弹窗复用现有审批接口 |
src/views/flow/done.vue |
移除顶部跨页统计和额外统计请求;页面左右 padding 收紧 |
src/views/flow/started.vue |
移除顶部跨页统计和额外统计请求;页面左右 padding 收紧 |
src/views/flow/cc.vue |
移除顶部跨页统计和额外统计请求;保留收到/发出二级 Tab 与未读角标 |
approveTask / rejectTask 真实接口。claimTask 签收,再提交审批。git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowTaskCardList.vue src/views/flow/todo.vue src/views/flow/done.vue src/views/flow/started.vue src/views/flow/cc.vue
# → 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 52.86s
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm dev --host 127.0.0.1 --port 3000
# → VITE ready in 1685 ms, Local: http://127.0.0.1:3000/
curl -I http://127.0.0.1:3000/
curl -I http://127.0.0.1:3000/src/views/flow/todo.vue
curl -I http://127.0.0.1:3000/src/views/flow/done.vue
curl -I http://127.0.0.1:3000/src/views/flow/started.vue
curl -I http://127.0.0.1:3000/src/views/flow/cc.vue
# → 首页和四个动态模块均 HTTP/1.1 200 OK
pnpm build 仍输出既有 CSS //padding 注释警告,以及 src/store/index.js 动静态混合导入 chunk 警告;本轮未引入,非阻断。Ctrl-C 停止,未保留后台服务。| 文件 | 改动 |
|---|---|
src/components/flow/FlowTaskCardList.vue |
列表组件设为 width: 100%;任务条目横向 padding 从 16px 继续收紧到 10px;列间距和元信息横向间距同步压缩 |
src/views/flow/todo.vue |
页面容器改为 padding: 8px 0 12px,横向不再额外留白 |
src/views/flow/done.vue |
同步页面容器宽度适配 |
src/views/flow/started.vue |
同步页面容器宽度适配 |
src/views/flow/cc.vue |
同步页面容器宽度适配 |
git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowTaskCardList.vue src/views/flow/todo.vue src/views/flow/done.vue src/views/flow/started.vue src/views/flow/cc.vue
# → 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 48.98s
pnpm build 仍输出既有 CSS //padding 注释警告,以及 src/store/index.js 动静态混合导入 chunk 警告;本轮未引入,非阻断。| 文件 | 改动 |
|---|---|
src/utils/flow-task-layout.js |
新增流程任务列表路由判断工具,集中维护 /flow/todo、/flow/done、/flow/started、/flow/cc |
src/layouts/top-menu/index.vue |
默认布局内容区在流程任务列表页移除外层 p-12,解决当前页面仍显窄的问题 |
src/layouts/top-side-menu/index.vue |
顶部+侧边布局同步移除流程任务列表页外层 padding |
src/layouts/full/index.vue |
全屏布局同步增加流程任务列表 flush 内容区 |
src/layouts/simple/index.vue |
简洁布局同步增加流程任务列表 flush 内容区 |
src/layouts/bento/index.vue |
Bento 布局同步增加流程任务列表 flush 内容区 |
src/layouts/immersive/index.vue |
沉浸式布局同步增加流程任务列表 flush 内容区 |
src/layouts/nexus/index.vue |
Nexus 布局同步增加流程任务列表 flush 内容区 |
上轮已经把四个流程列表页自身横向 padding 清零,但默认 top-menu 布局的页面内容容器仍带 p-12,其它布局也存在 10px/16px 外层 padding。列表组件的 width: 100% 只能铺满带 padding 的内容区,所以视觉上仍然像没改。
git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/utils/flow-task-layout.js src/layouts/top-menu/index.vue src/layouts/top-side-menu/index.vue src/layouts/full/index.vue src/layouts/simple/index.vue src/layouts/bento/index.vue src/layouts/immersive/index.vue src/layouts/nexus/index.vue
# → 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowTaskCardList.vue src/views/flow/todo.vue src/views/flow/done.vue src/views/flow/started.vue src/views/flow/cc.vue
# → 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 46.28s
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm dev --host 127.0.0.1 --port 3000
# → VITE ready in 1293 ms, Local: http://127.0.0.1:3000/
curl -I http://127.0.0.1:3000/flow/todo
curl -I http://127.0.0.1:3000/src/layouts/top-menu/index.vue
curl -I http://127.0.0.1:3000/src/utils/flow-task-layout.js
curl -I http://127.0.0.1:3000/src/views/flow/todo.vue
# → 四个请求均 HTTP/1.1 200 OK
pnpm build 仍输出既有 CSS //padding 注释警告,以及 src/store/index.js 动静态混合导入 chunk 警告;本轮未引入,非阻断。scripts/with_server.py,本轮直接启动 Vite dev server 做 HTTP 冒烟。Ctrl-C 停止,未保留后台服务。| 文件 | 改动 |
|---|---|
src/components/flow/FlowTaskCardList.vue |
撤销列表容器左右外扩,恢复为 width: 100%,避免横向推出页面 |
src/components/flow/FlowTaskCardList.vue |
n-spin 容器、任务栈和任务行显式 width: 100%,避免中间层收缩 |
src/components/flow/FlowTaskCardList.vue |
工具栏左右 padding 保持 4px,任务行保持全宽但不超过页面 |
git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowTaskCardList.vue src/views/flow/todo.vue src/views/flow/done.vue src/views/flow/started.vue src/views/flow/cc.vue
# → 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# → ✓ built in 45.13s
pnpm build 仍输出既有 CSS //padding 注释警告,以及 src/store/index.js 动静态混合导入 chunk 警告;本轮未引入,非阻断。| 文件 | 改动 |
|---|---|
src/views/flow/done.vue |
右侧“查看详情”改为行内“详情 + 箭头”动作 |
src/views/flow/started.vue |
右侧“查看进度”改为行内“进度 + 箭头”动作 |
src/components/flow/FlowTaskCardList.vue |
新增 task-row-link-action 样式:透明、无边框、hover 浅底色 |
git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowTaskCardList.vue src/views/flow/done.vue src/views/flow/started.vue
# → 通过,0 error
pnpm build;前序列表样式调整后已执行完整构建。| 文件 | 改动 |
|---|---|
src/components/flow/FlowTaskCardList.vue |
行动作区统一右对齐,支持换行后仍靠右 |
src/components/flow/FlowTaskCardList.vue |
轻量行内动作增加 info、success、danger 颜色变体 |
src/views/flow/todo.vue |
待办行内“签收 / 驳回 / 同意 / 审批”改为同款轻量动作 |
git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowTaskCardList.vue src/views/flow/todo.vue src/views/flow/done.vue src/views/flow/started.vue
# → 通过,0 error
pnpm build;前序列表样式调整已通过完整构建。| 文件 | 改动 |
|---|---|
src/views/flow/done.vue |
将右侧“查看详情”从 Naive 小号次级按钮改为“详情 + 箭头”行内动作 |
src/views/flow/started.vue |
将右侧“查看进度”从 Naive 小号次级按钮改为“进度 + 箭头”行内动作 |
src/components/flow/FlowTaskCardList.vue |
新增 task-row-link-action 样式:无边框、透明底色、hover 浅色反馈 |
git diff --check
# → 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow/FlowTaskCardList.vue src/views/flow/done.vue src/views/flow/started.vue
# → 通过,0 error
| 文件 | 改动 |
|---|---|
src/components/flow-designer/nodes/NodeCard.vue |
只读态节点图标从 42px 放大到 52px |
src/components/flow-designer/nodes/NodeCard.vue |
只读态图标字体提升到 30px,标题行改为居中对齐并增加间距 |
src/components/flow-designer/nodes/NodeCard.vue |
只读态图标圆角和阴影同步增强,提升缩放画布下的辨识度 |
git diff --check
# -> 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow-designer/nodes/NodeCard.vue src/components/flow-designer/viewer/DingFlowViewer.vue
# -> 通过,0 error
pnpm build;前序流程设计器和流程列表样式调整已通过完整构建。| 文件 | 改动 |
|---|---|
src/components/flow-designer/nodes/NodeCard.vue |
readonly 查看态隐藏 subtitle、默认插槽和 title-extra,避免显示 SPEL、表达式、会签等配置内容 |
src/components/flow-designer/nodes/NodeCard.vue |
查看态节点卡片内容垂直居中,隐藏摘要后不留突兀空层 |
src/components/flow-designer/viewer/NodeDetailPopover.vue |
节点详情弹层收窄到 360px,改为紧凑信息列表,只展示运行态处理信息 |
src/components/flow-designer/nodes/__tests__/node-cards.spec.js |
增加 readonly 隐藏配置摘要和标题附加徽章的单测 |
src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js |
更新为紧凑详情布局单测 |
git diff --check
# -> 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/components/flow-designer/nodes/NodeCard.vue src/components/flow-designer/viewer/NodeDetailPopover.vue src/components/flow-designer/nodes/__tests__/node-cards.spec.js src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js src/components/flow-designer/viewer/DingFlowViewer.vue
# -> 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm vitest run src/components/flow-designer/nodes/__tests__/node-cards.spec.js src/components/flow-designer/viewer/__tests__/NodeDetailPopover.spec.js
# -> 2 个测试文件通过,21 个用例通过
${deptManager} 触发 no-template-curly-in-string,已改为字符串拼接后复跑通过。pnpm build;已用目标 lint、目标单测和 git diff --check 覆盖本次查看态模板/CSS改动。| 文件 | 改动 |
|---|---|
src/views/flow/model.vue |
顶部查询区按钮从 Naive 默认按钮改为页面内轻量工具按钮 |
src/views/flow/model.vue |
“新增模型”改为克制深色主操作按钮,并移到筛选项之后 |
src/views/flow/model.vue |
卡片右侧“设计 / 部署 / 实例”改为行内轻量操作按钮 |
src/views/flow/model.vue |
更多操作从默认小按钮改为 28px 图标按钮 |
src/views/flow/model.vue |
补充移动端工具按钮独占一行、480px 以下等宽铺开 |
git diff --check
# -> 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/flow/model.vue
# -> 通过,0 error
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# -> 通过,built in 54.03s
pnpm build 仍输出既有 CSS //padding 注释 warning,以及 src/store/index.js 动静态混合导入 warning;本轮未引入,非阻断。| 文件 | 改动 |
|---|---|
src/views/flow/monitor.vue |
流程实例监控主表“详情”从 Naive text 按钮改为轻量行内按钮 |
src/views/flow/monitor.vue |
“更多”从文字按钮改为 28px 图标按钮 |
src/views/flow/monitor.vue |
新增 monitor-row-actions、monitor-row-action、monitor-row-more 样式,补充 hover、focus-visible、disabled 状态 |
git diff --check
# -> 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/flow/monitor.vue
# -> 通过,0 error
aria-label 与未引号属性混用触发 style/quote-props,已统一该对象 key 引号后复跑通过。pnpm build;本轮未重复执行长构建。| 文件 | 改动 |
|---|---|
src/views/flow/monitor.vue |
流程实例监控主表“详情 / 更多”统一为已办页同款青绿色行内文字按钮 |
src/views/flow/monitor.vue |
“详情”保留右箭头,“更多”改为文字 + 下拉图标,替代无颜色的图标按钮 |
src/views/flow/monitor.vue |
补齐透明底、浅青 hover、14px 加粗、disabled 透明度等按钮状态 |
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/flow/monitor.vue
# -> 通过,0 error
git diff --check
# -> 通过,无空白错误
pnpm build。| 文件 | 改动 |
|---|---|
src/views/flow/monitor.vue |
将 .monitor-row-link-action 改为 .flow-monitor-page :deep(.monitor-row-link-action),确保 NDataTable 列 render 生成的按钮能命中样式 |
src/views/flow/monitor.vue |
按钮文字颜色改为 #177c7d !important,hover 改为 #0f5f63 !important,覆盖默认灰色 |
src/views/flow/monitor.vue |
按钮内 span 和图标统一继承 currentColor,避免图标或文字仍被外部样式置灰 |
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/flow/monitor.vue
# -> 通过,0 error
git diff --check
# -> 通过,无空白错误
| 文件 | 改动 |
|---|---|
src/views/flow/todo.vue |
从 dist/assets/todo-B8Vb9fog.js 残留产物恢复新版待办列表源码结构 |
src/views/flow/todo.vue |
恢复 FlowTaskCardList 任务条目列表、筛选、搜索、刷新、分页和选中态 |
src/views/flow/todo.vue |
恢复单条“签收 / 驳回 / 同意 / 审批”和批量“驳回 / 同意”快捷操作 |
src/views/flow/todo.vue |
快捷操作会先签收候选任务;动态表单、外部表单、手写签名任务跳过并提示进入详情处理 |
src/views/flow/todo.vue |
恢复 FlowTaskDetailShell 全屏详情,保留动态表单、外部表单、签名、转办和流程图处理链路 |
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/flow/todo.vue
# -> 通过,0 error
git diff --check
# -> 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# -> 通过,built in 1m 1s
pnpm build 仍输出既有 CSS //padding 注释 warning,以及 src/store/index.js 动静态混合导入 warning;本轮未引入,非阻断。/home 待办任务列表需要按前序优化思路调整)| 文件 | 改动 |
|---|---|
src/views/home/index.vue |
待办任务列表从装饰化卡片行改为扁平工作台任务行 |
src/views/home/index.vue |
行内信息调整为“待签收/待处理状态 + 标题/节点/发起人/部门 + 时间/处理动作” |
src/views/home/index.vue |
右上角入口从“查看全部”改为轻量“全部”文字动作 |
src/views/home/index.vue |
单条任务点击和“处理”按钮统一跳转 /flow/todo?taskId=...,匹配待办页详情打开逻辑 |
src/views/home/index.vue |
补充移动端两行布局和暗色模式状态、动作样式 |
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/home/index.vue
# -> 通过,0 error
git diff --check
# -> 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# -> 通过,built in 1m 10s
pnpm build 仍输出既有 CSS //padding 注释 warning,以及 src/store/index.js 动静态混合导入 warning;本轮未引入,非阻断。| 文件 | 改动 |
|---|---|
src/views/flow/todo.vue |
待办列表状态标签从通用 default/info 改为待办页专用 todo-status-pending/todo-status-active |
src/views/flow/todo.vue |
待签收状态改为琥珀色,待处理状态改为青绿色 |
src/views/flow/todo.vue |
审批详情头部状态图标同步使用待办页专用颜色 |
src/views/flow/todo.vue |
未修改 FlowTaskCardList 通用状态类,避免影响已办、我发起、抄送列表 |
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/flow/todo.vue
# -> 通过,0 error
git diff --check
# -> 通过,无空白错误
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# -> 通过,built in 56.91s
pnpm build 仍输出既有 CSS //padding 注释 warning,以及 src/store/index.js 动静态混合导入 warning;本轮未引入,非阻断。leave_multi,应显示流程名称)| 文件 | 改动 |
|---|---|
src/views/flow/todo.vue |
审批详情字段从“流程分类”改为“流程名称” |
src/views/flow/todo.vue |
新增 getProcessDisplayName,优先展示 processName,再回退到旧字段 |
FlowTask.java |
增加非表字段 processName,用于承载流程模型名称 |
FlowTaskMapper.xml |
待办、已办、我发起和任务详情查询关联 sys_flow_model,返回 m.model_name AS process_name |
FlowTaskMapper.java |
移除 selectByTaskId 注解 SQL,改由 XML 承载 |
FlowTaskServiceImpl.java |
getTaskDetail 改为调用 selectByTaskId,详情接口也能返回流程名称 |
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
pnpm exec eslint src/views/flow/todo.vue
# -> 通过,0 error
git diff --check
# -> 通过,无空白错误
mvn -pl forge-framework/forge-plugin-parent/forge-plugin-flow -am compile -DskipTests
# -> 失败:当前 shell JDK 不支持 target 17
JAVA_HOME=/opt/homebrew/Cellar/openjdk@17/17.0.13/libexec/openjdk.jdk/Contents/Home \
PATH=/opt/homebrew/Cellar/openjdk@17/17.0.13/libexec/openjdk.jdk/Contents/Home/bin:$PATH \
mvn -pl forge-framework/forge-plugin-parent/forge-plugin-flow -am compile -DskipTests
# -> 通过,BUILD SUCCESS
source ~/.nvm/nvm.sh && nvm use v20.19.0 && \
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
# -> 通过,built in 1m 3s
JAVA_HOME 后通过。pnpm build 仍输出既有 CSS //padding 注释 warning,以及 src/store/index.js 动静态混合导入 warning;本轮未引入,非阻断。