import { postgrestGet, postgrestDelete, postgrestPut, type PostgrestParams } from '../postgrest-client'; import { getDocumentTypes } from '../document-types/document-types'; import { formatDate } from '../../utils'; /** * 从不同格式的 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; } /** * 查询参数 */ export interface DocumentSearchParams { name?: string; documentNumber?: string; documentType?: string; status?: string; auditStatus?: string; fileStatus?: string; dateFrom?: string; dateTo?: string; page?: number; pageSize?: number; reviewType?: string; } /** * 数据库文档结构 */ 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: 'pass' | 'warning' | 'waiting' | 'processing' | 'fail'; file_status: 'Waiting' | 'Cutting' | 'Extractioning' | 'Evaluationing' | 'Processed'; audit_status: number; // -1: 不通过, 0: 待审核, 1: 通过, 2: 警告, 3: 审核中 ocr_result?: { __meta?: { page_count?: number; } }; extracted_results?: unknown; summary?: unknown; remark?: string; created_at: string; updated_at: string; } /** * 前端UI文档结构 */ export interface DocumentUI { id: number; name: string; documentNumber: string; type: string; typeName: string; size: number; auditStatus: number; // -1: 不通过, 0: 待审核, 1: 通过, 2: 警告, 3: 审核中 fileStatus: string; // Waiting, Cutting, Extractioning, Failed, Evaluationing, Processed issues: number | null; uploadTime: string; fileType: string; path: string; isTest: boolean; updatedAt?: string; pageCount?: number; ocrResult?: unknown; } /** * 获取文件扩展名 * @param filename 文件名 * @returns 文件扩展名 */ function getFileExtension(filename: string): string { const parts = filename.split('.'); return parts.length > 1 ? parts.pop()?.toLowerCase() || '' : ''; } /** * 获取评查结果 * @param id 评查结果ID * @returns 评查结果 */ async function getEvaluationResults(id: number) { const response = await postgrestGet<[]>('evaluation_results', { filter: { 'document_id': `eq.${id}` } }); if (response.error) { return { error: response.error, status: response.status }; } const evaluationResult = extractApiData<[]>(response.data); return evaluationResult; } /** * 将API文档转换为UI文档 */ async function convertToUIDocument(doc: Document): Promise { // 获取文档类型信息 const typeResponse = await getDocumentTypes(); const documentTypes = typeResponse.data?.types || []; const docType = documentTypes.find(type => type.id.toString() === doc.type_id.toString()); const evaluationResult = await getEvaluationResults(doc.id); let issues = 0; interface EvaluationResultItem { evaluated_results?: { result?: string; [key: string]: unknown; }; [key: string]: unknown; } if (evaluationResult && Array.isArray(evaluationResult)) { evaluationResult.forEach((result: EvaluationResultItem) => { if(result && result.evaluated_results && !result.evaluated_results.result){ issues++; } }); } return { id: doc.id, name: doc.name, documentNumber: doc.document_number, type: doc.type_id.toString(), typeName: docType?.name || '未知类型', size: doc.file_size, auditStatus: doc.audit_status || 0, fileStatus: doc.status || '', // 默认为'' issues: issues, // 使用计算得到的issues uploadTime: formatDate(doc.updated_at), fileType: getFileExtension(doc.name), path: doc.path, isTest: doc.is_test_document, updatedAt: formatDate(doc.updated_at), pageCount: doc.ocr_result?.__meta?.page_count || 0, ocrResult: doc.ocr_result }; } /** * 获取文档列表 * @param searchParams 搜索参数 * @returns 文档列表和总数 */ export async function getDocuments(searchParams: DocumentSearchParams = {}): Promise<{ data?: { documents: DocumentUI[], total: number }; error?: string; status?: number; }> { try { const page = searchParams.page || 1; const pageSize = searchParams.pageSize || 10; // 构建查询参数 const params: PostgrestParams = { select: '*', order: 'updated_at.desc', headers: { 'Prefer': 'count=exact' }, limit: pageSize, offset: (page - 1) * pageSize, filter: {} as Record }; // 添加筛选条件 const filter: Record = {}; if (searchParams.name) { filter['name'] = `ilike.%${searchParams.name}%`; } if (searchParams.documentNumber) { filter['document_number'] = `ilike.%${searchParams.documentNumber}%`; } if (searchParams.documentType) { filter['type_id'] = `eq.${searchParams.documentType}`; } if (searchParams.auditStatus) { // 处理"待审核"状态 - 特殊处理 audit_status = 0 的情况,同时包含 null 值 if (searchParams.auditStatus === '0') { filter['or'] = `(audit_status.eq.0,audit_status.is.null)`; } else { filter['audit_status'] = `eq.${searchParams.auditStatus}`; } } if (searchParams.fileStatus) { filter['status'] = `eq.${searchParams.fileStatus}`; } // 处理日期范围 if (searchParams.dateFrom) { // 添加当天开始时间 00:00:00 filter['created_at'] = `gte.${searchParams.dateFrom + ' 00:00:00'}`; } if (searchParams.dateTo) { // 如果有开始日期,使用and条件;否则直接设置结束日期 const dateToKey = searchParams.dateFrom ? 'and' : 'created_at'; // 添加当天结束时间 23:59:59 if (dateToKey === 'and') { delete filter['created_at']; // 使用OR操作符连接两个条件 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'}`; } } // 根据 reviewType 添加过滤条件 if (searchParams.reviewType) { // 如果已经有文档类型过滤,则不再添加 reviewType 的过滤 if (!searchParams.documentType) { if (searchParams.reviewType === 'contract') { // 如果是合同类型,只显示 type_id=1 的文档 filter['type_id'] = 'eq.1'; } else if (searchParams.reviewType === 'record') { // 如果是卷宗类型,只显示 type_id=2 或 type_id=3 的文档 filter['type_id'] = 'in.(2,3)'; } } } // console.log('filter-----', filter); params.filter = filter; // 发送请求 const response = await postgrestGet('documents', params); if (response.error) { return { error: response.error, status: response.status }; } // 提取数据 const extractedData = extractApiData(response.data); if (!extractedData) { return { error: '获取文档数据失败', status: 500 }; } // console.log('extractedData---1--',extractedData[0]); // 转换为UI格式 const documents = await Promise.all(extractedData.map(convertToUIDocument)); // console.log('documentsItem',documents) // 获取总数 let totalCount = 0; const responseWithHeaders = response as { data: unknown; headers?: Record }; if (responseWithHeaders.headers) { const rangeHeader = responseWithHeaders.headers['content-range']; if (rangeHeader) { const total = rangeHeader.split('/')[1]; if (total !== '*') { totalCount = parseInt(total, 10); } } } return { data: { documents, total: totalCount || documents.length } }; } catch (error) { console.error('获取文档列表失败:', error); return { error: error instanceof Error ? error.message : '获取文档列表失败', status: 500 }; } } /** * 删除文档 * @param id 文档ID * @returns 删除结果 */ export async function deleteDocument(id: string): Promise<{ success?: boolean; error?: string; status?: number; }> { try { if (!id) { return { error: '文档ID不能为空', status: 400 }; } const response = await postgrestDelete( 'documents', { filter: { 'id': `eq.${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 }; } } /** * 获取单个文档详情 * @param id 文档ID * @returns 文档详情 */ export async function getDocument(id: string): Promise<{ data?: DocumentUI; error?: string; status?: number; }> { try { if (!id) { return { error: '文档ID不能为空', status: 400 }; } const response = await postgrestGet( 'documents', { filter: { 'id': `eq.${id}` }, limit: 1 } ); if (response.error) { return { error: response.error, status: response.status }; } const extractedData = extractApiData(response.data); if (!extractedData || extractedData.length === 0) { return { error: '文档不存在', status: 404 }; } const documentUI = await convertToUIDocument(extractedData[0]); return { data: documentUI }; } catch (error) { console.error('获取文档详情失败:', error); return { error: error instanceof Error ? error.message : '获取文档详情失败', status: 500 }; } } /** * 获取文件下载链接 * @param filePath 文件路径 * @returns 下载链接 */ export async function getFileDownloadUrl(filePath: string): Promise<{ data?: { downloadUrl: string }; error?: string; status?: number; }> { try { if (!filePath) { return { error: '文件路径不能为空', status: 400 }; } // 这里应该调用获取文件下载链接的API // 假设后端有这样的端点:/api/files/generate-download-url?path=xxx // 实际项目中需要根据你的后端API调整 // 临时解决方案:返回Remix路由路径 // 这将通过Remix服务器代理对文件的访问 return { data: { downloadUrl: `/documents/download?path=${encodeURIComponent(filePath)}` } }; } catch (error) { console.error('获取文件下载链接失败:', error); return { error: error instanceof Error ? error.message : '获取文件下载链接失败', status: 500 }; } } /** * 更新文档信息 * @param id 文档ID * @param document 部分文档数据 * @returns 更新结果 */ export async function updateDocument(id: string, document: Partial & { remark?: string }): Promise<{ data?: DocumentUI; error?: string; status?: number; }> { try { if (!id) { return { error: '文档ID不能为空', status: 400 }; } // 准备API数据 - 将UI数据转换为API格式 const apiDocument: Partial = {}; 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>( 'documents', apiDocument, { id: parseInt(id) } ); if (response.error) { console.error('更新文档API错误:', response.error); return { error: response.error, status: response.status }; } // 获取更新后的完整文档数据 const updatedResponse = await getDocument(id); return updatedResponse; } catch (error) { console.error('更新文档信息失败:', error); return { error: error instanceof Error ? error.message : '更新文档信息失败', status: 500 }; } }