import { ArrowLeft } from 'lucide-react'; import type { CustomWorldGenerationProgress } from '../../packages/shared/src/contracts/runtime'; import type { CustomWorldStructuredAnchorEntry } from '../services/customWorldAgentGenerationProgress'; import { GenerationCurrentStepCard, GenerationPageBackdrop, GenerationProgressHero, } from './GenerationProgressHero'; interface CustomWorldGenerationViewProps { settingText: string; anchorEntries?: CustomWorldStructuredAnchorEntry[]; progress: CustomWorldGenerationProgress | null; isGenerating: boolean; error?: string | null; onBack: () => void; onEditSetting: () => void; onRetry: () => void; onInterrupt?: () => void; backLabel?: string; settingActionLabel?: string | null; retryLabel?: string; interruptLabel?: string; settingTitle?: string; settingDescription?: string | null; progressTitle?: string; activeBadgeLabel?: string; pausedBadgeLabel?: string; idleBadgeLabel?: string; structuredEmptyText?: string; hideBatchModule?: boolean; } function formatDuration(ms: number) { const safeMs = Math.max(0, Math.round(ms)); const totalSeconds = Math.ceil(safeMs / 1000); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; if (minutes <= 0) { return `${Math.max(1, seconds)} 秒`; } if (seconds === 0) { return `${minutes} 分钟`; } return `${minutes} 分 ${seconds} 秒`; } function getProgressPercentage(progress: CustomWorldGenerationProgress | null) { return Math.max(0, Math.min(100, progress?.overallProgress ?? 0)); } function getStepProgressPercentage(step: { completed: number; total: number; status: string; }) { if (step.status === 'completed') { return 100; } if (step.total <= 0) { return 0; } return Math.max( 0, Math.min(100, Math.round((step.completed / step.total) * 100)), ); } function getStepStatusLabel(step: { status: string }) { if (step.status === 'completed') { return '完成'; } if (step.status === 'active') { return '进行中'; } return '待处理'; } function resolveCurrentGenerationStep( progress: CustomWorldGenerationProgress | null, ) { const steps = progress?.steps ?? []; return ( steps.find((step) => step.status === 'active') ?? steps[progress?.activeStepIndex ?? -1] ?? steps.find((step) => step.status === 'pending') ?? steps.at(-1) ?? null ); } export function CustomWorldGenerationView({ progress, isGenerating, onBack, onRetry, onInterrupt, backLabel = '返回', retryLabel = '重新开始生成', interruptLabel = '中断世界生成', progressTitle = '生成进度', activeBadgeLabel = '世界建设中', idleBadgeLabel = '等待操作', hideBatchModule = false, }: CustomWorldGenerationViewProps) { void hideBatchModule; const progressValue = getProgressPercentage(progress); const currentStep = resolveCurrentGenerationStep(progress); const currentStepProgress = currentStep ? getStepProgressPercentage(currentStep) : progressValue; const currentStepLabel = currentStep?.label ?? progress?.phaseLabel ?? '准备生成'; const currentStepStatusLabel = currentStep ? getStepStatusLabel(currentStep) : isGenerating ? '进行中' : '待处理'; const estimatedWaitText = progress?.estimatedRemainingMs != null ? formatDuration(progress.estimatedRemainingMs) : '校准中'; const elapsedText = progress != null ? formatDuration(progress.elapsedMs) : '启动中'; return (