"use client"; import { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter } from "@/components/ui/alert-dialog"; import { preparePageRefresh } from "@/lib/client/page-refresh"; export function AppUpdateNotice() { const [availableVersion, setAvailableVersion] = useState(""); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(""); useEffect(() => { let disposed = false; let controller: AbortController | undefined; let checking = false; const check = async () => { if (disposed || checking || document.visibilityState !== "visible") return; checking = true; controller = new AbortController(); const current = controller; const timeout = window.setTimeout(() => current.abort(), 8000); try { const response = await fetch("/api/app-version", { cache: "no-store", signal: current.signal }); if (!response.ok) return; const data = await response.json(); if (!disposed && !current.signal.aborted && typeof data.version === "string" && data.version) setAvailableVersion(data.version !== (process.env.NEXT_PUBLIC_APP_RELEASE || "development") ? data.version : ""); } catch { // A failed version read leaves the current workspace available. } finally { window.clearTimeout(timeout); checking = false; } }; void check(); const interval = window.setInterval(check, 60_000); window.addEventListener("focus", check); window.addEventListener("online", check); document.addEventListener("visibilitychange", check); return () => { disposed = true; controller?.abort(); clearInterval(interval); window.removeEventListener("focus", check); window.removeEventListener("online", check); document.removeEventListener("visibilitychange", check); }; }, []); const refresh = async () => { if (refreshing) return; setRefreshing(true); setError(""); try { await preparePageRefresh(); window.location.reload(); setRefreshing(false); } catch (cause) { setError(cause instanceof Error ? cause.message : "当前内容同步失败,请保留此页并重试。"); setRefreshing(false); } }; return event.preventDefault()}> 平台已更新 需要刷新页面后继续使用。点击后会先同步当前画布并保留输入;正在处理的任务完成后再刷新。 {error ?

{error}

: null}
; }