library-picturebook-activity/docs/legacy/DYNAMIC_MENU_GUIDE.md
aid 418aa57ea8 Day4: 超管端设计优化 + UGC绘本创作社区P0实现
一、超管端设计优化
- 文档管理SOP体系建立,docs目录重组
- 统一用户管理:跨租户全局视角,合并用户管理+公众用户
- 活动监管全模块重构:全部活动(统计卡片+阶段筛选+SuperDetail详情页)、报名数据/作品数据/评审进度(两层合一扁平列表)、成果发布(去Tab+统计+隐藏写操作)
- 菜单精简:移除评委管理/评审规则/通知管理
- Bug修复:租户编辑丢失隐藏菜单、pageSize限制、主色统一

二、UGC绘本创作社区P0
- 数据库:10张新表(user_works/user_work_pages/work_tags等)
- 子女账号独立化:Child升级为独立User,家长切换+独立登录
- 用户作品库:CRUD+发布审核,8个API
- AI创作流程:提交→生成→保存到作品库,4个API
- 作品广场:首页改造为推荐流,标签+搜索+排序
- 内容审核(超管端):作品审核+作品管理+标签管理
- 活动联动:WorkSelector作品选择器
- 布局改造:底部5Tab(发现/创作/活动/作品库/我的)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:20:25 +08:00

6.7 KiB
Raw Blame History

动态菜单系统实现指南

📋 概述

已成功将菜单管理模块扩展为完全动态化的菜单生成系统。系统现在支持:

  • 从数据库动态加载菜单
  • 根据用户权限自动过滤菜单
  • 动态生成路由配置
  • 动态生成侧边栏菜单
  • 支持多级菜单结构
  • 菜单级别的权限控制

🏗️ 架构设计

后端架构

数据库 (Menu表)
  ↓
MenusService.findUserMenus()
  ↓
根据用户权限过滤菜单
  ↓
返回树形菜单结构

前端架构

用户登录
  ↓
获取用户菜单 (API)
  ↓
存储到 Auth Store
  ↓
转换为路由配置 (convertMenusToRoutes)
  ↓
动态注册路由 (router.addRoute)
  ↓
转换为菜单项 (convertMenusToMenuItems)
  ↓
渲染到侧边栏

🔧 实现细节

1. 数据库 Schema 更新

Menu 模型中添加了 permission 字段:

model Menu {
  // ... 其他字段
  permission String? /// 权限编码用于控制菜单显示menu:read
  // ... 其他字段
}

需要运行数据库迁移:

cd backend
npx prisma migrate dev --name add_menu_permission

2. 后端 API

新增接口:GET /menus/user-menus

获取当前用户的菜单(根据权限自动过滤)

响应示例:

[
  {
    "id": 1,
    "name": "系统管理",
    "path": "/system",
    "icon": "SettingOutlined",
    "permission": null,
    "children": [
      {
        "id": 2,
        "name": "用户管理",
        "path": "/system/users",
        "component": "system/users/Index",
        "permission": "user:read"
      }
    ]
  }
]

3. 前端工具函数

创建了 frontend/src/utils/menu.ts,包含:

  • convertMenusToMenuItems(): 将数据库菜单转换为 Ant Design Vue Menu 格式
  • convertMenusToRoutes(): 将数据库菜单转换为 Vue Router 路由配置
  • getIconComponent(): 动态加载图标组件
  • flattenMenus(): 扁平化菜单树

4. Auth Store 扩展

auth.ts 中添加了:

  • menus: 存储用户菜单数据
  • fetchUserMenus(): 获取用户菜单
  • 登录时自动获取菜单
  • 登出时清空菜单

5. 路由动态注册

router/index.ts 中:

  • 基础路由登录页、404等保持静态
  • 业务路由从数据库动态加载
  • 登录后自动注册动态路由
  • 支持路由权限检查

6. 布局组件更新

BasicLayout.vue 现在:

  • authStore.menus 读取菜单数据
  • 使用 convertMenusToMenuItems() 转换菜单
  • 自动展开包含当前路径的父菜单

📝 使用方法

1. 创建菜单

