/** * 角色权限管理 API * 用于角色、路由权限、用户角色的管理 */ // ==================== 常量定义 ==================== /** * RBAC API 基础路径 * 注意:使用相对路径,会命中Remix API路由而不是后端服务器 */ const RBAC_API_BASE = '/api/v3/rbac'; /** * RBAC专用API客户端 - 使用fetch直接请求Remix API路由 */ async function rbacFetch(url: string, options: RequestInit = {}): Promise { console.log('🔗 [RBAC Fetch] 请求:', url, options.method || 'GET'); const response = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', ...options.headers } }); console.log('📡 [RBAC Fetch] 响应状态:', response.status, response.statusText); const data = await response.json(); console.log('📦 [RBAC Fetch] 响应数据:', data); if (!response.ok) { throw new Error(data.detail || data.message || `HTTP ${response.status}`); } return data; } /** * 统一响应处理函数 * 处理后端返回的统一格式响应 */ function handleApiResponse(response: ApiResponse): T { if (response.error) { throw new Error(response.error); } if (response.data && 'code' in response.data) { if (response.data.code !== 200) { throw new Error(response.data.message || '请求失败'); } return response.data.data as T; } // 如果没有code字段,直接返回data return response.data as T; } // ==================== 类型定义 ==================== /** * 路由信息 */ export interface RouteInfo { id: number; route_path: string; route_name: string; route_title: string; component?: string; parent_id?: number | null; icon?: string; sort_order: number; is_hidden: boolean; is_cache: boolean; status: number; children?: RouteInfo[]; } /** * 角色信息 */ export interface RoleInfo { id: number; role_key: string; role_name: string; data_scope: string; description: string; parent_role_id?: number | null; priority: number; is_system_role: boolean; created_at: string; updated_at: string; } /** * 角色-路由权限关联 */ export interface RoleRoutePermission { id: number; role_id: number; route_id: number; permission: string; // 'R' | 'RW' | 'NONE' created_at: string; } /** * 用户信息 */ export interface UserInfo { id: number; username: string; nick_name: string; phone_number?: string; email?: string; ou_name: string; status: number; is_leader: boolean; } /** * 用户-角色关联 */ export interface UserRoleRelation { id: number; user_id: number; role_id: number; created_at: string; } /** * RBAC权限信息 */ export interface Permission { id: number; permission_key: string; // 格式: module:resource:action module: string; // 模块名 resource: string; // 资源名 action: string; // 操作名 display_name: string; // 显示名称 description: string | null; permission_type: 'API' | 'MENU' | 'BUTTON'; is_system: boolean; parent_id: number | null; sort_order: number; children?: Permission[]; // 树形结构 } /** * 角色权限配置 */ export interface RolePermissionConfig { permission_id: number; grant_type?: 'GRANT' | 'DENY'; data_scope?: 'ALL' | 'DEPT' | 'SELF'; } /** * 角色权限详情 */ export interface RolePermissionDetail { id: number; permission_id: number; permission_key: string; display_name: string; grant_type: 'GRANT' | 'DENY'; data_scope: 'ALL' | 'DEPT' | 'SELF'; } // ==================== 模拟数据 ==================== /** * 模拟路由数据(树形结构) */ const mockRoutes: RouteInfo[] = [ { id: 1, route_path: '/documents', route_name: 'documents', route_title: '文档管理', icon: 'ri-file-text-line', sort_order: 1, is_hidden: false, is_cache: true, status: 1, parent_id: null, children: [ { id: 11, route_path: '/documents/list', route_name: 'documents-list', route_title: '文档列表', icon: 'ri-list-check', sort_order: 1, is_hidden: false, is_cache: true, status: 1, parent_id: 1 }, { id: 12, route_path: '/documents/upload', route_name: 'documents-upload', route_title: '文档上传', icon: 'ri-upload-line', sort_order: 2, is_hidden: false, is_cache: true, status: 1, parent_id: 1 } ] }, { id: 2, route_path: '/cross-checking', route_name: 'cross-checking', route_title: '交叉评查', icon: 'ri-exchange-line', sort_order: 2, is_hidden: false, is_cache: true, status: 1, parent_id: null, children: [ { id: 21, route_path: '/cross-checking/tasks', route_name: 'cross-checking-tasks', route_title: '评查任务', icon: 'ri-task-line', sort_order: 1, is_hidden: false, is_cache: true, status: 1, parent_id: 2 } ] }, { id: 3, route_path: '/settings', route_name: 'settings', route_title: '系统设置', icon: 'ri-settings-3-line', sort_order: 3, is_hidden: false, is_cache: true, status: 1, parent_id: null, children: [ { id: 31, route_path: '/settings/document-types', route_name: 'document-types', route_title: '文档类型管理', icon: 'ri-file-list-line', sort_order: 1, is_hidden: false, is_cache: true, status: 1, parent_id: 3 }, { id: 32, route_path: '/settings/rule-groups', route_name: 'rule-groups', route_title: '评查点分组', icon: 'ri-folder-line', sort_order: 2, is_hidden: false, is_cache: true, status: 1, parent_id: 3 }, { id: 33, route_path: '/settings/prompts', route_name: 'prompts', route_title: '提示词管理', icon: 'ri-message-line', sort_order: 3, is_hidden: false, is_cache: true, status: 1, parent_id: 3 } ] }, { id: 4, route_path: '/role-permissions', route_name: 'role-permissions', route_title: '角色权限管理', icon: 'ri-shield-user-line', sort_order: 4, is_hidden: false, is_cache: true, status: 1, parent_id: null } ]; /** * 模拟角色数据(与数据库实际数据一致) * 仅用于开发阶段API失败时的降级方案 */ const mockRoles: RoleInfo[] = [ { id: 1, role_key: 'admin', role_name: '市级管理员', data_scope: 'DEPT', description: '负责本地区的所有业务管理,不包括系统设置和角色权限管理', priority: 0, is_system_role: false, created_at: '2025-07-18 10:35:39', updated_at: '2025-07-18 10:35:39' }, { id: 2, role_key: 'common', role_name: '普通员工', data_scope: 'SELF', description: '仅能操作自己的数据', priority: 0, is_system_role: false, created_at: '2025-07-18 10:35:39', updated_at: '2025-07-18 10:35:39' }, { id: 52, role_key: 'provincial_admin', role_name: '省级管理员', data_scope: 'ALL', description: '拥有全部权限,可以管理所有地区的评查点规则、提示词、动态按钮、评查组', priority: 1, is_system_role: true, created_at: '2025-11-19 17:25:45', updated_at: '2025-11-19 17:25:45' } ]; /** * 模拟角色-路由权限关联数据 */ const mockRoleRoutePermissions: RoleRoutePermission[] = [ // 系统管理员拥有所有权限 { id: 1, role_id: 1, route_id: 1, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 2, role_id: 1, route_id: 11, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 3, role_id: 1, route_id: 12, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 4, role_id: 1, route_id: 2, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 5, role_id: 1, route_id: 21, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 6, role_id: 1, route_id: 3, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 7, role_id: 1, route_id: 31, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 8, role_id: 1, route_id: 32, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 9, role_id: 1, route_id: 33, permission: 'RW', created_at: '2024-01-01 10:00:00' }, { id: 10, role_id: 1, route_id: 4, permission: 'RW', created_at: '2024-01-01 10:00:00' }, // 省级管理员 { id: 11, role_id: 2, route_id: 1, permission: 'RW', created_at: '2024-01-02 10:00:00' }, { id: 12, role_id: 2, route_id: 11, permission: 'RW', created_at: '2024-01-02 10:00:00' }, { id: 13, role_id: 2, route_id: 12, permission: 'RW', created_at: '2024-01-02 10:00:00' }, { id: 14, role_id: 2, route_id: 3, permission: 'RW', created_at: '2024-01-02 10:00:00' }, { id: 15, role_id: 2, route_id: 31, permission: 'RW', created_at: '2024-01-02 10:00:00' }, { id: 16, role_id: 2, route_id: 32, permission: 'RW', created_at: '2024-01-02 10:00:00' }, // 普通用户 { id: 17, role_id: 4, route_id: 1, permission: 'R', created_at: '2024-01-04 10:00:00' }, { id: 18, role_id: 4, route_id: 11, permission: 'R', created_at: '2024-01-04 10:00:00' }, ]; /** * 模拟用户数据 */ const mockUsers: UserInfo[] = [ { id: 1, username: 'admin', nick_name: '系统管理员', phone_number: '13800138000', email: 'admin@example.com', ou_name: '系统管理部', status: 1, is_leader: true }, { id: 2, username: 'zhangsan', nick_name: '张三', phone_number: '13800138001', email: 'zhangsan@example.com', ou_name: '广东省局', status: 1, is_leader: true }, { id: 3, username: 'lisi', nick_name: '李四', phone_number: '13800138002', email: 'lisi@example.com', ou_name: '梅州市局', status: 1, is_leader: false }, { id: 4, username: 'wangwu', nick_name: '王五', phone_number: '13800138003', email: 'wangwu@example.com', ou_name: '云浮市局', status: 1, is_leader: false }, { id: 5, username: 'zhaoliu', nick_name: '赵六', phone_number: '13800138004', email: 'zhaoliu@example.com', ou_name: '揭阳市局', status: 1, is_leader: false } ]; /** * 模拟用户-角色关联数据 */ const mockUserRoles: UserRoleRelation[] = [ { id: 1, user_id: 1, role_id: 1, created_at: '2024-01-01 10:00:00' }, { id: 2, user_id: 2, role_id: 2, created_at: '2024-01-02 10:00:00' }, { id: 3, user_id: 3, role_id: 3, created_at: '2024-01-03 10:00:00' }, { id: 4, user_id: 4, role_id: 4, created_at: '2024-01-04 10:00:00' }, { id: 5, user_id: 5, role_id: 5, created_at: '2024-01-05 10:00:00' } ]; // ==================== API 函数 ==================== /** * 获取所有角色列表 * @param params 查询参数 */ export async function getRoles(params?: { page?: number; page_size?: number; role_key?: string; role_name?: string; include_system?: boolean; }): Promise { try { // 导入 axios-client 的 get 函数 const { get } = await import('~/api/axios-client'); console.log('🔍 [getRoles] 开始调用后端API:', `/api/v3/rbac/roles`, params); // 使用 axios-client 的 get 函数调用真实后端API const response = await get(`/api/v3/rbac/roles`, params || {}); console.log('📦 [getRoles] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // 后端响应格式: { code: 200, message: "success", data: { total, page, page_size, items: [...] } } let items: any[] = []; if (response.data && response.data.data && Array.isArray(response.data.data.items)) { items = response.data.data.items; } else if (response.data && Array.isArray(response.data.items)) { items = response.data.items; } console.log('✅ [getRoles] 解析出的角色数组:', items); // 数据格式转换(后端字段 -> 前端字段) const roles = items.map(role => ({ id: role.id, role_key: role.role_key, role_name: role.role_name, data_scope: role.data_scope, description: role.description || '', parent_role_id: role.parent_role_id || null, priority: role.priority || 0, is_system_role: role.is_system || false, created_at: role.created_at, updated_at: role.updated_at })); console.log('✅ [getRoles] 最终返回的角色列表,共', roles.length, '个角色'); return roles; } catch (error) { console.error('❌ [getRoles] 获取角色列表失败:', error); // 失败时返回空数组 return []; } } /** * 获取角色详情 * @param roleId 角色ID */ export async function getRoleDetail(roleId: number): Promise { try { const response = await get(`${RBAC_API_BASE}/roles/${roleId}`); const role = handleApiResponse(response); return { id: role.id, role_key: role.role_key, role_name: role.role_name, data_scope: role.data_scope, description: role.description || '', parent_role_id: role.parent_role_id || null, priority: role.priority || 0, is_system_role: role.is_system, created_at: role.created_at, updated_at: role.updated_at }; } catch (error) { console.error('获取角色详情失败:', error); return null; } } /** * 获取所有路由(树形结构) * 从后端API获取当前用户可访问的所有路由 */ export async function getRoutes(): Promise { try { const { get } = await import('~/api/axios-client'); console.log('🔍 [getRoutes] 开始调用后端API: /rbac/user/routes'); // 调用后端API获取当前用户的路由(provincial_admin应该有所有路由权限) const response = await get('/rbac/user/routes'); if (response.error) { console.error('❌ [getRoutes] API调用失败:', response.error); throw new Error(response.error); } // 后端响应格式: { code: 200, msg: "success", data: { user_id, username, routes: [...], routes_flat: [...] } } let routes: any[] = []; if (response.data && response.data.data && Array.isArray(response.data.data.routes)) { routes = response.data.data.routes; } else if (response.data && Array.isArray(response.data.routes)) { // 兼容可能的响应格式 routes = response.data.routes; } console.log('✅ [getRoutes] 成功获取路由数据,共', routes.length, '个顶级路由'); // 将后端数据转换为前端RouteInfo格式 const mapRouteData = (route: any): RouteInfo => ({ id: route.id, route_path: route.route_path, route_name: route.route_name, route_title: route.route_title, icon: route.icon || '', sort_order: route.sort_order || 0, is_hidden: route.is_hidden || false, is_cache: route.is_cache !== false, // 默认true status: route.status || 1, parent_id: route.parent_id || null, component: route.component, children: route.children ? route.children.map(mapRouteData) : undefined }); return routes.map(mapRouteData); } catch (error) { console.error('❌ [getRoutes] 获取路由数据失败:', error); // 失败时返回空数组,让前端显示错误提示 return []; } } /** * 获取指定角色的路由权限 * @param roleId 角色ID */ export async function getRoleRoutePermissions(roleId: number): Promise { try { // 导入 axios-client 的 get 函数 const { get } = await import('~/api/axios-client'); console.log('🔍 [getRoleRoutePermissions] 开始调用后端API:', `/rbac/roles/${roleId}/routes`); // 使用 axios-client 的 get 函数调用真实后端API const response = await get(`/rbac/roles/${roleId}/routes`); console.log('📦 [getRoleRoutePermissions] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // 后端响应格式: { code: 200, msg: "success", data: { role_id, routes: [...] } } let routes: any[] = []; if (response.data && response.data.data && Array.isArray(response.data.data.routes)) { routes = response.data.data.routes; } // 将路由数据转换为RoleRoutePermission格式 const permissions = routes.map((route, index) => ({ id: index + 1, role_id: roleId, route_id: route.id, permission: 'RW', // 默认读写权限 created_at: new Date().toISOString() })); console.log('✅ [getRoleRoutePermissions] 获取角色路由权限成功:', permissions); return permissions; } catch (error) { console.error('❌ [getRoleRoutePermissions] 获取角色路由权限失败:', error); // 失败时返回空数组,避免页面崩溃 return []; } } /** * 更新角色的路由权限 * @param roleId 角色ID * @param routeIds 路由ID数组 */ export async function updateRoleRoutePermissions( roleId: number, routeIds: number[] ): Promise<{ success: boolean; message: string }> { try { // 导入 axios-client 的 put 函数 const { put } = await import('~/api/axios-client'); console.log('🔍 [updateRoleRoutePermissions] 开始调用后端API:', `/rbac/roles/${roleId}/routes`, routeIds); // 使用 axios-client 的 put 函数调用真实后端API const response = await put(`/rbac/roles/${roleId}/routes`, { route_ids: routeIds, permission: 'RW' }); console.log('📦 [updateRoleRoutePermissions] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // 后端响应格式: { code: 200, msg: "success", data: { role_id, assigned_count, removed_count, route_ids } } let message = '角色权限更新成功'; if (response.data && response.data.msg) { message = response.data.msg; } else if (response.data && response.data.data) { const { assigned_count, removed_count } = response.data.data; message = `成功分配 ${assigned_count} 个路由,移除了 ${removed_count} 个旧路由`; } console.log('✅ [updateRoleRoutePermissions] 角色权限更新成功'); return { success: true, message }; } catch (error) { console.error('❌ [updateRoleRoutePermissions] 更新角色权限失败:', error); return { success: false, message: error instanceof Error ? error.message : '更新角色权限失败' }; } } // ==================== 用户角色管理 API ==================== /** * 获取指定角色的用户列表 * @param roleId 角色ID * @param params 查询参数 */ export async function getRoleUsers( roleId: number, params?: { page?: number; page_size?: number; area?: string; username?: string; } ): Promise { try { // 导入 axios-client 的 get 函数 const { get } = await import('~/api/axios-client'); console.log('🔍 [getRoleUsers] 开始调用后端API:', `/api/v3/rbac/roles/${roleId}/users`, params); // 构建查询参数对象 const queryParams: Record = {}; if (params?.page) queryParams.page = params.page; if (params?.page_size) queryParams.page_size = params.page_size; if (params?.area) queryParams.area = params.area; if (params?.username) queryParams.username = params.username; // 使用 axios-client 的 get 函数调用真实后端API const response = await get(`/api/v3/rbac/roles/${roleId}/users`, queryParams); console.log('📦 [getRoleUsers] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // 后端响应格式: { code: 200, message: "success", data: { total, page, page_size, items: [...] } } let items: any[] = []; if (response.data && response.data.data && Array.isArray(response.data.data.items)) { items = response.data.data.items; } else if (response.data && Array.isArray(response.data.items)) { items = response.data.items; } console.log('✅ [getRoleUsers] 解析出的用户数组:', items); const users = items.map((user: any) => ({ id: user.user_id || user.id, username: user.username, nick_name: user.nick_name, phone_number: user.phone_number || '', email: user.email || '', ou_name: user.ou_name, status: user.status || 1, is_leader: user.is_leader || false })); console.log('✅ [getRoleUsers] 最终返回的用户列表:', users); return users; } catch (error) { console.error('❌ [getRoleUsers] 获取角色用户列表失败:', error); return []; } } /** * 获取所有用户列表 * @param params 查询参数 */ export async function getAllUsers(params?: { page?: number; page_size?: number; area?: string; username?: string; }): Promise { try { // 导入 axios-client 的 get 函数 const { get } = await import('~/api/axios-client'); console.log('🔍 [getAllUsers] 开始调用后端API:', '/admin/users/users', params); // 构建查询参数对象 const queryParams: Record = {}; if (params?.page) queryParams.page = params.page; if (params?.page_size) queryParams.page_size = params.page_size; if (params?.username) queryParams.search = params.username; // 使用 axios-client 的 get 函数,会自动添加 baseURL 和 Authorization const response = await get('/admin/users/users', queryParams); console.log('📦 [getAllUsers] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // axios-client 返回格式: { data: { users: [...], total: number }, status: 200 } // 后端实际返回: { users: [...], total: number } let users: any[] = []; if (response.data) { // 如果 response.data 是对象且包含 users 字段 if (response.data.users && Array.isArray(response.data.users)) { users = response.data.users; } // 如果 response.data 本身就是数组 else if (Array.isArray(response.data)) { users = response.data; } } console.log('✅ [getAllUsers] 解析出的用户数组:', users); console.log('✅ [getAllUsers] 用户数量:', users.length); const userList = users.map(user => ({ id: user.user_id || user.id, // 优先使用 user_id,兼容不同的后端响应格式 username: user.username, nick_name: user.nick_name, phone_number: user.phone_number || '', email: user.email || '', ou_name: user.ou_name, status: user.status || 1, is_leader: user.is_leader || false })); console.log('✅ [getAllUsers] 最终返回的用户列表:', userList); return userList; } catch (error) { console.error('❌ [getAllUsers] 获取用户列表失败:', error); return []; } } /** * 为用户分配角色 * @param userId 用户ID * @param roleIds 角色ID数组 */ export async function assignUserRoles( userId: number, roleIds: number[] ): Promise<{ success: boolean; message: string }> { try { // 导入 axios-client 的 post 函数 const { post } = await import('~/api/axios-client'); console.log('🔍 [assignUserRoles] 开始调用后端API:', `/api/v3/rbac/users/${userId}/roles`, roleIds); // 使用 axios-client 的 post 函数调用真实后端API const response = await post(`/api/v3/rbac/users/${userId}/roles`, { role_ids: roleIds }); console.log('📦 [assignUserRoles] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // 后端响应格式: { code: 200, message: "角色分配成功", data: { user_id, roles: [...] } } let message = '用户角色分配成功'; if (response.data && response.data.message) { message = response.data.message; } console.log('✅ [assignUserRoles] 角色分配成功'); return { success: true, message }; } catch (error) { console.error('❌ [assignUserRoles] 分配用户角色失败:', error); return { success: false, message: error instanceof Error ? error.message : '分配失败' }; } } /** * 移除用户角色 * @param userId 用户ID * @param roleId 角色ID */ export async function revokeUserRole( userId: number, roleId: number ): Promise<{ success: boolean; message: string }> { try { // 导入 axios-client 的 del 函数 const { del } = await import('~/api/axios-client'); console.log('🔍 [revokeUserRole] 开始调用后端API:', `/api/v3/rbac/users/${userId}/roles/${roleId}`); // 使用 axios-client 的 del 函数调用真实后端API const response = await del(`/api/v3/rbac/users/${userId}/roles/${roleId}`); console.log('📦 [revokeUserRole] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // 后端响应格式: { code: 200, message: "角色移除成功" } let message = '用户角色移除成功'; if (response.data && response.data.message) { message = response.data.message; } console.log('✅ [revokeUserRole] 角色移除成功'); return { success: true, message }; } catch (error) { console.error('❌ [revokeUserRole] 移除用户角色失败:', error); return { success: false, message: error instanceof Error ? error.message : '移除失败' }; } } /** * 创建新角色 * @param roleData 角色数据 */ export async function createRole( roleData: Omit ): Promise<{ success: boolean; message: string; data?: RoleInfo }> { try { // 导入 axios-client 的 post 函数 const { post } = await import('~/api/axios-client'); console.log('🔍 [createRole] 开始调用后端API:', `/api/v3/rbac/roles`, roleData); // 使用 axios-client 的 post 函数调用真实后端API const response = await post(`/api/v3/rbac/roles`, { role_key: roleData.role_key, role_name: roleData.role_name, description: roleData.description || '', data_scope: roleData.data_scope || 'SELF', metadata: {} }); console.log('📦 [createRole] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } // 后端响应格式: { code: 200, message: "角色创建成功", data: { id, role_key, ... } } const data = response.data?.data || response.data; return { success: true, message: response.data?.message || '角色创建成功', data: { id: data.id, role_key: data.role_key, role_name: data.role_name, data_scope: data.data_scope, description: data.description || '', parent_role_id: data.parent_role_id || null, priority: data.priority || 0, is_system_role: data.is_system || false, created_at: data.created_at, updated_at: data.updated_at } }; } catch (error) { console.error('❌ [createRole] 创建角色失败:', error); return { success: false, message: error instanceof Error ? error.message : '创建角色失败' }; } } /** * 更新角色信息 * @param roleId 角色ID * @param roleData 角色数据 */ export async function updateRole( roleId: number, roleData: Partial> ): Promise<{ success: boolean; message: string }> { try { // 导入 axios-client 的 put 函数 const { put } = await import('~/api/axios-client'); const updatePayload: any = {}; if (roleData.role_name !== undefined) updatePayload.role_name = roleData.role_name; if (roleData.description !== undefined) updatePayload.description = roleData.description; if (roleData.data_scope !== undefined) updatePayload.data_scope = roleData.data_scope; if (roleData.priority !== undefined) updatePayload.priority = roleData.priority; if (roleData.parent_role_id !== undefined) updatePayload.parent_role_id = roleData.parent_role_id; console.log('🔍 [updateRole] 开始调用后端API:', `/api/v3/rbac/roles/${roleId}`, updatePayload); const response = await put(`/api/v3/rbac/roles/${roleId}`, updatePayload); console.log('📦 [updateRole] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } return { success: true, message: response.data?.message || '角色更新成功' }; } catch (error) { console.error('❌ [updateRole] 更新角色失败:', error); return { success: false, message: error instanceof Error ? error.message : '更新角色失败' }; } } /** * 删除角色 * @param roleId 角色ID * @param force 是否强制删除(会自动解除用户关联) */ export async function deleteRole( roleId: number, force = false ): Promise<{ success: boolean; message: string }> { try { // 导入 axios-client 的 del 函数 const { del } = await import('~/api/axios-client'); const url = `/api/v3/rbac/roles/${roleId}${force ? '?force=true' : ''}`; console.log('🔍 [deleteRole] 开始调用后端API:', url); const response = await del(url); console.log('📦 [deleteRole] 后端API完整响应:', JSON.stringify(response, null, 2)); if (response.error) { throw new Error(response.error); } return { success: true, message: response.data?.message || '角色删除成功' }; } catch (error) { console.error('❌ [deleteRole] 删除角色失败:', error); return { success: false, message: error instanceof Error ? error.message : '删除角色失败' }; } } // ==================== 权限管理 API ==================== /** * 获取权限列表(树形或平铺) * @param format 格式:tree(树形)或 flat(平铺) * @param params 查询参数 */ export async function getPermissions( format: 'tree' | 'flat' = 'tree', params?: { module?: string; permission_type?: 'API' | 'MENU' | 'BUTTON'; include_system?: boolean; } ): Promise { try { const response = await get(`${RBAC_API_BASE}/permissions`, { format, ...params }); const data = handleApiResponse(response); return data; } catch (error) { console.error('获取权限列表失败:', error); return []; } } /** * 获取权限详情 * @param permissionId 权限ID */ export async function getPermissionDetail(permissionId: number): Promise { try { const response = await get(`${RBAC_API_BASE}/permissions/${permissionId}`); const data = handleApiResponse(response); return data; } catch (error) { console.error('获取权限详情失败:', error); return null; } } /** * 创建权限 * @param permissionData 权限数据 */ export async function createPermission( permissionData: Omit ): Promise<{ success: boolean; message: string; data?: Permission }> { try { // 从 permission_key 解析 module, resource, action const [module, resource, action] = permissionData.permission_key.split(':'); const response = await post(`${RBAC_API_BASE}/permissions`, { permission_key: permissionData.permission_key, display_name: permissionData.display_name, description: permissionData.description || '', module, resource, action, permission_type: permissionData.permission_type || 'API', parent_id: permissionData.parent_id || null, sort_order: permissionData.sort_order || 0, metadata: {} }); const data = handleApiResponse(response); return { success: true, message: '权限创建成功', data }; } catch (error) { console.error('创建权限失败:', error); return { success: false, message: error instanceof Error ? error.message : '创建权限失败' }; } } /** * 更新权限 * @param permissionId 权限ID * @param permissionData 权限数据 */ export async function updatePermission( permissionId: number, permissionData: Partial> ): Promise<{ success: boolean; message: string }> { try { const response = await put(`${RBAC_API_BASE}/permissions/${permissionId}`, permissionData); handleApiResponse(response); return { success: true, message: '权限更新成功' }; } catch (error) { console.error('更新权限失败:', error); return { success: false, message: error instanceof Error ? error.message : '更新权限失败' }; } } /** * 删除权限 * @param permissionId 权限ID */ export async function deletePermission( permissionId: number ): Promise<{ success: boolean; message: string }> { try { const response = await del(`${RBAC_API_BASE}/permissions/${permissionId}`); handleApiResponse(response); return { success: true, message: '权限删除成功' }; } catch (error) { console.error('删除权限失败:', error); return { success: false, message: error instanceof Error ? error.message : '删除权限失败' }; } } // ==================== 角色权限关联 API ==================== /** * 获取角色的所有权限 * @param roleId 角色ID */ export async function getRolePermissions(roleId: number): Promise { try { const response = await get(`${RBAC_API_BASE}/roles/${roleId}/permissions`); const data = handleApiResponse<{ permissions: any[] }>(response); return data.permissions.map(perm => ({ id: perm.id, permission_id: perm.permission_id, permission_key: perm.permission_key, display_name: perm.display_name, grant_type: perm.grant_type || 'GRANT', data_scope: perm.data_scope || 'ALL' })); } catch (error) { console.error('获取角色权限失败:', error); return []; } } /** * 批量分配权限给角色 * @param roleId 角色ID * @param permissions 权限配置列表 * @param replace 是否替换全部(true=替换,false=追加) */ export async function assignPermissionsToRole( roleId: number, permissions: RolePermissionConfig[], replace = false ): Promise<{ success: boolean; message: string }> { try { const response = await post(`${RBAC_API_BASE}/roles/${roleId}/permissions`, { permissions: permissions.map(p => ({ permission_id: p.permission_id, grant_type: p.grant_type || 'GRANT', data_scope: p.data_scope || 'ALL' })), replace }); handleApiResponse(response); return { success: true, message: '权限分配成功' }; } catch (error) { console.error('分配权限失败:', error); return { success: false, message: error instanceof Error ? error.message : '分配权限失败' }; } } /** * 更新单个权限配置 * @param roleId 角色ID * @param permissionId 权限ID * @param config 权限配置 */ export async function updateRolePermission( roleId: number, permissionId: number, config: Partial ): Promise<{ success: boolean; message: string }> { try { const response = await put( `${RBAC_API_BASE}/roles/${roleId}/permissions/${permissionId}`, config ); handleApiResponse(response); return { success: true, message: '权限配置更新成功' }; } catch (error) { console.error('更新权限配置失败:', error); return { success: false, message: error instanceof Error ? error.message : '更新权限配置失败' }; } } /** * 移除角色权限 * @param roleId 角色ID * @param permissionId 权限ID */ export async function revokeRolePermission( roleId: number, permissionId: number ): Promise<{ success: boolean; message: string }> { try { const response = await del(`${RBAC_API_BASE}/roles/${roleId}/permissions/${permissionId}`); handleApiResponse(response); return { success: true, message: '权限移除成功' }; } catch (error) { console.error('移除权限失败:', error); return { success: false, message: error instanceof Error ? error.message : '移除权限失败' }; } } /** * 获取指定用户的所有角色 * @param userId 用户ID * @returns 用户的角色列表 */ export async function getUserRoles(userId: number): Promise { try { const { get } = await import('~/api/axios-client'); console.log('🔍 [getUserRoles] 开始调用后端API:', `/api/v3/rbac/users/${userId}/roles`); const response = await get(`/api/v3/rbac/users/${userId}/roles`); if (response.error) { console.error('❌ [getUserRoles] API调用失败:', response.error); throw new Error(response.error); } // 后端响应格式: { code: 200, msg: "success", data: { user_id, username, roles: [...] } } let roles: any[] = []; if (response.data && response.data.data && Array.isArray(response.data.data.roles)) { roles = response.data.data.roles; } else if (response.data && Array.isArray(response.data.roles)) { // 兼容可能的响应格式 roles = response.data.roles; } console.log('✅ [getUserRoles] 成功获取用户角色,共', roles.length, '个角色'); // 将后端数据转换为RoleInfo格式 return roles.map(role => ({ id: role.id || role.role_id, role_key: role.role_key, role_name: role.role_name, data_scope: role.data_scope, description: role.description || '', priority: role.priority || 0, is_system_role: role.is_system || false, created_at: role.created_at || '', updated_at: role.updated_at || '' })); } catch (error) { console.error('❌ [getUserRoles] 获取用户角色失败:', error); // 失败时返回空数组 return []; } }