## 🎨 前端优化:板块合并 + 序号标题 + UI 精细化 (Day 26) ### 概述 首页原有 9 个独立板块(左栏 7 个 + 右栏 2 个),每个都有自己的卡片容器和标题,视觉碎片化严重。本次将相关板块合并为 5 个主板块,添加中文序号(一~十),移除 emoji 图标,并对多个子组件的布局和交互细节进行优化。 --- ## ✅ 改动内容 ### 1. 板块合并方案 **左栏(4 个主板块 + 2 个独立区域):** | 序号 | 板块名 | 子板块 | 原组件 | |------|--------|--------|--------| | 一 | 文案提取与编辑 | — | ScriptEditor | | 二 | 标题与字幕 | — | TitleSubtitlePanel | | 三 | 配音 | 配音方式 / 配音列表 | VoiceSelector + GeneratedAudiosPanel | | 四 | 素材编辑 | 视频素材 / 时间轴编辑 | MaterialSelector + TimelineEditor | | 五 | 背景音乐 | — | BgmPanel | | — | 生成按钮 | — | GenerateActionBar(不编号) | **右栏(1 个主板块):** | 序号 | 板块名 | 子板块 | 原组件 | |------|--------|--------|--------| | 六 | 作品 | 作品列表 / 作品预览 | HistoryList + PreviewPanel | **发布页(/publish):** | 序号 | 板块名 | |------|--------| | 七 | 平台账号 | | 八 | 选择发布作品 | | 九 | 发布信息 | | 十 | 选择发布平台 | ### 2. embedded 模式 6 个组件新增 `embedded?: boolean` prop(默认 `false`): - `VoiceSelector` — embedded 时不渲染外层卡片和主标题 - `GeneratedAudiosPanel` — embedded 时两行布局:第 1 行(语速+生成配音右对齐)、第 2 行(配音列表+刷新) - `MaterialSelector` — embedded 时自渲染 h3 子标题"视频素材"+ 上传/刷新按钮同行 - `TimelineEditor` — embedded 时自渲染 h3 子标题"时间轴编辑"+ 画面比例/播放控件同行 - `PreviewPanel` — embedded 时不渲染外层卡片和标题 - `HistoryList` — embedded 时不渲染外层卡片和标题(刷新按钮由 HomePage 提供) ### 3. 序号标题 + emoji 移除 所有编号板块移除 emoji 图标,使用纯中文序号: - ScriptEditor: `✍️ 文案提取与编辑` → `一、文案提取与编辑` - TitleSubtitlePanel: `🎬 标题与字幕` → `二、标题与字幕` - BgmPanel: `🎵 背景音乐` → `五、背景音乐` - HomePage 右栏: `五、作品` → `六、作品` - PublishPage: `👤 平台账号` → `七、平台账号`、`📹 选择发布作品` → `八、选择发布作品`、`✍️ 发布信息` → `九、发布信息`、`📱 选择发布平台` → `十、选择发布平台` ### 4. 子标题与分隔样式 - **主标题**: `text-base sm:text-lg font-semibold text-white` - **子标题**: `text-sm font-medium text-gray-400` - **分隔线**: `
` ### 5. 配音列表布局优化 GeneratedAudiosPanel embedded 模式下采用两行布局: - **第 1 行**:语速下拉 + 生成配音按钮(右对齐,`flex justify-end`) - **第 2 行**:`

配音列表

