新增提示Toast组件

This commit is contained in:
2025-04-21 09:22:13 +08:00
parent 01d93522b8
commit 5c2c367856
36 changed files with 2609 additions and 478 deletions
+53 -28
View File
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useEffect } 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";
@@ -12,6 +12,7 @@ import documentsIndexStyles from "~/styles/pages/documents_index.css?url";
import { getDocuments, deleteDocument, type DocumentUI } from "~/api/files/documents";
import { getDocumentTypes } from "~/api/document-types/document-types";
import { updateDocumentAuditStatus } from "~/api/evaluation_points/rules-files";
import { toastService } from "~/components/ui/Toast";
// 导入样式
export function links() {
@@ -80,6 +81,12 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
});
};
// 定义action返回的数据类型
interface ActionResponse {
success: boolean;
message: string;
}
// 处理表单提交和删除等操作
export const action = async ({ request }: ActionFunctionArgs) => {
const formData = await request.formData();
@@ -92,7 +99,6 @@ export const action = async ({ request }: ActionFunctionArgs) => {
if (response.error) {
return Response.json({ success: false, message: response.error }, { status: response.status || 500 });
}
return Response.json({ success: true, message: "文档已成功删除" });
}
@@ -109,7 +115,7 @@ export const action = async ({ request }: ActionFunctionArgs) => {
message: `删除失败: ${failures.map(f => f.error).join(', ')}`
}, { status: 400 });
}
return Response.json({ success: true, message: `已成功删除${ids.length}个文档` });
}
@@ -133,6 +139,7 @@ const fileProcessingStatusOptions = [
{ value: "Cutting", label: "切分中", icon: "ri-loader-line", color: "purple" },
{ value: "Extractioning", label: "抽取中", icon: "ri-loader-line", color: "cyan" },
{ value: "Evaluationing", label: "评查中", icon: "ri-loader-line", color: "teal" },
{ value: "Failed", label: "抽取异常", icon: "ri-close-circle-line", color: "red" },
{ value: "Processed", label: "已完成", icon: "ri-check-line", color: "green" },
];
@@ -143,6 +150,7 @@ const fileStatusOptions = [
{ value: "Cutting", label: "切分中" },
{ value: "Extractioning", label: "抽取中" },
{ value: "Evaluationing", label: "评查中" },
{ value: "Failed", label: "抽取异常" },
{ value: "Processed", label: "已完成" },
];
@@ -182,7 +190,7 @@ export default function DocumentsIndex() {
const [searchParams, setSearchParams] = useSearchParams();
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const loaderData = useLoaderData<typeof loader>();
const fetcher = useFetcher();
const fetcher = useFetcher<ActionResponse>();
const navigate = useNavigate();
// 从URL获取当前筛选条件
@@ -363,27 +371,26 @@ export default function DocumentsIndex() {
// 删除文档
const handleDelete = (id: string, name: string, fileStatus: string) => {
if (fileStatus !== 'Processed') {
alert('文档正在处理中,不能删除');
// 禁止删除处理中的文件
if (fileStatus !== "Processed" && fileStatus !== "Failed") {
toastService.warning("文件正在处理中,无法删除");
return;
}
if (window.confirm(`确认删除文档 "${name}"`)) {
// 使用fetcher提交表单
const formData = new FormData();
formData.append('_action', 'delete');
formData.append('id', id);
if (confirm(`确定要删除文档"${name}"吗?`)) {
const form = new FormData();
form.append("_action", "delete");
form.append("id", id);
fetcher.submit(formData, { method: 'post' });
// 更新选中行
setSelectedRowKeys(selectedRowKeys.filter(key => key !== id));
fetcher.submit(form, { method: "post" });
}
};
// 批量删除
const handleBatchDelete = () => {
if (selectedRowKeys.length === 0) {
alert('请至少选择一个文档');
// alert('请至少选择一个文档');
toastService.error('请至少选择一个文档');
return;
}
@@ -393,7 +400,8 @@ export default function DocumentsIndex() {
);
if (hasProcessingFiles) {
alert('存在服务器未处理完成的文件,请重新选择需要删除的文件');
// alert('存在服务器未处理完成的文件,请重新选择需要删除的文件');
toastService.error('存在服务器未处理完成的文件,请重新选择需要删除的文件');
return;
}
@@ -430,7 +438,8 @@ export default function DocumentsIndex() {
const handleExport = async () => {
// 如果没有文档,显示提示信息
if (documents.length === 0) {
alert('当前页面没有文档可供导出');
// alert('当前页面没有文档可供导出');
toastService.error('当前页面没有文档可供导出');
return;
}
@@ -480,7 +489,8 @@ export default function DocumentsIndex() {
const failed = results.filter(r => r && !r.success).length;
if (succeeded === 0) {
alert('所有文件下载失败');
// alert('所有文件下载失败');
toastService.error('所有文件下载失败');
return;
}
@@ -503,36 +513,51 @@ export default function DocumentsIndex() {
// 显示结果消息
if (failed > 0) {
alert(`成功导出 ${succeeded} 个文件,${failed} 个文件失败`);
// alert(`成功导出 ${succeeded} 个文件,${failed} 个文件失败`);
toastService.warning(`成功导出 ${succeeded} 个文件,${failed} 个文件失败`);
} else {
alert(`成功导出 ${succeeded} 个文件`);
// alert(`成功导出 ${succeeded} 个文件`);
toastService.success(`成功导出 ${succeeded} 个文件`);
}
} catch (error) {
console.error('导出文件失败:', error);
alert(`导出文件失败: ${error instanceof Error ? error.message : '未知错误'}`);
// alert(`导出文件失败: ${error instanceof Error ? error.message : '未知错误'}`);
toastService.error(`导出文件失败: ${error instanceof Error ? error.message : '未知错误'}`);
}
};
// 开始审核
const handleReviewFileClick = async (fileId: number, auditStatus: number | null) => {
// 检查audit_status是否为0,如果是则更新为2
if (auditStatus === 0) {
if (auditStatus === 0 || auditStatus === null) {
try {
const response = await updateDocumentAuditStatus(fileId.toString(), 2);
if (response.error) {
console.error('更新文件审核状态失败:', response.error);
alert('更新文件审核状态失败:' + (response.error || '未知错误'));
// alert('更新文件审核状态失败:' + (response.error || '未知错误'));
toastService.error('更新文件审核状态失败:' + (response.error || '未知错误'));
}
} catch (error) {
console.error('更新文件审核状态时出错:', error);
alert('更新文件审核状态时出错:' + (error instanceof Error ? error.message : '未知错误'));
// alert('更新文件审核状态时出错:' + (error instanceof Error ? error.message : '未知错误'));
toastService.error('更新文件审核状态时出错:' + (error instanceof Error ? error.message : '未知错误'));
}
}
// 导航到评查详情页
navigate(`/reviews?id=${fileId}`);
navigate(`/reviews?id=${fileId}&previousRoute=documents`);
};
// 使用useEffect监听fetcher状态变化并显示Toast
useEffect(() => {
if (fetcher.data && fetcher.state === 'idle') {
if (fetcher.data.success) {
toastService.success(fetcher.data.message);
} else if (fetcher.data.message) {
toastService.error(fetcher.data.message);
}
}
}, [fetcher.data, fetcher.state]);
// 表格列定义
const columns = [
@@ -610,7 +635,7 @@ export default function DocumentsIndex() {
const fileStatus = record.fileStatus || "-";
const status = fileProcessingStatusOptions.find(s => s.value === fileStatus) ||
fileProcessingStatusOptions[0];
const isSpinning = fileStatus !== "Processed";
const isSpinning = fileStatus !== "Processed" && fileStatus !== "Failed";
return (
<div className={`inline-flex items-center px-2 py-1 rounded-full text-xs bg-${status.color}-100 text-${status.color}-800`}>
<i className={`${status.icon} ${isSpinning ? "animate-spin" : ""} mr-1`}></i>
@@ -680,7 +705,7 @@ export default function DocumentsIndex() {
</Link>
) : (
<Link
to={`/reviews?id=${record.id}`}
to={`/reviews?id=${record.id}&previousRoute=documents`}
className="mr-1 hover:underline"
>
<i className="ri-eye-line"></i>