# 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(含你要求的测试运营管理员) ```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 过滤) + 运营管理人员多区域数据权限**”落地;菜单权限仅作用于前端可见性,接口侧保持角色与区域权限校验。