# 资源详情API与预览面板集成 **日期**: 2026-02-08 **类型**: 功能实现 **影响范围**: 后端API + 前端预览面板 ## 概述 实现了项目资源(角色/场景/道具)的详情API,并集成到预览面板中,支持展示资源的标签列表及其关联图片。 ## 背景 用户在资源面板点击角色/场景/道具时,需要在预览面板中查看: 1. 资源的基础信息 2. 资源的变体标签列表(如角色的"便装"、"正装") 3. 每个标签关联的图片资源作为缩略图 之前只有列表API(`/resource-library/*`),无法单独获取某个资源的完整详情。 ## 实施方案 ### 后端改动 #### 1. Service层新增方法(`resource_library_service.py`) ```python async def get_character_detail(user_id, project_id, character_id) async def get_location_detail(user_id, project_id, location_id) async def get_prop_detail(user_id, project_id, prop_id) ``` **逻辑**: - 复用现有的 `_build_*_with_resources()` 方法 - 查询 `project_element_tags` 表获取标签 - 通过 `project_resources.element_tag_id` 关联获取每个标签的图片资源 - 返回标签列表,每个标签包含: - `tag_id` - `tag_label` - `resource_count`: 关联的图片数量(动态计算) - `thumbnail_url`: 第一张图片的缩略图URL #### 2. API层新增路由(`project_elements.py`) ```python GET /api/v1/projects/{project_id}/characters/{character_id} GET /api/v1/projects/{project_id}/locations/{location_id} GET /api/v1/projects/{project_id}/props/{prop_id} ``` **响应示例**: ```json { "data": { "character_id": "xxx", "name": "孙悟空", "has_tags": true, "tags": [ { "tag_id": "tag-1", "tag_label": "便装", "description": "日常装扮", "display_order": 0, "resource_count": 3, "thumbnail_url": "https://..." } ] } } ``` ### 前端改动 #### 1. API Client 扩展(`project-elements.ts`) 新增类型定义和API方法: ```typescript export interface CharacterDetailResponse { character_id: string; name: string; tags: ElementTag[]; // ... } projectElementsApi.getCharacterDetail(projectId, characterId) projectElementsApi.getLocationDetail(projectId, locationId) projectElementsApi.getPropDetail(projectId, propId) ``` #### 2. 新增 Hook(`useProjectElementsDetail.ts`) ```typescript useCharacterDetail(projectId, characterId) useLocationDetail(projectId, locationId) usePropDetail(projectId, propId) ``` #### 3. 修改预览数据Hook(`usePreviewData.ts`) **变更前**: - 使用资源库列表API获取数据 - 从 `metadata.tags` 读取标签(mock数据) **变更后**: - 根据资源类型调用对应的详情API - 直接使用API返回的真实标签数据 - 格式化为统一的 `resource` 对象供预览面板使用 ```typescript const { data: characterDetail } = useCharacterDetail(projectId, characterId); const resource = { id: characterDetail.character_id, metadata: { tags: characterDetail.tags.map(tag => ({ tag_id: tag.tag_id, tag_label: tag.tag_label, resource_count: tag.resource_count, thumbnail_url: tag.thumbnail_url, })) } }; ``` ## 数据流 ``` 1. 用户点击资源面板的"孙悟空"角色 ↓ 2. ProjectResourcePanel 调用 selectResource('characterId', 'character') ↓ 3. usePreviewData 根据 selectedResourceType 调用 useCharacterDetail ↓ 4. 后端 GET /api/v1/projects/{projectId}/characters/{characterId} ↓ 5. ResourceLibraryService.get_character_detail() - 查询 project_element_tags 表 - 查询 project_resources 表(通过 element_tag_id) - 构建标签列表(每个标签含 thumbnail_url) ↓ 6. 前端接收数据,格式化为统一的 resource 对象 ↓ 7. PreviewPanel 渲染标签缩略图列表 ``` ## 技术细节 ### 标签的 resource_count 计算 **数据库层面**: - `project_element_tags` 表**没有** `resource_count` 字段 - 通过 SQL JOIN 动态计算: ```python resources = await project_resource_repo.get_by_element_tag_id(tag.tag_id) resource_count = len(resources) ``` ### 标签的 thumbnail_url 来源 取标签关联的**第一张图片**的缩略图: ```python thumbnail_url = resources[0].thumbnail_url or resources[0].file_url ``` ### API路由规划 - **详情接口**: `/api/v1/projects/{projectId}/characters/{characterId}` - **列表接口**: `/api/v1/projects/{projectId}/characters` - **资源库接口**(逐步废弃): `/api/v1/projects/{projectId}/resource-library/characters` 未来计划用 `/characters` 替代 `/resource-library/characters`。 ## 测试建议 1. **后端测试**: ```bash curl -X GET "http://localhost:8000/api/v1/projects/{projectId}/characters/{characterId}" \ -H "Authorization: Bearer {token}" ``` 2. **前端测试**: - 在资源面板点击角色/场景/道具 - 验证预览面板显示标签列表 - 验证每个标签显示正确的缩略图 ## 后续扩展 1. **新增标签功能**(待实现): - 调用 `POST /api/v1/projects/{projectId}/element-tags` - 刷新详情数据 2. **上传图片到标签**(待实现): - 调用 `POST /api/v1/projects/{projectId}/resources` - 传入 `element_tag_id` 关联到标签 3. **AI生成标签图片**(暂不实现): - 根据标签描述生成图片 - 自动关联到标签 ## 影响的文件 ### 后端 - `server/app/services/resource_library_service.py` - 新增3个详情方法 - `server/app/api/v1/project_elements.py` - 新增3个详情路由 ### 前端 - `client/src/services/api/project-elements.ts` - 新增详情API方法 - `client/src/hooks/api/useProjectElementsDetail.ts` - 新增详情Hooks - `client/src/hooks/api/index.ts` - 导出新Hooks - `client/src/components/features/preview/hooks/usePreviewData.ts` - 使用详情API ## 注意事项 1. **兼容性**:实拍资源(footage)仍使用资源库API,未来需统一 2. **性能**:详情API会查询标签和关联资源,数据量大时需优化 3. **缓存**:前端使用 React Query 缓存,5分钟有效期