fix: 1.将主页和法务助手对话设置成手机也能够正确加载的响应式布局。
2. 修改合同重新上传模板的可接受文件类型,修改对接的上传模板对应的接口。 3. 交叉评查任务列表去除任务名称的点击效果。 4. 交叉评查文件预览在点击完成评查的按钮后会返回任务列表并打开任务的文档列表。 5.修复点击完成评查按钮造成页面刷新。 6. 修复创建任务的第3步无法返回列表。
This commit is contained in:
@@ -38,21 +38,28 @@ export function Layout({ children, userRole = 'developer' as UserRole, frontendJ
|
||||
const [selectedApp, setSelectedApp] = useState<AppModule>('');
|
||||
const matches = useMatches() as Match[];
|
||||
const location = useLocation();
|
||||
|
||||
|
||||
// 检查当前路径是否应该隐藏侧边栏
|
||||
const noLayoutPaths = ['/login', '/'];
|
||||
const shouldHideSidebar = noLayoutPaths.includes(location.pathname);
|
||||
|
||||
|
||||
// 检查当前路由是否应该隐藏默认面包屑
|
||||
const shouldHideBreadcrumb = shouldHideSidebar || matches.some(match =>
|
||||
const shouldHideBreadcrumb = shouldHideSidebar || matches.some(match =>
|
||||
match.handle && match.handle.hideBreadcrumb === true
|
||||
);
|
||||
|
||||
|
||||
// 从sessionStorage中获取侧边栏状态和reviewType
|
||||
useEffect(() => {
|
||||
// 检查是否为移动端
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
// 从localStorage获取侧边栏状态
|
||||
const savedState = localStorage.getItem('sidebarCollapsed');
|
||||
if (savedState) {
|
||||
|
||||
// 移动端默认收起,桌面端使用保存的状态
|
||||
if (isMobile) {
|
||||
setSidebarCollapsed(true);
|
||||
} else if (savedState) {
|
||||
setSidebarCollapsed(savedState === 'true');
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,24 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '', selec
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true); // 添加加载状态
|
||||
const [menuItems, setMenuItems] = useState<MenuItem[]>([]); // 动态菜单项
|
||||
const [isLoadingRoutes, setIsLoadingRoutes] = useState<boolean>(true); // 路由加载状态
|
||||
const [isMobile, setIsMobile] = useState<boolean>(false); // 移动端检测
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 移动端检测
|
||||
useEffect(() => {
|
||||
const checkMobile = () => {
|
||||
const mobile = window.innerWidth <= 768; // 768px以下视为移动端
|
||||
setIsMobile(mobile);
|
||||
};
|
||||
|
||||
// 初始检测
|
||||
checkMobile();
|
||||
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener('resize', checkMobile);
|
||||
return () => window.removeEventListener('resize', checkMobile);
|
||||
}, []);
|
||||
|
||||
// 获取用户路由权限
|
||||
useEffect(() => {
|
||||
const fetchUserRoutes = async () => {
|
||||
@@ -254,8 +270,26 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '', selec
|
||||
// })
|
||||
|
||||
return (
|
||||
<div className={`sidebar ${collapsed ? 'collapsed' : ''} flex flex-col`}>
|
||||
<div className="py-6 px-4 border-b border-gray-100 flex justify-between items-center">
|
||||
<>
|
||||
{/* 移动端遮罩层 */}
|
||||
{isMobile && !collapsed && (
|
||||
<div
|
||||
className="sidebar-overlay"
|
||||
onClick={onToggle}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-label="关闭侧边栏"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
onToggle();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className={`sidebar ${collapsed ? 'collapsed' : ''} ${isMobile ? 'sidebar-mobile' : ''} flex flex-col`}>
|
||||
<div className="py-6 px-4 border-b border-gray-100 flex justify-between items-center">
|
||||
<div className="flex items-center"
|
||||
onClick={() => {
|
||||
navigate('/');
|
||||
@@ -396,6 +430,7 @@ export function Sidebar({ onToggle, collapsed, userRole, frontendJWT = '', selec
|
||||
{!collapsed && <span className="text-base">操作手册</span>}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { UploadArea, type UploadAreaRef } from '~/components/ui/UploadArea';
|
||||
import { Button } from '~/components/ui/Button';
|
||||
import { toastService } from '~/components/ui/Toast';
|
||||
// import { DOCUMENT_URL } from "~/api/axios-client";
|
||||
import { uploadFileToBinary, uploadDocumentToServer } from '~/api/files/files-upload';
|
||||
import { uploadContractTemplate } from '~/api/files/files-upload';
|
||||
|
||||
interface ReviewTabsProps {
|
||||
activeTab: string;
|
||||
@@ -22,6 +22,7 @@ interface ReviewTabsProps {
|
||||
path?: string;
|
||||
auditStatus?: number;
|
||||
type?: string;
|
||||
comparisonId?: number;
|
||||
};
|
||||
onConfirmResults: () => void;
|
||||
jwtToken?: string | null;
|
||||
@@ -117,23 +118,32 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
|
||||
const handleTemplateFilesSelected = (files: FileList) => {
|
||||
try {
|
||||
if (files.length > 0) {
|
||||
// 验证文件类型,只允许PDF文件
|
||||
// 验证文件类型,允许PDF和Word文件
|
||||
const validFiles: File[] = [];
|
||||
let hasInvalidFiles = false;
|
||||
|
||||
|
||||
Array.from(files).forEach(file => {
|
||||
if (file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf')) {
|
||||
const fileName = file.name.toLowerCase();
|
||||
const isValidType =
|
||||
file.type === 'application/pdf' ||
|
||||
fileName.endsWith('.pdf') ||
|
||||
file.type === 'application/msword' ||
|
||||
file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
|
||||
fileName.endsWith('.doc') ||
|
||||
fileName.endsWith('.docx');
|
||||
|
||||
if (isValidType) {
|
||||
validFiles.push(file);
|
||||
} else {
|
||||
hasInvalidFiles = true;
|
||||
console.error(`无效的文件类型: ${file.name}, 类型: ${file.type}`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (hasInvalidFiles) {
|
||||
toastService.error('只能上传PDF格式的文件');
|
||||
toastService.error('只能上传PDF或Word格式的文件');
|
||||
}
|
||||
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
setSelectedTemplateFiles(validFiles);
|
||||
}
|
||||
@@ -152,57 +162,42 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证必需的参数
|
||||
if (!fileInfo.id) {
|
||||
toastService.error('文档ID不能为空');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsUploading(true);
|
||||
|
||||
// 这里可以调用上传API
|
||||
let binaryData: ArrayBuffer;
|
||||
try {
|
||||
binaryData = await uploadFileToBinary(selectedTemplateFiles[0]);
|
||||
} catch (error) {
|
||||
console.error('上传文件失败:', error);
|
||||
throw new Error(`文件 ${selectedTemplateFiles[0].name} 转换失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
||||
|
||||
console.log('【重新上传模板】开始上传:', {
|
||||
fileName: selectedTemplateFiles[0].name,
|
||||
documentId: fileInfo.id,
|
||||
comparisonId: fileInfo.comparisonId
|
||||
});
|
||||
|
||||
// 调用专门的合同模板上传接口
|
||||
const uploadResult = await uploadContractTemplate(
|
||||
selectedTemplateFiles[0], // file: File 对象
|
||||
fileInfo.id, // documentId: 合同文件的id
|
||||
fileInfo.comparisonId, // comparisonId: 模板预览文件的id (可选)
|
||||
jwtToken || undefined // jwtToken
|
||||
);
|
||||
|
||||
console.log('【重新上传模板】上传结果:', uploadResult);
|
||||
|
||||
if (uploadResult.error) {
|
||||
throw new Error(uploadResult.error);
|
||||
}
|
||||
|
||||
// const uploadInfo = {
|
||||
// binaryData,
|
||||
// fileName: selectedTemplateFiles[0].name,
|
||||
// fileType: 'pdf',
|
||||
// documentType: '1',
|
||||
// priority: 'normal',
|
||||
// documentNumber: null,
|
||||
// remark: null,
|
||||
// isTestDocument: false,
|
||||
// documentId: fileInfo
|
||||
// };
|
||||
// console.log('uploadInfo',uploadInfo);
|
||||
|
||||
const uploadResult = await uploadDocumentToServer(
|
||||
binaryData,
|
||||
selectedTemplateFiles[0].name,
|
||||
'pdf', //file_type 文件类型:pdf
|
||||
'1', //fileType(type_id) 合同id:1
|
||||
'normal', //priority 优先级:normal
|
||||
null, //document_number 文档编号
|
||||
null, //remark 备注
|
||||
false, //is_test_document 是否为测试文档:false
|
||||
fileInfo.id, //document_id 主文档id
|
||||
true, //is_reupload 是否为重新上传:true
|
||||
jwtToken || undefined, //jwtToken
|
||||
);
|
||||
// console.log('重新上传合同模板',uploadResult);
|
||||
|
||||
if (uploadResult.error) {
|
||||
throw new Error(uploadResult.error);
|
||||
}
|
||||
|
||||
toastService.success('模板文件上传成功,结构比对数据将会发生更新,即将返回上一页...');
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
|
||||
handleCloseReuploadModal();
|
||||
handleBack();
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('上传模板文件失败:', error);
|
||||
toastService.error(`上传失败: ${error instanceof Error ? error.message : '未知错误'}`);
|
||||
@@ -335,21 +330,21 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
|
||||
<p>请选择新的模板文件用于结构比对。</p>
|
||||
<p className="mt-2 text-orange-600">
|
||||
<i className="ri-information-line mr-1"></i>
|
||||
注意:只支持PDF格式的文件,上传后将替换当前的比对模板。
|
||||
注意:支持PDF和Word格式的文件,上传后将替换当前的比对模板。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<UploadArea
|
||||
ref={uploadAreaRef}
|
||||
onFilesSelected={handleTemplateFilesSelected}
|
||||
accept=".pdf,application/pdf"
|
||||
accept=".pdf,.doc,.docx,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
||||
multiple={false}
|
||||
icon="ri-file-pdf-line"
|
||||
icon="ri-file-text-line"
|
||||
buttonText="选择模板文件"
|
||||
mainText="点击或拖拽PDF文件到此区域"
|
||||
mainText="点击或拖拽文件到此区域"
|
||||
tipText={
|
||||
<span className="text-xs text-gray-500">
|
||||
支持格式:PDF
|
||||
支持格式:PDF、DOC、DOCX
|
||||
</span>
|
||||
}
|
||||
disabled={isUploading}
|
||||
@@ -360,38 +355,50 @@ export function ReviewTabs({ activeTab, onTabChange, children, fileInfo, onConfi
|
||||
<div className="mt-4">
|
||||
<h4 className="text-sm font-medium text-gray-900 mb-2">已选择的文件:</h4>
|
||||
<div className="space-y-2">
|
||||
{selectedTemplateFiles.map((file, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center justify-between p-3 bg-gray-50 rounded-lg border"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<i className="ri-file-pdf-line text-red-500 mr-2"></i>
|
||||
<div>
|
||||
<div className="text-sm font-medium text-gray-900">
|
||||
{file.name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
{formatFileSize(file.size)}
|
||||
{selectedTemplateFiles.map((file, index) => {
|
||||
// 根据文件类型确定图标和颜色
|
||||
const fileName = file.name.toLowerCase();
|
||||
let fileIcon = 'ri-file-pdf-line';
|
||||
let iconColor = 'text-red-500';
|
||||
|
||||
if (fileName.endsWith('.doc') || fileName.endsWith('.docx')) {
|
||||
fileIcon = 'ri-file-word-2-line';
|
||||
iconColor = 'text-blue-600';
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center justify-between p-3 bg-gray-50 rounded-lg border"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<i className={`${fileIcon} ${iconColor} mr-2`}></i>
|
||||
<div>
|
||||
<div className="text-sm font-medium text-gray-900">
|
||||
{file.name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
{formatFileSize(file.size)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="text-gray-400 hover:text-red-500 transition-colors"
|
||||
onClick={() => {
|
||||
setSelectedTemplateFiles(prev =>
|
||||
prev.filter((_, i) => i !== index)
|
||||
);
|
||||
if (uploadAreaRef.current) {
|
||||
uploadAreaRef.current.resetFileInput();
|
||||
}
|
||||
}}
|
||||
disabled={isUploading}
|
||||
>
|
||||
<i className="ri-close-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
className="text-gray-400 hover:text-red-500 transition-colors"
|
||||
onClick={() => {
|
||||
setSelectedTemplateFiles(prev =>
|
||||
prev.filter((_, i) => i !== index)
|
||||
);
|
||||
if (uploadAreaRef.current) {
|
||||
uploadAreaRef.current.resetFileInput();
|
||||
}
|
||||
}}
|
||||
disabled={isUploading}
|
||||
>
|
||||
<i className="ri-close-line"></i>
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user