` + 刷新按钮(两端对齐) - 非 embedded 模式保持原单行布局 ### 6. TitleSubtitlePanel 下拉对齐 - 标题样式/副标题样式/字幕样式三行标签统一 `w-20`(固定 80px),确保下拉菜单垂直对齐 - 下拉菜单宽度 `w-1/3 min-w-[100px]`,避免过宽 ### 7. RefAudioPanel 文案简化 - 原底部段落"上传任意语音样本(3-10秒)…" 移至 "我的参考音频" 标题旁,简化为 `(上传3-10秒语音样本)` ### 8. 账户下拉菜单添加手机号 - AccountSettingsDropdown 在账户有效期上方新增手机号显示区域 - 显示 `user?.phone || '未知账户'` ### 9. 标题显示模式对副标题生效 - **payload 修复**: `useHomeController.ts` 中 `title_display_mode` 的发送条件从 `videoTitle.trim()` 改为 `videoTitle.trim() || videoSecondaryTitle.trim()`,确保仅有副标题时也能发送显示模式 - **UI 调整**: 短暂显示/常驻显示下拉从片头标题输入行移至"二、标题与字幕"板块标题行(与预览样式按钮同行),明确表示该设置对标题和副标题同时生效 - Remotion 端 `Title.tsx` 已支持(标题和副标题作为整体组件渲染,`displayMode` 统一控制) ### 10. 时间轴模糊遮罩 遮罩从外层 wrapper 移入"四、素材编辑"卡片内,仅覆盖时间轴子区域(`rounded-xl`)。 ### 11. 登录后用户信息立即可用 - AuthContext 新增 `setUser` 方法暴露给消费者 - 登录页成功后调用 `setUser(result.user)` 立即写入 Context,无需等页面刷新 - 修复登录后账户下拉显示"未知账户"、刷新后才显示手机号的问题 ### 12. 文案与选项微调 - MaterialSelector 描述 `(可多选,最多4个)` → `(上传自拍视频,最多可选4个)` - TitleSubtitlePanel 显示模式选项 `短暂显示/常驻显示` → `标题短暂显示/标题常驻显示` ### 13. UI/UX 体验优化(6 项) - **操作按钮移动端可见**: 配音列表、作品列表、素材列表、参考音频、历史文案的操作按钮从 `opacity-0`(hover 才显示)改为 `opacity-40`(平时半透明可见,hover 全亮),解决触屏设备无法发现按钮的问题 - **手机号脱敏**: AccountSettingsDropdown 手机号中间四位遮掩 `138****5678` - **标题字数计数器**: TitleSubtitlePanel 标题/副标题输入框右侧显示实时字数 `3/15`,超限变红 - **列表滚动条提示**: ~~配音列表、作品列表、素材列表、BGM 列表从 `hide-scrollbar` 改为 `custom-scrollbar`~~ → 已全部改回 `hide-scrollbar` 隐藏滚动条(滚动功能不变) - **时间轴拖拽提示**: TimelineEditor 色块左上角新增 `GripVertical` 抓手图标,暗示可拖拽排序 - **截取滑块放大**: ClipTrimmer 手柄从 16px 放大到 20px,触控区从 32px 放大到 40px ### 14. 代码质量修复(4 项) - **AccountSettingsDropdown**: 关闭密码弹窗补齐 `setSuccess('')` 清空 - **MaterialSelector**: `selectedSet` 加 `useMemo` 避免每次渲染重建 - **TimelineEditor**: `visibleSegments`/`overflowSegments` 加 `useMemo` - **MaterialSelector**: 素材满 4 个时非选中项按钮加 `disabled` ### 15. 发布页平台账号响应式布局 - **单行布局**:图标+名称+状态在左,按钮在右(`flex items-center`) - **移动端紧凑**:图标 `h-6 w-6`、按钮 `text-xs px-2 py-1 rounded-md`、间距 `space-y-2 px-3 py-2.5` - **桌面端宽松**:`sm:h-7 sm:w-7`、`sm:text-sm sm:px-3 sm:py-1.5 sm:rounded-lg`、`sm:space-y-3 sm:px-4 sm:py-3.5` - 两端各自美观,风格与其他板块一致 ### 16. 移动端刷新回顶部修复 - **问题**: 移动端刷新页面后不回到顶部,而是滚动到背景音乐板块 - **根因**: 1) 浏览器原生滚动恢复覆盖 `scrollTo(0,0)`;2) 列表 scroll effect 有双依赖(`selectedId` + `list`),数据异步加载时第二次触发跳过了 ref 守卫,执行了 `scrollIntoView` 导致页面跳动 - **修复**: 三管齐下 — ① `history.scrollRestoration = "manual"` 禁用浏览器原生恢复;② 时间门控 `scrollEffectsEnabled` ref(1 秒内禁止所有列表自动滚动)替代单次 ref 守卫;③ 200ms 延迟兜底 `scrollTo(0,0)` ### 17. 移动端样式预览窗口缩小 - **问题**: 移动端点击"预览样式"后窗口占满整屏(宽 358px,高约 636px),遮挡样式调节控件 - **修复**: 移动端宽度从 `window.innerWidth - 32` 缩小到 **160px**;位置从左上角改为**右下角**(`right:12, bottom:12`),不遮挡上方控件;最大高度限制 `50dvh` - 桌面端保持不变(280px,左上角) ### 18. 列表滚动条统一隐藏 - 将 Day 26 早期改为 `custom-scrollbar`(细紫色滚动条)的 7 处全部改回 `hide-scrollbar` - 涉及:BgmPanel、GeneratedAudiosPanel、HistoryList、MaterialSelector(2处)、ScriptExtractionModal(2处) - 滚动功能不受影响,仅视觉上不显示滚动条 ### 19. 配音按钮移动端适配 - VoiceSelector "选择声音/克隆声音" 按钮:内边距 `px-4` → `px-2 sm:px-4`,字号加 `text-sm sm:text-base`,图标加 `shrink-0` - 修复移动端窄屏下按钮被挤压导致"克隆声音"不可见的问题 ### 20. 素材标题溢出修复 - MaterialSelector embedded 标题行移除 `whitespace-nowrap` - 描述文字 `(上传自拍视频,最多可选4个)` 在移动端隐藏(`hidden sm:inline`),桌面端正常显示 - 修复移动端刷新按钮被推出容器外的问题 ### 21. 生成配音按钮放大 - "生成配音" 作为核心操作按钮,从辅助尺寸升级为主操作尺寸 - 内边距 `px-2/px-3 py-1/py-1.5` → `px-4 py-2`,字号 `text-xs` → `text-sm font-medium` - 图标 `h-3.5 w-3.5` → `h-4 w-4`,新增 `shadow-sm` + hover `shadow-md` - embedded 与非 embedded 模式统一放大 ### 22. 生成进度条位置调整 - **问题**: 生成进度条在"六、作品"卡片内部(作品预览下方),不够醒目 - **修复**: 进度条从 PreviewPanel 内部提取到 HomePage 右栏,作为独立卡片渲染在"六、作品"卡片**上方** - 使用紫色边框(`border-purple-500/30`)区分,显示任务消息和百分比 - PreviewPanel embedded 模式下不再渲染进度条(传入 `currentTask={null}`) - 生成完成后进度卡片自动消失 ### 23. LatentSync 超时修复 - **问题**: 约 2 分钟的视频(3023 帧,190 段推理)预计推理 54 分钟,但 httpx 超时仅 20 分钟,导致 LatentSync 调用失败并回退到无口型同步 - **根因**: `lipsync_service.py` 中 `httpx.AsyncClient(timeout=1200.0)` 不足以覆盖长视频推理时间 - **修复**: 超时从 `1200s`(20 分钟)改为 `3600s`(1 小时),足以覆盖 2-3 分钟视频的推理 ### 24. 字幕时间戳节奏映射(修复长视频字幕漂移) - **问题**: 2 分钟视频字幕明显对不上语音,越到后面偏差越大 - **根因**: `whisper_service.py` 的 `original_text` 处理逻辑丢弃了 Whisper 逐词时间戳,仅保留总时间范围后做全程线性插值,每个字分配相同时长,完全忽略语速变化和停顿 - **修复**: 保留 Whisper 的逐字时间戳作为语音节奏模板,将原文字符按比例映射到 Whisper 时间节奏上(rhythm-mapping),而非线性均分。字幕文字不变,只是时间戳跟随真实语速 - **算法**: 原文第 i 个字符映射到 Whisper 时间线的 `(i/N)*M` 位置(N=原文字符数,M=Whisper字符数),在相邻 Whisper 时间点间线性插值 --- ## 📁 修改文件清单 | 文件 | 改动 | |------|------| | `VoiceSelector.tsx` | 新增 embedded prop,移动端按钮适配(`px-2 sm:px-4`) | | `GeneratedAudiosPanel.tsx` | 新增 embedded prop,两行布局,操作按钮可见度,"生成配音"按钮放大 | | `MaterialSelector.tsx` | 新增 embedded prop,自渲染子标题+操作按钮,useMemo,disabled 守卫,操作按钮可见度,标题溢出修复 | | `TimelineEditor.tsx` | 新增 embedded prop,自渲染子标题+控件,useMemo,拖拽抓手图标 | | `PreviewPanel.tsx` | 新增 embedded prop | | `HistoryList.tsx` | 新增 embedded prop,操作按钮可见度 | | `ScriptEditor.tsx` | 标题加序号,移除 emoji,操作按钮可见度 | | `TitleSubtitlePanel.tsx` | 标题加序号,移除 emoji,下拉对齐,显示模式下拉上移,字数计数器 | | `BgmPanel.tsx` | 标题加序号 | | `HomePage.tsx` | 核心重构:合并板块、序号标题、生成配音按钮迁入、`scrollRestoration` + 延迟兜底修复刷新回顶部、生成进度条提取到作品卡片上方 | | `PublishPage.tsx` | 四个板块加序号(七~十),移除 emoji,平台卡片响应式单行布局 | | `RefAudioPanel.tsx` | 简化提示文案,操作按钮可见度 | | `AccountSettingsDropdown.tsx` | 新增手机号显示(脱敏),补齐 success 清空 | | `AuthContext.tsx` | 新增 `setUser` 方法,登录后立即更新用户状态 | | `login/page.tsx` | 登录成功后调用 `setUser` 写入用户数据 | | `useHomeController.ts` | titleDisplayMode 条件修复,列表 scroll 时间门控 `scrollEffectsEnabled` | | `FloatingStylePreview.tsx` | 移动端预览窗口缩小(160px)并移至右下角 | | `ScriptExtractionModal.tsx` | 滚动条改回隐藏 | | `ClipTrimmer.tsx` | 滑块手柄放大、触控区增高 | | `lipsync_service.py` | httpx 超时从 1200s 改为 3600s | | `whisper_service.py` | 字幕时间戳从线性插值改为 Whisper 节奏映射 | --- ## 🔍 验证 - `npm run build` — 零报错零警告 - 合并后布局:各子板块分隔清晰、主标题有序号 - 向后兼容:`embedded` 默认 `false`,组件独立使用不受影响 - 配音列表两行布局:语速+生成配音在上,配音列表+刷新在下 - 下拉菜单垂直对齐正确 - 短暂显示/常驻显示对标题和副标题同时生效 - 操作按钮在移动端(触屏)可见 - 手机号脱敏显示 - 标题字数计数器正常 - 列表滚动条全部隐藏 - 时间轴拖拽抓手图标显示 - 发布页平台卡片:移动端紧凑、桌面端宽松,风格一致 - 移动端刷新后回到顶部,不再滚动到背景音乐位置 - 移动端样式预览窗口不遮挡控件 - 移动端配音按钮(选择声音/克隆声音)均可见 - 移动端素材标题行按钮不溢出 - 生成配音按钮视觉层级高于辅助按钮 - 生成进度条在作品卡片上方独立显示 - LatentSync 长视频推理不再超时回退 - 字幕时间戳与语音节奏同步,长视频不漂移