import { type MetaFunction, type LoaderFunctionArgs } from "@remix-run/node"; import { useLoaderData, useSearchParams, useNavigate } from "@remix-run/react"; import { useEffect } from "react"; import { Button } from "~/components/ui/Button"; import { Card } from "~/components/ui/Card"; import { FileIcon } from "~/components/ui/FileIcon"; import { FilterPanel, FilterSelect, SearchFilter, DateRangeFilter } from "~/components/ui/FilterPanel"; import { Pagination } from "~/components/ui/Pagination"; import { Table } from "~/components/ui/Table"; import { Tag } from "~/components/ui/Tag"; import { StatusBadge } from "~/components/ui/StatusBadge"; import rulesFilesStyles from "~/styles/pages/rules-files.css?url"; import { getReviewFiles, type ReviewFileUI, updateDocumentAuditStatus } from "~/api/evaluation_points/rules-files"; import { getDocumentTypes } from "~/api/document-types/document-types"; import { toastService } from "~/components/ui/Toast"; // 导入axios下载文件方法 import { downloadFile } from "~/api/axios-client"; export const links = () => [ { rel: "stylesheet", href: rulesFilesStyles } ]; export const handle = { breadcrumb: "评查文件列表" }; export const meta: MetaFunction = () => { return [ { title: "评查文件列表 - 中国烟草AI合同及卷宗审核系统" }, { name: "description", content: "管理系统中所有上传的评查文件,支持按文件类型、评查状态进行筛选" }, { name: "keywords", content: "评查文件,合同审核,中国烟草,文件管理" } ]; }; // 日期范围枚举 export enum DateRange { ALL = 'all', TODAY = 'today', WEEK = 'week', MONTH = 'month', CUSTOM = 'custom' } // 评查状态标签映射 export const REVIEW_STATUS_LABELS: Record = { 'pass': '通过', 'warning': '警告', 'fail': '不通过', 'pending': '待人工确认' }; // 加载评查文件列表 export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const fileType = url.searchParams.get("fileType") || ""; const reviewStatus = url.searchParams.get("reviewStatus") || ""; const dateRange = url.searchParams.get("dateRange") || ""; const dateFrom = url.searchParams.get("dateFrom") || ""; const dateTo = url.searchParams.get("dateTo") || ""; const keyword = url.searchParams.get("keyword") || ""; const sortOrder = url.searchParams.get("sortOrder") || "upload_time_desc"; const currentPage = parseInt(url.searchParams.get("page") || "1", 10); const pageSize = parseInt(url.searchParams.get("pageSize") || "10", 10); try { // 获取文档类型列表 const typesResponse = await getDocumentTypes({pageSize:500}); const documentTypes = typesResponse.data?.types || []; // 获取文件列表 const searchParams = { fileType, reviewStatus, dateRange, dateFrom, dateTo, keyword, sortOrder, page: currentPage, pageSize, }; // console.log('rules-filessearchParams-----',searchParams); const filesResponse = await getReviewFiles(searchParams); if (filesResponse.error) { console.error('获取评查文件列表失败:', filesResponse.error); return Response.json({ result: false, message: filesResponse.error }, { status: filesResponse.status || 500 }); } const files = filesResponse.data?.files || []; const totalCount = filesResponse.data?.total || 0; return Response.json({ files, documentTypes, totalCount, currentPage, pageSize, }); } catch (error) { console.error('加载评查文件列表失败:', error); return Response.json({ result: false, message: error instanceof Error ? error.message : '加载评查文件列表失败' }, { status: 500 }); } } export default function RulesFiles() { const navigate = useNavigate(); const { files, documentTypes, totalCount, currentPage, pageSize, result, message } = useLoaderData(); const [searchParams, setSearchParams] = useSearchParams(); const dateFrom = searchParams.get('dateFrom') || ''; const dateTo = searchParams.get('dateTo') || ''; // 处理初始加载数据loader的错误 useEffect(() => { if(result === false && message) { toastService.error(message); } }, [result, message]); // 处理筛选条件变更 const handleFilterChange = (e: React.ChangeEvent) => { const { name, value } = e.target; const newParams = new URLSearchParams(searchParams); if (value) { newParams.set(name, value); } else { newParams.delete(name); } // 切换筛选条件时,重置到第一页 newParams.set('page', '1'); setSearchParams(newParams); }; // 处理搜索操作 const handleSearch = (keyword: string) => { const newParams = new URLSearchParams(searchParams); if (keyword) { newParams.set('keyword', keyword); } else { newParams.delete('keyword'); } // 搜索时,重置到第一页 newParams.set('page', '1'); setSearchParams(newParams); }; // 处理页码变更 const handlePageChange = (page: number) => { const newParams = new URLSearchParams(searchParams); newParams.set('page', page.toString()); setSearchParams(newParams); }; // 处理每页条数变更 const handlePageSizeChange = (size: number) => { const newParams = new URLSearchParams(searchParams); newParams.set('pageSize', size.toString()); newParams.set('page', '1'); // 改变每页条数时重置为第一页 setSearchParams(newParams); }; // 查看评查文件 const handleReviewFileClick = async (fileId: string, auditStatus: number | null) => { // 检查audit_status是否为0,如果是则更新为2 if (auditStatus === 0 || auditStatus === null) { try { const response = await updateDocumentAuditStatus(fileId, 2); if (response.error) { throw new Error(response.error); } } catch (error) { console.error('更新文件审核状态时出错:', error); toastService.error(`更新文件审核状态时出错:${error instanceof Error ? error.message : '未知错误'}`); return; } } // 导航到评查详情页 navigate(`/reviews?id=${fileId}&previousRoute=rulesFiles`); }; // 渲染问题摘要 const renderIssues = (file: ReviewFileUI) => { // 如果文件状态为完成 if (file.status === 'Processed') { // 如果没有问题,显示"所有评查点均通过" if (file.warningCount <= 0 && file.failCount <= 0) { return (
所有评查点均通过
); } // 如果评查状态为不通过,显示"统计分数为:{file.score || 0}。分数低于80分。" // if (file.reviewStatus === 'fail') { // return ( //
// 统计分数为:{file.score || 0}。分数低于80分。 //
// ); // } // 显示问题列表 if (file.issues && file.issues.length > 0) { // 最多显示2个问题 const displayIssues = file.issues.slice(0, 2); return (
{displayIssues.map((issue, index) => (
{issue.message}
))} {file.issues.length > 2 && (
还有 {file.issues.length - 2} 个问题...
)}
); } } // 其他状态显示占位符 return
-
; }; // 下载文件 const handleDownload = async (path: string) => { try { // 使用axios封装的下载方法 const blob = await downloadFile(path); // 创建Blob URL const blobUrl = URL.createObjectURL(blob); // 创建一个隐藏的a标签并点击它 const a = document.createElement('a'); a.style.display = 'none'; a.href = blobUrl; // 从路径中获取文件名 const fileName = path.split('/').pop() || 'document'; a.download = decodeURIComponent(fileName); document.body.appendChild(a); a.click(); // 清理 setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(blobUrl); }, 100); } catch (error) { console.error('下载文件失败:', error); toastService.error(`下载文件失败: ${error instanceof Error ? error.message : '未知错误'}`); } }; // 处理时间范围变更 const handleDateChange = (field: 'dateFrom' | 'dateTo', value: string) => { const newParams = new URLSearchParams(searchParams); if(value) { newParams.set(field, value); } else { newParams.delete(field); } newParams.set('page', '1'); setSearchParams(newParams); }; const handleReset = () => { const newParams = new URLSearchParams(); const searchInput = document.querySelector('input[name="keyword"]'); if(searchInput) { (searchInput as HTMLInputElement).value = ''; } setSearchParams(newParams); }; // 文件类型选项 const fileTypeOptions = documentTypes.map((type: {id: number, name: string}) => ({ value: type.id.toString(), label: type.name })); // 定义表格列配置 const columns = [ { title: "文件名称", key: "fileName", width: "30%", render: (_: unknown, file: ReviewFileUI) => (
{file.fileName}
文件编号:{file.fileCode}
) }, { title: "文件类型", key: "fileType", width: "12%", render: (_: unknown, file: ReviewFileUI) => ( {file.fileType} ) }, { title: "上传时间", key: "uploadTime", width: "12%", render: (_: unknown, file: ReviewFileUI) => { const [date, time] = file.uploadTime.split(' '); return (
{date}
{time}
); } }, { title: "评查统计", key: "reviewStatus", width: "12%", render: (_: unknown, file: ReviewFileUI) => // 要文件切分处理完之后,再显示评查统计 file.status === 'Processed' ? (
{file.passCount > 0 && ( )} {file.warningCount > 0 && ( )} {file.failCount > 0 && ( )} {file.manualCount > 0 && ( )}
) : (
-
) }, { title: "问题摘要", key: "issues", width: "20%", render: (_: unknown, file: ReviewFileUI) => renderIssues(file) }, { title: "操作", key: "operation", width: "14%", render: (_: unknown, file: ReviewFileUI) => ( <> ) } ]; return (
{/* 页面头部 */}

评查文件列表

总文件数: {totalCount}
{/* 筛选区域 */} } > {/* */} {/* */} handleDateChange('dateFrom', value)} onEndDateChange={(value) => handleDateChange('dateTo', value)} simple={true} colorMode="light" /> {/* 文件列表 */} {/* 分页组件 */} {totalCount > 0 && ( )} ); } // 错误边界 export function ErrorBoundary() { return (

出错了

加载评查文件列表时发生错误。请稍后再试,或联系管理员。

); }