# Day 12 - iOS 兼容与移动端 UI 优化 **日期**:2026-01-28 --- ## 🔐 Axios 全局拦截器优化 ### 背景 统一处理 API 请求的认证失败场景,避免各页面重复处理 401/403 错误。 ### 实现 (`frontend/src/lib/axios.ts`) ```typescript import axios from 'axios'; // 动态获取 API 地址:服务端使用 localhost,客户端使用当前域名 const API_BASE = typeof window === 'undefined' ? 'http://localhost:8006' : ''; // 防止重复跳转 let isRedirecting = false; const api = axios.create({ baseURL: API_BASE, withCredentials: true, // 自动携带 HttpOnly cookie headers: { 'Content-Type': 'application/json' }, }); // 响应拦截器 - 全局处理 401/403 api.interceptors.response.use( (response) => response, async (error) => { const status = error.response?.status; if ((status === 401 || status === 403) && !isRedirecting) { isRedirecting = true; // 调用 logout API 清除 HttpOnly cookie try { await fetch('/api/auth/logout', { method: 'POST' }); } catch (e) { /* 忽略 */ } // 跳转登录页 if (typeof window !== 'undefined') { window.location.replace('/login'); } } return Promise.reject(error); } ); export default api; ``` ### 关键特性 - ✅ **自动携带 Cookie**: `withCredentials: true` 确保 HttpOnly JWT cookie 被发送 - ✅ **401/403 自动跳转**: 认证失败时自动清理并跳转登录页 - ✅ **防重复跳转**: `isRedirecting` 标志避免多个请求同时触发跳转 - ✅ **SSR 兼容**: 服务端渲染时使用 `localhost`,客户端使用相对路径 --- ## 🔧 iOS Safari 安全区域白边修复 ### 问题描述 iPhone Safari 浏览器底部和顶部显示白色区域,安卓正常。原因是 iOS Safari 有安全区域 (Safe Area),页面背景没有延伸到该区域。 ### 根本原因 1. 缺少 `viewport-fit=cover` 配置 2. `min-h-screen` (100vh) 在 iOS Safari 中不包含安全区域 3. 背景渐变在页面 div 上,而非 body 上,导致安全区域显示纯色 ### 解决方案 #### 1. 添加 viewport 配置 (`layout.tsx`) ```typescript export const viewport: Viewport = { width: 'device-width', initialScale: 1, viewportFit: 'cover', // 允许内容延伸到安全区域 themeColor: '#0f172a', // 顶部状态栏颜色 }; ``` #### 2. 统一渐变背景到 body (`layout.tsx`) ```tsx {children} ``` #### 3. CSS 安全区域支持 (`globals.css`) ```css html { background-color: #0f172a !important; min-height: 100%; } body { margin: 0 !important; min-height: 100dvh; padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); } ``` #### 4. 移除页面独立渐变背景 各页面的根 div 移除 `bg-gradient-to-br` 类,统一使用 body 渐变: - `page.tsx` - `login/page.tsx` - `publish/page.tsx` - `admin/page.tsx` - `register/page.tsx` ### 结果 - ✅ 顶部状态栏颜色与页面一致 (themeColor) - ✅ 底部安全区域颜色与渐变边缘一致 - ✅ 消除分层感,背景统一 --- ## 📱 移动端 Header 响应式优化 ### 问题描述 移动端顶部导航按钮(视频生成、发布管理、退出)过于拥挤,文字换行显示。 ### 解决方案 #### 首页 Header (`page.tsx`) ```tsx
🎬 ViGent
视频生成
``` #### 发布管理页 Header (`publish/page.tsx`) 同步应用相同的响应式类名。 ### 关键改动 | 属性 | 移动端 | 桌面端 | |------|--------|--------| | 容器内边距 | `px-4 py-3` | `px-6 py-4` | | 按钮间距 | `gap-1` | `gap-4` | | 按钮内边距 | `px-2 py-1` | `px-4 py-2` | | 字体大小 | `text-sm` | `text-base` | | Logo 大小 | `text-xl` + `text-3xl` | `text-2xl` + `text-4xl` | ### 结果 - ✅ 移动端按钮紧凑排列,不再换行 - ✅ 桌面端保持原有宽松布局 --- ## 🚀 发布页面 UI 重构 ### 问题描述 原有设计将"发布时间"选项放在表单中,用户可能误选"定时发布"但忘记设置时间。 ### 解决方案 将"一键发布"按钮改为两个独立按钮: - **立即发布** (绿色,占 3/4 宽度) - 主要操作 - **定时** (占 1/4 宽度) - 点击展开时间选择器 #### 新布局 (`publish/page.tsx`) ```tsx {/* 发布按钮区域 */}
{/* 立即发布 - 占 3/4 */} {/* 定时发布 - 占 1/4 */}
{/* 定时发布时间选择器 (展开时显示) */} {scheduleMode === "scheduled" && (
)}
``` ### 结果 - ✅ 主操作(立即发布)更醒目 - ✅ 定时发布需要二次确认,防止误触 - ✅ 从表单区域移除发布时间选项,界面更简洁 --- ## 🛤️ 后续优化项 ### 后端定时发布 (待实现) **当前状态**:定时发布使用平台端定时(在各平台设置发布时间) **优化方向**:改为后端定时任务 - 使用 APScheduler 实现任务调度 - 存储定时任务到数据库 - 到时间后端自动触发发布 API - 支持查看/取消定时任务 **优势**: - 统一逻辑,不依赖平台定时 UI - 更灵活,可管理定时任务 - 平台页面更新不影响功能 --- ## 🤖 Qwen3-TTS 0.6B 声音克隆部署 ### 背景 为实现用户自定义声音克隆功能,部署 Qwen3-TTS 0.6B-Base 模型,支持 3 秒参考音频快速克隆。 ### GPU 分配 | GPU | 服务 | 模型 | |-----|------|------| | GPU0 | Qwen3-TTS | 0.6B-Base (声音克隆) | | GPU1 | LatentSync | 1.6 (唇形同步) | ### 部署步骤 #### 1. 克隆仓库 ```bash cd /home/rongye/ProgramFiles/ViGent2/models git clone https://github.com/QwenLM/Qwen3-TTS.git ``` #### 2. 创建 conda 环境 ```bash conda create -n qwen-tts python=3.10 -y conda activate qwen-tts ``` #### 3. 安装依赖 ```bash cd Qwen3-TTS pip install -e . conda install -y -c conda-forge sox # 音频处理依赖 ``` #### 4. 下载模型权重 (使用 ModelScope,国内更快) ```bash pip install modelscope # Tokenizer (651MB) modelscope download --model Qwen/Qwen3-TTS-Tokenizer-12Hz --local_dir ./checkpoints/Tokenizer # 0.6B-Base 模型 (2.4GB) modelscope download --model Qwen/Qwen3-TTS-12Hz-0.6B-Base --local_dir ./checkpoints/0.6B-Base ``` #### 5. 测试推理 ```python # test_inference.py import torch import soundfile as sf from qwen_tts import Qwen3TTSModel model = Qwen3TTSModel.from_pretrained( "./checkpoints/0.6B-Base", device_map="cuda:0", dtype=torch.bfloat16, ) wavs, sr = model.generate_voice_clone( text="测试文本", language="Chinese", ref_audio="./examples/myvoice.wav", ref_text="参考音频的文字内容", ) sf.write("output.wav", wavs[0], sr) ``` ### 测试结果 - ✅ 模型加载成功 (GPU0) - ✅ 声音克隆推理成功 - ✅ 输出音频 24000Hz,质量良好 ### 目录结构 ``` models/Qwen3-TTS/ ├── checkpoints/ │ ├── Tokenizer/ # 651MB │ └── 0.6B-Base/ # 2.4GB ├── qwen_tts/ # 源码 ├── examples/ │ └── myvoice.wav # 参考音频 └── test_inference.py # 测试脚本 ``` --- ## 📁 今日修改文件清单 | 文件 | 变更类型 | 说明 | |------|----------|------| | `frontend/src/lib/axios.ts` | 修改 | Axios 全局拦截器 (401/403 自动跳转) | | `frontend/src/app/layout.tsx` | 修改 | viewport 配置 + body 渐变背景 | | `frontend/src/app/globals.css` | 修改 | 安全区域 CSS 支持 | | `frontend/src/app/page.tsx` | 修改 | 移除独立渐变 + Header 响应式 | | `frontend/src/app/login/page.tsx` | 修改 | 移除独立渐变 | | `frontend/src/app/publish/page.tsx` | 修改 | Header 响应式 + 发布按钮重构 | | `frontend/src/app/admin/page.tsx` | 修改 | 移除独立渐变 | | `frontend/src/app/register/page.tsx` | 修改 | 移除独立渐变 | | `README.md` | 修改 | 添加 "iOS/Android 移动端适配" 功能说明 | | `Docs/FRONTEND_DEV.md` | 修改 | iOS Safari 安全区域兼容规范 + 移动端响应式规则 | | `models/Qwen3-TTS/` | 新增 | Qwen3-TTS 声音克隆模型部署 | | `Docs/QWEN3_TTS_DEPLOY.md` | 新增 | Qwen3-TTS 部署指南 | --- ## 🔗 相关文档 - [task_complete.md](../task_complete.md) - 任务总览 - [Day11.md](./Day11.md) - 上传架构重构 - [QWEN3_TTS_DEPLOY.md](../QWEN3_TTS_DEPLOY.md) - Qwen3-TTS 部署指南