在菜单管理界面创建菜单时,需要填写:

  • 菜单名称: 显示名称
  • 路由路径: 如 /system/users
  • 图标: Ant Design Icons 名称,如 UserOutlined
  • 组件路径: Vue 组件路径,如 system/users/Index(相对于 @/views/
  • 权限编码: 可选,如 user:read(留空则所有用户可见)
  • 父菜单: 可选,用于创建多级菜单
  • 排序: 数字,控制显示顺序

2. 权限控制

菜单级别权限

在菜单的"权限编码"字段设置权限码,如:

  • user:read - 需要用户查看权限
  • role:create - 需要角色创建权限
  • 留空 - 所有用户可见

路由级别权限

菜单的权限会自动添加到路由的 meta.permissions 中,路由守卫会自动检查。

3. 组件路径规则

组件路径应该相对于 frontend/src/views/ 目录:

  • system/users/Index@/views/system/users/Index.vue
  • dashboard/Index@/views/dashboard/Index.vue
  • @/views/system/users/Index (不需要 @/views/ 前缀)

🔄 工作流程

用户登录流程

1. 用户输入账号密码
   ↓
2. 调用 login API
   ↓
3. 获取 token 和用户信息
   ↓
4. 调用 fetchUserMenus() 获取菜单
   ↓
5. 菜单数据存储到 authStore.menus
   ↓
6. 动态路由注册 (addDynamicRoutes)
   ↓
7. 跳转到首页

页面访问流程

1. 用户访问 /system/users
   ↓
2. 路由守卫检查认证
   ↓
3. 检查路由权限 (meta.permissions)
   ↓
4. 如果通过,渲染组件
   ↓
5. BasicLayout 显示侧边栏菜单

🎯 示例场景

场景1: 创建带权限的菜单

  1. 进入"菜单管理"
  2. 点击"新增菜单"
  3. 填写:
    • 名称: 用户管理
    • 路径: /system/users
    • 图标: UserOutlined
    • 组件路径: system/users/Index
    • 权限编码: user:read
  4. 保存

结果:只有拥有 user:read 权限的用户才能看到此菜单。

场景2: 创建多级菜单

  1. 创建父菜单:

    • 名称: 系统管理
    • 路径: /system
    • 图标: SettingOutlined
    • (不填组件路径和权限编码)
  2. 创建子菜单:

    • 名称: 用户管理
    • 路径: /system/users
    • 父菜单: 选择"系统管理"
    • 组件路径: system/users/Index

结果:侧边栏显示为:

系统管理
  └─ 用户管理

⚠️ 注意事项

  1. 数据库迁移: 添加 permission 字段后,需要运行 Prisma 迁移
  2. 组件路径: 确保组件文件存在,否则路由会失败
  3. 权限编码: 必须与权限系统中定义的权限码一致
  4. 路由名称: 自动生成,基于路径(如 /system/usersSystemUsers
  5. 动态路由: 只在登录后添加一次,刷新页面不会重复添加

🐛 故障排除

菜单不显示

  1. 检查菜单的 validState 是否为 1有效
  2. 检查用户是否有菜单对应的权限
  3. 检查浏览器控制台是否有错误

路由404

  1. 检查组件路径是否正确
  2. 检查组件文件是否存在
  3. 检查路由是否已动态注册(查看 Vue DevTools

图标不显示

  1. 检查图标名称是否正确Ant Design Icons
  2. 检查图标是否已导入到项目中

📚 相关文件

  • 后端菜单服务: backend/src/menus/menus.service.ts
  • 后端菜单控制器: backend/src/menus/menus.controller.ts
  • 前端菜单工具: frontend/src/utils/menu.ts
  • 前端路由配置: frontend/src/router/index.ts
  • 前端布局组件: frontend/src/layouts/BasicLayout.vue
  • 前端菜单管理: frontend/src/views/system/menus/Index.vue

🚀 下一步优化建议

  1. 菜单缓存: 可以缓存菜单数据减少API调用
  2. 菜单刷新: 提供手动刷新菜单的功能
  3. 菜单搜索: 在侧边栏添加菜单搜索功能
  4. 菜单收藏: 允许用户收藏常用菜单
  5. 菜单拖拽排序: 在管理界面支持拖拽排序