新增合同模板上传功能,支持选择PDF和Word格式文件,并实现上传逻辑及状态管理。
This commit is contained in:
@@ -136,6 +136,85 @@ export async function uploadFileToBinary(file: File): Promise<ArrayBuffer> {
|
||||
* @param jwtToken JWT token
|
||||
* @returns 上传结果
|
||||
*/
|
||||
/**
|
||||
* 上传合同模板(用于与合同文档结构对比)
|
||||
* @param file 模板文件
|
||||
* @param documentId 源合同文档ID
|
||||
* @param comparisonId 已有对比记录ID(可选)
|
||||
* @param jwtToken JWT token
|
||||
* @returns 上传结果
|
||||
*/
|
||||
export async function uploadContractTemplate(
|
||||
file: File,
|
||||
documentId: number,
|
||||
comparisonId?: number,
|
||||
jwtToken?: string
|
||||
): Promise<{data: FileUploadResponse; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
console.log('【合同模板上传】开始上传模板:', { fileName: file.name, documentId, comparisonId });
|
||||
|
||||
// 创建FormData对象
|
||||
const formData = new FormData();
|
||||
|
||||
// 添加文件
|
||||
formData.append('file', file);
|
||||
|
||||
// 添加上传信息
|
||||
const uploadInfo = {
|
||||
document_id: documentId,
|
||||
...(comparisonId && { comparison_id: comparisonId })
|
||||
};
|
||||
|
||||
formData.append('upload_info', JSON.stringify(uploadInfo));
|
||||
|
||||
// 构建请求URL
|
||||
const uploadUrl = `${UPLOAD_URL}/upload_contract_template`;
|
||||
console.log('【合同模板上传】准备发送请求到服务器:', uploadUrl);
|
||||
|
||||
// 设置请求头
|
||||
const headers: HeadersInit = {
|
||||
'Accept': 'application/json'
|
||||
};
|
||||
|
||||
if (jwtToken) {
|
||||
headers['Authorization'] = `Bearer ${jwtToken}`;
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: formData
|
||||
});
|
||||
|
||||
console.log('【合同模板上传】服务器响应状态:', response.status);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error('【合同模板上传】服务器返回错误:', errorText);
|
||||
return {
|
||||
error: `服务器错误: ${response.status} ${response.statusText}`,
|
||||
status: response.status
|
||||
};
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('【合同模板上传】服务器返回结果:', result);
|
||||
|
||||
if (result.success) {
|
||||
return { data: result.result };
|
||||
} else {
|
||||
return { error: result.error || '合同模板上传失败' };
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('【合同模板上传】上传过程中发生错误:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : '合同模板上传过程中发生未知错误'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同文档追加附件并合并
|
||||
* @param documentId 合同文档ID
|
||||
|
||||
+182
-11
@@ -17,6 +17,7 @@ import {
|
||||
uploadFileToBinary,
|
||||
uploadDocumentToServer,
|
||||
appendContractAttachments,
|
||||
uploadContractTemplate,
|
||||
type Document,
|
||||
type DocumentType,
|
||||
type FileUploadResponse,
|
||||
@@ -313,6 +314,11 @@ export default function FilesUpload() {
|
||||
const [attachmentMergeMode, setAttachmentMergeMode] = useState<'overwrite' | 'new'>('overwrite');
|
||||
const [attachmentRemark, setAttachmentRemark] = useState<string>("");
|
||||
const [attachmentUploading, setAttachmentUploading] = useState<boolean>(false);
|
||||
|
||||
// 合同模板上传状态
|
||||
const [showTemplateUpload, setShowTemplateUpload] = useState<boolean>(false);
|
||||
const [templateFile, setTemplateFile] = useState<File | null>(null);
|
||||
const [templateUploading, setTemplateUploading] = useState<boolean>(false);
|
||||
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const [uploadSpeed, setUploadSpeed] = useState("0KB/s");
|
||||
@@ -864,6 +870,75 @@ export default function FilesUpload() {
|
||||
setAttachmentUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理合同模板文件选择
|
||||
const handleTemplateFileSelected = (files: FileList) => {
|
||||
try {
|
||||
console.log('【合同模板上传】开始处理模板文件选择, 文件数量:', files.length);
|
||||
|
||||
if (files.length > 0) {
|
||||
const file = files[0];
|
||||
// 验证文件类型,支持PDF和Word
|
||||
const fileName = file.name.toLowerCase();
|
||||
const isValidType =
|
||||
file.type === 'application/pdf' || fileName.endsWith('.pdf') ||
|
||||
file.type === 'application/msword' || fileName.endsWith('.doc') ||
|
||||
file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || fileName.endsWith('.docx');
|
||||
|
||||
if (isValidType) {
|
||||
setTemplateFile(file);
|
||||
console.log('【合同模板上传】有效文件:', file.name);
|
||||
} else {
|
||||
messageService.error('只支持PDF、Word格式的文件', {
|
||||
title: '文件类型错误',
|
||||
confirmText: '确定',
|
||||
cancelText: '',
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('【合同模板上传】处理文件选择时发生错误:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理合同模板上传
|
||||
const handleTemplateUpload = async () => {
|
||||
if (!selectedDocumentId || !templateFile) {
|
||||
toastService.error('请选择文档和模板文件');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setTemplateUploading(true);
|
||||
|
||||
const result = await uploadContractTemplate(
|
||||
templateFile,
|
||||
selectedDocumentId,
|
||||
undefined, // comparisonId
|
||||
loaderData.userInfo?.token
|
||||
);
|
||||
|
||||
if (result.error) {
|
||||
throw new Error(result.error);
|
||||
}
|
||||
|
||||
toastService.success('合同模板上传成功!');
|
||||
|
||||
// 重置状态
|
||||
setTemplateFile(null);
|
||||
setShowTemplateUpload(false);
|
||||
setSelectedDocumentId(null);
|
||||
|
||||
// 刷新文档列表
|
||||
await filterDocuments(reviewType);
|
||||
|
||||
} catch (error) {
|
||||
console.error('【合同模板上传】上传失败:', error);
|
||||
toastService.error(error instanceof Error ? error.message : '合同模板上传失败');
|
||||
} finally {
|
||||
setTemplateUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 检查并准备上传
|
||||
const checkAndPrepareUpload = (mainFiles: File[], attachmentFiles: File[]) => {
|
||||
@@ -1785,17 +1860,30 @@ export default function FilesUpload() {
|
||||
查看
|
||||
</Button>
|
||||
{record.type_id === 1 && record.status === DocumentStatus.PROCESSED && (
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="ri-attachment-line"
|
||||
onClick={() => {
|
||||
setSelectedDocumentId(record.id);
|
||||
setShowAttachmentUpload(true);
|
||||
}}
|
||||
>
|
||||
追加附件
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="ri-attachment-line"
|
||||
onClick={() => {
|
||||
setSelectedDocumentId(record.id);
|
||||
setShowAttachmentUpload(true);
|
||||
}}
|
||||
>
|
||||
追加附件
|
||||
</Button>
|
||||
<Button
|
||||
type="default"
|
||||
size="small"
|
||||
icon="ri-file-copy-line"
|
||||
onClick={() => {
|
||||
setSelectedDocumentId(record.id);
|
||||
setShowTemplateUpload(true);
|
||||
}}
|
||||
>
|
||||
上传模板
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
@@ -2310,6 +2398,89 @@ export default function FilesUpload() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 合同模板上传模态框 */}
|
||||
{showTemplateUpload && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg p-6 w-full max-w-lg mx-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-lg font-semibold">上传合同模板</h3>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowTemplateUpload(false);
|
||||
setSelectedDocumentId(null);
|
||||
setTemplateFile(null);
|
||||
}}
|
||||
className="text-gray-400 hover:text-gray-600"
|
||||
>
|
||||
<i className="ri-close-line text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* 文档信息 */}
|
||||
<div className="bg-gray-50 p-3 rounded">
|
||||
<p className="text-sm text-gray-600">
|
||||
目标文档ID: <span className="font-medium">{selectedDocumentId}</span>
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
支持PDF、Word格式,用于与合同文档进行结构对比
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 文件上传区域 */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
选择模板文件 <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<UploadArea
|
||||
onFilesSelected={handleTemplateFileSelected}
|
||||
multiple={false}
|
||||
accept=".pdf,.doc,.docx"
|
||||
tipText="支持PDF、Word格式"
|
||||
mainText="选择模板文件"
|
||||
buttonText="选择文件"
|
||||
icon="ri-file-copy-line"
|
||||
/>
|
||||
{templateFile && (
|
||||
<div className="mt-2">
|
||||
<p className="text-sm text-green-600 mb-2">
|
||||
<i className="ri-checkbox-circle-line"></i> 已选择模板文件
|
||||
</p>
|
||||
<div className="text-xs text-gray-600 bg-gray-50 p-2 rounded">
|
||||
<i className="ri-file-line mr-1"></i>
|
||||
{templateFile.name} ({formatFileSize(templateFile.size)})
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<div className="flex justify-end gap-3 pt-4 border-t">
|
||||
<Button
|
||||
type="default"
|
||||
onClick={() => {
|
||||
setShowTemplateUpload(false);
|
||||
setSelectedDocumentId(null);
|
||||
setTemplateFile(null);
|
||||
}}
|
||||
disabled={templateUploading}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={handleTemplateUpload}
|
||||
disabled={!templateFile || templateUploading}
|
||||
icon={templateUploading ? "ri-loader-4-line" : "ri-upload-cloud-line"}
|
||||
>
|
||||
{templateUploading ? '上传中...' : '开始上传'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user