fix: 1. 继续对齐交叉评查的接口,完善创建交叉评查的逻辑 和 相关组件的渲染布局。
2. 文档的基本信息修改改用接口。 3. 重新完善角色权限管理的页面逻辑。 4.将评查点列表中的返回逻辑改用浏览器的记忆返回。
This commit is contained in:
@@ -179,7 +179,10 @@ export default function CrossCheckingUpload() {
|
||||
type: 'CITY', // 使用枚举值,默认为市局间交叉评查
|
||||
});
|
||||
// 步骤2状态
|
||||
const [groupChecked, setGroupChecked] = useState<string[]>(userInfo?.user_id ? [`user_${userInfo.user_id}`] : []);
|
||||
// 当前用户ID(用于标识主要负责人,不可取消勾选)
|
||||
const currentUserId = userInfo?.user_id ? `user_${userInfo.user_id}` : null;
|
||||
const [groupChecked, setGroupChecked] = useState<string[]>(currentUserId ? [currentUserId] : []);
|
||||
const [leaderIds, setLeaderIds] = useState<string[]>([]); // 额外的负责人ID数组(不包含当前用户)
|
||||
const [userSelectionState, setUserSelectionState] = useState<UserSelectionState>({
|
||||
treeData: DEFAULT_TREE,
|
||||
loading: false,
|
||||
@@ -192,15 +195,12 @@ export default function CrossCheckingUpload() {
|
||||
const [remark] = useState<string>("");
|
||||
const [isTestDocument] = useState<boolean>(false);
|
||||
|
||||
// 文件管理状态
|
||||
const [singleFiles, setSingleFiles] = useState<CrossCheckingUploadedFile[]>([]);
|
||||
const [multipleFiles, setMultipleFiles] = useState<CrossCheckingUploadedFile[]>([]);
|
||||
const [uploadType, setUploadType] = useState<'none' | 'single' | 'multiple'>('none');
|
||||
// 文件管理状态 - 简化为单文件上传
|
||||
const [uploadedFile, setUploadedFile] = useState<CrossCheckingUploadedFile | null>(null);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
// 引用
|
||||
const singleUploadRef = useRef<UploadAreaRef>(null);
|
||||
const multipleUploadRef = useRef<UploadAreaRef>(null);
|
||||
const uploadRef = useRef<UploadAreaRef>(null);
|
||||
|
||||
|
||||
|
||||
@@ -218,147 +218,62 @@ export default function CrossCheckingUpload() {
|
||||
console.log("案卷类型切换为:", selectedType?.name, "ID:", docTypeId);
|
||||
};
|
||||
|
||||
// 清空所有文件
|
||||
// 清空文件
|
||||
const clearAllFiles = () => {
|
||||
setSingleFiles([]);
|
||||
setMultipleFiles([]);
|
||||
setUploadType('none');
|
||||
// 重置文件输入框
|
||||
singleUploadRef.current?.resetFileInput();
|
||||
multipleUploadRef.current?.resetFileInput();
|
||||
setUploadedFile(null);
|
||||
uploadRef.current?.resetFileInput();
|
||||
};
|
||||
|
||||
// 处理单案件文件选择
|
||||
const handleSingleFilesSelected = (files: FileList) => {
|
||||
if (uploadType === 'multiple') {
|
||||
toastService.warning("已选择多案件导入方式,无法选择单案件文件");
|
||||
return;
|
||||
}
|
||||
// 获取文件类型信息
|
||||
const getFileTypeInfo = (file: File) => {
|
||||
const fileName = file.name.toLowerCase();
|
||||
const isPdf = file.type === 'application/pdf' || fileName.endsWith('.pdf');
|
||||
const isDocx = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || fileName.endsWith('.docx');
|
||||
const isZip = file.type === 'application/zip' || file.type === 'application/x-zip-compressed' || fileName.endsWith('.zip');
|
||||
const is7z = file.type === 'application/x-7z-compressed' || fileName.endsWith('.7z');
|
||||
|
||||
const validFiles: CrossCheckingUploadedFile[] = [];
|
||||
let hasInvalidFiles = false;
|
||||
return { isPdf, isDocx, isZip, is7z };
|
||||
};
|
||||
|
||||
Array.from(files).forEach(file => {
|
||||
const isPdf = file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf');
|
||||
const isDocx = file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
|
||||
file.name.toLowerCase().endsWith('.docx');
|
||||
// 处理文件选择(合并单案件和多案件)
|
||||
const handleFileSelected = (files: FileList) => {
|
||||
if (files.length === 0) return;
|
||||
|
||||
if (isPdf || isDocx) {
|
||||
validFiles.push({
|
||||
id: generateFileId(),
|
||||
file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
uploadType: 'single'
|
||||
});
|
||||
} else {
|
||||
hasInvalidFiles = true;
|
||||
}
|
||||
});
|
||||
// 只取第一个文件
|
||||
const file = files[0];
|
||||
const { isPdf, isDocx, isZip, is7z } = getFileTypeInfo(file);
|
||||
|
||||
if (hasInvalidFiles) {
|
||||
messageService.error('只能上传PDF或DOCX格式的文件', {
|
||||
// 验证文件类型
|
||||
if (!isPdf && !isDocx && !isZip && !is7z) {
|
||||
messageService.error('只能上传 PDF、DOCX 文件或 ZIP、7Z 压缩包', {
|
||||
title: '文件类型错误',
|
||||
confirmText: '确定',
|
||||
});
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
setSingleFiles(prev => [...prev, ...validFiles]);
|
||||
setUploadType('single');
|
||||
console.log("选择单案件文件:", validFiles.length, "个");
|
||||
}
|
||||
};
|
||||
|
||||
// 处理多案件文件选择
|
||||
const handleMultipleFilesSelected = (files: FileList) => {
|
||||
if (uploadType === 'single') {
|
||||
toastService.warning("已选择单案件导入方式,无法选择多案件文件");
|
||||
return;
|
||||
}
|
||||
|
||||
const validFiles: CrossCheckingUploadedFile[] = [];
|
||||
let hasInvalidFiles = false;
|
||||
// 确定文件上传类型
|
||||
const uploadType: 'single' | 'multiple' = (isZip || is7z) ? 'multiple' : 'single';
|
||||
|
||||
Array.from(files).forEach(file => {
|
||||
const isZip = file.type === 'application/zip' ||
|
||||
file.type === 'application/x-zip-compressed' ||
|
||||
file.name.toLowerCase().endsWith('.zip');
|
||||
const is7z = file.type === 'application/x-7z-compressed' ||
|
||||
file.name.toLowerCase().endsWith('.7z');
|
||||
|
||||
if (isZip || is7z) {
|
||||
validFiles.push({
|
||||
id: generateFileId(),
|
||||
file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
uploadType: 'multiple'
|
||||
});
|
||||
} else {
|
||||
hasInvalidFiles = true;
|
||||
}
|
||||
setUploadedFile({
|
||||
id: generateFileId(),
|
||||
file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
uploadType
|
||||
});
|
||||
|
||||
if (hasInvalidFiles) {
|
||||
messageService.error('只能上传ZIP或7Z格式的压缩文件', {
|
||||
title: '文件类型错误',
|
||||
confirmText: '确定',
|
||||
});
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
setMultipleFiles(prev => [...prev, ...validFiles]);
|
||||
setUploadType('multiple');
|
||||
console.log("选择多案件文件:", validFiles.length, "个");
|
||||
}
|
||||
console.log("选择文件:", file.name, "类型:", uploadType);
|
||||
};
|
||||
|
||||
// 删除单个文件
|
||||
const handleRemoveFile = (fileId: string, type: 'single' | 'multiple') => {
|
||||
// 删除文件
|
||||
const handleRemoveFile = () => {
|
||||
if (isUploading) {
|
||||
toastService.warning("上传进行中,无法删除文件");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'single') {
|
||||
setSingleFiles(prev => {
|
||||
const newFiles = prev.filter(f => f.id !== fileId);
|
||||
if (newFiles.length === 0) {
|
||||
setUploadType('none');
|
||||
singleUploadRef.current?.resetFileInput();
|
||||
}
|
||||
return newFiles;
|
||||
});
|
||||
} else {
|
||||
setMultipleFiles(prev => {
|
||||
const newFiles = prev.filter(f => f.id !== fileId);
|
||||
if (newFiles.length === 0) {
|
||||
setUploadType('none');
|
||||
multipleUploadRef.current?.resetFileInput();
|
||||
}
|
||||
return newFiles;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 清空文件列表
|
||||
const handleClearFiles = (type: 'single' | 'multiple') => {
|
||||
if (isUploading) {
|
||||
toastService.warning("上传进行中,无法清空文件");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'single') {
|
||||
setSingleFiles([]);
|
||||
singleUploadRef.current?.resetFileInput();
|
||||
} else {
|
||||
setMultipleFiles([]);
|
||||
multipleUploadRef.current?.resetFileInput();
|
||||
}
|
||||
setUploadType('none');
|
||||
clearAllFiles();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -382,11 +297,11 @@ export default function CrossCheckingUpload() {
|
||||
}
|
||||
|
||||
// 验证步骤3:文件上传
|
||||
const filesToUpload = uploadType === 'single' ? singleFiles : multipleFiles;
|
||||
if (filesToUpload.length === 0) {
|
||||
if (!uploadedFile) {
|
||||
toastService.error("请先选择要上传的文件");
|
||||
return;
|
||||
}
|
||||
const filesToUpload = [uploadedFile];
|
||||
|
||||
// 验证选择了案卷类型
|
||||
if (!selectedDocTypeId) {
|
||||
@@ -437,6 +352,20 @@ export default function CrossCheckingUpload() {
|
||||
// console.log("requireParam", requireParam)
|
||||
// return;
|
||||
|
||||
// 构建负责人ID数组:当前用户(主要负责人)+ 额外负责人
|
||||
const principalUserIds: number[] = [];
|
||||
// 添加当前用户作为主要负责人
|
||||
if (currentUserId) {
|
||||
principalUserIds.push(parseInt(currentUserId.replace('user_', '')));
|
||||
}
|
||||
// 添加额外的负责人
|
||||
leaderIds.forEach(id => {
|
||||
const numId = parseInt(id.replace('user_', ''));
|
||||
if (!principalUserIds.includes(numId)) {
|
||||
principalUserIds.push(numId);
|
||||
}
|
||||
});
|
||||
|
||||
// 使用文档类型名称作为 doc_type
|
||||
const uploadResult = await batchUploadAndAssignCrossCheckingFiles(
|
||||
filesToUpload,
|
||||
@@ -449,7 +378,8 @@ export default function CrossCheckingUpload() {
|
||||
taskInfo.name,
|
||||
selectedDocType.code, // 使用文档类型code
|
||||
taskInfo.type, // 使用任务类型(市局间交叉评查 或 区局间交叉评查)
|
||||
frontendJWT
|
||||
frontendJWT,
|
||||
principalUserIds // 负责人ID数组
|
||||
);
|
||||
|
||||
|
||||
@@ -563,7 +493,7 @@ export default function CrossCheckingUpload() {
|
||||
// 小组多选逻辑 - 默认不选择任何项
|
||||
|
||||
// 检查是否可以完成
|
||||
const canComplete = (singleFiles.length > 0 || multipleFiles.length > 0) && !isUploading;
|
||||
const canComplete = uploadedFile !== null && !isUploading;
|
||||
// const navigation = useNavigation();
|
||||
// 由于 isSubmitting 未被使用,暂时移除该行代码
|
||||
|
||||
@@ -738,8 +668,18 @@ export default function CrossCheckingUpload() {
|
||||
placeholder="请选择评查小组成员"
|
||||
value={groupChecked}
|
||||
onChange={(values: string[]) => {
|
||||
setGroupChecked(values);
|
||||
// 确保当前用户始终被选中
|
||||
let newValues = values;
|
||||
if (currentUserId && !values.includes(currentUserId)) {
|
||||
newValues = [currentUserId, ...values];
|
||||
}
|
||||
setGroupChecked(newValues);
|
||||
// 移除已被取消选中的负责人
|
||||
setLeaderIds(prev => prev.filter(id => newValues.includes(id)));
|
||||
}}
|
||||
maxHeight={460}
|
||||
searchable={true}
|
||||
searchPlaceholder="搜索成员..."
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -749,12 +689,20 @@ export default function CrossCheckingUpload() {
|
||||
<div className="p-4">
|
||||
<h4 className="text-sm font-medium text-gray-700 mb-3">已选择的评查小组成员</h4>
|
||||
{groupChecked.length > 0 ? (
|
||||
<div className="space-y-2 max-h-64 overflow-y-auto">
|
||||
{groupChecked.map((member, index) => {
|
||||
<div className="space-y-2 max-h-[460px] overflow-y-auto">
|
||||
{/* 将当前用户排在第一位 */}
|
||||
{[...groupChecked].sort((a, b) => {
|
||||
if (a === currentUserId) return -1;
|
||||
if (b === currentUserId) return 1;
|
||||
return 0;
|
||||
}).map((member, index) => {
|
||||
let displayName: string = member;
|
||||
let displayOrg = '';
|
||||
|
||||
if (member.startsWith('user_')) {
|
||||
const isUser = member.startsWith('user_');
|
||||
const isCurrentUser = member === currentUserId;
|
||||
const isLeader = leaderIds.includes(member);
|
||||
|
||||
if (isUser) {
|
||||
// 查找真实用户名
|
||||
const userName = findUserNameById(userSelectionState.treeData, member) || member.replace('user_', '');
|
||||
displayName = userName;
|
||||
@@ -765,11 +713,59 @@ export default function CrossCheckingUpload() {
|
||||
displayName = parts[parts.length - 1];
|
||||
displayOrg = parts.slice(0, -1).join(' - ') || '组织';
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div key={index} className="bg-white p-2 rounded text-xs border">
|
||||
<div className="font-medium text-gray-800">{displayName}</div>
|
||||
<div className="text-gray-500 mt-1">{displayOrg}</div>
|
||||
<div
|
||||
key={index}
|
||||
className={`bg-white p-2 rounded text-xs border flex items-center justify-between ${
|
||||
isCurrentUser
|
||||
? 'border-amber-400 bg-amber-50'
|
||||
: isLeader
|
||||
? 'border-[var(--color-primary)] bg-[rgba(0,104,74,0.05)]'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
<div className="flex-1">
|
||||
<div className="font-medium text-gray-800 flex items-center gap-2">
|
||||
{displayName}
|
||||
{isCurrentUser && (
|
||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-amber-500 text-white">
|
||||
<i className="ri-user-star-fill mr-0.5"></i>主要负责人
|
||||
</span>
|
||||
)}
|
||||
{!isCurrentUser && isLeader && (
|
||||
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-[var(--color-primary)] text-white">
|
||||
<i className="ri-star-fill mr-0.5"></i>负责人
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-gray-500 mt-1">{displayOrg}</div>
|
||||
</div>
|
||||
{/* 当前用户不能取消选中,也不显示设为负责人按钮 */}
|
||||
{isCurrentUser ? (
|
||||
<span className="ml-2 px-2 py-1 rounded text-[10px] bg-gray-100 text-gray-400 cursor-not-allowed">
|
||||
不可更改
|
||||
</span>
|
||||
) : isUser ? (
|
||||
<button
|
||||
type="button"
|
||||
className={`ml-2 px-2 py-1 rounded text-[10px] transition-colors ${
|
||||
isLeader
|
||||
? 'bg-gray-100 text-gray-500 hover:bg-gray-200'
|
||||
: 'bg-[var(--color-primary-light)] text-[var(--color-primary)] hover:bg-[var(--color-primary)] hover:text-white'
|
||||
}`}
|
||||
onClick={() => {
|
||||
if (isLeader) {
|
||||
setLeaderIds(prev => prev.filter(id => id !== member));
|
||||
} else {
|
||||
setLeaderIds(prev => [...prev, member]);
|
||||
}
|
||||
}}
|
||||
title={isLeader ? '取消负责人' : '设为负责人'}
|
||||
>
|
||||
{isLeader ? '取消负责人' : '设为负责人'}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -781,18 +777,32 @@ export default function CrossCheckingUpload() {
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-4 pt-3 border-t border-gray-200">
|
||||
<div className="text-xs text-gray-500">
|
||||
共选择 {groupChecked.length} 名成员
|
||||
<div className="text-xs text-gray-500 flex flex-col gap-1">
|
||||
<div className="flex items-center justify-between">
|
||||
<span>共选择 {groupChecked.length} 名成员</span>
|
||||
<span className="text-amber-600">
|
||||
<i className="ri-user-star-fill mr-1"></i>
|
||||
主要负责人: 1 人
|
||||
</span>
|
||||
</div>
|
||||
{leaderIds.length > 0 && (
|
||||
<div className="flex items-center justify-end">
|
||||
<span className="text-[var(--color-primary)]">
|
||||
<i className="ri-star-fill mr-1"></i>
|
||||
额外负责人: {leaderIds.length} 人
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* 按钮区域移到卡片内部 */}
|
||||
<div className="flex justify-between items-center mt-6">
|
||||
<Button
|
||||
type="default"
|
||||
<Button
|
||||
type="default"
|
||||
icon="ri-arrow-left-line"
|
||||
onClick={() => {
|
||||
console.log('点击返回列表按钮');
|
||||
@@ -847,132 +857,116 @@ export default function CrossCheckingUpload() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 文件上传区域 */}
|
||||
{/* 文件上传区域 - 左右布局 */}
|
||||
<input type="hidden" name="selectedDocTypeId" value={selectedDocTypeId || ''} />
|
||||
<input type="hidden" name="uploadType" value={uploadType} />
|
||||
|
||||
{/* 上传框区域 */}
|
||||
<div className="upload-section">
|
||||
{/* 单案件导入 */}
|
||||
<div className="upload-item">
|
||||
<div className="upload-item-header">
|
||||
<i className="upload-item-icon ri-file-text-line"></i>
|
||||
<span>单案件导入</span>
|
||||
</div>
|
||||
<div className="flex gap-6">
|
||||
{/* 左侧:上传区域 */}
|
||||
<div className="flex-1">
|
||||
<div className="text-sm font-medium text-gray-700 mb-3">上传文件</div>
|
||||
<UploadArea
|
||||
ref={singleUploadRef}
|
||||
onFilesSelected={handleSingleFilesSelected}
|
||||
ref={uploadRef}
|
||||
onFilesSelected={handleFileSelected}
|
||||
className="custom-upload-area"
|
||||
accept=".pdf,.docx"
|
||||
multiple={true}
|
||||
icon="ri-file-upload-line"
|
||||
buttonText="选择文件"
|
||||
mainText="点击或拖拽文件到此区域上传"
|
||||
tipText={
|
||||
<div className="upload-tip-error">
|
||||
请上传案件相关PDF或DOCX文件
|
||||
</div>
|
||||
}
|
||||
disabled={uploadType === 'multiple' || isUploading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 多案件导入 */}
|
||||
<div className="upload-item">
|
||||
<div className="upload-item-header">
|
||||
<i className="upload-item-icon ri-file-list-line"></i>
|
||||
<span>多案件导入</span>
|
||||
</div>
|
||||
<UploadArea
|
||||
ref={multipleUploadRef}
|
||||
onFilesSelected={handleMultipleFilesSelected}
|
||||
className="custom-upload-area"
|
||||
accept=".zip,.7z"
|
||||
accept=".pdf,.docx,.zip,.7z"
|
||||
multiple={false}
|
||||
icon="ri-folder-zip-line"
|
||||
icon="ri-upload-cloud-2-line"
|
||||
buttonText="选择文件"
|
||||
mainText="点击或拖拽文件到此区域上传"
|
||||
tipText={
|
||||
<div className="upload-tip-error">
|
||||
请上传多个案件作为压缩包zip、7z文件
|
||||
<div className="text-gray-500 text-xs mt-2">
|
||||
<div>支持文件类型:</div>
|
||||
<div className="flex flex-wrap gap-2 mt-1 justify-center">
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded bg-red-50 text-red-600">
|
||||
<i className="ri-file-pdf-line mr-1"></i>PDF
|
||||
</span>
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded bg-blue-50 text-blue-600">
|
||||
<i className="ri-file-word-2-line mr-1"></i>DOCX
|
||||
</span>
|
||||
<span className="inline-flex items-center px-2 py-0.5 rounded bg-orange-50 text-orange-600">
|
||||
<i className="ri-folder-zip-line mr-1"></i>ZIP/7Z
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
disabled={uploadType === 'single' || isUploading}
|
||||
disabled={isUploading || uploadedFile !== null}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 文件预览区域 */}
|
||||
{(singleFiles.length > 0 || multipleFiles.length > 0) && (
|
||||
<div className="mt-6 bg-green-50 border border-green-200 rounded-lg p-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="text-sm font-medium text-gray-700">
|
||||
已选择 {uploadType === 'single' ? singleFiles.length : multipleFiles.length} 个文件
|
||||
</div>
|
||||
<Button
|
||||
type="default"
|
||||
size="small"
|
||||
icon="ri-delete-bin-line"
|
||||
onClick={() => handleClearFiles(uploadType === 'single' ? 'single' : 'multiple')}
|
||||
disabled={isUploading}
|
||||
>
|
||||
清空
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 单案件文件列表 */}
|
||||
{uploadType === 'single' && singleFiles.length > 0 && (
|
||||
<div className="max-h-32 overflow-y-auto space-y-1">
|
||||
{singleFiles.map((file) => {
|
||||
const isDocx = file.name.toLowerCase().endsWith('.docx');
|
||||
const isPdf = file.name.toLowerCase().endsWith('.pdf');
|
||||
return (
|
||||
<div key={file.id} className="flex items-center justify-between bg-white p-2 rounded border">
|
||||
<div className="flex items-center space-x-2 flex-1 min-w-0">
|
||||
{isPdf && <i className="ri-file-pdf-line text-red-500"></i>}
|
||||
{isDocx && <i className="ri-file-word-2-line text-blue-500"></i>}
|
||||
{!isPdf && !isDocx && <i className="ri-file-line text-gray-500"></i>}
|
||||
<span className="text-sm truncate">{file.name}</span>
|
||||
<span className="text-xs text-gray-500">{formatFileSize(file.size)}</span>
|
||||
{/* 右侧:文件信息展示 */}
|
||||
<div className="flex-1">
|
||||
<div className="text-sm font-medium text-gray-700 mb-3">文件信息</div>
|
||||
<div className="border border-gray-200 rounded-lg bg-gray-50 min-h-[200px] p-4">
|
||||
{uploadedFile ? (
|
||||
<div className="h-full flex flex-col">
|
||||
{/* 文件图标和类型 */}
|
||||
<div className="flex items-center justify-center mb-4">
|
||||
{(() => {
|
||||
const fileName = uploadedFile.name.toLowerCase();
|
||||
const isPdf = fileName.endsWith('.pdf');
|
||||
const isDocx = fileName.endsWith('.docx');
|
||||
const isZip = fileName.endsWith('.zip');
|
||||
const is7z = fileName.endsWith('.7z');
|
||||
|
||||
if (isPdf) return <i className="ri-file-pdf-line text-5xl text-red-500"></i>;
|
||||
if (isDocx) return <i className="ri-file-word-2-line text-5xl text-blue-500"></i>;
|
||||
if (isZip || is7z) return <i className="ri-folder-zip-line text-5xl text-orange-500"></i>;
|
||||
return <i className="ri-file-line text-5xl text-gray-500"></i>;
|
||||
})()}
|
||||
</div>
|
||||
|
||||
{/* 文件详情 */}
|
||||
<div className="flex-1 space-y-3">
|
||||
<div className="bg-white rounded-md p-3 border border-gray-200">
|
||||
<div className="text-xs text-gray-500 mb-1">文件名</div>
|
||||
<div className="text-sm font-medium text-gray-800 truncate" title={uploadedFile.name}>
|
||||
{uploadedFile.name}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveFile(file.id, 'single')}
|
||||
className="text-red-500 hover:text-red-700 p-1"
|
||||
disabled={isUploading}
|
||||
>
|
||||
<i className="ri-close-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 多案件文件列表 */}
|
||||
{uploadType === 'multiple' && multipleFiles.length > 0 && (
|
||||
<div className="max-h-32 overflow-y-auto space-y-1">
|
||||
{multipleFiles.map((file) => (
|
||||
<div key={file.id} className="flex items-center justify-between bg-white p-2 rounded border">
|
||||
<div className="flex items-center space-x-2 flex-1 min-w-0">
|
||||
<i className="ri-folder-zip-line text-orange-500"></i>
|
||||
<span className="text-sm truncate">{file.name}</span>
|
||||
<span className="text-xs text-gray-500">{formatFileSize(file.size)}</span>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="bg-white rounded-md p-3 border border-gray-200">
|
||||
<div className="text-xs text-gray-500 mb-1">文件大小</div>
|
||||
<div className="text-sm font-medium text-gray-800">
|
||||
{formatFileSize(uploadedFile.size)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white rounded-md p-3 border border-gray-200">
|
||||
<div className="text-xs text-gray-500 mb-1">导入类型</div>
|
||||
<div className="text-sm font-medium text-gray-800">
|
||||
{uploadedFile.uploadType === 'single' ? (
|
||||
<span className="text-blue-600">单案件导入</span>
|
||||
) : (
|
||||
<span className="text-orange-600">多案件导入</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 删除按钮 */}
|
||||
<div className="mt-4 pt-3 border-t border-gray-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveFile(file.id, 'multiple')}
|
||||
className="text-red-500 hover:text-red-700 p-1"
|
||||
onClick={handleRemoveFile}
|
||||
disabled={isUploading}
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-2 text-sm text-red-600 bg-red-50 hover:bg-red-100 rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<i className="ri-close-line"></i>
|
||||
<i className="ri-delete-bin-line"></i>
|
||||
删除文件
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-full flex flex-col items-center justify-center text-gray-400">
|
||||
<i className="ri-file-line text-4xl mb-2"></i>
|
||||
<span className="text-sm">暂未选择文件</span>
|
||||
<span className="text-xs mt-1">请在左侧上传区域选择文件</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 完成按钮 */}
|
||||
<div className="flex justify-between items-center mt-8">
|
||||
@@ -1001,7 +995,7 @@ export default function CrossCheckingUpload() {
|
||||
{/* 文件选择状态提示 */}
|
||||
{!canComplete && !isUploading && (
|
||||
<div className="text-center mt-4 text-gray-500 text-sm">
|
||||
请至少选择一种导入方式的文件
|
||||
请选择要上传的文件
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1016,9 +1010,9 @@ export default function CrossCheckingUpload() {
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-blue-700">
|
||||
{isCreatingTask
|
||||
? `正在创建交叉评查任务:${taskInfo.name}`
|
||||
: `正在上传 ${uploadType === 'single' ? singleFiles.length : multipleFiles.length} 个文件,请稍候`
|
||||
{isCreatingTask
|
||||
? `正在创建交叉评查任务:${taskInfo.name}`
|
||||
: `正在上传文件 ${uploadedFile?.name},请稍候`
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user