2026-04-29-web-admin-super-admin-menu-region-design.md 14 KB

Web-Admin 超级管理员与运营数据/菜单权限改造设计

日期:2026-04-29
需求来源:运营端权限体系升级(用户确认版)

1. 已确认需求口径

  • 角色体系新增 super_admin(超级管理员),可查看所有菜单、所有区域数据。
  • 现有 admin 账号统一迁移为 super_admin。
  • 运营管理人员(沿用 admin)改为“多区域权限”模型。
  • 菜单授权粒度为“页面菜单级”(仅控制菜单/页面可见,不做按钮级权限)。
  • 菜单实现模式补充:web-admin 保持“前端静态菜单模式”,后端仅返回授权菜单 code 列表。
  • 菜单授权关系补充:运营管理人员与菜单通过 menu_code 建立关系并存库。
  • 超级管理员菜单规则:super_admin 始终全菜单可见,不受 code 授权限制。
  • 父级补齐规则:仅自动补齐顶级菜单;二级及以下菜单必须显式授权。
  • 在 用户管理 中:
    • 运营管理人员新增/编辑时,区域支持多选。
    • 增加“菜单权限管理”操作,支持从已有菜单中勾选授权。
    • 页面改造为“运营管理人员 Tab + 区域 Tab”双维度展示。
  • 具备区域概念的菜单需按运营管理人员区域权限做数据隔离:
    询价报价管理、订单列表、商家结算管理、客户结算管理、配送列表、时效预警、用户管理。
  • 订单列表、配送列表、时效预警 参考 商家结算管理 顶部区域 Tab 模式,仅展示有权限区域 Tab。
  • 需要向数据库插入测试运营管理员数据。

2. 现状评估(基于当前代码)

  • 当前后台权限校验以 role == "admin" 为主,尚无 super_admin 角色常量与判断分支。
  • 当前菜单接口 GET /web/menu/list 按 sys_menu 全量返回,尚未提供“当前用户授权菜单 code 列表”能力。
  • 当前 sys_user 只有单值 region_id,不支持多区域。
  • 当前 admin 模块已存在“管理员按区域过滤”基础逻辑,但依赖“单区域绑定”语义。
  • 当前 用户管理 页面弹窗中“所属区域”为单选。

结论:需要同时改造 角色模型 + 菜单授权模型 + 区域权限模型 + 前后端展示交互。


3. 方案对比(2-3 种)

方案 A:最小侵入扩展(推荐)

  • 新增关联表:
    • sys_user_region_scope(用户-区域多对多)
    • sys_user_menu_scope(用户-菜单 code 多对多)
  • sys_user.role 保留字符串角色,新增 super_admin 枚举值。
  • 保持前端静态菜单模式,仅新增“按用户返回菜单 code 列表”接口。
  • 复用现有业务接口,在查询入口统一接入“可见区域集合”过滤。

优点:

  • 对现有代码与表结构冲击小,实施风险最低。
  • 便于灰度:先迁移角色,再逐模块切换数据过滤。
  • 后续可扩展按钮级权限(新增 menu_type=button 过滤)但本期不实现。

缺点:

  • 权限语义分散在用户维度,不是标准 RBAC(角色-资源)模型。

方案 B:标准 RBAC 重构(本期不推荐)

  • 新建角色表、角色菜单表、用户角色表、用户区域范围表。
  • 将当前用户 role 字段转为兼容冗余字段或废弃。

优点:

  • 体系标准、长期可扩展性最佳。

缺点:

  • 变更面过大,涉及登录态、路由、所有鉴权分支,交付周期长,回归成本高。

方案 C:前端本地过滤为主(不推荐)

  • 后端继续返回全菜单/全数据,前端按登录信息过滤显示。

优点:

  • 开发快。

缺点:

  • 安全性不足(接口仍可访问未授权数据),不满足权限改造目标。

推荐结论

采用 方案 A,以“后端强约束 + 前端按授权展示”为原则落地。


4. 目标架构设计

