新增上传队列显示

This commit is contained in:
2026-01-29 16:54:45 +08:00
parent 7e6424e9ac
commit 0a436311c8
5 changed files with 920 additions and 34 deletions
+1
View File
@@ -113,6 +113,7 @@ function getDocumentTypeIdsFromSession(): number[] | null {
export enum DocumentStatus {
waiting = 'waiting',
WAITING = "Waiting",
QUEUED = "Queued", // 排队中
CUTTING = "Cutting",
EXTRACTIONING = "Extractioning",
EVALUATIONING = "Evaluationing",
+59
View File
@@ -0,0 +1,59 @@
// app/api/queue.ts
// 队列状态 API 客户端
import axios from 'axios';
import { API_BASE_URL } from '../config/api-config';
/**
* 队列状态响应接口
*/
export interface QueueStatus {
success: boolean;
timestamp: string;
queue: {
pending_tasks: number;
processing_tasks: number;
available_slots: number;
max_concurrent: number;
};
documents: {
waiting: number; // 排队中的文档数
processing: number; // 处理中的文档数
processing_ids: string[];
};
}
/**
* 获取队列整体状态
* @returns 队列状态信息
*/
export async function getQueueStatus(): Promise<{ data?: QueueStatus; error?: string }> {
try {
// 从 localStorage 获取 token
let token: string | null = null;
if (typeof window !== 'undefined') {
token = localStorage.getItem('access_token');
}
const headers: Record<string, string> = {
'Accept': 'application/json'
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const response = await axios.get<QueueStatus>(
`${API_BASE_URL}/api/v2/system/queue/status`,
{ headers }
);
return { data: response.data };
} catch (error) {
console.error('【队列状态】获取队列状态失败:', error);
if (axios.isAxiosError(error)) {
return { error: error.response?.data?.detail || error.message };
}
return { error: error instanceof Error ? error.message : '获取队列状态失败' };
}
}
+100 -34
View File
@@ -26,6 +26,7 @@ import {
} from "~/api/files/files-upload";
import { updateDocumentAuditStatus } from "~/api/evaluation_points/rules-files";
import { links as fileTypeTagLinks } from "~/components/ui/FileTypeTag";
import { getQueueStatus, type QueueStatus } from "~/api/queue";
export function links() {
return [
@@ -375,6 +376,7 @@ export default function FilesUpload() {
const [uploadStage, setUploadStage] = useState<"idle" | "uploading" | "processing" | "completed" | "hadden">("idle");
const [processingSteps, setProcessingSteps] = useState<Step[]>([
{ title: "文件上传", description: "等待上传文件到服务器...", status: "waiting" },
{ title: "排队等待", description: "等待进入处理队列", status: "waiting" },
{ title: "文档转换拆分", description: "转换文档格式,拆分文档内容", status: "waiting" },
{ title: "评查点抽取", description: "DeepSeek 抽取中", status: "waiting" },
{ title: "评查点审核", description: "DeepSeek 评查中", status: "waiting" },
@@ -385,6 +387,9 @@ export default function FilesUpload() {
// 队列文件状态
const [queueFiles, setQueueFiles] = useState<Document[]>([]);
const [documentTypesState, setDocumentTypesState] = useState<DocumentType[]>([]);
// 全局队列状态(用于显示排队统计)
const [globalQueueStatus, setGlobalQueueStatus] = useState<QueueStatus | null>(null);
// 在组件挂载时从 sessionStorage 获取 documentTypeIds
useEffect(() => {
@@ -543,7 +548,35 @@ export default function FilesUpload() {
}
};
}, []);
// 全局队列状态轮询 - 每10秒获取一次队列统计
useEffect(() => {
// 立即获取一次队列状态
const fetchQueueStatus = async () => {
try {
const response = await getQueueStatus();
if (response.data && isMountedRef.current) {
setGlobalQueueStatus(response.data);
}
} catch (error) {
console.error('获取全局队列状态失败:', error);
}
};
fetchQueueStatus();
// 设置轮询定时器
const intervalId = setInterval(() => {
if (isMountedRef.current) {
fetchQueueStatus();
}
}, 10000);
return () => {
clearInterval(intervalId);
};
}, []);
// 启动状态检查定时器的函数
const startStatusChecker = (files: Document[]) => {
console.log('启动状态检查定时器,队列文件数量:', files.length);
@@ -1677,14 +1710,14 @@ export default function FilesUpload() {
// 更新上传阶段
setUploadStage("processing");
// 更新步骤状态
// 更新步骤状态:上传完成,进入排队等待
const updatedSteps = processingSteps.map(step => ({...step}));
updatedSteps[0].status = "done";
updatedSteps[0].description = "文件已成功上传到服务器";
updatedSteps[1].status = "active";
updatedSteps[1].description = "正在转换文档格式,拆分文档内容...";
updatedSteps[1].description = "文档正在排队等待处理...";
setProcessingSteps(updatedSteps);
// 获取文件ID列表
@@ -1808,13 +1841,14 @@ export default function FilesUpload() {
...step,
status: "done" as Step["status"]
}));
completedSteps[0].description = "文件已成功上传到服务器";
completedSteps[1].description = "文档格式转换完成,内容已拆分";
completedSteps[2].description = "评查点已成功抽取";
completedSteps[3].description = "文档评查已完成";
completedSteps[4].description = "文档已准备就绪,可以查看";
completedSteps[1].description = "已进入处理队列";
completedSteps[2].description = "文档格式转换完成,内容已拆分";
completedSteps[3].description = "评查点已成功抽取";
completedSteps[4].description = "文档评查已完成";
completedSteps[5].description = "文档已准备就绪,可以查看";
setProcessingSteps(completedSteps);
setUploadStage("completed");
} else {
@@ -1834,55 +1868,71 @@ export default function FilesUpload() {
};
// 更新处理步骤状态
// 步骤索引: 0-文件上传, 1-排队等待, 2-文档转换拆分, 3-评查点抽取, 4-评查点审核, 5-审核准备
const updateProcessingSteps = (status: DocumentStatus) => {
// console.log('更新处理步骤状态:', status);
const updatedSteps = [...processingSteps];
// 重置所有步骤为等待状态
updatedSteps.forEach(step => {
step.status = "waiting";
});
// 第一步始终是完成的
// 第一步始终是完成的(文件上传)
updatedSteps[0].status = "done";
updatedSteps[0].description = "文件已成功上传到服务器";
// 根据状态更新步骤
switch (status) {
case DocumentStatus.CUTTING:
case DocumentStatus.QUEUED:
// 排队等待中
updatedSteps[1].status = "active";
updatedSteps[1].description = "正在转换文档格式,拆分文档内容...";
updatedSteps[1].description = "文档正在排队等待处理...";
break;
case DocumentStatus.CUTTING:
// 排队完成,开始转换
updatedSteps[1].status = "done";
updatedSteps[1].description = "已进入处理队列";
updatedSteps[2].status = "active";
updatedSteps[2].description = "正在转换文档格式,拆分文档内容...";
break;
case DocumentStatus.EXTRACTIONING:
updatedSteps[1].status = "done";
updatedSteps[1].description = "文档格式转换完成,内容已拆分";
updatedSteps[2].status = "active";
updatedSteps[2].description = "正在抽取评查点...";
updatedSteps[1].description = "已进入处理队列";
updatedSteps[2].status = "done";
updatedSteps[2].description = "文档格式转换完成,内容已拆分";
updatedSteps[3].status = "active";
updatedSteps[3].description = "正在抽取评查点...";
break;
case DocumentStatus.EVALUATIONING:
updatedSteps[1].status = "done";
updatedSteps[1].description = "文档格式转换完成,内容已拆分";
updatedSteps[1].description = "已进入处理队列";
updatedSteps[2].status = "done";
updatedSteps[2].description = "评查点已成功抽取";
updatedSteps[3].status = "active";
updatedSteps[3].description = "正在评查文档...";
updatedSteps[2].description = "文档格式转换完成,内容已拆分";
updatedSteps[3].status = "done";
updatedSteps[3].description = "评查点已成功抽取";
updatedSteps[4].status = "active";
updatedSteps[4].description = "正在评查文档...";
break;
case DocumentStatus.PROCESSED:
updatedSteps[1].status = "done";
updatedSteps[1].description = "文档格式转换完成,内容已拆分";
updatedSteps[1].description = "已进入处理队列";
updatedSteps[2].status = "done";
updatedSteps[2].description = "评查点已成功抽取";
updatedSteps[2].description = "文档格式转换完成,内容已拆分";
updatedSteps[3].status = "done";
updatedSteps[3].description = "文档评查已完成";
updatedSteps[3].description = "评查点已成功抽取";
updatedSteps[4].status = "done";
updatedSteps[4].description = "文档已准备就绪,可以查看";
updatedSteps[4].description = "文档评查已完成";
updatedSteps[5].status = "done";
updatedSteps[5].description = "文档已准备就绪,可以查看";
break;
}
setProcessingSteps(updatedSteps);
};
@@ -1934,6 +1984,7 @@ export default function FilesUpload() {
// 重置步骤状态
setProcessingSteps([
{ title: "文件上传", description: "等待上传文件到服务器...", status: "waiting" },
{ title: "排队等待", description: "等待进入处理队列", status: "waiting" },
{ title: "文档转换拆分", description: "转换文档格式,拆分文档内容", status: "waiting" },
{ title: "评查点抽取", description: "DeepSeek 抽取中", status: "waiting" },
{ title: "评查点审核", description: "DeepSeek 评查中", status: "waiting" },
@@ -2212,7 +2263,22 @@ export default function FilesUpload() {
<div className="file-upload-page">
{/* 页面头部 */}
<div className="page-header">
<h2 className="page-title"></h2>
<div className="flex items-center gap-4">
<h2 className="page-title"></h2>
{/* 全局队列状态显示 */}
{globalQueueStatus && (
<div className="flex items-center gap-3 text-sm">
<span className="flex items-center gap-1 text-orange-600">
<i className="ri-time-line"></i>
: {globalQueueStatus.documents.waiting}
</span>
<span className="flex items-center gap-1 text-blue-600">
<i className="ri-loader-4-line"></i>
: {globalQueueStatus.documents.processing}
</span>
</div>
)}
</div>
<button className="ant-btn ant-btn-default flex items-center my-2" onClick={()=>handleBackClick()}><i className="ri-arrow-left-line"></i>{isNavigating ? '返回中...' : '返回'}</button>
</div>