diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx index cb1cea796..8a52123e0 100644 --- a/apps/web/src/pages/generate/GeneratePage.tsx +++ b/apps/web/src/pages/generate/GeneratePage.tsx @@ -1,15 +1,15 @@ /** - * 智能剪辑页面 — V23 标题样式面板迁移到 Step5 + CSS 实时预览 + * 智能剪辑页面 — V24 前端预览播放器架构改造 * 7 步向导:选择模板 → 素材 → 配音 → 标题 → 预览 → 封面 → 确认生成 * 左右布局:左侧 generate-form + 右侧 generate-preview - * 主组件仅保留整体布局与事件编排 - * 状态管理 → hooks/useGenerateFormState - * 步骤导航 → hooks/useStepNavigation - * 步骤内容 → components/GenerateStepContent - * 底部按钮 → components/GenerateStepActions - * 生成核心逻辑 → hooks/useGenerateVideo + * + * 架构改造: + * - Step5 预览改为前端素材切片播放(FrontendPreviewPlayer) + * - 完全去除后端 FFmpeg 预览依赖 + * - 标题样式通过 CSS 层实时叠加,所见即所得 + * - 最终成片仍走后端 FFmpeg 渲染(Step7 确认生成) */ -import React, { useState, useMemo } from "react" +import React, { useMemo } from "react" import { Modal, message } from "antd" import { useNavigate } from "react-router-dom" import type { VoiceClone } from "@/api/voice-clone" @@ -24,7 +24,7 @@ import GenerateStepActions from "./components/GenerateStepActions" import { useGenerateFormState } from "./hooks/useGenerateFormState" import { useStepNavigation } from "./hooks/useStepNavigation" import { useGenerateVideo } from "./hooks/useGenerateVideo" -import { useStep5Preview } from "./hooks/useStep5Preview" +import { usePreviewAssets } from "./hooks/usePreviewAssets" import { useTitleStyleUpdaters } from "./hooks/useStep4Title/useTitleStyleUpdaters" import "./generate.css" @@ -87,36 +87,23 @@ const GeneratePage: React.FC = () => { message.success("音色克隆成功!") } - /* ── 预览数量(多预览) ── */ - const [previewCount, setPreviewCount] = useState(1) + /* ── 前端预览:加载选中素材的视频文件信息 ── */ + const previewAssetIds = useMemo( + () => (materialMode === "auto" ? smartSelectedIds : selectedMaterials), + [materialMode, smartSelectedIds, selectedMaterials], + ) + const previewAssetsEnabled = currentStep >= 4 && previewAssetIds.length > 0 + const { + assets: previewAssets, + loading: previewAssetsLoading, + ready: previewAssetsReady, + } = usePreviewAssets(previewAssetIds, previewAssetsEnabled) - /* ── 根据 voiceMode 构建 voiceIds 传给预览接口 ── */ - /* selectedVoice / selectedClonedVoice 均为 string 类型(voice ID), - 见 useGenerateFormState 返回值类型定义 */ - const previewVoiceIds = useMemo((): string[] => { - if (voiceMode === "clone") { - const id: string = selectedClonedVoice - return id ? [id] : [] - } - // preset / custom 模式 - const id: string = selectedVoice - return id ? [id] : [] - }, [voiceMode, selectedVoice, selectedClonedVoice]) - - /* ── Step5 预览生成(多预览 + voice_ids) ── */ - const step5Preview = useStep5Preview({ - templates: userTemplates, - selectedTemplate, - materialMode, - selectedMaterials, - smartSelectedIds, - duration, - videoRatio, - voiceIds: previewVoiceIds, - voiceLibraryId: selectedVoice || undefined, - previewCount, - titleSettings, - }) + /* ── 当前模板对象(传给前端预览播放器) ── */ + const currentTemplate = useMemo( + () => userTemplates.find((t) => t.id === selectedTemplate) || null, + [userTemplates, selectedTemplate], + ) /* ── 步骤导航 ── */ const { goNext, goPrev } = useStepNavigation({ @@ -127,7 +114,7 @@ const GeneratePage: React.FC = () => { selectedMaterials, smartSelectedIds, titleSettings, - previewReady: step5Preview.canProceed, + previewReady: previewAssetsReady, }) /* ── 视频生成核心逻辑 ── */ @@ -158,7 +145,7 @@ const GeneratePage: React.FC = () => { autoSubtitles, bgm, generateCount, - previewTaskId: step5Preview.selectedTaskId, + previewTaskId: "", }) /* ================================================================ @@ -225,16 +212,6 @@ const GeneratePage: React.FC = () => { onRetry={handleRetryGenerate} onDismissError={handleDismissError} presetVoices={presetVoices} - /* Step5 多预览 */ - previewCount={previewCount} - onPreviewCountChange={setPreviewCount} - previewItems={step5Preview.items} - previewOverallStatus={step5Preview.previewStatus} - previewOverallError={step5Preview.previewError} - previewOverallProgress={step5Preview.progress} - previewAnyGenerating={step5Preview.anyGenerating} - onGeneratePreview={step5Preview.generatePreview} - onRegeneratePreview={step5Preview.regeneratePreview} /> { {/* 预览视频面板(Step4+ 显示,含 CSS 标题实时预览层) */} {currentStep >= 4 && ( )} diff --git a/apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx b/apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx new file mode 100644 index 000000000..531af36ef --- /dev/null +++ b/apps/web/src/pages/generate/components/FrontendPreviewPlayer.tsx @@ -0,0 +1,300 @@ +/** + * 前端预览播放器 + * 用原生