4.1 角色模型

  • super_admin:全菜单、全区域、全数据。
  • admin(运营管理人员):仅可见授权菜单,且仅可见授权区域数据。
  • 其他业务角色(supplier/client/deliver)保持原语义。

4.2 区域权限模型

  • 运营管理人员通过 sys_user_region_scope 绑定多个区域。
  • 查询时优先规则:
    • super_admin:不过滤区域。
    • admin:仅允许 region_id in 可见区域集合。

4.3 菜单权限模型(菜单级 + code 驱动)

  • 运营管理人员通过 sys_user_menu_scope 绑定可见菜单 menu_code。
  • 前端菜单源保持 web-admin 本地默认菜单树(静态)。
  • 登录后额外拉取当前用户 allowedMenuCodes:
    • super_admin:返回标识 all=true(或空集 + isSuperAdmin=true),前端不过滤。
    • admin:返回授权 code 集合。
  • 前端过滤规则:
    • 命中授权 code 的菜单显示;
    • 顶级父菜单可自动补齐;
    • 二级及以下不自动补齐,必须显式授权 code。
  • 后端安全规则:
    • 本期菜单权限仅用于前端可见性控制,不做接口级 menu_code 鉴权;
    • 接口侧仅保留角色与区域权限强校验。

4.4 数据权限应用范围

  • 必须接入区域过滤的模块:
    • 询价报价管理
    • 订单列表
    • 商家结算管理
    • 客户结算管理
    • 配送列表
    • 时效预警
    • 用户管理

5. 数据库设计(满足项目规范)

5.1 变更点

表 1:sys_user(增量)

  • role 增加可选值:super_admin。

表 2:sys_user_region_scope(新增)

  • 用于运营管理人员多区域授权。
  • 字段建议:
    • id VARCHAR(32) PK
    • user_id VARCHAR(32) 非空
    • region_id VARCHAR(32) 非空
    • is_del TINYINT 默认 0
    • create_at DATETIME
    • create_by VARCHAR(32)
    • create_name VARCHAR(100)
    • update_at DATETIME
    • update_by VARCHAR(32)
  • 唯一索引建议:(user_id, region_id, is_del)。

表 3:sys_user_region_scope_his(新增历史表)

  • 与主表同结构,去掉 is_del,id 不做唯一限制,不建索引。

表 4:sys_user_menu_scope(新增)

  • 用于运营管理人员菜单授权。
  • 字段建议:
    • id VARCHAR(32) PK
    • user_id VARCHAR(32) 非空
    • menu_code VARCHAR(100) 非空
    • is_del TINYINT 默认 0
    • create_at DATETIME
    • create_by VARCHAR(32)
    • create_name VARCHAR(100)
    • update_at DATETIME
    • update_by VARCHAR(32)
  • 唯一索引建议:(user_id, menu_code, is_del)。

表 5:sys_user_menu_scope_his(新增历史表)

  • 与主表同结构,去掉 is_del,id 不做唯一限制,不建索引。

6. 接口改造设计

6.1 认证与用户信息

  • 登录返回 userInfo.role 支持 super_admin。
  • current-user 返回新增:
    • regionIds: string[](运营管理人员可见区域)
    • isSuperAdmin: boolean

6.2 菜单接口(code 模式)

  • 保留 GET /web/menu/list 仅用于管理端菜单维护场景(非登录态菜单渲染依赖)。
  • 新增(或替代)接口:
    • GET /web/auth/menu-codes:返回当前登录用户授权菜单 code 集合与 isSuperAdmin。
    • GET /web/admin/menus/assignable-codes:可授权菜单 code 列表(含层级信息,来源于 sys_menu.code)。
    • GET /web/admin/users/{id}/menu-scopes:查询用户菜单授权 code 列表。
    • PUT /web/admin/users/{id}/menu-scopes:更新用户菜单授权(按 code 全量覆盖)。

