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.
7.3 KiB
7.3 KiB
ProjectsPage API 对接
日期: 2026-01-21
类型: 功能增强
影响范围: 项目列表页面及相关组件
变更概述
完成 ProjectsPage 及相关组件与后端项目 API 的完整对接,替换 Mock 数据为真实 API 调用。
变更详情
1. CreateProjectModal 组件
文件: client/src/components/features/project/CreateProjectModal.tsx
变更内容:
- ✅ 使用
useCreateProject()hook 替换addProject()方法 - ✅ 使用
useUpdateProject()hook 替换updateProject()方法 - ✅ 添加异步错误处理和加载状态
- ✅ 虚拟根文件夹 ID('1', '2')转换为
null - ✅ 集成 Toast 通知反馈
关键逻辑:
// 创建项目
const newProject = await createProject.mutateAsync({
name: data.name,
folderId: data.folderId === '1' || data.folderId === '2' ? null : data.folderId,
contentType: data.projectType,
// ...其他字段
});
// 更新项目
await updateProject.mutateAsync({
id: editingProjectInfo.id,
data: { /* 更新数据 */ }
});
2. DeleteConfirmModal 组件
文件: client/src/components/features/project/DeleteConfirmModal.tsx
变更内容:
- ✅ 使用
useDeleteProject()hook 删除项目(移至回收站) - ✅ 使用
useDeleteFolder()hook 删除文件夹(级联删除) - ✅ 添加异步错误处理和加载状态
- ✅ 更新删除提示文案(项目删除说明可恢复)
关键逻辑:
if (deletingResource.type === 'project') {
// 删除项目(移至回收站,30天内可恢复)
await deleteProject.mutateAsync(deletingResource.id);
} else if (deletingResource.type === 'folder') {
// 删除文件夹(级联删除)
await deleteFolder.mutateAsync({ id: deletingResource.id, cascade: true });
}
3. ProjectsPage 页面
文件: client/src/pages/ProjectsPage.tsx
变更内容:
- ✅ 使用
useProjects()hook 替换useProjectStore() - ✅ 从 API 响应中提取项目列表
- ✅ 添加加载状态支持
- ✅ 保留项目过滤和显示逻辑
关键逻辑:
// 获取项目列表
const { data: projectsData, isLoading: isLoadingProjects } = useProjects();
const projects = projectsData?.items || [];
4. 项目右键菜单组件
文件:
client/src/components/features/project/ProjectContextMenu.tsxclient/src/components/features/project/ProjectContextMenuContent.tsx
变更内容:
- ✅ 使用
useCloneProject()hook 替换cloneProject()方法 - ✅ 添加异步错误处理和 Toast 通知
- ✅ 简化编辑属性逻辑(暂时使用基础信息)
关键逻辑:
const handleCloneProject = async () => {
try {
await cloneProjectMutation.mutateAsync({ id: projectId });
toast({ title: '项目已克隆', description: `项目 "${projectName}" 已成功克隆` });
} catch (error) {
toast({ title: '克隆失败', variant: 'destructive' });
}
};
4. FolderSelector 组件
文件: client/src/components/features/project/FolderSelector.tsx
变更内容:
- ✅ 使用
useFolderTree()hook 替换 Mock 数据 - ✅ 从后端 API 获取文件夹树形结构
- ✅ 添加加载状态和空状态显示
- ✅ 保留虚拟根节点(我的项目/协作项目)
- ✅ 支持按 folderCategory 过滤
关键逻辑:
// 获取文件夹树
const { data: folderTreeData, isLoading } = useFolderTree();
const folderTree = folderTreeData?.tree || [];
// 构建虚拟根节点 + 真实文件夹树
const fullTree = [
{
folderId: VIRTUAL_ROOTS.mine.id,
name: VIRTUAL_ROOTS.mine.name,
children: folderTree.filter(node => node.folderCategory === 1),
},
{
folderId: VIRTUAL_ROOTS.collab.id,
name: VIRTUAL_ROOTS.collab.name,
children: folderTree.filter(node => node.folderCategory === 2),
},
];
技术细节
API Hooks 使用
所有组件统一使用 TanStack Query hooks:
useProjects()- 获取项目列表useCreateProject()- 创建项目useUpdateProject()- 更新项目useDeleteProject()- 删除项目(移至回收站)useCloneProject()- 克隆项目useDeleteFolder()- 删除文件夹
数据流转
用户操作 → Modal/Page 组件 → API Hook → 后端 API
↓
TanStack Query 缓存
↓
自动刷新相关查询
虚拟根文件夹处理
前端使用虚拟根文件夹 ID('1' = 我的项目, '2' = 协作项目),后端使用 null 表示根文件夹:
// 前端 → 后端
folderId: data.folderId === '1' || data.folderId === '2' ? null : data.folderId
// 后端 → 前端(在 API 响应中处理)
folderId: response.folderId || '1' // 默认为"我的项目"
待优化项
1. FolderSelector 文件夹路径
当前 FolderSelector 显示的路径仅为文件夹名称,未构建完整路径。
建议优化:
// 使用 folderApi.getPath() 获取完整路径
const path = await folderApi.getPath(folderId);
const fullPath = path.map(p => p.name).join(' / ');
2. 编辑项目属性
当前右键菜单的"编辑属性"功能使用简化逻辑,未从 API 获取完整项目详情。
建议优化:
const handleEditProperties = async () => {
const project = await projectApi.getById(projectId);
setCreateProjectModalOpen(true, null, {
id: project.id,
name: project.name,
// ...完整项目信息
});
};
2. 加载状态显示
ProjectsPage 和 FolderSelector 已获取加载状态,建议在 UI 中显示。
建议添加:
{isLoadingProjects ? (
<LoadingSpinner />
) : (
<ProjectGridView ... />
)}
3. 错误处理
当前仅在 Modal 中显示错误 Toast,页面级错误未处理。
建议添加:
- 使用
ErrorBoundary包裹页面 - 显示错误状态和重试按钮
测试建议
功能测试
-
创建项目
- 在根文件夹创建项目
- 在子文件夹创建项目
- 验证项目出现在列表中
-
更新项目
- 修改项目名称
- 修改项目属性
- 验证更新后的数据
-
删除项目
- 删除项目(移至回收站)
- 验证项目从列表中消失
- 验证可在回收站中找到
-
克隆项目
- 克隆项目
- 验证副本出现在列表中
- 验证副本名称正确(带"副本"后缀)
-
删除文件夹
- 删除空文件夹
- 删除包含项目的文件夹(级联删除)
- 验证文件夹及内容被删除
集成测试
-
API 调用
- 验证请求参数正确
- 验证响应数据格式
- 验证错误处理
-
缓存更新
- 创建后列表自动刷新
- 更新后详情自动刷新
- 删除后列表自动刷新
相关文档
- 项目 API 对接 - API Hooks 实现
- 项目回收站系统 - 后端回收站实现
- RFC 131: 项目回收站系统 - 回收站设计文档
下一步
- 实现 ProjectPage 的 API 对接
- 添加加载状态和错误处理 UI
- 优化编辑项目属性功能
- 实现回收站页面