12 KiB
组织树与脑图操作能力一致 Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 让“组织树模式”和“脑图模式”只是展示形式不同,组织节点和人员节点的操作能力完全一致。
Architecture: 保留 SystemPermissionView.vue 作为唯一组织动作编排层,继续复用现有 nodeActions(node)、runNodeAction(actionKey, node)、各类 drawer 打开函数和删除/授权函数。OrgPermissionTree.vue 只负责展示组织树、选中节点、发出节点菜单事件,不新增第二套业务动作逻辑。
Tech Stack: Vue 3 <script setup>、现有静态 Node test、Vite、现有 OrgPermissionTree.vue / SystemPermissionView.vue 组件体系。
File Structure
-
Modify:
frontend/src/components/OrgPermissionTree.vue- 增加右侧“节点操作”入口。
- 继续支持组织树节点右键菜单。
- 通过
node-contextmenuemit 当前节点和菜单坐标,不直接执行业务动作。 - 调整右侧 header 按钮布局,让“节点操作”和“新增人员”共存。
-
Modify:
frontend/src/components/OrgPermissionTree.test.js- 锁定组织树存在“节点操作”按钮。
- 锁定组织树节点右键仍然 emit
open-menu。 - 锁定组织树不新增第二套动作函数,只 emit
node-contextmenu。
-
Modify:
frontend/src/views/SystemPermissionView.vue- 复用现有
openContextMenu(eventPayload)和runNodeAction(actionKey, node)。 - 必要时给当前节点操作入口提供更稳定的菜单坐标处理。
- 不复制
nodeActions到子组件。
- 复用现有
-
Modify:
frontend/src/views/SystemPermissionView.test.js- 锁定组织树仍绑定
@node-contextmenu="openContextMenu"。 - 锁定组织树的“节点操作”最终仍进入同一套
contextMenuActions/runNodeAction。
- 锁定组织树仍绑定
-
Modify:
frontend/src/styles/main.cssif needed- 如果组件 scoped 样式不够覆盖全局表格/抽屉样式,补少量全局样式。
- 不引入新的视觉体系。
Task 1: 锁定组织树动作入口契约
Files:
-
Modify:
frontend/src/components/OrgPermissionTree.test.js -
Step 1: 写失败测试,要求组织树有显式节点操作入口
在 OrgPermissionTree.test.js 末尾追加:
describe("OrgPermissionTree node action parity", () => {
it("exposes a visible current-node action entry that emits the shared node context menu event", () => {
assert.match(source, /节点操作/);
assert.match(source, /@click="openSelectedNodeMenu"/);
assert.match(source, /function openSelectedNodeMenu\(event\)/);
assert.match(source, /emit\("node-contextmenu"/);
assert.doesNotMatch(source, /function runNodeAction\(/);
assert.doesNotMatch(source, /function nodeActions\(/);
});
});
- Step 2: 运行测试确认失败
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP/frontend
node src/components/OrgPermissionTree.test.js
Expected:
not ok ... exposes a visible current-node action entry ...
失败原因应是当前源码没有 节点操作、openSelectedNodeMenu。
- Step 3: 不修改生产代码,先提交测试是不需要的
此任务只建立红灯,不单独提交。
Task 2: 在组织树右侧 header 增加“节点操作”入口
Files:
-
Modify:
frontend/src/components/OrgPermissionTree.vue -
Step 1: 修改右侧 header 按钮区
将当前右侧 header 中的单个“新增人员”按钮:
<button
class="primary-button"
type="button"
:disabled="!canAddEmployee"
@click="addEmployee"
>
新增人员
</button>
替换为:
<div class="employee-head-actions">
<button
class="ghost-button node-action-button"
type="button"
:disabled="!selectedNode"
@click="openSelectedNodeMenu"
>
节点操作
</button>
<button
class="primary-button"
type="button"
:disabled="!canAddEmployee"
@click="addEmployee"
>
新增人员
</button>
</div>
- Step 2: 添加
openSelectedNodeMenu函数
在 openNodeMenu(payload) 下方添加:
function openSelectedNodeMenu(event) {
if (!selectedNode.value) {
return;
}
const rect = event.currentTarget?.getBoundingClientRect?.();
emit("node-contextmenu", {
node: selectedNode.value,
x: rect ? rect.left : event.clientX,
y: rect ? rect.bottom + 6 : event.clientY
});
}
说明:这里仍然只 emit node-contextmenu,由父组件现有 openContextMenu 接管菜单,不在子组件里实现动作。
- Step 3: 添加 scoped 样式
在 .employee-head 附近增加:
.employee-head-actions {
display: inline-flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 10px;
}
.node-action-button {
border: 1px solid rgba(148, 163, 184, 0.5);
background: #ffffff;
color: #334155;
}
.node-action-button:hover:not(:disabled) {
background: #eff6ff;
color: #1d4ed8;
}
- Step 4: 运行组件测试确认 Task 1 变绿
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP/frontend
node src/components/OrgPermissionTree.test.js
Expected:
# pass ...
Task 3: 锁定父页面复用同一套节点菜单
Files:
-
Modify:
frontend/src/views/SystemPermissionView.test.js -
Step 1: 写测试确认组织树和脑图共用
openContextMenu
在 SystemPermissionView.test.js 末尾追加:
describe("SystemPermissionView organization view action parity", () => {
it("routes both mind map and tree node actions through the same context menu action pipeline", () => {
assert.match(source, /<OrgMindMap[\s\S]*?@node-contextmenu="openContextMenu"/);
assert.match(source, /<OrgPermissionTree[\s\S]*?@node-contextmenu="openContextMenu"/);
assert.match(source, /const contextMenuActions = computed\(\(\) => \(contextMenu\.node \? nodeActions\(contextMenu\.node\) : \[\]\)\);/);
assert.match(source, /function runNodeAction\(actionKey, node\)/);
assert.match(source, /openOrgRenameDrawer\(node\)/);
assert.match(source, /openOrgManagerDrawer\(node\)/);
assert.match(source, /openOrgCreateDrawer\(node,\s*"DEPARTMENT"\)/);
assert.match(source, /openOrgEmployeeDrawer\(node\)/);
});
});
- Step 2: 运行测试
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP/frontend
node src/views/SystemPermissionView.test.js
Expected:
# pass ...
如果失败,说明当前源码实际函数名或字符串不同;不要新增第二套函数,先核对现有 nodeActions 和 runNodeAction,再调整测试为真实函数名。
Task 4: 优化上下文菜单打开位置与组织树使用体验
Files:
-
Modify:
frontend/src/views/SystemPermissionView.vue -
Step 1: 检查现有
openContextMenu
确认当前函数类似:
function openContextMenu(eventPayload) {
selectedNode.value = eventPayload.node;
contextMenu.visible = true;
contextMenu.x = eventPayload.x;
contextMenu.y = eventPayload.y;
contextMenu.node = eventPayload.node;
}
- Step 2: 改为带视口保护的位置计算
将 openContextMenu 替换为:
function openContextMenu(eventPayload) {
selectedNode.value = eventPayload.node;
const menuWidth = 220;
const menuHeight = 280;
const viewportWidth = window.innerWidth || 1280;
const viewportHeight = window.innerHeight || 720;
contextMenu.visible = true;
contextMenu.x = Math.max(12, Math.min(Number(eventPayload.x || 12), viewportWidth - menuWidth - 12));
contextMenu.y = Math.max(12, Math.min(Number(eventPayload.y || 12), viewportHeight - menuHeight - 12));
contextMenu.node = eventPayload.node;
}
说明:组织树右侧“节点操作”按钮会把菜单开在按钮下方;如果靠右或靠下,菜单不应跑出屏幕。
- Step 3: 运行父页面测试
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP/frontend
node src/views/SystemPermissionView.test.js
Expected:
# pass ...
Task 5: 手动浏览器验收
Files:
-
No code changes.
-
Step 1: 打开系统权限管理页面
Use in-app Browser:
http://localhost:5173/system-permissions
- Step 2: 验收组织树模式下组织节点操作
操作:
- 切换到“组织树模式”。
- 点击左侧“总公司”节点。
- 点击右侧“节点操作”。
Expected:
菜单出现,包含:重命名、添加该节点的主管、新增分公司节点。
- Step 3: 验收分公司节点操作
操作:
- 点击“旭升车间”或“嘉恒车间”。
- 点击“节点操作”。
Expected:
菜单出现,包含:重命名、添加该节点的主管、新增部门节点、删除节点。
- Step 4: 验收部门节点操作
操作:
- 点击“旭升加工部”或“嘉恒生产部”。
- 点击“节点操作”。
Expected:
菜单出现,包含:重命名、添加该节点的主管、新增小组节点、新增人员、删除节点。
- Step 5: 验收右键入口
操作:
- 在组织树左侧任意组织节点上右键。
Expected:
弹出的菜单内容和右侧“节点操作”按钮一致。
- Step 6: 验收人员操作仍正常
操作:
- 在右侧人员列表点击“人员授权”。
- 确认弹窗仍为卡片式角色授权界面。
- 关闭弹窗。
Expected:
人员授权弹窗打开正常,不受节点操作入口影响。
Task 6: 回归验证与提交
Files:
-
All modified files from earlier tasks.
-
Step 1: 运行关键测试
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP/frontend
node src/components/OrgPermissionTree.test.js
node src/views/SystemPermissionView.test.js
node src/utils/orgTreeEmployees.test.js
node src/App.test.js
Expected:
# fail 0
- Step 2: 运行构建
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP/frontend
npm run build
Expected:
✓ built
允许出现当前项目既有的大 chunk warning,不作为阻断。
- Step 3: 检查 diff
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP
git diff --stat
git diff -- frontend/src/components/OrgPermissionTree.vue frontend/src/components/OrgPermissionTree.test.js frontend/src/views/SystemPermissionView.vue frontend/src/views/SystemPermissionView.test.js
Expected:
只包含组织树动作入口、菜单位置保护、相关测试和少量样式。
- Step 4: 等用户确认后提交 main
Run only after user confirms:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP
git add frontend/src/components/OrgPermissionTree.vue frontend/src/components/OrgPermissionTree.test.js frontend/src/views/SystemPermissionView.vue frontend/src/views/SystemPermissionView.test.js
git commit -m "补齐组织树节点操作能力"
git push origin main
Expected:
main -> main
- Step 5: 同步 BH_DEV
Run only after main push succeeds:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP
git switch BH_DEV
git pull --ff-only origin BH_DEV
git cherry-pick <main_commit_hash>
Expected:
[BH_DEV <hash>] 补齐组织树节点操作能力
- Step 6: 在 BH_DEV 运行同样验证并推送
Run:
cd /Users/souplearn/Gitlab/py/ForgeFlow-ERP/frontend
node src/components/OrgPermissionTree.test.js
node src/views/SystemPermissionView.test.js
node src/utils/orgTreeEmployees.test.js
node src/App.test.js
npm run build
cd ..
git push origin BH_DEV
Expected:
BH_DEV -> BH_DEV
Self-Review
Spec coverage:
已覆盖“组织树和脑图只是展示不同,功能一致”的核心要求。组织树右键入口和显式“节点操作”入口都会进入现有 openContextMenu,菜单项仍由 nodeActions 根据节点类型动态决定。
Placeholder scan:
未使用 TBD/TODO/后续补充。每个任务都有具体文件、代码片段、命令和预期结果。
Type consistency:
计划中使用的函数名与当前代码一致:openContextMenu、nodeActions、runNodeAction、openOrgCreateDrawer、openOrgRenameDrawer、openOrgManagerDrawer、openOrgEmployeeDrawer、openAuthorizeDrawer、removeOrgEmployee、removeOrgNode。