6.2.1 菜单权限边界(实现约束)

  • 本期菜单权限边界:只控制“前端菜单可见性”。
  • 不实现接口级 menu_code 鉴权,避免接口粒度过细带来的测试复杂度。
  • 接口安全仍由“角色权限 + 区域权限”承担:
    • 非运营角色不可访问运营接口;
    • 运营仅可访问授权区域数据;
    • 区域越权统一返回 403。

6.3 用户管理接口

  • GET /web/admin/users:
    • 运营管理人员仅能看到其区域范围内数据(且允许查看超管+运营在“运营管理人员 Tab”)。
  • POST /web/admin/users / PUT /web/admin/users/{id}:
    • 对 admin 角色支持 regionIds 多选写入。
    • super_admin 不要求区域绑定。
  • 角色列表 GET /web/admin/roles 增加 super_admin。

6.4 区域过滤相关业务接口

  • 在目标模块列表/详情查询入口统一注入 allowed_region_ids。
  • 当请求传入 regionId 时必须校验是否属于授权范围,否则返回 403。

7. 前端(web-admin)交互设计

7.1 菜单显示

  • 登录后先读取当前用户 allowedMenuCodes,再过滤前端默认静态菜单树。
  • super_admin 不做菜单过滤,直接展示前端默认全菜单。
  • admin 菜单按 code 过滤,且仅自动补齐顶级父菜单。
  • 无任何授权菜单的运营管理人员,展示“暂无菜单权限”空状态页。

7.1.1 code 单一真源与一致性(新增)

  • 单一真源约定:
    • 前端菜单渲染真源:web-admin 本地静态路由中的 name/code。
    • 后端授权真源:sys_menu.code,并要求与前端静态路由 code 一致。
  • 一致性校验机制:
    • 启动校验(推荐):后端启动时检查 sys_menu.code 与约定 code 字典是否存在差异,差异写日志告警。
    • CI 校验(推荐):新增脚本比对“前端 code 清单 vs 数据库基线 SQL code 清单”,差异时阻断发布。
  • 运维规则:
    • 新增/修改菜单必须同步更新前端静态菜单 code 与 sys_menu.code,否则视为变更不完整。

7.2 用户管理页改造

  • 顶部改为双层 Tab:
    • 第一层:运营管理人员、区域用户
    • 第二层(区域维度):按当前登录用户可见区域动态显示
  • 运营管理人员 Tab:
    • 展示 super_admin + admin
    • 支持新增/编辑这两类角色
    • admin 编辑弹窗中“所属区域”改为多选
    • 行操作新增“菜单权限管理”弹窗(树形勾选)
  • 区域用户 Tab:
    • 展示 client/supplier/deliver
    • 支持新增/编辑这三类角色

7.3 订单/配送/时效预警页面

  • 参考商家结算管理顶部区域 Tab 风格:
    • 仅渲染登录用户有权限的区域 Tab。
    • 切换 Tab 即带入对应 regionId 查询。
  • super_admin 默认可见全部区域 Tab。

8. 迁移策略

8.1 角色迁移(已确认)

  • 一次性将现有 sys_user.role='admin' 批量更新为 super_admin。
  • 后续由超级管理员创建新的运营管理人员(admin)。

8.2 回滚策略

  • 保留迁移 SQL 与反向 SQL:
    • 正向:admin -> super_admin
    • 反向:super_admin -> admin(仅紧急回滚使用)

8.3 割接执行顺序(新增,强约束)

  1. 上线数据库增量(sys_user_region_scope*、sys_user_menu_scope*)与兼容代码(不切主流程)。
  2. 上线菜单 code 接口(仅用于前端菜单过滤),不启用接口级菜单守卫。
  3. 由当前管理员创建测试运营账号并完成区域+菜单授权,完成联调回归。
  4. 执行 admin -> super_admin 迁移 SQL(维护窗口内执行)。
  5. 迁移后立即执行冒烟:
    • super_admin 全菜单可见;
    • 运营账号仅见授权菜单;
    • 区域外数据不可见。
  6. 通过后进入常规发布;若失败按回滚策略恢复。

9. 测试数据 SQL(含你要求的测试运营管理员)

