# 选择共享资源 - 资源树接口方案分析 **日期**:2026-02-08 **范围**:CreateProjectModal → 选择共享资源 → 资源内容数据来源 **结论**:建议**新增「项目资源树」专用接口**,或采用**前端组合 + 懒加载**;不推荐仅靠改造 `/api/v1/folders/tree` 承载「项目下角色/场景/道具」层级。 --- ## 1. 现状 ### 1.1 选择共享资源面板需要的数据 - **ResourceSelectorPanel**(`ResourceSelectorPanel.tsx`)当前用 **Mock 数据**,目标结构为: - 虚拟根「我的项目」→ **文件夹** → **项目** → **项目下的角色 / 场景 / 道具**(character / scene / prop) - 能力:按类型过滤(全部 / 角色 / 场景 / 道具)、搜索、级联选择、展示项目下资源统计(如「角色 15 场景 8 道具 12」)。 - 前端类型:`SharedResource` 含 `type: 'project' | 'folder' | 'character' | 'scene' | 'prop'`,即需要**至少到「项目 + 项目内资源」**这一层。 ### 1.2 现有接口能力 | 接口 | 返回内容 | 是否满足「资源内容」树 | |------|----------|------------------------| | **GET /api/v1/folders/tree** | 根 → 文件夹 → 项目;项目的 `children` 仅为 `[]` 或**子项目**,**不包含** character/scene/prop | ❌ 只到「文件夹 + 项目」 | | **GET /api/v1/projects/{id}/resources** | 某项目的素材**分页扁平列表**(character/scene/prop 等),非树形 | ✅ 有项目下资源,但需按项目逐个请求、且为列表而非树节点 | - `folders/tree` 当前参数:`maxDepth`、`includeProjects`、`includeSubprojects`、`includeFullProjectFields`;**无** `category`(前端 `shared-resources.ts` 的 `category=1` 在后端未使用,若要做「我的项目/协作项目」需前后端对齐)。 - 项目资源列表接口:分页、按类型/标签/搜索过滤,返回的是 `items[]`,不是「树节点 + children」。 --- ## 2. 方案对比 ### 方案 A:改造 `/api/v1/folders/tree` - **做法**:增加参数(如 `includeProjectResources=true`),当为 true 时对每个项目查询其 character/scene/prop,挂到该项目的 `children` 下。 - **优点**:一次请求拿到「文件夹 + 项目 + 项目内资源」整棵树,前端实现简单。 - **缺点**: - 树规模大时(多文件夹 × 多项目 × 每项目多资源)响应体大、耗时长。 - `folders/tree` 同时服务「选文件夹/选项目」和「选共享资源」两种场景,职责混合,后续扩展(如仅要统计、懒加载)不便。 - 与现有「项目节点 children 仅子项目」的语义不一致,易造成复用方误解。 **结论**:仅适合「树规模很小且确定不会膨胀」的场景;一般不推荐作为唯一方案。 --- ### 方案 B:新增「项目资源树」专用接口 - **做法**:新增例如 `GET /api/v1/shared-resources/tree` 或 `GET /api/v1/projects/resources/tree`,专门返回「可共享资源树」: - 结构:虚拟根(可选)→ 文件夹 → 项目 → 可选一层:项目下的 character/scene/prop。 - 可通过查询参数控制:是否包含资源层级、是否只返回资源统计(如 `characterCount`/`sceneCount`/`propCount`)、`category`(我的项目/协作项目)、最大深度等。 - **优点**: - 职责清晰,与「选文件夹」用的 `folders/tree` 分离。 - 可单独做性能设计:例如先只返回「文件夹 + 项目 + 统计」,项目下明细按需懒加载或另接口分页。 - 前端 `ResourceSelectorPanel` 与 `getShareableFoldersAndProjects` 的语义一致,便于对接。 - **缺点**:多一个接口需要维护、文档与测试。 **结论**:**推荐**,尤其当产品需要「一棵清晰的、可扩展的共享资源树」时。 --- ### 方案 C:前端组合现有接口 + 懒加载 - **做法**: - 用现有 `folders/tree`(或对齐后的 `getShareableFoldersAndProjects`)拉取「文件夹 + 项目」树。 - 项目节点展示时,可用「项目资源统计」接口(若存在)只显示数量;用户**展开某项目**时再请求 `GET /api/v1/projects/{projectId}/resources`,将结果转为树子节点挂到该节点下(懒加载)。 - **优点**:不新增后端接口,首屏只加载文件夹+项目,体积小、响应快。 - **缺点**:展开多个项目时会有多次请求;前端需维护「树节点 + 懒加载状态」逻辑。 **结论**:在**不新增接口**的前提下可作为过渡或长期方案;若已有或计划有「项目资源统计」接口,体验会更好。 --- ## 3. 建议 1. **资源内容(到 character/scene/prop)** - **不推荐**仅通过改造 `folders/tree` 把「项目下资源」塞进同一棵树并作为主方案(职责与性能考虑)。 - **推荐**二选一或组合使用: - **方案 B**:新增「项目资源树」接口,专门服务「选择共享资源」场景,便于后续加统计、过滤、懒加载。 - **方案 C**:沿用 `folders/tree` + 按项目懒加载 `projects/{id}/resources`,首屏轻量、不增新接口。 2. **若选方案 B** - 建议接口设计时考虑: - 是否先只返回「文件夹 + 项目 + 每项目资源统计」,明细(character/scene/prop 列表)通过原 `projects/{id}/resources` 按需加载,以控制首包体积。 - 前端 `ResourceSelectorPanel` 中已注释的 `getShareableFoldersAndProjects` 可改为调用新树接口(或先接 `folders/tree` + 统计/明细按需请求)。 3. **若选方案 C** - 前端需要: - 用 `folders/tree`(或带 category 的等价能力)拿 文件夹+项目; - 项目节点展开时请求 `getProjectResources(projectId)`(及可选 `getProjectResourceStats`)并挂到节点; - 统一成 `ResourceSelectorPanel` 所需的树形与 `SharedResource` 类型。 4. **与 CreateProjectModal 的衔接** - 无论 B 或 C,提交时仍将选中项整理为 `sharedResources: [{ id, type }]` 传给创建/更新项目 API(当前代码中 TODO 部分),后端需有对应字段与校验。 --- ## 4. 涉及文件(参考) - 前端:`client/src/components/features/project/CreateProjectModal.tsx`、`ResourceSelectorPanel.tsx`、`shared-resources.ts`、`types/shared-resource.ts` - 后端:`server/app/api/v1/folders.py`(`/tree`)、`server/app/services/folder_service.py`、`server/app/repositories/folder_repository.py`、`server/app/api/v1/project_resources.py`(`/projects/{id}/resources`)