新增提示Toast组件
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user