fix: 移除 previewTaskId 自动清除 + 从预览响应提取 source_edit_plan_id #1483
@@ -38,6 +38,8 @@ export interface CreatePreviewResponse {
|
||||
is_preview: boolean
|
||||
resolution: string
|
||||
created_at: string
|
||||
/** 后端自动关联的编辑计划 ID(用于 fallback 路径传递 source_edit_plan_id) */
|
||||
source_edit_plan_id?: string
|
||||
}
|
||||
|
||||
/** 预览任务详情响应 */
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* - 标题样式通过 CSS 层实时叠加,所见即所得
|
||||
* - 最终成片仍走后端 FFmpeg 渲染(Step7 确认生成)
|
||||
*/
|
||||
import React, { useMemo, useEffect } 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"
|
||||
@@ -79,6 +79,8 @@ const GeneratePage: React.FC = () => {
|
||||
setPreviewModalOpen,
|
||||
previewTaskId,
|
||||
setPreviewTaskId,
|
||||
storedSourceEditPlanId,
|
||||
setStoredSourceEditPlanId,
|
||||
} = formState
|
||||
|
||||
/* ── 标题样式回调(Step5 样式面板 + 右侧预览 CSS 层共用) ── */
|
||||
@@ -101,13 +103,10 @@ const GeneratePage: React.FC = () => {
|
||||
() => (materialMode === "auto" ? smartSelectedIds : selectedMaterials),
|
||||
[materialMode, smartSelectedIds, selectedMaterials],
|
||||
)
|
||||
// 素材、模板或生成参数变化时,清除旧的 previewTaskId,防止 Step7 复用过期预览产物
|
||||
// confirmGeneration 无法覆盖 duration/ratio/title_config,所以这些参数变化后必须重新创建预览
|
||||
const titleKey = JSON.stringify(titleSettings)
|
||||
useEffect(() => {
|
||||
setPreviewTaskId(null)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [previewAssetIds, selectedTemplate, duration, videoRatio, titleKey, bgm, setPreviewTaskId])
|
||||
// previewTaskId 不再因设置变化而自动清除。
|
||||
// 用户修改设置后,confirmGeneration 会检测参数是否匹配:
|
||||
// 匹配则复用产物秒出;不匹配则后端自动 fallback 到 createGenerationTask 重新渲染。
|
||||
// 只有当用户明确返回 Step5 重新预览时,才会创建新的预览任务并覆盖 previewTaskId。
|
||||
|
||||
const previewAssetsEnabled = currentStep >= 4 && previewAssetIds.length > 0
|
||||
const {
|
||||
@@ -182,7 +181,7 @@ const GeneratePage: React.FC = () => {
|
||||
autoSubtitles,
|
||||
bgm,
|
||||
generateCount,
|
||||
sourceEditPlanId,
|
||||
sourceEditPlanId: storedSourceEditPlanId || sourceEditPlanId,
|
||||
previewTaskId,
|
||||
})
|
||||
|
||||
@@ -227,6 +226,7 @@ const GeneratePage: React.FC = () => {
|
||||
activePreset={styleUpdaters.activePreset}
|
||||
titlePresets={styleUpdaters.titlePresets}
|
||||
onPreviewTaskCreated={setPreviewTaskId}
|
||||
onSourceEditPlanIdExtracted={setStoredSourceEditPlanId}
|
||||
coverSettings={coverSettings}
|
||||
onCoverSettingsChange={setCoverSettings}
|
||||
duration={duration}
|
||||
|
||||
@@ -78,6 +78,8 @@ export interface GenerateStepContentProps {
|
||||
presetVoices: PresetVoiceItem[]
|
||||
/** 预览任务创建回调——传递给 Step6CoverSettings */
|
||||
onPreviewTaskCreated?: (taskId: string) => void
|
||||
/** 从预览响应中提取到 source_edit_plan_id 时的回调 */
|
||||
onSourceEditPlanIdExtracted?: (planId: string) => void
|
||||
}
|
||||
|
||||
export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) => {
|
||||
@@ -124,6 +126,7 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
|
||||
onDismissError,
|
||||
presetVoices,
|
||||
onPreviewTaskCreated,
|
||||
onSourceEditPlanIdExtracted,
|
||||
} = props
|
||||
|
||||
/* 当前模板的 segments,传给 Step2 构建 clips */
|
||||
@@ -194,6 +197,7 @@ export const GenerateStepContent: React.FC<GenerateStepContentProps> = (props) =
|
||||
selectedTemplate={selectedTemplate}
|
||||
titleSettings={titleSettings}
|
||||
onPreviewTaskCreated={onPreviewTaskCreated}
|
||||
onSourceEditPlanIdExtracted={onSourceEditPlanIdExtracted}
|
||||
/>
|
||||
)
|
||||
case 7:
|
||||
|
||||
@@ -18,6 +18,8 @@ interface Step6CoverSettingsProps {
|
||||
titleSettings?: import("../types").TitleSettings
|
||||
/** 预览任务创建回调——将 task_id 暴露给父组件供 confirmGeneration 复用 */
|
||||
onPreviewTaskCreated?: (taskId: string) => void
|
||||
/** 从预览响应中提取到 source_edit_plan_id 时的回调 */
|
||||
onSourceEditPlanIdExtracted?: (planId: string) => void
|
||||
}
|
||||
|
||||
const Step6CoverSettings: React.FC<Step6CoverSettingsProps> = (props) => {
|
||||
@@ -46,6 +48,7 @@ const Step6CoverSettings: React.FC<Step6CoverSettingsProps> = (props) => {
|
||||
selectedTemplate: props.selectedTemplate,
|
||||
titleSettings: props.titleSettings,
|
||||
onPreviewTaskCreated: props.onPreviewTaskCreated,
|
||||
onSourceEditPlanIdExtracted: props.onSourceEditPlanIdExtracted,
|
||||
})
|
||||
|
||||
const handleAutoGenerate = () => {
|
||||
|
||||
@@ -99,6 +99,10 @@ export interface GenerateFormState {
|
||||
/** 预览任务 ID(由 useStep6Cover 创建后写入,供 useGenerateVideo 复用) */
|
||||
previewTaskId: string | null
|
||||
setPreviewTaskId: (id: string | null) => void
|
||||
|
||||
/** 从预览响应中提取的 source_edit_plan_id(供 fallback 路径使用) */
|
||||
storedSourceEditPlanId: string | null
|
||||
setStoredSourceEditPlanId: (planId: string | null) => void
|
||||
}
|
||||
|
||||
export const useGenerateFormState = (): GenerateFormState => {
|
||||
@@ -167,6 +171,9 @@ export const useGenerateFormState = (): GenerateFormState => {
|
||||
/* ── 预览任务 ID(useStep6Cover 创建预览时写入,useGenerateVideo 复用) ── */
|
||||
const [previewTaskId, setPreviewTaskId] = useState<string | null>(null)
|
||||
|
||||
/* ── 从预览响应中提取的 source_edit_plan_id(供 fallback 路径使用) ── */
|
||||
const [storedSourceEditPlanId, setStoredSourceEditPlanId] = useState<string | null>(null)
|
||||
|
||||
/* ── 从 URL / 编辑计划加载配置 ── */
|
||||
usePlanConfigLoader({
|
||||
editPlanId,
|
||||
@@ -217,5 +224,7 @@ export const useGenerateFormState = (): GenerateFormState => {
|
||||
setPreviewModalOpen,
|
||||
previewTaskId,
|
||||
setPreviewTaskId,
|
||||
storedSourceEditPlanId,
|
||||
setStoredSourceEditPlanId,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ interface UseStep6CoverProps {
|
||||
titleSettings?: TitleSettings
|
||||
/** 预览任务创建回调——将 task_id 暴露给父组件供 confirmGeneration 复用 */
|
||||
onPreviewTaskCreated?: (taskId: string) => void
|
||||
/** 从预览响应中提取到 source_edit_plan_id 时的回调 */
|
||||
onSourceEditPlanIdExtracted?: (planId: string) => void
|
||||
}
|
||||
|
||||
export function useStep6Cover({
|
||||
@@ -38,6 +40,7 @@ export function useStep6Cover({
|
||||
selectedTemplate = "",
|
||||
titleSettings,
|
||||
onPreviewTaskCreated,
|
||||
onSourceEditPlanIdExtracted,
|
||||
}: UseStep6CoverProps) {
|
||||
const [generating, setGenerating] = useState(false)
|
||||
// 防竞态:记录当前预览生成的参数指纹,任务完成时校验一致性
|
||||
@@ -181,6 +184,10 @@ export function useStep6Cover({
|
||||
const currentFingerprint = JSON.stringify({ selectedTemplate, assetIds, titleSettings })
|
||||
if (previewResp.task_id && previewParamsRef.current === currentFingerprint) {
|
||||
onPreviewTaskCreated?.(previewResp.task_id)
|
||||
// 提取后端自动关联的 source_edit_plan_id,供 fallback 路径使用
|
||||
if (previewResp.source_edit_plan_id) {
|
||||
onSourceEditPlanIdExtracted?.(previewResp.source_edit_plan_id)
|
||||
}
|
||||
}
|
||||
// 轮询等待预览渲染完成:递归 setTimeout 避免请求重叠 + 120s 超时兜底
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
@@ -295,6 +302,7 @@ export function useStep6Cover({
|
||||
duration,
|
||||
titleSettings,
|
||||
onPreviewTaskCreated,
|
||||
onSourceEditPlanIdExtracted,
|
||||
])
|
||||
|
||||
// ── 模板操作方法 ──
|
||||
|
||||
Reference in New Issue
Block a user