新增合同上传附件追加

This commit is contained in:
2025-09-11 17:11:38 +08:00
parent 066e8ba4d9
commit c611d6621d
4 changed files with 364 additions and 17 deletions
+255 -10
View File
@@ -16,6 +16,7 @@ import {
getDocumentsStatus,
uploadFileToBinary,
uploadDocumentToServer,
appendContractAttachments,
type Document,
type DocumentType,
type FileUploadResponse,
@@ -304,6 +305,14 @@ export default function FilesUpload() {
const [isContractType, setIsContractType] = useState<boolean>(false);
const [contractMainFiles, setContractMainFiles] = useState<File[]>([]);
const [contractAttachmentFiles, setContractAttachmentFiles] = useState<File[]>([]);
// 附件追加状态
const [showAttachmentUpload, setShowAttachmentUpload] = useState<boolean>(false);
const [selectedDocumentId, setSelectedDocumentId] = useState<number | null>(null);
const [attachmentFiles, setAttachmentFiles] = useState<File[]>([]);
const [attachmentMergeMode, setAttachmentMergeMode] = useState<'overwrite' | 'new'>('overwrite');
const [attachmentRemark, setAttachmentRemark] = useState<string>("");
const [attachmentUploading, setAttachmentUploading] = useState<boolean>(false);
const [uploadProgress, setUploadProgress] = useState(0);
const [uploadSpeed, setUploadSpeed] = useState("0KB/s");
@@ -768,6 +777,93 @@ export default function FilesUpload() {
console.error('【调试-handleContractAttachmentFilesSelected】处理合同附件选择时发生错误:', error);
}
};
// 处理附件追加文件选择
const handleAttachmentFilesSelected = (files: FileList) => {
try {
console.log('【附件追加】开始处理附件文件选择, 文件数量:', files.length);
if (files.length > 0) {
// 验证文件类型,支持PDF、Word、ZIP、RAR
const validFiles: File[] = [];
let hasInvalidFiles = false;
Array.from(files).forEach(file => {
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') ||
file.type === 'application/zip' || fileName.endsWith('.zip') ||
file.type === 'application/x-rar-compressed' || fileName.endsWith('.rar');
if (isValidType) {
validFiles.push(file);
} else {
hasInvalidFiles = true;
console.error(`【附件追加】无效的文件类型: ${file.name}, 类型: ${file.type}`);
}
});
if (hasInvalidFiles) {
messageService.error('只支持PDF、Word、ZIP、RAR格式的文件', {
title: '文件类型错误',
confirmText: '确定',
cancelText: '',
});
}
if (validFiles.length > 0) {
setAttachmentFiles(validFiles);
console.log('【附件追加】有效文件数量:', validFiles.length);
}
}
} catch (error) {
console.error('【附件追加】处理文件选择时发生错误:', error);
}
};
// 处理附件追加上传
const handleAttachmentUpload = async () => {
if (!selectedDocumentId || attachmentFiles.length === 0) {
toastService.error('请选择文档和附件文件');
return;
}
try {
setAttachmentUploading(true);
const result = await appendContractAttachments(
selectedDocumentId,
attachmentFiles,
attachmentMergeMode,
true, // isReprocess
attachmentRemark || undefined,
loaderData.userInfo?.token
);
if (result.error) {
throw new Error(result.error);
}
toastService.success('附件追加成功!');
// 重置状态
setAttachmentFiles([]);
setAttachmentRemark("");
setShowAttachmentUpload(false);
setSelectedDocumentId(null);
// 刷新文档列表
await filterDocuments(reviewType);
} catch (error) {
console.error('【附件追加】上传失败:', error);
toastService.error(error instanceof Error ? error.message : '附件追加失败');
} finally {
setAttachmentUploading(false);
}
};
// 检查并准备上传
const checkAndPrepareUpload = (mainFiles: File[], attachmentFiles: File[]) => {
@@ -1676,17 +1772,32 @@ export default function FilesUpload() {
{
title: "操作",
key: "operation",
width: "15%",
width: "20%",
render: (_: unknown, record: Document) => (
<Button
type="default"
size="small"
disabled={record.status !== DocumentStatus.PROCESSED}
icon="ri-eye-line"
onClick={() => handleViewFile(record)}
>
</Button>
<div className="flex gap-2">
<Button
type="default"
size="small"
disabled={record.status !== DocumentStatus.PROCESSED}
icon="ri-eye-line"
onClick={() => handleViewFile(record)}
>
</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>
)}
</div>
)
}
];
@@ -2065,6 +2176,140 @@ export default function FilesUpload() {
emptyText="暂无上传文件"
/>
</Card>
{/* 附件追加模态框 */}
{showAttachmentUpload && (
<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-2xl mx-4 max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-semibold"></h3>
<button
onClick={() => {
setShowAttachmentUpload(false);
setSelectedDocumentId(null);
setAttachmentFiles([]);
setAttachmentRemark("");
}}
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">
PDFWordZIPRAR格式ZIP/RAR内仅合并其中的PDF文件
</p>
</div>
{/* 文件上传区域 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<span className="text-red-500">*</span>
</label>
<UploadArea
onFilesSelected={handleAttachmentFilesSelected}
multiple={true}
accept=".pdf,.doc,.docx,.zip,.rar"
tipText="支持PDF、Word、ZIP、RAR格式,可多选"
mainText="选择附件文件"
buttonText="选择文件"
icon="ri-attachment-line"
/>
{attachmentFiles.length > 0 && (
<div className="mt-2">
<p className="text-sm text-green-600 mb-2">
<i className="ri-checkbox-circle-line"></i> {attachmentFiles.length}
</p>
<div className="space-y-1 max-h-32 overflow-y-auto">
{attachmentFiles.map((file, index) => (
<div key={index} className="text-xs text-gray-600 bg-gray-50 p-2 rounded">
<i className="ri-file-line mr-1"></i>
{file.name} ({formatFileSize(file.size)})
</div>
))}
</div>
</div>
)}
</div>
{/* 合并模式选择 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
</label>
<div className="space-y-2">
<label className="flex items-center">
<input
type="radio"
name="mergeMode"
value="overwrite"
checked={attachmentMergeMode === 'overwrite'}
onChange={(e) => setAttachmentMergeMode(e.target.value as 'overwrite' | 'new')}
className="mr-2"
/>
<span className="text-sm"></span>
</label>
<label className="flex items-center">
<input
type="radio"
name="mergeMode"
value="new"
checked={attachmentMergeMode === 'new'}
onChange={(e) => setAttachmentMergeMode(e.target.value as 'overwrite' | 'new')}
className="mr-2"
/>
<span className="text-sm"></span>
</label>
</div>
</div>
{/* 备注 */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
</label>
<textarea
value={attachmentRemark}
onChange={(e) => setAttachmentRemark(e.target.value)}
className="w-full p-2 border border-gray-300 rounded-md text-sm"
rows={3}
placeholder="请输入备注信息..."
/>
</div>
{/* 操作按钮 */}
<div className="flex justify-end gap-3 pt-4 border-t">
<Button
type="default"
onClick={() => {
setShowAttachmentUpload(false);
setSelectedDocumentId(null);
setAttachmentFiles([]);
setAttachmentRemark("");
}}
disabled={attachmentUploading}
>
</Button>
<Button
type="primary"
onClick={handleAttachmentUpload}
disabled={attachmentFiles.length === 0 || attachmentUploading}
icon={attachmentUploading ? "ri-loader-4-line" : "ri-upload-cloud-line"}
>
{attachmentUploading ? '上传中...' : '开始追加'}
</Button>
</div>
</div>
</div>
</div>
)}
</div>
);
}