# 小虾 SaaS 前端页面重构改造计划

> 版本：v1.0 | 日期：2026-06-28 | 作者：前端编码  
> 状态：规划阶段，暂未改动代码

---

## 一、背景与目标

### 1.1 背景
产品从「项目制」改为「扁平化」结构，去掉 Workspace（工作空间）和 Project（项目）两层嵌套。用户不再需要「先选工作空间 → 再选项目 → 再进入功能页」，而是直接面对各功能模块。

### 1.2 目标
- 去除 Workspace / Project 层级，所有资源归用户直接所有
- 页面路由扁平化，一级路由直达各功能
- 保留并适配现有功能：素材库、标题库、配音库、模板库、一键生成、生成记录、成品库、订阅管理
- 兼顾移动端响应式体验

---

## 二、现有代码结构分析

### 2.1 当前路由结构

```
/                           → 重定向到 /projects
/login                      → 登录
/register                   → 注册
/forgot-password            → 忘记密码
/reset-password             → 重置密码
/projects                   → 工作空间/项目列表（WorkspaceList）
/projects/:id/assets        → 项目素材库（ProjectAssets）
/projects/:id/titles        → 项目标题库（ProjectTitles）
/projects/:id/voices        → 项目配音库（ProjectVoices）
/projects/:id/generation    → 项目视频剪辑（ProjectGeneration）
/projects/:id/tasks         → 项目任务列表（ProjectTasks）
/projects/:id/results       → 项目成片库（ProjectResults）
/subscription               → 订阅套餐（Plans）
/subscription/upgrade       → 升级订阅（UpgradeSubscription）
/subscription/billing       → 账单管理（Billing）
/admin                      → 管理后台（AdminComingSoon）
/admin/users                → 用户管理
/admin/analytics            → 数据分析
/admin/monitor              → 监控面板
/admin/logs                 → 日志查看
/profile                    → 个人设置（Settings）
```

### 2.2 当前页面文件清单

| 文件路径 | 行数 | 功能 | 改造命运 |
|---------|------|------|---------|
| `pages/workspace/WorkspaceList.tsx` | 99 | 项目列表 + 工作空间选择 | **删除** |
| `pages/workspace/ProjectAssets.tsx` | 93 | 项目内素材管理 | **改造** → 全局素材库 |
| `pages/workspace/ProjectTitles.tsx` | 110 | 项目内标题管理 | **改造** → 全局标题库 |
| `pages/workspace/ProjectVoices.tsx` | 52 | 项目内配音管理 | **改造** → 全局配音库 |
| `pages/workspace/ProjectGeneration.tsx` | 423 | 项目内视频生成（核心页面） | **改造** → 一键生成 |
| `pages/workspace/ProjectTasks.tsx` | 131 | 项目内任务列表 | **改造** → 生成记录 |
| `pages/workspace/ProjectResults.tsx` | 51 | 项目内成片展示 | **改造** → 成品库 |
| `pages/subscription/Plans.tsx` | — | 订阅套餐 | **保留** |
| `pages/subscription/UpgradeSubscription.tsx` | — | 升级订阅 | **保留** |
| `pages/subscription/Billing.tsx` | — | 账单管理 | **保留** |
| `pages/admin/AdminComingSoon.tsx` | — | 管理后台占位 | **保留** |
| `pages/auth/Login.tsx` | — | 登录 | **保留** |
| `pages/auth/Register.tsx` | — | 注册 | **保留** |
| `pages/auth/ForgotPassword.tsx` | — | 忘记密码 | **保留** |
| `pages/auth/ResetPassword.tsx` | — | 重置密码 | **保留** |
| `pages/profile/Settings.tsx` | — | 个人设置 | **保留** |

### 2.3 当前 API 层分析

