"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(() => { const controller = new AbortController(); let checking = false; const check = async () => { if (checking || document.visibilityState !== "visible") return; checking = true; try { const response = await fetch("/api/app-version", { cache: "no-store", signal: AbortSignal.any([controller.signal, AbortSignal.timeout(8000)]) }); if (!response.ok) return; const data = await response.json(); if (!controller.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 { checking = false; } }; void check(); const interval = window.setInterval(check, 60_000); window.addEventListener("focus", check); document.addEventListener("visibilitychange", check); return () => { controller.abort(); clearInterval(interval); window.removeEventListener("focus", 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}
; }