From b6e89b16a841ffaf3a7a17a31a69bd96e8a20bcf Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 12 Aug 2026 15:05:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=B0=81=E9=9D=A2=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E6=8E=A5=E5=85=A5=20UI=20+=20AI=20=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=8C=89=E9=92=AE=20+=20=E8=BF=9B=E5=BA=A6=E5=BC=B9=E7=AA=97?= =?UTF-8?q?=20(#1341)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - useEditorDrawers: 添加 coverDrawerOpen 开关状态 - EditorDrawers: 渲染 CoverSelector Drawer - EditingPlanner: 传递 cover 相关 props 到 EditorDrawers 和 RightPanel - clipProperties.ts: 添加 onOpenCoverDrawer 属性 - ClipPropertiesPanel: 添加封面设置入口按钮 - RightPanel: 透传 onOpenCoverDrawer 到 ClipPropertiesPanel - cover-selector/index.tsx: 添加 templateId prop、AI 生成封面按钮、 进度弹窗 Modal + Spin - EditingPlanner.css: 添加生成按钮样式 --- .../pages/editing-planner/EditingPlanner.css | 32 ++++++++++ .../pages/editing-planner/EditingPlanner.tsx | 7 +++ .../components/ClipPropertiesPanel.tsx | 17 ++++++ .../components/EditorDrawers.tsx | 25 ++++++++ .../editing-planner/components/RightPanel.tsx | 3 + .../components/cover-selector/index.tsx | 61 ++++++++++++++++++- .../editing-planner/hooks/useEditorDrawers.ts | 3 + .../editing-planner/types/clipProperties.ts | 1 + 8 files changed, 147 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pages/editing-planner/EditingPlanner.css b/apps/web/src/pages/editing-planner/EditingPlanner.css index d62b5e7dd..36a06cd3f 100644 --- a/apps/web/src/pages/editing-planner/EditingPlanner.css +++ b/apps/web/src/pages/editing-planner/EditingPlanner.css @@ -6408,3 +6408,35 @@ padding: 16px; text-align: center; } + +/* ═══ 封面 AI 生成按钮 ═══ */ +.cover-generate-section { + padding: 0 16px 12px; +} + +.cover-generate-btn { + width: 100%; + padding: 10px 16px; + border: 1px solid var(--color-primary, #1677ff); + border-radius: 8px; + background: var(--color-primary, #1677ff); + color: #fff; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + gap: 6px; +} + +.cover-generate-btn:hover:not(:disabled) { + background: var(--color-primary-hover, #4096ff); + border-color: var(--color-primary-hover, #4096ff); +} + +.cover-generate-btn:disabled { + opacity: 0.6; + cursor: not-allowed; +} diff --git a/apps/web/src/pages/editing-planner/EditingPlanner.tsx b/apps/web/src/pages/editing-planner/EditingPlanner.tsx index 5e0f08a86..9411865e3 100644 --- a/apps/web/src/pages/editing-planner/EditingPlanner.tsx +++ b/apps/web/src/pages/editing-planner/EditingPlanner.tsx @@ -243,6 +243,7 @@ const EditingPlanner: React.FC = () => { onOpenFilterDrawer={() => drawers.setFilterDrawerOpen(true)} onOpenGreenScreenDrawer={() => drawers.setChromaKeyDrawerOpen(true)} onOpenStickerDrawer={() => drawers.setStickerDrawerOpen(true)} + onOpenCoverDrawer={() => drawers.setCoverDrawerOpen(true)} clips={clips} selectedClipId={clipOps.selectedClipId} onClipSelect={clipOps.handleClipSelect} @@ -335,6 +336,12 @@ const EditingPlanner: React.FC = () => { stickerSettings={stickerSettings} onStickerChange={setStickerSettings} onCloseStickerDrawer={() => drawers.setStickerDrawerOpen(false)} + coverDrawerOpen={drawers.coverDrawerOpen} + onCloseCoverDrawer={() => drawers.setCoverDrawerOpen(false)} + coverConfig={coverConfig} + setCoverConfig={setCoverConfig} + templateId={urlTemplateId} + totalDuration={totalDuration} /> ) diff --git a/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx b/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx index ce9674d0f..d20302e7d 100644 --- a/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx +++ b/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx @@ -35,6 +35,7 @@ const ClipPropertiesPanel: React.FC = ({ onOpenFilterDrawer, onOpenGreenScreenDrawer, onOpenStickerDrawer, + onOpenCoverDrawer, }) => { const { previewingId, handlePreviewVoice, stopPreview } = useVoicePreview() @@ -140,6 +141,22 @@ const ClipPropertiesPanel: React.FC = ({ )} + + {/* ═══ 封面设置 ═══ */} +
+
+ 🖼️ + 封面设置 +
+ {onOpenCoverDrawer && ( + + )} +
+ {/* ═══ 片段详情(选中时显示) ═══ */} {selectedClip && ( void onCloseStickerDrawer: () => void + // 封面 + coverDrawerOpen: boolean + onCloseCoverDrawer: () => void + coverConfig: CoverConfig + setCoverConfig: (config: CoverConfig | ((prev: CoverConfig) => CoverConfig)) => void + templateId: string + totalDuration: number } + const EditorDrawers: React.FC = ({ bgmDrawerOpen, bgmSettings, @@ -135,6 +145,11 @@ const EditorDrawers: React.FC = ({ stickerSettings, onStickerChange, onCloseStickerDrawer, + coverDrawerOpen, + onCloseCoverDrawer, + coverConfig, + setCoverConfig, + templateId, }) => { const transitionConfig = transitionTargetClipId ? (clips.find((c) => c.id === transitionTargetClipId)?.transition ?? DEFAULT_TRANSITION) @@ -239,6 +254,16 @@ const EditorDrawers: React.FC = ({ onChange={onStickerChange} totalDuration={totalDuration} /> + + {/* 封面选择器 Drawer */} + ) } diff --git a/apps/web/src/pages/editing-planner/components/RightPanel.tsx b/apps/web/src/pages/editing-planner/components/RightPanel.tsx index 8d710ba50..f9e4601da 100644 --- a/apps/web/src/pages/editing-planner/components/RightPanel.tsx +++ b/apps/web/src/pages/editing-planner/components/RightPanel.tsx @@ -35,6 +35,7 @@ interface RightPanelProps { onOpenFilterDrawer: () => void onOpenGreenScreenDrawer: () => void onOpenStickerDrawer: () => void + onOpenCoverDrawer: () => void // 片段 tab clips: ClipData[] selectedClipId: string | null @@ -72,6 +73,7 @@ const RightPanel: React.FC = ({ onOpenFilterDrawer, onOpenGreenScreenDrawer, onOpenStickerDrawer, + onOpenCoverDrawer, clips, selectedClipId, onClipSelect, @@ -142,6 +144,7 @@ const RightPanel: React.FC = ({ onOpenFilterDrawer={onOpenFilterDrawer} onOpenGreenScreenDrawer={onOpenGreenScreenDrawer} onOpenStickerDrawer={onOpenStickerDrawer} + onOpenCoverDrawer={onOpenCoverDrawer} /> ) })()} diff --git a/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx b/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx index 6bb5a6d96..bf93f518a 100644 --- a/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx +++ b/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx @@ -2,8 +2,9 @@ * 封面选择器 * 抽帧选封面 + 上传自定义封面 + 智能封面推荐 */ -import React from "react" -import { Drawer } from "antd" +import React, { useState } from "react" +import { Drawer, Modal, Spin, message } from "antd" +import { generateCover } from "@/api/template-editor/aiFeatures" import type { CoverConfig, CoverMode } from "../../types" import { useCoverSelector, MODE_LABELS, MODE_ICONS } from "./useCoverSelector" import { CoverAutoMode, CoverFrameMode, CoverUploadMode } from "./CoverModePanels" @@ -14,6 +15,7 @@ interface CoverSelectorProps { config: CoverConfig onChange: (config: CoverConfig) => void totalDuration: number + templateId: string } const CoverSelector: React.FC = ({ @@ -22,6 +24,7 @@ const CoverSelector: React.FC = ({ config, onChange, totalDuration, + templateId, }) => { const { fileInputRef, @@ -36,6 +39,31 @@ const CoverSelector: React.FC = ({ formatTime, } = useCoverSelector({ config, onChange }) + const [generating, setGenerating] = useState(false) + + const handleGenerateCover = async () => { + if (!templateId) { + message.error("请先保存模板") + return + } + setGenerating(true) + try { + const res = await generateCover(templateId, { + asset_ids: [], + cover_type: "ai_frame", + }) + const imageUrl = res.cover?.image_url || res.cover?.thumbnail_url || "" + if (imageUrl) { + update({ upload_url: imageUrl, thumbnail_url: imageUrl }) + } + message.success("封面生成成功") + } catch (err: any) { + message.error("封面生成失败: " + (err?.message || "未知错误")) + } finally { + setGenerating(false) + } + } + return ( = ({ + + {/* AI 生成封面按钮 */} + {config.enabled && config.mode === "auto" && ( +
+ +
+ )} + {/* 底部 */}
+ + {/* 生成进度弹窗 */} + +
+ +

+ AI 正在生成封面,请稍候... +

+
+
) } diff --git a/apps/web/src/pages/editing-planner/hooks/useEditorDrawers.ts b/apps/web/src/pages/editing-planner/hooks/useEditorDrawers.ts index 310ae7010..ff44236c8 100644 --- a/apps/web/src/pages/editing-planner/hooks/useEditorDrawers.ts +++ b/apps/web/src/pages/editing-planner/hooks/useEditorDrawers.ts @@ -17,6 +17,7 @@ export const useEditorDrawers = () => { const [filterDrawerOpen, setFilterDrawerOpen] = useState(false) const [chromaKeyDrawerOpen, setChromaKeyDrawerOpen] = useState(false) const [stickerDrawerOpen, setStickerDrawerOpen] = useState(false) + const [coverDrawerOpen, setCoverDrawerOpen] = useState(false) /* ── 目标片段 ID ── */ /** 当前正在编辑转场的片段 ID(null = 全局默认转场) */ @@ -66,6 +67,8 @@ export const useEditorDrawers = () => { setChromaKeyDrawerOpen, stickerDrawerOpen, setStickerDrawerOpen, + coverDrawerOpen, + setCoverDrawerOpen, // 目标 ID transitionTargetClipId, speedTargetClipId, diff --git a/apps/web/src/pages/editing-planner/types/clipProperties.ts b/apps/web/src/pages/editing-planner/types/clipProperties.ts index 3f37015f2..51bdd29cf 100644 --- a/apps/web/src/pages/editing-planner/types/clipProperties.ts +++ b/apps/web/src/pages/editing-planner/types/clipProperties.ts @@ -68,4 +68,5 @@ export interface ClipPropertiesPanelProps { /** 打开贴纸面板 Drawer */ onOpenStickerDrawer?: () => void /** 打开封面选择器 Drawer */ + onOpenCoverDrawer?: () => void } -- 2.54.0 From 1764d2c29f1a0c3fe7f776bb39d1489cbecd36c7 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 12 Aug 2026 15:10:29 +0800 Subject: [PATCH 2/2] style: prettier format --- .../components/ClipPropertiesPanel.tsx | 1 - .../editing-planner/components/EditorDrawers.tsx | 1 - .../components/cover-selector/index.tsx | 12 ++---------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx b/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx index d20302e7d..e635332d6 100644 --- a/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx +++ b/apps/web/src/pages/editing-planner/components/ClipPropertiesPanel.tsx @@ -141,7 +141,6 @@ const ClipPropertiesPanel: React.FC = ({ )} - {/* ═══ 封面设置 ═══ */}
diff --git a/apps/web/src/pages/editing-planner/components/EditorDrawers.tsx b/apps/web/src/pages/editing-planner/components/EditorDrawers.tsx index 20d25c74e..3e4fddf4d 100644 --- a/apps/web/src/pages/editing-planner/components/EditorDrawers.tsx +++ b/apps/web/src/pages/editing-planner/components/EditorDrawers.tsx @@ -96,7 +96,6 @@ interface EditorDrawersProps { totalDuration: number } - const EditorDrawers: React.FC = ({ bgmDrawerOpen, bgmSettings, diff --git a/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx b/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx index bf93f518a..5ee92f1b9 100644 --- a/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx +++ b/apps/web/src/pages/editing-planner/components/cover-selector/index.tsx @@ -161,7 +161,6 @@ const CoverSelector: React.FC = ({
- {/* AI 生成封面按钮 */} {config.enabled && config.mode === "auto" && (
@@ -183,17 +182,10 @@ const CoverSelector: React.FC = ({
{/* 生成进度弹窗 */} - +
-

- AI 正在生成封面,请稍候... -

+

AI 正在生成封面,请稍候...

-- 2.54.0