| API 文件 | 接口前缀 | 改造影响 |
|---------|---------|---------|
| `api/workspace.ts` | `/workspaces` | **删除** — 不再需要工作空间 CRUD |
| `api/assets.ts` | `/projects/:id/...`, `/asset-libraries`, `/assets`, `/upload` | **改造** — 去掉 `project_id` 参数 |
| `api/editPlans.ts` | `/projects/:id/edit-plans/...` | **改造** — 去掉 `projectId` 前缀 |
| `api/tasks.ts` | `/projects/:id/tasks`, `/tasks/:type/:id/retry` | **改造** — 去掉 `projectId` |
| `api/auth.ts` | `/auth/...` | **不变** |
| `api/client.ts` | Axios 实例 | **不变** |

### 2.4 关键组件与 Hook

| 文件 | 功能 | 改造命运 |
|------|------|---------|
| `components/layout/MainLayout.tsx` | 布局壳（Outlet） | **保留**，微调 |
| `components/layout/Header.tsx` | 顶部导航，动态渲染项目子导航 | **改造** — 去掉 projectId 逻辑，改为固定一级导航 |
| `hooks/useWorkspace.ts` | 工作空间状态管理 | **删除** |
| `hooks/useAuth.ts` | 认证状态管理 | **保留** |
| `store/authStore.ts` | 认证 Zustand store | **保留** |

---

## 三、新路由结构设计

### 3.1 新路由表

```
/                           → 重定向到 /assets（首页即素材库）
/login                      → 登录（不变）
/register                   → 注册（不变）
/forgot-password            → 忘记密码（不变）
/reset-password             → 重置密码（不变）

# ── 以下均在 MainLayout (ProtectedRoute) 内 ──

/assets                     → 素材库
/titles                     → 标题库
/voices                     → 配音库
/templates                  → 模板库（新增）
/generate                   → 一键生成
/history                    → 生成记录
/products                   → 成品库
/subscription               → 订阅套餐（不变）
/subscription/upgrade       → 升级订阅（不变）
/subscription/billing       → 账单管理（不变）
/admin                      → 管理后台（不变）
/admin/users                → 用户管理（不变）
/admin/analytics            → 数据分析（不变）
/admin/monitor              → 监控面板（不变）
/admin/logs                 → 日志查看（不变）
/profile                    → 个人设置（不变）
```

### 3.2 路由设计说明

| 新路由 | 对应旧路由 | 说明 |
|--------|-----------|------|
| `/assets` | `/projects/:id/assets` | 去掉 projectId，展示用户所有素材 |
| `/titles` | `/projects/:id/titles` | 去掉 projectId，展示用户所有标题 |
| `/voices` | `/projects/:id/voices` | 去掉 projectId，展示用户所有配音 |
| `/templates` | 无（新增） | 模板库，从 ProjectGeneration 的模板选择部分独立出来 |
| `/generate` | `/projects/:id/generation` | 去掉 projectId，一键生成入口 |
| `/history` | `/projects/:id/tasks` | 去掉 projectId，展示用户所有生成任务 |
| `/products` | `/projects/:id/results` | 去掉 projectId，展示用户所有成品 |
| `/subscription` | `/subscription` | 不变 |
| `/profile` | `/profile` | 不变 |
| `/admin/*` | `/admin/*` | 不变 |

### 3.3 默认首页

首页 `/` 重定向到 `/assets`（素材库），因为素材是视频制作流程的起点，用户最常访问。

---

## 四、页面改造详细方案

### 4.1 删除页面（1 个）

#### WorkspaceList.tsx → 删除
- 原因：不再有工作空间/项目概念
- 相关功能（如「创建项目」）迁移到素材库页面的「上传素材」流程中

### 4.2 改造页面（6 个）

#### ProjectAssets.tsx → `pages/assets/AssetLibrary.tsx`
- **重命名** + 移动到 `pages/assets/` 目录
- **去除** `projectId` 参数和路由依赖
- **改造** API 调用：`getAssetLibraries(projectId)` → `getAssetLibraries()`（后端需配合去掉 project_id）
- 页面内「新建素材库」表单去掉 project_id 字段
- 上传流程简化：直接上传到用户空间，不再需要先选项目再选素材库

