You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

8.6 KiB

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 更新:

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 命名:

{
  folderId: "xxx",
  contentType: "movie",
  sortBy: "updatedAt"
}

响应格式

后端返回 camelCase 格式(通过 alias 配置):

{
  id: "xxx",
  name: "项目名称",
  folderId: "xxx",
  createdAt: "2026-01-21T10:00:00Z"
}

分页参数

{
  page: 1,        // 页码(从 1 开始)
  pageSize: 20    // 每页数量
}

分页响应

{
  items: [...],
  total: 100,
  page: 1,
  pageSize: 20,
  totalPages: 5
}

使用示例

1. 获取项目列表

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 <div>加载中...</div>;

  return (
    <div>
      {data?.items.map(project => (
        <div key={project.id}>{project.name}</div>
      ))}
      <div> {data?.total} 个项目</div>
    </div>
  );
}

2. 创建项目

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 (
    <button onClick={handleCreate} disabled={createProject.isPending}>
      {createProject.isPending ? '创建中...' : '创建项目'}
    </button>
  );
}

3. 删除项目(移至回收站)

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 (
    <button onClick={handleDelete}>删除项目</button>
  );
}

4. 回收站列表

import { useTrashProjects, useRestoreProject, usePermanentDeleteProject } from '@/hooks/api';

function TrashPage() {
  const { data } = useTrashProjects({ page: 1, pageSize: 20 });
  const restore = useRestoreProject();
  const permanentDelete = usePermanentDeleteProject();

  return (
    <div>
      <h1>回收站</h1>
      {data?.items.map(project => (
        <div key={project.id}>
          <span>{project.name}</span>
          <span>{project.daysRemaining} 天后自动删除</span>
          <button onClick={() => restore.mutate(project.id)}>
            恢复
          </button>
          <button onClick={() => permanentDelete.mutate(project.id)}>
            永久删除
          </button>
        </div>
      ))}
    </div>
  );
}

5. 移动项目

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 <button onClick={() => handleMove('folder-456')}>移动</button>;
}

Breaking Changes

⚠️ API 切换

影响: 所有使用 projectApi 的代码

变更前: Mock API(内存数据)

import { projectApi } from '@/services/mock';

变更后: 真实 API(后端对接)

import { projectApi } from '@/services/api';

迁移方案:

  • 代码无需修改(导出路径已更新)
  • 确保后端服务已启动
  • 确保 API 基础 URL 配置正确

⚠️ 响应格式变更

影响: 项目列表查询

变更前: 返回数组

const projects: Project[] = await projectApi.getAll();

变更后: 返回分页对象

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. 离线支持 - 添加离线缓存策略

相关文档


变更作者: System
审核人: 待定
发布状态: 已完成