From f82c93db848a77cfc84fc7ecadf459ea16995b35 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Fri, 28 Aug 2026 22:58:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(generate):=20=E8=B0=83=E6=8D=A2=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4=E7=94=9F=E6=88=90=E4=B8=8E=E9=80=89=E6=8B=A9=E5=B0=81?= =?UTF-8?q?=E9=9D=A2=E9=A1=BA=E5=BA=8F=EF=BC=8C=E5=B0=81=E9=9D=A2=E4=BB=8E?= =?UTF-8?q?=E6=9C=80=E7=BB=88=E6=88=90=E7=89=87=E9=80=89=E5=B8=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 步骤顺序调整为:模板→素材→配音→标题→确认生成→选择封面 - 确认生成完成后点"下一步"进入选择封面(不自动跳转) - 封面源从预览片段改为确认生成任务产出的最终视频 - generateCover API 传 generated_video_id + video_url - 移除 createPreview 预览创建兜底逻辑(不再需要预览视频) - MediaKit 选帧算法/降级逻辑由后端保持不变 - 步骤5(确认生成)右侧内联播放最终视频,含下载/分享/成片库入口 - 步骤6(选择封面)展示最终成片名称提示,自动生成封面按钮无视频时禁用 - 步骤导航增加 generated 校验:未生成视频不能进入封面步骤 - 步骤4右侧仍为 FrontendPreviewPlayer 实时预览 --- apps/web/src/api/generation/cover.ts | 11 +- apps/web/src/pages/generate/GeneratePage.tsx | 51 +++-- .../components/GenerateStepContent.tsx | 50 ++-- .../components/Step6CoverSettings.tsx | 59 +++-- apps/web/src/pages/generate/constants.ts | 4 +- .../src/pages/generate/hooks/useStep6Cover.ts | 215 ++---------------- .../pages/generate/hooks/useStepNavigation.ts | 15 +- 7 files changed, 110 insertions(+), 295 deletions(-) diff --git a/apps/web/src/api/generation/cover.ts b/apps/web/src/api/generation/cover.ts index 3a230220d..8bf308d1e 100644 --- a/apps/web/src/api/generation/cover.ts +++ b/apps/web/src/api/generation/cover.ts @@ -12,7 +12,14 @@ export interface GenerateCoverTitleConfig { } export interface GenerateCoverRequest { - asset_ids: string[] + /** + * 封面源视频标识(二选一): + * - generated_video_id:确认生成任务产出的最终视频 ID + * - video_url:最终视频 URL(兜底) + * 后端根据此标识定位最终成片文件并抽帧,MediaKit 选帧逻辑不变 + */ + generated_video_id?: string + video_url?: string cover_type?: "ai_frame" | "manual" | "upload" | "ai_regenerate" frame_time?: number /** 标题样式,用于在封面上叠加标题文字 */ @@ -31,7 +38,7 @@ export interface GenerateCoverResponse { } } -/** AI 生成封面 — 从预览视频中抽帧 */ +/** AI 生成封面 — 从最终成片中抽帧(MediaKit 选帧) */ export async function generateCover( templateId: string, data: GenerateCoverRequest, diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx index f27a2a8fd..8d47b17e5 100644 --- a/apps/web/src/pages/generate/GeneratePage.tsx +++ b/apps/web/src/pages/generate/GeneratePage.tsx @@ -1,11 +1,11 @@ /** * 智能剪辑页面 — 前端实时预览架构 - * 6 步向导:选择模板 → 素材 → 配音 → 标题(含预览) → 封面 → 确认生成 - * 左右布局:左侧 generate-form + 右侧 generate-preview + * 6 步向导:选择模板 → 素材 → 配音 → 标题(含预览) → 确认生成 → 选择封面 * * 架构: - * - 步骤 4-5 右侧显示 FrontendPreviewPlayer 实时预览 - * - 步骤 6 右侧内联播放生成的最终视频 + * - 步骤 4 右侧显示 FrontendPreviewPlayer 实时预览 + * - 步骤 5 右侧内联播放生成中的/最终视频 + * - 步骤 6 封面从最终成片中智能选帧(MediaKit) * - 点"确认生成"时调用 createGenerationTask 创建一次服务器渲染任务 */ import React, { useMemo, useState, useEffect, useRef } from "react" @@ -181,18 +181,6 @@ const GeneratePage: React.FC = () => { return estimateTotalVideoDuration(currentTemplate ?? undefined) }, [previewAssets, currentTemplate]) - /* ── 步骤导航 ── */ - const { goNext, goPrev } = useStepNavigation({ - currentStep, - setCurrentStep, - selectedTemplate, - materialMode, - selectedMaterials, - smartSelectedIds, - titleSettings, - previewReady, - }) - /* ── 视频生成核心逻辑 ── */ const { generating, @@ -229,6 +217,22 @@ const GeneratePage: React.FC = () => { }, }) + /* ── 步骤导航 ── */ + const { goNext, goPrev } = useStepNavigation({ + currentStep, + setCurrentStep, + selectedTemplate, + materialMode, + selectedMaterials, + smartSelectedIds, + titleSettings, + previewReady, + generated, + }) + + /* ── 最终成片(步骤5/6 右侧播放) ── */ + const finalVideo = generatedVideos[0] + /* ================================================================ 渲染 ================================================================ */ @@ -265,13 +269,10 @@ const GeneratePage: React.FC = () => { onApplyPreset={styleUpdaters.applyPreset} activePreset={styleUpdaters.activePreset} titlePresets={styleUpdaters.titlePresets} - onPreviewTaskCreated={setPreviewTaskId} - onSourceEditPlanIdExtracted={setStoredSourceEditPlanId} bgm={bgm} bgmConfig={bgmConfig} coverSettings={coverSettings} onCoverSettingsChange={setCoverSettings} - duration={duration} selectedVoice={selectedVoice} onSelectedVoiceChange={setSelectedVoice} totalVideoDuration={totalVideoDuration} @@ -306,9 +307,9 @@ const GeneratePage: React.FC = () => { /> - {/* ════ 右侧:步骤 4-5 实时预览,步骤 6 最终视频 ════ */} + {/* ════ 右侧:步骤4实时预览,步骤5/6最终视频 ════ */}
- {currentStep >= 4 && currentStep <= 5 && !!currentTemplate && ( + {currentStep === 4 && !!currentTemplate && ( { }} /> )} - {currentStep === 6 && generated && generatedVideos.length > 0 && ( + {currentStep >= 5 && generated && finalVideo && (