通过 VITE_AUTO_FILL_TEST 环境变量控制,在 .env.test 中启用, 使测试环境构建后登录框也能自动填充测试账号,方便测试人员使用。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.3 KiB
8.3 KiB
新增前端页面路由指南
本文档介绍如何在活动管理系统中新增前端页面路由。
概述
系统采用动态路由机制,路由配置存储在数据库中,前端根据用户权限动态加载。新增页面需要完成以下 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
组件模板示例:
<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
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 示例:
-- 添加顶级菜单
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
Step 4: 关联租户菜单
在 tenant_menus 表中添加租户与菜单的关联关系。
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
<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
const componentMap: Record<string, () => Promise<any>> = {
// ... 其他组件
"announcements/Index": () => import("@/views/announcements/Index.vue"),
};
3. 添加菜单记录
INSERT INTO menus (name, path, component, icon, parent_id, sort, permission, tenant_id)
VALUES ('公告管理', '/announcements', 'announcements/Index', 'NotificationOutlined', NULL, 5, 'announcement:read', 1);
4. 关联租户
INSERT INTO tenant_menus (tenant_id, menu_id) VALUES (1, LAST_INSERT_ID());
5. 验证
- 重新登录系统(清除缓存)
- 检查侧边栏是否显示新菜单
- 点击菜单验证页面是否正常加载
常见问题
Q1: 菜单不显示?
检查以下几点:
tenant_menus表是否已关联当前租户- 用户角色是否有该菜单的权限
- 清除浏览器缓存后重新登录
Q2: 点击菜单报 404?
检查以下几点:
componentMap是否已注册该组件- 组件文件路径是否正确
- 查看控制台是否有警告信息
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 |
主布局、侧边栏菜单渲染 |