import { type MetaFunction, type LoaderFunctionArgs } from "@remix-run/node"; import { useLoaderData, useSearchParams, useNavigate } from "@remix-run/react"; import { Button } from "~/components/ui/Button"; import { Card } from "~/components/ui/Card"; import { FileIcon } from "~/components/ui/FileIcon"; import { FilterPanel, FilterSelect, SearchFilter } 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"; 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 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, keyword, sortOrder, page: currentPage, pageSize, }; console.log('rules-filessearchParams-----',searchParams); const filesResponse = await getReviewFiles(searchParams); if (filesResponse.error) { console.error('获取评查文件列表失败:', filesResponse.error); throw new Response('获取评查文件列表失败', { 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); throw new Response('加载评查文件列表失败', { status: 500 }); } } // 提取renderErrorBoundary函数作为命名导出 export function ErrorBoundary() { return (

出错了

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

); } // 在文件中定义一个与路由文件名匹配的命名函数组件 export default function RulesFiles() { const { files, documentTypes, totalCount, currentPage, pageSize } = useLoaderData(); const [searchParams, setSearchParams] = useSearchParams(); const navigate = useNavigate(); // 处理筛选条件变更 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) { console.error('更新文件审核状态失败:', response.error); // 尽管更新失败,仍然导航到文件详情页 } } catch (error) { console.error('更新文件审核状态时出错:', error); // 尽管发生错误,仍然导航到文件详情页 } } // 导航到评查详情页 navigate(`/reviews?id=${fileId}&previousRoute=rulesFiles`); }; // 渲染问题摘要 const renderIssues = (file: ReviewFileUI) => { // 如果评查状态为通过(说明所有评查结果为true),显示"所有评查点均通过" if (file.status === 'Processed') { if (file.reviewStatus === 'pass') { return (
所有评查点均通过
); } // 如果评查状态为通过,显示"所有评查点均通过" if (file.reviewStatus === 'fail') { return (
统计分数为:{file.score || 0}。分数低于80分。
); } // 显示问题列表 if (file.reviewStatus !== 'pass' && file.reviewStatus !== 'fail' && 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 { const urlBefore = 'http://172.18.0.100:9000/docauditai/'; const downloadUrl = `${urlBefore}${path}`; // 使用fetch获取文件内容 const response = await fetch(downloadUrl); if (!response.ok) { throw new Error(`下载失败: ${response.status} ${response.statusText}`); } // 将响应转换为Blob const blob = await response.blob(); // 创建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); alert(`下载文件失败: ${error instanceof Error ? error.message : '未知错误'}`); } }; // 文件类型选项 const fileTypeOptions = documentTypes.map((type: {id: number, name: string}) => ({ value: type.id.toString(), label: type.name })); // 评查状态选项 const reviewStatusOptions = [ { value: 'pass', label: '通过' }, { value: 'warning', label: '警告' }, { value: 'fail', label: '不通过' }, { value: 'pending', label: '待人工确认' } ]; // 时间范围选项 const dateRangeOptions = [ { value: DateRange.TODAY, label: '今天' }, { value: DateRange.WEEK, label: '本周' }, { value: DateRange.MONTH, label: '本月' }, // { value: DateRange.CUSTOM, label: '自定义时间段' } ]; // 定义表格列配置 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' ? ( 0?'('+file.issueCount+')':''}`} showIcon={true} /> ) : (
-
) }, { title: "问题摘要", key: "issues", width: "20%", render: (_: unknown, file: ReviewFileUI) => renderIssues(file) }, { title: "操作", key: "operation", width: "14%", render: (_: unknown, file: ReviewFileUI) => ( <> ) } ]; return (
{/* 页面头部 */}

评查文件列表

总文件数: {totalCount}
{/* 筛选区域 */} {/* 文件列表 */} {/* 分页组件 */} {totalCount > 0 && ( )} ); }