-- 1) 角色迁移:admin -> super_admin
UPDATE sys_user
SET role = 'super_admin', update_at = NOW()
WHERE is_del = 0 AND role = 'admin';

-- 2) 插入测试运营管理员(admin)
-- 注意:password_hash 需替换为项目实际哈希算法生成值(示例占位)
INSERT INTO sys_user (
  id, username, password_hash, real_name, phone, role, region_id, is_active, is_del,
  create_at, create_by, create_name, update_at, update_by
) VALUES
('op_admin_001_32char_id_xxxxxx01', 'op_admin_a', 'REPLACE_WITH_HASH', '运营A', '13800000001', 'admin', NULL, 1, 0, NOW(), 'seed', 'seed', NOW(), 'seed'),
('op_admin_002_32char_id_xxxxxx02', 'op_admin_b', 'REPLACE_WITH_HASH', '运营B', '13800000002', 'admin', NULL, 1, 0, NOW(), 'seed', 'seed', NOW(), 'seed');

-- 3) 绑定测试运营管理员多区域(示例)
INSERT INTO sys_user_region_scope (
  id, user_id, region_id, is_del, create_at, create_by, create_name, update_at, update_by
) VALUES
('urs_001_32char_id_xxxxxxxxxx01', 'op_admin_001_32char_id_xxxxxx01', 'region_id_east', 0, NOW(), 'seed', 'seed', NOW(), 'seed'),
('urs_002_32char_id_xxxxxxxxxx02', 'op_admin_001_32char_id_xxxxxx01', 'region_id_west', 0, NOW(), 'seed', 'seed', NOW(), 'seed'),
('urs_003_32char_id_xxxxxxxxxx03', 'op_admin_002_32char_id_xxxxxx02', 'region_id_south', 0, NOW(), 'seed', 'seed', NOW(), 'seed');

-- 4) 绑定测试运营管理员菜单权限(示例,menu_code 需替换为 sys_menu.code)
INSERT INTO sys_user_menu_scope (
  id, user_id, menu_code, is_del, create_at, create_by, create_name, update_at, update_by
) VALUES
('ums_001_32char_id_xxxxxxxxxx01', 'op_admin_001_32char_id_xxxxxx01', 'Order', 0, NOW(), 'seed', 'seed', NOW(), 'seed'),
('ums_002_32char_id_xxxxxxxxxx02', 'op_admin_001_32char_id_xxxxxx01', 'OrderList', 0, NOW(), 'seed', 'seed', NOW(), 'seed'),
('ums_003_32char_id_xxxxxxxxxx03', 'op_admin_002_32char_id_xxxxxx02', 'Delivery', 0, NOW(), 'seed', 'seed', NOW(), 'seed');

10. 验收标准(UAT)

  • 超级管理员登录后:
    • 可见全部菜单、全部区域 Tab、全部数据。
  • 运营管理人员登录后:
    • 仅可见授权菜单。
    • 仅可见授权区域 Tab。
    • 仅可查询授权区域的数据(接口层强校验)。
  • 用户管理:
    • 可为运营管理人员配置多区域。
    • 可为运营管理人员配置菜单权限。
    • 双层 Tab 交互与展示符合定义。
  • 未授权访问:
    • 前端菜单不可见;
    • 后端仅对区域越权返回 403。

11. 风险与控制

  • 风险 1:code 过滤后菜单层级不完整导致导航异常。
    控制:仅自动补齐顶级父菜单,授权弹窗中明确提示“二级及以下需显式授权”。
  • 风险 2:区域过滤遗漏导致越权。
    控制:抽取统一 allowed_region_ids 过滤函数,在模块接口层强制调用。
  • 风险 3:历史 admin 全量迁移后短期无人可用。
    控制:迁移脚本与测试运营管理员插入脚本同批执行。

12. 本设计结论

本期按“超级管理员全权限 + 前端静态菜单(code 过滤) + 运营管理人员多区域数据权限”落地;菜单权限仅作用于前端可见性,接口侧保持角色与区域权限校验。