9.6 KiB
9.6 KiB
Day 12 - iOS 兼容与移动端 UI 优化
日期:2026-01-28
🔐 Axios 全局拦截器优化
背景
统一处理 API 请求的认证失败场景,避免各页面重复处理 401/403 错误。
实现 (frontend/src/lib/axios.ts)
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),页面背景没有延伸到该区域。
根本原因
- 缺少
viewport-fit=cover配置 min-h-screen(100vh) 在 iOS Safari 中不包含安全区域- 背景渐变在页面 div 上,而非 body 上,导致安全区域显示纯色
解决方案
1. 添加 viewport 配置 (layout.tsx)
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
viewportFit: 'cover', // 允许内容延伸到安全区域
themeColor: '#0f172a', // 顶部状态栏颜色
};
2. 统一渐变背景到 body (layout.tsx)
<html lang="en" style={{ backgroundColor: '#0f172a' }}>
<body
style={{
margin: 0,
minHeight: '100dvh',
background: 'linear-gradient(to bottom, #0f172a 0%, #0f172a 5%, #581c87 50%, #0f172a 95%, #0f172a 100%)',
}}
>
{children}
</body>
</html>
3. CSS 安全区域支持 (globals.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.tsxlogin/page.tsxpublish/page.tsxadmin/page.tsxregister/page.tsx
结果
- ✅ 顶部状态栏颜色与页面一致 (themeColor)
- ✅ 底部安全区域颜色与渐变边缘一致
- ✅ 消除分层感,背景统一
📱 移动端 Header 响应式优化
问题描述
移动端顶部导航按钮(视频生成、发布管理、退出)过于拥挤,文字换行显示。
解决方案
首页 Header (page.tsx)
<header className="border-b border-white/10 bg-black/20 backdrop-blur-sm">
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-3 sm:py-4 flex items-center justify-between">
<Link href="/" className="text-xl sm:text-2xl font-bold ...">
<span className="text-3xl sm:text-4xl">🎬</span>
ViGent
</Link>
<div className="flex items-center gap-1 sm:gap-4">
<span className="px-2 sm:px-4 py-1 sm:py-2 text-sm sm:text-base ...">
视频生成
</span>
<!-- 其他按钮同样处理 -->
</div>
</div>
</header>
发布管理页 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)
{/* 发布按钮区域 */}
<div className="space-y-3">
<div className="flex gap-3">
{/* 立即发布 - 占 3/4 */}
<button
onClick={() => { setScheduleMode("now"); handlePublish(); }}
className="flex-[3] py-4 rounded-xl font-bold text-lg bg-gradient-to-r from-green-600 to-teal-600 ..."
>
🚀 立即发布
</button>
{/* 定时发布 - 占 1/4 */}
<button
onClick={() => setScheduleMode(scheduleMode === "scheduled" ? "now" : "scheduled")}
className="flex-1 py-4 rounded-xl font-bold text-base ..."
>
⏰ 定时
</button>
</div>
{/* 定时发布时间选择器 (展开时显示) */}
{scheduleMode === "scheduled" && (
<div className="flex gap-3 items-center">
<input type="datetime-local" ... />
<button>确认定时</button>
</div>
)}
</div>
结果
- ✅ 主操作(立即发布)更醒目
- ✅ 定时发布需要二次确认,防止误触
- ✅ 从表单区域移除发布时间选项,界面更简洁
🛤️ 后续优化项
后端定时发布 (待实现)
当前状态:定时发布使用平台端定时(在各平台设置发布时间)
优化方向:改为后端定时任务
- 使用 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. 克隆仓库
cd /home/rongye/ProgramFiles/ViGent2/models
git clone https://github.com/QwenLM/Qwen3-TTS.git
2. 创建 conda 环境
conda create -n qwen-tts python=3.10 -y
conda activate qwen-tts
3. 安装依赖
cd Qwen3-TTS
pip install -e .
conda install -y -c conda-forge sox # 音频处理依赖
4. 下载模型权重 (使用 ModelScope,国内更快)
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. 测试推理
# 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 - 任务总览
- Day11.md - 上传架构重构
- QWEN3_TTS_DEPLOY.md - Qwen3-TTS 部署指南