新增全局加载进度条组件

This commit is contained in:
2025-04-24 20:51:10 +08:00
parent 65b7d0739a
commit 0eaaa5b041
6 changed files with 340 additions and 144 deletions
+170 -137
View File
@@ -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 { type MetaFunction, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
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 { toastService } from "~/components/ui/Toast";
import { messageService } from "~/components/ui/MessageModal";
import { loadingBarService } from "~/components/ui/LoadingBar";
// 导入样式
export function links() {
@@ -196,6 +197,10 @@ export default function DocumentsIndex() {
const fetcher = useFetcher<ActionResponse>();
const navigate = useNavigate();
// 添加页面加载状态管理
const [isLoadingData, setIsLoadingData] = useState(true);
const dataCache = useRef<typeof loaderData | null>(null);
// 从URL获取当前筛选条件
const search = searchParams.get("search") || "";
const documentType = searchParams.get("documentType") || "";
@@ -210,12 +215,29 @@ export default function DocumentsIndex() {
// 获取API返回的数据
const { documents, total, documentTypeOptions } = loaderData;
// 处理loader错误
// 使用并更新缓存数据
useEffect(() => {
// 如果有缓存数据,先显示缓存,再在后台加载新数据
if (dataCache.current) {
setIsLoadingData(false);
} else {
// 显示加载状态 - 确保显示加载条
loadingBarService.show();
setIsLoadingData(true);
}
// 设置缓存数据
dataCache.current = loaderData;
// 数据加载完成后,执行额外的延迟以确保UI效果
setIsLoadingData(false);
loadingBarService.hide();
// 处理loader错误
if (loaderData.error) {
toastService.error(loaderData.error);
}
}, [loaderData.error]);
}, [loaderData]);
// 使用useEffect监听fetcher状态变化并显示Toast
useEffect(() => {
@@ -564,17 +586,25 @@ export default function DocumentsIndex() {
// 检查audit_status是否为0,如果是则更新为2
if (auditStatus === 0 || auditStatus === null) {
try {
// 显示加载状态
loadingBarService.show();
const response = await updateDocumentAuditStatus(fileId.toString(), 2);
if (response.error) {
console.error('更新文件审核状态失败:', response.error);
// alert('更新文件审核状态失败:' + (response.error || '未知错误'));
toastService.error('更新文件审核状态失败:' + (response.error || '未知错误'));
loadingBarService.hide();
return;
}
} catch (error) {
console.error('更新文件审核状态时出错:', error);
// alert('更新文件审核状态时出错:' + (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 (
<div className="documents-page">
{/* 页面头部 */}
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-medium"></h2>
<div>
<Button
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 className="documents-page relative">
{/* 页面内容,在加载时降低不透明度但不隐藏内容 */}
<div className={isLoadingData ? "opacity-70 pointer-events-none transition-opacity" : "transition-opacity"}>
{/* 页面头部 */}
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-medium"></h2>
<div>
<Button
type="default"
icon="ri-delete-bin-line"
onClick={handleBatchDelete}
className="mr-2"
disabled={selectedRowKeys.length === 0}
type="primary"
icon="ri-upload-line"
to="/files/upload"
className="hover:text-white"
>
</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="暂无数据"
{/* 搜索筛选区 */}
<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>
<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>
{/* 分页 */}
<Pagination
currentPage={currentPage}
total={total}
pageSize={pageSize}
onChange={handlePageChange}
onPageSizeChange={handlePageSizeChange}
pageSizeOptions={[10, 20, 50, 100]}
/>
</Card>
</Card>
</div>
</div>
);
}
+5 -1
View File
@@ -45,6 +45,7 @@ import {
// 从ReviewPointsList组件中导入ReviewPoint类型
import { type ReviewPoint } from '~/components/reviews';
import { messageService } from "~/components/ui/MessageModal";
import { Button } from "~/components/ui/Button";
/**
@@ -485,7 +486,10 @@ export default function ReviewDetails() {
<>
{/* 文件信息和操作按钮 */}
<FileInfo
fileInfo={reviewData.fileInfo}
fileInfo={{
...reviewData.fileInfo,
previousRoute: loaderData.previousRoute
}}
onConfirmResults={handleConfirmResults}
/>