#### ProjectTitles.tsx → `pages/titles/TitleLibrary.tsx`
- **重命名** + 移动到 `pages/titles/` 目录
- **去除** projectId 相关逻辑
- API 调用适配（后端需提供无 projectId 的标题列表接口）

#### ProjectVoices.tsx → `pages/voices/VoiceLibrary.tsx`
- **重命名** + 移动到 `pages/voices/` 目录
- **去除** projectId 相关逻辑
- API 调用适配

#### ProjectGeneration.tsx → `pages/generate/GeneratePage.tsx`
- **重命名** + 移动到 `pages/generate/` 目录
- 这是最复杂的页面（423 行），包含：
  - 模板选择 → 部分拆到 `/templates` 模板库
  - 素材库选择 → 改为全局素材库下拉
  - 标题选择 → 改为全局标题库下拉
  - 配音选择 → 改为全局配音库下拉
  - 编排计划生成/编辑 → 保留，去掉 projectId
  - 生成任务提交 → 保留，去掉 projectId
- **拆分**：模板浏览部分独立为 `pages/templates/TemplateLibrary.tsx`

#### ProjectTasks.tsx → `pages/history/TaskHistory.tsx`
- **重命名** + 移动到 `pages/history/` 目录
- **去除** projectId 过滤
- 展示用户所有生成任务（后端需支持按 user_id 查询）

#### ProjectResults.tsx → `pages/products/ProductLibrary.tsx`
- **重命名** + 移动到 `pages/products/` 目录
- **去除** projectId 过滤
- 展示用户所有成品视频

### 4.3 新增页面（1 个）

#### `pages/templates/TemplateLibrary.tsx`（新增）
- 模板库，展示所有可用编辑模板
- 功能从 ProjectGeneration.tsx 的模板选择部分抽取
- 支持模板预览、收藏、按类型筛选
- API：需后端提供 `/templates` 全局模板列表接口

### 4.4 保留不变的页面（11 个）

| 页面 | 说明 |
|------|------|
| `pages/auth/Login.tsx` | 登录 |
| `pages/auth/Register.tsx` | 注册 |
| `pages/auth/ForgotPassword.tsx` | 忘记密码 |
| `pages/auth/ResetPassword.tsx` | 重置密码 |
| `pages/subscription/Plans.tsx` | 订阅套餐 |
| `pages/subscription/UpgradeSubscription.tsx` | 升级订阅 |
| `pages/subscription/Billing.tsx` | 账单管理 |
| `pages/admin/AdminComingSoon.tsx` | 管理后台占位 |
| `pages/profile/Settings.tsx` | 个人设置 |

---

## 五、组件与 Hook 改造

### 5.1 Header.tsx 改造

**现状**：Header 通过 `extractProjectId(pathname)` 解析 URL 中的 projectId，动态渲染项目子导航。

**改造方案**：
- 删除 `extractProjectId` 函数
- 导航项改为固定一级菜单：

```tsx
const navItems = [
  { key: 'assets',     label: '素材库',   path: '/assets' },
  { key: 'titles',     label: '标题库',   path: '/titles' },
  { key: 'voices',     label: '配音库',   path: '/voices' },
  { key: 'templates',  label: '模板库',   path: '/templates' },
  { key: 'generate',   label: '一键生成', path: '/generate' },
  { key: 'history',    label: '生成记录', path: '/history' },
  { key: 'products',   label: '成品库',   path: '/products' },
  { key: 'subscription', label: '订阅',   path: '/subscription' },
];
```

- 移动端下导航收起为汉堡菜单（Drawer）

### 5.2 删除 Hook

- `hooks/useWorkspace.ts` — 删除，不再需要工作空间状态

### 5.3 删除 API 文件

- `api/workspace.ts` — 删除，不再需要工作空间 CRUD API

### 5.4 改造 API 文件

