# 分镜服务完整实现 > **日期**:2026-02-04 > **类型**:Feature Implementation > **影响范围**:后端 - 分镜管理模块 --- ## 概述 完整实现分镜管理服务(Storyboard Service),包括分镜 CRUD、排序管理、元素关联、筛选搜索等核心功能。 ## 实现内容 ### 1. 数据模型层 **新建文件**:`server/app/models/storyboard.py` - ✅ `Storyboard` 模型:分镜主表 - ✅ `StoryboardItem` 模型:分镜元素关联表 - ✅ `ShotSizeType` 枚举:8种景别类型 - ✅ `CameraMovementType` 枚举:9种运镜类型 - ✅ `ItemType` 枚举:元素类型(剧本元素标签/项目素材) **技术栈符合度**: - ✅ UUID v7 应用层生成(`generate_uuid_v7()`) - ✅ 枚举类型使用 SMALLINT + IntEnum - ✅ 时间戳使用 TIMESTAMPTZ - ✅ 无物理外键约束 - ✅ CHECK 约束和 UNIQUE 约束 ### 2. Schema 层 **新建文件**:`server/app/schemas/storyboard.py` - ✅ `StoryboardCreate`:创建分镜请求 - ✅ `StoryboardUpdate`:更新分镜请求 - ✅ `StoryboardResponse`:分镜响应 - ✅ `StoryboardReorder`:重新排序请求 - ✅ `StoryboardItemCreate`:添加元素请求 - ✅ `StoryboardItemUpdate`:更新元素请求 - ✅ `StoryboardItemResponse`:元素响应 - ✅ `StoryboardListResponse`:分镜列表响应 - ✅ `StoryboardDurationStats`:时长统计响应 ### 3. 仓储层 **新建文件**:`server/app/repositories/storyboard_repository.py` **实现功能**: - ✅ 分镜 CRUD 操作 - ✅ 排序管理(获取最大 order_index、批量更新顺序) - ✅ 筛选查询(按景别、运镜筛选) - ✅ 全文搜索(标题、描述、拍摄描述) - ✅ 时长统计(总时长、平均时长、方差) - ✅ 分镜元素关联 CRUD - ✅ 批量操作(批量检查存在性) **技术栈符合度**: - ✅ 使用 `async/await` 异步编程 - ✅ 使用 `flush()` 而非 `commit()`(Repository 职责) - ✅ 日志使用 %-formatting 格式化 ### 4. 服务层 **新建文件**:`server/app/services/storyboard_service.py` **实现功能**: - ✅ 分镜 CRUD(创建、查询、更新、删除) - ✅ 排序管理(重新排序、删除后自动重排) - ✅ 元素关联管理(添加、移除、更新属性、批量调整顺序) - ✅ 筛选和搜索(按景别/运镜筛选、全文搜索) - ✅ 时长统计(项目总时长、平均时长、方差) - ✅ 权限检查(应用层验证项目权限) **技术栈符合度**: - ✅ 使用 `commit()` 提交事务(Service 职责) - ✅ 日志记录关键操作 - ✅ 异常日志使用 `exc_info=True` - ✅ 应用层验证引用完整性 ### 5. API 路由层 **新建文件**:`server/app/api/v1/storyboards.py` **实现端点**(13个): 1. ✅ `GET /storyboards` - 获取分镜列表 2. ✅ `POST /storyboards` - 创建分镜 3. ✅ `GET /storyboards/{id}` - 获取分镜详情 4. ✅ `PUT /storyboards/{id}` - 更新分镜 5. ✅ `DELETE /storyboards/{id}` - 删除分镜 6. ✅ `POST /storyboards/reorder` - 重新排序分镜 7. ✅ `POST /storyboards/{id}/items` - 添加元素到分镜 8. ✅ `GET /storyboards/{id}/items` - 获取分镜的所有关联元素 9. ✅ `PATCH /storyboards/items/{id}` - 更新元素的关联属性 10. ✅ `DELETE /storyboards/items/{id}` - 从分镜移除元素 11. ✅ `POST /storyboards/{id}/items/reorder` - 批量调整元素顺序 12. ✅ `GET /storyboards/filter` - 按景别和运镜筛选分镜 13. ✅ `GET /storyboards/search` - 全文搜索分镜 14. ✅ `GET /storyboards/statistics/duration` - 获取项目时长统计 **技术栈符合度**: - ✅ 使用 `ApiResponse` 统一响应格式 - ✅ 依赖注入模式 - ✅ 日志记录 API 调用 ### 6. 数据库迁移 **新建文件**:`server/alembic/versions/20260204_1600_create_storyboards_tables.py` **迁移内容**: - ✅ 创建 `storyboards` 表 - ✅ 创建 `storyboard_items` 表 - ✅ 创建索引(B-tree、GIN、部分索引) - ✅ 创建全文搜索索引(pg_trgm) - ✅ 创建触发器(自动更新 updated_at) - ✅ 添加表和列注释 **索引策略**: - B-tree 索引:project_id, order_index - 部分索引:shot_size, camera_movement(仅非空值) - GIN 索引:metadata, 全文搜索(title, description, shooting_description) ### 7. 路由注册 **修改文件**:`server/app/api/v1/__init__.py` - ✅ 导入 `storyboards` 模块 - ✅ 注册路由:`/storyboards` --- ## 核心设计 ### 1. 镜号管理 - **设计**:使用 `order_index` 作为镜号(1, 2, 3...) - **创建时**:自动分配下一个序号 - **删除时**:后续分镜的 `order_index` 自动 -1 - **排序时**:批量更新 `order_index` - **优势**:极简设计,无需单独维护镜号字段 ### 2. 影视专业字段 - **景别(shot_size)**:SMALLINT 存储(1-8),代码层使用 IntEnum - 8种标准景别:大远景、远景、全景、中景、中近景、特写、大特写、过肩 - **运镜(camera_movement)**:SMALLINT 存储(1-9),代码层使用 IntEnum - 9种标准运镜:固定、摇镜、俯仰、推拉、变焦、跟踪、环绕、升降、手持 - **拍摄描述(shooting_description)**:TEXT 类型,支持全文搜索 ### 3. 元素关联设计 **统一关联表**:`storyboard_items` - **两种关联类型**: - `item_type=1`:剧本元素标签(角色/场景/道具的变体) - `item_type=2`:项目素材(实拍素材、音频、视频等) - **关联字段**: - `element_tag_id`:指向 `screenplay_element_tags.tag_id` - `resource_id`:指向 `project_resources.project_resource_id` - **冗余字段**:`element_name`, `tag_label`, `cover_url` 避免 JOIN - **关联属性**:`action_description`(动作)、`spatial_position`(位置)、`is_visible`(可见性) - **排序与层级**:`display_order`(显示顺序)、`z_index`(视觉层级) ### 4. 时间轴管理 - **start_time/end_time**:用于视频编辑时间轴定位 - **estimated_duration/actual_duration**:预估时长 vs 实际时长 - **时间范围查询**:支持 GiST 索引(未来扩展) --- ## 技术栈符合度检查 ### ✅ 数据库设计 - [x] UUID v7 应用层生成(`generate_uuid_v7()`) - [x] 枚举类型使用 SMALLINT + IntEnum - [x] 时间戳使用 TIMESTAMPTZ(ADR 006) - [x] 无物理外键约束,应用层验证引用完整性 - [x] 索引策略完整(B-tree、GIN、部分索引) ### ✅ 后端代码 - [x] 异步编程(async/await) - [x] Repository 使用 `flush()`,Service 使用 `commit()` - [x] 日志使用 %-formatting 格式化 - [x] 异常日志使用 `exc_info=True` - [x] API 响应使用 `ApiResponse` 统一格式 - [x] 依赖注入模式 ### ✅ 文档规范 - [x] Changelog 文档创建 - [x] 文件路径符合规范:`docs/server/changelogs/` - [x] 日期格式:YYYY-MM-DD --- ## 后续工作 ### 阶段 3:分镜看板服务(未实现) - [ ] 创建 `StoryboardBoardService` - [ ] 实现六种轨道(分镜、资源、视频、音效、对白、配音) - [ ] 实时计算时间轴数据 - [ ] 创建 API 路由 ### 阶段 4:项目素材关联(未实现) - [ ] 扩展 `ProjectResource` 模型(添加 `usage_count` 字段) - [ ] 创建数据库迁移脚本 - [ ] 扩展 `ProjectResourceService`(引用计数维护) - [ ] 实现删除保护逻辑 --- ## 测试建议 ### 单元测试 - [ ] `test_storyboard_repository.py`:仓储层测试 - [ ] `test_storyboard_service.py`:服务层测试 ### 集成测试 - [ ] `test_storyboard_api.py`:API 端点测试 ### 测试场景 1. 创建分镜并自动分配 order_index 2. 删除分镜后自动重排序 3. 批量调整分镜顺序 4. 添加/移除元素到分镜 5. 按景别/运镜筛选分镜 6. 全文搜索分镜 7. 获取项目时长统计 --- ## 数据库迁移 ### 执行迁移 ```bash # 在 Docker 容器内执行 docker exec jointo-server-app python scripts/db_migrate.py upgrade ``` ### 验证迁移 ```bash # 检查当前迁移版本 docker exec jointo-server-app alembic current # 查看表结构 docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d storyboards" docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d storyboard_items" ``` --- ## 相关文档 - [分镜管理服务需求](../../requirements/backend/04-services/project/storyboard-service.md) - [分镜看板服务需求](../../requirements/backend/04-services/project/storyboard-board-service.md) - [分镜-项目素材关联需求](../../requirements/backend/04-services/project/storyboard-project-resource-association.md) - [分镜资源服务需求](../../requirements/backend/04-services/project/storyboard-resource-service.md) - [ADR 006: TIMESTAMPTZ 时间戳规范](../../architecture/adrs/006-timestamptz-for-event-timestamps.md) - [后端架构指南](../guides/backend-architecture.md) --- **实现者**:Kiro AI **审核状态**:待审核 **部署状态**:待部署