import { toastService } from '~/components/ui'; import { postgrestGet } from '../postgrest-client'; // 路由数据接口 export interface RouteInfo { id: number; path: string; name: string; meta: { title: string; icon: string; order: number; requiredRole?: string; }; parent_id: number; is_menu: number; } // 用户路由权限接口 export interface UserRoutePermission { route_id: number; role_id: number; permission: string; route: RouteInfo; } // MenuItem结构接口 export interface MenuItem { id: string; title: string; path: string; icon: string; order: number; hideBreadcrumb?: boolean; requiredRole?: string; children?: MenuItem[]; } // 静态菜单数据作为后备 (保留用于开发和紧急情况,当前不使用) // eslint-disable-next-line @typescript-eslint/no-unused-vars const FALLBACK_MENU_DATA: Record = { 'admin': [ { id: 'home', title: '系统概览', path: '/home', icon: 'ri-home-line', order: 1 }, { id: 'chat-with-llm', title: 'AI对话', path: '/chat-with-llm', icon: 'ri-chat-smile-2-line', order: 2 }, { id: 'file-management', title: '文件管理', path: '/files', icon: 'ri-folder-line', order: 3, children: [ { id: 'file-upload', title: '文件上传', path: '/files/upload', icon: 'ri-upload-cloud-line', order: 1 }, { id: 'documents', title: '文档列表', path: '/documents', icon: 'ri-file-list-3-line', order: 2 } ] }, { id: 'rule-management', title: '评查规则库', path: '/rules', icon: 'ri-book-3-line', order: 4, children: [ { id: 'rule-groups', title: '评查点分组', path: '/rule-groups', icon: 'ri-folder-open-line', order: 1 }, { id: 'rules-list', title: '评查点列表', path: '/rules', icon: 'ri-list-check-3', order: 2 }, { id: 'rules-file', title: '评查文件列表', path: '/rules-files', icon: 'ri-list-check-2', order: 3 } ] }, { id: 'contract-template', title: '合同模板', path: '/contract-template', icon: 'ri-file-search-line', order: 5, children: [ { id: 'contract-search-ai', title: '智能搜索', path: '/contract-template/search', icon: 'ri-search-line', order: 1 }, { id: 'contract-list', title: '合同列表', path: '/contract-template/list', icon: 'ri-folder-line', order: 2 } ] }, { id: 'system-settings', title: '系统设置', path: '/settings', icon: 'ri-settings-4-line', order: 6, requiredRole: 'developer', children: [ { id: 'config-lists', title: '配置列表', path: '/config-lists', icon: 'ri-list-check-3', order: 1, requiredRole: 'developer' }, { id: 'document-types', title: '文档类型', path: '/document-types', icon: 'ri-file-list-line', order: 2, requiredRole: 'developer' }, { id: 'prompt-management', title: '提示词管理', path: '/prompts', icon: 'ri-chat-1-line', order: 3, requiredRole: 'developer' } ] }, { id: 'cross-checking', title: '交叉评查', path: '/cross-checking', icon: 'ri-color-filter-line', order: 7 } ], 'common': [ { id: 'home', title: '系统概览', path: '/home', icon: 'ri-home-line', order: 1 }, { id: 'file-management', title: '文件管理', path: '/files', icon: 'ri-folder-line', order: 3, children: [ { id: 'file-upload', title: '文件上传', path: '/files/upload', icon: 'ri-upload-cloud-line', order: 1 }, { id: 'documents', title: '文档列表', path: '/documents', icon: 'ri-file-list-3-line', order: 2 } ] }, { id: 'rule-management', title: '评查规则库', path: '/rules', icon: 'ri-book-3-line', order: 4, children: [ { id: 'rule-groups', title: '评查点分组', path: '/rule-groups', icon: 'ri-folder-open-line', order: 1 }, { id: 'rules-list', title: '评查点列表', path: '/rules', icon: 'ri-list-check-3', order: 2 }, { id: 'rules-file', title: '评查文件列表', path: '/rules-files', icon: 'ri-list-check-2', order: 3 } ] }, { id: 'contract-template', title: '合同模板', path: '/contract-template', icon: 'ri-file-search-line', order: 5, children: [ { id: 'contract-search-ai', title: '智能搜索', path: '/contract-template/search', icon: 'ri-search-line', order: 1 }, { id: 'contract-list', title: '合同列表', path: '/contract-template/list', icon: 'ri-folder-line', order: 2 } ] }, { id: 'cross-checking', title: '交叉评查', path: '/cross-checking', icon: 'ri-color-filter-line', order: 7 } ], 'deptLeader': [ { id: 'home', title: '系统概览', path: '/home', icon: 'ri-home-line', order: 1 }, { id: 'chat-with-llm', title: 'AI对话', path: '/chat-with-llm', icon: 'ri-chat-smile-2-line', order: 2 }, { id: 'file-management', title: '文件管理', path: '/files', icon: 'ri-folder-line', order: 3, children: [ { id: 'file-upload', title: '文件上传', path: '/files/upload', icon: 'ri-upload-cloud-line', order: 1 }, { id: 'documents', title: '文档列表', path: '/documents', icon: 'ri-file-list-3-line', order: 2 } ] }, { id: 'rule-management', title: '评查规则库', path: '/rules', icon: 'ri-book-3-line', order: 4, children: [ { id: 'rule-groups', title: '评查点分组', path: '/rule-groups', icon: 'ri-folder-open-line', order: 1 }, { id: 'rules-list', title: '评查点列表', path: '/rules', icon: 'ri-list-check-3', order: 2 }, { id: 'rules-file', title: '评查文件列表', path: '/rules-files', icon: 'ri-list-check-2', order: 3 } ] }, { id: 'contract-template', title: '合同模板', path: '/contract-template', icon: 'ri-file-search-line', order: 5, children: [ { id: 'contract-search-ai', title: '智能搜索', path: '/contract-template/search', icon: 'ri-search-line', order: 1 }, { id: 'contract-list', title: '合同列表', path: '/contract-template/list', icon: 'ri-folder-line', order: 2 } ] }, { id: 'cross-checking', title: '交叉评查', path: '/cross-checking', icon: 'ri-color-filter-line', order: 7 } ], 'groupLeader': [ { id: 'home', title: '系统概览', path: '/home', icon: 'ri-home-line', order: 1 }, { id: 'file-management', title: '文件管理', path: '/files', icon: 'ri-folder-line', order: 3, children: [ { id: 'file-upload', title: '文件上传', path: '/files/upload', icon: 'ri-upload-cloud-line', order: 1 }, { id: 'documents', title: '文档列表', path: '/documents', icon: 'ri-file-list-3-line', order: 2 } ] }, { id: 'rule-management', title: '评查规则库', path: '/rules', icon: 'ri-book-3-line', order: 4, children: [ { id: 'rule-groups', title: '评查点分组', path: '/rule-groups', icon: 'ri-folder-open-line', order: 1 }, { id: 'rules-list', title: '评查点列表', path: '/rules', icon: 'ri-list-check-3', order: 2 }, { id: 'rules-file', title: '评查文件列表', path: '/rules-files', icon: 'ri-list-check-2', order: 3 } ] }, { id: 'contract-template', title: '合同模板', path: '/contract-template', icon: 'ri-file-search-line', order: 5, children: [ { id: 'contract-search-ai', title: '智能搜索', path: '/contract-template/search', icon: 'ri-search-line', order: 1 }, { id: 'contract-list', title: '合同列表', path: '/contract-template/list', icon: 'ri-folder-line', order: 2 } ] }, { id: 'cross-checking', title: '交叉评查', path: '/cross-checking', icon: 'ri-color-filter-line', order: 7 } ] }; /** * 根据角色获取用户可访问的路由 * @param roleKey 角色标识 (如: 'admin', 'common', 'deptLeader', 'groupLeader') * @returns 用户可访问的路由列表 */ export async function getUserRoutesByRole(roleKey: string): Promise<{ success: boolean; data?: MenuItem[]; error?: string; shouldRedirectToHome?: boolean }> { try { console.log(`获取角色 ${roleKey} 的路由权限`); // 首先获取角色ID const roleResult = await postgrestGet>("roles", { filter: { "role_key": `eq.${roleKey}` } }); if (roleResult.error || !roleResult.data || roleResult.data.length === 0) { console.error("角色不存在:", roleKey); toastService.error("角色不存在,请联系管理员配置权限后重新登录"); return { success: false, error: "角色不存在", shouldRedirectToHome: true }; } const roleId = roleResult.data[0].id; // 查询角色的路由权限 const roleRoutesResult = await postgrestGet>("role_route", { filter: { "role_id": `eq.${roleId}` } }); if (roleRoutesResult.error) { console.error("查询角色路由关联失败:", roleRoutesResult.error); toastService.error("查询角色路由关联失败,请稍后再试"); return { success: false, error: "查询角色路由关联失败", shouldRedirectToHome: true }; } const roleRoutes = roleRoutesResult.data || []; const routeIds = roleRoutes.map(item => item.route_id); if (routeIds.length === 0) { console.log(`角色 ${roleKey} 没有分配任何路由权限`); toastService.error("您的角色没有分配任何路由权限,请联系管理员配置权限"); return { success: false, error: "角色没有分配任何路由权限", shouldRedirectToHome: true }; } // 查询具体的路由信息 const routesResult = await postgrestGet("sys_routes", { filter: { "id": `in.(${routeIds.join(',')})`, "is_menu": "eq.1" }, order: "parent_id,meta->>order" }); if (routesResult.error) { console.error("查询路由信息失败:", routesResult.error); toastService.error("查询路由信息失败,请稍后再试"); return { success: false, error: "查询路由信息失败", shouldRedirectToHome: true }; } const routes = routesResult.data || []; // 构建菜单树 const menuItems = buildMenuTreeFromRoutes(routes); console.log(`角色 ${roleKey} 可访问 ${menuItems.length} 个路由`); return { success: true, data: menuItems }; } catch (error) { console.error("获取用户路由时发生错误:", error); toastService.error("获取用户路由时发生错误,请稍后再试"); return { success: false, error: `获取用户路由失败: ${error instanceof Error ? error.message : String(error)}`, shouldRedirectToHome: true }; } } /** * 从路由信息构建菜单树结构 * @param routes 路由信息数组 * @returns 菜单树结构 */ function buildMenuTreeFromRoutes(routes: RouteInfo[]): MenuItem[] { // 转换为MenuItem格式 const menuMap = new Map(); routes.forEach(route => { const menuItem: MenuItem = { id: route.name, title: route.meta.title, path: route.path, icon: route.meta.icon, order: route.meta.order || 0, requiredRole: route.meta.requiredRole }; menuMap.set(route.id, menuItem); }); // 构建父子关系 const rootItems: MenuItem[] = []; const itemsWithParent: Array<{ item: MenuItem; parentId: number }> = []; routes.forEach(route => { const menuItem = menuMap.get(route.id); if (!menuItem) return; if (route.parent_id === 0) { rootItems.push(menuItem); } else { itemsWithParent.push({ item: menuItem, parentId: route.parent_id }); } }); // 添加子菜单 itemsWithParent.forEach(({ item, parentId }) => { const parent = menuMap.get(parentId); if (parent) { if (!parent.children) { parent.children = []; } parent.children.push(item); } }); // 排序 rootItems.sort((a, b) => a.order - b.order); rootItems.forEach(item => { if (item.children) { item.children.sort((a, b) => a.order - b.order); } }); return rootItems; } /** * 根据用户角色映射到权限系统的角色标识 * @param userRole 前端用户角色 ('common' | 'admin' | 'deptLeader' | 'groupLeader') * @returns 数据库中的角色标识 */ export function mapUserRoleToRoleKey(userRole: string): string { const roleMapping: Record = { 'common': 'common', 'admin': 'admin', 'deptLeader': 'deptLeader', 'groupLeader': 'groupLeader' }; return roleMapping[userRole]; }