refactor: switch upload to new POST /api/upload with flat FormData
Replace the old nested upload_info JSON approach with flat
multipart fields (typeId, region, fileRole, createdBy, autoRun,
speed) matching the new leaudit-platform backend.
- uploadDocumentToServer: POST ${API_BASE_URL}/api/upload
- handleFileUpload: pass region from userInfo.area, derive speed
from priority enum, pass createdBy from JWT user_id
- UploadResult replaces FileUploadResponse with documentId/fileId
replacing the old nested result.id/result.file_name pattern
This commit is contained in:
+88
-119
@@ -171,26 +171,47 @@ export interface ContractStructureComparison {
|
||||
comparison_results?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// 文件上传响应接口
|
||||
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<string, string> = {
|
||||
'X-File-Name': encodeURIComponent(fileName)
|
||||
};
|
||||
const headers: Record<string, string> = {
|
||||
"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<DocumentUploadVO> 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<FileUploadResponse>(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 : "上传失败" };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user