library-picturebook-activity/docs/design/menu-config.md
zhonghua 7384a0423c feat: 工作台仪表盘补全、快捷操作与租户菜单优化
- TenantDashboard: 快捷操作去掉用户管理;最近活动依赖后端 recentContests

- ContestServiceImpl: getDashboard 返回最近活动、进行中、待审、今日报名及租户信息

- 机构管理: 子菜单全未选时剔除父菜单 ID(pruneOrphanParentMenuIds)

- 菜单管理: AntdIconPicker 与表单调整;设计文档同步

Made-with: Cursor
2026-04-09 18:25:13 +08:00

14 KiB
Raw Blame History

各端菜单配置规范

最后更新2026-04-08 维护人:开发团队

本文档记录各端的正确菜单配置,是菜单分配的唯一权威来源。修改菜单时必须对照此文档。


快速参考:各端登录信息

租户编码 登录URL 用户名 密码 角色
超管端 super /super/login admin admin123 super_admin
广东省图端(租户端) gdlib /gdlib/login admin admin123 tenant_admin
评委端 judge /judge/login admin admin123 judge
公众端 /p/login 自主注册 public_user

注意在同一浏览器中切换不同端时需要先登出或清除缓存localStorage否则旧 token 会导致跳转错误。建议用无痕窗口测试不同端。


一、超管端tenant_id=1, code='super')— 21条

定位:只读监管,不含操作类功能。

一级菜单5 个(活动监管、内容管理、机构管理、用户中心、系统设置)

不包含:数据统计(租户端专属)、活动管理(租户端专属)、我的评审(评委端专属)

活动监管 (id=37) ← 只读监管视角
├── 全部活动 (38)
├── 报名数据 (39)
├── 作品数据 (40)
├── 评审进度 (41)
└── 活动成果 (44)

内容管理 (id=46)
├── 作品审核 (47)
├── 作品管理 (48)
└── 标签管理 (49)

机构管理 (id=28)
└── 机构管理 (30)

用户中心 (id=29)
├── 用户管理 (32)
└── 角色管理 (33)

系统设置 (id=14)
├── 菜单管理 (17)
├── 数据字典 (18)
├── 系统配置 (19)
├── 日志记录 (20)
└── 权限管理 (21)

tenant_menus ID 列表21条

14, 17, 18, 19, 20, 21, 28, 29, 30, 32, 33, 37, 38, 39, 40, 41, 44, 46, 47, 48, 49

超管端不包含的菜单及原因

