import { postgrestGet, postgrestPut, type PostgrestParams } from '../postgrest-client'; // import dayjs from 'dayjs'; import { getDocumentTypes } from '../document-types/document-types'; import type { DocumentTypeUI } from '../document-types/document-types'; // import weekday from 'dayjs/plugin/weekday'; // import updateLocale from 'dayjs/plugin/updateLocale'; import { formatDate } from '../../utils'; // // 配置 dayjs // dayjs.extend(weekday); // dayjs.extend(updateLocale); // // 设置一周的第一天为周一 // dayjs.updateLocale('en', { // weekStart: 1 // }); // 文档数据库表接口 export interface Document { id: number; user_id: number | null; type_id: number; name: string; document_number: string; path: string; storage_type: string; file_size: number; upload_time: string; is_test_document: boolean; evaluation_level: string; status: string; ocr_result: Record; extracted_results: Record | null; sumary: string | null; remark: string; created_at: string; updated_at: string; evaluations_status: number | null; audit_status: number | null; } // 文档类型接口 export interface DocumentType { id: number; name: string; description: string | null; status: number; created_at: string; updated_at: string; } // 评查文件UI接口 export interface ReviewFileUI { id: string; status: string; path: string; fileName: string; fileCode: string; fileType: string; fileTypeId: number; fileSize: number; uploadTime: string; reviewStatus: string; reviewStatusCode: number; issueCount: number; score?: number; auditStatus: number | null; issues: Array<{ severity: 'info' | 'warning' | 'error' | 'critical'; message: string; }>; createdBy: string; passCount: number; warningCount: number; failCount: number; manualCount: number; } // 文件列表搜索参数 export interface DocumentSearchParams { fileType?: string; // 文件类型ID reviewStatus?: string; // 评查状态 // dateRange?: string; // 日期范围 dateFrom?: string; // 开始日期 dateTo?: string; // 结束日期 keyword?: string; // 搜索关键字 sortOrder?: string; // 排序方式 page?: number; // 当前页码 pageSize?: number; // 每页条数 } // 添加评查结果和评查点类型定义 // 评查结果类型 interface EvaluationResult { id: string | number; document_id: string | number; evaluation_point_id: string | number; evaluated_results?: { result?: boolean; message?: string; data?: string; [key: string]: unknown; }; [key: string]: unknown; } // 评查点类型 interface EvaluationPoint { id: string | number; post_action?: string; score?: number; [key: string]: unknown; } // 文档评查状态结果 interface DocumentReviewResult { status: number; issueCount: number; passCount: number; warningCount: number; failCount: number; manualCount: number; } /** * 从不同格式的 API 响应中提取数据 * @param responseData API 响应数据 * @returns 提取后的数据或 null */ function extractApiData(responseData: unknown): T | null { if (!responseData) return null; // 格式1: { code: number, msg: string, data: T } if (typeof responseData === 'object' && responseData !== null && 'code' in responseData && 'data' in responseData && (responseData as { data: unknown }).data) { return (responseData as { data: T }).data; } // 格式2: 直接是数据对象 return responseData as T; } /** * 将评查状态代码映射到UI状态 * @param status 评查状态代码 * @returns UI状态 */ export function mapReviewStatusToUI(status: number | null): string { switch(status) { case 1: return 'pass'; case -2: return 'warning'; case -1: return 'fail'; case 0: return 'pending'; default: return 'pending'; } } /** * 将UI状态映射到评查状态代码 * @param status UI状态 * @returns 评查状态代码 */ export function mapUIToReviewStatus(status: string): number { switch(status) { case 'pass': return 1; case 'warning': return -2; case 'fail': return -1; case 'pending': return 0; default: return 0; } } /** * 获取文件扩展名 * @param fileName 文件名 * @returns 文件扩展名 */ export function getFileExtension(fileName: string): string { return fileName.split('.').pop()?.toLowerCase() || ''; } /** * 将数据库文档转换为UI文件对象 * @param document 数据库文档 * @param documentTypeName 文档类型名称 * @returns UI文件对象 */ export function convertToReviewFileUI(document: Document, documentTypeName: string): ReviewFileUI { // 将评查状态转换为UI状态(这个评查状态后续可能不需要,这里先预留) const reviewStatus = mapReviewStatusToUI(document.evaluations_status); const reviewFileUI: ReviewFileUI = { id: document.id.toString(), status: document.status, path: document.path, fileName: document.name, fileCode: document.document_number, fileType: documentTypeName, fileTypeId: document.type_id, fileSize: document.file_size, uploadTime: formatDate(document.created_at), reviewStatus: reviewStatus, reviewStatusCode: document.evaluations_status || 0, issueCount: 0, score: 0, auditStatus: document.audit_status, issues: [], createdBy: document.user_id?.toString() || '系统', passCount: 0, warningCount: 0, failCount: 0, manualCount: 0 }; // console.log('reviewFileUI-----',reviewFileUI); return reviewFileUI; } /** * 获取评查文件列表 * @param searchParams 搜索参数 * @returns 评查文件列表和总数 */ export async function getReviewFiles(searchParams: DocumentSearchParams = {}): Promise<{ data?: { files: ReviewFileUI[], total: number }; error?: string; status?: number; }> { try { const page = searchParams.page || 1; const pageSize = searchParams.pageSize || 10; // 构建查询参数 const params: PostgrestParams = { select: '*', order: 'created_at.desc', headers: { 'Prefer': 'count=exact' }, limit: pageSize, offset: (page - 1) * pageSize, filter: {} as Record }; // 根据排序方式设置排序 if (searchParams.sortOrder) { switch (searchParams.sortOrder) { case 'upload_time_desc': params.order = 'created_at.desc'; break; case 'upload_time_asc': params.order = 'created_at.asc'; break; // case 'issue_count_desc': // params.order = 'issue_count.desc'; // break; // case 'issue_count_asc': // params.order = 'issue_count.asc'; // break; } } // 添加筛选条件 const filter: Record = {}; if (searchParams.fileType) { filter['type_id'] = `eq.${searchParams.fileType}`; } if (searchParams.reviewStatus) { const statusValue = mapUIToReviewStatus(searchParams.reviewStatus); filter['evaluations_status'] = `eq.${statusValue}`; } if (searchParams.keyword) { filter['or'] = `(name.ilike.%${searchParams.keyword}%,document_number.ilike.%${searchParams.keyword}%)`; } // 处理日期范围筛选 if(searchParams.dateFrom){ filter['created_at'] = `gte.${searchParams.dateFrom+ ' 00:00:00'}`; } if(searchParams.dateTo){ const dateToKey = searchParams.dateFrom ? 'and' : 'created_at'; if(dateToKey === 'and'){ delete filter['created_at']; filter[dateToKey] = `(created_at.gte.${searchParams.dateFrom+' 00:00:00'},created_at.lte.${searchParams.dateTo+' 23:59:59'})`; }else{ filter['created_at'] = `lte.${searchParams.dateTo+' 23:59:59'}`; } } // if (searchParams.dateRange) { // const now = dayjs(); // const today = now.startOf('day').format('YYYY-MM-DD HH:mm:ss'); // switch (searchParams.dateRange) { // case 'today': // filter['created_at'] = `gte.${today}`; // break; // case 'week': { // const weekStart = now.startOf('week').format('YYYY-MM-DD HH:mm:ss'); // filter['created_at'] = `gte.${weekStart}`; // break; // } // case 'month': { // const monthStart = now.startOf('month').format('YYYY-MM-DD HH:mm:ss'); // filter['created_at'] = `gte.${monthStart}`; // break; // } // } // } params.filter = filter; console.log('params-----',params); // 发送API请求获取文档列表 const response = await postgrestGet('documents', params); if (response.error) { return { error: response.error, status: response.status }; } // 提取API返回的数据 const extractedDocuments = extractApiData(response.data); if (!extractedDocuments) { return { error: '获取评查文件数据失败', status: 500 }; } // 从响应头中获取总数 let totalCount = 0; const responseWithHeaders = response as { data: Document[]; headers: Record }; if(responseWithHeaders.headers){ const rangeHeader = responseWithHeaders.headers['content-range']; if(rangeHeader){ const total = rangeHeader.split('/')[1]; if(total !== '*'){ totalCount = parseInt(total, 10); } } } // 获取文档类型数据,用于查找文档类型名称 const documentTypesResponse = await getDocumentTypes({pageSize: 500}); const documentTypes = documentTypesResponse.data?.types || []; // 创建文档类型ID到名称的映射 const typeNameMap: Record = {}; documentTypes.forEach((type: DocumentTypeUI) => { typeNameMap[type.id] = type.name; }); // 获取评查文件的评查结果 // 第一步:收集所有文档ID const documentIds = extractedDocuments.map(doc => doc.id); // 第二步:查询所有文档的评查结果数据 const evaluationResultParams: PostgrestParams = { select: '*', filter: { 'document_id': `in.(${documentIds.join(',')})` } }; const evaluationResultsResponse = await postgrestGet('evaluation_results', evaluationResultParams); let evaluationResults: EvaluationResult[] = []; if (!evaluationResultsResponse.error) { evaluationResults = extractApiData(evaluationResultsResponse.data) || []; } // 第三步:收集所有评查点ID const evaluationPointIds = evaluationResults .map(result => result.evaluation_point_id) .filter(Boolean); // 第四步:获取评查点数据 let evaluationPoints: EvaluationPoint[] = []; if (evaluationPointIds.length > 0) { const evaluationPointsParams: PostgrestParams = { select: '*', filter: { 'id': `in.(${evaluationPointIds.join(',')})` } }; const evaluationPointsResponse = await postgrestGet('evaluation_points', evaluationPointsParams); if (!evaluationPointsResponse.error) { evaluationPoints = extractApiData(evaluationPointsResponse.data) || []; } } // 创建评查点ID到评查点数据的映射 const pointsMap = new Map(); evaluationPoints.forEach(point => { pointsMap.set(point.id, point); }); // 创建文档ID到评查结果列表的映射 const documentResultsMap = new Map(); evaluationResults.forEach(result => { const docId = result.document_id; if (!documentResultsMap.has(docId)) { documentResultsMap.set(docId, []); } documentResultsMap.get(docId)!.push(result); }); // 计算每个文档的评查状态和问题列表 const documentStatusMap = new Map(); // 存储每个文档的问题消息 const documentIssuesMap = new Map>(); // 存储每个文档的分数 const documentScoreMap = new Map(); documentIds.forEach(docId => { const results = documentResultsMap.get(docId) || []; // 1. 首先检查是否有需要人工审核的评查点 let hasManualReviewPoint = false; let hasFailResult = false; let totalScore = 0; let totalPoints = 0; let totalPassPoints = 0; let totalWarningPoints = 0; let totalFailPoints = 0; let totalManualPoints = 0; // 存储该文档的问题消息 const issuesList: Array<{severity: 'info' | 'warning' | 'error' | 'critical', message: string}> = []; for (const result of results) { const evaluatedResults = result.evaluated_results || {}; const resultValue = evaluatedResults.result; const pointId = result.evaluation_point_id; const point = pointsMap.get(pointId); // 统计需要人工审核的评查点 if (point && point.post_action === 'manual') { hasManualReviewPoint = true; totalManualPoints++; } // 检查是否有不通过的结果 if (!resultValue) { hasFailResult = true; // 收集问题消息 if (evaluatedResults.message) { issuesList.push({ severity: 'error', message: evaluatedResults.message as string }); } // 统计不通过而且评查点是警告的评查点 if (point && point.suggestion_message_type === 'warning') { totalWarningPoints++; }else if (point && point.suggestion_message_type === 'error') { totalFailPoints++; } }else{ totalPassPoints++; } // 计算总分 if (point) { totalScore += point.score || 0; totalPoints++; } } // 保存文档的问题列表 documentIssuesMap.set(docId, issuesList); // 计算并保存文档的分数 const calculatedScore = totalScore || 100; documentScoreMap.set(docId, calculatedScore); // 根据优先级确定评查状态 let status = 1; // 默认为通过 // 待人工确认优先级最高 if (hasManualReviewPoint) { status = 0; // 待人工确认 } // 警告次之 else if (hasFailResult) { status = -2; // 警告 } // 最后判断分数 else { // 如果没有评查点,默认为通过 if (totalPoints > 0) { // 通过分数线为80分 // status = totalScore >= 80 ? 1 : -1; // 通过或不通过 // 通过率为80% status = parseFloat((totalPassPoints/totalPoints).toFixed(1)) >= 0.8 ? 1 : -1; // 通过或不通过 } } documentStatusMap.set(docId, { status, passCount: totalPassPoints, warningCount: totalWarningPoints, failCount: totalFailPoints, manualCount: totalManualPoints, issueCount: results.filter(r => r.evaluated_results?.result === false).length }); }); // console.log("documentStatusMap-----",documentStatusMap); // 将文档数据转换为UI文件对象,同时应用评查状态 const reviewFiles = extractedDocuments.map(doc => { const typeName = typeNameMap[doc.type_id] || '未知类型'; const reviewResult = documentStatusMap.get(doc.id) || { status: doc.evaluations_status || 0, issueCount: 0, passCount: 0, warningCount: 0, failCount: 0, manualCount: 0 }; const issues = documentIssuesMap.get(doc.id) || []; const score = documentScoreMap.get(doc.id) || 100; // 获取计算后的分数,默认为100 // 如果文档的评查状态与计算结果不同,更新文档的评查状态 if (doc.evaluations_status !== reviewResult.status) { // 异步更新文档评查状态 postgrestPut('documents', { evaluations_status: reviewResult.status }, { id: doc.id } ).catch(err => console.error(`更新文档${doc.id}评查状态失败:`, err)); } const reviewFile = convertToReviewFileUI(doc, typeName); // 覆盖文档的评查状态和问题计数 reviewFile.reviewStatusCode = reviewResult.status; reviewFile.reviewStatus = mapReviewStatusToUI(reviewResult.status); reviewFile.issueCount = reviewResult.issueCount; reviewFile.passCount = reviewResult.passCount; reviewFile.warningCount = reviewResult.warningCount; reviewFile.failCount = reviewResult.failCount; reviewFile.manualCount = reviewResult.manualCount; reviewFile.score = score; // 添加分数 // 添加问题列表 reviewFile.issues = issues; return reviewFile; }); // console.log('reviewFiles-----',reviewFiles); return { data: { files: reviewFiles, total: totalCount } }; } catch (error) { console.error('获取评查文件列表失败:', error); return { error: error instanceof Error ? error.message : '获取评查文件列表失败', status: 500 }; } } /** * 更新文件的评查状态 * @param id 文件ID * @param status 评查状态 * @returns 更新后的文件信息 */ // export async function updateReviewStatus(id: string, status: string): Promise<{ // data?: ReviewFileUI; // error?: string; // status?: number; // }> { // try { // if (!id) { // return { error: '文件ID不能为空', status: 400 }; // } // const statusValue = mapUIToReviewStatus(status); // const response = await postgrestPut>( // 'documents', // { evaluations_status: statusValue }, // { id: parseInt(id) } // ); // if (response.error) { // return { error: response.error, status: response.status }; // } // const extractedData = extractApiData(response.data); // if (!extractedData) { // return { error: '更新评查状态失败', status: 500 }; // } // // 获取文档类型,用于查找文档类型名称 // const documentTypesResponse = await getDocumentTypes({pageSize: 500}); // const documentTypes = documentTypesResponse.data?.types || []; // // 查找文档类型名称 // const docType = documentTypes.find((type: DocumentTypeUI) => type.id === extractedData.type_id); // const typeName = docType ? docType.name : '未知类型'; // return { data: convertToReviewFileUI(extractedData, typeName) }; // } catch (error) { // console.error('更新评查状态失败:', error); // return { // error: error instanceof Error ? error.message : '更新评查状态失败', // status: 500 // }; // } // } /** * 更新文件的审核状态 * @param id 文件ID * @param auditStatus 审核状态 * @returns 更新结果 */ export async function updateDocumentAuditStatus(id: string, auditStatus: number): Promise<{ success?: boolean; error?: string; status?: number; }> { try { if (!id) { return { error: '文件ID不能为空', status: 400 }; } const response = await postgrestPut>( 'documents', { audit_status: auditStatus }, { id: parseInt(id) } ); 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 }; } }