# RFC 122: 文件夹 API 对接 > **状态**: 已实现 > **创建日期**: 2026-01-20 > **作者**: 架构团队 --- ## 概述 将前端文件夹功能从 Mock API 对接到真实后端 API,实现完整的文件夹管理功能。 ## 动机 1. 后端文件夹服务已完整实现(RFC 016) 2. 前端 UI 组件已完成,使用 Mock 数据 3. 需要对接真实 API 实现完整功能 4. 为后续清理 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()` - 创建 mutation - `useUpdateFolder()` - 更新 mutation - `useDeleteFolder()` - 删除 mutation - `useMoveFolder()` - 移动 mutation - `useCloneFolder()` - 克隆 mutation - `useFolderStats()` - 查询统计信息 **Query Keys 设计**: ```typescript 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 → 前端 camelCase - `keysToSnakeCase()` - 前端请求 camelCase → 后端 snake_case - 递归处理嵌套对象和数组 #### 4. Mock API 模块化重构 将 `services/mockApi.ts` (600+ 行) 拆分为独立模块: - `mock/projectApi.ts` - `mock/storyboardApi.ts` - `mock/resourceApi.ts` - `mock/timelineApi.ts` - `mock/folderApi.ts`(未来可删除) **优势**: - 便于维护 - 清理成本低(删除单个文件即可) - 模块独立 ### 组件更新 #### CreateFolderModal **变更**: - 使用 `useCreateFolder()` 和 `useUpdateFolder()` hooks - 添加 loading 状态处理 - 添加 toast 提示 - 移除 `mockDelay()` 模拟 **代码示例**: ```typescript 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): ```json { "id": "uuid", "name": "文件夹", "parent_folder_id": "uuid", "owner_id": "uuid", "created_at": "2026-01-20T10:00:00Z" } ``` **前端使用**(camelCase): ```typescript { id: "uuid", name: "文件夹", parentFolderId: "uuid", ownerId: "uuid", createdAt: "2026-01-20T10:00:00Z" } ``` ### 错误处理 1. **网络错误**:axios 拦截器统一处理 2. **401 未授权**:自动跳转登录页 3. **业务错误**:组件层 try-catch + toast 提示 ### 性能优化 1. **缓存策略**: - 列表/树:5 分钟 staleTime - 详情:从列表缓存初始化 - 乐观更新:mutation 成功后立即更新缓存 2. **请求优化**: - 分页查询避免大量数据 - 树形结构支持限制深度 - 统计信息按需查询 ## 测试计划 ### 功能测试 - [x] 创建文件夹(根目录/子文件夹) - [x] 更新文件夹(名称/描述/颜色) - [ ] 删除文件夹(普通/级联) - [ ] 移动文件夹 - [ ] 克隆文件夹 - [ ] 获取文件夹树 - [ ] 获取文件夹路径 ### 集成测试 - [ ] 与后端 API 联调 - [ ] 错误场景处理 - [ ] 并发操作测试 ## 未来工作 ### 短期(1-2 周) 1. **完成其他组件对接**: - MoveFolderModal - CloneFolderModal - FolderContextMenu 操作 - ProjectSidebar 文件夹树展示 2. **添加错误边界**: - 网络错误重试 - 降级到 Mock API ### 中期(1 个月) 1. **清理 Mock 数据**: - 删除 `services/mock/folderApi.ts` - 移除环境判断逻辑 2. **性能优化**: - 虚拟滚动(大量文件夹) - 懒加载子节点 ### 长期 1. **离线支持**: - IndexedDB 缓存 - 离线操作队列 2. **实时同步**: - WebSocket 推送 - 多端协同 ## 清理计划 当所有功能稳定后,清理 Mock 数据: **步骤**: 1. 删除 `services/mock/folderApi.ts` 2. 从 `services/mock/index.ts` 移除导出 3. 完成 ✅ **清理成本**:< 5 分钟 ## 依赖 - React Query 5.x - Axios 1.x - TypeScript 5.x ## 相关文档 - [RFC 016: 文件夹服务实现](../../server/rfcs/016-folder-service-implementation.md) - [API 设计规范](../../requirements/api-design-specification.md) --- **实施状态**:✅ 核心功能已完成,待完善其他组件对接