# RFC 132: 剧本资源数据结构重构 > **状态**: ✅ 已实施 > **创建时间**: 2026-01-26 > **实施时间**: 2026-01-26 --- ## 背景 原有的 `resources.ts` Mock 数据混淆了两个不同的概念: 1. **剧本元素档案**:从剧本中提取的角色、场景、道具的基础信息(纯文字描述) 2. **项目素材**:实际的图片/视频文件,用于视觉呈现 这导致数据结构混乱,不符合后端架构设计。 ## 问题分析 ### 原有设计的问题 ```typescript // ❌ 错误:resources.ts 混合了两种数据 export const mockResources: Resource[] = [ { id: '001', name: '孙悟空形象1', type: 'character', fileUrl: 'https://...', // 图片 URL elementTagId: 'tag_char_002', // 关联到标签 // ... 这是项目素材,不是剧本元素档案 } ]; ``` ### 正确的数据架构 根据后端文档分析,应该有三层数据结构: ``` 1. screenplay_characters/scenes/props (剧本元素档案) ↓ 从剧本中提取的基础信息,不包含具体形象 2. screenplay_element_tags (元素标签) ↓ 元素的不同状态/变体(如年龄段、时代) 3. project_resources (项目素材 - 图片/视频) ↓ 关联到标签的具体视觉素材 ``` ## 解决方案 ### 1. 文件拆分 **重命名**:`resources.ts` → `screenplay-resources.ts` - 存储:剧本元素档案(角色、场景、道具的文字信息) - 不包含:图片、视频等视觉素材 **新建**:`project-resources.ts` - 存储:实际的图片/视频素材 - 关联:通过 `elementTagId` 关联到标签 ### 2. 数据结构对比 #### screenplay-resources.ts(剧本元素档案) ```typescript export const mockScreenplayCharacters = [ { character_id: '018e1234-5678-7abc-8def-300000000001', screenplay_id: '018e1234-5678-7abc-8def-100000000001', name: '孙悟空', description: '主角,齐天大圣,从被压五行山到护送唐僧西天取经的成长故事', role_type: 'main', line_count: 150, appearance_count: 45, has_tags: true, // 标识该角色有多个标签 default_tag_id: 'tag_char_002', // 默认显示"青年"标签 metadata: { gender: 'male', species: '石猴', personality: '桀骜不驯、勇敢正义', abilities: ['七十二变', '筋斗云', '火眼金睛'] }, // ❌ 没有 fileUrl, thumbnailUrl 等字段 } ]; ``` #### project-resources.ts(项目素材) ```typescript export const mockProjectResources: Resource[] = [ { id: '018e1234-5678-7abc-8def-200000000001', projectId: '018e1234-5678-7abc-8def-100000000001', name: '孙悟空-青年形象1', type: 'character', fileUrl: 'https://images.unsplash.com/...', thumbnailUrl: 'https://images.unsplash.com/...', fileSize: 1024000, mimeType: 'image/png', width: 400, height: 533, elementTagId: 'tag_char_002', // 关联到"孙悟空-青年"标签 isDefault: true, // 该标签的默认素材 // ... } ]; ``` ### 3. 数据关联关系 ``` 剧本元素档案 (screenplay-resources.ts) └─ 孙悟空 (character_id: char_001) ├─ has_tags: true └─ default_tag_id: tag_char_002 剧本元素标签 (screenplay-tags.ts) ├─ 孙悟空-少年 (tag_id: tag_char_001) └─ 孙悟空-青年 (tag_id: tag_char_002) ← 默认标签 项目素材 (project-resources.ts) ├─ 孙悟空-少年形象1 (elementTagId: tag_char_001, isDefault: true) ├─ 孙悟空-少年形象2 (elementTagId: tag_char_001, isDefault: false) ├─ 孙悟空-青年形象1 (elementTagId: tag_char_002, isDefault: true) └─ 孙悟空-青年形象2 (elementTagId: tag_char_002, isDefault: false) ``` ## 实施步骤 ### 1. 创建新文件 - ✅ `client/src/mocks/screenplay-resources.ts` - ✅ `client/src/mocks/project-resources.ts` ### 2. 更新导出 - ✅ `client/src/mocks/index.ts` ### 3. 更新引用 - ✅ `client/src/services/mockApi.ts` - ✅ `client/src/services/mock/resourceApi.ts` ### 4. 删除旧文件 - ✅ `client/src/mocks/resources.ts` ## 数据示例 ### 剧本元素档案(screenplay-resources.ts) ```typescript // 角色档案 { character_id: '018e1234-5678-7abc-8def-300000000001', screenplay_id: '018e1234-5678-7abc-8def-100000000001', name: '孙悟空', description: '主角,齐天大圣', role_type: 'main', has_tags: true, default_tag_id: 'tag_char_002', metadata: { gender: 'male', species: '石猴' } } // 场景档案 { scene_id: '018e1234-5678-7abc-8def-400000000001', screenplay_id: '018e1234-5678-7abc-8def-100000000001', scene_number: 1, title: '花果山水帘洞', location: '花果山', time_of_day: 'morning', description: '孙悟空的老家,瀑布后的洞府', has_tags: true, default_tag_id: 'tag_scene_001' } // 道具档案 { prop_id: '018e1234-5678-7abc-8def-500000000001', screenplay_id: '018e1234-5678-7abc-8def-100000000001', name: '金箍棒', description: '孙悟空的武器,可大可小', category: '武器', importance: 'key', has_tags: true, default_tag_id: 'tag_prop_001' } ``` ### 项目素材(project-resources.ts) ```typescript // 角色素材(关联到标签) { id: '018e1234-5678-7abc-8def-200000000001', projectId: '018e1234-5678-7abc-8def-100000000001', name: '孙悟空-青年形象1', type: 'character', fileUrl: 'https://...', thumbnailUrl: 'https://...', elementTagId: 'tag_char_002', // 关联到"孙悟空-青年"标签 isDefault: true // 该标签的默认素材 } // 场景素材(关联到标签) { id: '018e1234-5678-7abc-8def-200000000006', projectId: '018e1234-5678-7abc-8def-100000000001', name: '花果山水帘洞-白天1', type: 'scene', fileUrl: 'https://...', elementTagId: 'tag_scene_001', // 关联到"花果山-白天"标签 isDefault: true } // 通用素材(不关联标签) { id: '018e1234-5678-7abc-8def-200000000004', projectId: '018e1234-5678-7abc-8def-100000000001', name: '唐僧形象1', type: 'character', fileUrl: 'https://...', elementTagId: undefined, // 未关联标签 isDefault: false } ``` ## 优势 ### 1. 符合后端架构 - ✅ 与后端数据库设计一致 - ✅ 清晰的数据层级关系 - ✅ 便于后续 API 集成 ### 2. 职责分离 - ✅ 剧本元素档案:纯文字信息,从剧本提取 - ✅ 项目素材:视觉资源,用户上传或 AI 生成 - ✅ 标签系统:连接档案和素材 ### 3. 易于维护 - ✅ 数据结构清晰,不混淆 - ✅ 便于扩展新功能 - ✅ 便于理解和调试 ## 后续工作 ### 短期(本周) - [ ] 更新所有引用 `mockResources` 的组件 - [ ] 更新 TypeScript 类型定义(如需要) - [ ] 测试数据关联是否正确 ### 中期(下周) - [ ] 实现剧本元素档案的 CRUD API - [ ] 实现项目素材的上传和管理 API - [ ] 集成标签系统 ### 长期(未来) - [ ] AI 自动提取剧本元素档案 - [ ] AI 生成项目素材 - [ ] 素材库功能 ## 参考文档 - [剧本管理服务](../../requirements/backend/04-services/project/screenplay-service.md) - [剧本标签管理服务](../../requirements/backend/04-services/project/screenplay-tag-service.md) - [项目素材管理服务](../../requirements/backend/04-services/project/project-resource-service.md) ## 变更记录 **2026-01-26** - 创建 RFC - 实施文件拆分和重构 - 更新所有引用 --- **RFC 编号**: 132 **状态**: ✅ 已实施 **创建时间**: 2026-01-26