#### `api/assets.ts`
```diff
- export const getAssetLibraries = async (projectId: string) => {
-   const response = await apiClient.get('/asset-libraries', { params: { project_id: projectId } });
+ export const getAssetLibraries = async () => {
+   const response = await apiClient.get('/asset-libraries');
    return response.data.items;
  };

- export const createAssetLibrary = async (data: { project_id: string; name: string; kind: '...' }) => {
+ export const createAssetLibrary = async (data: { name: string; kind: '...' }) => {
    ...
  };

- export const uploadAssetDirect = async (data: { file: File; project_id: string; library_id: string }) => {
+ export const uploadAssetDirect = async (data: { file: File; library_id: string }) => {
    ...
  };
```

#### `api/editPlans.ts`
```diff
- export const getEditTemplates = async (projectId: string) => {
-   const response = await apiClient.get(`/projects/${projectId}/edit-plans/templates`);
+ export const getEditTemplates = async () => {
+   const response = await apiClient.get('/templates');
    return response.data;
  };

- export const createEditPlan = async ({ projectId, data }) => {
-   const response = await apiClient.post(`/projects/${projectId}/edit-plans`, data);
+ export const createEditPlan = async (data: { asset_library_id: string; template_id?: string; title_id?: string }) => {
+   const response = await apiClient.post('/edit-plans', data);
    return response.data;
  };

// 同理：getEditPlans, getEditPlan, autoGenerateEditPlan, deleteEditPlan, updateEditPlan
// 全部去掉 projectId 参数
```

#### `api/tasks.ts`
```diff
- export const getProjectTasks = async (projectId: string) => {
-   const response = await apiClient.get(`/projects/${projectId}/tasks`);
+ export const getUserTasks = async () => {
+   const response = await apiClient.get('/tasks');
    return response.data.items;
  };
```

---

## 六、新目录结构

```
src/
├── api/
│   ├── assets.ts          # 改造：去掉 project_id
│   ├── auth.ts            # 不变
│   ├── client.ts          # 不变
│   ├── editPlans.ts       # 改造：去掉 projectId
│   ├── tasks.ts           # 改造：去掉 projectId
│   └── templates.ts       # 新增：模板 API
│   ✗ workspace.ts         # 删除
├── components/
│   └── layout/
│       ├── Header.tsx     # 改造：固定一级导航
│       └── MainLayout.tsx # 微调
├── hooks/
│   ├── useAuth.ts         # 不变
│   ✗ useWorkspace.ts      # 删除
├── pages/
│   ├── auth/              # 不变
│   ├── assets/            # 新增目录
│   │   └── AssetLibrary.tsx      # 改造自 ProjectAssets
│   ├── titles/            # 新增目录
│   │   └── TitleLibrary.tsx      # 改造自 ProjectTitles
│   ├── voices/            # 新增目录
│   │   └── VoiceLibrary.tsx      # 改造自 ProjectVoices
│   ├── templates/         # 新增目录
│   │   └── TemplateLibrary.tsx   # 新增
│   ├── generate/          # 新增目录
│   │   └── GeneratePage.tsx      # 改造自 ProjectGeneration
│   ├── history/           # 新增目录
│   │   └── TaskHistory.tsx       # 改造自 ProjectTasks
│   ├── products/          # 新增目录
│   │   └── ProductLibrary.tsx    # 改造自 ProjectResults
│   ├── subscription/      # 不变
│   ├── admin/             # 不变
│   └── profile/           # 不变
├── store/
│   └── authStore.ts       # 不变
├── router/
│   └── index.tsx          # 改造：全新路由表
└── test/
    └── ...                # 更新测试用例
```

---

## 七、API 路由变更映射（前后端对照）

> 需后端同步改造，以下为建议的新 API 路由

