一、超管端设计优化 - 文档管理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>
281 lines
6.7 KiB
Markdown
281 lines
6.7 KiB
Markdown
# 动态菜单系统实现指南
|
||
|
||
## 📋 概述
|
||
|
||
已成功将菜单管理模块扩展为**完全动态化的菜单生成系统**。系统现在支持:
|
||
|
||
- ✅ 从数据库动态加载菜单
|
||
- ✅ 根据用户权限自动过滤菜单
|
||
- ✅ 动态生成路由配置
|
||
- ✅ 动态生成侧边栏菜单
|
||
- ✅ 支持多级菜单结构
|
||
- ✅ 菜单级别的权限控制
|
||
|
||
## 🏗️ 架构设计
|
||
|
||
### 后端架构
|
||
|
||
```
|
||
数据库 (Menu表)
|
||
↓
|
||
MenusService.findUserMenus()
|
||
↓
|
||
根据用户权限过滤菜单
|
||
↓
|
||
返回树形菜单结构
|
||
```
|
||
|
||
### 前端架构
|
||
|
||
```
|
||
用户登录
|
||
↓
|
||
获取用户菜单 (API)
|
||
↓
|
||
存储到 Auth Store
|
||
↓
|
||
转换为路由配置 (convertMenusToRoutes)
|
||
↓
|
||
动态注册路由 (router.addRoute)
|
||
↓
|
||
转换为菜单项 (convertMenusToMenuItems)
|
||
↓
|
||
渲染到侧边栏
|
||
```
|
||
|
||
## 🔧 实现细节
|
||
|
||
### 1. 数据库 Schema 更新
|
||
|
||
在 `Menu` 模型中添加了 `permission` 字段:
|
||
|
||
```prisma
|
||
model Menu {
|
||
// ... 其他字段
|
||
permission String? /// 权限编码(用于控制菜单显示,如:menu:read)
|
||
// ... 其他字段
|
||
}
|
||
```
|
||
|
||
**需要运行数据库迁移:**
|
||
|
||
```bash
|
||
cd backend
|
||
npx prisma migrate dev --name add_menu_permission
|
||
```
|
||
|
||
### 2. 后端 API
|
||
|
||
#### 新增接口:`GET /menus/user-menus`
|
||
|
||
获取当前用户的菜单(根据权限自动过滤)
|
||
|
||
**响应示例:**
|
||
|
||
```json
|
||
[
|
||
{
|
||
"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/users` → `SystemUsers`)
|
||
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. **菜单拖拽排序**: 在管理界面支持拖拽排序
|