From 33ccb16bd3e9ef4b1533f9332db636da6dda1fbd Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 16 Jul 2026 11:08:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BC=96=E8=BE=91=E5=99=A8=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E8=AE=A1=E5=88=92=E6=97=B6=E4=BC=98=E5=85=88=E4=BB=8E?= =?UTF-8?q?=E5=90=8E=E7=AB=AFclips=E8=A1=A8=E8=BF=98=E5=8E=9F=E7=89=87?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 加载计划时并行请求 clips 列表 - 优先从后端 clips 表还原片段(含 config.tts_config / trim_config) - 无 clips 数据时从 config.segments 兜底(老数据兼容) - 形成完整闭环:编辑→同步→生成→重新加载 --- .../pages/editing-planner/EditingPlanner.tsx | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/apps/web/src/pages/editing-planner/EditingPlanner.tsx b/apps/web/src/pages/editing-planner/EditingPlanner.tsx index 045af65c6..d0647d730 100755 --- a/apps/web/src/pages/editing-planner/EditingPlanner.tsx +++ b/apps/web/src/pages/editing-planner/EditingPlanner.tsx @@ -417,8 +417,16 @@ const EditingPlanner: React.FC = () => { */ useEffect(() => { if (!loadedPlanId) return; - getEditPlan(loadedPlanId) - .then((plan) => { + + // 并行加载计划基本信息 + 片段列表 + Promise.all([ + getEditPlan(loadedPlanId), + getEditPlanClips(loadedPlanId, { limit: 500 }).catch(() => ({ + items: [], + total: 0, + })), + ]) + .then(([plan, clipsRes]) => { // 设置关联的模板(触发模板加载 effect) setLoadedTemplateId(plan.template_id); @@ -458,8 +466,41 @@ const EditingPlanner: React.FC = () => { })); } - // 还原片段 — 延迟设置,等模板加载 effect 先执行 resetClips - if (cfg.segments && cfg.segments.length > 0) { + // 还原片段:优先从后端 clips 表,其次从 config.segments 兜底 + const backendClips = clipsRes?.items || []; + if (backendClips.length > 0) { + // 从后端 clips 表还原 + const sorted = [...backendClips].sort( + (a, b) => a.order - b.order, + ); + const mapped: ClipData[] = sorted.map((clip) => ({ + id: clip.id, + template_segment_id: + (clip.config?.template_segment_id as string) || "", + type: (clip.clip_type === "voiceover" + ? "voice" + : "pip") as ClipType, + duration: clip.duration || 3, + startOffset: 0, + script_text: clip.text_content || "", + order: clip.order, + media_asset_id: clip.asset_id || undefined, + transition: + clip.transition_effect && clip.transition_effect !== "none" + ? { + type: clip.transition_effect as TransitionEffect["type"], + duration: clip.transition_duration || 0.3, + } + : undefined, + speed: clip.playback_speed + ? { rate: clip.playback_speed, pitchCorrection: true } + : undefined, + tts_config: (clip.config?.tts_config as TtsConfig) || undefined, + trim_config: (clip.config?.trim_config as TrimConfig) || undefined, + })); + setTimeout(() => resetClips(mapped), 100); + } else if (cfg.segments && cfg.segments.length > 0) { + // 兜底:从 config.segments 还原(老数据兼容) const mapped: ClipData[] = cfg.segments.map((seg, idx) => ({ id: `seg-${idx}`, template_segment_id: `seg-${idx}`,