'use client'; import { useEffect, useState, useRef, useCallback } from 'react'; import { snapshotApi } from '@/lib/api/snapshot.api'; import type { BackupTarget, SnapshotTask } from '@/types/snapshot.types'; interface TargetProgress { target: BackupTarget; percent: number; message: string; status: 'pending' | 'running' | 'completed' | 'failed'; } interface UseSnapshotPollingReturn { progresses: Map; taskCompleted: boolean; totalSize: string | null; duration: number | null; error: string | null; } const POLL_INTERVAL = 2000; // 2 秒轮询 export function useSnapshotPolling(taskId: string | null): UseSnapshotPollingReturn { const [progresses, setProgresses] = useState>(new Map()); const [taskCompleted, setTaskCompleted] = useState(false); const [totalSize, setTotalSize] = useState(null); const [duration, setDuration] = useState(null); const [error, setError] = useState(null); const timerRef = useRef | null>(null); const updateFromTask = useCallback((task: SnapshotTask) => { // 从 task.details 构建进度 Map const next = new Map(); for (const d of task.details) { const statusMap: Record = { PENDING: 'pending', RUNNING: 'running', COMPLETED: 'completed', FAILED: 'failed', }; next.set(d.target, { target: d.target, percent: d.status === 'COMPLETED' ? 100 : d.progress, message: d.error ? d.error : d.status === 'COMPLETED' ? '完成' : d.status === 'RUNNING' ? `备份中... ${d.progress}%` : '等待中', status: statusMap[d.status] || 'pending', }); } setProgresses(next); // 任务整体完成/失败 → 停止轮询 if (task.status === 'COMPLETED' || task.status === 'FAILED') { setTaskCompleted(true); setTotalSize(task.totalSize); if (task.startedAt && task.completedAt) { setDuration(new Date(task.completedAt).getTime() - new Date(task.startedAt).getTime()); } if (task.error) { setError(task.error); } } }, []); useEffect(() => { if (!taskId) return; // 重置状态 setProgresses(new Map()); setTaskCompleted(false); setTotalSize(null); setDuration(null); setError(null); let stopped = false; const poll = async () => { if (stopped) return; try { const task = await snapshotApi.getById(taskId); if (stopped) return; updateFromTask(task); // 任务结束,停止轮询 if (task.status === 'COMPLETED' || task.status === 'FAILED') { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } } } catch { // 网络错误静默忽略,下次继续轮询 } }; // 立即拉一次 poll(); // 定时轮询 timerRef.current = setInterval(poll, POLL_INTERVAL); return () => { stopped = true; if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } }; }, [taskId, updateFromTask]); return { progresses, taskCompleted, totalSize, duration, error }; }