feat: 1. 本地化思源黑体的字体包并优先使用。

2. 添加权限映射表和全局查看权限的hook,便于路由控制不同权限按钮显示/隐藏。
3. 删除评查点分组的部分旧api方法。
4. 对接评查点分组接口,文档类型接口, 提示词管理接口, 入口模块管理的接口。
5. 优化角色权限管理的接口,完善不用地区的访问权限认证。
6. 优化主页交叉评查和设置的入口样式和布局。
7. 优化评查点分组,评查规则的功能权限校验。
This commit is contained in:
2025-11-29 10:37:35 +08:00
parent 61facf5d71
commit 30e100ef3e
29 changed files with 2527 additions and 2126 deletions
+105 -3
View File
@@ -14,6 +14,7 @@ export interface BackendRouteInfo {
is_hidden: boolean;
is_cache: boolean;
meta: string;
permissions?: string[]; // ✅ 新增:该路由下用户拥有的权限列表
children?: BackendRouteInfo[];
}
@@ -60,6 +61,7 @@ export interface MenuItem {
order: number;
hideBreadcrumb?: boolean;
requiredRole?: string;
permissions?: string[]; // ✅ 新增:该菜单项的权限列表
children?: MenuItem[];
}
@@ -484,6 +486,88 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
]
};
/**
* 权限映射表类型
* key: 路由路径 (如 '/prompts', '/documents')
* value: 该路由下的权限列表
*/
export type PermissionMap = Map<string, string[]>;
/**
* 从路由树中提取权限映射表
* @param routes 路由树
* @param aggregateChildren 是否聚合子路由权限到父路由(默认true)
* @returns 权限映射表 (路径 -> 权限列表)
*/
export function buildPermissionMap(routes: BackendRouteInfo[], aggregateChildren: boolean = true): PermissionMap {
const permissionMap = new Map<string, string[]>();
/**
* 递归收集路由及其所有子路由的权限
*/
function collectAllPermissions(route: BackendRouteInfo): string[] {
const allPermissions = new Set<string>();
// 添加当前路由的权限
if (route.permissions && route.permissions.length > 0) {
route.permissions.forEach(p => allPermissions.add(p));
}
// 递归收集子路由的权限
if (aggregateChildren && route.children && route.children.length > 0) {
route.children.forEach(child => {
const childPermissions = collectAllPermissions(child);
childPermissions.forEach(p => allPermissions.add(p));
});
}
return Array.from(allPermissions);
}
function traverse(routeList: BackendRouteInfo[]) {
for (const route of routeList) {
// 存储当前路由的权限(聚合或不聚合)
const permissions = aggregateChildren
? collectAllPermissions(route)
: (route.permissions || []);
if (permissions.length > 0) {
permissionMap.set(route.route_path, permissions);
}
// 递归处理子路由
if (route.children && route.children.length > 0) {
traverse(route.children);
}
}
}
traverse(routes);
return permissionMap;
}
/**
* 将权限映射表转换为普通对象(用于JSON序列化)
*/
export function permissionMapToObject(map: PermissionMap): Record<string, string[]> {
const obj: Record<string, string[]> = {};
map.forEach((value, key) => {
obj[key] = value;
});
return obj;
}
/**
* 从对象恢复权限映射表
*/
export function objectToPermissionMap(obj: Record<string, string[]>): PermissionMap {
const map = new Map<string, string[]>();
Object.entries(obj).forEach(([key, value]) => {
map.set(key, value);
});
return map;
}
/**
* 根据角色获取用户可访问的路由(调用后端统一接口)
* @param roleKey 角色标识 (如: 'admin', 'common', 'deptLeader', 'groupLeader') - 暂时不使用,后端通过JWT自动识别
@@ -491,7 +575,17 @@ const FALLBACK_MENU_DATA: Record<string, MenuItem[]> = {
* @param includeHidden 是否包含隐藏路由(默认 false)。true: 用于权限校验,false: 用于菜单渲染
* @returns 用户可访问的路由列表
*/
export async function getUserRoutesByRole(roleKey: string, jwt?: string, includeHidden: boolean = false): Promise<{ success: boolean; data?: MenuItem[]; error?: string; shouldRedirectToHome?: boolean }> {
export async function getUserRoutesByRole(
roleKey: string,
jwt?: string,
includeHidden: boolean = false
): Promise<{
success: boolean;
data?: MenuItem[];
permissionMap?: Record<string, string[]>; // ✅ 新增:返回权限映射表
error?: string;
shouldRedirectToHome?: boolean
}> {
try {
// console.log(`🔍 [User Routes] 获取用户路由,角色: ${roleKey}, JWT前20字符: ${jwt?.substring(0, 20)}`);
@@ -598,6 +692,9 @@ export async function getUserRoutesByRole(roleKey: string, jwt?: string, include
// console.log('🔍 [User Routes] 后端返回的原始路由数据:', JSON.stringify(routes, null, 2));
// console.log('🔍 [User Routes] 检查第一个路由是否有children:', routes[0]?.children);
// ✅ 构建权限映射表
const permissionMapObj = permissionMapToObject(buildPermissionMap(routes));
// 将后端路由格式转换为前端 MenuItem 格式
const menuItems = convertBackendRoutesToMenuItems(routes, includeHidden);
@@ -605,7 +702,11 @@ export async function getUserRoutesByRole(roleKey: string, jwt?: string, include
// console.log('🔍 [User Routes] 转换后的菜单数据:', JSON.stringify(menuItems, null, 2));
// console.log('🔍 [User Routes] 检查第一个菜单项是否有children:', menuItems[0]?.children);
return { success: true, data: menuItems };
return {
success: true,
data: menuItems,
permissionMap: permissionMapObj // ✅ 返回权限映射表
};
} catch (error) {
console.error("❌ [User Routes] 获取用户路由时发生错误:", error);
@@ -801,7 +902,8 @@ function convertBackendRoutesToMenuItems(backendRoutes: BackendRouteInfo[], incl
path: route.route_path,
icon: convertIcon(route.icon),
order: route.sort_order,
hideBreadcrumb: route.is_hidden
hideBreadcrumb: route.is_hidden,
permissions: route.permissions // ✅ 传递权限列表
};
// 递归处理子路由,传递 includeHidden 参数