Are you an LLM? You can read better optimized documentation at /frontend/stores/permission-store.md for this page in Markdown format
权限状态管理 (permission)
功能概述
权限状态管理模块负责动态路由的生成、权限过滤和多布局路由管理,是实现基于角色的访问控制(RBAC)的核心模块。
核心职责
- 动态路由生成:从后端获取路由配置并转换为前端路由
- 权限过滤:基于用户角色和权限过滤路由
- 布局管理:处理顶部导航、侧边栏等不同布局需求
- 组件加载:动态加载路由对应的视图组件
状态定义
typescript
// 路由状态
routes: RouteRecordRaw[] // 所有路由(静态+动态)
addRoutes: RouteRecordRaw[] // 动态添加的路由
defaultRoutes: RouteRecordRaw[] // 默认路由
topbarRouters: RouteRecordRaw[] // 顶部导航路由
sidebarRouters: RouteRecordRaw[] // 侧边栏路由
1
2
3
4
5
6
2
3
4
5
6
核心方法
generateRoutes - 生成动态路由
typescript
async generateRoutes(): Result<RouteRecordRaw[]>
1
完整的路由生成流程:
- 从后端API获取路由配置
- 转换路由为前端组件对象
- 处理不同布局场景的路由格式
- 添加有权限的动态路由
- 检查路由名称冲突
filterAsyncRouter - 路由转换
typescript
filterAsyncRouter(
asyncRouterMap: RouteRecordRaw[],
lastRouter?: RouteRecordRaw,
type?: boolean
): RouteRecordRaw[]
1
2
3
4
5
2
3
4
5
将后端路由配置转换为前端路由:
- 字符串组件名转换为组件对象
- 处理Layout、ParentView、InnerLink特殊组件
- 递归处理嵌套路由
filterDynamicRoutes - 权限过滤
typescript
filterDynamicRoutes(routes: RouteRecordRaw[]): RouteRecordRaw[]
1
基于用户权限过滤路由:
- 检查路由所需permissions
- 验证路由所需roles
- 返回用户有权访问的路由
路由组件映射
特殊组件处理
typescript
// Layout组件 - 主布局容器
if (route.component === 'Layout') {
route.component = Layout
}
// ParentView - 嵌套路由容器
if (route.component === 'ParentView') {
route.component = ParentView
}
// InnerLink - iframe内嵌页面
if (route.component === 'InnerLink') {
route.component = InnerLink
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
动态视图加载
typescript
// 使用import.meta.glob动态加载视图
const modules = import.meta.glob('./../../views/**/*.vue')
// 根据路径匹配并加载组件
loadView(view: string, name: string)
1
2
3
4
5
2
3
4
5
多布局路由管理
路由类型分配
- constantRoutes: 静态路由(登录、404等)
- sidebarRoutes: 侧边栏菜单路由
- topbarRoutes: 顶部导航路由
- defaultRoutes: 默认基础路由
布局场景处理
typescript
// 侧边栏路由 - 保持原始嵌套结构
const sidebarRoutes = filterAsyncRouter(sdata)
// 重写路由 - 扁平化处理
const rewriteRoutes = filterAsyncRouter(rdata, undefined, true)
// 顶部路由 - 用于顶部导航
const defaultRoutes = filterAsyncRouter(defaultData)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
使用示例
初始化路由
typescript
// 在路由守卫中生成路由
router.beforeEach(async (to, from, next) => {
if (hasToken && !permissionStore.routes.length) {
const [err, routes] = await permissionStore.generateRoutes()
if (!err) {
// 动态添加路由
routes.forEach(route => router.addRoute(route))
next({ ...to, replace: true })
}
}
})
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
获取菜单数据
typescript
// 侧边栏菜单
const sidebarMenus = computed(() =>
permissionStore.getSidebarRoutes()
)
// 顶部导航
const topbarMenus = computed(() =>
permissionStore.getTopbarRoutes()
)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
路由冲突检测
duplicateRouteChecker
自动检测路由名称重复问题:
- 递归展平所有路由
- 检查name属性唯一性
- 发现冲突时弹出警告
typescript
// 避免的问题:
// - 路由跳转失败
// - 页面404错误
// - 导航高亮异常
1
2
3
4
2
3
4
与其他模块协作
与 User Store
- 依赖用户的roles和permissions
- 登录成功后触发路由生成
与 TagsView Store
- 提供可访问的路由列表
- 控制哪些页面可以被缓存
与 Auth Composable
- 使用hasPermission判断权限
- 使用hasRole验证角色
性能优化
- 路由懒加载:使用import.meta.glob实现按需加载
- 组件缓存:配合keep-alive缓存常用页面
- 路由复用:相同组件不同参数的路由复用组件实例
- 权限缓存:避免重复的权限计算
注意事项
- 路由名称唯一性:确保每个路由的name属性唯一
- 组件命名规范:组件name要与路由name一致(用于keep-alive)
- 权限配置位置:权限配置应在路由meta中定义
- 动态路由限制:避免过深的路由嵌套(建议不超过3层)