| 旧 API | 新 API | 说明 |
|--------|--------|------|
| `GET /workspaces` | — | 删除 |
| `GET /workspaces/:id` | — | 删除 |
| `POST /workspaces` | — | 删除 |
| `GET /workspaces/:id/members` | — | 删除 |
| `POST /workspaces/:id/members/invite` | — | 删除 |
| `DELETE /workspaces/:id/members/:mid` | — | 删除 |
| `PATCH /workspaces/:id/members/:mid/role` | — | 删除 |
| `GET /asset-libraries?project_id=X` | `GET /asset-libraries` | 按当前用户查询 |
| `POST /asset-libraries {project_id,...}` | `POST /asset-libraries {name, kind}` | 去掉 project_id |
| `GET /assets?library_id=X` | `GET /assets?library_id=X` | 不变 |
| `POST /upload` | `POST /upload` | 不变 |
| `POST /upload/direct/prepare {project_id,...}` | `POST /upload/direct/prepare {library_id,...}` | 去掉 project_id |
| `POST /upload/direct/complete {project_id,...}` | `POST /upload/direct/complete {library_id,...}` | 去掉 project_id |
| `GET /projects/:id/asset-diagnosis` | `GET /asset-diagnosis` | 按当前用户查询 |
| `POST /classification-jobs {project_id,...}` | `POST /classification-jobs {asset_id}` | 去掉 project_id |
| `GET /projects/:id/edit-plans/templates` | `GET /templates` | 全局模板列表 |
| `GET /projects/:id/edit-plans` | `GET /edit-plans` | 按当前用户查询 |
| `POST /projects/:id/edit-plans` | `POST /edit-plans` | 去掉 projectId |
| `GET /projects/:id/edit-plans/:pid` | `GET /edit-plans/:pid` | 去掉 projectId |
| `POST /projects/:id/edit-plans/auto-generate` | `POST /edit-plans/auto-generate` | 去掉 projectId |
| `PATCH /projects/:id/edit-plans/:pid` | `PATCH /edit-plans/:pid` | 去掉 projectId |
| `DELETE /projects/:id/edit-plans/:pid` | `DELETE /edit-plans/:pid` | 去掉 projectId |
| `GET /projects/:id/tasks` | `GET /tasks` | 按当前用户查询 |
| `POST /tasks/:type/:id/retry` | `POST /tasks/:type/:id/retry` | 不变 |

---

## 八、移动端响应式策略

### 8.1 现状
- 当前使用 Ant Design v5，内置 Grid 系统和响应式工具
- Header 导航在移动端无适配（水平排列，小屏会溢出）
- 页面内容区基本为单列布局，移动端兼容性尚可

### 8.2 改造方案

#### 导航层
- **顶部导航**（Header）：
  - 桌面端（≥768px）：水平导航，全部菜单项平铺
  - 移动端（<768px）：隐藏导航文字，显示汉堡菜单图标，点击展开侧边 Drawer
  - Logo 始终可见
- **底部 Tab 栏**（可选，Phase 2）：
  - 移动端增加底部固定 Tab 栏，包含 5 个核心入口：素材库、一键生成、生成记录、成品库、我的
  - 使用 Ant Design `TabBar` 或自定义实现

#### 内容层
- **素材库**：
  - 桌面端：卡片网格（4 列），支持拖拽上传
  - 移动端：单列卡片，底部固定「上传」按钮，调用手机相机/相册
- **标题库 / 配音库**：
  - 桌面端：表格视图
  - 移动端：列表视图，卡片样式
- **一键生成**：
  - 桌面端：左右分栏（左侧配置，右侧预览）
  - 移动端：步骤条（Steps）纵向流程，分步填写
- **生成记录 / 成品库**：
  - 桌面端：表格 + 视频预览弹窗
  - 移动端：卡片列表 + 全屏视频播放器
- **订阅管理**：
  - 桌面端：套餐对比表格
  - 移动端：卡片式套餐展示，纵向排列

#### 技术实现
- 使用 CSS 媒体查询 + Ant Design `useBreakpoint` Hook
- 关键断点：`xs: 480px`, `sm: 576px`, `md: 768px`, `lg: 992px`, `xl: 1200px`
- 图片/视频缩略图使用响应式 `srcset` 或统一使用较小尺寸 + CSS 缩放
- 上传组件使用 Ant Design `Upload.Dragger`（桌面）和自定义移动端上传按钮

