diff --git a/components/canvas/CanvasChatPanel.tsx b/components/canvas/CanvasChatPanel.tsx index 2dbae2d2d..6bded23fd 100644 --- a/components/canvas/CanvasChatPanel.tsx +++ b/components/canvas/CanvasChatPanel.tsx @@ -376,6 +376,9 @@ const CLAWD_TABLE_MAX_BYTES = 10 * 1024 * 1024; const CLAWD_PROCESSING_HINT = "已收到,这个任务稍微繁重一些,处理时间可能会长一点,请耐心等候。"; const CLAWD_SUBMITTED_COMPOSER_RECOVERY_TTL_MS = 30 * 60 * 1000; +const CLAWD_SUBMITTED_COMPOSER_RESTORE_GUARD_DELAYS_MS = [ + 0, 80, 180, 360, 700, 1200, 2000, 3500, 6000, 10000, +]; const CLAWD_SUBMITTED_COMPOSER_STORAGE_KEY = "ai-chatbot:clawd-submitted-composer"; const CLAWD_SIMPLE_PROMPT_PATTERNS = [ @@ -2467,28 +2470,79 @@ export function CanvasChatPanel({ isClawdSubmissionForCurrentComposer, ]); + const scheduleClearRestoredClawdComposerText = useCallback(() => { + if (typeof window === "undefined") return; + CLAWD_SUBMITTED_COMPOSER_RESTORE_GUARD_DELAYS_MS.forEach((delay) => { + window.setTimeout(clearRestoredClawdComposerText, delay); + }); + }, [clearRestoredClawdComposerText]); + useEffect(() => { if (typeof window === "undefined") return; - const clearAfterRestore = () => { - [0, 120, 500, 1500].forEach((delay) => { - window.setTimeout(clearRestoredClawdComposerText, delay); - }); - }; const handleVisibilityChange = () => { if (document.visibilityState === "visible") { - clearAfterRestore(); + scheduleClearRestoredClawdComposerText(); } }; document.addEventListener("visibilitychange", handleVisibilityChange); - window.addEventListener("focus", clearAfterRestore); - window.addEventListener("pageshow", clearAfterRestore); + window.addEventListener("focus", scheduleClearRestoredClawdComposerText); + window.addEventListener("pageshow", scheduleClearRestoredClawdComposerText); return () => { document.removeEventListener("visibilitychange", handleVisibilityChange); - window.removeEventListener("focus", clearAfterRestore); - window.removeEventListener("pageshow", clearAfterRestore); + window.removeEventListener("focus", scheduleClearRestoredClawdComposerText); + window.removeEventListener("pageshow", scheduleClearRestoredClawdComposerText); + }; + }, [scheduleClearRestoredClawdComposerText]); + + useEffect(() => { + if (typeof window === "undefined" || typeof MutationObserver === "undefined") { + return; + } + + let observedEditor: HTMLDivElement | null = null; + let observer: MutationObserver | null = null; + let scheduled = false; + let scheduledTimer: number | null = null; + + const scheduleMutationCheck = () => { + if (scheduled) return; + scheduled = true; + scheduledTimer = window.setTimeout(() => { + scheduled = false; + scheduledTimer = null; + clearRestoredClawdComposerText(); + }, 0); + }; + + const observeCurrentEditor = () => { + const editableDiv = textareaRef.current as HTMLDivElement | null; + if (editableDiv === observedEditor) return; + + observer?.disconnect(); + observer = null; + observedEditor = editableDiv; + + if (!editableDiv) return; + observer = new MutationObserver(scheduleMutationCheck); + observer.observe(editableDiv, { + childList: true, + characterData: true, + subtree: true, + }); + }; + + observeCurrentEditor(); + const observerRefreshTimer = window.setInterval(observeCurrentEditor, 1000); + + return () => { + observer?.disconnect(); + window.clearInterval(observerRefreshTimer); + if (scheduledTimer !== null) { + window.clearTimeout(scheduledTimer); + } }; }, [clearRestoredClawdComposerText]); @@ -10050,9 +10104,7 @@ export function CanvasChatPanel({ ]) ); clearComposerEditor(); - [0, 120, 500, 1500].forEach((delay) => { - window.setTimeout(clearRestoredClawdComposerText, delay); - }); + scheduleClearRestoredClawdComposerText(); setAttachments([]); setClawdTableFiles([]); setSelectedSkillTagId(null); @@ -10513,7 +10565,7 @@ export function CanvasChatPanel({ setSendGuard, setMessages, clearComposerEditor, - clearRestoredClawdComposerText, + scheduleClearRestoredClawdComposerText, shouldBlockDuplicateSend, status, mutate, @@ -14232,6 +14284,9 @@ export function CanvasChatPanel({ activeClawdSubmission, textContent ); + if (isRestoredSubmittedClawdText) { + scheduleClearRestoredClawdComposerText(); + } if (!isRestoredSubmittedClawdText) { composerUserEditedAtRef.current = Date.now(); }