添加合同和卷宗数据隔离
This commit is contained in:
+176
-73
@@ -71,6 +71,7 @@ export const PRIORITY_LABELS: Record<Priority, string> = {
|
||||
};
|
||||
|
||||
// 优先级中文映射
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const PRIORITY_TO_CHINESE: Record<Priority, string> = {
|
||||
[Priority.NORMAL]: "普通",
|
||||
[Priority.HIGH]: "优先",
|
||||
@@ -109,60 +110,74 @@ export interface UploadedFile {
|
||||
};
|
||||
}
|
||||
|
||||
// 模拟上传文件到服务器的API
|
||||
async function uploadFileToServer(
|
||||
binaryData: ArrayBuffer,
|
||||
fileName: string,
|
||||
fileType: string,
|
||||
documentType: FileType,
|
||||
// 修改文件上传函数部分,解决类型问题
|
||||
async function handleFileUpload(
|
||||
binaryData: ArrayBuffer,
|
||||
fileName: string,
|
||||
fileType: string,
|
||||
documentType: FileType,
|
||||
priority: Priority,
|
||||
documentNumber: string | null,
|
||||
remark: string | null,
|
||||
isTestDocument: boolean
|
||||
): Promise<FileUploadResponse> {
|
||||
// 在实际应用中,这里会使用fetch或axios发送请求到后端API
|
||||
// console.log(`[API] 上传文件: ${fileName}, 大小: ${binaryData.byteLength} 字节`);
|
||||
// try {
|
||||
// // 使用封装的上传函数
|
||||
// const response = await uploadDocumentToServer(
|
||||
// binaryData,
|
||||
// fileName,
|
||||
// fileType,
|
||||
// documentType,
|
||||
// PRIORITY_TO_CHINESE[priority],
|
||||
// documentNumber,
|
||||
// remark,
|
||||
// isTestDocument
|
||||
// );
|
||||
|
||||
// if (response.error) {
|
||||
// console.error('[API] 上传错误:', response.error);
|
||||
// return {
|
||||
// success: false,
|
||||
// error: response.error
|
||||
// };
|
||||
// }
|
||||
|
||||
// // 确保返回有效的FileUploadResponse对象
|
||||
// // console.log('上传成功:', response.data);
|
||||
// if (response.data) {
|
||||
// return response.data;
|
||||
// }
|
||||
|
||||
// // 如果没有数据,则返回错误
|
||||
// // console.log('上传失败:', response.error);
|
||||
// return {
|
||||
// success: false,
|
||||
// error: '上传失败,未获取到响应数据'
|
||||
// };
|
||||
// } catch (error) {
|
||||
// console.error('[API] 上传错误:', error);
|
||||
// return {
|
||||
// success: false,
|
||||
// error: error instanceof Error ? error.message : '上传失败'
|
||||
// };
|
||||
// }
|
||||
|
||||
try {
|
||||
// 使用封装的上传函数
|
||||
const response = await uploadDocumentToServer(
|
||||
binaryData,
|
||||
fileName,
|
||||
fileType,
|
||||
documentType,
|
||||
PRIORITY_TO_CHINESE[priority],
|
||||
documentNumber,
|
||||
remark,
|
||||
isTestDocument
|
||||
);
|
||||
|
||||
if (response.error) {
|
||||
console.error('[API] 上传错误:', response.error);
|
||||
return {
|
||||
success: false,
|
||||
error: response.error
|
||||
};
|
||||
}
|
||||
|
||||
// 确保返回有效的FileUploadResponse对象
|
||||
// console.log('上传成功:', response.data);
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 如果没有数据,则返回错误
|
||||
// console.log('上传失败:', response.error);
|
||||
return {
|
||||
success: false,
|
||||
error: '上传失败,未获取到响应数据'
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[API] 上传错误:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : '上传失败'
|
||||
};
|
||||
const response = await uploadDocumentToServer(
|
||||
binaryData,
|
||||
fileName,
|
||||
fileType,
|
||||
documentType,
|
||||
priority,
|
||||
documentNumber,
|
||||
remark,
|
||||
isTestDocument
|
||||
);
|
||||
|
||||
if (response.error || !response.data) {
|
||||
throw new Error(response.error || '上传失败');
|
||||
}
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// 定义action返回数据的类型
|
||||
@@ -242,6 +257,8 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
// console.log('loader: 开始加载数据...');
|
||||
const url = new URL(request.url);
|
||||
const mode = url.searchParams.get("mode") || "create";
|
||||
|
||||
// 我们不能在服务器端访问 sessionStorage,所以在客户端组件中处理 reviewType 过滤
|
||||
// 并行加载文档和文档类型
|
||||
const [documentsResponse, typesResponse] = await Promise.all([
|
||||
getTodayDocuments(),
|
||||
@@ -271,8 +288,12 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
|
||||
// 文件上传页面组件
|
||||
export default function FilesUpload() {
|
||||
// 获取 sessionStorage 中的 reviewType 值
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [reviewType, setReviewType] = useState<string | null>(null);
|
||||
|
||||
// 使用 useLoaderData 获取初始数据
|
||||
const { documents, documentTypes } = useLoaderData<LoaderData>();
|
||||
const loaderData = useLoaderData<LoaderData>();
|
||||
|
||||
// 状态管理
|
||||
// 高级上传设置
|
||||
@@ -285,9 +306,10 @@ export default function FilesUpload() {
|
||||
const [currentFiles, setCurrentFiles] = useState<File[]>([]);
|
||||
|
||||
// 合同文件上传状态
|
||||
const [isContractType, setIsContractType] = useState<boolean>(false);
|
||||
const [contractMainFiles, setContractMainFiles] = useState<File[]>([]);
|
||||
const [contractAttachmentFiles, setContractAttachmentFiles] = useState<File[]>([]);
|
||||
// 这些变量暂时未使用,但保留以备将来扩展
|
||||
// const [isContractType, setIsContractType] = useState<boolean>(false);
|
||||
// const [contractMainFiles, setContractMainFiles] = useState<File[]>([]);
|
||||
// const [contractAttachmentFiles, setContractAttachmentFiles] = useState<File[]>([]);
|
||||
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const [uploadSpeed, setUploadSpeed] = useState("0KB/s");
|
||||
@@ -302,8 +324,76 @@ export default function FilesUpload() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 队列文件状态
|
||||
const [queueFiles, setQueueFiles] = useState<Document[]>(documents);
|
||||
const [documentTypesState] = useState<DocumentType[]>(documentTypes);
|
||||
const [queueFiles, setQueueFiles] = useState<Document[]>([]);
|
||||
const [documentTypesState, setDocumentTypesState] = useState<DocumentType[]>([]);
|
||||
|
||||
// 在组件挂载时从 sessionStorage 获取 reviewType
|
||||
useEffect(() => {
|
||||
try {
|
||||
// 在客户端环境中执行
|
||||
if (typeof window !== 'undefined') {
|
||||
const storedReviewType = sessionStorage.getItem('reviewType');
|
||||
setReviewType(storedReviewType);
|
||||
|
||||
// 根据 reviewType 过滤文档类型和文档列表
|
||||
filterDocumentTypes(storedReviewType, loaderData.documentTypes);
|
||||
filterDocuments(storedReviewType);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取 sessionStorage 中的 reviewType 失败:', error);
|
||||
}
|
||||
}, [loaderData]);
|
||||
|
||||
// 过滤文档类型列表
|
||||
const filterDocumentTypes = (reviewType: string | null, types: DocumentType[]) => {
|
||||
if (!reviewType) {
|
||||
// 如果没有特定的 reviewType,使用原始数据
|
||||
setDocumentTypesState(types);
|
||||
return;
|
||||
}
|
||||
|
||||
let filteredTypes: DocumentType[] = [];
|
||||
|
||||
if (reviewType === 'contract') {
|
||||
// 只保留 id=1 的选项
|
||||
filteredTypes = types.filter(type => type.id === 1);
|
||||
} else if (reviewType === 'record') {
|
||||
// 只保留 id=2 和 id=3 的选项
|
||||
filteredTypes = types.filter(type => type.id === 2 || type.id === 3);
|
||||
} else {
|
||||
// 如果reviewType不匹配任何条件,使用原始数据
|
||||
filteredTypes = types;
|
||||
}
|
||||
|
||||
setDocumentTypesState(filteredTypes);
|
||||
};
|
||||
|
||||
// 过滤文档列表
|
||||
const filterDocuments = async (reviewType: string | null) => {
|
||||
if (!reviewType) {
|
||||
// 如果没有特定的 reviewType,使用原始数据
|
||||
setQueueFiles(loaderData.documents);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用 reviewType 获取过滤后的文档列表
|
||||
const response = await getTodayDocuments(reviewType);
|
||||
|
||||
if (response.error) {
|
||||
console.error('过滤文档列表失败:', response.error);
|
||||
// 失败时使用原始数据
|
||||
setQueueFiles(loaderData.documents);
|
||||
return;
|
||||
}
|
||||
|
||||
setQueueFiles(response.data || []);
|
||||
} catch (error) {
|
||||
console.error('过滤文档列表失败:', error);
|
||||
// 出错时使用原始数据
|
||||
setQueueFiles(loaderData.documents);
|
||||
}
|
||||
};
|
||||
|
||||
// 构建文件类型标签映射
|
||||
useEffect(() => {
|
||||
@@ -312,11 +402,11 @@ export default function FilesUpload() {
|
||||
delete FILE_TYPE_LABELS[key];
|
||||
});
|
||||
|
||||
// 使用从API获取的文档类型构建新的映射
|
||||
documentTypes.forEach(type => {
|
||||
// 使用过滤后的文档类型构建新的映射
|
||||
documentTypesState.forEach(type => {
|
||||
FILE_TYPE_LABELS[type.id.toString()] = type.name;
|
||||
});
|
||||
}, [documentTypes]);
|
||||
}, [documentTypesState]);
|
||||
|
||||
// 上传完成后的文件信息列表
|
||||
const [completedFiles, setCompletedFiles] = useState<UploadedFile[]>([]);
|
||||
@@ -462,7 +552,7 @@ export default function FilesUpload() {
|
||||
setFileTypeError(null);
|
||||
|
||||
// 检查是否选择了合同类型
|
||||
const selectedType = documentTypes.find(t => t.id.toString() === value);
|
||||
const selectedType = loaderData.documentTypes.find(t => t.id.toString() === value);
|
||||
const isContract = !!(selectedType && selectedType.name.includes('合同'));
|
||||
// console.log('【调试-handleFileTypeChange】文件类型检查:', {
|
||||
// selectedType,
|
||||
@@ -471,11 +561,11 @@ export default function FilesUpload() {
|
||||
// currentFiles: currentFiles.length
|
||||
// });
|
||||
|
||||
setIsContractType(isContract);
|
||||
// setIsContractType(isContract);
|
||||
|
||||
// 重置文件状态
|
||||
setContractMainFiles([]);
|
||||
setContractAttachmentFiles([]);
|
||||
// setContractMainFiles([]);
|
||||
// setContractAttachmentFiles([]);
|
||||
setCurrentFiles([]);
|
||||
|
||||
// 如果已经有选中的文件,且选择了文件类型,且不是合同类型,则开始上传
|
||||
@@ -490,20 +580,21 @@ export default function FilesUpload() {
|
||||
|
||||
} else {
|
||||
setFileType("");
|
||||
setIsContractType(false);
|
||||
// setIsContractType(false);
|
||||
// 如果用户选择了空选项,显示错误信息
|
||||
setFileTypeError("上传文件之前请选择文件类型");
|
||||
}
|
||||
};
|
||||
|
||||
// 处理合同主文件选择
|
||||
// 处理合同主文件选择 - 暂时未使用,保留以备将来扩展
|
||||
/*
|
||||
const handleContractMainFilesSelected = (files: FileList) => {
|
||||
try {
|
||||
// console.log('【调试-handleContractMainFilesSelected】开始处理合同主文件选择, 文件数量:', files.length);
|
||||
|
||||
// 检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
// console.error('【调试-handleContractMainFilesSelected】组件已卸载,取消处理');
|
||||
console.error('【调试-handleContractMainFilesSelected】组件已卸载,取消处理');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -535,7 +626,7 @@ export default function FilesUpload() {
|
||||
// console.log('【调试-handleContractMainFilesSelected】有效文件数量:', validFiles.length);
|
||||
// console.log('【调试-handleContractMainFilesSelected】有效文件:', validFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
|
||||
setContractMainFiles(validFiles);
|
||||
// setContractMainFiles(validFiles);
|
||||
} else {
|
||||
console.error('【调试-handleContractMainFilesSelected】没有有效的PDF文件或组件已卸载');
|
||||
}
|
||||
@@ -546,8 +637,10 @@ export default function FilesUpload() {
|
||||
console.error('【调试-handleContractMainFilesSelected】处理合同主文件选择时发生错误:', error);
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// 处理合同附件选择
|
||||
// 处理合同附件选择 - 暂时未使用,保留以备将来扩展
|
||||
/*
|
||||
const handleContractAttachmentFilesSelected = (files: FileList) => {
|
||||
try {
|
||||
// console.log('【调试-handleContractAttachmentFilesSelected】开始处理合同附件选择, 文件数量:', files.length);
|
||||
@@ -586,7 +679,7 @@ export default function FilesUpload() {
|
||||
// console.log('【调试-handleContractAttachmentFilesSelected】有效文件数量:', validFiles.length);
|
||||
// console.log('【调试-handleContractAttachmentFilesSelected】有效文件:', validFiles.map(f => ({ name: f.name, size: f.size, type: f.type })));
|
||||
|
||||
setContractAttachmentFiles(validFiles);
|
||||
// setContractAttachmentFiles(validFiles);
|
||||
} else {
|
||||
console.error('【调试-handleContractAttachmentFilesSelected】没有有效的PDF文件或组件已卸载');
|
||||
}
|
||||
@@ -597,8 +690,10 @@ export default function FilesUpload() {
|
||||
console.error('【调试-handleContractAttachmentFilesSelected】处理合同附件选择时发生错误:', error);
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// 检查并准备上传
|
||||
// 检查并准备上传 - 暂时未使用,保留以备将来扩展
|
||||
/*
|
||||
const checkAndPrepareUpload = (mainFiles: File[], attachmentFiles: File[]) => {
|
||||
try {
|
||||
// console.log('【调试-checkAndPrepareUpload】开始检查并准备上传文件', {
|
||||
@@ -621,7 +716,7 @@ export default function FilesUpload() {
|
||||
}
|
||||
|
||||
// 检查是否为合同类型
|
||||
const selectedType = documentTypes.find(t => t.id.toString() === fileType);
|
||||
const selectedType = loaderData.documentTypes.find(t => t.id.toString() === fileType);
|
||||
const isContract = !!(selectedType && selectedType.name.includes('合同'));
|
||||
|
||||
// console.log('【调试-checkAndPrepareUpload】文件类型检查', {
|
||||
@@ -721,6 +816,7 @@ export default function FilesUpload() {
|
||||
}
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// 开始上传文件
|
||||
const startUpload = async (files: File[]) => {
|
||||
@@ -822,7 +918,7 @@ export default function FilesUpload() {
|
||||
// console.log(`【调试-startUpload】准备上传文件 ${file.name} 到服务器`);
|
||||
|
||||
// 使用Promise.race添加超时处理
|
||||
const uploadPromise = uploadFileToServer(
|
||||
const uploadPromise = handleFileUpload(
|
||||
binaryData,
|
||||
file.name,
|
||||
file.type,
|
||||
@@ -840,7 +936,7 @@ export default function FilesUpload() {
|
||||
});
|
||||
|
||||
// 使用Promise.race处理超时
|
||||
response = await Promise.race([uploadPromise, timeoutPromise]);
|
||||
const uploadResult = await Promise.race([uploadPromise, timeoutPromise]);
|
||||
|
||||
// 再次检查组件是否已卸载
|
||||
if (!isMountedRef.current) {
|
||||
@@ -848,6 +944,13 @@ export default function FilesUpload() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查上传结果
|
||||
if (!uploadResult.success || !uploadResult.result) {
|
||||
throw new Error(uploadResult.error || '上传失败');
|
||||
}
|
||||
|
||||
response = uploadResult;
|
||||
|
||||
// console.log(`【调试-startUpload】文件 ${file.name} 上传响应:`, response);
|
||||
} catch (error) {
|
||||
// 检查组件是否已卸载
|
||||
@@ -1215,8 +1318,8 @@ export default function FilesUpload() {
|
||||
setCompletedFiles([]);
|
||||
|
||||
// 重置合同文件状态
|
||||
setContractMainFiles([]);
|
||||
setContractAttachmentFiles([]);
|
||||
// setContractMainFiles([]);
|
||||
// setContractAttachmentFiles([]);
|
||||
|
||||
// 重置步骤状态
|
||||
setProcessingSteps([
|
||||
@@ -1493,7 +1596,7 @@ export default function FilesUpload() {
|
||||
disabled={uploadStage !== "idle"}
|
||||
>
|
||||
<option value="">请选择文件类型</option>
|
||||
{documentTypes.map(type => (
|
||||
{documentTypesState.map(type => (
|
||||
<option key={type.id} value={type.id}>{type.name}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user