fix: 处理菜单权限相关判断与筛选问题
This commit is contained in:
+93
-4
@@ -1,16 +1,105 @@
|
||||
import { get } from '@/utils/request';
|
||||
import type { MenuNode, PermissionCode } from '@/types';
|
||||
import { FALLBACK_MENU_NODES } from '@/config/fallbackRoutes';
|
||||
|
||||
// ============================================================
|
||||
// 权限数据缓存(/op/permission 只请求一次)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 获取当前用户的菜单树(后端下发)
|
||||
* Promise 级缓存:并发调用共享同一个请求,失败时清除以便重试
|
||||
*/
|
||||
export function fetchMenuTree(): Promise<MenuNode[]> {
|
||||
return get('/op/permission');
|
||||
let authDataPromise: Promise<AuthData> | null = null;
|
||||
|
||||
/**
|
||||
* 权限数据(角色 + 权限码)
|
||||
*/
|
||||
export interface AuthData {
|
||||
roleList: string[];
|
||||
permsList: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的完整权限数据(角色列表 + 权限编码列表)
|
||||
* 接口: GET /op/permission
|
||||
* Promise 级缓存:并发调用共享同一个请求,失败时清除缓存以允许重试
|
||||
*/
|
||||
export function fetchAuthData(): Promise<AuthData> {
|
||||
if (authDataPromise) return authDataPromise;
|
||||
authDataPromise = get('/op/permission')
|
||||
.then((res: any) => ({
|
||||
roleList: res.data?.roleList || [],
|
||||
permsList: res.data?.permsList || [],
|
||||
}))
|
||||
.catch((err) => {
|
||||
authDataPromise = null;
|
||||
throw err;
|
||||
});
|
||||
return authDataPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除权限数据缓存(退出登录时调用,确保下次登录不读到旧数据)
|
||||
*/
|
||||
export function clearAuthDataCache() {
|
||||
authDataPromise = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的权限编码列表
|
||||
* 复用 fetchAuthData 的缓存,避免重复请求
|
||||
*/
|
||||
export function fetchPermissions(): Promise<PermissionCode[]> {
|
||||
return get('/admin/sys/role/permissionList');
|
||||
return fetchAuthData().then((data) => data.permsList);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 菜单树 — 基于权限过滤兜底路由
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 按用户拥有的权限码过滤菜单树
|
||||
*
|
||||
* 规则:
|
||||
* - 节点有 permission 字段 → 权限码必须在 permsSet 中才保留
|
||||
* - 节点无 permission 但有 children → 保留并递归过滤子节点
|
||||
* - 节点被过滤且父节点过滤后无子节点、无 component → 父节点也移除
|
||||
*/
|
||||
function filterMenuNodesByPermission(nodes: MenuNode[], permsSet: Set<string>): MenuNode[] {
|
||||
return nodes
|
||||
.map((node) => {
|
||||
// 叶子节点:有 permission 则按权限过滤
|
||||
if (node.permission) {
|
||||
if (!permsSet.has(node.permission)) return null;
|
||||
return { ...node };
|
||||
}
|
||||
|
||||
// 分组节点(无 permission 有 children):递归过滤子节点
|
||||
if (node.children && node.children.length > 0) {
|
||||
const filteredChildren = filterMenuNodesByPermission(node.children, permsSet);
|
||||
// 子节点全部被过滤且父节点无 component → 移除父节点
|
||||
if (filteredChildren.length === 0 && !node.component) return null;
|
||||
return { ...node, children: filteredChildren };
|
||||
}
|
||||
|
||||
// 无 permission、无 children、无 component → 保留(如纯展示节点)
|
||||
return { ...node };
|
||||
})
|
||||
.filter((node): node is MenuNode => node !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的菜单树(基于权限过滤兜底路由)
|
||||
*
|
||||
* 1. 调用 /op/permission 获取用户权限码
|
||||
* 2. 用权限码过滤 FALLBACK_MENU_NODES
|
||||
* 3. 返回过滤后的菜单树
|
||||
*
|
||||
* 异常时抛出,由调用方(menuStore.loadMenu)降级使用未过滤的兜底路由
|
||||
*/
|
||||
export function fetchMenuTree(): Promise<MenuNode[]> {
|
||||
return fetchAuthData().then(({ permsList }) => {
|
||||
const permsSet = new Set(permsList);
|
||||
return filterMenuNodesByPermission(FALLBACK_MENU_NODES, permsSet);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user