"use client"; import { useEffect, useMemo, useState } from "react"; import { cn } from "@/lib/utils"; type GenerationPhase = "idle" | "queued" | "processing" | "finalizing" | "failed" | "completed"; interface GenerationDotPlaceholderProps { className?: string; title?: string; phase?: GenerationPhase; progress?: number | null; compact?: boolean; showProgress?: boolean; } const PHASE_TITLES: Record = { idle: "正在创建图片", queued: "等待开始生成", processing: "生成初稿中", finalizing: "正在润饰细节", failed: "生成失败", completed: "生成完成", }; const ROTATING_TITLES = ["正在创建图片", "生成初稿中", "正在润饰细节"]; function clampProgress(value: number) { if (!Number.isFinite(value)) return 0; return Math.max(0, Math.min(100, Math.round(value))); } function estimateProgress(phase: GenerationPhase, elapsedMs: number) { if (phase === "completed") return 100; if (phase === "failed") return 100; if (phase === "finalizing") return 96; if (phase === "queued") { return clampProgress(6 + Math.min(12, elapsedMs / 3500)); } if (phase === "processing") { const eased = 1 - Math.exp(-elapsedMs / 85_000); return clampProgress(18 + eased * 78); } return clampProgress(Math.min(8, elapsedMs / 1000)); } export function GenerationDotPlaceholder({ className, title, phase = "processing", progress, compact = false, showProgress = true, }: GenerationDotPlaceholderProps) { const [elapsedMs, setElapsedMs] = useState(0); useEffect(() => { const startedAt = Date.now(); const timer = window.setInterval(() => { setElapsedMs(Date.now() - startedAt); }, 600); return () => window.clearInterval(timer); }, [phase]); const resolvedProgress = clampProgress( typeof progress === "number" ? progress : estimateProgress(phase, elapsedMs) ); const rotatingTitle = ROTATING_TITLES[Math.floor(elapsedMs / 3200) % ROTATING_TITLES.length]; const resolvedTitle = title || (phase === "processing" ? rotatingTitle : PHASE_TITLES[phase]); const dotOpacity = phase === "failed" ? 0.22 : 0.34; const progressStyle = useMemo( () => ({ width: `${resolvedProgress}%` }), [resolvedProgress] ); return (
{resolvedTitle}
{showProgress ? (
{phase === "failed" ? "已停止" : "生成进度"} {resolvedProgress}%
) : null}
); }