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.
6.4 KiB
6.4 KiB
RFC 122: 文件夹 API 对接
状态: 已实现
创建日期: 2026-01-20
作者: 架构团队
概述
将前端文件夹功能从 Mock API 对接到真实后端 API,实现完整的文件夹管理功能。
动机
- 后端文件夹服务已完整实现(RFC 016)
- 前端 UI 组件已完成,使用 Mock 数据
- 需要对接真实 API 实现完整功能
- 为后续清理 Mock 数据做准备
设计方案
架构设计
采用渐进式对接策略,保留 Mock API 作为开发降级方案:
services/
├── api/
│ ├── client.ts # axios 实例
│ ├── folders.ts # 真实 folder API ✅
│ └── index.ts
└── mock/ # 模块化 Mock API
├── folderApi.ts # folder mock(未来可删除)
├── projectApi.ts # project mock
├── storyboardApi.ts # storyboard mock
├── resourceApi.ts # resource mock
├── timelineApi.ts # timeline mock
└── index.ts
hooks/api/
├── useFolders.ts # folder hooks ✅
└── index.ts
lib/
└── api-utils.ts # 数据转换工具 ✅
核心功能
1. API 服务层 (services/api/folders.ts)
实现的接口:
getAll()- 获取文件夹列表(分页)getTree()- 获取树形结构getById()- 获取详情create()- 创建文件夹update()- 更新文件夹delete()- 删除文件夹move()- 移动文件夹getPath()- 获取路径(面包屑)clone()- 克隆文件夹getStats()- 获取统计信息
2. React Query Hooks (hooks/api/useFolders.ts)
实现的 hooks:
useFolders()- 查询列表useFolderTree()- 查询树形结构useFolder()- 查询单个文件夹useFolderPath()- 查询路径useCreateFolder()- 创建 mutationuseUpdateFolder()- 更新 mutationuseDeleteFolder()- 删除 mutationuseMoveFolder()- 移动 mutationuseCloneFolder()- 克隆 mutationuseFolderStats()- 查询统计信息
Query Keys 设计:
folderKeys = {
all: ['folders'],
lists: () => [...folderKeys.all, 'list'],
list: (parentId?, page?, pageSize?) => [...folderKeys.lists(), { parentId, page, pageSize }],
trees: () => [...folderKeys.all, 'tree'],
tree: (maxDepth?) => [...folderKeys.trees(), { maxDepth }],
details: () => [...folderKeys.all, 'detail'],
detail: (id) => [...folderKeys.details(), id],
paths: () => [...folderKeys.all, 'path'],
path: (id) => [...folderKeys.paths(), id],
stats: () => [...folderKeys.all, 'stats'],
stat: (id, recursive?) => [...folderKeys.stats(), id, { recursive }],
}
缓存策略:
- 列表/树形结构:5 分钟 staleTime
- 详情:从列表缓存初始化
- 路径/统计:按需查询
3. 数据转换工具 (lib/api-utils.ts)
处理前后端数据格式差异:
keysToCamelCase()- 后端响应 snake_case → 前端 camelCasekeysToSnakeCase()- 前端请求 camelCase → 后端 snake_case- 递归处理嵌套对象和数组
4. Mock API 模块化重构
将 services/mockApi.ts (600+ 行) 拆分为独立模块:
mock/projectApi.tsmock/storyboardApi.tsmock/resourceApi.tsmock/timelineApi.tsmock/folderApi.ts(未来可删除)
优势:
- 便于维护
- 清理成本低(删除单个文件即可)
- 模块独立
组件更新
CreateFolderModal
变更:
- 使用
useCreateFolder()和useUpdateFolder()hooks - 添加 loading 状态处理
- 添加 toast 提示
- 移除
mockDelay()模拟
代码示例:
const createFolder = useCreateFolder();
const updateFolder = useUpdateFolder();
const submitHandler = async (data) => {
try {
if (isEditing) {
await updateFolder.mutateAsync({ id, data });
toast({ title: '更新成功' });
} else {
await createFolder.mutateAsync(data);
toast({ title: '创建成功' });
}
handleClose();
} catch (error) {
toast({ title: '操作失败', variant: 'destructive' });
}
};
实现细节
数据格式转换
后端响应示例(snake_case):
{
"id": "uuid",
"name": "文件夹",
"parent_folder_id": "uuid",
"owner_id": "uuid",
"created_at": "2026-01-20T10:00:00Z"
}
前端使用(camelCase):
{
id: "uuid",
name: "文件夹",
parentFolderId: "uuid",
ownerId: "uuid",
createdAt: "2026-01-20T10:00:00Z"
}
错误处理
- 网络错误:axios 拦截器统一处理
- 401 未授权:自动跳转登录页
- 业务错误:组件层 try-catch + toast 提示
性能优化
-
缓存策略:
- 列表/树:5 分钟 staleTime
- 详情:从列表缓存初始化
- 乐观更新:mutation 成功后立即更新缓存
-
请求优化:
- 分页查询避免大量数据
- 树形结构支持限制深度
- 统计信息按需查询
测试计划
功能测试
- 创建文件夹(根目录/子文件夹)
- 更新文件夹(名称/描述/颜色)
- 删除文件夹(普通/级联)
- 移动文件夹
- 克隆文件夹
- 获取文件夹树
- 获取文件夹路径
集成测试
- 与后端 API 联调
- 错误场景处理
- 并发操作测试
未来工作
短期(1-2 周)
-
完成其他组件对接:
- MoveFolderModal
- CloneFolderModal
- FolderContextMenu 操作
- ProjectSidebar 文件夹树展示
-
添加错误边界:
- 网络错误重试
- 降级到 Mock API
中期(1 个月)
-
清理 Mock 数据:
- 删除
services/mock/folderApi.ts - 移除环境判断逻辑
- 删除
-
性能优化:
- 虚拟滚动(大量文件夹)
- 懒加载子节点
长期
-
离线支持:
- IndexedDB 缓存
- 离线操作队列
-
实时同步:
- WebSocket 推送
- 多端协同
清理计划
当所有功能稳定后,清理 Mock 数据:
步骤:
- 删除
services/mock/folderApi.ts - 从
services/mock/index.ts移除导出 - 完成 ✅
清理成本:< 5 分钟
依赖
- React Query 5.x
- Axios 1.x
- TypeScript 5.x
相关文档
实施状态:✅ 核心功能已完成,待完善其他组件对接