150 lines
4.4 KiB
Markdown
150 lines
4.4 KiB
Markdown
# 前端路由与菜单
|
|
|
|
前端路由定义页面的访问路径,菜单是路由的可视化展示。项目的路由和菜单由后端动态返回,前端只需注册路由组件映射。
|
|
|
|
## 动态路由机制
|
|
|
|
项目的路由和菜单是动态的,由后端驱动:
|
|
|
|
```
|
|
登录成功 → 请求 /index/getMenus → 生成动态路由 → 注册到 Vue Router → 渲染菜单
|
|
```
|
|
|
|
### 路由生成流程
|
|
|
|
1. 用户登录成功,获取 JWT Token
|
|
2. 前端路由守卫(`router-guards.ts`)检测到已登录
|
|
3. 调用 `GET /index/getMenus` 获取菜单树
|
|
4. 将菜单树转换为 Vue Router 路由记录
|
|
5. 使用 `router.addRoute()` 动态注册路由
|
|
6. 渲染侧边栏菜单
|
|
|
|
### 关键代码
|
|
|
|
```typescript
|
|
// src/router/generator-routers.ts
|
|
// 将后端菜单转换为前端路由
|
|
function generateRoutes(menus) {
|
|
const routes = [];
|
|
for (const menu of menus) {
|
|
const route = {
|
|
path: menu.path,
|
|
name: menu.name,
|
|
component: loadComponent(menu.component), // 动态加载组件
|
|
meta: {
|
|
title: menu.name,
|
|
icon: menu.icon,
|
|
},
|
|
};
|
|
if (menu.children) {
|
|
route.children = generateRoutes(menu.children);
|
|
}
|
|
routes.push(route);
|
|
}
|
|
return routes;
|
|
}
|
|
```
|
|
|
|
## 菜单 component 字段
|
|
|
|
后端菜单的 `component` 字段必须与前端 `.vue` 文件路径对应:
|
|
|
|
| 菜单 component | 前端文件路径 |
|
|
|:----|:----|
|
|
| `tool/example/index` | `ui/src/views/tool/example/index.vue` |
|
|
| `system/user/index` | `ui/src/views/system/user/index.vue` |
|
|
| `content/article/index` | `ui/src/views/content/article/index.vue` |
|
|
|
|
### 组件加载方式
|
|
|
|
前端使用 `import.meta.glob` 自动扫描所有 `.vue` 文件:
|
|
|
|
```typescript
|
|
// 扫描 src/views/ 下所有 .vue 文件
|
|
const modules = import.meta.glob('../views/**/*.vue');
|
|
|
|
function loadComponent(component) {
|
|
const path = `../views/${component}.vue`;
|
|
return modules[path];
|
|
}
|
|
```
|
|
|
|
## 后端菜单配置
|
|
|
|
在「系统管理 -> 菜单管理」中添加菜单节点:
|
|
|
|
| 字段 | 值 | 说明 |
|
|
|:----|:----|:----|
|
|
| 菜单名称 | 案例管理 | 菜单显示名称 |
|
|
| 菜单类型 | 菜单(type=0) | 目录/菜单/权限 |
|
|
| 路由路径 | `/tool/example` | 前端路由路径 |
|
|
| 组件路径 | `tool/example/index` | 对应 .vue 文件路径 |
|
|
| 菜单图标 | 选择合适图标 | 菜单图标 |
|
|
| 排序号 | 设置显示顺序 | 菜单排序 |
|
|
| 状态 | 启用 | 是否启用 |
|
|
|
|
### 菜单数据返回格式
|
|
|
|
后端接口 `/index/getMenus` 返回的菜单数据:
|
|
|
|
```json
|
|
{
|
|
"code": 0,
|
|
"data": [
|
|
{
|
|
"id": 10,
|
|
"name": "系统工具",
|
|
"parent_id": 0,
|
|
"path": "/tool",
|
|
"component": "Layout",
|
|
"type": 0,
|
|
"icon": "tool",
|
|
"children": [
|
|
{
|
|
"id": 101,
|
|
"name": "案例管理",
|
|
"parent_id": 10,
|
|
"path": "/tool/example",
|
|
"component": "tool/example/index",
|
|
"type": 0,
|
|
"icon": "example"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## 菜单与权限的关系
|
|
|
|
```
|
|
菜单管理
|
|
├── 系统工具(目录,type=0)
|
|
│ ├── 案例管理(菜单,type=0)
|
|
│ │ ├── 案例查询(权限,type=1)→ sys:example:page
|
|
│ │ ├── 案例新增(权限,type=1)→ sys:example:add
|
|
│ │ ├── 案例编辑(权限,type=1)→ sys:example:update
|
|
│ │ ├── 案例删除(权限,type=1)→ sys:example:delete
|
|
│ │ └── 案例状态(权限,type=1)→ sys:example:status
|
|
│ └── ...
|
|
└── ...
|
|
```
|
|
|
|
| 节点类型 | type | 作用 |
|
|
|:----|:----|:----|
|
|
| 目录 | 0 | 菜单分组,不对应页面 |
|
|
| 菜单 | 0 | 对应一个页面路由 |
|
|
| 权限 | 1 | 对应一个操作权限,不在菜单中显示 |
|
|
|
|
## 开发要点
|
|
|
|
1. **路由和菜单由后端动态返回**:前端不需要手动编辑路由文件
|
|
2. **component 字段必须与 .vue 文件路径对应**:否则页面白屏
|
|
3. **使用 `import.meta.glob` 自动扫描组件**:无需手动注册
|
|
4. **菜单类型区分目录和权限**:目录用于分组,权限用于按钮控制
|
|
5. **新增模块只需在菜单管理中配置**:自动出现在前端菜单中
|
|
|
|
## 总结
|
|
|
|
前端路由使用 Vue Router 4,菜单路由由后端动态返回,前端通过 `addRoute` 动态注册。路由守卫负责权限校验和登录状态检查,未登录自动跳转登录页。新增模块只需在菜单管理中配置,无需编辑前端路由文件。
|