diff --git a/app/api/files/documents.ts b/app/api/files/documents.ts index 71e8b50..467ec91 100644 --- a/app/api/files/documents.ts +++ b/app/api/files/documents.ts @@ -130,6 +130,57 @@ export interface DocumentVersionUI { previous_manual_count?: number | null; // 上一版本人工数量 } +interface LeauditHistoryVersion { + documentId: number; + fileId?: number | null; + versionNo: number; + fileName?: string | null; + fileExt?: string | null; + processingStatus?: string | null; + runStatus?: string | null; + resultStatus?: string | null; + updatedAt?: string | null; +} + +interface LeauditListItem { + documentId: number; + internalDocumentNo: number; + versionGroupKey: string; + versionNo: number; + rootVersionId: number; + previousVersionId?: number | null; + typeId?: number | null; + typeCode?: string | null; + region: string; + normalizedName?: string | null; + fileId?: number | null; + fileName?: string | null; + fileExt?: string | null; + mimeType?: string | null; + fileSize?: number | null; + ossUrl?: string | null; + processingStatus?: string | null; + currentRunId?: number | null; + runStatus?: string | null; + resultStatus?: string | null; + totalScore?: number | null; + passedCount?: number | null; + failedCount?: number | null; + skippedCount?: number | null; + updatedAt?: string | null; + hasHistory?: boolean; + totalVersions?: number; + historyVersions?: LeauditHistoryVersion[]; +} + +interface LeauditListPage { + total: number; + page: number; + pageSize: number; + totalPages: number; + documents: LeauditListItem[]; +} + /** * 获取文件扩展名 * @param filename 文件名 @@ -140,6 +191,61 @@ function getFileExtension(filename: string): string { return parts.length > 1 ? parts.pop()?.toLowerCase() || '' : ''; } +function mapProcessingStatusToFileStatus(status?: string | null): string { + const normalized = (status || '').toLowerCase(); + if (normalized === 'completed') return 'Processed'; + if (normalized === 'failed') return 'Failed'; + if (normalized === 'running' || normalized === 'queued' || normalized === 'dispatch') return 'Evaluationing'; + if (normalized === 'waiting' || normalized === 'pending') return 'Waiting'; + return 'Waiting'; +} + +function mapLeauditDocToAuditStatus(doc: { + processingStatus?: string | null; + runStatus?: string | null; + passedCount?: number | null; + failedCount?: number | null; +}): number { + const processingStatus = (doc.processingStatus || '').toLowerCase(); + const runStatus = (doc.runStatus || '').toLowerCase(); + + if (runStatus === 'queued' || runStatus === 'running' || processingStatus === 'running') { + return 2; + } + if (processingStatus === 'waiting' || processingStatus === 'pending') { + return 0; + } + if (processingStatus === 'failed') { + return -1; + } + if ((doc.failedCount || 0) > 0) { + return -1; + } + if ((doc.passedCount || 0) > 0) { + return 1; + } + return 0; +} + +function typeNameFromCode(typeCode?: string | null): string { + if (!typeCode) return '未知类型'; + const typeMap: Record = { + 'contract.sale': '购销合同', + 'contract.purchase': '采购合同', + 'contract.lease': '租赁合同', + 'contract.service': '服务合同', + }; + if (typeMap[typeCode]) return typeMap[typeCode]; + return typeCode; +} + +function buildDocumentNumber(doc: LeauditListItem | LeauditHistoryVersion): string { + if ('versionNo' in doc && doc.versionNo) { + return `v${doc.versionNo}`; + } + return ''; +} + /** * 获取评查结果 * @param id 评查结果ID @@ -401,20 +507,12 @@ export async function getDocumentTypesByIds(ids: number[], frontendJWT?: string) return { data: { types: [], total: 0 } }; } - const response = await postgrestGet( - '/api/postgrest/proxy/document_types', - { - filter: { - 'id': `in.(${ids.join(',')})` - }, - token: frontendJWT - }); - + const response = await getDocumentTypes({ ids, page: 1, pageSize: Math.max(ids.length, 10) }, frontendJWT); if (response.error) { return { error: response.error, status: response.status }; } - const extractedData = extractApiData(response.data); + const extractedData = response.data?.types; if (!extractedData) { return { error: '获取文档类型列表失败', status: 500 }; } @@ -556,30 +654,45 @@ export async function getDocumentsListFromAPI(searchParams: { token } = searchParams; - // 构建查询参数 const params: Record = { page, - page_size: pageSize + pageSize }; - // 添加可选参数 - if (name) params.name = name; - if (documentNumber) params.document_number = documentNumber; - if (auditStatus) params.audit_status = parseInt(auditStatus, 10); - if (fileStatus) params.status = fileStatus; - if (dateFrom) params.start_time = dateFrom; - if (dateTo) params.end_time = dateTo; - - // 处理文档类型ID数组 - 转换为逗号分隔的字符串 - if (documentTypeIds && documentTypeIds.length > 0) { - params.type_id = documentTypeIds.join(','); + // 新接口已落地的筛选项 + if (name) params.keyword = name; + if (fileStatus) { + const normalizedFileStatus = fileStatus.toLowerCase(); + if (normalizedFileStatus === 'processed') { + params.processingStatus = 'completed'; + } else if (normalizedFileStatus === 'failed') { + params.processingStatus = 'failed'; + } else { + params.processingStatus = 'running'; + } } - // console.log('📤 [getDocumentsListFromAPI] 请求参数:', params); + if (documentTypeIds && documentTypeIds.length === 1) { + const typeResponse = await getDocumentTypes({ ids: documentTypeIds, page: 1, pageSize: 10 }, token); + const matchedType = typeResponse.data?.types?.[0]; + if (matchedType?.code) { + params.typeCode = matchedType.code; + } + } + + // 下面几个旧筛选项在新系统版列表接口里暂未一一对齐: + // - documentNumber + // - auditStatus + // - dateFrom/dateTo + // - 多个 documentTypeIds 的组合筛选 + // 先保留参数签名,后续再单独接新后端的类型/状态体系。 + void documentNumber; + void auditStatus; + void dateFrom; + void dateTo; - // 调用后端API const axios = await import('axios').then(m => m.default); - const response = await axios.get(`${API_BASE_URL}/admin/versions/documents-list`, { + const response = await axios.get(`${API_BASE_URL}/api/documents/list`, { params, headers: { 'Authorization': `Bearer ${token}`, @@ -587,105 +700,79 @@ export async function getDocumentsListFromAPI(searchParams: { } }); - const data = response.data; - const backendDocuments = data.documents || []; - const totalCount = data.total || 0; - const totalPages = data.total_pages || 0; + const pageData = extractApiData(response.data); + if (!pageData) { + return { error: '获取文档列表失败', status: response.status }; + } - // console.log(`📥 [getDocumentsListFromAPI] 获取到 ${backendDocuments.length} 个文档,总数: ${totalCount}`); + const backendDocuments = pageData.documents || []; + const totalCount = pageData.total || 0; + const totalPages = pageData.totalPages || Math.ceil(totalCount / pageSize) || 0; - // 转换后端数据为前端 DocumentUI 格式 - const convertedDocuments: DocumentUI[] = backendDocuments.map((doc: any) => { - // 转换历史版本数据 - const historyVersions: DocumentVersionUI[] = (doc.history_versions || []).map((hv: any, index: number) => { - // 计算与下一个版本(更早的版本)的问题数量差异 - let issuesDiff: number | undefined; - let issuesDiffType: 'increase' | 'decrease' | 'same' | undefined; - - if (index < doc.history_versions.length - 1) { - const olderDoc = doc.history_versions[index + 1]; - if (hv.issue_count != null && olderDoc.issue_count != null) { - const diff = hv.issue_count - olderDoc.issue_count; - issuesDiff = Math.abs(diff); - if (diff > 0) { - issuesDiffType = 'increase'; - } else if (diff < 0) { - issuesDiffType = 'decrease'; - } else { - issuesDiffType = 'same'; - } - } - } - - // 获取前一个版本的统计数据(如果存在) - const prevVersion = index < doc.history_versions.length - 1 ? doc.history_versions[index + 1] : null; - - return { - id: hv.id, - name: hv.name || doc.name, - documentNumber: hv.document_number || doc.document_number || '', - type: hv.type_id?.toString() || doc.type_id?.toString() || '', - typeName: hv.type_name || doc.type_name || '未知类型', - size: hv.file_size || 0, - auditStatus: hv.audit_status ?? 0, - fileStatus: hv.status || 'Processed', - issues: hv.issue_count ?? null, - issuesDiff, - issuesDiffType, - uploadTime: formatDate(hv.created_at), - fileType: getFileExtension(hv.name || doc.name), - path: hv.path || '', - isTest: hv.is_test_document || false, - updatedAt: formatDate(hv.updated_at || hv.created_at), - pageCount: hv.ocr_result?.__meta?.page_count || 0, - ocrResult: hv.ocr_result, - versionNumber: hv.version_number, - // 结果统计字段 - pass_count: hv.pass_count ?? null, - warning_count: hv.warning_count ?? null, - error_count: hv.error_count ?? null, - manual_count: hv.manual_count ?? null, - // 前一版本统计(用于差异对比) - previous_pass_count: prevVersion?.pass_count ?? null, - previous_warning_count: prevVersion?.warning_count ?? null, - previous_error_count: prevVersion?.error_count ?? null, - previous_manual_count: prevVersion?.manual_count ?? null - }; - }); + const convertedDocuments: DocumentUI[] = backendDocuments.map((doc) => { + const historyVersions: DocumentVersionUI[] = (doc.historyVersions || []).map((hv) => ({ + id: hv.documentId, + name: hv.fileName || doc.fileName || doc.normalizedName || '未命名文档', + documentNumber: buildDocumentNumber(hv), + type: doc.typeId?.toString() || '', + typeName: typeNameFromCode(doc.typeCode), + size: 0, + auditStatus: mapLeauditDocToAuditStatus({ + processingStatus: hv.processingStatus, + runStatus: hv.runStatus, + passedCount: null, + failedCount: null, + }), + fileStatus: mapProcessingStatusToFileStatus(hv.processingStatus), + issues: null, + uploadTime: formatDate(hv.updatedAt || ''), + fileType: hv.fileExt || getFileExtension(hv.fileName || doc.fileName || ''), + path: '', + isTest: false, + updatedAt: formatDate(hv.updatedAt || ''), + pageCount: 0, + ocrResult: undefined, + versionNumber: hv.versionNo, + pass_count: null, + warning_count: 0, + error_count: null, + manual_count: null, + previous_pass_count: null, + previous_warning_count: null, + previous_error_count: null, + previous_manual_count: null + })); return { - id: doc.id, - name: doc.name, - documentNumber: doc.document_number || '', - type: doc.type_id?.toString() || '', - typeName: doc.type_name || '未知类型', - size: doc.file_size || 0, - auditStatus: doc.audit_status ?? 0, - fileStatus: doc.status || '', - issues: doc.issue_count ?? null, - uploadTime: formatDate(doc.upload_time || doc.created_at), - fileType: getFileExtension(doc.name), - path: doc.path || '', - isTest: doc.is_test_document || false, - updatedAt: formatDate(doc.updated_at || doc.created_at), - pageCount: doc.ocr_result?.__meta?.page_count || 0, - ocrResult: doc.ocr_result, - // 结果统计字段 - pass_count: doc.pass_count ?? null, - warning_count: doc.warning_count ?? null, - error_count: doc.error_count ?? null, - manual_count: doc.manual_count ?? null, - // 消息详情字段 - warning_messages: doc.warning_messages || [], - error_messages: doc.error_messages || [], - manual_messages: doc.manual_messages || [], - // 版本管理字段 - historyCount: (doc.total_versions || 1) - 1, // 总版本数 - 1 = 历史版本数 - previousIssues: doc.history_versions?.[0]?.issue_count ?? null, - previous_pass_count: doc.history_versions?.[0]?.pass_count ?? null, - previous_warning_count: doc.history_versions?.[0]?.warning_count ?? null, - previous_error_count: doc.history_versions?.[0]?.error_count ?? null, - previous_manual_count: doc.history_versions?.[0]?.manual_count ?? null, + id: doc.documentId, + name: doc.fileName || doc.normalizedName || '未命名文档', + documentNumber: buildDocumentNumber(doc), + type: doc.typeId?.toString() || '', + typeName: typeNameFromCode(doc.typeCode), + size: doc.fileSize || 0, + auditStatus: mapLeauditDocToAuditStatus(doc), + fileStatus: mapProcessingStatusToFileStatus(doc.processingStatus), + issues: doc.failedCount ?? null, + uploadTime: formatDate(doc.updatedAt || ''), + fileType: doc.fileExt || getFileExtension(doc.fileName || ''), + path: doc.ossUrl || '', + isTest: false, + updatedAt: formatDate(doc.updatedAt || ''), + pageCount: 0, + ocrResult: undefined, + pass_count: doc.passedCount ?? null, + warning_count: 0, + error_count: doc.failedCount ?? null, + manual_count: doc.skippedCount ?? null, + warning_messages: [], + error_messages: [], + manual_messages: [], + historyCount: Math.max(0, (doc.totalVersions || 1) - 1), + previousIssues: historyVersions[0]?.issues ?? null, + previous_pass_count: historyVersions[0]?.pass_count ?? null, + previous_warning_count: historyVersions[0]?.warning_count ?? null, + previous_error_count: historyVersions[0]?.error_count ?? null, + previous_manual_count: historyVersions[0]?.manual_count ?? null, historyVersions: historyVersions.length > 0 ? historyVersions : undefined }; }); @@ -694,7 +781,7 @@ export async function getDocumentsListFromAPI(searchParams: { data: { documents: convertedDocuments, total: totalCount, - page: data.page || page, + page: pageData.page || page, totalPages } }; diff --git a/app/routes/documents.list.tsx b/app/routes/documents.list.tsx index 16b15e0..7f23c5d 100644 --- a/app/routes/documents.list.tsx +++ b/app/routes/documents.list.tsx @@ -322,12 +322,22 @@ export default function DocumentsIndex() { // 获取经过过滤的文档类型列表 const filteredTypesResponse = await getDocumentTypesByIds(typeIds, jwtToken); - const filteredDocumentTypes = filteredTypesResponse.data?.types || []; - const filteredOptions = filteredDocumentTypes.map(type => ({ - value: type.id, - label: type.name - })); - setFilteredDocumentTypeOptions(filteredOptions); + if (filteredTypesResponse.data?.types?.length) { + const filteredOptions = filteredTypesResponse.data.types.map(type => ({ + value: type.id, + label: type.name + })); + setFilteredDocumentTypeOptions(filteredOptions); + } else { + const fallbackOptions = Array.from( + new Map( + result.data.documents + .filter(doc => doc.type && doc.typeName) + .map(doc => [doc.type, { value: Number(doc.type), label: doc.typeName }]) + ).values() + ); + setFilteredDocumentTypeOptions(fallbackOptions); + } } catch (error) { console.error('❌ [fetchData] 获取文档列表失败:', error);