201 lines
5.1 KiB
Markdown
201 lines
5.1 KiB
Markdown
# 菜单权限功能前后端对接分析报告
|
||
|
||
## 分析时间
|
||
2025-08-26
|
||
|
||
## 项目概述
|
||
- **后端**: Spring Boot + MyBatis-Plus + JWT
|
||
- **前端**: Vue 3 + TypeScript + Element Plus + Pinia
|
||
|
||
## 后端菜单权限现状
|
||
|
||
### ✅ 已实现的功能
|
||
|
||
1. **数据库设计完整**
|
||
- `sys_menu`: 菜单表,包含层级结构
|
||
- `sys_role_menu`: 角色菜单关联表
|
||
- `sys_user_role`: 用户角色关联表
|
||
|
||
2. **接口权限控制**
|
||
- 使用 `@PreAuthorize` 注解控制接口访问权限
|
||
- JWT token 身份验证机制
|
||
|
||
3. **菜单管理接口完整**
|
||
- `GET /menus/tree`: 查询完整菜单树(管理用)
|
||
- `GET /menus/user-tree`: 查询用户菜单树(权限过滤)
|
||
- 完整的 CRUD 操作接口
|
||
|
||
4. **权限查询方法**
|
||
- `getUserPermissions(userId)`: 获取用户权限列表
|
||
- `getUserMenuTree(userId)`: 获取用户可访问的菜单树
|
||
|
||
### ⚠️ 存在的问题
|
||
|
||
1. **用户ID获取方式**
|
||
```java
|
||
// 当前硬编码为1L,需要从JWT获取真实用户ID
|
||
List<SysMenu> result = menuService.getUserMenuTree(1L);
|
||
```
|
||
|
||
2. **权限验证机制**
|
||
- 后端有权限控制,但前端路由未集成权限验证
|
||
|
||
## 前端菜单权限现状
|
||
|
||
### ✅ 已实现的功能
|
||
|
||
1. **用户状态管理**
|
||
- Pinia store 管理用户信息、权限、角色
|
||
- JWT token 持久化存储
|
||
|
||
2. **基础路由守卫**
|
||
- 登录状态验证
|
||
- 基础的路由重定向
|
||
|
||
3. **菜单 API 接口**
|
||
- 已定义完整的菜单相关 API 方法
|
||
- TypeScript 类型定义完整
|
||
|
||
### ❌ 缺失的功能
|
||
|
||
1. **动态菜单渲染**
|
||
- 当前侧边栏菜单是静态硬编码的
|
||
- 没有基于权限的动态菜单生成
|
||
|
||
2. **菜单权限控制**
|
||
- 没有菜单 store 管理菜单状态
|
||
- 没有基于用户权限的菜单过滤
|
||
|
||
3. **动态路由生成**
|
||
- 路由配置是静态的
|
||
- 没有根据用户权限动态生成路由
|
||
|
||
## 前后端对接可行性分析
|
||
|
||
### ✅ 对接优势
|
||
|
||
1. **API 接口完备**
|
||
- 后端提供 `/menus/user-tree` 接口获取用户菜单
|
||
- 前端已有对应的 `getUserMenuTree()` 方法
|
||
|
||
2. **数据结构兼容**
|
||
```typescript
|
||
// 前端 Menu 类型与后端 SysMenu 实体匹配度高
|
||
interface Menu {
|
||
id: number
|
||
menuName: string
|
||
parentId: number
|
||
path: string
|
||
component: string
|
||
menuType: string // M=目录, C=菜单, F=按钮
|
||
permission: string
|
||
icon: string
|
||
visible: number
|
||
status: number
|
||
children?: Menu[]
|
||
}
|
||
```
|
||
|
||
3. **权限体系完整**
|
||
- 后端:基于角色的权限控制(RBAC)
|
||
- 前端:用户 store 已存储权限和角色信息
|
||
|
||
### ⚠️ 对接挑战
|
||
|
||
1. **菜单类型映射**
|
||
- 需要将后端菜单类型(M/C/F)映射到前端路由类型
|
||
|
||
2. **动态组件加载**
|
||
- 需要将后端 component 路径转换为前端组件导入
|
||
|
||
3. **权限指令实现**
|
||
- 需要实现 v-permission 等权限指令用于按钮级权限控制
|
||
|
||
## 实现方案建议
|
||
|
||
### 1. 后端优化 (高优先级)
|
||
|
||
```java
|
||
// 修改 SysMenuController.getUserMenuTree()
|
||
@GetMapping("/user-tree")
|
||
@Operation(summary = "查询用户菜单树")
|
||
public Result<List<SysMenu>> getUserMenuTree() {
|
||
Long userId = SecurityUtils.getCurrentUserId(); // 从JWT获取用户ID
|
||
List<SysMenu> result = menuService.getUserMenuTree(userId);
|
||
return Result.success(result);
|
||
}
|
||
```
|
||
|
||
### 2. 前端菜单 Store 实现 (高优先级)
|
||
|
||
```typescript
|
||
// 新增 src/stores/menu.ts
|
||
export const useMenuStore = defineStore('menu', () => {
|
||
const menuTree = ref<Menu[]>([])
|
||
const flatMenus = ref<Menu[]>([])
|
||
|
||
const loadUserMenus = async () => {
|
||
const response = await getUserMenuTree()
|
||
menuTree.value = response.data
|
||
flatMenus.value = flattenMenus(response.data)
|
||
}
|
||
|
||
return { menuTree, flatMenus, loadUserMenus }
|
||
})
|
||
```
|
||
|
||
### 3. 动态菜单组件 (中优先级)
|
||
|
||
```vue
|
||
<!-- 新增 src/components/DynamicMenu.vue -->
|
||
<template>
|
||
<el-menu>
|
||
<template v-for="menu in menuTree" :key="menu.id">
|
||
<DynamicMenuItem :menu="menu" />
|
||
</template>
|
||
</el-menu>
|
||
</template>
|
||
```
|
||
|
||
### 4. 权限指令实现 (中优先级)
|
||
|
||
```typescript
|
||
// 新增 src/directives/permission.ts
|
||
app.directive('permission', {
|
||
mounted(el, binding) {
|
||
const { hasPermission } = useUserStore()
|
||
if (!hasPermission(binding.value)) {
|
||
el.remove()
|
||
}
|
||
}
|
||
})
|
||
```
|
||
|
||
## 结论
|
||
|
||
**前后端菜单权限功能具备良好的对接基础**:
|
||
|
||
✅ **可以立即对接的部分**:
|
||
- API 接口调用
|
||
- 基础权限验证
|
||
- 菜单数据获取
|
||
|
||
⚠️ **需要开发的关键功能**:
|
||
- 动态菜单渲染组件
|
||
- 菜单状态管理 Store
|
||
- 权限指令和按钮级权限控制
|
||
|
||
📈 **实现难度评估**:
|
||
- 后端调整:**简单** (主要是用户ID获取)
|
||
- 前端菜单Store:**中等** (状态管理和数据处理)
|
||
- 动态菜单组件:**中等** (递归组件渲染)
|
||
- 权限指令:**简单** (基础指令实现)
|
||
|
||
**建议实施顺序**:
|
||
1. 修复后端用户ID获取逻辑
|
||
2. 实现前端菜单 Store
|
||
3. 创建动态菜单组件
|
||
4. 集成到布局组件中
|
||
5. 实现权限指令用于按钮控制
|
||
|
||
整体评估:**前后端对接可行性较高**,主要工作集中在前端动态菜单实现上。 |