refactor: 更新现有文件适配前端预览播放器架构

This commit is contained in:
2026-08-18 01:05:10 +08:00
parent 9f910e0c7f
commit 5a7566d2bc
@@ -1,33 +1,15 @@
/**
* Step 5 生成预览组件(支持多预览)
* 调用后端预览生成接口,展示预览生成状态
* 预览视频由右侧 PreviewVideoPanel 展示,本组件不重复显示预览网格
* 标题样式面板(TitleStylePanel)在此展示,用户可实时调整标题样式
* Step 5 生成预览组件
* 架构改造:移除后端预览生成,改为前端实时预览
* 左侧仅保留标题样式面板,视频在右侧 PreviewVideoPanel 实时播放
*/
import React from "react"
import {
CheckCircleFilled,
ReloadOutlined,
PlayCircleOutlined,
ExclamationCircleFilled,
ClockCircleOutlined,
} from "@ant-design/icons"
import { InputNumber } from "antd"
import { PlayCircleOutlined } from "@ant-design/icons"
import { POSITION_OPTIONS, FONT_OPTIONS } from "../constants"
import type { TitleSettings } from "../types"
import type { PreviewItem, PreviewStatus } from "../hooks/useStep5Preview"
import TitleStylePanel from "./title/TitleStylePanel"
interface Step5GeneratePreviewProps {
previewCount: number
onPreviewCountChange: (count: number) => void
items: PreviewItem[]
overallStatus: PreviewStatus
overallError: string
overallProgress: number
anyGenerating: boolean
onGeneratePreview: () => void
onRegeneratePreview: () => void
/* 标题样式 */
titleSettings: TitleSettings
onUpdatePosition: (position: string) => void
@@ -42,23 +24,7 @@ interface Step5GeneratePreviewProps {
titlePresets: { key: string; label: string; previewStyle: React.CSSProperties }[]
}
/** 预览数量选项 */
const PREVIEW_COUNT_OPTIONS = [
{ value: 1, label: "1个" },
{ value: 2, label: "2个" },
{ value: 3, label: "3个" },
]
const Step5GeneratePreview: React.FC<Step5GeneratePreviewProps> = ({
previewCount,
onPreviewCountChange,
items,
overallStatus,
overallError,
overallProgress,
anyGenerating,
onGeneratePreview,
onRegeneratePreview,
titleSettings,
onUpdatePosition,
onUpdateFont,
@@ -71,14 +37,31 @@ const Step5GeneratePreview: React.FC<Step5GeneratePreviewProps> = ({
activePreset,
titlePresets,
}) => {
const isIdle = overallStatus === "idle"
const isError = overallStatus === "error" && !items.some((it) => it.status === "ready")
return (
<div className="xx-form-section">
<h3>🎬 生成预览</h3>
<h3>🎬 预览设置</h3>
{/* 标题样式面板 — 用户可实时调整标题样式,右侧预览同步更新 */}
{/* 前端实时预览提示 */}
<div
className="xx-preview-tip"
style={{
display: "flex",
alignItems: "center",
gap: 8,
padding: "12px 16px",
background: "rgba(59, 130, 246, 0.08)",
borderRadius: 8,
marginBottom: 16,
border: "1px solid rgba(59, 130, 246, 0.15)",
}}
>
<PlayCircleOutlined style={{ fontSize: 18, color: "#3b82f6" }} />
<span style={{ fontSize: 13, color: "var(--text-secondary, #666)" }}>
右侧面板直接播放素材片段,调整标题样式可实时预览效果
</span>
</div>
{/* 标题样式面板 */}
<TitleStylePanel
settings={titleSettings}
onUpdatePosition={onUpdatePosition}
@@ -94,116 +77,6 @@ const Step5GeneratePreview: React.FC<Step5GeneratePreviewProps> = ({
POSITION_OPTIONS={POSITION_OPTIONS}
FONT_OPTIONS={FONT_OPTIONS}
/>
{/* 预览数量选择器(仅在 idle 状态显示) */}
{isIdle && (
<div style={{ marginBottom: 16, display: "flex", alignItems: "center", gap: 12 }}>
<span style={{ fontSize: 14, color: "#666" }}>预览数量:</span>
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
{PREVIEW_COUNT_OPTIONS.map((opt) => (
<button
key={opt.value}
type="button"
onClick={() => onPreviewCountChange(opt.value)}
style={{
padding: "4px 12px",
borderRadius: 6,
border: previewCount === opt.value ? "1px solid #1677ff" : "1px solid #d9d9d9",
background: previewCount === opt.value ? "#e6f4ff" : "#fff",
color: previewCount === opt.value ? "#1677ff" : "#666",
cursor: "pointer",
fontSize: 13,
fontWeight: previewCount === opt.value ? 600 : 400,
}}
>
{opt.label}
</button>
))}
<InputNumber
min={1}
max={10}
value={previewCount}
onChange={(val) => val && onPreviewCountChange(val)}
style={{ width: 70 }}
placeholder="自定义"
/>
<span style={{ fontSize: 12, color: "#999", marginLeft: 4 }}>(1~10)</span>
</div>
{previewCount > 1 && (
<span style={{ fontSize: 12, color: "#999" }}>生成多个预览可对比不同剪辑效果</span>
)}
</div>
)}
{/* 预览生成按钮(idle 状态) */}
{isIdle && (
<div className="xx-preview-generate-section">
<div className="xx-preview-generate-hint">
<PlayCircleOutlined style={{ fontSize: 32, color: "#3b82f6", marginBottom: 12 }} />
<p className="xx-preview-generate-title">一键生成剪辑预览</p>
<p className="xx-preview-generate-desc">
AI 将根据您选择的模板、素材和配音,智能生成
{previewCount > 1 ? `${previewCount}个不同版本的` : ""}视频预览(480p 低清版)
</p>
</div>
<button
className="xx-btn xx-btn-primary xx-preview-generate-btn"
onClick={onGeneratePreview}
>
✨ 生成预览{previewCount > 1 ? `(${previewCount}个)` : ""}
</button>
</div>
)}
{/* 整体排队中(所有都在 pending) */}
{anyGenerating && items.every((it) => it.status === "pending") && (
<div className="xx-preview-loading">
<ClockCircleOutlined style={{ fontSize: 32, color: "#faad14" }} spin />
<p className="xx-preview-loading-text">预览排队中...</p>
<p className="xx-preview-loading-desc">正在等待渲染资源,请稍候</p>
</div>
)}
{/* 预览网格已移除 — 右侧 PreviewVideoPanel 已展示实际预览视频,左侧不再重复显示 */}
{/* 整体进度条(多预览生成中) */}
{anyGenerating && (
<div className="xx-preview-progress-bar" style={{ marginBottom: 12 }}>
<div className="xx-preview-progress-fill" style={{ width: `${overallProgress}%` }} />
</div>
)}
{/* 全部完成提示 */}
{overallStatus === "ready" && (
<div className="xx-preview-tip">
<CheckCircleFilled style={{ color: "#52c41a", marginRight: 8 }} />
<span>
{items.filter((it) => it.status === "ready").length} 个预览生成成功
",请在右侧预览面板查看效果"
</span>
<button
className="xx-preview-regenerate-btn"
onClick={onRegeneratePreview}
title="重新生成"
>
<ReloadOutlined /> 重新生成
</button>
</div>
)}
{/* 全部失败 */}
{isError && (
<div className="xx-preview-error">
<ExclamationCircleFilled style={{ fontSize: 28, color: "#ef4444" }} />
<p className="xx-preview-error-text">预览生成失败</p>
<p className="xx-preview-error-desc">
{typeof overallError === "string" && overallError ? overallError : "请稍后重试"}
</p>
<button className="xx-btn xx-btn-primary" onClick={onRegeneratePreview}>
<ReloadOutlined /> 重新生成
</button>
</div>
)}
</div>
)
}