diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx
index a2f377d64..f27a2a8fd 100644
--- a/apps/web/src/pages/generate/GeneratePage.tsx
+++ b/apps/web/src/pages/generate/GeneratePage.tsx
@@ -1,11 +1,11 @@
/**
* 智能剪辑页面 — 前端实时预览架构
- * 7 步向导:选择模板 → 素材 → 配音 → 标题 → 预览 → 封面 → 确认生成
+ * 6 步向导:选择模板 → 素材 → 配音 → 标题(含预览) → 封面 → 确认生成
* 左右布局:左侧 generate-form + 右侧 generate-preview
*
* 架构:
- * - 步骤 4-6 右侧显示 FrontendPreviewPlayer 实时预览
- * - 步骤 7 右侧内联播放生成的最终视频
+ * - 步骤 4-5 右侧显示 FrontendPreviewPlayer 实时预览
+ * - 步骤 6 右侧内联播放生成的最终视频
* - 点"确认生成"时调用 createGenerationTask 创建一次服务器渲染任务
*/
import React, { useMemo, useState, useEffect, useRef } from "react"
@@ -163,7 +163,16 @@ const GeneratePage: React.FC = () => {
/* ── 加载素材详情(供前端预览播放器使用 + 配音时长校验) ── */
const previewAssetsEnabled = previewAssetIds.length > 0
- const { assets: previewAssets } = usePreviewAssets(previewAssetIds, previewAssetsEnabled)
+ const { assets: previewAssets, ready: previewAssetsReady } = usePreviewAssets(
+ previewAssetIds,
+ previewAssetsEnabled,
+ )
+
+ /* ── 预览就绪:素材已加载,且有模板 ── */
+ const previewReady = useMemo(
+ () => previewAssetsReady && !!currentTemplate,
+ [previewAssetsReady, currentTemplate],
+ )
/* ── 视频总时长计算 ── */
const totalVideoDuration = useMemo(() => {
@@ -181,6 +190,7 @@ const GeneratePage: React.FC = () => {
selectedMaterials,
smartSelectedIds,
titleSettings,
+ previewReady,
})
/* ── 视频生成核心逻辑 ── */
@@ -296,9 +306,9 @@ const GeneratePage: React.FC = () => {
/>
- {/* ════ 右侧:步骤 4-6 实时预览,步骤 7 最终视频 ════ */}
+ {/* ════ 右侧:步骤 4-5 实时预览,步骤 6 最终视频 ════ */}
- {currentStep >= 4 && currentStep <= 6 && !!currentTemplate && (
+ {currentStep >= 4 && currentStep <= 5 && !!currentTemplate && (
{
}}
/>
)}
- {currentStep === 7 && generated && generatedVideos.length > 0 && (
+ {currentStep === 6 && generated && generatedVideos.length > 0 && (
)
}
diff --git a/apps/web/src/pages/generate/components/Step5GeneratePreview.tsx b/apps/web/src/pages/generate/components/Step5GeneratePreview.tsx
deleted file mode 100644
index 47f22274b..000000000
--- a/apps/web/src/pages/generate/components/Step5GeneratePreview.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * Step 5 预览设置组件
- *
- * 前端实时预览架构:
- * - 右侧面板使用 FrontendPreviewPlayer 实时播放素材片段
- * - 标题样式可实时调整,CSS 层即时叠加预览
- * - 点"确认生成"时触发一次服务器渲染
- */
-import React from "react"
-import { PlayCircleOutlined } from "@ant-design/icons"
-import { POSITION_OPTIONS, FONT_OPTIONS } from "../constants"
-import type { TitleSettings } from "../types"
-import TitleStylePanel from "./title/TitleStylePanel"
-
-interface Step5GeneratePreviewProps {
- titleSettings: TitleSettings
- onUpdatePosition: (position: string) => void
- onUpdateFont: (font: string) => void
- onUpdateSize: (size: number) => void
- onToggleBold: () => void
- onToggleItalic: () => void
- onToggleStroke: () => void
- onToggleShadow: () => void
- onApplyPreset: (presetKey: string) => void
- activePreset: string | null
- titlePresets: { key: string; label: string; previewStyle: React.CSSProperties }[]
-}
-
-const Step5GeneratePreview: React.FC = ({
- titleSettings,
- onUpdatePosition,
- onUpdateFont,
- onUpdateSize,
- onToggleBold,
- onToggleItalic,
- onToggleStroke,
- onToggleShadow,
- onApplyPreset,
- activePreset,
- titlePresets,
-}) => {
- return (
-
-
🎬 预览设置
-
-
-
-
- 右侧为实时预览,选完素材即可播放。确认生成后服务器渲染最终视频
-
-
-
-
-
- )
-}
-
-export default Step5GeneratePreview
diff --git a/apps/web/src/pages/generate/constants.ts b/apps/web/src/pages/generate/constants.ts
index 6810c6c49..c6a9bf764 100644
--- a/apps/web/src/pages/generate/constants.ts
+++ b/apps/web/src/pages/generate/constants.ts
@@ -33,9 +33,8 @@ export const STEPS = [
{ key: 2, label: "选择素材" },
{ key: 3, label: "选择配音" },
{ key: 4, label: "选择标题" },
- { key: 5, label: "生成预览" },
- { key: 6, label: "选择封面" },
- { key: 7, label: "确认生成" },
+ { key: 5, label: "选择封面" },
+ { key: 6, label: "确认生成" },
]
/* ── 标题位置选项 ── */
diff --git a/apps/web/src/pages/generate/hooks/useStepNavigation.ts b/apps/web/src/pages/generate/hooks/useStepNavigation.ts
index 7a92e266c..02c46a14b 100644
--- a/apps/web/src/pages/generate/hooks/useStepNavigation.ts
+++ b/apps/web/src/pages/generate/hooks/useStepNavigation.ts
@@ -1,9 +1,9 @@
/**
* GeneratePage 步骤导航
* 管理步骤切换与各步骤的前置校验
- * 步骤顺序:模板(1) → 素材(2) → 配音(3) → 标题(4) → 预览(5) → 封面(6) → 确认(7)
+ * 步骤顺序(6步):模板(1) → 素材(2) → 配音(3) → 标题(4) → 封面(5) → 确认(6)
*
- * 前端实时预览架构:Step5 无需等待服务器渲染
+ * 原 Step4(标题) + Step5(预览) 已合并为 Step4
*/
import { message } from "antd"
import type { TitleSettings } from "../types"
@@ -16,6 +16,8 @@ export interface UseStepNavigationOptions {
selectedMaterials: string[]
smartSelectedIds: string[]
titleSettings: TitleSettings
+ /** 预览是否已就绪(素材已加载,可播放) */
+ previewReady: boolean
}
export interface UseStepNavigationReturn {
@@ -32,6 +34,7 @@ export const useStepNavigation = (options: UseStepNavigationOptions): UseStepNav
selectedMaterials,
smartSelectedIds,
titleSettings,
+ previewReady,
} = options
const goNext = () => {
@@ -47,11 +50,18 @@ export const useStepNavigation = (options: UseStepNavigationOptions): UseStepNav
message.warning("请先进行智能匹配并选择素材")
return
}
- if (currentStep === 4 && !titleSettings.title.trim()) {
- message.warning("请选择或输入标题")
- return
+ // Step4(合并后的标题+预览):标题必填 + 预览必须已生成
+ if (currentStep === 4) {
+ if (!titleSettings.title.trim()) {
+ message.warning("请选择或输入标题")
+ return
+ }
+ if (!previewReady) {
+ message.warning("预览视频正在加载,请稍候")
+ return
+ }
}
- if (currentStep < 7) {
+ if (currentStep < 6) {
setCurrentStep((s) => s + 1)
}
}
diff --git a/apps/web/src/test/pages/generate/smoke.test.tsx b/apps/web/src/test/pages/generate/smoke.test.tsx
index 5433a0291..ef10ff4d5 100755
--- a/apps/web/src/test/pages/generate/smoke.test.tsx
+++ b/apps/web/src/test/pages/generate/smoke.test.tsx
@@ -17,7 +17,6 @@ import "@/api/generation/types"
// 直接引入所有 Step 组件,建立完整依赖链
import "@/pages/generate/GeneratePage"
import "@/pages/generate/components/Step2MaterialSelect"
-import "@/pages/generate/components/Step5GeneratePreview"
import "@/pages/generate/components/Step4TitleSettings"
import "@/pages/generate/components/Step5VoiceSelect"
import "@/pages/generate/components/PreviewVideoPanel"
diff --git a/apps/web/src/test/pages/generate/step5-preview.smoke.test.tsx b/apps/web/src/test/pages/generate/step5-preview.smoke.test.tsx
index 4b8fb7723..a8dfcf8ec 100644
--- a/apps/web/src/test/pages/generate/step5-preview.smoke.test.tsx
+++ b/apps/web/src/test/pages/generate/step5-preview.smoke.test.tsx
@@ -1,10 +1,9 @@
/**
- * Step5GeneratePreview smoke test
+ * Step4+5 merged preview smoke test
* 确保 vitest related 模式能匹配到第5步预览生成相关文件的改动
*/
import { describe, it, expect } from "vitest"
-import "@/pages/generate/components/Step5GeneratePreview"
import "@/pages/generate/hooks/usePreviewAssets"
import "@/pages/generate/hooks/useSegmentScheduler"
import "@/pages/generate/components/FrontendPreviewPlayer"
@@ -12,8 +11,8 @@ import "@/pages/generate/hooks/useStepNavigation"
import "@/pages/generate/components/GenerateStepContent"
import "@/pages/generate/GeneratePage"
-describe("Step5GeneratePreview module smoke test", () => {
- it("should load all step5 preview modules", () => {
+describe("Merged Step4+5 preview module smoke test", () => {
+ it("should load all merged step4+5 preview modules", () => {
expect(true).toBe(true)
})
})