From ce9c4f041c99e58bd8583e241fdd386d5ff48774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=B5=E5=BA=94?= Date: Tue, 30 Jun 2026 22:53:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=E4=BF=AE=E6=AD=A3=E4=B8=80=E9=94=AE?= =?UTF-8?q?=E7=94=9F=E6=88=90=E9=A1=B5=E9=9D=A2=E5=81=8F=E5=B7=AE=EF=BC=8C?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E8=A7=86=E9=A2=91=E9=A2=84=E8=A7=88=E3=80=81?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=BA=BF=E3=80=81=E5=85=8B=E9=9A=86=E5=A3=B0?= =?UTF-8?q?=E9=9F=B3=E5=8C=BA=E5=9F=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/pages/generate/GeneratePage.tsx | 316 ++++++++++++++----- apps/web/src/pages/generate/generate.css | 256 ++++++++++++++- 2 files changed, 490 insertions(+), 82 deletions(-) diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx index c98632d25..15c257568 100644 --- a/apps/web/src/pages/generate/GeneratePage.tsx +++ b/apps/web/src/pages/generate/GeneratePage.tsx @@ -5,8 +5,6 @@ */ import React, { useState, useRef, useCallback } from "react"; import { - Row, - Col, Typography, Collapse, Progress, @@ -28,7 +26,6 @@ import { PauseCircleOutlined, DownloadOutlined, ShareAltOutlined, - ReloadOutlined, InboxOutlined, SoundOutlined, FormOutlined, @@ -147,6 +144,37 @@ const MOCK_VOICES: VoiceItem[] = [ }, ]; +/* ── 克隆声音 Mock ── */ +interface ClonedVoice { + id: string; + name: string; + createdAt: string; + duration: string; +} + +const MOCK_CLONED_VOICES: ClonedVoice[] = [ + { id: "cv1", name: "我的声音 v1", createdAt: "2026-06-20", duration: "45s" }, + { id: "cv2", name: "我的声音 v2", createdAt: "2026-06-25", duration: "30s" }, +]; + +/* ── 时间线 Mock ── */ +interface TimelineScene { + scene: string; + time: string; + duration: number; + color: string; +} + +const MOCK_TIMELINE: TimelineScene[] = [ + { scene: "开场 - 品牌 Logo 展示", time: "0:00 - 0:05", duration: 5, color: "#6366f1" }, + { scene: "产品特写 - 细节展示", time: "0:05 - 0:15", duration: 10, color: "#818cf8" }, + { scene: "使用场景 - 生活化演绎", time: "0:15 - 0:30", duration: 15, color: "#10b981" }, + { scene: "卖点字幕 - 核心优势", time: "0:30 - 0:40", duration: 10, color: "#f59e0b" }, + { scene: "结尾 CTA - 引导关注", time: "0:40 - 0:50", duration: 10, color: "#ef4444" }, +]; + +const TOTAL_DURATION = MOCK_TIMELINE.reduce((sum, t) => sum + t.duration, 0); + /* ── 常量 ── */ interface RatioOption { @@ -218,9 +246,14 @@ const GeneratePage: React.FC = () => { /* ── 配音 ── */ const [selectedVoice, setSelectedVoice] = useState(""); const [playingVoice, setPlayingVoice] = useState(null); - const [voiceMode, setVoiceMode] = useState<"preset" | "custom">("preset"); + const [voiceMode, setVoiceMode] = useState<"preset" | "custom" | "clone">("preset"); const [customVoiceText, setCustomVoiceText] = useState(""); + /* ── 克隆声音 ── */ + const [cloneFileList, setCloneFileList] = useState([]); + const [selectedClonedVoice, setSelectedClonedVoice] = useState(""); + const [cloning, setCloning] = useState(false); + /* ── 标题/文案 ── */ const [titleMode, setTitleMode] = useState<"ai" | "manual">("ai"); const [manualCopy, setManualCopy] = useState(""); @@ -473,6 +506,7 @@ const GeneratePage: React.FC = () => { > 系统预设 自定义录制 + 克隆我的声音 {voiceMode === "preset" ? ( @@ -528,7 +562,7 @@ const GeneratePage: React.FC = () => { ); })} - ) : ( + ) : voiceMode === "custom" ? (