新增全局加载进度条组件
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { useNavigate } from "@remix-run/react";
|
import { useNavigate } from "@remix-run/react";
|
||||||
import { toastService } from "~/components/ui/Toast";
|
import { useState } from "react";
|
||||||
|
|
||||||
interface FileInfoProps {
|
interface FileInfoProps {
|
||||||
fileInfo: {
|
fileInfo: {
|
||||||
fileName: string;
|
fileName: string;
|
||||||
@@ -11,12 +12,15 @@ interface FileInfoProps {
|
|||||||
uploadUser?: string;
|
uploadUser?: string;
|
||||||
auditStatus?: number;
|
auditStatus?: number;
|
||||||
path?: string;
|
path?: string;
|
||||||
|
previousRoute?: string;
|
||||||
};
|
};
|
||||||
onConfirmResults: () => void;
|
onConfirmResults: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FileInfo({ fileInfo, onConfirmResults }: FileInfoProps) {
|
export function FileInfo({ fileInfo, onConfirmResults }: FileInfoProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [isNavigating, setIsNavigating] = useState(false);
|
||||||
|
|
||||||
const handleDownloadFile = async () => {
|
const handleDownloadFile = async () => {
|
||||||
try {
|
try {
|
||||||
const urlBefore = 'http://172.18.0.100:9000/docauditai/';
|
const urlBefore = 'http://172.18.0.100:9000/docauditai/';
|
||||||
@@ -56,7 +60,22 @@ export function FileInfo({ fileInfo, onConfirmResults }: FileInfoProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
navigate(-1);
|
// 防抖处理 - 如果已经在导航中,不重复触发
|
||||||
|
if (isNavigating) return;
|
||||||
|
|
||||||
|
// 设置导航状态为true
|
||||||
|
setIsNavigating(true);
|
||||||
|
|
||||||
|
// 根据来源页面返回
|
||||||
|
const previousRoute = fileInfo.previousRoute || 'documents';
|
||||||
|
const returnTo = previousRoute === 'documents'
|
||||||
|
? "/documents"
|
||||||
|
: previousRoute === 'filesUpload'
|
||||||
|
? "/files/upload"
|
||||||
|
: "/rules-files";
|
||||||
|
|
||||||
|
// 立即导航返回
|
||||||
|
navigate(returnTo);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExportReport = () => {
|
const handleExportReport = () => {
|
||||||
@@ -89,8 +108,9 @@ export function FileInfo({ fileInfo, onConfirmResults }: FileInfoProps) {
|
|||||||
<button
|
<button
|
||||||
className="ant-btn ant-btn-default flex items-center"
|
className="ant-btn ant-btn-default flex items-center"
|
||||||
onClick={() => handleBack()}
|
onClick={() => handleBack()}
|
||||||
|
disabled={isNavigating}
|
||||||
>
|
>
|
||||||
<i className="ri-arrow-left-line mr-1"></i> 返回
|
<i className="ri-arrow-left-line mr-1"></i> {isNavigating ? '返回中...' : '返回'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="ant-btn ant-btn-default flex items-center"
|
className="ant-btn ant-btn-default flex items-center"
|
||||||
|
|||||||
@@ -1024,9 +1024,15 @@ export function ReviewPointsList({
|
|||||||
<div className="review-point-header flex justify-between items-start">
|
<div className="review-point-header flex justify-between items-start">
|
||||||
<div className="review-point-title flex-1 text-left min-w-[25%]">{reviewPoint.title}</div>
|
<div className="review-point-title flex-1 text-left min-w-[25%]">{reviewPoint.title}</div>
|
||||||
{/* 评查点所属分组 */}
|
{/* 评查点所属分组 */}
|
||||||
<div className="review-point-location max-w-[40%]">
|
<div className="review-point-location max-w-[40%] flex items-center">
|
||||||
<i className="ri-file-list-line mr-1"></i>
|
<i className="ri-file-list-line mr-1 flex-shrink-0"></i>
|
||||||
<span>{reviewPoint.groupName}</span>
|
<span
|
||||||
|
className="truncate block whitespace-nowrap overflow-hidden hover:overflow-visible hover:text-clip hover:bg-white hover:shadow-md hover:z-10 hover:text-wrap px-1 rounded"
|
||||||
|
title={reviewPoint.groupName}
|
||||||
|
style={{ cursor: 'text', userSelect: 'all' }}
|
||||||
|
>
|
||||||
|
{reviewPoint.groupName}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-center ml-2 flex-shrink-0 max-w-[15%]">
|
<div className="flex flex-col items-center ml-2 flex-shrink-0 max-w-[15%]">
|
||||||
{renderStatusBadge(reviewPoint.status, reviewPoint.result)}
|
{renderStatusBadge(reviewPoint.status, reviewPoint.result)}
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
|
interface LoadingBarProps {
|
||||||
|
isVisible: boolean;
|
||||||
|
isComplete?: boolean;
|
||||||
|
height?: number;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载进度条状态管理
|
||||||
|
let showLoadingBar: (show: boolean, completeFirst?: boolean) => void = () => {};
|
||||||
|
let loadingBarVisible = false;
|
||||||
|
|
||||||
|
export function LoadingBar({
|
||||||
|
isVisible,
|
||||||
|
isComplete = false,
|
||||||
|
height = 2,
|
||||||
|
className = ''
|
||||||
|
}: LoadingBarProps) {
|
||||||
|
// 当组件挂载时,进行进度的随机增长动画
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
|
||||||
|
// 处理完成状态
|
||||||
|
useEffect(() => {
|
||||||
|
if (isComplete) {
|
||||||
|
// 立即将进度设为100%
|
||||||
|
setProgress(100);
|
||||||
|
}
|
||||||
|
}, [isComplete]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let interval: NodeJS.Timeout;
|
||||||
|
|
||||||
|
if (isVisible && progress < 90) {
|
||||||
|
// 随机增长进度,模拟加载 - 加速更新频率
|
||||||
|
interval = setInterval(() => {
|
||||||
|
setProgress(prev => {
|
||||||
|
// 进度越大,增长越慢
|
||||||
|
const increment = Math.random() * (20 - prev / 8);
|
||||||
|
return Math.min(prev + increment, 90);
|
||||||
|
});
|
||||||
|
}, 300); // 更高频率的更新
|
||||||
|
} else if (!isVisible) {
|
||||||
|
// 隐藏时重置进度
|
||||||
|
setProgress(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (interval) clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, [isVisible, progress]);
|
||||||
|
|
||||||
|
// 当isVisible变化时,立即触发显示或隐藏效果
|
||||||
|
useEffect(() => {
|
||||||
|
if (isVisible) {
|
||||||
|
setProgress(20); // 立刻显示更多进度
|
||||||
|
} else if (progress > 0) {
|
||||||
|
// 如果已经有进度了,先快速完成进度,然后再隐藏
|
||||||
|
setProgress(100);
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setProgress(0);
|
||||||
|
}, 300); // 更快的隐藏
|
||||||
|
return () => clearTimeout(timeout);
|
||||||
|
}
|
||||||
|
}, [isVisible]);
|
||||||
|
|
||||||
|
if (!isVisible && progress === 0) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed top-0 left-0 right-0 z-[9999]">
|
||||||
|
<div
|
||||||
|
className={`${className} animate-pulse`}
|
||||||
|
style={{
|
||||||
|
height: `${height}px`,
|
||||||
|
width: `${progress}%`,
|
||||||
|
opacity: progress > 0 ? 1 : 0,
|
||||||
|
transition: 'width 0.3s ease-out, opacity 0.2s ease-in-out',
|
||||||
|
background: 'linear-gradient(90deg, var(--color-primary) 0%, var(--color-primary-hover) 50%, var(--color-primary) 100%)',
|
||||||
|
boxShadow: '0 0 10px rgba(0, 104, 74, 0.7)'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个全局加载进度条容器
|
||||||
|
function LoadingBarContainer() {
|
||||||
|
const [visible, setVisible] = useState(loadingBarVisible);
|
||||||
|
const [completeBeforeHide, setCompleteBeforeHide] = useState(false);
|
||||||
|
|
||||||
|
// 保存引用以便外部调用
|
||||||
|
useEffect(() => {
|
||||||
|
showLoadingBar = (show: boolean, completeFirst: boolean = false) => {
|
||||||
|
if (!show && completeFirst) {
|
||||||
|
// 当隐藏时,先触发完成动画,再隐藏
|
||||||
|
setCompleteBeforeHide(true);
|
||||||
|
// 延迟隐藏,以让完成动画显示出来
|
||||||
|
setTimeout(() => {
|
||||||
|
loadingBarVisible = false;
|
||||||
|
setVisible(false);
|
||||||
|
setCompleteBeforeHide(false);
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
loadingBarVisible = show;
|
||||||
|
setVisible(show);
|
||||||
|
if (!show) {
|
||||||
|
setCompleteBeforeHide(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 使用Portal确保加载进度条总是渲染在body末尾
|
||||||
|
return typeof window !== 'undefined'
|
||||||
|
? createPortal(
|
||||||
|
<LoadingBar isVisible={visible} isComplete={completeBeforeHide} />,
|
||||||
|
document.body
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出全局控制函数
|
||||||
|
export const loadingBarService = {
|
||||||
|
show: () => showLoadingBar(true),
|
||||||
|
hide: () => showLoadingBar(false, true),
|
||||||
|
toggle: () => showLoadingBar(!loadingBarVisible),
|
||||||
|
isVisible: () => loadingBarVisible
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoadingBarContainer;
|
||||||
@@ -19,6 +19,7 @@ import "remixicon/fonts/remixicon.css";
|
|||||||
import styles from "~/styles/main.css?url";
|
import styles from "~/styles/main.css?url";
|
||||||
import messageModalStyles from "~/styles/components/message-modal.css?url";
|
import messageModalStyles from "~/styles/components/message-modal.css?url";
|
||||||
import toastStyles from "~/styles/components/toast.css?url";
|
import toastStyles from "~/styles/components/toast.css?url";
|
||||||
|
import LoadingBarContainer from "~/components/ui/LoadingBar";
|
||||||
|
|
||||||
// 添加客户端hydration错误处理
|
// 添加客户端hydration错误处理
|
||||||
// if (typeof window !== "undefined") {
|
// if (typeof window !== "undefined") {
|
||||||
@@ -87,6 +88,7 @@ export default function App() {
|
|||||||
</MessageModalProvider>
|
</MessageModalProvider>
|
||||||
<ScrollRestoration />
|
<ScrollRestoration />
|
||||||
<Scripts />
|
<Scripts />
|
||||||
|
<LoadingBarContainer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
+170
-137
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { useSearchParams, useLoaderData, useFetcher, useNavigate,Link } from "@remix-run/react";
|
import { useSearchParams, useLoaderData, useFetcher, useNavigate,Link } from "@remix-run/react";
|
||||||
import { type MetaFunction, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
|
import { type MetaFunction, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
|
||||||
import { Card } from "~/components/ui/Card";
|
import { Card } from "~/components/ui/Card";
|
||||||
@@ -14,6 +14,7 @@ import { getDocumentTypes } from "~/api/document-types/document-types";
|
|||||||
import { updateDocumentAuditStatus } from "~/api/evaluation_points/rules-files";
|
import { updateDocumentAuditStatus } from "~/api/evaluation_points/rules-files";
|
||||||
import { toastService } from "~/components/ui/Toast";
|
import { toastService } from "~/components/ui/Toast";
|
||||||
import { messageService } from "~/components/ui/MessageModal";
|
import { messageService } from "~/components/ui/MessageModal";
|
||||||
|
import { loadingBarService } from "~/components/ui/LoadingBar";
|
||||||
|
|
||||||
// 导入样式
|
// 导入样式
|
||||||
export function links() {
|
export function links() {
|
||||||
@@ -196,6 +197,10 @@ export default function DocumentsIndex() {
|
|||||||
const fetcher = useFetcher<ActionResponse>();
|
const fetcher = useFetcher<ActionResponse>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
// 添加页面加载状态管理
|
||||||
|
const [isLoadingData, setIsLoadingData] = useState(true);
|
||||||
|
const dataCache = useRef<typeof loaderData | null>(null);
|
||||||
|
|
||||||
// 从URL获取当前筛选条件
|
// 从URL获取当前筛选条件
|
||||||
const search = searchParams.get("search") || "";
|
const search = searchParams.get("search") || "";
|
||||||
const documentType = searchParams.get("documentType") || "";
|
const documentType = searchParams.get("documentType") || "";
|
||||||
@@ -210,12 +215,29 @@ export default function DocumentsIndex() {
|
|||||||
// 获取API返回的数据
|
// 获取API返回的数据
|
||||||
const { documents, total, documentTypeOptions } = loaderData;
|
const { documents, total, documentTypeOptions } = loaderData;
|
||||||
|
|
||||||
// 处理loader错误
|
// 使用并更新缓存数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// 如果有缓存数据,先显示缓存,再在后台加载新数据
|
||||||
|
if (dataCache.current) {
|
||||||
|
setIsLoadingData(false);
|
||||||
|
} else {
|
||||||
|
// 显示加载状态 - 确保显示加载条
|
||||||
|
loadingBarService.show();
|
||||||
|
setIsLoadingData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置缓存数据
|
||||||
|
dataCache.current = loaderData;
|
||||||
|
|
||||||
|
// 数据加载完成后,执行额外的延迟以确保UI效果
|
||||||
|
setIsLoadingData(false);
|
||||||
|
loadingBarService.hide();
|
||||||
|
|
||||||
|
// 处理loader错误
|
||||||
if (loaderData.error) {
|
if (loaderData.error) {
|
||||||
toastService.error(loaderData.error);
|
toastService.error(loaderData.error);
|
||||||
}
|
}
|
||||||
}, [loaderData.error]);
|
}, [loaderData]);
|
||||||
|
|
||||||
// 使用useEffect监听fetcher状态变化并显示Toast
|
// 使用useEffect监听fetcher状态变化并显示Toast
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -564,17 +586,25 @@ export default function DocumentsIndex() {
|
|||||||
// 检查audit_status是否为0,如果是则更新为2
|
// 检查audit_status是否为0,如果是则更新为2
|
||||||
if (auditStatus === 0 || auditStatus === null) {
|
if (auditStatus === 0 || auditStatus === null) {
|
||||||
try {
|
try {
|
||||||
|
// 显示加载状态
|
||||||
|
loadingBarService.show();
|
||||||
|
|
||||||
const response = await updateDocumentAuditStatus(fileId.toString(), 2);
|
const response = await updateDocumentAuditStatus(fileId.toString(), 2);
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.error('更新文件审核状态失败:', response.error);
|
console.error('更新文件审核状态失败:', response.error);
|
||||||
// alert('更新文件审核状态失败:' + (response.error || '未知错误'));
|
|
||||||
toastService.error('更新文件审核状态失败:' + (response.error || '未知错误'));
|
toastService.error('更新文件审核状态失败:' + (response.error || '未知错误'));
|
||||||
|
loadingBarService.hide();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('更新文件审核状态时出错:', error);
|
console.error('更新文件审核状态时出错:', error);
|
||||||
// alert('更新文件审核状态时出错:' + (error instanceof Error ? error.message : '未知错误'));
|
|
||||||
toastService.error('更新文件审核状态时出错:' + (error instanceof Error ? error.message : '未知错误'));
|
toastService.error('更新文件审核状态时出错:' + (error instanceof Error ? error.message : '未知错误'));
|
||||||
|
loadingBarService.hide();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 显示加载状态
|
||||||
|
loadingBarService.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导航到评查详情页
|
// 导航到评查详情页
|
||||||
@@ -764,146 +794,149 @@ export default function DocumentsIndex() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="documents-page">
|
<div className="documents-page relative">
|
||||||
{/* 页面头部 */}
|
{/* 页面内容,在加载时降低不透明度但不隐藏内容 */}
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className={isLoadingData ? "opacity-70 pointer-events-none transition-opacity" : "transition-opacity"}>
|
||||||
<h2 className="text-xl font-medium">文档列表</h2>
|
{/* 页面头部 */}
|
||||||
<div>
|
<div className="flex justify-between items-center mb-4">
|
||||||
<Button
|
<h2 className="text-xl font-medium">文档列表</h2>
|
||||||
type="primary"
|
|
||||||
icon="ri-upload-line"
|
|
||||||
to="/files/upload"
|
|
||||||
className="hover:text-white"
|
|
||||||
>
|
|
||||||
上传文档
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 搜索筛选区 */}
|
|
||||||
<FilterPanel
|
|
||||||
actions={
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
icon="ri-refresh-line"
|
|
||||||
onClick={handleReset}
|
|
||||||
className="mr-2"
|
|
||||||
>
|
|
||||||
重置
|
|
||||||
</Button>
|
|
||||||
{/* <Button
|
|
||||||
type="primary"
|
|
||||||
icon="ri-search-line"
|
|
||||||
onClick={() => {
|
|
||||||
// 保持当前筛选条件,刷新数据
|
|
||||||
// 在实际应用中,这里可能需要触发某些操作
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
搜索
|
|
||||||
</Button> */}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
noActionDivider={true}
|
|
||||||
>
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 w-full">
|
|
||||||
<SearchFilter
|
|
||||||
label="文档名称"
|
|
||||||
placeholder="请输入文档名称"
|
|
||||||
value={search}
|
|
||||||
onSearch={handleNameSearch}
|
|
||||||
instantSearch={true}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SearchFilter
|
|
||||||
label="文档编号"
|
|
||||||
placeholder="请输入文档编号"
|
|
||||||
value={documentNumber}
|
|
||||||
onSearch={handleDocumentNumberChange}
|
|
||||||
instantSearch={true}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FilterSelect
|
|
||||||
label="文档类型"
|
|
||||||
name="documentType"
|
|
||||||
value={documentType}
|
|
||||||
options={documentTypeOptions}
|
|
||||||
onChange={handleDocumentTypeChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FilterSelect
|
|
||||||
label="文件状态"
|
|
||||||
name="fileStatus"
|
|
||||||
value={fileStatus}
|
|
||||||
options={fileStatusOptions}
|
|
||||||
onChange={handleFileStatusChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FilterSelect
|
|
||||||
label="审核状态"
|
|
||||||
name="auditStatus"
|
|
||||||
value={auditStatus}
|
|
||||||
options={auditStatusOptions}
|
|
||||||
onChange={handleStatusChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DateRangeFilter
|
|
||||||
label="上传时间"
|
|
||||||
startDate={dateFrom}
|
|
||||||
endDate={dateTo}
|
|
||||||
onStartDateChange={(value) => handleDateChange('dateFrom', value)}
|
|
||||||
onEndDateChange={(value) => handleDateChange('dateTo', value)}
|
|
||||||
simple={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</FilterPanel>
|
|
||||||
|
|
||||||
|
|
||||||
{/* 数据表格 */}
|
|
||||||
<Card>
|
|
||||||
<div className="mb-3 flex items-center justify-between">
|
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
type="default"
|
type="primary"
|
||||||
icon="ri-delete-bin-line"
|
icon="ri-upload-line"
|
||||||
onClick={handleBatchDelete}
|
to="/files/upload"
|
||||||
className="mr-2"
|
className="hover:text-white"
|
||||||
disabled={selectedRowKeys.length === 0}
|
|
||||||
>
|
>
|
||||||
批量删除
|
上传文档
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
icon="ri-download-line"
|
|
||||||
onClick={handleExport}
|
|
||||||
>
|
|
||||||
导出列表
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className="text-sm text-secondary">
|
|
||||||
共 <span className="font-medium text-primary">{total}</span> 条记录
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="overflow-x-auto">
|
{/* 搜索筛选区 */}
|
||||||
<Table
|
<FilterPanel
|
||||||
columns={columns}
|
actions={
|
||||||
dataSource={documents}
|
<>
|
||||||
rowKey="id"
|
<Button
|
||||||
emptyText="暂无数据"
|
type="default"
|
||||||
|
icon="ri-refresh-line"
|
||||||
|
onClick={handleReset}
|
||||||
|
className="mr-2"
|
||||||
|
>
|
||||||
|
重置
|
||||||
|
</Button>
|
||||||
|
{/* <Button
|
||||||
|
type="primary"
|
||||||
|
icon="ri-search-line"
|
||||||
|
onClick={() => {
|
||||||
|
// 保持当前筛选条件,刷新数据
|
||||||
|
// 在实际应用中,这里可能需要触发某些操作
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
搜索
|
||||||
|
</Button> */}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
noActionDivider={true}
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 w-full">
|
||||||
|
<SearchFilter
|
||||||
|
label="文档名称"
|
||||||
|
placeholder="请输入文档名称"
|
||||||
|
value={search}
|
||||||
|
onSearch={handleNameSearch}
|
||||||
|
instantSearch={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SearchFilter
|
||||||
|
label="文档编号"
|
||||||
|
placeholder="请输入文档编号"
|
||||||
|
value={documentNumber}
|
||||||
|
onSearch={handleDocumentNumberChange}
|
||||||
|
instantSearch={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FilterSelect
|
||||||
|
label="文档类型"
|
||||||
|
name="documentType"
|
||||||
|
value={documentType}
|
||||||
|
options={documentTypeOptions}
|
||||||
|
onChange={handleDocumentTypeChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FilterSelect
|
||||||
|
label="文件状态"
|
||||||
|
name="fileStatus"
|
||||||
|
value={fileStatus}
|
||||||
|
options={fileStatusOptions}
|
||||||
|
onChange={handleFileStatusChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FilterSelect
|
||||||
|
label="审核状态"
|
||||||
|
name="auditStatus"
|
||||||
|
value={auditStatus}
|
||||||
|
options={auditStatusOptions}
|
||||||
|
onChange={handleStatusChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DateRangeFilter
|
||||||
|
label="上传时间"
|
||||||
|
startDate={dateFrom}
|
||||||
|
endDate={dateTo}
|
||||||
|
onStartDateChange={(value) => handleDateChange('dateFrom', value)}
|
||||||
|
onEndDateChange={(value) => handleDateChange('dateTo', value)}
|
||||||
|
simple={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FilterPanel>
|
||||||
|
|
||||||
|
|
||||||
|
{/* 数据表格 */}
|
||||||
|
<Card>
|
||||||
|
<div className="mb-3 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
icon="ri-delete-bin-line"
|
||||||
|
onClick={handleBatchDelete}
|
||||||
|
className="mr-2"
|
||||||
|
disabled={selectedRowKeys.length === 0}
|
||||||
|
>
|
||||||
|
批量删除
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
icon="ri-download-line"
|
||||||
|
onClick={handleExport}
|
||||||
|
>
|
||||||
|
导出列表
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-secondary">
|
||||||
|
共 <span className="font-medium text-primary">{total}</span> 条记录
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
dataSource={documents}
|
||||||
|
rowKey="id"
|
||||||
|
emptyText="暂无数据"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 分页 */}
|
||||||
|
<Pagination
|
||||||
|
currentPage={currentPage}
|
||||||
|
total={total}
|
||||||
|
pageSize={pageSize}
|
||||||
|
onChange={handlePageChange}
|
||||||
|
onPageSizeChange={handlePageSizeChange}
|
||||||
|
pageSizeOptions={[10, 20, 50, 100]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Card>
|
||||||
|
</div>
|
||||||
{/* 分页 */}
|
|
||||||
<Pagination
|
|
||||||
currentPage={currentPage}
|
|
||||||
total={total}
|
|
||||||
pageSize={pageSize}
|
|
||||||
onChange={handlePageChange}
|
|
||||||
onPageSizeChange={handlePageSizeChange}
|
|
||||||
pageSizeOptions={[10, 20, 50, 100]}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import {
|
|||||||
// 从ReviewPointsList组件中导入ReviewPoint类型
|
// 从ReviewPointsList组件中导入ReviewPoint类型
|
||||||
import { type ReviewPoint } from '~/components/reviews';
|
import { type ReviewPoint } from '~/components/reviews';
|
||||||
import { messageService } from "~/components/ui/MessageModal";
|
import { messageService } from "~/components/ui/MessageModal";
|
||||||
|
import { Button } from "~/components/ui/Button";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -485,7 +486,10 @@ export default function ReviewDetails() {
|
|||||||
<>
|
<>
|
||||||
{/* 文件信息和操作按钮 */}
|
{/* 文件信息和操作按钮 */}
|
||||||
<FileInfo
|
<FileInfo
|
||||||
fileInfo={reviewData.fileInfo}
|
fileInfo={{
|
||||||
|
...reviewData.fileInfo,
|
||||||
|
previousRoute: loaderData.previousRoute
|
||||||
|
}}
|
||||||
onConfirmResults={handleConfirmResults}
|
onConfirmResults={handleConfirmResults}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user