This commit is contained in:
Kevin Wong
2026-02-04 18:04:17 +08:00
parent aaa8088c82
commit b2c1042c5c
45 changed files with 1849 additions and 1592 deletions

View File

@@ -9,7 +9,7 @@
### 背景
统一处理 API 请求的认证失败场景,避免各页面重复处理 401/403 错误。
### 实现 (`frontend/src/lib/axios.ts`)
### 实现 (`frontend/src/shared/api/axios.ts`)
```typescript
import axios from 'axios';
@@ -325,7 +325,7 @@ models/Qwen3-TTS/
| 文件 | 变更类型 | 说明 |
|------|----------|------|
| `frontend/src/lib/axios.ts` | 修改 | Axios 全局拦截器 (401/403 自动跳转) |
| `frontend/src/shared/api/axios.ts` | 修改 | Axios 全局拦截器 (401/403 自动跳转) |
| `frontend/src/app/layout.tsx` | 修改 | viewport 配置 + body 渐变背景 |
| `frontend/src/app/globals.css` | 修改 | 安全区域 CSS 支持 |
| `frontend/src/app/page.tsx` | 修改 | 移除独立渐变 + Header 响应式 |

View File

@@ -358,7 +358,7 @@ const storageKey = userId || 'guest';
### 解决方案
**文件**: `frontend/src/lib/axios.ts`
**文件**: `frontend/src/shared/api/axios.ts`
在拦截器中对公开路由跳过重定向,仅在受保护页面触发登录跳转:
@@ -391,7 +391,7 @@ if ((status === 401 || status === 403) && !isRedirecting && !isPublicPath) {
| `backend/app/main.py` | 修改 | 注册 ai 路由 |
| `frontend/src/app/page.tsx` | 修改 | AI 生成按钮 + localStorage 修复 |
| `frontend/src/app/publish/page.tsx` | 修改 | 恢复 AI 生成的标签 |
| `frontend/src/lib/axios.ts` | 修改 | 公开路由跳过 401/403 登录重定向 |
| `frontend/src/shared/api/axios.ts` | 修改 | 公开路由跳过 401/403 登录重定向 |
---

View File

@@ -161,7 +161,7 @@ if (!/^\d{11}$/.test(phone)) {
### 3. Auth 工具函数 (`auth.ts`)
**文件**: `frontend/src/lib/auth.ts`
**文件**: `frontend/src/shared/lib/auth.ts`
```typescript
export interface User {
@@ -304,7 +304,7 @@ pm2 restart vigent2-backend vigent2-frontend
| `backend/.env` | 修改 | ADMIN_PHONE=15549380526 |
| `frontend/src/app/login/page.tsx` | 修改 | 手机号登录 + 11位验证 |
| `frontend/src/app/register/page.tsx` | 修改 | 手机号注册 + 11位验证 |
| `frontend/src/lib/auth.ts` | 修改 | phone 参数 + changePassword 函数 |
| `frontend/src/shared/lib/auth.ts` | 修改 | phone 参数 + changePassword 函数 |
| `frontend/src/app/page.tsx` | 修改 | AccountSettingsDropdown 组件 |
| `frontend/src/app/admin/page.tsx` | 修改 | 用户列表显示手机号 |
| `frontend/src/contexts/AuthContext.tsx` | 修改 | 存储完整用户信息含 expires_at |

View File

@@ -127,7 +127,7 @@ if service["failures"] >= service['threshold']:
- 交互按钮保持一致尺寸与对齐
### 涉及文件
- `frontend/src/components/home/`
- `frontend/src/features/home/ui/`
- `frontend/src/app/publish/page.tsx`
---

View File

@@ -4,7 +4,7 @@
### 内容
- 首页 `page.tsx` 拆分为独立 UI 组件,状态与逻辑仍集中在页面
- 新增首页组件目录 `frontend/src/components/home/`
- 新增首页组件目录 `frontend/src/features/home/ui/`
### 组件列表
- `HomeHeader`
@@ -27,7 +27,7 @@
- 首页与发布页统一调用,消除重复逻辑
### 涉及文件
- `frontend/src/lib/media.ts`
- `frontend/src/shared/lib/media.ts`
- `frontend/src/app/page.tsx`
- `frontend/src/app/publish/page.tsx`
@@ -102,12 +102,12 @@
- `useGeneratedVideos`:历史作品列表获取 + 选择逻辑抽取
### 涉及文件
- `frontend/src/hooks/useTitleSubtitleStyles.ts`
- `frontend/src/hooks/useMaterials.ts`
- `frontend/src/hooks/useRefAudios.ts`
- `frontend/src/hooks/useBgm.ts`
- `frontend/src/hooks/useMediaPlayers.ts`
- `frontend/src/hooks/useGeneratedVideos.ts`
- `frontend/src/features/home/model/useTitleSubtitleStyles.ts`
- `frontend/src/features/home/model/useMaterials.ts`
- `frontend/src/features/home/model/useRefAudios.ts`
- `frontend/src/features/home/model/useBgm.ts`
- `frontend/src/features/home/model/useMediaPlayers.ts`
- `frontend/src/features/home/model/useGeneratedVideos.ts`
- `frontend/src/app/page.tsx`
---
@@ -120,7 +120,7 @@
### 涉及文件
- `frontend/src/app/page.tsx`
- `frontend/src/hooks/useHomePersistence.ts`
- `frontend/src/features/home/model/useHomePersistence.ts`
---
@@ -134,10 +134,10 @@
### 涉及文件
- `frontend/src/app/publish/page.tsx`
- `frontend/src/hooks/useMediaPlayers.ts`
- `frontend/src/hooks/useBgm.ts`
- `frontend/src/hooks/useMaterials.ts`
- `frontend/src/components/home/RefAudioPanel.tsx`
- `frontend/src/features/home/model/useMediaPlayers.ts`
- `frontend/src/features/home/model/useBgm.ts`
- `frontend/src/features/home/model/useMaterials.ts`
- `frontend/src/features/home/ui/RefAudioPanel.tsx`
- `frontend/src/components/VideoPreviewModal.tsx`
- `frontend/src/app/layout.tsx`
@@ -150,6 +150,27 @@
- 标题输入兼容中文输入法,限制 15 字(发布信息同规则)
### 涉及文件
- `frontend/src/features/home/model/useHomeController.ts`
- `frontend/src/features/home/ui/TitleSubtitlePanel.tsx`
- `frontend/src/features/publish/model/usePublishController.ts`
---
## 🧱 轻量 FSD 迁移 (16:20)
### 内容
- 页面瘦身:`app` 仅保留入口组件,业务逻辑集中到 Controller Hook
- 引入 `features/*` 分层UI 与 model 分离Home/Publish 按功能聚合
- 通用能力下沉到 `shared/*`lib/hooks/api
### 涉及文件
- `frontend/src/features/home/ui/HomePage.tsx`
- `frontend/src/features/home/model/useHomeController.ts`
- `frontend/src/features/publish/ui/PublishPage.tsx`
- `frontend/src/features/publish/model/usePublishController.ts`
- `frontend/src/shared/lib/media.ts`
- `frontend/src/shared/lib/title.ts`
- `frontend/src/shared/api/axios.ts`
- `frontend/src/shared/hooks/useTitleInput.ts`
- `frontend/src/app/page.tsx`
- `frontend/src/components/home/TitleSubtitlePanel.tsx`
- `frontend/src/app/publish/page.tsx`

View File

@@ -228,7 +228,7 @@ else:
| 文件 | 说明 | 状态 |
|------|------|------|
| `src/lib/auth.ts` | 认证工具函数 | ✅ |
| `src/shared/lib/auth.ts` | 认证工具函数 | ✅ |
| `src/app/login/page.tsx` | 登录页 | ✅ |
| `src/app/register/page.tsx` | 注册页 | ✅ |
| `src/app/admin/page.tsx` | 管理后台 | ✅ |

View File

@@ -104,14 +104,14 @@ body {
### 必须使用 `api` (axios 实例)
所有需要认证的 API 请求**必须**使用 `@/lib/axios` 导出的 axios 实例。该实例已配置:
所有需要认证的 API 请求**必须**使用 `@/shared/api/axios` 导出的 axios 实例。该实例已配置:
- 自动携带 `credentials: include`
- 遇到 401/403 时自动清除 cookie 并跳转登录页
**使用方式:**
```typescript
import api from '@/lib/axios';
import api from '@/shared/api/axios';
// GET 请求
const { data } = await api.get('/api/materials');
@@ -140,7 +140,7 @@ await api.post('/api/materials', formData, {
### SWR 配合使用
```typescript
import api from '@/lib/axios';
import api from '@/shared/api/axios';
// SWR fetcher 使用 axios
const fetcher = (url: string) => api.get(url).then(res => res.data);
@@ -153,10 +153,10 @@ const { data } = useSWR('/api/xxx', fetcher, { refreshInterval: 2000 });
## 通用工具函数 (media.ts)
### 统一 API Base / URL 解析
使用 `@/lib/media` 统一处理服务端/客户端 API Base 与资源地址,避免硬编码:
使用 `@/shared/lib/media` 统一处理服务端/客户端 API Base 与资源地址,避免硬编码:
```typescript
import { getApiBaseUrl, resolveMediaUrl, resolveAssetUrl, formatDate } from '@/lib/media';
import { getApiBaseUrl, resolveMediaUrl, resolveAssetUrl, formatDate } from '@/shared/lib/media';
const apiBase = getApiBaseUrl(); // SSR: http://localhost:8006 / Client: ''
const playableUrl = resolveMediaUrl(video.path); // 兼容签名 URL 与相对路径
@@ -186,18 +186,28 @@ new Date(timestamp * 1000).toLocaleString('zh-CN')
**正确做法:**
```typescript
// ✅ 使用固定格式
import { formatDate } from '@/lib/media';
import { formatDate } from '@/shared/lib/media';
```
---
## 组件拆分规范
当页面组件超过 300-500 行,建议拆分到 `components/`
当页面组件超过 300-500 行,建议按功能拆分到 `features/*/ui`
- `page.tsx` 负责状态与业务逻辑
- 组件只接受 props 与回调,尽量不直接发 API
- 首页拆分组件统一放在 `components/home/`
- `page.tsx` 仅做组合与布局
- 业务逻辑集中在 `features/*/model` 的 Controller Hook
- UI 组件只接受 props 与回调,尽量不直接发 API
- 首页拆分组件统一放在 `features/home/ui/`
---
## 轻量 FSD 结构
- `app/`:页面入口,保持轻量
- `features/*/model`:业务逻辑与状态 (hooks)
- `features/*/ui`:功能 UI 组件
- `shared/`:通用工具、通用 hooks、API 实例
---
@@ -226,14 +236,15 @@ import { formatDate } from '@/lib/media';
- 中文输入法合成阶段不截断,合成结束后才校验长度。
- 首页片头标题修改会同步写入 `vigent_${storageKey}_publish_title`
- 避免使用 `maxLength` 强制截断输入法合成态。
- 推荐使用 `@/shared/hooks/useTitleInput` 统一处理输入逻辑。
---
## 新增页面 Checklist
1. [ ] 导入 `import api from '@/lib/axios'`
1. [ ] 导入 `import api from '@/shared/api/axios'`
2. [ ] 所有 API 请求使用 `api.get/post/delete()` 而非原生 `fetch`
3. [ ] 日期格式化使用 `@/lib/media``formatDate`
3. [ ] 日期格式化使用 `@/shared/lib/media``formatDate`
4. [ ] 资源 URL 使用 `resolveMediaUrl`/`resolveAssetUrl`
5. [ ] 添加 `'use client'` 指令(如需客户端交互)

View File

@@ -62,7 +62,7 @@ ViGent2 的前端界面,采用 Next.js 16 + TailwindCSS 构建。
- **样式**: TailwindCSS
- **图标**: Lucide React
- **组件**: 自定义现代化组件 (Glassmorphism 风格)
- **API**: Axios 实例 `@/lib/axios` (对接后端 FastAPI :8006)
- **API**: Axios 实例 `@/shared/api/axios` (对接后端 FastAPI :8006)
## 🚀 开发指南
@@ -85,22 +85,29 @@ npm run dev
```
src/
├── app/
├── app/ # 页面入口 (轻量)
│ ├── page.tsx # 视频生成主页
│ ├── publish/ # 发布管理页
│ │ └── page.tsx
│ └── layout.tsx # 全局布局 (导航栏)
├── components/ # UI 组件
│ ├── home/ # 首页拆分组件
└── ...
└── lib/ # 工具函数
└── media.ts # API Base / URL / 日期等通用工具
├── features/
│ ├── home/
│ ├── model/ # Home 业务逻辑 (hooks)
│ │ └── ui/ # Home UI 组件
└── publish/
│ ├── model/ # Publish 业务逻辑 (hooks)
│ └── ui/ # Publish UI 组件
├── shared/
│ ├── api/ # API 实例
│ ├── hooks/ # 通用 hooks
│ └── lib/ # 工具函数
└── components/ # 跨页面复用 UI
```
## 🔌 后端对接
- **Base URL**: `http://localhost:8006` (SSR) / 相对路径 (Client)
- **URL 统一工具**: `@/lib/media` 提供 `resolveMediaUrl` / `resolveAssetUrl`
- **URL 统一工具**: `@/shared/lib/media` 提供 `resolveMediaUrl` / `resolveAssetUrl`
- **代理配置**: Next.js Rewrites (如需) 或直接 CORS。
## 🎨 设计规范

View File

@@ -60,7 +60,7 @@
## ✅ 现状补充 (Day 17)
- 前端已拆分为组件化结构(`components/home/`),主页面逻辑集中。
- 前端已拆分为组件化结构(`features/home/ui/`),主页面逻辑集中。
- 通用工具 `media.ts` 统一处理 API Base / 资源 URL / 日期格式化。
- 作品预览弹窗统一样式,并支持素材/发布预览复用。
- 标题/字幕预览按素材分辨率缩放,效果更接近成片。

View File

@@ -12,11 +12,14 @@
### Day 17: 前端重构与体验优化 (Current) 🚀
- [x] **UI 组件拆分**: 首页拆分为独立组件,降低 `page.tsx` 复杂度。
- [x] **轻量 FSD 迁移**: `app` 页面轻量化,逻辑集中到 `features/*/model`,通用能力下沉 `shared/*`
- [x] **Controller Hooks**: Home/Publish 页面逻辑集中到 Controller HookPage 仅组合渲染。
- [x] **通用工具抽取**: `media.ts` 统一 API Base / URL / 日期格式化。
- [x] **交互优化**: 选择项持久化、列表内定位、刷新回顶部、最新作品优先预览。
- [x] **发布页改造**: 作品列表卡片化 + 搜索 + 预览弹窗。
- [x] **预览体验**: 预览弹窗统一头部样式与提示文案。
- [x] **预览一致性**: 标题/字幕预览按素材分辨率缩放。
- [x] **标题同步与限制**: 片头标题同步发布标题,输入法合成态兼容,限制 15 字。
- [x] **样式默认与持久化**: 默认样式与字号调整,刷新保留用户选择。
- [x] **性能微优化**: 列表渲染优化 + 并行请求 + localStorage 防抖。
- [x] **资源能力**: 字体/BGM 资源库 + `/api/assets` 接入。