feat: 1. 接入CollaboraViewer选中的高亮效果,清除高亮功能,页面销毁自动清除高亮。
2. 合同模板对比接入monaco editor的效果。 3. 添加交叉评查的案卷类型的数据查询。 fix: 1. 修复文档列表的打开模态框蒙板层显示效果。
This commit is contained in:
@@ -16,6 +16,10 @@ import {
|
||||
formatFileSize,
|
||||
batchUploadAndAssignCrossCheckingFiles
|
||||
} from "~/api/cross-checking/cross-files-upload";
|
||||
import {
|
||||
getCrossCheckingDocumentTypes,
|
||||
type DocumentType
|
||||
} from "~/api/cross-checking/cross-files";
|
||||
import {
|
||||
getOrganizationTree,
|
||||
convertToTreeData
|
||||
@@ -125,16 +129,21 @@ const TreeNodeCheckbox: React.FC<{
|
||||
);
|
||||
};
|
||||
/**
|
||||
* 获取用户会话和前端JWT
|
||||
* 获取用户会话和前端JWT,以及文档类型列表
|
||||
*/
|
||||
export const loader = async ({ request }: LoaderFunctionArgs) => {
|
||||
// 获取用户会话信息
|
||||
const { getUserSession } = await import("~/api/login/auth.server");
|
||||
const { userInfo, frontendJWT } = await getUserSession(request);
|
||||
|
||||
|
||||
// 获取可用于交叉评查的文档类型列表
|
||||
const documentTypesResponse = await getCrossCheckingDocumentTypes(frontendJWT);
|
||||
|
||||
return Response.json({
|
||||
userInfo,
|
||||
frontendJWT
|
||||
frontendJWT,
|
||||
documentTypes: documentTypesResponse.success ? documentTypesResponse.data : [],
|
||||
documentTypesError: documentTypesResponse.error
|
||||
});
|
||||
};
|
||||
|
||||
@@ -194,10 +203,12 @@ export const action = async ({ request }: ActionFunctionArgs) => {
|
||||
|
||||
export default function CrossCheckingUpload() {
|
||||
// 获取loader数据
|
||||
const { userInfo, frontendJWT } = useLoaderData<typeof loader>();
|
||||
|
||||
// 基础状态
|
||||
const [caseType, setCaseType] = useState<CaseType>(CaseType.ADMINISTRATIVE_PENALTY);
|
||||
const { userInfo, frontendJWT, documentTypes, documentTypesError } = useLoaderData<typeof loader>();
|
||||
|
||||
// 基础状态 - 使用第一个文档类型的ID作为默认值
|
||||
const [selectedDocTypeId, setSelectedDocTypeId] = useState<number | null>(
|
||||
documentTypes && documentTypes.length > 0 ? documentTypes[0].id : null
|
||||
);
|
||||
// 步骤状态
|
||||
const [currentStep, setCurrentStep] = useState(1);
|
||||
// 任务创建状态
|
||||
@@ -235,16 +246,17 @@ export default function CrossCheckingUpload() {
|
||||
|
||||
|
||||
// 处理案卷类型切换
|
||||
const handleCaseTypeChange = (type: CaseType) => {
|
||||
const handleDocTypeChange = (docTypeId: number) => {
|
||||
if (isUploading) {
|
||||
toastService.warning("上传进行中,无法切换案卷类型");
|
||||
return;
|
||||
}
|
||||
|
||||
setCaseType(type);
|
||||
setSelectedDocTypeId(docTypeId);
|
||||
// 清空已选择的文件和重置上传方式
|
||||
clearAllFiles();
|
||||
console.log("案卷类型切换为:", type, "typeId:", CASE_TYPE_TO_TYPE_ID[type]);
|
||||
const selectedType = documentTypes?.find((dt: DocumentType) => dt.id === docTypeId);
|
||||
console.log("案卷类型切换为:", selectedType?.name, "ID:", docTypeId);
|
||||
};
|
||||
|
||||
// 清空所有文件
|
||||
@@ -268,7 +280,11 @@ export default function CrossCheckingUpload() {
|
||||
let hasInvalidFiles = false;
|
||||
|
||||
Array.from(files).forEach(file => {
|
||||
if (file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf')) {
|
||||
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');
|
||||
|
||||
if (isPdf || isDocx) {
|
||||
validFiles.push({
|
||||
id: generateFileId(),
|
||||
file,
|
||||
@@ -283,7 +299,7 @@ export default function CrossCheckingUpload() {
|
||||
});
|
||||
|
||||
if (hasInvalidFiles) {
|
||||
messageService.error('只能上传PDF格式的文件', {
|
||||
messageService.error('只能上传PDF或DOCX格式的文件', {
|
||||
title: '文件类型错误',
|
||||
confirmText: '确定',
|
||||
});
|
||||
@@ -413,12 +429,25 @@ export default function CrossCheckingUpload() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证选择了案卷类型
|
||||
if (!selectedDocTypeId) {
|
||||
toastService.error("请选择案卷类型");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsCreatingTask(true);
|
||||
setIsUploading(true);
|
||||
|
||||
|
||||
try {
|
||||
// 获取选中的文档类型信息
|
||||
const selectedDocType = documentTypes?.find((dt: DocumentType) => dt.id === selectedDocTypeId);
|
||||
if (!selectedDocType) {
|
||||
toastService.error("无效的案卷类型");
|
||||
return;
|
||||
}
|
||||
|
||||
// 第一步:上传文件并自动分配任务(新接口)
|
||||
console.log("开始批量上传文件并分配任务:", filesToUpload.length, "个,案卷类型:", caseType);
|
||||
console.log("开始批量上传文件并分配任务:", filesToUpload.length, "个,案卷类型:", selectedDocType.name);
|
||||
|
||||
// 提取用户ID(从选中的组织架构中获取用户)
|
||||
const userIds = groupChecked.filter(id => {
|
||||
@@ -431,22 +460,17 @@ export default function CrossCheckingUpload() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建任务数据
|
||||
const docTypeMap = {
|
||||
[CaseType.ADMINISTRATIVE_PENALTY]: 'XZCF',
|
||||
[CaseType.ADMINISTRATIVE_PERMIT]: 'XZXK'
|
||||
};
|
||||
|
||||
// 使用文档类型名称作为 doc_type
|
||||
const uploadResult = await batchUploadAndAssignCrossCheckingFiles(
|
||||
filesToUpload,
|
||||
CASE_TYPE_TO_TYPE_ID[caseType],
|
||||
selectedDocTypeId, // 使用选中的文档类型ID
|
||||
priority,
|
||||
documentNumber,
|
||||
remark,
|
||||
isTestDocument,
|
||||
userIds,
|
||||
taskInfo.name,
|
||||
docTypeMap[caseType] || 'XZCF',
|
||||
selectedDocType.name, // 使用文档类型名称
|
||||
frontendJWT
|
||||
);
|
||||
|
||||
@@ -814,29 +838,36 @@ export default function CrossCheckingUpload() {
|
||||
<div className="flex justify-center mb-6">
|
||||
<div>
|
||||
<div className="text-sm font-medium text-gray-700 mb-3 text-center">选择案卷类型</div>
|
||||
<div className="case-type-options">
|
||||
<button
|
||||
type="button"
|
||||
className={`case-type-option ${caseType === CaseType.ADMINISTRATIVE_PENALTY ? 'active' : 'inactive'}`}
|
||||
onClick={() => handleCaseTypeChange(CaseType.ADMINISTRATIVE_PENALTY)}
|
||||
disabled={isUploading}
|
||||
>
|
||||
行政处罚
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`case-type-option ${caseType === CaseType.ADMINISTRATIVE_PERMIT ? 'active' : 'inactive'}`}
|
||||
onClick={() => handleCaseTypeChange(CaseType.ADMINISTRATIVE_PERMIT)}
|
||||
disabled={isUploading}
|
||||
>
|
||||
行政许可
|
||||
</button>
|
||||
</div>
|
||||
{documentTypesError ? (
|
||||
<div className="text-red-500 text-sm text-center p-4 border border-red-200 rounded-md bg-red-50">
|
||||
<i className="ri-error-warning-line mr-2"></i>
|
||||
加载案卷类型失败: {documentTypesError}
|
||||
</div>
|
||||
) : documentTypes && documentTypes.length > 0 ? (
|
||||
<div className="case-type-options">
|
||||
{documentTypes.map((docType: DocumentType) => (
|
||||
<button
|
||||
key={docType.id}
|
||||
type="button"
|
||||
className={`case-type-option ${selectedDocTypeId === docType.id ? 'active' : 'inactive'}`}
|
||||
onClick={() => handleDocTypeChange(docType.id)}
|
||||
disabled={isUploading}
|
||||
>
|
||||
{docType.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-gray-500 text-sm text-center p-4 border border-gray-200 rounded-md bg-gray-50">
|
||||
<i className="ri-information-line mr-2"></i>
|
||||
暂无可用的案卷类型
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* 文件上传区域 */}
|
||||
<input type="hidden" name="caseType" value={caseType} />
|
||||
<input type="hidden" name="selectedDocTypeId" value={selectedDocTypeId || ''} />
|
||||
<input type="hidden" name="uploadType" value={uploadType} />
|
||||
|
||||
{/* 上传框区域 */}
|
||||
@@ -851,14 +882,14 @@ export default function CrossCheckingUpload() {
|
||||
ref={singleUploadRef}
|
||||
onFilesSelected={handleSingleFilesSelected}
|
||||
className="custom-upload-area"
|
||||
accept=".pdf"
|
||||
accept=".pdf,.docx"
|
||||
multiple={true}
|
||||
icon="ri-file-upload-line"
|
||||
buttonText="选择文件"
|
||||
mainText="点击或拖拽文件到此区域上传"
|
||||
tipText={
|
||||
<div className="upload-tip-error">
|
||||
请上传案件相关PDF文件
|
||||
请上传案件相关PDF或DOCX文件
|
||||
</div>
|
||||
}
|
||||
disabled={uploadType === 'multiple' || isUploading}
|
||||
@@ -911,23 +942,29 @@ export default function CrossCheckingUpload() {
|
||||
{/* 单案件文件列表 */}
|
||||
{uploadType === 'single' && singleFiles.length > 0 && (
|
||||
<div className="max-h-32 overflow-y-auto space-y-1">
|
||||
{singleFiles.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-file-pdf-line text-red-500"></i>
|
||||
<span className="text-sm truncate">{file.name}</span>
|
||||
<span className="text-xs text-gray-500">{formatFileSize(file.size)}</span>
|
||||
{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>
|
||||
<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>
|
||||
<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>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user