fix: 1. 继续对齐交叉评查的接口,完善创建交叉评查的逻辑 和 相关组件的渲染布局。
2. 文档的基本信息修改改用接口。 3. 重新完善角色权限管理的页面逻辑。 4.将评查点列表中的返回逻辑改用浏览器的记忆返回。
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { postgrestGet, postgrestPut } from "../postgrest-client";
|
||||
import axios from 'axios';
|
||||
import { API_BASE_URL } from '../../config/api-config';
|
||||
|
||||
/**
|
||||
* 从不同格式的 API 响应中提取数据
|
||||
@@ -83,32 +84,50 @@ async function safeGetJWT(jwtToken?: string): Promise<string> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户是否是发起人
|
||||
* 检查用户是否有权确认完成文档评查
|
||||
*
|
||||
* 🔥 接口文档: auth_doc/交叉评查接口文档.md 接口11
|
||||
* 📍 API地址: GET /api/v2/cross_review/tasks/{task_id}/can-confirm
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
* @param userId 用户ID
|
||||
* @returns 是否是发起人
|
||||
* @param frontendJWT JWT token
|
||||
* @returns 是否有权确认完成
|
||||
*/
|
||||
export async function findIsProposer(taskId: string | number, userId: number | undefined, frontendJWT?: string): Promise<boolean> {
|
||||
// 通过postgrest的get请求去cross_examination_tasks表中进行查找assignee_id是否等于userId
|
||||
const response = await postgrestGet(`/api/postgrest/proxy/cross_examination_tasks`, {
|
||||
select: 'assigner_id',
|
||||
filter: {
|
||||
id: `eq.${taskId}`
|
||||
},
|
||||
token: frontendJWT
|
||||
});
|
||||
if (response.error) {
|
||||
console.error('获取任务数据失败:', response.error);
|
||||
try {
|
||||
if (!taskId) {
|
||||
console.error('任务ID不能为空');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 调用新的接口检查用户是否有权确认完成
|
||||
// GET /api/v2/cross_review/tasks/{task_id}/can-confirm
|
||||
const response = await axios.get(
|
||||
`${API_BASE_URL}/api/v2/cross_review/tasks/${taskId}/can-confirm`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${frontendJWT}`
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const data = response.data;
|
||||
console.log('[findIsProposer] 检查权限响应:', data);
|
||||
|
||||
// 返回 can_confirm 字段,表示是否有权确认完成
|
||||
// 有权限的用户:任务创建者(assigner_id) 或 主要负责人(principal_user_ids)
|
||||
return data?.can_confirm === true;
|
||||
} catch (error) {
|
||||
console.error('[findIsProposer] 检查权限失败:', error);
|
||||
|
||||
// 正确处理 axios 错误响应
|
||||
if (axios.isAxiosError(error) && error.response?.data) {
|
||||
console.error('[findIsProposer] 错误详情:', error.response.data);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
const data = extractApiData<{assigner_id: number}[]>(response.data);
|
||||
// console.log('data', data, userId);
|
||||
|
||||
if (data && data.length > 0) {
|
||||
return data[0].assigner_id.toString() === userId?.toString();
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,8 +199,6 @@ export async function submitCrossCheckingOpinion(
|
||||
* @param jwtToken JWT token
|
||||
* @returns 意见列表和总数
|
||||
*/
|
||||
import { API_BASE_URL } from '../../config/api-config';
|
||||
|
||||
export async function getCrossCheckingOpinions(
|
||||
documentId: string | number,
|
||||
page: number = 1,
|
||||
|
||||
@@ -210,6 +210,7 @@ export async function uploadCrossCheckingDocument(
|
||||
* @param docType 文档类型(如 XZCF、XZXK)
|
||||
* @param taskType 任务类型(如 市局间交叉评查、区局间交叉评查)
|
||||
* @param token JWT Token
|
||||
* @param principalUserIds 负责人ID数组(包含主要负责人和额外负责人)
|
||||
*/
|
||||
export async function batchUploadAndAssignCrossCheckingFiles(
|
||||
files: CrossCheckingUploadedFile[],
|
||||
@@ -222,17 +223,18 @@ export async function batchUploadAndAssignCrossCheckingFiles(
|
||||
taskName: string,
|
||||
docType: string,
|
||||
taskType: string = '市局间交叉评查',
|
||||
token: string | null = null
|
||||
token: string | null = null,
|
||||
principalUserIds: number[] = []
|
||||
): Promise<{
|
||||
successes: Array<{file: CrossCheckingUploadedFile; result: Record<string, unknown>}>;
|
||||
failures: Array<{file: CrossCheckingUploadedFile; error: string}>;
|
||||
}> {
|
||||
const successes: Array<{file: CrossCheckingUploadedFile; result: Record<string, unknown>}> = [];
|
||||
const failures: Array<{file: CrossCheckingUploadedFile; error: string}> = [];
|
||||
const uploadEndpoint = '/cross_review/documents/upload_and_assign';
|
||||
const uploadUrl = UPLOAD_URL + uploadEndpoint;
|
||||
const uploadEndpoint = '/admin/v2/documents/cross_review/documents/upload_and_assign';
|
||||
const uploadUrl = API_BASE_URL + uploadEndpoint;
|
||||
|
||||
// console.log('[批量上传] 任务类型:', taskType, '文档类型:', docType);
|
||||
// console.log('[批量上传] 任务类型:', taskType, '文档类型:', docType, '负责人ID:', leaderId);
|
||||
|
||||
|
||||
for (const fileInfo of files) {
|
||||
@@ -254,6 +256,11 @@ export async function batchUploadAndAssignCrossCheckingFiles(
|
||||
formData.append('upload_info', JSON.stringify(uploadInfo));
|
||||
formData.append('assign_user_ids', JSON.stringify(assignUserIds));
|
||||
|
||||
// 添加负责人ID数组(包含主要负责人和额外负责人)
|
||||
if (principalUserIds.length > 0) {
|
||||
formData.append('principal_user_ids', JSON.stringify(principalUserIds));
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {};
|
||||
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`;
|
||||
|
||||
@@ -107,9 +107,9 @@ export function mapUIToReviewStatus(status: string): number {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: 是否需要出一个公共的接口,文件上传/文档列表 都需要用到:点击查看/开始审核 更新这个文件的审核状态(只有待审核的状态才会进行更新调用)
|
||||
/**
|
||||
* 更新文件的审核状态
|
||||
* 更新文件的审核状态
|
||||
* @param id 文件ID
|
||||
* @param auditStatus 审核状态
|
||||
* @param userId 用户ID
|
||||
@@ -144,7 +144,7 @@ export async function updateDocumentAuditStatus(id: string, auditStatus: number,
|
||||
}
|
||||
);
|
||||
|
||||
console.log('📝 [updateDocumentAuditStatus] postgrestPut响应:', response);
|
||||
// console.log('📝 [updateDocumentAuditStatus] postgrestPut响应:', response);
|
||||
|
||||
if (response.error) {
|
||||
console.warn('⚠️ [updateDocumentAuditStatus] postgrestPut返回错误,但操作可能已成功:', response.error);
|
||||
|
||||
@@ -239,11 +239,11 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
|
||||
}
|
||||
|
||||
// 🔑 添加地区过滤
|
||||
if (user_role === 'provincial_admin') {
|
||||
queryParams.append('area', '省级');
|
||||
} else if (area) {
|
||||
queryParams.append('area', area);
|
||||
}
|
||||
// if (user_role === 'provincial_admin') {
|
||||
// queryParams.append('area', '省级');
|
||||
// } else if (area) {
|
||||
// queryParams.append('area', area);
|
||||
// }
|
||||
|
||||
// 添加关键词搜索(后端会同时搜索 name 和 code)
|
||||
if (keyword) {
|
||||
@@ -251,6 +251,8 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
|
||||
queryParams.append('code', keyword);
|
||||
}
|
||||
|
||||
// console.log('🔍 [getRulesList] 查询参数:', queryParams.toString());
|
||||
|
||||
// 调用 FastAPI 接口
|
||||
const response = await apiRequest<{
|
||||
data: EvaluationPointData[];
|
||||
@@ -275,7 +277,7 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
|
||||
return { error: '接口返回数据格式不正确', status: 500 };
|
||||
}
|
||||
|
||||
console.log('✅ [getRulesList] 成功获取评查点列表,共', response.data.total, '条');
|
||||
// console.log('✅ [getRulesList] 成功获取评查点列表,共', response.data.total, '条');
|
||||
|
||||
// 🆕 直接映射后端返回的数据到前端 Rule 模型
|
||||
// 后端已包含 ruleType、groupName、groupId 字段,无需额外处理
|
||||
@@ -308,9 +310,11 @@ export async function getRulesList(params: RulesQueryParams): Promise<{data: Rul
|
||||
description: point.description || '',
|
||||
isActive: point.is_enabled,
|
||||
createdAt: formatDate(point.created_at || ''),
|
||||
updatedAt: formatDate(point.updated_at || '')
|
||||
updatedAt: formatDate(point.updated_at || ''),
|
||||
area: point.area || ''
|
||||
};
|
||||
});
|
||||
console.log('✅ [getRulesList] 成功映射评查点列表数据', response.data.data[0]);
|
||||
|
||||
return {
|
||||
data: {
|
||||
@@ -950,9 +954,8 @@ export async function batchUpdateRuleStatus(
|
||||
// 逐个验证并更新
|
||||
for (const id of ids) {
|
||||
try {
|
||||
|
||||
// 执行更新
|
||||
const updateResult = await updateRule(id, { isActive: is_enabled }, token);
|
||||
// 执行更新 - 使用 updateEvaluationPoint,只传入 is_enabled 字段
|
||||
const updateResult = await updateEvaluationPoint(id, { is_enabled }, token);
|
||||
if (updateResult.error) {
|
||||
failedIds.push(id);
|
||||
errors.push({ id, error: updateResult.error });
|
||||
|
||||
+46
-28
@@ -431,9 +431,17 @@ export async function getDocumentTypesByIds(ids: number[], frontendJWT?: string)
|
||||
|
||||
/**
|
||||
* 更新文档信息
|
||||
*
|
||||
* 使用 PATCH 方法调用 /api/postgrest/proxy/documents 接口
|
||||
* 后端会自动注入 user_id 过滤条件,确保用户只能更新自己的文档
|
||||
*
|
||||
* @param id 文档ID
|
||||
* @param document 部分文档数据
|
||||
* @param document 部分文档数据(可更新字段:document_number, audit_status, is_test_document, remark)
|
||||
* @param userId 用户ID(用于权限验证)
|
||||
* @param frontendJWT JWT Token(可选,如不传则使用 localStorage 中的 access_token)
|
||||
* @returns 更新结果
|
||||
*
|
||||
* @see auth_doc/document_update_api.md 接口文档
|
||||
*/
|
||||
export async function updateDocument(id: string, document: Partial<DocumentUI> & { remark?: string }, userId: string, frontendJWT?: string): Promise<{
|
||||
data?: DocumentUI;
|
||||
@@ -444,57 +452,67 @@ export async function updateDocument(id: string, document: Partial<DocumentUI> &
|
||||
if (!id) {
|
||||
return { error: '文档ID不能为空', status: 400 };
|
||||
}
|
||||
|
||||
|
||||
if (!userId) {
|
||||
return { error: '用户身份验证失败', status: 401 };
|
||||
}
|
||||
|
||||
|
||||
// 准备API数据 - 将UI数据转换为API格式
|
||||
// 根据文档,可更新字段:document_number, audit_status, is_test_document, remark
|
||||
const apiDocument: Partial<Document> = {};
|
||||
|
||||
|
||||
if (document.documentNumber !== undefined) {
|
||||
apiDocument.document_number = document.documentNumber;
|
||||
}
|
||||
|
||||
// if (document.type !== undefined) {
|
||||
// apiDocument.type_id = parseInt(document.type);
|
||||
// }
|
||||
|
||||
|
||||
if (document.auditStatus !== undefined) {
|
||||
apiDocument.audit_status = document.auditStatus;
|
||||
}
|
||||
|
||||
|
||||
if (document.isTest !== undefined) {
|
||||
apiDocument.is_test_document = document.isTest;
|
||||
}
|
||||
|
||||
|
||||
if (document.remark !== undefined) {
|
||||
apiDocument.remark = document.remark;
|
||||
}
|
||||
|
||||
// console.log('更新文档API数据:', apiDocument);
|
||||
|
||||
const response = await postgrestPut<Document, Partial<Document>>(
|
||||
'/api/postgrest/proxy/documents',
|
||||
apiDocument,
|
||||
{
|
||||
id: parseInt(id),
|
||||
user_id: parseInt(userId) // 确保只能更新自己的文档
|
||||
},
|
||||
frontendJWT
|
||||
|
||||
// console.log('📤 [updateDocument] 更新文档API数据:', apiDocument);
|
||||
|
||||
// 使用 axios-client 的 apiRequest 方法(支持自定义 headers)
|
||||
// 接口路径: /api/postgrest/proxy/documents?id=eq.{id}
|
||||
// 后端会自动注入 user_id 过滤条件(根据JWT中的用户信息)
|
||||
const { apiRequest } = await import('../axios-client');
|
||||
const response = await apiRequest<Document[]>(
|
||||
`/api/postgrest/proxy/documents?id=eq.${id}`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
data: apiDocument,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(frontendJWT ? { 'Authorization': `Bearer ${frontendJWT}` } : {})
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
if (response.error) {
|
||||
console.error('更新文档API错误:', response.error);
|
||||
console.error('❌ [updateDocument] 更新文档API错误:', response.error);
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
// 获取更新后的完整文档数据
|
||||
|
||||
// 检查返回数据
|
||||
// 成功时返回更新后的文档数组,空数组表示文档不存在或无权访问
|
||||
const responseData = response.data;
|
||||
if (!responseData || (Array.isArray(responseData) && responseData.length === 0)) {
|
||||
return { error: '文档不存在或无权访问', status: 404 };
|
||||
}
|
||||
|
||||
// 获取更新后的完整文档数据(包含关联的文档类型信息)
|
||||
const updatedResponse = await getDocument(id, userId, frontendJWT);
|
||||
|
||||
|
||||
return updatedResponse;
|
||||
} catch (error) {
|
||||
console.error('更新文档信息失败:', error);
|
||||
console.error('❌ [updateDocument] 更新文档信息失败:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : '更新文档信息失败',
|
||||
status: 500
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
* 用于角色、路由权限、用户角色的管理
|
||||
*/
|
||||
|
||||
import { get, post, put, del } from '~/api/axios-client';
|
||||
|
||||
// ==================== 类型定义 ====================
|
||||
|
||||
/**
|
||||
* API 响应类型
|
||||
*/
|
||||
interface ApiResponse<T> {
|
||||
data?: T;
|
||||
error?: string;
|
||||
status?: number;
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
// ==================== 常量定义 ====================
|
||||
|
||||
/**
|
||||
@@ -36,6 +50,8 @@ function handleApiResponse<T>(response: ApiResponse<any>): T {
|
||||
/**
|
||||
* API权限信息(关联到路由的权限)
|
||||
* v3.0新增:每个路由可以关联多个API操作权限
|
||||
* v3.6新增:支持通用权限(related_routes 字段)
|
||||
* v3.7新增:is_shared 字段由后端直接返回
|
||||
*/
|
||||
export interface ApiPermission {
|
||||
id: number;
|
||||
@@ -43,6 +59,9 @@ export interface ApiPermission {
|
||||
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: 是否为通用权限(后端返回)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,10 +186,6 @@ export async function getRoles(params?: {
|
||||
include_system?: boolean;
|
||||
}): Promise<RoleInfo[]> {
|
||||
try {
|
||||
// 导入 axios-client 的 get 函数
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
|
||||
// 使用 axios-client 的 get 函数调用真实后端API
|
||||
const response = await get<any>(`/api/v3/rbac/roles`, params || {});
|
||||
|
||||
@@ -242,9 +257,6 @@ export async function getRoleDetail(roleId: number): Promise<RoleInfo | null> {
|
||||
*/
|
||||
export async function getRoutes(): Promise<RouteInfo[]> {
|
||||
try {
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
|
||||
// 调用后端API获取当前用户的路由(provincial_admin应该有所有路由权限)
|
||||
const response = await get<any>('/rbac/user/routes');
|
||||
|
||||
@@ -278,8 +290,6 @@ export async function getRoutes(): Promise<RouteInfo[]> {
|
||||
children: route.children ? route.children.map(mapRouteData) : undefined
|
||||
});
|
||||
|
||||
console.log('获取当前用户的路由', routes.map(mapRouteData) )
|
||||
|
||||
return routes.map(mapRouteData);
|
||||
} catch (error) {
|
||||
console.error('❌ [getRoutes] 获取路由数据失败:', error);
|
||||
@@ -288,15 +298,69 @@ export async function getRoutes(): Promise<RouteInfo[]> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 函数
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
// 使用 axios-client 的 get 函数调用真实后端API
|
||||
const response = await get<any>(`/rbac/roles/${roleId}/routes`);
|
||||
|
||||
@@ -340,8 +404,6 @@ export async function getRoleRoutesWithPermissions(roleId: number): Promise<{
|
||||
selectedPermissionIds: number[];
|
||||
}> {
|
||||
try {
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
const response = await get<any>(`/rbac/roles/${roleId}/routes`);
|
||||
|
||||
if (response.error) {
|
||||
@@ -444,8 +506,6 @@ export async function saveRoleApiPermissions(
|
||||
permissionIds: number[]
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
const { post } = await import('~/api/axios-client');
|
||||
|
||||
// 构建权限配置
|
||||
const permissions = permissionIds.map(id => ({
|
||||
permission_id: id,
|
||||
@@ -492,10 +552,6 @@ export async function updateRoleRoutePermissions(
|
||||
routeIds: number[]
|
||||
): Promise<{ success: boolean; message: string; code?: number }> {
|
||||
try {
|
||||
// 导入 axios-client 的 put 函数
|
||||
const { put } = await import('~/api/axios-client');
|
||||
|
||||
|
||||
// 使用 axios-client 的 put 函数调用真实后端API
|
||||
const response = await put<any>(`/rbac/roles/${roleId}/routes`, {
|
||||
route_ids: routeIds,
|
||||
@@ -563,7 +619,6 @@ export async function getRoleUsers(
|
||||
): Promise<UserInfo[]> {
|
||||
try {
|
||||
// 导入 axios-client 的 get 函数
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
// 构建查询参数对象
|
||||
const queryParams: Record<string, any> = {};
|
||||
@@ -618,7 +673,6 @@ export async function getAllUsers(params?: {
|
||||
}): Promise<UserInfo[]> {
|
||||
try {
|
||||
// 导入 axios-client 的 get 函数
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
// 构建查询参数对象
|
||||
const queryParams: Record<string, any> = {};
|
||||
@@ -683,7 +737,6 @@ export async function assignUserRoles(
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
// 导入 axios-client 的 post 函数
|
||||
const { post } = await import('~/api/axios-client');
|
||||
|
||||
// 使用 axios-client 的 post 函数调用真实后端API
|
||||
const response = await post<any>(`/api/v3/rbac/users/${userId}/roles`, {
|
||||
@@ -729,7 +782,6 @@ export async function revokeUserRole(
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
// 导入 axios-client 的 del 函数
|
||||
const { del } = await import('~/api/axios-client');
|
||||
|
||||
// 使用 axios-client 的 del 函数调用真实后端API
|
||||
const response = await del<any>(`/api/v3/rbac/users/${userId}/roles/${roleId}`);
|
||||
@@ -763,7 +815,6 @@ export async function createRole(
|
||||
): Promise<{ success: boolean; message: string; data?: RoleInfo }> {
|
||||
try {
|
||||
// 导入 axios-client 的 post 函数
|
||||
const { post } = await import('~/api/axios-client');
|
||||
|
||||
// 使用 axios-client 的 post 函数调用真实后端API
|
||||
const response = await post<any>(`/api/v3/rbac/roles`, {
|
||||
@@ -817,7 +868,6 @@ export async function updateRole(
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
// 导入 axios-client 的 put 函数
|
||||
const { put } = await import('~/api/axios-client');
|
||||
|
||||
const updatePayload: any = {};
|
||||
|
||||
@@ -854,7 +904,6 @@ export async function deleteRole(
|
||||
): 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' : ''}`;
|
||||
|
||||
@@ -1011,7 +1060,6 @@ export async function deletePermission(
|
||||
*/
|
||||
export async function getRolePermissions(roleId: number): Promise<RolePermissionDetail[]> {
|
||||
try {
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
// v3.4: 使用文档规范的API路径(查询参数方式)
|
||||
const response = await get<any>('/api/v3/rbac/role-permissions', {
|
||||
@@ -1143,7 +1191,6 @@ export async function revokeRolePermission(
|
||||
*/
|
||||
export async function getUserRoles(userId: number): Promise<RoleInfo[]> {
|
||||
try {
|
||||
const { get } = await import('~/api/axios-client');
|
||||
|
||||
const response = await get<any>(`/api/v3/rbac/users/${userId}/roles`);
|
||||
|
||||
@@ -1179,3 +1226,85 @@ export async function getUserRoles(userId: number): Promise<RoleInfo[]> {
|
||||
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] : [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user