1447 lines
43 KiB
TypeScript
1447 lines
43 KiB
TypeScript
/**
|
||
* 角色权限管理 API
|
||
* 用于角色、路由权限、用户角色的管理
|
||
*/
|
||
|
||
import { get, post, put, del } from '~/api/axios-client';
|
||
|
||
// ==================== 类型定义 ====================
|
||
|
||
/**
|
||
* API 响应类型
|
||
*/
|
||
interface ApiResponse<T> {
|
||
data?: T;
|
||
error?: string;
|
||
status?: number;
|
||
headers?: Record<string, string>;
|
||
}
|
||
|
||
// ==================== 常量定义 ====================
|
||
|
||
/**
|
||
* RBAC API 基础路径
|
||
* 注意:使用相对路径,会命中Remix API路由而不是后端服务器
|
||
*/
|
||
const RBAC_API_BASE = '/api/v3/rbac';
|
||
|
||
/**
|
||
* 统一响应处理函数
|
||
* 处理后端返回的统一格式响应
|
||
*/
|
||
function handleApiResponse<T>(response: ApiResponse<any>): 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;
|
||
}
|
||
|
||
// ==================== 类型定义 ====================
|
||
|
||
/**
|
||
* API权限信息(关联到路由的权限)
|
||
* v3.0新增:每个路由可以关联多个API操作权限
|
||
* v3.6新增:支持通用权限(related_routes 字段)
|
||
* v3.7新增:is_shared 字段由后端直接返回
|
||
*/
|
||
export interface ApiPermission {
|
||
id: number;
|
||
permission_key: string; // 权限标识,如 "evaluation_group:create:write"
|
||
display_name: string; // 显示名称,如 "创建评查点分组"
|
||
api_method: string; // HTTP方法:GET | POST | PUT | DELETE
|
||
api_path: string; // API路径,如 "/api/v3/evaluation-point-groups"
|
||
route_id?: number | null; // v3.6: 关联的路由ID(独立权限使用)
|
||
related_routes?: number[] | null; // v3.6: 关联的多个路由ID(通用权限使用)
|
||
is_shared?: boolean; // v3.7: 是否为通用权限(后端返回)
|
||
}
|
||
|
||
/**
|
||
* 路由信息
|
||
*/
|
||
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;
|
||
permissions?: ApiPermission[]; // v3.0新增:关联的API权限列表
|
||
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 UserRoleInfo {
|
||
role_id: number;
|
||
role_key: string;
|
||
role_name: string;
|
||
}
|
||
|
||
/**
|
||
* 用户信息(v3.4: 增加角色信息)
|
||
*/
|
||
export interface UserInfo {
|
||
id: number;
|
||
username: string;
|
||
nick_name: string;
|
||
phone_number?: string;
|
||
email?: string;
|
||
area: string; // v3.3: 地区字段,用于权限隔离(省/市级别)
|
||
ou_name: string; // 部门名称,用于组织显示(部门级别)
|
||
status: number;
|
||
is_leader: boolean;
|
||
// v3.4: 用户角色信息(从 /api/v3/rbac/users 返回)
|
||
roles?: UserRoleInfo[];
|
||
tenant_name?: string; // 租户名称(多租户场景)
|
||
dep_name?: string; // 部门名称(多租户场景)
|
||
}
|
||
|
||
/**
|
||
* 用户-角色关联
|
||
*/
|
||
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';
|
||
}
|
||
|
||
/**
|
||
* 获取所有角色列表
|
||
* @param params 查询参数
|
||
*/
|
||
export async function getRoles(params?: {
|
||
page?: number;
|
||
page_size?: number;
|
||
role_key?: string;
|
||
role_name?: string;
|
||
include_system?: boolean;
|
||
}): Promise<RoleInfo[]> {
|
||
try {
|
||
// 使用 axios-client 的 get 函数调用真实后端API
|
||
const response = await get<any>(`/api/v3/rbac/roles`, params || {});
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
// 数据格式转换(后端字段 -> 前端字段)
|
||
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.role_key == 'admin' || role.role_key == 'common') ? true : role.is_system || false,
|
||
created_at: role.created_at,
|
||
updated_at: role.updated_at
|
||
}));
|
||
|
||
return roles;
|
||
} catch (error) {
|
||
console.error('❌ [getRoles] 获取角色列表失败:', error);
|
||
// 失败时返回空数组
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取角色详情
|
||
* @param roleId 角色ID
|
||
*/
|
||
export async function getRoleDetail(roleId: number): Promise<RoleInfo | null> {
|
||
try {
|
||
const response = await get<any>(`${RBAC_API_BASE}/roles/${roleId}`);
|
||
const role = handleApiResponse<any>(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<RouteInfo[]> {
|
||
try {
|
||
// 调用后端API获取当前用户的路由(provincial_admin应该有所有路由权限)
|
||
const response = await get<any>('/api/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;
|
||
}
|
||
|
||
// 将后端数据转换为前端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 [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* v3.7: 获取所有路由列表(管理员接口)
|
||
* 使用 /api/v3/routes 接口获取所有路由
|
||
* @param format 返回格式(tree/flat)
|
||
* @param includeHidden 是否包含隐藏路由
|
||
*/
|
||
export async function getAllRoutes(
|
||
format: 'tree' | 'flat' = 'tree',
|
||
includeHidden = false
|
||
): Promise<RouteInfo[]> {
|
||
try {
|
||
const response = await get<any>('/api/v3/routes', {
|
||
format,
|
||
include_hidden: includeHidden
|
||
});
|
||
|
||
if (response.error) {
|
||
console.error('❌ [getAllRoutes] API调用失败:', response.error);
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
// 后端响应格式: 直接返回路由数组(树形或平铺)
|
||
let routes: any[] = [];
|
||
if (response.data) {
|
||
// 如果是包装格式 { code, message, data: [...] }
|
||
if (response.data.code === 200 && Array.isArray(response.data.data)) {
|
||
routes = response.data.data;
|
||
}
|
||
// 如果直接是数组
|
||
else if (Array.isArray(response.data)) {
|
||
routes = response.data;
|
||
}
|
||
}
|
||
|
||
// 将后端数据转换为前端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,
|
||
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('❌ [getAllRoutes] 获取路由数据失败:', error);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取指定角色的路由权限
|
||
* @param roleId 角色ID
|
||
*/
|
||
export async function getRoleRoutePermissions(roleId: number): Promise<RoleRoutePermission[]> {
|
||
try {
|
||
// 使用 axios-client 的 get 函数调用真实后端API
|
||
const response = await get<any>(`/api/rbac/roles/${roleId}/routes`);
|
||
|
||
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("路由权限数据", permissions)
|
||
|
||
return permissions;
|
||
} catch (error) {
|
||
console.error('❌ [getRoleRoutePermissions] 获取角色路由权限失败:', error);
|
||
// 失败时返回空数组,避免页面崩溃
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取角色的路由权限(含API权限)- v3.0新增
|
||
* 返回树形结构的路由,每个路由包含关联的API权限
|
||
* @param roleId 角色ID
|
||
*/
|
||
export async function getRoleRoutesWithPermissions(roleId: number): Promise<{
|
||
routes: RouteInfo[];
|
||
selectedRouteIds: number[];
|
||
selectedPermissionIds: number[];
|
||
}> {
|
||
try {
|
||
const response = await get<any>(`/api/rbac/roles/${roleId}/routes`);
|
||
|
||
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;
|
||
} else if (response.data && Array.isArray(response.data.routes)) {
|
||
routes = response.data.routes;
|
||
}
|
||
|
||
// 递归转换路由数据格式
|
||
const mapRouteData = (route: any): any => ({
|
||
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,
|
||
status: route.status || 1,
|
||
parent_id: route.parent_id || null,
|
||
component: route.component,
|
||
// v3.2: 添加 enabled 字段
|
||
enabled: route.enabled !== undefined ? route.enabled : true,
|
||
// v3.0: 转换permissions数组
|
||
permissions: Array.isArray(route.permissions) ? route.permissions.map((p: any) => ({
|
||
id: p.id,
|
||
permission_key: p.permission_key,
|
||
display_name: p.display_name,
|
||
api_method: p.api_method,
|
||
api_path: p.api_path
|
||
})) : [],
|
||
children: route.children ? route.children.map(mapRouteData) : undefined
|
||
});
|
||
|
||
const mappedRoutes = routes.map(mapRouteData);
|
||
|
||
// v3.2: 收集已启用的路由ID(enabled=true)
|
||
const collectRouteIds = (routes: any[]): number[] => {
|
||
let ids: number[] = [];
|
||
routes.forEach(route => {
|
||
// v3.2: 只收集 enabled=true 的路由
|
||
if (route.enabled) {
|
||
ids.push(route.id);
|
||
}
|
||
if (route.children) {
|
||
ids = ids.concat(collectRouteIds(route.children));
|
||
}
|
||
});
|
||
return ids;
|
||
};
|
||
|
||
// v3.5: 修复BUG - 删除了 collectPermissionIds 函数
|
||
// BUG说明:从路由元数据收集权限ID是错误的,因为路由的permissions数组包含的仅仅是权限定义,
|
||
// 而不是实际授权状态。实际授权状态应该从 `/api/v3/rbac/role-permissions` 接口获取。
|
||
//
|
||
// 之前的错误实现:
|
||
// const collectPermissionIds = (routes: RouteInfo[]): number[] => {
|
||
// let ids: number[] = [];
|
||
// routes.forEach(route => {
|
||
// if (route.permissions) {
|
||
// ids = ids.concat(route.permissions.map(p => p.id));
|
||
// }
|
||
// });
|
||
// return ids;
|
||
// };
|
||
//
|
||
// 修复方案:返回空数组,由调用方使用 getRolePermissions() 获取实际授权数据
|
||
|
||
const selectedRouteIds = collectRouteIds(mappedRoutes);
|
||
const selectedPermissionIds: number[] = []; // v3.5: 修复BUG - 返回空数组
|
||
|
||
return {
|
||
routes: mappedRoutes,
|
||
selectedRouteIds,
|
||
selectedPermissionIds
|
||
};
|
||
} catch (error) {
|
||
console.error('❌ [getRoleRoutesWithPermissions] 获取角色路由权限失败:', error);
|
||
return {
|
||
routes: [],
|
||
selectedRouteIds: [],
|
||
selectedPermissionIds: []
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 保存角色的API权限 - v3.0新增
|
||
* @param roleId 角色ID
|
||
* @param permissionIds 权限ID数组
|
||
*/
|
||
export async function saveRoleApiPermissions(
|
||
roleId: number,
|
||
permissionIds: number[],
|
||
scopePermissionIds: number[] = []
|
||
): Promise<{ success: boolean; message: string }> {
|
||
try {
|
||
// 构建权限配置
|
||
const permissions = permissionIds.map(id => ({
|
||
permission_id: id,
|
||
grant_type: 'GRANT',
|
||
data_scope: 'ALL'
|
||
}));
|
||
|
||
// v3.4: 使用文档规范的API路径(查询参数方式)
|
||
const response = await post<any>('/api/v3/rbac/role-permissions', {
|
||
role_id: roleId,
|
||
permissions,
|
||
replace: true, // 替换模式:仅替换当前页面涉及的权限范围
|
||
replace_scope_permission_ids: scopePermissionIds
|
||
});
|
||
|
||
if (response.error) {
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
let message = 'API权限保存成功';
|
||
if (response.data && response.data.message) {
|
||
message = response.data.message;
|
||
} else if (response.data && response.data.data) {
|
||
const { assigned_count } = response.data.data;
|
||
message = `成功分配 ${assigned_count} 个API权限`;
|
||
}
|
||
|
||
return { success: true, message };
|
||
} catch (error) {
|
||
console.error('❌ [saveRoleApiPermissions] 保存API权限失败:', error);
|
||
return {
|
||
success: false,
|
||
message: error instanceof Error ? error.message : '保存API权限失败'
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 原子保存角色的菜单权限与 API 权限
|
||
* @param roleId 角色ID
|
||
* @param routeIds 路由ID数组
|
||
* @param permissionIds 权限ID数组
|
||
* @param scopePermissionIds 本页允许被替换清理的权限范围
|
||
*/
|
||
export async function saveRoleAccess(
|
||
roleId: number,
|
||
routeIds: number[],
|
||
permissionIds: number[],
|
||
scopePermissionIds: number[] = []
|
||
): Promise<{ success: boolean; message: string; code?: number }> {
|
||
try {
|
||
const response = await post<any>(`/api/v3/rbac/roles/${roleId}/access`, {
|
||
route_ids: routeIds,
|
||
permission_ids: permissionIds,
|
||
route_permission: 'RW',
|
||
replace_scope_permission_ids: scopePermissionIds
|
||
});
|
||
|
||
if (response.error) {
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
if (response.data?.code && response.data.code !== 200) {
|
||
return {
|
||
success: false,
|
||
message: response.data.message || '角色权限保存失败',
|
||
code: response.data.code
|
||
};
|
||
}
|
||
|
||
return {
|
||
success: true,
|
||
message: response.data?.message || '角色权限保存成功'
|
||
};
|
||
} catch (error) {
|
||
console.error('❌ [saveRoleAccess] 保存角色联合权限失败:', error);
|
||
return {
|
||
success: false,
|
||
message: error instanceof Error ? error.message : '角色权限保存失败'
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 更新角色的路由权限 - v3.2更新
|
||
* @param roleId 角色ID
|
||
* @param routeIds 路由ID数组
|
||
*/
|
||
export async function updateRoleRoutePermissions(
|
||
roleId: number,
|
||
routeIds: number[]
|
||
): Promise<{ success: boolean; message: string; code?: number }> {
|
||
try {
|
||
// 使用 axios-client 的 put 函数调用真实后端API
|
||
const response = await put<any>(`/api/rbac/roles/${roleId}/routes`, {
|
||
route_ids: routeIds,
|
||
permission: 'RW'
|
||
});
|
||
|
||
if (response.error) {
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
// v3.3: 处理权限不足错误
|
||
if (response.data && response.data.code === 4003) {
|
||
return {
|
||
success: false,
|
||
message: response.data.msg || '权限不足:仅省级管理员可以修改角色路由权限',
|
||
code: 4003
|
||
};
|
||
}
|
||
|
||
// v3.2: 新响应格式: { code: 200, msg: "success", data: { role_id, enabled_count, disabled_count, inserted_count, route_ids } }
|
||
let message = '角色权限更新成功';
|
||
if (response.data && response.data.msg) {
|
||
message = response.data.msg;
|
||
} else if (response.data && response.data.data) {
|
||
const { enabled_count, disabled_count, inserted_count } = response.data.data;
|
||
if (enabled_count !== undefined && disabled_count !== undefined) {
|
||
message = `成功启用 ${enabled_count} 个路由,禁用 ${disabled_count} 个路由`;
|
||
if (inserted_count && inserted_count > 0) {
|
||
message += `,新增 ${inserted_count} 个路由关联`;
|
||
}
|
||
} else {
|
||
// 兼容旧版本响应格式
|
||
const { assigned_count, removed_count } = response.data.data;
|
||
if (assigned_count !== undefined && removed_count !== undefined) {
|
||
message = `成功分配 ${assigned_count} 个路由,移除了 ${removed_count} 个旧路由`;
|
||
}
|
||
}
|
||
}
|
||
|
||
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<UserInfo[]> {
|
||
try {
|
||
// 导入 axios-client 的 get 函数
|
||
|
||
// 构建查询参数对象
|
||
const queryParams: Record<string, any> = {};
|
||
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<any>(`/api/v3/rbac/roles/${roleId}/users`, queryParams);
|
||
|
||
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;
|
||
}
|
||
|
||
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 || '',
|
||
area: user.area || '', // v3.3: 地区字段,用于权限隔离
|
||
ou_name: user.ou_name,
|
||
status: user.status || 1,
|
||
is_leader: user.is_leader || false
|
||
}));
|
||
|
||
return users;
|
||
} catch (error) {
|
||
console.error('❌ [getRoleUsers] 获取角色用户列表失败:', error);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取所有用户列表
|
||
* @param params 查询参数
|
||
* @deprecated 请使用 getUsersWithRoles 替代
|
||
*/
|
||
export async function getAllUsers(params?: {
|
||
page?: number;
|
||
page_size?: number;
|
||
area?: string;
|
||
username?: string;
|
||
}): Promise<UserInfo[]> {
|
||
try {
|
||
// 导入 axios-client 的 get 函数
|
||
|
||
// 构建查询参数对象
|
||
const queryParams: Record<string, any> = {};
|
||
if (params?.page) queryParams.page = params.page;
|
||
if (params?.page_size) queryParams.page_size = params.page_size;
|
||
if (params?.username) queryParams.search = params.username;
|
||
|
||
// v3.3: 使用标准 RBAC API,后端会自动根据用户角色进行地区过滤
|
||
// 省级管理员: 返回所有地区用户
|
||
// 市级管理员: 只返回同地区用户
|
||
const response = await get<any>('/api/v2/users', queryParams);
|
||
|
||
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('获取的用户列表', users )
|
||
|
||
|
||
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 || '',
|
||
area: user.area || '', // v3.3: 地区字段,用于权限隔离
|
||
ou_name: user.ou_name,
|
||
status: user.status || 1,
|
||
is_leader: user.is_leader || false
|
||
}));
|
||
|
||
return userList;
|
||
} catch (error) {
|
||
console.error('❌ [getAllUsers] 获取用户列表失败:', error);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* v3.4: 获取用户列表(含角色信息)
|
||
* 使用统一的 /api/v3/rbac/users 接口,一次性获取用户和角色信息
|
||
* @param params 查询参数
|
||
*/
|
||
export async function getUsersWithRoles(params?: {
|
||
page?: number;
|
||
page_size?: number;
|
||
area?: string;
|
||
nick_name?: string;
|
||
}): Promise<{
|
||
total: number;
|
||
page: number;
|
||
page_size: number;
|
||
items: UserInfo[];
|
||
}> {
|
||
try {
|
||
const queryParams: Record<string, any> = {};
|
||
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?.nick_name) queryParams.nick_name = params.nick_name;
|
||
|
||
const response = await get<any>('/api/v3/rbac/users', queryParams);
|
||
|
||
if (response.error) {
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
// 后端响应格式: { code: 200, message: "success", data: { total, page, page_size, items: [...] } }
|
||
let data: any;
|
||
if (response.data?.data) {
|
||
data = response.data.data;
|
||
} else if (response.data?.code === 200 && response.data) {
|
||
data = response.data;
|
||
} else {
|
||
data = response.data;
|
||
}
|
||
|
||
// console.log('获取的用户列表', data )
|
||
|
||
const items: UserInfo[] = (data.items || []).map((user: any) => ({
|
||
id: user.id,
|
||
username: user.username,
|
||
nick_name: user.nick_name,
|
||
phone_number: user.phone_number || '',
|
||
email: user.email || '',
|
||
area: user.area || '',
|
||
ou_name: user.ou_name,
|
||
ou_id: user.ou_id,
|
||
status: user.status || 0,
|
||
is_leader: user.is_leader || false,
|
||
roles: user.roles || [],
|
||
dep_name: user.dep_name,
|
||
tenant_name: user.tenant_name
|
||
}));
|
||
|
||
return {
|
||
total: data.total || 0,
|
||
page: data.page || 1,
|
||
page_size: data.page_size || 50,
|
||
items
|
||
};
|
||
} catch (error) {
|
||
console.error('❌ [getUsersWithRoles] 获取用户列表失败:', error);
|
||
return {
|
||
total: 0,
|
||
page: 1,
|
||
page_size: 50,
|
||
items: []
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 为用户分配角色
|
||
* @param userId 用户ID
|
||
* @param roleIds 角色ID数组
|
||
*/
|
||
export async function assignUserRoles(
|
||
userId: number,
|
||
roleIds: number[]
|
||
): Promise<{ success: boolean; message: string }> {
|
||
try {
|
||
// 导入 axios-client 的 post 函数
|
||
|
||
// 使用 axios-client 的 post 函数调用真实后端API
|
||
const response = await post<any>(`/api/v3/rbac/users/${userId}/roles`, {
|
||
role_ids: roleIds
|
||
});
|
||
|
||
if (response.error) {
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
// v3.4: 检查后端返回的code(200表示成功)
|
||
if (response.data && response.data.code && response.data.code !== 200) {
|
||
// 后端返回错误,如权限不足(403)等
|
||
return {
|
||
success: false,
|
||
message: response.data.message || '分配失败'
|
||
};
|
||
}
|
||
|
||
// 后端响应格式: { code: 200, message: "角色分配成功", data: { user_id, roles: [...] } }
|
||
let message = '用户角色分配成功';
|
||
if (response.data && response.data.message) {
|
||
message = response.data.message;
|
||
}
|
||
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 函数
|
||
|
||
// 使用 axios-client 的 del 函数调用真实后端API
|
||
const response = await del<any>(`/api/v3/rbac/users/${userId}/roles/${roleId}`);
|
||
|
||
if (response.error) {
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
// 后端响应格式: { code: 200, message: "角色移除成功" }
|
||
let message = '用户角色移除成功';
|
||
if (response.data && response.data.message) {
|
||
message = response.data.message;
|
||
}
|
||
|
||
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<RoleInfo, 'id' | 'created_at' | 'updated_at'>
|
||
): Promise<{ success: boolean; message: string; data?: RoleInfo }> {
|
||
try {
|
||
// 导入 axios-client 的 post 函数
|
||
|
||
// 使用 axios-client 的 post 函数调用真实后端API
|
||
const response = await post<any>(`/api/v3/rbac/roles`, {
|
||
role_key: roleData.role_key,
|
||
role_name: roleData.role_name,
|
||
description: roleData.description || '',
|
||
data_scope: roleData.data_scope || 'SELF',
|
||
metadata: {}
|
||
});
|
||
|
||
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<Omit<RoleInfo, 'id' | 'created_at' | 'updated_at'>>
|
||
): Promise<{ success: boolean; message: string }> {
|
||
try {
|
||
// 导入 axios-client 的 put 函数
|
||
|
||
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;
|
||
|
||
const response = await put<any>(`/api/v3/rbac/roles/${roleId}`, updatePayload);
|
||
|
||
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 url = `/api/v3/rbac/roles/${roleId}${force ? '?force=true' : ''}`;
|
||
|
||
const response = await del<any>(url);
|
||
|
||
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<Permission[]> {
|
||
try {
|
||
const response = await get<any>(`${RBAC_API_BASE}/permissions`, {
|
||
format,
|
||
...params
|
||
});
|
||
const data = handleApiResponse<Permission[]>(response);
|
||
|
||
return data;
|
||
} catch (error) {
|
||
console.error('获取权限列表失败:', error);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取权限详情
|
||
* @param permissionId 权限ID
|
||
*/
|
||
export async function getPermissionDetail(permissionId: number): Promise<Permission | null> {
|
||
try {
|
||
const response = await get<any>(`${RBAC_API_BASE}/permissions/${permissionId}`);
|
||
const data = handleApiResponse<Permission>(response);
|
||
|
||
return data;
|
||
} catch (error) {
|
||
console.error('获取权限详情失败:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建权限
|
||
* @param permissionData 权限数据
|
||
*/
|
||
export async function createPermission(
|
||
permissionData: Omit<Permission, 'id' | 'children'>
|
||
): 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<any>(`${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<Permission>(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<Omit<Permission, 'id' | 'children'>>
|
||
): Promise<{ success: boolean; message: string }> {
|
||
try {
|
||
const response = await put<any>(`${RBAC_API_BASE}/permissions/${permissionId}`, permissionData);
|
||
handleApiResponse<any>(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<any>(`${RBAC_API_BASE}/permissions/${permissionId}`);
|
||
handleApiResponse<any>(response);
|
||
|
||
return { success: true, message: '权限删除成功' };
|
||
} catch (error) {
|
||
console.error('删除权限失败:', error);
|
||
return {
|
||
success: false,
|
||
message: error instanceof Error ? error.message : '删除权限失败'
|
||
};
|
||
}
|
||
}
|
||
|
||
// ==================== 角色权限关联 API ====================
|
||
|
||
/**
|
||
* 获取角色的所有权限(已分配的API权限)
|
||
* @param roleId 角色ID
|
||
*/
|
||
export async function getRolePermissions(roleId: number): Promise<RolePermissionDetail[]> {
|
||
try {
|
||
|
||
// v3.4: 使用文档规范的API路径(查询参数方式)
|
||
const response = await get<any>('/api/v3/rbac/role-permissions', {
|
||
role_id: roleId
|
||
});
|
||
|
||
if (response.error) {
|
||
throw new Error(response.error);
|
||
}
|
||
|
||
// 解析响应数据
|
||
let permissions: any[] = [];
|
||
if (response.data?.data?.permissions) {
|
||
permissions = response.data.data.permissions;
|
||
} else if (response.data?.permissions) {
|
||
permissions = response.data.permissions;
|
||
} else if (Array.isArray(response.data?.data)) {
|
||
permissions = response.data.data;
|
||
} else if (Array.isArray(response.data)) {
|
||
permissions = response.data;
|
||
}
|
||
|
||
return permissions.map(perm => ({
|
||
id: perm.id,
|
||
permission_id: perm.permission_id || perm.id, // 兼容:如果没有 permission_id,使用 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('❌ [getRolePermissions] 获取角色权限失败:', 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 {
|
||
// v3.4: 使用文档规范的API路径(查询参数方式)
|
||
const response = await post<any>(`${RBAC_API_BASE}/role-permissions`, {
|
||
role_id: roleId,
|
||
permissions: permissions.map(p => ({
|
||
permission_id: p.permission_id,
|
||
grant_type: p.grant_type || 'GRANT',
|
||
data_scope: p.data_scope || 'ALL'
|
||
})),
|
||
replace
|
||
});
|
||
|
||
handleApiResponse<any>(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<RolePermissionConfig>
|
||
): Promise<{ success: boolean; message: string }> {
|
||
try {
|
||
// v3.4: 使用文档规范的API路径(查询参数方式)
|
||
const response = await put<any>(
|
||
`${RBAC_API_BASE}/role-permissions?role_id=${roleId}&permission_id=${permissionId}`,
|
||
config
|
||
);
|
||
handleApiResponse<any>(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 {
|
||
// v3.4: 使用文档规范的API路径(查询参数方式)
|
||
const response = await del<any>(`${RBAC_API_BASE}/role-permissions?role_id=${roleId}&permission_id=${permissionId}`);
|
||
handleApiResponse<any>(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<RoleInfo[]> {
|
||
try {
|
||
|
||
const response = await get<any>(`/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;
|
||
}
|
||
|
||
// 将后端数据转换为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 [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* v3.7: 获取指定路由的所有权限(包含通用权限)
|
||
* 使用专用 API 接口 /api/v3/routes/{route_id}/permissions
|
||
* @param routeId 路由ID
|
||
* @returns 权限列表(包含独立权限和通用权限,带 is_shared 标识)
|
||
*/
|
||
export async function getRoutePermissions(routeId: number): Promise<ApiPermission[]> {
|
||
try {
|
||
|
||
// v3.7: 使用专用 API 接口获取路由权限(包含通用权限)
|
||
const response = await get<any>(`/api/v3/routes/${routeId}/permissions`);
|
||
|
||
if (response.error) {
|
||
console.error('❌ [getRoutePermissions] API调用失败:', response.error);
|
||
return [];
|
||
}
|
||
|
||
// 处理响应数据
|
||
// 后端响应格式: { route_id, route_path, route_title, permissions: [...] }
|
||
let permissions: any[] = [];
|
||
if (response.data) {
|
||
// 如果是包装格式 { code, message, data: { permissions: [...] } }
|
||
if (response.data.code === 200 && response.data.data?.permissions) {
|
||
permissions = response.data.data.permissions;
|
||
}
|
||
// 如果直接返回 { route_id, permissions: [...] }
|
||
else if (response.data.permissions) {
|
||
permissions = response.data.permissions;
|
||
}
|
||
// 如果直接是数组
|
||
else if (Array.isArray(response.data)) {
|
||
permissions = response.data;
|
||
}
|
||
}
|
||
|
||
// 转换为 ApiPermission 格式,保留 is_shared 字段
|
||
return permissions.map(p => ({
|
||
id: p.id,
|
||
permission_key: p.permission_key,
|
||
display_name: p.display_name,
|
||
api_method: p.api_method || '',
|
||
api_path: p.api_path || '',
|
||
route_id: p.route_id,
|
||
related_routes: p.related_routes,
|
||
is_shared: p.is_shared || false // v3.7: 使用后端返回的 is_shared 字段
|
||
}));
|
||
} catch (error) {
|
||
console.error('❌ [getRoutePermissions] 获取路由权限失败:', error);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* v3.7: 判断权限是否为通用权限
|
||
* 优先使用后端返回的 is_shared 字段,降级时使用 related_routes 判断
|
||
* @param permission 权限对象
|
||
* @returns 是否为通用权限
|
||
*/
|
||
export function isSharedPermission(permission: ApiPermission): boolean {
|
||
// v3.7: 优先使用后端返回的 is_shared 字段
|
||
if (permission.is_shared !== undefined) {
|
||
return permission.is_shared === true;
|
||
}
|
||
// 降级:通过 related_routes 字段判断
|
||
return permission.related_routes !== null &&
|
||
permission.related_routes !== undefined &&
|
||
Array.isArray(permission.related_routes) &&
|
||
permission.related_routes.length > 1;
|
||
}
|
||
|
||
/**
|
||
* v3.6: 获取通用权限关联的所有路由ID
|
||
* @param permission 权限对象
|
||
* @returns 路由ID数组
|
||
*/
|
||
export function getRelatedRouteIds(permission: ApiPermission): number[] {
|
||
if (isSharedPermission(permission)) {
|
||
return permission.related_routes || [];
|
||
}
|
||
return permission.route_id ? [permission.route_id] : [];
|
||
}
|