# 使用统计模型

<cite>
**本文引用的文件**
- [schema.prisma](file://server/prisma/schema.prisma)
- [models/index.ts](file://server/src/models/index.ts)
- [player.controller.ts](file://server/src/modules/player/player.controller.ts)
- [player.service.ts](file://server/src/modules/player/player.service.ts)
- [search.controller.ts](file://server/src/modules/search/search.controller.ts)
- [search.service.ts](file://server/src/modules/search/search.service.ts)
- [index.vue](file://my-uniapp-vue3/src/pages/search/index.vue)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件面向AI有声书生成平台的“使用统计模型”，聚焦以下三类用户行为数据模型与其实现：
- 播放记录模型：PlayRecord，用于记录用户对章节的播放进度与时长，支撑继续播放、最近播放、播放时长统计等功能。
- 搜索统计模型：SearchHistory 与 HotSearch，分别记录用户搜索历史与热门搜索词热度，支撑搜索推荐与趋势分析。
- 用户偏好模型：UserPreference，用于记录播放速度、音质、默认音色等偏好，辅助个性化推荐。

本文将从数据模型设计、后端服务与控制器实现、前端调用与展示、以及业务场景（播放统计分析、用户行为画像、内容推荐）等方面进行系统化说明，并提供API使用示例与可视化思路。

## 项目结构
围绕使用统计的核心文件分布如下：
- 数据模型定义：Prisma Schema（包含 PlayRecord、SearchHistory、HotSearch、UserPreference 等）
- 数据库连接：Prisma 客户端封装
- 播放统计模块：player.controller.ts 与 player.service.ts
- 搜索统计模块：search.controller.ts 与 search.service.ts
- 前端搜索页：my-uniapp-vue3/src/pages/search/index.vue（演示搜索历史与热门词的调用）

```mermaid
graph TB
subgraph "前端"
FE_Search["搜索页<br/>index.vue"]
end
subgraph "后端"
PCtrl["播放控制器<br/>player.controller.ts"]
PService["播放服务<br/>player.service.ts"]
SCtrl["搜索控制器<br/>search.controller.ts"]
SService["搜索服务<br/>search.service.ts"]
Models["Prisma 模型<br/>schema.prisma"]
DB["MySQL 数据库"]
end
FE_Search --> PCtrl
FE_Search --> SCtrl
PCtrl --> PService
SCtrl --> SService
PService --> Models
SService --> Models
Models --> DB
```

**图表来源**
- [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)
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)
- [search.service.ts:1-145](file://server/src/modules/search/search.service.ts#L1-L145)
- [schema.prisma:63-240](file://server/prisma/schema.prisma#L63-L240)

**章节来源**
- [schema.prisma:63-240](file://server/prisma/schema.prisma#L63-L240)
- [models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)

## 核心组件
本节概述三大使用统计模型及其职责与关键字段。

- PlayRecord 播放记录
  - 字段要点：用户ID、章节ID、播放进度、播放时长、创建/更新时间
  - 约束：唯一索引（用户+章节），便于按用户或章节快速查询
  - 用途：继续播放、最近播放、播放时长统计、章节完成度分析

- SearchHistory 搜索历史
  - 字段要点：用户ID、关键词、创建时间
  - 约束：用户+时间复合索引；支持去重保留最新关键词
  - 用途：个性化搜索建议、用户搜索行为追踪

- HotSearch 热门搜索
  - 字段要点：关键词、热度计数、排序分值、创建/更新时间
  - 约束：排序与热度索引，便于排行榜查询
  - 用途：热门搜索排行、内容推荐触发

- UserPreference 用户偏好
  - 字段要点：播放速度、音质、主题、默认音色、音量、自动下一曲、仅WiFi下载等
  - 用途：个性化推荐、播放体验优化

**章节来源**
- [schema.prisma:63-92](file://server/prisma/schema.prisma#L63-L92)
- [schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)

## 架构总览
播放与搜索统计的端到端流程如下：

```mermaid
sequenceDiagram
participant FE as "前端应用"
participant PC as "播放控制器"
participant PS as "播放服务"
participant SC as "搜索控制器"
participant SS as "搜索服务"
participant PRISMA as "Prisma 客户端"
participant DB as "MySQL"
FE->>PC : "POST /api/player/progress"
PC->>PS : "保存播放进度"
PS->>PRISMA : "upsert PlayRecord"
PRISMA->>DB : "写入/更新记录"
DB-->>PRISMA : "确认"
PRISMA-->>PS : "返回记录"
PS-->>PC : "返回记录"
PC-->>FE : "保存成功"
FE->>SC : "GET /api/search/hot"
SC->>SS : "获取热门搜索"
SS->>PRISMA : "查询 HotSearch"
PRISMA->>DB : "读取热门词"
DB-->>PRISMA : "返回结果"
PRISMA-->>SS : "返回热门词"
SS-->>SC : "返回热门词"
SC-->>FE : "返回热门词"
```

**图表来源**
- [player.controller.ts:31-53](file://server/src/modules/player/player.controller.ts#L31-L53)
- [player.service.ts:39-81](file://server/src/modules/player/player.service.ts#L39-L81)
- [search.controller.ts:38-58](file://server/src/modules/search/search.controller.ts#L38-L58)
- [search.service.ts:41-50](file://server/src/modules/search/search.service.ts#L41-L50)

## 详细组件分析

### PlayRecord 模型与播放统计
- 数据结构与约束
  - 唯一索引：用户+章节，确保同一用户对同一章节仅有一条播放记录
  - 外键：关联用户与章节，便于跨表查询
- 关键功能
  - 保存/更新播放进度：支持 upsert 语义，避免重复插入
  - 获取单条进度：按用户+章节查询
  - 获取最近播放：按更新时间倒序取前N条
  - 删除进度：按用户+章节删除
- 播放时长统计
  - duration 字段记录本次播放时长，可用于累计播放时长、章节完成度等分析
- 继续播放与播放时长分析
  - progress/duration 结合可计算“剩余时长”、“完成百分比”
  - 结合 BookChapter 的音频时长，可做章节完成度与整体阅读进度画像

```mermaid
classDiagram
class PlayRecord {
+int id
+int userId
+int chapterId
+float progress
+float duration
+datetime createdAt
+datetime updatedAt
}
class User {
+int id
+string phone
+string openid
+int memberLevel
+int dailyUsage
+string lastUsageDate
+int usedAudioMinutes
}
class BookChapter {
+int id
+int bookId
+int parentId
+int level
+int number
+string title
+string audioUrl
+int audioDuration
}
PlayRecord --> User : "属于用户"
PlayRecord --> BookChapter : "属于章节"
```

**图表来源**
- [schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77)
- [schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38)
- [schema.prisma:161-192](file://server/prisma/schema.prisma#L161-L192)

**章节来源**
- [player.service.ts:10-139](file://server/src/modules/player/player.service.ts#L10-L139)
- [player.controller.ts:13-132](file://server/src/modules/player/player.controller.ts#L13-L132)

### SearchHistory 与 HotSearch 模型与搜索统计
- SearchHistory
  - 记录用户每次搜索的关键词，支持去重（同一用户同一关键词仅保留最新一条）
  - 限制用户历史数量上限（超过阈值删除最旧记录）
- HotSearch
  - 记录热门关键词及其热度（count）与排序分值（sort）
  - 排行榜查询按 sort 降序、count 降序排序
- 搜索统计实现
  - 保存搜索历史时，同时更新热门搜索计数
  - 获取热门搜索与用户历史接口分别提供排行榜与个性化建议

```mermaid
flowchart TD
Start(["开始搜索"]) --> SaveHistory["保存搜索历史"]
SaveHistory --> Dedup["删除同用户同关键词旧记录"]
Dedup --> InsertNew["插入新历史记录"]
InsertNew --> LimitCheck{"历史数量是否超过上限?"}
LimitCheck --> |是| TrimOld["删除最旧的历史记录"]
LimitCheck --> |否| UpdateHot["更新热门搜索计数"]
TrimOld --> UpdateHot
UpdateHot --> GetHot["获取热门搜索排行"]
GetHot --> ReturnHot["返回热门搜索列表"]
```

**图表来源**
- [search.service.ts:72-119](file://server/src/modules/search/search.service.ts#L72-L119)
- [search.controller.ts:84-113](file://server/src/modules/search/search.controller.ts#L84-L113)

**章节来源**
- [search.service.ts:57-119](file://server/src/modules/search/search.service.ts#L57-L119)
- [search.controller.ts:64-113](file://server/src/modules/search/search.controller.ts#L64-L113)

### UserPreference 模型与个性化推荐
- 字段覆盖播放速度、音质、主题、默认音色、音量、自动下一曲、仅WiFi下载等
- 用途
  - 个性化推荐：结合用户偏好与播放记录，提升推荐相关性
  - 播放体验：根据偏好自动调整播放参数

**章节来源**
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)

## 依赖关系分析
- 模块耦合
  - 控制器仅负责参数校验与响应包装，业务逻辑集中在服务层
  - 服务层通过 Prisma 客户端访问数据库，保证数据一致性
- 外部依赖
  - Prisma Client 作为 ORM 层，负责与 MySQL 交互
  - 前端通过 HTTP 请求调用后端 API，实现搜索与播放统计的前后端联动

```mermaid
graph LR
FE["前端搜索页<br/>index.vue"] --> API_Search["搜索API<br/>GET /api/search/*"]
FE --> API_Player["播放API<br/>GET/POST /api/player/*"]
API_Search --> SCtrl["search.controller.ts"]
API_Player --> PCtrl["player.controller.ts"]
SCtrl --> SService["search.service.ts"]
PCtrl --> PService["player.service.ts"]
SService --> Prisma["models/index.ts"]
PService --> Prisma
Prisma --> DB["MySQL"]
```

**图表来源**
- [index.vue:166-240](file://my-uniapp-vue3/src/pages/search/index.vue#L166-L240)
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)
- [player.controller.ts:1-344](file://server/src/modules/player/player.controller.ts#L1-L344)
- [models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)

**章节来源**
- [models/index.ts:1-15](file://server/src/models/index.ts#L1-L15)
- [player.controller.ts:1-344](file://server/src/modules/player/player.controller.ts#L1-L344)
- [search.controller.ts:1-170](file://server/src/modules/search/search.controller.ts#L1-L170)

## 性能考量
- 查询优化
  - PlayRecord：按用户或章节查询时利用唯一索引（用户+章节）与单列索引（用户、章节）
  - SearchHistory：按用户+时间复合索引，支持去重与上限控制
  - HotSearch：按排序与热度建立索引，排行榜查询高效
- 写入优化
  - upsert 语义减少重复插入，降低写入冲突
  - 热门搜索计数采用原子自增，避免并发竞争
- 前端缓存
  - 前端可对热门搜索词进行本地缓存，减少重复请求

[本节为通用性能建议，不直接分析具体文件]

## 故障排查指南
- 播放进度保存失败
  - 检查请求参数：audioId、progress、duration 是否有效
  - 检查用户认证：开发环境使用测试用户ID，生产需登录态
  - 查看数据库唯一索引冲突：同一用户同一章节应合并为一次记录
- 搜索历史异常
  - 关键词为空或空白字符会被忽略
  - 历史数量超过上限会自动清理最旧记录
  - 热门搜索计数未更新可能因关键词不存在导致创建失败
- 热门搜索排行为空
  - 确认是否有搜索行为产生，或检查定时任务/触发条件

**章节来源**
- [player.controller.ts:42-44](file://server/src/modules/player/player.controller.ts#L42-L44)
- [player.service.ts:46-81](file://server/src/modules/player/player.service.ts#L46-L81)
- [search.service.ts:72-119](file://server/src/modules/search/search.service.ts#L72-L119)

## 结论
本项目通过 PlayRecord、SearchHistory、HotSearch、UserPreference 四个核心模型，构建了完整的使用统计体系：
- 播放侧：以播放进度与时长为核心，支撑继续播放、最近播放、播放时长统计与章节完成度分析
- 搜索侧：以搜索历史与热门搜索为核心，支撑个性化推荐与内容发现
- 偏好侧：以用户偏好为核心，提升个性化推荐与播放体验

配合清晰的控制器与服务层分离、完善的索引策略与前端缓存机制，能够满足高并发下的统计需求，并为后续的用户行为画像与内容推荐打下坚实基础。

[本节为总结性内容，不直接分析具体文件]

## 附录

### API 使用示例（播放统计）
- 获取播放进度列表
  - 方法：GET
  - 路径：/api/player/progress
  - 参数：userId（可选，开发环境默认使用测试用户ID）、audioId（可选，按章节过滤）
  - 响应：records 列表
- 保存播放进度
  - 方法：POST
  - 路径：/api/player/progress
  - 请求体：{ audioId, progress, duration }
  - 响应：保存的记录
- 更新播放进度
  - 方法：PUT
  - 路径：/api/player/progress/:audioId
  - 请求体：{ progress, duration? }
  - 响应：更新后的记录
- 删除播放记录
  - 方法：DELETE
  - 路径：/api/player/progress/:audioId
  - 响应：删除成功消息
- 获取最近播放记录
  - 方法：GET
  - 路径：/api/player/recent
  - 响应：包含章节标题、封面、进度百分比、更新时间的列表

**章节来源**
- [player.controller.ts:13-132](file://server/src/modules/player/player.controller.ts#L13-L132)
- [player.service.ts:10-279](file://server/src/modules/player/player.service.ts#L10-L279)

### API 使用示例（搜索统计）
- 搜索书籍
  - 方法：GET
  - 路径：/api/search
  - 参数：q（关键词）、limit（结果数量）
  - 响应：匹配的书籍列表
- 获取热门搜索词
  - 方法：GET
  - 路径：/api/search/hot
  - 参数：limit（数量）
  - 响应：热门搜索列表（按 sort 降序、count 降序）
- 获取搜索历史
  - 方法：GET
  - 路径：/api/search/history
  - 参数：userId、limit
  - 响应：用户搜索历史（去重保留最新关键词）
- 保存搜索历史
  - 方法：POST
  - 路径：/api/search/history
  - 请求体：{ userId, keyword }
  - 响应：成功消息
- 删除单条搜索历史
  - 方法：DELETE
  - 路径：/api/search/history
  - 参数：userId、keyword
  - 响应：成功消息
- 清空搜索历史
  - 方法：DELETE
  - 路径：/api/search/history/all
  - 参数：userId
  - 响应：成功消息

**章节来源**
- [search.controller.ts:6-167](file://server/src/modules/search/search.controller.ts#L6-L167)
- [search.service.ts:13-141](file://server/src/modules/search/search.service.ts#L13-L141)

### 前端调用示例（搜索页）
- 加载搜索上下文（历史与热门）
  - 并行请求：/api/search/history 与 /api/search/hot
  - 成功后缓存热门词到本地存储
- 点击历史/热搜关键词
  - 将关键词填入搜索框并发起搜索请求 /api/search?q=关键词
- 保存搜索历史
  - 搜索成功后调用 /api/search/history 保存关键词

**章节来源**
- [index.vue:166-240](file://my-uniapp-vue3/src/pages/search/index.vue#L166-L240)

### 业务场景与可视化建议
- 播放统计分析
  - 用户维度：累计播放时长、平均播放进度、章节完成率
  - 内容维度：章节播放次数、平均时长、完播率
  - 可视化：折线图（趋势）、柱状图（排行榜）、仪表盘（完成率）
- 用户行为画像
  - 基于 PlayRecord 与 UserPreference，构建用户偏好画像（速度、音质、音色）
  - 结合搜索历史，识别兴趣标签（题材、作者、关键词）
- 内容推荐算法
  - 协同过滤：基于相似用户的行为进行推荐
  - 内容过滤：基于用户偏好与搜索标签进行匹配
  - 热度与新鲜度：结合 HotSearch 与时间衰减因子

[本节为概念性建议，不直接分析具体文件]