更新
This commit is contained in:
@@ -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 响应式 |
|
||||
|
||||
@@ -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 登录重定向 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -127,7 +127,7 @@ if service["failures"] >= service['threshold']:
|
||||
- 交互按钮保持一致尺寸与对齐
|
||||
|
||||
### 涉及文件
|
||||
- `frontend/src/components/home/`
|
||||
- `frontend/src/features/home/ui/`
|
||||
- `frontend/src/app/publish/page.tsx`
|
||||
|
||||
---
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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` | 管理后台 | ✅ |
|
||||
|
||||
@@ -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'` 指令(如需客户端交互)
|
||||
|
||||
|
||||
@@ -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。
|
||||
|
||||
## 🎨 设计规范
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
## ✅ 现状补充 (Day 17)
|
||||
|
||||
- 前端已拆分为组件化结构(`components/home/`),主页面逻辑集中。
|
||||
- 前端已拆分为组件化结构(`features/home/ui/`),主页面逻辑集中。
|
||||
- 通用工具 `media.ts` 统一处理 API Base / 资源 URL / 日期格式化。
|
||||
- 作品预览弹窗统一样式,并支持素材/发布预览复用。
|
||||
- 标题/字幕预览按素材分辨率缩放,效果更接近成片。
|
||||
|
||||
@@ -12,11 +12,14 @@
|
||||
|
||||
### Day 17: 前端重构与体验优化 (Current) 🚀
|
||||
- [x] **UI 组件拆分**: 首页拆分为独立组件,降低 `page.tsx` 复杂度。
|
||||
- [x] **轻量 FSD 迁移**: `app` 页面轻量化,逻辑集中到 `features/*/model`,通用能力下沉 `shared/*`。
|
||||
- [x] **Controller Hooks**: Home/Publish 页面逻辑集中到 Controller Hook,Page 仅组合渲染。
|
||||
- [x] **通用工具抽取**: `media.ts` 统一 API Base / URL / 日期格式化。
|
||||
- [x] **交互优化**: 选择项持久化、列表内定位、刷新回顶部、最新作品优先预览。
|
||||
- [x] **发布页改造**: 作品列表卡片化 + 搜索 + 预览弹窗。
|
||||
- [x] **预览体验**: 预览弹窗统一头部样式与提示文案。
|
||||
- [x] **预览一致性**: 标题/字幕预览按素材分辨率缩放。
|
||||
- [x] **标题同步与限制**: 片头标题同步发布标题,输入法合成态兼容,限制 15 字。
|
||||
- [x] **样式默认与持久化**: 默认样式与字号调整,刷新保留用户选择。
|
||||
- [x] **性能微优化**: 列表渲染优化 + 并行请求 + localStorage 防抖。
|
||||
- [x] **资源能力**: 字体/BGM 资源库 + `/api/assets` 接入。
|
||||
|
||||
Reference in New Issue
Block a user