# 新增前端页面路由指南 本文档介绍如何在比赛管理系统中新增前端页面路由。 ## 概述 系统采用**动态路由**机制,路由配置存储在数据库中,前端根据用户权限动态加载。新增页面需要完成以下 4 个步骤: ``` ┌──────────────────────────────────────────────────────────────┐ │ Step 1: 创建 Vue 组件文件 │ │ frontend/src/views/xxx/Index.vue │ ├──────────────────────────────────────────────────────────────┤ │ Step 2: 在 componentMap 中注册组件 │ │ frontend/src/utils/menu.ts │ ├──────────────────────────────────────────────────────────────┤ │ Step 3: 在数据库 menus 表中添加菜单记录 │ ├──────────────────────────────────────────────────────────────┤ │ Step 4: 在数据库 tenant_menus 表中关联租户 │ └──────────────────────────────────────────────────────────────┘ ``` ## 详细步骤 ### Step 1: 创建 Vue 组件文件 在 `frontend/src/views/` 目录下创建对应的 Vue 组件。 **目录结构规范:** ``` frontend/src/views/ ├── workbench/ # 工作台模块 │ └── Index.vue ├── contests/ # 赛事管理模块 │ ├── Index.vue # 赛事列表 │ ├── Create.vue # 创建赛事 │ ├── Detail.vue # 赛事详情 │ ├── registrations/ # 报名管理 │ │ └── Index.vue │ ├── works/ # 作品管理 │ │ └── Index.vue │ └── ... ├── system/ # 系统管理模块 │ ├── users/ │ │ └── Index.vue │ ├── roles/ │ │ └── Index.vue │ └── ... └── your-module/ # 你的新模块 └── Index.vue ``` **组件模板示例:** ```vue ``` ### Step 2: 注册组件映射 在 `frontend/src/utils/menu.ts` 文件中的 `componentMap` 对象中添加组件映射。 **文件位置:** `frontend/src/utils/menu.ts` ```typescript const componentMap: Record Promise> = { // 工作台 "workbench/Index": () => import("@/views/workbench/Index.vue"), // 赛事管理模块 "contests/Index": () => import("@/views/contests/Index.vue"), "contests/Create": () => import("@/views/contests/Create.vue"), // ... // 系统管理模块 "system/users/Index": () => import("@/views/system/users/Index.vue"), // ... // ========== 新增组件映射 ========== "your-module/Index": () => import("@/views/your-module/Index.vue"), "your-module/Detail": () => import("@/views/your-module/Detail.vue"), }; ``` **注意事项:** - Key 格式:`模块名/组件名`,不需要 `@/views/` 前缀和 `.vue` 后缀 - Value 格式:使用动态 import 函数 - 如果未注册,控制台会输出警告信息 ### Step 3: 添加数据库菜单记录 在数据库的 `menus` 表中插入菜单记录。 **menus 表结构:** | 字段 | 类型 | 说明 | |------|------|------| | id | int | 主键,自增 | | name | varchar | 菜单名称(显示文本) | | path | varchar | 路由路径,如 `/contests` | | component | varchar | 组件路径,对应 componentMap 的 key | | icon | varchar | 图标名称,使用 Ant Design 图标 | | parent_id | int | 父菜单ID,顶级菜单为 NULL | | sort | int | 排序序号 | | permission | varchar | 权限标识,如 `contest:read` | | tenant_id | int | 租户ID | **SQL 示例:** ```sql -- 添加顶级菜单 INSERT INTO menus (name, path, component, icon, parent_id, sort, tenant_id) VALUES ('新模块', '/your-module', 'your-module/Index', 'AppstoreOutlined', NULL, 10, 1); -- 获取刚插入的菜单ID SET @parent_id = LAST_INSERT_ID(); -- 添加子菜单 INSERT INTO menus (name, path, component, icon, parent_id, sort, tenant_id) VALUES ('子页面1', '/your-module/sub1', 'your-module/Sub1', NULL, @parent_id, 1, 1); INSERT INTO menus (name, path, component, icon, parent_id, sort, tenant_id) VALUES ('子页面2', '/your-module/sub2', 'your-module/Sub2', NULL, @parent_id, 2, 1); ``` **常用图标名称:** - `HomeOutlined` - 首页 - `AppstoreOutlined` - 应用 - `TrophyOutlined` - 奖杯/赛事 - `TeamOutlined` - 团队 - `UserOutlined` - 用户 - `SettingOutlined` - 设置 - `FileOutlined` - 文件 - `FolderOutlined` - 文件夹 更多图标请参考:[Ant Design Icons](https://ant.design/components/icon-cn) ### Step 4: 关联租户菜单 在 `tenant_menus` 表中添加租户与菜单的关联关系。 **SQL 示例:** ```sql -- 假设菜单ID为 30,租户ID为 1 INSERT INTO tenant_menus (tenant_id, menu_id) VALUES (1, 30); -- 如果刚插入菜单,可以使用 LAST_INSERT_ID() INSERT INTO tenant_menus (tenant_id, menu_id) VALUES (1, LAST_INSERT_ID()); -- 批量关联(关联多个租户) INSERT INTO tenant_menus (tenant_id, menu_id) VALUES (1, 30), (2, 30), (3, 30); ``` ## 完整示例 假设要新增一个「公告管理」页面: ### 1. 创建组件文件 **文件:** `frontend/src/views/announcements/Index.vue` ```vue ``` ### 2. 注册组件 **文件:** `frontend/src/utils/menu.ts` ```typescript const componentMap: Record Promise> = { // ... 其他组件 "announcements/Index": () => import("@/views/announcements/Index.vue"), }; ``` ### 3. 添加菜单记录 ```sql INSERT INTO menus (name, path, component, icon, parent_id, sort, permission, tenant_id) VALUES ('公告管理', '/announcements', 'announcements/Index', 'NotificationOutlined', NULL, 5, 'announcement:read', 1); ``` ### 4. 关联租户 ```sql INSERT INTO tenant_menus (tenant_id, menu_id) VALUES (1, LAST_INSERT_ID()); ``` ### 5. 验证 1. 重新登录系统(清除缓存) 2. 检查侧边栏是否显示新菜单 3. 点击菜单验证页面是否正常加载 ## 常见问题 ### Q1: 菜单不显示? 检查以下几点: 1. `tenant_menus` 表是否已关联当前租户 2. 用户角色是否有该菜单的权限 3. 清除浏览器缓存后重新登录 ### Q2: 点击菜单报 404? 检查以下几点: 1. `componentMap` 是否已注册该组件 2. 组件文件路径是否正确 3. 查看控制台是否有警告信息 ### Q3: 控制台警告「组件路径未在 componentMap 中定义」? 在 `menu.ts` 的 `componentMap` 中添加对应的组件映射。 ### Q4: 如何添加需要权限的页面? 在 `menus` 表的 `permission` 字段设置权限标识,如 `announcement:read`,然后确保用户角色拥有该权限。 ## 相关文件 | 文件 | 说明 | |------|------| | `frontend/src/utils/menu.ts` | 组件映射、菜单转换工具 | | `frontend/src/router/index.ts` | 路由配置、动态路由加载 | | `frontend/src/stores/auth.ts` | 用户认证、菜单数据存储 | | `frontend/src/layouts/BasicLayout.vue` | 主布局、侧边栏菜单渲染 |