diff --git a/core/frontend/src/routes/pipeline.tsx b/core/frontend/src/routes/pipeline.tsx index 9d81612..b193f63 100644 --- a/core/frontend/src/routes/pipeline.tsx +++ b/core/frontend/src/routes/pipeline.tsx @@ -1283,19 +1283,22 @@ export function PipelinePage(props: { function persistPending(next: Set) { try { localStorage.setItem(`airshelf:pending-del:${project.id}`, JSON.stringify([...next])); } catch { /* localStorage 不可用就算了 */ } } - function dropPending(id: string) { + function stopDeleteRetry(id: string) { delRetryingRef.current.delete(id); + } + function dropPending(id: string) { + stopDeleteRetry(id); setPendingDeletes((prev) => { if (!prev.has(id)) return prev; const next = new Set(prev); next.delete(id); persistPending(next); return next; }); } async function runDeleteRetry(shotId: string, attempt: number) { try { await api.deleteScriptSegment(project.id, { segment_id: shotId }); - dropPending(shotId); + stopDeleteRetry(shotId); void onRefreshProject(); // 后端已删 → 拉回最新(re-sort 后的镜号) } catch (e) { const status = e instanceof ApiError ? e.status : 0; - if (status === 404) { dropPending(shotId); void onRefreshProject(); return; } // 本来就没了 = 删成 - if (status >= 400 && status < 500) { console.warn("删除被拒(非网络),停重试但按要求不回滚:", status, shotId); delRetryingRef.current.delete(shotId); return; } + if (status === 404) { stopDeleteRetry(shotId); void onRefreshProject(); return; } // 本来就没了 = 删成 + if (status >= 400 && status < 500) { console.warn("删除被拒(非网络),停重试但按要求不回滚:", status, shotId); stopDeleteRetry(shotId); return; } // 网络/5xx → 退避重试(最长 30s),扛到删成 const delay = Math.min(30000, 1000 * 2 ** Math.min(attempt, 5)); window.setTimeout(() => { void runDeleteRetry(shotId, attempt + 1); }, delay); @@ -1320,6 +1323,24 @@ export function PipelinePage(props: { ids.forEach((id) => ensureDeleteRetry(id)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [project.id]); + useEffect(() => { + if (!currentScript || pendingDeletes.size === 0) return; + const liveIds = new Set((currentScript.segments ?? []).map((segment) => segment.id)); + setPendingDeletes((prev) => { + let changed = false; + const next = new Set(prev); + prev.forEach((id) => { + if (!liveIds.has(id)) { + stopDeleteRetry(id); + next.delete(id); + changed = true; + } + }); + if (changed) persistPending(next); + return changed ? next : prev; + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentScript, pendingDeletes]); useEffect(() => { if (!armedDelete) return; const timer = window.setTimeout(() => setArmedDelete(null), 3000);