Files
docs/superpowers/specs/2026-07-27-admin-permission-tree-design.md

4.0 KiB
Raw Permalink Blame History

Admin 权限树分组同步设计

目标

让权限管理和角色授权中的资源层级与已完成的 admin 侧边栏一致,并支持后续继续增加更深层级,而不需要修改页面的树构建逻辑。

方案选择

有三种可选方式:

  1. 在权限页面和角色页面分别编写递归逻辑。改动直接,但会产生两份容易漂移的实现。
  2. 使用共享的权限树构建器。两个页面消费同一棵树,筛选、排序和层级行为一致,作为本次采用方案。
  3. 直接从侧边栏导航生成权限树。可以保证菜单一致,但导航不包含按钮和接口权限,且未来后端动态权限尚未确定,不适合当前阶段。

权限层级

静态权限数据调整为:

工作台

业务管理
├── 客户管理
│   ├── 新增客户
│   └── 审核客户
└── 头程订单
    ├── 创建订单
    └── 更新状态

系统管理
├── 内部用户
│   └── 维护用户
├── 角色管理
│   └── 角色授权
└── 菜单权限
    └── 维护权限

“业务管理”和“系统管理”是目录;“工作台、客户管理、头程订单、内部用户、角色管理、菜单权限”是菜单;具体操作是按钮权限。菜单本身使用现有路由权限编码,例如 customer:list 和 system:role:list,不再额外保留同义的“查看客户”“查看角色”节点。

接口权限待 Java 接口契约确定后再补充。本次不根据静态 URL 猜测接口资源;现有按钮权限上的临时 /api/... 路径和 HTTP 方法一并清空,按钮只保留稳定的权限编码。

共享树构建器

在 src/utils/permissionTree.ts 提供纯函数:

  • 根据 parentId 递归构建任意深度的权限树。
  • 同级按 sort 排序。
  • 接收可选匹配函数;子节点匹配时保留完整祖先链。
  • 防止异常循环引用造成无限递归。
  • 提供后代 ID 查询,编辑上级资源时排除自身及全部后代,避免创建循环。

权限管理页面使用完整 Permission 节点,以便编辑、启停和添加下级。角色页面将同一结果映射为 Element Plus 树需要的 id、label、code 和 children。

静态角色授权

同步更新五个模拟角色的 permissionIds:

  • 超级管理员拥有全部资源。
  • 运营主管拥有工作台、业务管理、客户审核、订单查看和状态处理。
  • 操作员拥有工作台及头程订单创建、处理权限。
  • 财务拥有工作台及头程订单查看权限。
  • 销售拥有工作台、客户维护及头程订单查看权限。

分组目录 ID 一并保留在角色授权中,以确保回显和父子半选状态明确。

页面行为

权限管理:

  • 默认展开完整三级树。
  • 搜索命中按钮时仍显示所属菜单及目录。
  • 新增下级、编辑、启停继续使用现有静态交互。
  • 编辑上级资源时不能选择自身或自己的后代。

角色管理:

  • 授权抽屉展示相同的目录、菜单和按钮层级。
  • 保存时继续合并已选和半选节点。
  • 权限摘要按菜单与操作分别计数,不把目录计入菜单数量。

测试与验收

使用 admin 现有 Vitest:

  • 先写失败测试固定三级结构和同级排序。
  • 验证搜索命中深层节点时保留祖先链。
  • 验证循环引用不会导致递归失控。
  • 验证后代 ID 查询能阻止把节点移动到自己的后代下。
  • 验证静态权限编码与导航叶子权限编码一致。

最后执行 pnpm test、pnpm typecheck、pnpm build,并在浏览器检查权限管理页面和角色授权抽屉的桌面及移动端层级展示。UI 改动完成后运行一次 Impeccable 检测。

完成标准

  • 权限管理和角色授权不再显示五个独立一级业务目录。
  • 两个页面使用同一个递归树构建器。
  • 搜索、排序、授权回显和静态编辑交互保持可用。
  • 不新增真实 API 调用或猜测后端响应格式。
  • 测试、类型检查、构建及浏览器验收通过。