2026-03-27 22:20:25 +08:00
|
|
|
|
# 新增前端页面路由指南
|
|
|
|
|
|
|
|
|
|
|
|
本文档介绍如何在活动管理系统中新增前端页面路由。
|
|
|
|
|
|
|
|
|
|
|
|
## 概述
|
|
|
|
|
|
|
|
|
|
|
|
系统采用**动态路由**机制,路由配置存储在数据库中,前端根据用户权限动态加载。新增页面需要完成以下 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
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="page-container">
|
|
|
|
|
|
<h1>页面标题</h1>
|
|
|
|
|
|
<!-- 页面内容 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
// 组件逻辑
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.page-container {
|
|
|
|
|
|
// 样式
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Step 2: 注册组件映射
|
|
|
|
|
|
|
|
|
|
|
|
在 `frontend/src/utils/menu.ts` 文件中的 `componentMap` 对象中添加组件映射。
|
|
|
|
|
|
|
|
|
|
|
|
**文件位置:** `frontend/src/utils/menu.ts`
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
const componentMap: Record<string, () => Promise<any>> = {
|
|
|
|
|
|
// 工作台
|
|
|
|
|
|
"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
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<a-card title="公告管理">
|
|
|
|
|
|
<a-table :columns="columns" :data-source="data" />
|
|
|
|
|
|
</a-card>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { ref } from 'vue'
|
|
|
|
|
|
|
|
|
|
|
|
const columns = [
|
|
|
|
|
|
{ title: '标题', dataIndex: 'title' },
|
|
|
|
|
|
{ title: '发布时间', dataIndex: 'createdAt' },
|
|
|
|
|
|
{ title: '操作', key: 'action' },
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
const data = ref([])
|
|
|
|
|
|
</script>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 注册组件
|
|
|
|
|
|
|
|
|
|
|
|
**文件:** `frontend/src/utils/menu.ts`
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
const componentMap: Record<string, () => Promise<any>> = {
|
|
|
|
|
|
// ... 其他组件
|
|
|
|
|
|
"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` | 主布局、侧边栏菜单渲染 |
|