diff --git a/app/api/files/files-upload.ts b/app/api/files/files-upload.ts index 9ee3879..1e8a7a8 100644 --- a/app/api/files/files-upload.ts +++ b/app/api/files/files-upload.ts @@ -171,26 +171,47 @@ export interface ContractStructureComparison { comparison_results?: Record; } -// 文件上传响应接口 -export interface FileUploadResponse { +// 文件上传响应接口(兼容旧前端) +export interface UploadResult { success: boolean; - result?: { - id: number; - file_name: string; - file_size: number; - file_url: string; - type_id: number; - type_description: string; - document_number: string | null; - storage_type: string; - is_test_document: boolean; - remark: string | null; - background_processing: boolean; - evaluation_level: string; - }; + documentId: number; + fileId: number; + fileName: string; + fileSize: number; + typeId: number; + region: string; + processingStatus: string; + duplicateUpload: boolean; + error?: string; +} + +// 旧接口上传响应(uploadContractTemplate / appendContractAttachments 仍在使用) +interface LegacyUploadResponse { + success: boolean; + result?: { id: number; file_name: string; file_size: number; [key: string]: unknown }; error: string | null; } +// 新后端上传响应 +interface NewUploadResponse { + documentId: number; + internalDocumentNo: number; + versionGroupKey: string; + versionNo: number; + previousVersionId: number | null; + rootVersionId: number; + duplicateUpload: boolean; + fileId: number; + typeId: number; + typeCode: string; + region: string; + fileName: string; + ossUrl: string; + speed: string; + processingStatus: string; + autoRunTriggered: boolean; +} + /** * 将文件转换为二进制数据 */ @@ -237,7 +258,7 @@ export async function uploadContractTemplate( documentId: number, comparisonId?: number, jwtToken?: string -): Promise<{data: FileUploadResponse; error?: never} | {data?: never; error: string; status?: number}> { +): Promise<{data: LegacyUploadResponse; error?: never} | {data?: never; error: string; status?: number}> { try { console.log('【合同模板上传】开始上传模板:', { fileName: file.name, documentId, comparisonId }); @@ -313,7 +334,7 @@ export async function appendContractAttachments( isReprocess: boolean = true, remark?: string, token?: string -): Promise<{data: FileUploadResponse; error?: never} | {data?: never; error: string; status?: number}> { +): Promise<{data: LegacyUploadResponse; error?: never} | {data?: never; error: string; status?: number}> { try { console.log('【合同附件追加】开始追加附件:', { documentId, fileCount: files.length, mergeMode }); @@ -375,119 +396,67 @@ export async function uploadDocumentToServer( binaryData: ArrayBuffer, fileName: string, fileType: string, - typeId: string | number, - priority: string, - documentNumber?: string | null, - remark?: string | null, - isTestDocument: boolean = false, - documentId?: number | null, - isReupload: boolean = false, + typeId: number, + region: string = "default", + createdBy?: number, + autoRun: boolean = true, + speed: string = "normal", jwtToken?: string, - attachments?: File[], - attributeType?: string -): Promise<{data: FileUploadResponse; error?: never} | {data?: never; error: string; status?: number}> { +): Promise<{ data: UploadResult } | { error: string; status?: number }> { try { - // console.log('【调试】开始上传文档:', { fileName, fileSize: binaryData.byteLength }); - - // 创建FormData对象 const formData = new FormData(); - - // 将二进制数据转换为Blob并添加到FormData const blob = new Blob([binaryData], { type: fileType }); - formData.append('file', blob, fileName); - // console.log('【调试】Blob已创建,文件大小:', blob.size); - - // 将信息添加到一个JSON对象中 - const uploadInfo = { - type_id: Number(typeId), - evaluation_level: priority, - document_number: documentNumber || null, - remark: remark || null, - is_test_document: isTestDocument, - document_id: documentId || null, - is_reupload: isReupload, - attribute_type: attributeType || null - }; - - // 添加JSON字符串到FormData - formData.append('upload_info', JSON.stringify(uploadInfo)); - // console.log('【调试】FormData准备完成:', JSON.stringify(uploadInfo)); - - // 如果提供了附件(仅当后端支持首传合并时使用),按照后端规范追加到 FormData - if (attachments && attachments.length > 0) { - attachments.forEach(att => { - formData.append('attachments', att); - }); + formData.append("file", blob, fileName); + formData.append("typeId", String(typeId)); + formData.append("region", region); + formData.append("fileRole", "primary"); + if (createdBy !== undefined) { + formData.append("createdBy", String(createdBy)); } - - // 根据是否有documentId决定使用哪个接口 - // 首传合并:无论是否有附件,都应走 /upload; - // 仅当要上传“合同模板”时,使用独立的 uploadContractTemplate 接口(不在本函数中处理)。 - const uploadEndpoint = '/upload'; - const uploadUrl = UPLOAD_URL + uploadEndpoint; - // console.log('【调试】准备发送请求到服务器:', uploadUrl); - - // 发送请求 - // const response = await axios.post(`${API_BASE_URL}/admin/documents/upload`, ... - try { - // console.log('【调试】开始axios请求...'); + formData.append("autoRun", String(autoRun)); + formData.append("speed", speed); - // 构建请求头,只在有JWT token时添加Authorization - const headers: Record = { - 'X-File-Name': encodeURIComponent(fileName) - }; + const headers: Record = { + "X-File-Name": encodeURIComponent(fileName), + }; + if (jwtToken) { + headers["Authorization"] = `Bearer ${jwtToken}`; + } - if (jwtToken) { - headers['Authorization'] = `Bearer ${jwtToken}`; - } + const response = await axios.post(`${API_BASE_URL}/api/upload`, formData, { headers }); + const body = response.data; - const response = await axios.post(uploadUrl, formData, { - headers - }); + // Result envelope + const uploadData: NewUploadResponse | undefined = body?.data; + if (!uploadData || !uploadData.documentId) { + return { error: body?.message || "上传响应解析失败", status: response.status }; + } - // console.log('【调试】收到服务器响应:', { status: response.status, statusText: response.statusText }); - - const responseData = response.data; - // console.log('【上传调试】服务器原始JSON响应:', responseData); - // console.log('【上传调试】响应类型:', typeof responseData); - // console.log('【上传调试】响应keys:', Object.keys(responseData)); - - const extractedData = extractApiData(responseData); - // console.log('【上传调试】提取后的数据:', extractedData); - // console.log('【上传调试】提取数据详情:', { - // hasData: !!extractedData, - // success: extractedData?.success, - // hasResult: !!extractedData?.result, - // error: extractedData?.error - // }); - - if (!extractedData) { - console.error('【调试】无法提取数据,原始响应:', JSON.stringify(responseData)); - return { error: '处理上传响应失败', status: 500 }; - } - - // console.log('【调试】上传成功,返回数据'); - return { data: extractedData }; - } catch (axiosError) { - console.error('【调试】axios请求失败:', axiosError); - if (axios.isAxiosError(axiosError)) { - const errorText = axiosError.response?.data || axiosError.message; - return { - error: `上传失败: ${axiosError.response?.status || 500} ${axiosError.response?.statusText || ''} - ${errorText}`, - status: axiosError.response?.status || 500 - }; - } + return { + data: { + success: true, + documentId: uploadData.documentId, + fileId: uploadData.fileId, + fileName: uploadData.fileName, + fileSize: binaryData.byteLength, + typeId: uploadData.typeId, + region: uploadData.region, + processingStatus: uploadData.processingStatus, + duplicateUpload: uploadData.duplicateUpload, + }, + }; + } catch (axiosError) { + console.error("上传文档失败:", axiosError); + if (axios.isAxiosError(axiosError)) { + const serverMessage = + (axiosError.response?.data as any)?.message || + (axiosError.response?.data as any)?.msg; return { - error: `axios请求错误: ${axiosError instanceof Error ? axiosError.message : '未知错误'}`, - status: 500 + error: serverMessage || `上传失败 (HTTP ${axiosError.response?.status || "unknown"})`, + status: axiosError.response?.status, }; } - } catch (error) { - console.error('【调试】上传过程中发生错误:', error); - return { - error: error instanceof Error ? error.message : '上传失败', - status: 500 - }; + return { error: axiosError instanceof Error ? axiosError.message : "上传失败" }; } } diff --git a/app/routes/files.upload.tsx b/app/routes/files.upload.tsx index a9c3383..f62f25f 100644 --- a/app/routes/files.upload.tsx +++ b/app/routes/files.upload.tsx @@ -21,7 +21,7 @@ import { checkDocumentDuplicate, type Document, type DocumentType, - type FileUploadResponse, + type UploadResult, DocumentStatus } from "~/api/files/files-upload"; import { updateDocumentAuditStatus } from "~/api/evaluation_points/rules-files"; @@ -126,52 +126,30 @@ async function handleFileUpload( fileType: string, documentType: FileType, priority: Priority, - documentNumber: string | null, - remark: string | null, - isTestDocument: boolean, - documentId?: number | null, - isReupload: boolean = false, + region: string, + createdBy?: number, jwtToken?: string, - attachments?: File[], - attributeType?: string -): Promise { - // console.log('【handleFileUpload】开始上传:', { - // fileName, - // fileSize: binaryData.byteLength, - // documentType, - // hasAttachments: !!(attachments && attachments.length > 0), - // attachmentCount: attachments?.length || 0 - // }); +): Promise { + const speed = priority === Priority.NORMAL ? "normal" : "urgent"; const response = await uploadDocumentToServer( binaryData, fileName, fileType, - documentType, - priority, - documentNumber, - remark, - isTestDocument, - documentId, - isReupload, + Number(documentType), + region, + createdBy, + true, + speed, jwtToken, - attachments, - attributeType ); - // console.log('【handleFileUpload】uploadDocumentToServer返回:', { - // hasError: !!response.error, - // hasData: !!response.data, - // error: response.error, - // dataKeys: response.data ? Object.keys(response.data) : [] - // }); - - if (response.error || !response.data) { - console.error('【handleFileUpload】上传失败:', response.error); - throw new Error(response.error || '上传失败'); + if ("error" in response || !response.data) { + const errMsg = "error" in response ? response.error : "上传响应为空"; + console.error("上传失败:", errMsg); + throw new Error(errMsg || "上传失败"); } - // console.log('【handleFileUpload】返回数据:', response.data); return response.data; } @@ -1184,39 +1162,20 @@ export default function FilesUpload() { // 转二进制 const binaryData = await uploadFileToBinary(mainFile); - // 首传:将附件通过 attachments 一起带上 + // 首传 + const region = (loaderData.userInfo?.area as string) || "default"; + const createdBy = loaderData.userInfo?.user_id as number | undefined; const uploadResp = await handleFileUpload( - binaryData, - mainFile.name, - mainFile.type, - fileType as FileType, - priority, - documentNumber || null, - remark || null, - isTestDocument, - null, - false, - loaderData.frontendJWT || undefined, - attachmentFiles, - attributeType + binaryData, mainFile.name, mainFile.type, + fileType as FileType, priority, + region, createdBy, loaderData.frontendJWT || undefined, ); - // console.log('【合同上传】服务器响应数据:', uploadResp); - // console.log('【合同上传】响应详情:', { - // success: uploadResp.success, - // hasResult: !!uploadResp.result, - // error: uploadResp.error, - // fullResponse: JSON.stringify(uploadResp) - // }); - if (!uploadResp.success) { - throw new Error(uploadResp.error || '上传失败,服务器返回success=false'); + throw new Error(uploadResp.error || "上传失败"); } - if (!uploadResp.result) { - throw new Error('主文件上传失败:服务器未返回文档信息'); - } - const documentId = uploadResp.result.id; + const documentId = uploadResp.documentId; // 可选:模板上传 if (templateFiles && templateFiles.length > 0) { @@ -1240,14 +1199,13 @@ export default function FilesUpload() { setUploadProgress(100); setUploadSpeed('完成'); - toastService.success('上传成功'); + toastService.success("上传成功"); - // 构造已上传文件并进入处理流程(保持与旧逻辑一致,点亮步骤条) const uploadedFiles: UploadedFile[] = [ { - id: uploadResp.result.id, - name: uploadResp.result.file_name, - size: uploadResp.result.file_size, + id: uploadResp.documentId, + name: uploadResp.fileName, + size: uploadResp.fileSize, type: mainFile.type, fileType: fileType as FileType, priority, @@ -1499,15 +1457,10 @@ export default function FilesUpload() { throw new Error(`文件 ${file.name} 转换失败: ${binaryError instanceof Error ? binaryError.message : '未知错误'}`); } - let response: FileUploadResponse; - // console.log(`【调试-startUpload】开始上传文件 ${file.name} 到服务器,文件类型: ${fileType}`); - + let response: UploadResult; try { - // 上传文件 - // 检查组件是否已卸载 if (!isMountedRef.current) { - console.error('【调试-startUpload】组件已卸载,取消上传'); - return { success: false, error: '组件已卸载' } as FileUploadResponse; + return { success: false, error: "组件已卸载", documentId: 0, fileId: 0, fileName: "", fileSize: 0, typeId: 0, region: "", processingStatus: "", duplicateUpload: false } as UploadResult; } // console.log(`【调试-startUpload】准备上传文件 ${file.name} 到服务器`); @@ -1544,26 +1497,18 @@ export default function FilesUpload() { }); // 使用Promise.race添加超时处理 + const region = (loaderData.userInfo?.area as string) || "default"; + const createdBy = loaderData.userInfo?.user_id as number | undefined; const uploadPromise = handleFileUpload( - binaryData, - file.name, - file.type, - fileType as FileType, - priority, - documentNumber || null, - remark || null, - isTestDocument, - temp_n > 1 ? firstFileDocumentId : null, // 第二个文件及以后使用第一个文件的document_id - false, - loaderData.frontendJWT || undefined, - undefined, - attributeType + binaryData, file.name, file.type, + fileType as FileType, priority, + region, createdBy, loaderData.frontendJWT || undefined, ); - - const timeoutPromise = new Promise((_, reject) => { + + const timeoutPromise = new Promise((_, reject) => { setTimeout(() => { - reject(new Error('上传超时')); - }, 600000); // 10分钟超时 + reject(new Error("上传超时")); + }, 600000); }); // 并行执行上传和进度更新 @@ -1584,16 +1529,15 @@ export default function FilesUpload() { } // 检查上传结果 - if (!uploadResult.success || !uploadResult.result) { - throw new Error(uploadResult.error || '上传失败'); + if (!uploadResult.success) { + throw new Error(uploadResult.error || "上传失败"); } - + response = uploadResult; - - // 保存第一个文件的document_id,用于后续附件上传 - if (temp_n === 1 && response.result?.id) { - firstFileDocumentId = response.result.id; - console.log('【调试-startUpload】保存第一个文件的document_id:', firstFileDocumentId); + + // 保存第一个文件的 documentId + if (temp_n === 1 && response.documentId) { + firstFileDocumentId = response.documentId; } // console.log(`【调试-startUpload】文件 ${file.name} 上传响应:`, response); @@ -1608,19 +1552,17 @@ export default function FilesUpload() { throw new Error(`文件 ${file.name} 上传失败: ${error instanceof Error ? error.message : '未知错误'}`); } - if (!response.success || !response.result) { - console.error(`【调试-startUpload】文件 ${file.name} 上传失败:`, response.error); + if (!response.success) { + console.error(`上传文件 ${file.name} 失败:`, response.error); throw new Error(response.error || `文件 ${file.name} 上传失败`); } - - // 更新已上传大小 + uploadedSize += file.size; - - // 创建新的文件对象 + const newFile: UploadedFile = { - id: response.result.id, - name: response.result.file_name, - size: response.result.file_size, + id: response.documentId, + name: response.fileName, + size: response.fileSize, type: file.type, fileType: fileType as FileType, priority,