3850d05bdd
2. 给文档类型添加入口模块和相关数据的渲染。并且给文档类型进行功能上的角色权限区分 3. 新增角色权限管理页面
507 lines
15 KiB
TypeScript
507 lines
15 KiB
TypeScript
import { API_BASE_URL } from '../../config/api-config';
|
|
import { postgrestPut } from '../postgrest-client';
|
|
import axios from 'axios';
|
|
|
|
// 交叉评查任务状态枚举
|
|
export enum CrossCheckingTaskStatus {
|
|
PENDING = 'pending',
|
|
IN_PROGRESS = 'in_progress',
|
|
COMPLETED = 'completed'
|
|
}
|
|
|
|
// 交叉评查任务类型枚举
|
|
export enum CrossCheckingTaskType {
|
|
CITY = 'city',
|
|
COUNTY = 'county'
|
|
}
|
|
|
|
// 案卷类型枚举
|
|
export enum CrossCheckingDocType {
|
|
PENALTY = 'penalty', // 行政处罚
|
|
PERMIT = 'permit' // 行政许可
|
|
}
|
|
|
|
// 交叉评查任务接口
|
|
export interface CrossCheckingTask {
|
|
id: number;
|
|
sequence: number;
|
|
taskName: string;
|
|
startDate: string;
|
|
taskType: CrossCheckingTaskType;
|
|
docType: string; // 改为直接使用返回的 doc_type 字符串
|
|
evaluationRegion: string;
|
|
progress: number;
|
|
status: string; // 改为直接使用返回的 task_status 字符串
|
|
score: number;
|
|
operation: string;
|
|
documents: UserTaskDocument[]; // 改为 documents 数组,包含完整的文档信息
|
|
totalDocuments?: number; // 新增:任务包含的文档总数
|
|
}
|
|
|
|
// 用户任务文档接口类型定义
|
|
export interface UserTaskDocument {
|
|
document_id: number;
|
|
document_name: string;
|
|
document_type_id: number;
|
|
document_type_name: string;
|
|
}
|
|
|
|
// 新的用户任务信息接口(根据新的API格式)
|
|
export interface UserTaskInfo {
|
|
task_id: number;
|
|
task_name?: string;
|
|
task_status: string;
|
|
doc_type?: string;
|
|
task_created_at?: string;
|
|
progress?: number;
|
|
total_documents?: number; // 新增:任务包含的文档总数
|
|
}
|
|
|
|
// 用户任务API响应格式(新格式)
|
|
export interface UserTaskApiResponse {
|
|
total: number;
|
|
page: number;
|
|
page_size: number;
|
|
items: UserTaskInfo[];
|
|
}
|
|
|
|
// 任务文档接口类型定义(新增)
|
|
export interface TaskDocument {
|
|
document_id: number;
|
|
file_name: string;
|
|
status: string;
|
|
path: string;
|
|
file_code: string;
|
|
file_type_name: string;
|
|
file_type_id: number;
|
|
file_size: number;
|
|
upload_time: string;
|
|
created_at: string;
|
|
evaluations_status: number;
|
|
audit_status: number;
|
|
created_by_user_id: number;
|
|
issues: Array<{
|
|
severity: string;
|
|
message: string;
|
|
}>;
|
|
final_score: number;
|
|
score_summary: string ;
|
|
score_percent?: number | null;
|
|
pass_count: number;
|
|
warning_count: number;
|
|
fail_count: number;
|
|
manual_count: number;
|
|
}
|
|
|
|
// 任务文档API响应格式(新增)
|
|
export interface TaskDocumentApiResponse {
|
|
total: number;
|
|
page: number;
|
|
page_size: number;
|
|
items: TaskDocument[];
|
|
}
|
|
|
|
// API响应格式
|
|
export interface ApiResponse<T> {
|
|
success: boolean;
|
|
data?: T;
|
|
error?: string;
|
|
message?: string;
|
|
status?: number;
|
|
}
|
|
|
|
// 任务列表查询参数
|
|
export interface TaskListParams {
|
|
page?: number;
|
|
pageSize?: number;
|
|
taskType?: string;
|
|
docType?: string;
|
|
status?: string;
|
|
keyword?: string;
|
|
dateFrom?: string;
|
|
dateTo?: string;
|
|
}
|
|
|
|
// 任务列表响应数据
|
|
export interface TaskListResponse {
|
|
tasks: CrossCheckingTask[];
|
|
totalCount: number;
|
|
currentPage: number;
|
|
pageSize: number;
|
|
totalPages: number;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 获取交叉评查任务列表
|
|
* @param params 查询参数
|
|
* @param userInfo 用户信息
|
|
* @param jwtToken JWT token
|
|
* @returns 任务列表响应
|
|
*/
|
|
export async function getCrossCheckingTasks(params: TaskListParams = {}, userInfo?: { user_id?: number; [key: string]: unknown }, jwtToken?: string): Promise<ApiResponse<TaskListResponse>> {
|
|
try {
|
|
console.log('开始调用getCrossCheckingTasks,参数:', params);
|
|
|
|
// 调用用户任务API,获取当前用户参与的任务
|
|
const userTasksResponse = await getUserTaskDocuments(params.page || 1, params.pageSize || 10, jwtToken);
|
|
|
|
// console.log('getUserTaskDocuments响应:', JSON.stringify(userTasksResponse,null,2));
|
|
|
|
if (!userTasksResponse.success || !userTasksResponse.data) {
|
|
console.error('获取用户任务失败:', userTasksResponse.error);
|
|
return {
|
|
success: false,
|
|
error: userTasksResponse.error || '获取用户任务失败'
|
|
};
|
|
}
|
|
|
|
// 将用户任务数据转换为CrossCheckingTask格式
|
|
const userTasks = userTasksResponse.data.items;
|
|
const convertedTasks: CrossCheckingTask[] = userTasks.map((userTask: UserTaskInfo, index: number) => {
|
|
// 从用户任务中提取任务信息,使用API返回的实际数据
|
|
const task: CrossCheckingTask = {
|
|
id: userTask.task_id,
|
|
sequence: index + 1,
|
|
taskName: userTask.task_name || `任务 ${userTask.task_id}`, // 使用API返回的任务名称
|
|
startDate: userTask.task_created_at ? new Date(userTask.task_created_at).toISOString().split('T')[0] : new Date().toISOString().split('T')[0],
|
|
taskType: CrossCheckingTaskType.CITY, // 保持默认任务类型
|
|
docType: userTask.doc_type || '未知类型', // 使用API返回的文档类型
|
|
evaluationRegion: '待定', // 保持默认评查地区
|
|
progress: userTask.progress || 0, // 使用API返回的进度
|
|
status: userTask.task_status || 'pending', // 使用API返回的任务状态
|
|
score: userTask.task_status === 'completed' ? 85 : 0, // 默认分数
|
|
operation: userTask.task_status === 'completed' ? '查看结果' :
|
|
userTask.task_status === 'in_progress' ? '进行中' : '去评查',
|
|
documents: [], // 暂时为空数组,因为新API格式中任务列表不包含具体文档信息
|
|
totalDocuments: userTask.total_documents || 0 // 使用API返回的文档总数
|
|
};
|
|
return task;
|
|
});
|
|
|
|
const {
|
|
taskType,
|
|
docType,
|
|
status,
|
|
keyword,
|
|
dateFrom,
|
|
dateTo
|
|
} = params;
|
|
|
|
// 筛选数据
|
|
let filteredTasks = [...convertedTasks];
|
|
|
|
// 按任务类型筛选
|
|
if (taskType && taskType !== 'all') {
|
|
filteredTasks = filteredTasks.filter(task => task.taskType === taskType);
|
|
}
|
|
|
|
// 按案卷类型筛选
|
|
if (docType && docType !== 'all') {
|
|
filteredTasks = filteredTasks.filter(task => task.docType === docType);
|
|
}
|
|
|
|
// 按状态筛选
|
|
if (status && status !== 'all') {
|
|
filteredTasks = filteredTasks.filter(task => task.status === status);
|
|
}
|
|
|
|
// 按关键词搜索
|
|
if (keyword) {
|
|
const lowerKeyword = keyword.toLowerCase();
|
|
filteredTasks = filteredTasks.filter(task =>
|
|
task.taskName.toLowerCase().includes(lowerKeyword) ||
|
|
task.evaluationRegion.toLowerCase().includes(lowerKeyword)
|
|
);
|
|
}
|
|
|
|
// 按日期范围筛选
|
|
if (dateFrom || dateTo) {
|
|
filteredTasks = filteredTasks.filter(task => {
|
|
const taskDate = new Date(task.startDate);
|
|
if (dateFrom && new Date(dateFrom) > taskDate) return false;
|
|
if (dateTo && new Date(dateTo) < taskDate) return false;
|
|
return true;
|
|
});
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
tasks: filteredTasks,
|
|
totalCount: userTasksResponse.data.total,
|
|
currentPage: userTasksResponse.data.page,
|
|
pageSize: userTasksResponse.data.page_size,
|
|
totalPages: Math.ceil(userTasksResponse.data.total / userTasksResponse.data.page_size)
|
|
}
|
|
};
|
|
} catch (error) {
|
|
console.error('获取交叉评查任务列表失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '获取任务列表失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 删除交叉评查任务
|
|
* @param taskId 任务ID
|
|
* @returns 删除结果
|
|
*/
|
|
export async function deleteCrossCheckingTask(taskId: number): Promise<ApiResponse<boolean>> {
|
|
try {
|
|
// 模拟API延迟
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
// 这里应该调用实际的API来删除任务
|
|
// 目前暂时返回成功,因为没有实际的删除API
|
|
console.log(`尝试删除任务ID: ${taskId}`);
|
|
|
|
return {
|
|
success: true,
|
|
data: true,
|
|
message: '删除任务成功'
|
|
};
|
|
} catch (error) {
|
|
console.error('删除交叉评查任务失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '删除任务失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取任务详情及相关文档
|
|
* @param taskId 任务ID
|
|
* @param page 页码,默认为1
|
|
* @param pageSize 每页大小,默认为10
|
|
* @param jwtToken JWT token
|
|
* @returns 任务详情和文档列表
|
|
*/
|
|
export async function getCrossCheckingTaskDetail(
|
|
taskId: number,
|
|
page: number = 1,
|
|
pageSize: number = 10,
|
|
jwtToken?: string
|
|
): Promise<ApiResponse<{
|
|
task: CrossCheckingTask | null;
|
|
files: TaskDocument[];
|
|
total: number;
|
|
currentPage: number;
|
|
pageSize: number;
|
|
}>> {
|
|
try {
|
|
console.log('开始调用getCrossCheckingTaskDetail,参数:', { taskId, page, pageSize });
|
|
|
|
// 获取任务的文档列表
|
|
const taskDocumentsResponse = await getTaskDocuments(taskId, page, pageSize, jwtToken);
|
|
|
|
if (!taskDocumentsResponse.success || !taskDocumentsResponse.data) {
|
|
console.error('获取任务文档失败:', taskDocumentsResponse.error);
|
|
return {
|
|
success: false,
|
|
error: taskDocumentsResponse.error || '获取任务文档失败'
|
|
};
|
|
}
|
|
|
|
const documentsData = taskDocumentsResponse.data;
|
|
|
|
const result = {
|
|
success: true,
|
|
data: {
|
|
task: null, // 暂时不返回任务详情,因为新接口主要关注文档列表
|
|
files: documentsData.items,
|
|
total: documentsData.total,
|
|
currentPage: documentsData.page,
|
|
pageSize: documentsData.page_size
|
|
}
|
|
};
|
|
|
|
return result;
|
|
} catch (error) {
|
|
console.error('获取任务详情失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '获取任务详情失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取统计数据
|
|
* @param userInfo 用户信息
|
|
* @param jwtToken JWT token
|
|
* @returns 统计数据
|
|
*/
|
|
export async function getCrossCheckingStats(userInfo?: { user_id?: number; [key: string]: unknown }, jwtToken?: string): Promise<ApiResponse<{
|
|
totalTasks: number;
|
|
pendingTasks: number;
|
|
inProgressTasks: number;
|
|
completedTasks: number;
|
|
}>> {
|
|
try {
|
|
console.log('开始调用getCrossCheckingStats');
|
|
|
|
// 获取用户任务数据来计算统计(默认获取第一页数据进行统计)
|
|
const userTasksResponse = await getUserTaskDocuments(1, 100, jwtToken); // 获取前100个任务用于统计
|
|
|
|
if (!userTasksResponse.success || !userTasksResponse.data) {
|
|
console.error('获取用户任务失败:', userTasksResponse.error);
|
|
return {
|
|
success: false,
|
|
error: userTasksResponse.error || '获取用户任务失败'
|
|
};
|
|
}
|
|
|
|
const userTasks = userTasksResponse.data.items;
|
|
const totalTasks = userTasksResponse.data.total;
|
|
const pendingTasks = userTasks.filter(t => t.task_status === 'pending').length;
|
|
const inProgressTasks = userTasks.filter(t => t.task_status === 'in_progress').length;
|
|
const completedTasks = userTasks.filter(t => t.task_status === 'completed').length;
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
totalTasks,
|
|
pendingTasks,
|
|
inProgressTasks,
|
|
completedTasks
|
|
}
|
|
};
|
|
} catch (error) {
|
|
console.error('获取统计数据失败:', error);
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '获取统计数据失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
// ==================== 更新:用户任务文档相关接口 ====================
|
|
|
|
/**
|
|
* 获取用户参与的所有任务列表(更新为新的API格式)
|
|
* @param page 页码
|
|
* @param pageSize 每页大小
|
|
* @param jwtToken JWT token
|
|
* @returns 用户任务列表
|
|
*/
|
|
export async function getUserTaskDocuments(page: number = 1, pageSize: number = 10, jwtToken?: string): Promise<ApiResponse<UserTaskApiResponse>> {
|
|
try {
|
|
// 拼接绝对路径,去除多余斜杠
|
|
const base = API_BASE_URL.endsWith('/') ? API_BASE_URL.slice(0, -1) : API_BASE_URL;
|
|
const url = `${base}/admin/cross_review/tasks/user_tasks`;
|
|
|
|
const response = await axios.post(url, {
|
|
page: page,
|
|
page_size: pageSize
|
|
}, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${jwtToken || ''}`
|
|
}
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
data: response.data
|
|
};
|
|
} catch (error) {
|
|
if (axios.isAxiosError(error)) {
|
|
return {
|
|
success: false,
|
|
error: `HTTP ${error.response?.status}: ${error.response?.statusText || error.message}`
|
|
};
|
|
}
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '获取用户任务列表失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取指定任务的文档列表(新增接口)
|
|
* @param taskId 任务ID
|
|
* @param page 页码
|
|
* @param pageSize 每页大小
|
|
* @param jwtToken JWT token
|
|
* @returns 任务文档列表
|
|
*/
|
|
export async function getTaskDocuments(taskId: number, page: number = 1, pageSize: number = 10, jwtToken?: string): Promise<ApiResponse<TaskDocumentApiResponse>> {
|
|
try {
|
|
// 拼接绝对路径,去除多余斜杠
|
|
const base = API_BASE_URL.endsWith('/') ? API_BASE_URL.slice(0, -1) : API_BASE_URL;
|
|
const url = `${base}/admin/cross_review/tasks/${taskId}/documents`;
|
|
// console.log('最终请求URL:', url);
|
|
|
|
const response = await axios.post(url, {
|
|
page: page,
|
|
page_size: pageSize
|
|
}, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${jwtToken || ''}`
|
|
}
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
data: response.data
|
|
};
|
|
} catch (error) {
|
|
if (axios.isAxiosError(error)) {
|
|
return {
|
|
success: false,
|
|
error: `HTTP ${error.response?.status}: ${error.response?.statusText || error.message}`
|
|
};
|
|
}
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : '获取任务文档列表失败'
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 更新文件的审核状态
|
|
* @param id 文件ID
|
|
* @param auditStatus 审核状态
|
|
* @returns 更新结果
|
|
*/
|
|
export async function updateDocumentAuditStatus(id: string, auditStatus: number, frontendJWT?: string): Promise<{
|
|
success?: boolean;
|
|
error?: string;
|
|
status?: number;
|
|
}> {
|
|
try {
|
|
if (!id) {
|
|
return { error: '文件ID不能为空', status: 400 };
|
|
}
|
|
|
|
const response = await postgrestPut<TaskDocument, Partial<TaskDocument>>(
|
|
'documents',
|
|
{ audit_status: auditStatus },
|
|
{
|
|
id: parseInt(id)
|
|
},
|
|
frontendJWT
|
|
);
|
|
|
|
if (response.error) {
|
|
return { error: response.error, status: response.status };
|
|
}
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error('更新文件审核状态失败:', error);
|
|
return {
|
|
error: error instanceof Error ? error.message : '更新文件审核状态失败',
|
|
status: 500
|
|
};
|
|
}
|
|
} |