6.7 KiB
ResourceLibraryService 实现
日期: 2026-02-03
类型: 新功能
影响范围: 后端服务层、API 层、数据模型
概述
实现了 ResourceLibraryService 服务,用于整合剧本元素(角色、场景、道具)、标签和项目资源的数据,为前端提供统一的资源库接口。
变更内容
1. 新增服务层
文件: server/app/services/resource_library_service.py
实现了以下核心方法:
get_characters()- 获取所有角色列表(包含标签和资源)get_locations()- 获取所有场景列表(包含标签和资源)get_props()- 获取所有道具列表(包含标签和资源)get_footage_resources()- 获取实拍资源列表get_element_with_tags()- 获取元素的所有标签和资源
关键特性:
- 支持父子项目资源聚合(
include_subprojects参数) - 返回所有元素(包含有资源和无资源的)
- 使用
selectinload预加载关联数据,避免 N+1 查询 - 不感知
storyboard_items表(职责分离) - 完整的权限检查和日志记录
2. 新增 Schema 定义
文件: server/app/schemas/resource_library.py
定义了以下 Pydantic 模型:
ResourceInTag- 标签中的资源ElementTag- 元素标签CharacterWithResources- 角色(包含标签和资源)LocationWithResources- 场景(包含标签和资源)PropWithResources- 道具(包含标签和资源)FootageResource- 实拍资源ElementWithTags- 元素详情(包含所有标签和资源)
3. 新增 API 路由
文件: server/app/api/v1/resource_library.py
实现了 5 个 API 端点:
GET /api/v1/projects/{project_id}/resource-library/characters
GET /api/v1/projects/{project_id}/resource-library/locations
GET /api/v1/projects/{project_id}/resource-library/props
GET /api/v1/projects/{project_id}/resource-library/footage-resources
GET /api/v1/projects/{project_id}/resource-library/elements/{element_type}/{element_id}/tags-with-resources
所有端点支持 include_subprojects 查询参数。
4. 新增数据模型
创建了以下 SQLModel 模型:
server/app/models/screenplay.py- 剧本主表模型server/app/models/screenplay_character.py- 剧本角色模型server/app/models/screenplay_location.py- 剧本场景模型server/app/models/screenplay_prop.py- 剧本道具模型server/app/models/screenplay_element_tag.py- 剧本元素标签模型
关键设计:
- 使用 UUID v7 主键
- 使用 SMALLINT + IntEnum 替代 PostgreSQL ENUM
- 使用
selectinload配置关系预加载 - 提供
*_str属性方法用于枚举值转字符串
5. 路由注册
文件: server/app/api/v1/__init__.py
注册了 resource_library 路由到 API v1 路由器。
技术规范遵循
✅ UUID v7: 所有主键使用 UUID v7(应用层生成)
✅ 无物理外键: 仅在模型层定义关系,数据库层无 FOREIGN KEY 约束
✅ SMALLINT 枚举: 使用 SMALLINT + IntEnum 替代 PostgreSQL ENUM
✅ 日志格式: 使用 %-formatting 格式化日志
✅ 异常日志: 异常日志添加 exc_info=True
✅ API 响应: 使用 success_response() 统一响应格式
✅ 日志系统: 使用 app.core.logging.get_logger 获取 logger
✅ 权限检查: 所有方法都进行项目权限验证
数据流程
获取角色列表流程
- 检查用户对项目的访问权限
- 获取项目ID列表(包含子项目,如果
include_subprojects=true) - 查询项目的所有剧本ID
- 查询剧本的所有角色(预加载标签)
- 查询标签关联的项目资源
- 组装返回数据(角色 → 标签 → 资源)
父子项目资源聚合
当 include_subprojects=true 时:
- 查询父项目的所有子项目ID
- 将父项目ID和子项目ID合并为项目ID列表
- 查询所有项目的剧本和资源
- 返回聚合后的数据
API 使用示例
获取角色列表
GET /api/v1/projects/{project_id}/resource-library/characters?include_subprojects=false
响应:
{
"success": true,
"code": 200,
"message": "success",
"data": [
{
"character_id": "uuid",
"screenplay_id": "uuid",
"name": "张三",
"description": "主角",
"role_type": "main",
"is_offscreen": false,
"has_tags": true,
"tags": [
{
"tag_id": "uuid",
"tag_label": "少年",
"description": "15岁",
"display_order": 0,
"resources": [
{
"project_resource_id": "uuid",
"name": "张三-少年形象",
"type": "character",
"file_url": "https://...",
"thumbnail_url": "https://..."
}
]
}
]
}
],
"timestamp": "2026-02-03T10:00:00Z"
}
获取元素详情
GET /api/v1/projects/{project_id}/resource-library/elements/character/{character_id}/tags-with-resources
依赖关系
依赖的服务
ProjectRepository- 项目权限检查
依赖的模型
Screenplay- 剧本主表ScreenplayCharacter- 剧本角色ScreenplayLocation- 剧本场景ScreenplayProp- 剧本道具ScreenplayElementTag- 剧本元素标签ProjectResource- 项目资源Project- 项目表
性能优化
- 预加载关联数据: 使用
selectinload()预加载标签,避免 N+1 查询 - 批量查询资源: 收集所有标签ID后批量查询资源,而非逐个查询
- 索引优化: 依赖数据库迁移中创建的索引(
screenplay_id,element_id,element_tag_id)
测试建议
单元测试
- 测试权限检查逻辑
- 测试父子项目资源聚合
- 测试空数据情况(无剧本、无标签、无资源)
集成测试
- 测试完整的数据查询流程
- 测试
include_subprojects参数 - 测试不同元素类型的查询
性能测试
- 测试大量角色/标签/资源的查询性能
- 测试预加载是否生效(检查 SQL 查询数量)
后续优化
- 缓存: 考虑对资源库数据添加 Redis 缓存
- 分页: 如果角色/场景/道具数量很大,考虑添加分页支持
- 搜索: 添加按名称搜索角色/场景/道具的功能
- 排序: 支持自定义排序(按名称、创建时间等)
相关文档
- 设计文档:
docs/requirements/backend/04-services/project/resource-library-service.md - 技术栈规范:
docs/architecture/tech-stack.md - 数据库迁移:
server/alembic/versions/20260203_1300_create_screenplay_tables.py
作者
Kiro AI Assistant
审核状态
- 代码审核
- 测试验证
- 文档审核