# Changelog: 项目 API 对接
> **版本**: v1.1.0
> **发布日期**: 2026-01-21
> **类型**: Feature
> **影响范围**: 前端 API 层、Hooks、类型定义
---
## 概述
完成前端项目模块与后端 API 的对接,包括项目 CRUD、回收站功能、分享管理等。
---
## 变更内容
### 1. 类型定义更新
**文件**: `client/src/types/project.ts`
**新增类型**:
- `MoveProjectDto` - 移动项目参数
- `ProjectListParams` - 列表查询参数
- `ProjectListResponse` - 列表响应
- `TrashProject` - 回收站项目
- `TrashListResponse` - 回收站列表响应
- `RestoreProjectResponse` - 恢复响应
**更新类型**:
- `Project` - 添加 `displayOrder`, `trashedAt` 字段
- `ProjectStatus` - 添加 `trashed`, `soft_deleted` 状态
- `CreateProjectDto` - 添加影视项目元数据字段
- `UpdateProjectDto` - 添加影视项目元数据字段
### 2. API 服务实现
**文件**: `client/src/services/api/projects.ts` (新建)
**实现功能**:
#### 基础 CRUD
- `getAll(params)` - 获取项目列表(支持筛选、搜索、排序、分页)
- `getById(id)` - 获取单个项目
- `create(data)` - 创建项目
- `update(id, data)` - 更新项目
- `delete(id)` - 删除项目(移至回收站)
- `move(id, data)` - 移动项目到文件夹
- `clone(id, data)` - 克隆项目
- `updateOrder(id, displayOrder)` - 更新项目顺序
#### 回收站功能
- `getTrash(params)` - 获取回收站列表
- `restore(id)` - 从回收站恢复
- `permanentDelete(id)` - 永久删除
#### 分享管理
- `createShare(id, data)` - 创建分享
- `getShares(id)` - 获取分享列表
- `revokeShare(id, shareId)` - 撤销分享
#### 成员管理
- `getMembers(id, params)` - 获取成员列表
- `addMember(id, data)` - 添加成员
- `removeMember(id, userId)` - 移除成员
### 3. React Query Hooks
**文件**: `client/src/hooks/api/useProjects.ts`
**新增 Hooks**:
- `useMoveProject()` - 移动项目
- `useCloneProject()` - 克隆项目
- `useUpdateProjectOrder()` - 更新顺序
- `useTrashProjects(params)` - 获取回收站列表
- `useRestoreProject()` - 恢复项目
- `usePermanentDeleteProject()` - 永久删除
**更新 Hooks**:
- `useProjects(params)` - 支持查询参数
- `useDeleteProject()` - 改为移至回收站,失效回收站缓存
**Query Keys 更新**:
```typescript
projectKeys = {
all: ['projects'],
lists: () => ['projects', 'list'],
list: (filters) => ['projects', 'list', filters],
details: () => ['projects', 'detail'],
detail: (id) => ['projects', 'detail', id],
trash: () => ['projects', 'trash'],
trashList: (params) => ['projects', 'trash', params],
}
```
### 4. API 导出更新
**文件**: `client/src/services/api/index.ts`
**变更**:
- 从 Mock API 切换到真实 API
- `projectApi` 现在导出自 `./projects` 而非 `../mock`
---
## API 对接说明
### 请求格式
所有请求使用 camelCase 命名:
```typescript
{
folderId: "xxx",
contentType: "movie",
sortBy: "updatedAt"
}
```
### 响应格式
后端返回 camelCase 格式(通过 `alias` 配置):
```typescript
{
id: "xxx",
name: "项目名称",
folderId: "xxx",
createdAt: "2026-01-21T10:00:00Z"
}
```
### 分页参数
```typescript
{
page: 1, // 页码(从 1 开始)
pageSize: 20 // 每页数量
}
```
### 分页响应
```typescript
{
items: [...],
total: 100,
page: 1,
pageSize: 20,
totalPages: 5
}
```
---
## 使用示例
### 1. 获取项目列表
```typescript
import { useProjects } from '@/hooks/api';
function ProjectList() {
const { data, isLoading } = useProjects({
folderId: 'folder-123',
sortBy: 'updatedAt',
sortOrder: 'desc',
page: 1,
pageSize: 20
});
if (isLoading) return
加载中...
;
return (
{data?.items.map(project => (
{project.name}
))}
共 {data?.total} 个项目
);
}
```
### 2. 创建项目
```typescript
import { useCreateProject } from '@/hooks/api';
function CreateProjectButton() {
const createProject = useCreateProject();
const handleCreate = () => {
createProject.mutate({
name: '新项目',
description: '项目描述',
type: 'mine',
folderId: 'folder-123',
contentType: 'movie',
aspectRatio: '16:9'
}, {
onSuccess: (project) => {
console.log('创建成功:', project);
}
});
};
return (
);
}
```
### 3. 删除项目(移至回收站)
```typescript
import { useDeleteProject } from '@/hooks/api';
import { useToast } from '@/hooks/use-toast';
function DeleteProjectButton({ projectId }: { projectId: string }) {
const deleteProject = useDeleteProject();
const { toast } = useToast();
const handleDelete = () => {
deleteProject.mutate(projectId, {
onSuccess: () => {
toast({
title: '已移至回收站',
description: '项目将在 30 天后自动删除'
});
}
});
};
return (
);
}
```
### 4. 回收站列表
```typescript
import { useTrashProjects, useRestoreProject, usePermanentDeleteProject } from '@/hooks/api';
function TrashPage() {
const { data } = useTrashProjects({ page: 1, pageSize: 20 });
const restore = useRestoreProject();
const permanentDelete = usePermanentDeleteProject();
return (
回收站
{data?.items.map(project => (
{project.name}
{project.daysRemaining} 天后自动删除
))}
);
}
```
### 5. 移动项目
```typescript
import { useMoveProject } from '@/hooks/api';
function MoveProjectButton({ projectId }: { projectId: string }) {
const moveProject = useMoveProject();
const handleMove = (targetFolderId: string) => {
moveProject.mutate({
id: projectId,
data: { folderId: targetFolderId }
});
};
return ;
}
```
---
## Breaking Changes
### ⚠️ API 切换
**影响**: 所有使用 `projectApi` 的代码
**变更前**: Mock API(内存数据)
```typescript
import { projectApi } from '@/services/mock';
```
**变更后**: 真实 API(后端对接)
```typescript
import { projectApi } from '@/services/api';
```
**迁移方案**:
- 代码无需修改(导出路径已更新)
- 确保后端服务已启动
- 确保 API 基础 URL 配置正确
### ⚠️ 响应格式变更
**影响**: 项目列表查询
**变更前**: 返回数组
```typescript
const projects: Project[] = await projectApi.getAll();
```
**变更后**: 返回分页对象
```typescript
const response: ProjectListResponse = await projectApi.getAll();
const projects = response.items;
```
**迁移方案**:
- 使用 `useProjects()` hook 自动处理
- 直接调用 API 需要访问 `.items` 属性
---
## 测试清单
### API 测试
- [ ] 获取项目列表(无参数)
- [ ] 获取项目列表(带筛选)
- [ ] 获取项目列表(带搜索)
- [ ] 获取项目列表(带排序)
- [ ] 获取项目列表(带分页)
- [ ] 获取单个项目
- [ ] 创建项目
- [ ] 更新项目
- [ ] 删除项目(移至回收站)
- [ ] 移动项目
- [ ] 克隆项目
- [ ] 更新项目顺序
### 回收站测试
- [ ] 获取回收站列表
- [ ] 从回收站恢复
- [ ] 永久删除
- [ ] 剩余天数显示正确
### Hooks 测试
- [ ] useProjects 缓存正常
- [ ] useProject 缓存正常
- [ ] useCreateProject 失效缓存
- [ ] useUpdateProject 更新缓存
- [ ] useDeleteProject 失效缓存
- [ ] useTrashProjects 独立缓存
---
## 已知问题
无
---
## 后续工作
1. **回收站页面** - 实现完整的回收站 UI
2. **项目分享** - 实现分享功能 UI
3. **成员管理** - 实现协作项目成员管理 UI
4. **批量操作** - 支持批量删除、移动等
5. **离线支持** - 添加离线缓存策略
---
## 相关文档
- [后端 RFC 131](../../server/rfcs/131-project-trash-system.md)
- [后端 Changelog](../../server/changelogs/2026-01-21-project-trash-system.md)
- [项目服务文档](../../requirements/backend/04-services/project/project-service.md)
---
**变更作者**: System
**审核人**: 待定
**发布状态**: 已完成