菜单 ID 原因
评委管理 42 操作类功能,属于租户端活动管理
评审规则 43 操作类功能,属于租户端活动管理
通知管理 45 操作类功能,属于租户端活动管理
数据统计 52,53,54 设计文档明确标注"所属端:租户端"(见 docs/design/org-admin/data-analytics-dashboard.md
活动管理 9 及子菜单 租户端操作菜单,超管用"活动监管"代替
我的评审 34,35,36 评委端专属
工作台 50 租户端工作台(TenantDashboard),超管端不需要
学校管理 2 及子菜单 已剥离(代码移至 competition-management-system-stripped-modules/

二、租户端(以 gdlib id=9 为例)— 18条

定位:机构管理员操作端,含全部业务操作功能。

一级菜单4 个(工作台、数据统计、活动管理、系统设置)

工作台 (id=50) ← TenantDashboard
  页面内容:欢迎信息 + 6个统计卡片 + 快捷操作 + 待办提醒 + 最近活动
  快捷操作:活动列表、报名管理、作品管理、评委管理(按权限显示;不含用户管理,见系统设置)

数据统计 (id=52) ← 租户端专属
├── 运营概览 (53) — 指标卡片 + 漏斗图 + 月度趋势 + 活动对比
└── 评审分析 (54) — 效率指标 + 评委工作量 + 奖项分布

活动管理 (id=9) ← 含全部操作功能(创建/编辑/审核/评委/评分/发布)
├── 活动列表 (10) — 创建、发布、编辑活动
├── 评委管理 (23) — 添加/移除评委、设置权重
├── 报名管理 (11) — 审核报名、添加指导老师
├── 作品管理 (12) — 查看作品、版本管理
├── 评审进度 (25) — 分配作品、查看进度
├── 评审规则 (26) — 创建/编辑评审规则和维度
├── 成果发布 (24) — 计算得分/排名、设置奖项、发布成果
└── 活动公告 (27) — 创建/编辑活动公告

系统设置 (id=14) ← 精简版
├── 机构信息 (51) — 查看/编辑机构名称和描述、复制登录地址
├── 用户管理 (15) — 本租户用户 CRUD
├── 角色管理 (16) — 本租户角色和权限分配
└── 日志记录 (20) — 操作日志查看

tenant_menus ID 列表18条

9, 10, 11, 12, 14, 15, 16, 20, 23, 24, 25, 26, 27, 50, 51, 52, 53, 54

租户评委与平台评委(菜单一致)

  • 平台评委:在评委租户(code=judge)登录,见第三节「评委端」,t_sys_tenant_menu 仅含 34、35、36
  • 租户评委:在机构租户(如 tenantCode=test2)登录,角色为 judge,与平台评委使用同一套「我的评审」菜单(仍为 34、35、36 对应的 componentactivities/Reviewactivities/PresetComments 及父级)。
  • 实现GET /api/menus/user-menusSysMenuServiceImpl.getUserMenus 中,若当前用户角色含 judge,会在 t_sys_tenant_menu 基础上合并评委端菜单(按组件路径识别,不依赖固定 ID评委角色权限由 JudgeRolePermissionConfigurerJudgesManagementServiceImpl 保证与上表「评委端权限码」一致,以便 /api/auth/user-infopermissions 与菜单 permission 字段匹配。纯评委(仅有 judge、无 tenant_admin/super_admin不展示机构端「评委管理」菜单(component=contests/judges/Index),避免与 judge:read 权限码重叠导致误显。
  • 可选:若希望机构租户在「菜单管理」中显式看到评委菜单,也可在 t_sys_tenant_menu 中手工追加 34、35、36(与第三节一致),与合并逻辑效果相同。

租户端系统设置不包含的子菜单

菜单 ID 原因
菜单管理 17 平台级功能,超管专属
数据字典 18 平台级功能,超管专属
系统配置 19 平台级功能,超管专属
权限管理 21 平台级功能,超管专属
租户管理 22 平台级功能,超管专属

新建租户时的菜单分配

创建新租户时,应分配与 gdlib 相同的菜单列表18条。在 SysTenantServiceImpl.createTenant 中实现。


三、评委端tenant_id=7, code='judge')— 3条

定位:评委评审工作台,只能看到自己被分配的活动和作品。租户评委(机构租户下的 judge 角色)与平台评委共用本节菜单与权限码。

详细接口与字段说明评委端评审任务

一级菜单1 个(我的评审)

我的评审 (id=34)
├── 评审任务 (35) — 查看分配的活动、作品列表、打分
└── 预设评语 (36) — 管理评审常用评语模板,支持跨活动同步

tenant_menus ID 列表3条

34, 35, 36

评委端权限码

权限码 用途
review:score 提交/更新评分
review:read 查看评审数据
review:create 创建评审记录
review:update 更新评审记录
activity:read 查看活动列表
judge:read 查看评委信息
judge:assign 分配评审
work:read 查看作品
notice:read 查看公告
workbench:read 查看工作台

四、公众端tenant_id=8, code='public'

公众端不使用动态菜单系统,路由固定在前端 router/index.ts 中。

导航结构

顶部导航栏Web 端)/ 底部 TabH5 移动端):
├── 发现 (/p/gallery)        — 作品广场,推荐+标签+搜索
├── 活动 (/p/activities)     — 活动大厅,浏览+报名
├── 创作 (/p/create)         — 绘本创作4步流程
├── 作品库 (/p/works)        — 我的作品(草稿/审核中/已发布)
└── 我的 (/p/mine)           — 个人中心
    ├── 个人信息              — 昵称/城市/性别
    ├── 我的报名              — 报名记录+审核状态
    ├── 我的收藏              — 收藏的作品
    └── 子女管理              — 添加子女/创建子女账号/切换身份

公众端权限码

权限码 用途
activity:read 浏览活动
registration:create 报名活动
work:create 创建作品
child:manage 子女管理

无需认证的接口(@Public

  • GET /public/activities — 活动列表
  • GET /public/activities/:id — 活动详情
  • GET /public/gallery — 作品广场
  • GET /public/gallery/recommended — 推荐作品
  • GET /public/gallery/:id — 作品详情
  • GET /public/tags — 标签列表
  • GET /public/tags/hot — 热门标签
  • POST /public/auth/register — 注册
  • POST /public/auth/login — 登录

五、完整菜单 ID 对照表

ID 名称 父ID 组件 所属端
1 工作台(旧) workbench/Index 废弃
2 学校管理 已剥离
3-8 学校子菜单 2 school/* 已剥离
9 活动管理 租户端
10 活动列表 9 contests/Index 租户端
11 报名管理 9 contests/registrations/Index 租户端
12 作品管理 9 contests/works/Index 租户端
14 系统设置 超管+租户
15 用户管理 14 system/users/Index 租户端
16 角色管理 14 system/roles/Index 租户端
17 菜单管理 14 system/menus/Index 超管端
18 数据字典 14 system/dict/Index 超管端
19 系统配置 14 system/config/Index 超管端
20 日志记录 14 system/logs/Index 超管+租户
21 权限管理 14 system/permissions/Index 超管端
22 租户管理 14 system/tenants/Index 超管用28/30代替
23 评委管理 9 contests/judges/Index 租户端
24 成果发布 9 contests/results/Index 租户端
25 评审进度 9 contests/reviews/Progress 租户端
26 评审规则 9 contests/ReviewRules 租户端
27 活动公告 9 contests/notices/Index 租户端
28 机构管理 超管端
29 用户中心 超管端
30 机构管理(列表) 28 system/tenants/Index 超管端
32 用户管理(超管) 29 system/users/Index 超管端
33 角色管理(超管) 29 system/roles/Index 超管端
34 我的评审 评委端
35 评审任务 34 activities/Review 评委端
36 预设评语 34 activities/PresetComments 评委端
37 活动监管 超管端
38 全部活动 37 contests/Index 超管端
39 报名数据 37 contests/registrations/Index 超管端
40 作品数据 37 contests/works/Index 超管端
41 评审进度 37 contests/reviews/Progress 超管端
42 评委管理 37 contests/judges/Index 超管端不用
43 评审规则 37 contests/reviews/Index 超管端不用
44 活动成果 37 contests/results/Index 超管端
45 通知管理 37 contests/notices/Index 超管端不用
46 内容管理 超管端
47 作品审核 46 content/WorkReview 超管端
48 作品管理 46 content/WorkManagement 超管端
49 标签管理 46 content/TagManagement 超管端
50 工作台 workbench/TenantDashboard 租户端
51 机构信息 14 system/tenant-info/Index 租户端
52 数据统计 租户端
53 运营概览 52 analytics/Overview 租户端
54 评审分析 52 analytics/Review 租户端

六、技术实现要点

菜单加载逻辑Java: SysMenuServiceImpl.getUserMenus

1. 查询所有 valid_state=1 的菜单
2. 查询当前用户 tenant_id 对应的 t_sys_tenant_menu
3. 按 tenant_menus 过滤菜单;若用户角色含 judge且非超管合并评委端菜单 ID评审任务/预设评语及其父级,按 component 识别)
4. 如果是超管(isSuperAdmin):不做权限码过滤
5. 如果是普通用户:按用户权限码过滤(菜单.permission 字段匹配用户 permissions
6. 补全父菜单(确保树结构完整)
7. 构建树形结构返回

⚠️ 重要:超管也必须按 tenant_menus 过滤,不能返回全部菜单。之前的 bug 就是超管返回全部 52 个菜单导致错乱。

评委角色judge 角色须绑定「评委端权限码」中的权限(见 JudgeRolePermissionConfigurer),否则 permissions 为空会导致第 5 步过滤掉所有菜单。

登录时租户识别

前端通过 URL 提取 tenantCode/gdlib/logintenantCode=gdlib),登录请求:

POST /api/auth/login
{"username": "admin", "password": "xxx", "tenantCode": "gdlib"}

Java 后端 AuthService.login 支持两种方式确定租户:

  1. X-Tenant-Id header数字ID优先
  2. body 中的 tenantCode(编码),后端通过 t_sys_tenant.code 查找租户ID

前端组件映射

菜单的 component 字段对应前端 menu.ts 中的 componentMap。如果某个 component 路径未在 componentMap 中注册,控制台会输出警告。已剥离的学校管理模块会有 6 条 warning属预期行为。

权威来源

来源 用途
docs/design/menu-config.md 本文档,菜单配置唯一权威
backend-java/.../JudgeRolePermissionConfigurer.java 评委角色权限码补全、judge/gdlib 模板复制
backend/data/menus.json 菜单定义(所有菜单的字段)
backend/scripts/init-menus.ts 菜单初始化脚本SUPER_TENANT_MENUS / NORMAL_TENANT_MENUS
t_sys_menu 数据库中的菜单数据
t_sys_tenant_menu 各端的菜单分配关系