# 播放记录数据模型 **本文档引用的文件** - [schema.prisma](file://server/prisma/schema.prisma) - [player.controller.ts](file://server/src/modules/player/player.controller.ts) - [player.service.ts](file://server/src/modules/player/player.service.ts) - [history.controller.ts](file://server/src/modules/history/history.controller.ts) - [history-batch.controller.ts](file://server/src/modules/history/history-batch.controller.ts) - [index.vue](file://my-uniapp-vue3/src/pages/player/index.vue) - [audio.ts](file://my-uniapp-vue3/src/store/audio.ts) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构概览](#架构概览) 5. [详细组件分析](#详细组件分析) 6. [依赖分析](#依赖分析) 7. [性能考虑](#性能考虑) 8. [故障排除指南](#故障排除指南) 9. [结论](#结论) ## 简介 AI有声书生成平台的播放记录功能是一个关键的用户体验优化模块,它通过精确记录用户的播放进度、音频时长和章节关联信息,实现了无缝的跨设备播放体验。该系统支持实时进度更新、离线播放恢复、播放历史管理和跨设备同步等功能。 播放记录数据模型采用Prisma ORM进行数据库持久化,通过User和BookChapter两个实体建立了强关联关系,确保了数据的一致性和完整性。系统设计充分考虑了移动端播放场景的特殊需求,提供了灵活的API接口和高效的查询机制。 ## 项目结构 播放记录功能涉及前后端多个层次的协作: ```mermaid graph TB subgraph "前端层" FE_Player[播放器页面
index.vue] FE_Store[音频状态管理
audio.ts] FE_API[API调用封装
request.ts] end subgraph "后端层" BE_Controller[播放记录控制器
player.controller.ts] BE_Service[播放记录服务
player.service.ts] BE_DB[(数据库)] end subgraph "数据模型" DM_PlayRecord[PlayRecord模型] DM_User[User模型] DM_Chapter[BookChapter模型] end FE_Player --> FE_Store FE_Store --> BE_Controller BE_Controller --> BE_Service BE_Service --> BE_DB BE_DB --> DM_PlayRecord DM_PlayRecord --> DM_User DM_PlayRecord --> DM_Chapter ``` **图表来源** - [player.controller.ts:1-344](file://server/src/modules/player/player.controller.ts#L1-L344) - [player.service.ts:1-280](file://server/src/modules/player/player.service.ts#L1-L280) - [schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77) **章节来源** - [player.controller.ts:1-344](file://server/src/modules/player/player.controller.ts#L1-L344) - [player.service.ts:1-280](file://server/src/modules/player/player.service.ts#L1-L280) - [schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77) ## 核心组件 ### PlayRecord数据模型 PlayRecord模型是整个播放记录系统的核心,它定义了用户播放行为的完整数据结构: | 字段名 | 类型 | 默认值 | 约束 | 描述 | |--------|------|--------|------|------| | id | Int | 自增主键 | @id | 记录唯一标识符 | | userId | Int | - | - | 关联用户ID | | chapterId | Int | - | - | 关联章节ID | | progress | Float | 0 | - | 播放进度(秒) | | duration | Float | 0 | - | 音频总时长(秒) | | createdAt | DateTime | now() | @default | 创建时间 | | updatedAt | DateTime | @updatedAt | - | 更新时间 | ### 关系映射 ```mermaid erDiagram User ||--o{ PlayRecord : "拥有" BookChapter ||--o{ PlayRecord : "被播放" PlayRecord { int id PK int userId FK int chapterId FK float progress float duration datetime createdAt datetime updatedAt } User { int id PK string phone string openid string nickname string avatar int memberLevel datetime createdAt datetime updatedAt } BookChapter { int id PK int bookId FK int parentId int level int number string title string audioUrl int audioDuration datetime createdAt datetime updatedAt } ``` **图表来源** - [schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38) - [schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77) - [schema.prisma:161-192](file://server/prisma/schema.prisma#L161-L192) ### 数据库索引策略 系统采用了多层次的索引策略来优化查询性能: - **唯一约束**: `userId_chapterId` 确保每个用户对特定章节只有一个播放记录 - **用户索引**: `userId` 索引支持用户播放历史的快速检索 - **章节索引**: `chapterId` 索引支持章节维度的统计分析 **章节来源** - [schema.prisma:74-76](file://server/prisma/schema.prisma#L74-L76) ## 架构概览 播放记录系统的整体架构采用分层设计,从前端交互到后端服务再到数据库存储形成了清晰的职责分离: ```mermaid sequenceDiagram participant Client as "客户端应用" participant Store as "音频状态管理" participant Controller as "播放记录控制器" participant Service as "播放记录服务" participant DB as "数据库" Client->>Store : 播放状态变化 Store->>Controller : 更新播放进度请求 Controller->>Service : savePlayProgress(userId, chapterId, progress, duration) Service->>DB : upsert PlayRecord DB-->>Service : 更新结果 Service-->>Controller : 播放记录 Controller-->>Store : 响应结果 Store-->>Client : 更新UI状态 Note over Client,DB : 实时同步机制 ``` **图表来源** - [player.controller.ts:32-53](file://server/src/modules/player/player.controller.ts#L32-L53) - [player.service.ts:39-81](file://server/src/modules/player/player.service.ts#L39-L81) ## 详细组件分析 ### 后端控制器实现 #### 播放进度管理API 系统提供了完整的播放进度管理API集合: ```mermaid flowchart TD Start([API请求到达]) --> Auth{身份验证} Auth --> |通过| Route{路由分发} Auth --> |失败| Error401[401 未授权] Route --> GetProgress[GET /progress
获取播放进度] Route --> SaveProgress[POST /progress
保存播放进度] Route --> UpdateProgress[PUT /progress/:chapterId
更新播放进度] Route --> DeleteRecord[DELETE /progress/:chapterId
删除播放记录] Route --> BatchDelete[DELETE /progress/batch
批量删除] GetProgress --> ServiceCall1[调用服务层] SaveProgress --> ServiceCall2[调用服务层] UpdateProgress --> ServiceCall3[调用服务层] DeleteRecord --> ServiceCall4[调用服务层] BatchDelete --> ServiceCall5[调用服务层] ServiceCall1 --> DB1[数据库查询] ServiceCall2 --> DB2[数据库upsert] ServiceCall3 --> DB3[数据库更新] ServiceCall4 --> DB4[数据库删除] ServiceCall5 --> DB5[批量删除] DB1 --> Response1[返回进度列表] DB2 --> Response2[返回更新记录] DB3 --> Response3[返回更新结果] DB4 --> Response4[删除成功] DB5 --> Response5[批量删除成功] Response1 --> End([响应客户端]) Response2 --> End Response3 --> End Response4 --> End Response5 --> End Error401 --> End ``` **图表来源** - [player.controller.ts:14-107](file://server/src/modules/player/player.controller.ts#L14-L107) #### 播放历史获取功能 系统还提供了专门的播放历史获取功能: ```mermaid sequenceDiagram participant Client as "客户端" participant HistoryCtrl as "历史控制器" participant DB as "数据库" Client->>HistoryCtrl : GET /history HistoryCtrl->>HistoryCtrl : 解析查询参数 HistoryCtrl->>DB : 查询AudioRecord DB-->>HistoryCtrl : 历史记录列表 HistoryCtrl->>HistoryCtrl : 格式化响应数据 HistoryCtrl-->>Client : 历史记录JSON ``` **图表来源** - [history.controller.ts:11-64](file://server/src/modules/history/history.controller.ts#L11-L64) **章节来源** - [player.controller.ts:14-107](file://server/src/modules/player/player.controller.ts#L14-L107) - [history.controller.ts:11-64](file://server/src/modules/history/history.controller.ts#L11-L64) ### 服务层实现 #### 播放进度更新策略 服务层实现了智能的播放进度更新策略,采用upsert语义确保数据一致性: ```mermaid flowchart TD Input[接收更新请求] --> Validate{验证参数} Validate --> |失败| Error[抛出错误] Validate --> |成功| CheckExisting[检查记录是否存在] CheckExisting --> |存在| UpdateRecord[更新现有记录] CheckExisting --> |不存在| CreateRecord[创建新记录] UpdateRecord --> SetFields[设置progress和duration字段] CreateRecord --> BuildData[构建完整数据] SetFields --> SaveChanges[保存到数据库] BuildData --> SaveChanges SaveChanges --> ReturnResult[返回更新结果] Error --> ReturnError[返回错误信息] ``` **图表来源** - [player.service.ts:46-81](file://server/src/modules/player/player.service.ts#L46-L81) #### 最近播放记录功能 系统提供了最近播放记录的聚合查询功能: ```mermaid classDiagram class PlayRecordService { +getPlayProgress(userId, chapterId) Promise~PlayRecord[]~ +savePlayProgress(userId, chapterId, progress, duration) Promise~PlayRecord~ +updatePlayProgress(userId, chapterId, progress, duration) Promise~PlayRecord~ +deletePlayRecord(userId, chapterId) Promise~PlayRecord~ +getSingleProgress(userId, chapterId) Promise~PlayRecord~ +getRecentPlayRecords(userId, limit) Promise~RecentRecord[]~ } class RecentRecord { +string id +string title +string coverUrl +number progress +string updatedAt } PlayRecordService --> RecentRecord : "返回" ``` **图表来源** - [player.service.ts:10-34](file://server/src/modules/player/player.service.ts#L10-L34) - [player.service.ts:250-279](file://server/src/modules/player/player.service.ts#L250-L279) **章节来源** - [player.service.ts:10-122](file://server/src/modules/player/player.service.ts#L10-L122) - [player.service.ts:250-279](file://server/src/modules/player/player.service.ts#L250-L279) ### 前端集成实现 #### 播放器状态管理 前端使用Pinia状态管理库实现播放器的全局状态控制: ```mermaid stateDiagram-v2 [*] --> 初始化 初始化 --> 空闲 : 应用启动 空闲 --> 播放中 : 开始播放 播放中 --> 暂停 : 用户暂停 暂停 --> 播放中 : 继续播放 播放中 --> 结束 : 播放完成 结束 --> 空闲 : 重置状态 暂停 --> 空闲 : 停止播放 播放中 --> 空闲 : 切换音频 播放中 --> 发送进度 : 定时器触发 发送进度 --> 播放中 : 更新UI state 发送进度 { [*] --> 准备数据 准备数据 --> 验证状态 验证状态 --> 调用API 调用API --> [*] } ``` **图表来源** - [audio.ts:53-62](file://my-uniapp-vue3/src/store/audio.ts#L53-L62) #### 播放进度同步机制 前端实现了基于定时器的播放进度同步机制: ```mermaid sequenceDiagram participant Timer as "定时器" participant Store as "音频状态管理" participant API as "播放记录API" participant Server as "服务器" Timer->>Store : onTimeUpdate回调 Store->>Store : 更新currentTime Store->>Store : 计算进度百分比 Store->>API : 保存播放进度 API->>Server : POST /player/progress Server-->>API : 进度更新结果 API-->>Store : 响应数据 Store-->>Timer : 继续监听 Note over Timer,Store : 每30秒同步一次进度 ``` **图表来源** - [audio.ts:53-62](file://my-uniapp-vue3/src/store/audio.ts#L53-L62) - [player.controller.ts:32-53](file://server/src/modules/player/player.controller.ts#L32-L53) **章节来源** - [audio.ts:53-79](file://my-uniapp-vue3/src/store/audio.ts#L53-L79) - [index.vue:309-348](file://my-uniapp-vue3/src/pages/player/index.vue#L309-L348) ## 依赖分析 ### 数据模型依赖关系 播放记录系统的核心依赖关系如下: ```mermaid graph LR subgraph "核心模型" PR[PlayRecord] U[User] BC[BookChapter] end subgraph "业务逻辑" PC[播放记录控制器] PS[播放记录服务] HC[历史控制器] end subgraph "前端集成" FE[播放器页面] AS[音频状态] end U --> PR BC --> PR PC --> PS PS --> PR HC --> PR FE --> PC AS --> PC ``` **图表来源** - [schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77) - [player.controller.ts:1-344](file://server/src/modules/player/player.controller.ts#L1-L344) - [player.service.ts:1-280](file://server/src/modules/player/player.service.ts#L1-L280) ### 外部依赖 系统主要依赖以下外部组件: - **Prisma ORM**: 数据库抽象层,提供类型安全的数据库操作 - **Koa Router**: HTTP路由框架,处理RESTful API请求 - **Pinia**: Vue.js状态管理库,管理播放器全局状态 - **UniApp**: 跨平台移动应用开发框架 **章节来源** - [schema.prisma:1-8](file://server/prisma/schema.prisma#L1-L8) - [player.controller.ts:1-6](file://server/src/modules/player/player.controller.ts#L1-L6) ## 性能考虑 ### 查询优化策略 系统采用了多种查询优化策略来提升性能: 1. **索引优化**: 在`userId`和`chapterId`字段上建立索引,支持高频查询 2. **唯一约束**: 使用`userId_chapterId`唯一约束避免重复记录 3. **延迟加载**: 使用`include`选项按需加载关联数据 4. **批量操作**: 提供批量删除功能减少数据库往返次数 ### 缓存策略 虽然当前实现主要依赖数据库查询,但可以考虑以下缓存优化: - **热点数据缓存**: 缓存用户最近播放的章节信息 - **进度缓存**: 缓存播放进度到本地存储,支持离线恢复 - **批量更新**: 合并多次进度更新请求,减少网络请求 ### 并发控制 系统通过数据库事务和唯一约束确保并发安全性: ```mermaid flowchart TD Request[并发请求] --> CheckLock{检查锁} CheckLock --> |无锁| AcquireLock[获取锁] CheckLock --> |有锁| WaitQueue[等待队列] AcquireLock --> ProcessRequest[处理请求] ProcessRequest --> ReleaseLock[释放锁] ReleaseLock --> NotifyQueue[通知等待队列] WaitQueue --> CheckLock ``` ## 故障排除指南 ### 常见问题及解决方案 #### 播放进度不同步 **问题描述**: 播放进度与实际播放位置不一致 **可能原因**: 1. 定时器更新频率过高导致数据库压力 2. 网络延迟导致进度更新失败 3. 前端状态与后端状态不一致 **解决方案**: 1. 调整进度更新间隔(当前为30秒) 2. 实现重试机制和错误处理 3. 添加状态同步检查 #### 数据库连接问题 **问题描述**: 播放记录无法保存到数据库 **可能原因**: 1. 数据库连接池耗尽 2. SQL查询超时 3. 数据库权限不足 **解决方案**: 1. 检查数据库连接配置 2. 实现连接池监控和重连机制 3. 优化SQL查询性能 #### 前端状态异常 **问题描述**: 播放器UI状态与实际播放状态不符 **可能原因**: 1. 音频上下文初始化失败 2. 事件监听器未正确清理 3. 异步操作竞态条件 **解决方案**: 1. 添加音频上下文初始化检查 2. 实现完整的生命周期管理 3. 使用防抖函数处理频繁更新 **章节来源** - [audio.ts:64-74](file://my-uniapp-vue3/src/store/audio.ts#L64-L74) - [player.service.ts:46-81](file://server/src/modules/player/player.service.ts#L46-L81) ## 结论 AI有声书生成平台的播放记录数据模型设计充分体现了现代Web应用的最佳实践。通过精心设计的数据模型、完善的API接口和高效的前端集成,系统实现了以下核心价值: ### 技术优势 1. **数据一致性**: 通过唯一约束和事务处理确保播放记录的准确性 2. **性能优化**: 多层次索引和查询优化提升了系统响应速度 3. **用户体验**: 实时进度同步和离线恢复功能改善了用户使用体验 4. **扩展性**: 模块化的架构设计便于功能扩展和维护 ### 业务价值 1. **用户粘性**: 精确的播放进度记录提高了用户留存率 2. **个性化推荐**: 播放历史数据为内容推荐算法提供重要依据 3. **产品优化**: 用户行为数据分析指导产品功能改进 4. **商业价值**: 通过提升用户体验间接促进业务增长 ### 未来发展方向 1. **智能推荐**: 基于播放记录的机器学习推荐算法 2. **跨设备同步**: 更完善的多设备播放状态同步机制 3. **离线播放**: 增强离线播放体验和数据同步能力 4. **社交功能**: 基于播放历史的社交分享和互动功能 该播放记录数据模型为AI有声书平台奠定了坚实的技术基础,通过持续优化和功能扩展,将为用户提供更加优质的音频播放体验。