### 8.3 分阶段实施
- **Phase 1**（本次重构）：Header 响应式改造 + 页面基本移动端适配
- **Phase 2**（后续）：底部 Tab 栏 + 移动端专属交互优化（手势、滑动等）

---

## 九、实施计划与优先级

### Phase 1：基础重构（本次核心工作）

| 序号 | 任务 | 涉及文件 | 预估工时 |
|------|------|---------|---------|
| 1 | 路由表重构 | `router/index.tsx` | 0.5h |
| 2 | Header 导航改造 | `Header.tsx` | 1h |
| 3 | 素材库页面改造 | `ProjectAssets` → `AssetLibrary` | 2h |
| 4 | 标题库页面改造 | `ProjectTitles` → `TitleLibrary` | 1h |
| 5 | 配音库页面改造 | `ProjectVoices` → `VoiceLibrary` | 1h |
| 6 | 一键生成页面改造 | `ProjectGeneration` → `GeneratePage` | 4h |
| 7 | 生成记录页面改造 | `ProjectTasks` → `TaskHistory` | 1h |
| 8 | 成品库页面改造 | `ProjectResults` → `ProductLibrary` | 1h |
| 9 | API 层改造 | `assets.ts`, `editPlans.ts`, `tasks.ts` | 2h |
| 10 | 删除废弃代码 | `workspace.ts`, `useWorkspace.ts`, `WorkspaceList.tsx` | 0.5h |
| 11 | 模板库页面新建 | `TemplateLibrary.tsx`, `templates.ts` | 2h |
| 12 | 更新测试用例 | `test/` 目录 | 2h |

**合计：约 18h**

### Phase 2：移动端优化（后续）
- 底部 Tab 栏
- 移动端上传优化
- 手势交互

### Phase 3：功能增强（后续）
- AI 配音集成
- 高级时间线编辑器
- 模板市场

---

## 十、风险与注意事项

### 10.1 前后端协同
- API 路由变更需要后端同步改造，建议前后端并行开发
- 过渡期可保留旧 API 兼容层（后端同时支持带/不带 projectId 的接口）
- 前端可通过 feature flag 切换新旧路由

### 10.2 数据迁移
- 后端需将现有 `project_id` 关联的数据迁移到 `user_id` 直接关联
- 素材、标题、配音、编辑计划、任务、成品均需迁移
- 建议后端提供迁移脚本，前端无需关心

### 10.3 向后兼容
- 旧路由 `/projects/:id/*` 设置 301 重定向到新路由（前端 `Navigate` 组件实现）
- 重定向逻辑保留 1-2 个版本后移除

### 10.4 测试覆盖
- 现有 `WorkspaceList.test.tsx` 需删除或重写
- 每个改造页面需更新对应的 E2E / 集成测试
- 路由跳转测试需全面更新

---

## 附录 A：新旧路由快速对照表

| 旧路由 | 新路由 | 页面 |
|--------|--------|------|
| `/projects` | `/assets` | 素材库（原项目列表→素材库首页） |
| `/projects/:id/assets` | `/assets` | 素材库 |
| `/projects/:id/titles` | `/titles` | 标题库 |
| `/projects/:id/voices` | `/voices` | 配音库 |
| `/projects/:id/generation` | `/generate` | 一键生成 |
| `/projects/:id/tasks` | `/history` | 生成记录 |
| `/projects/:id/results` | `/products` | 成品库 |
| — | `/templates` | 模板库（新增） |
| `/subscription` | `/subscription` | 订阅管理（不变） |
| `/profile` | `/profile` | 个人设置（不变） |
| `/admin/*` | `/admin/*` | 管理后台（不变） |

---

*本文档为规划阶段产出，待评审通过后进入实施阶段。*
