# 历史记录
**本文引用的文件**
- [server/src/modules/history/history.controller.ts](file://server/src/modules/history/history.controller.ts)
- [server/src/modules/history/history-batch.controller.ts](file://server/src/modules/history/history-batch.controller.ts)
- [server/src/modules/player/player.controller.ts](file://server/src/modules/player/player.controller.ts)
- [server/src/modules/player/player.service.ts](file://server/src/modules/player/player.service.ts)
- [server/src/modules/search/search.service.ts](file://server/src/modules/search/search.service.ts)
- [server/src/modules/search/search.controller.ts](file://server/src/modules/search/search.controller.ts)
- [server/prisma/schema.prisma](file://server/prisma/schema.prisma)
- [server/src/app.ts](file://server/src/app.ts)
- [server/src/middleware/auth.ts](file://server/src/middleware/auth.ts)
- [my-uniapp-vue3/src/pages/history/index.vue](file://my-uniapp-vue3/src/pages/history/index.vue)
- [my-uniapp-vue3/src/pages/search/index.vue](file://my-uniapp-vue3/src/pages/search/index.vue)
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本技术文档围绕“历史记录”功能进行全面梳理,涵盖以下方面:
- 架构设计:播放历史追踪、搜索历史保存、批量历史操作
- 数据模型与存储策略:时间戳管理、去重机制、数据清理规则
- 查询优化与索引设计
- 历史记录API接口文档(含单条与批量)
- 用户体验:个性化推荐与内容发现
- 隐私保护与合规性
## 项目结构
历史记录相关能力横跨后端模块与前端页面:
- 后端
- 历史记录模块:音频生成历史列表、批量删除
- 播放历史模块:播放进度记录、最近播放
- 搜索历史模块:历史查询、热门词、去重与清理
- 数据模型:Prisma 定义的 AudioRecord、PlayRecord、SearchHistory 等
- 应用入口:路由注册历史与播放、搜索模块
- 前端
- 历史页面:分页加载、筛选(今日/本周/本月)、搜索、批量删除/下载
- 搜索页面:历史与热门词展示
```mermaid
graph TB
subgraph "前端"
FE_History["历史页面
my-uniapp-vue3/src/pages/history/index.vue"]
FE_Search["搜索页面
my-uniapp-vue3/src/pages/search/index.vue"]
end
subgraph "后端"
APP["应用入口
server/src/app.ts"]
AUTH["认证中间件
server/src/middleware/auth.ts"]
subgraph "历史模块"
HIST_CTRL["历史控制器
history.controller.ts"]
HIST_BATCH["批量删除控制器
history-batch.controller.ts"]
end
subgraph "播放历史模块"
PLAYER_CTRL["播放控制器
player.controller.ts"]
PLAYER_SRV["播放服务
player.service.ts"]
end
subgraph "搜索历史模块"
SEARCH_CTRL["搜索控制器
search.controller.ts"]
SEARCH_SRV["搜索服务
search.service.ts"]
end
PRISMA["数据模型
server/prisma/schema.prisma"]
end
FE_History --> |HTTP| HIST_CTRL
FE_History --> |HTTP| HIST_BATCH
FE_Search --> |HTTP| SEARCH_CTRL
FE_History --> |HTTP| PLAYER_CTRL
FE_History --> |HTTP| PLAYER_SRV
HIST_CTRL --> AUTH --> PRISMA
HIST_BATCH --> AUTH --> PRISMA
PLAYER_CTRL --> AUTH --> PRISMA
PLAYER_SRV --> PRISMA
SEARCH_CTRL --> AUTH --> PRISMA
SEARCH_SRV --> PRISMA
APP --> HIST_CTRL
APP --> HIST_BATCH
APP --> PLAYER_CTRL
APP --> SEARCH_CTRL
```
图表来源
- [server/src/app.ts:120-127](file://server/src/app.ts#L120-L127)
- [server/src/modules/history/history.controller.ts:1-67](file://server/src/modules/history/history.controller.ts#L1-L67)
- [server/src/modules/history/history-batch.controller.ts:1-105](file://server/src/modules/history/history-batch.controller.ts#L1-L105)
- [server/src/modules/player/player.controller.ts:1-344](file://server/src/modules/player/player.controller.ts#L1-L344)
- [server/src/modules/player/player.service.ts:1-280](file://server/src/modules/player/player.service.ts#L1-L280)
- [server/src/modules/search/search.controller.ts:69-169](file://server/src/modules/search/search.controller.ts#L69-L169)
- [server/src/modules/search/search.service.ts:1-144](file://server/src/modules/search/search.service.ts#L1-L144)
- [server/prisma/schema.prisma:220-373](file://server/prisma/schema.prisma#L220-L373)
章节来源
- [server/src/app.ts:120-127](file://server/src/app.ts#L120-L127)
- [server/src/modules/history/history.controller.ts:1-67](file://server/src/modules/history/history.controller.ts#L1-L67)
- [server/src/modules/history/history-batch.controller.ts:1-105](file://server/src/modules/history/history-batch.controller.ts#L1-L105)
- [server/src/modules/player/player.controller.ts:1-344](file://server/src/modules/player/player.controller.ts#L1-L344)
- [server/src/modules/player/player.service.ts:1-280](file://server/src/modules/player/player.service.ts#L1-L280)
- [server/src/modules/search/search.controller.ts:69-169](file://server/src/modules/search/search.controller.ts#L69-L169)
- [server/src/modules/search/search.service.ts:1-144](file://server/src/modules/search/search.service.ts#L1-L144)
- [server/prisma/schema.prisma:220-373](file://server/prisma/schema.prisma#L220-L373)
## 核心组件
- 历史记录控制器:提供历史列表查询,支持按起始时间过滤、分页与总数统计
- 批量删除控制器:提供批量删除音频生成历史的能力
- 播放历史控制器与服务:提供播放进度的增删改查、最近播放列表、章节音频合并等
- 搜索历史服务与控制器:提供搜索历史的保存、查询、清理与热门词统计
- 数据模型:AudioRecord、PlayRecord、SearchHistory 等,包含索引与字段约束
- 认证中间件:optionalAuth 支持未登录场景下的测试用户兜底
章节来源
- [server/src/modules/history/history.controller.ts:10-64](file://server/src/modules/history/history.controller.ts#L10-L64)
- [server/src/modules/history/history-batch.controller.ts:10-102](file://server/src/modules/history/history-batch.controller.ts#L10-L102)
- [server/src/modules/player/player.controller.ts:13-132](file://server/src/modules/player/player.controller.ts#L13-L132)
- [server/src/modules/player/player.service.ts:10-122](file://server/src/modules/player/player.service.ts#L10-L122)
- [server/src/modules/search/search.service.ts:57-119](file://server/src/modules/search/search.service.ts#L57-L119)
- [server/src/modules/search/search.controller.ts:69-169](file://server/src/modules/search/search.controller.ts#L69-L169)
- [server/prisma/schema.prisma:220-373](file://server/prisma/schema.prisma#L220-L373)
- [server/src/middleware/auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80)
## 架构总览
历史记录系统采用“模块化控制器 + 服务层 + Prisma ORM”的分层架构:
- 控制器负责请求解析、参数校验与响应封装
- 服务层封装业务逻辑(如去重、清理、合并)
- Prisma 模型定义数据结构与索引,保证查询效率与一致性
- optionalAuth 中间件在未登录时提供测试用户兜底,便于前端联调
```mermaid
sequenceDiagram
participant FE as "前端历史页面"
participant CTRL as "历史控制器"
participant AUTH as "optionalAuth"
participant PRISMA as "Prisma ORM"
FE->>CTRL : GET /api/history?page=&pageSize=&startDate=
CTRL->>AUTH : 校验可选认证
AUTH-->>CTRL : 设置用户上下文(测试用户或真实用户)
CTRL->>PRISMA : 查询 AudioRecord 列表+总数
PRISMA-->>CTRL : 返回记录与总数
CTRL-->>FE : 分页列表与分页信息
```
图表来源
- [server/src/modules/history/history.controller.ts:11-64](file://server/src/modules/history/history.controller.ts#L11-L64)
- [server/src/middleware/auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
## 详细组件分析
### 历史记录模块(音频生成历史)
- 功能要点
- 列表查询:支持按起始时间过滤、分页、总数统计
- 字段映射:统一返回格式,包含标题、文本、音频链接、时长、字数、音色参数、状态、创建/更新时间等
- 关键实现
- 控制器:分页查询与总数统计并行执行;where 条件根据 startDate 构建
- 模型:AudioRecord 定义字段与索引(userId、audioId、bookId)
```mermaid
flowchart TD
Start(["进入历史列表接口"]) --> Parse["解析分页参数
page/pageSize"]
Parse --> BuildWhere["构建查询条件
startDate -> createdAt >= ..."]
BuildWhere --> Parallel["并行查询
列表 + 总数"]
Parallel --> MapFields["字段映射与格式化"]
MapFields --> Return["返回分页数据"]
```
图表来源
- [server/src/modules/history/history.controller.ts:14-64](file://server/src/modules/history/history.controller.ts#L14-L64)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
章节来源
- [server/src/modules/history/history.controller.ts:10-64](file://server/src/modules/history/history.controller.ts#L10-L64)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
### 批量历史操作(批量删除)
- 功能要点
- 支持 POST 与 DELETE 两种方式(兼容性考虑)
- 校验 ids 数组合法性
- 返回删除数量
- 关键实现
- 控制器:解析请求体或查询参数,构造 in 查询条件,调用 Prisma deleteMany
- 模型:基于 audioId 唯一键进行批量删除
```mermaid
sequenceDiagram
participant FE as "前端历史页面"
participant BATCH as "批量删除控制器"
participant AUTH as "optionalAuth"
participant PRISMA as "Prisma ORM"
FE->>BATCH : POST /api/history/batch-delete {ids[]}
BATCH->>AUTH : 校验可选认证
AUTH-->>BATCH : 设置用户上下文
BATCH->>BATCH : 校验ids数组
BATCH->>PRISMA : deleteMany({audioId : {in : ids}})
PRISMA-->>BATCH : 返回删除计数
BATCH-->>FE : {deletedCount}
```
图表来源
- [server/src/modules/history/history-batch.controller.ts:11-49](file://server/src/modules/history/history-batch.controller.ts#L11-L49)
- [server/src/modules/history/history-batch.controller.ts:52-102](file://server/src/modules/history/history-batch.controller.ts#L52-L102)
- [server/src/middleware/auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
章节来源
- [server/src/modules/history/history-batch.controller.ts:10-102](file://server/src/modules/history/history-batch.controller.ts#L10-L102)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
### 播放历史模块(播放进度与最近播放)
- 功能要点
- 保存/更新播放进度:upsert 语义,支持传入 duration
- 删除单条播放记录
- 获取最近播放列表(带进度百分比与书籍封面)
- 章节音频合并:当播放章(level=1)时自动合并其下小节音频
- 关键实现
- 控制器:提供 GET/POST/PUT/DELETE 接口
- 服务层:封装 upsert、合并逻辑、最近播放查询
- 模型:PlayRecord 唯一索引(userId, chapterId),支持关联章节与书籍
```mermaid
classDiagram
class PlayRecord {
+int id
+int userId
+int chapterId
+float progress
+float duration
+DateTime createdAt
+DateTime updatedAt
}
class BookChapter {
+int id
+int bookId
+int level
+int number
+String title
+String audioUrl
+int audioDuration
}
class Book {
+int id
+String title
+String coverUrl
}
PlayRecord --> BookChapter : "属于"
BookChapter --> Book : "属于"
```
图表来源
- [server/prisma/schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77)
- [server/prisma/schema.prisma:161-192](file://server/prisma/schema.prisma#L161-L192)
- [server/prisma/schema.prisma:130-159](file://server/prisma/schema.prisma#L130-L159)
章节来源
- [server/src/modules/player/player.controller.ts:13-132](file://server/src/modules/player/player.controller.ts#L13-L132)
- [server/src/modules/player/player.service.ts:10-122](file://server/src/modules/player/player.service.ts#L10-L122)
- [server/src/modules/player/player.service.ts:240-280](file://server/src/modules/player/player.service.ts#L240-L280)
- [server/prisma/schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77)
- [server/prisma/schema.prisma:161-192](file://server/prisma/schema.prisma#L161-L192)
- [server/prisma/schema.prisma:130-159](file://server/prisma/schema.prisma#L130-L159)
### 搜索历史模块(历史、热门、去重与清理)
- 功能要点
- 保存搜索历史:去重(同一用户相同关键词仅保留最新)、限制最大条数(超过则删除最旧)
- 查询历史:按时间倒序,distinct 关键词
- 清理历史:单条删除、清空全部
- 热门词统计:每次保存时增加计数,不存在则新建
- 关键实现
- 服务层:删除旧同关键词记录、限制最大长度、更新热门词
- 控制器:参数校验、异常捕获
- 模型:SearchHistory、HotSearch
```mermaid
flowchart TD
Save["保存搜索历史"] --> Dedup["删除同用户同关键词旧记录"]
Dedup --> InsertNew["插入新记录"]
InsertNew --> Limit["查询用户历史并限制数量<=20"]
Limit --> Cleanup["删除超出部分"]
Cleanup --> UpdateHot["更新/新增热门词计数"]
UpdateHot --> Done["完成"]
```
图表来源
- [server/src/modules/search/search.service.ts:72-119](file://server/src/modules/search/search.service.ts#L72-L119)
- [server/prisma/schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)
章节来源
- [server/src/modules/search/search.service.ts:57-119](file://server/src/modules/search/search.service.ts#L57-L119)
- [server/src/modules/search/search.controller.ts:69-169](file://server/src/modules/search/search.controller.ts#L69-L169)
- [server/prisma/schema.prisma:220-240](file://server/prisma/schema.prisma#L220-L240)
### 前端集成与用户体验
- 历史页面
- 支持标签筛选(全部/今天/本周/本月),按 startDate 过滤
- 支持搜索关键词过滤
- 支持批量删除与批量下载
- 分页加载与骨架屏
- 搜索页面
- 展示搜索历史与热门词,支持点击回填
章节来源
- [my-uniapp-vue3/src/pages/history/index.vue:168-360](file://my-uniapp-vue3/src/pages/history/index.vue#L168-L360)
- [my-uniapp-vue3/src/pages/history/index.vue:202-291](file://my-uniapp-vue3/src/pages/history/index.vue#L202-L291)
- [my-uniapp-vue3/src/pages/search/index.vue:166-191](file://my-uniapp-vue3/src/pages/search/index.vue#L166-L191)
## 依赖关系分析
- 路由注册
- 历史模块:/api/history
- 播放历史模块:/api/player
- 搜索模块:/api/search
- 认证依赖
- optionalAuth 为历史与播放等模块提供可选认证,未登录时使用测试用户
- 数据模型依赖
- AudioRecord、PlayRecord、SearchHistory 等模型定义字段与索引,支撑查询与去重
```mermaid
graph LR
APP["app.ts"] --> HIST["/api/history"]
APP --> PLAYER["/api/player"]
APP --> SEARCH["/api/search"]
HIST --> AUTH["optionalAuth"]
PLAYER --> AUTH
SEARCH --> AUTH
HIST --> PRISMA["Prisma模型"]
PLAYER --> PRISMA
SEARCH --> PRISMA
```
图表来源
- [server/src/app.ts:120-127](file://server/src/app.ts#L120-L127)
- [server/src/middleware/auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
章节来源
- [server/src/app.ts:120-127](file://server/src/app.ts#L120-L127)
- [server/src/middleware/auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
## 性能考量
- 查询优化
- 历史列表:按 createdAt 倒序分页,使用 where 条件过滤;并行查询列表与总数
- 播放历史:唯一索引(userId, chapterId)支持快速 upsert 与查询
- 搜索历史:对 userId、keyword 建立索引,distinct 关键词减少重复
- 索引设计
- AudioRecord:userId、audioId、bookId
- PlayRecord:userId、chapterId(唯一)
- SearchHistory:userId、keyword、createdAt
- 批量操作
- 批量删除使用 deleteMany,避免循环逐条删除
- 前端分页
- 前端按需加载,避免一次性拉取大量历史数据
章节来源
- [server/src/modules/history/history.controller.ts:23-31](file://server/src/modules/history/history.controller.ts#L23-L31)
- [server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
- [server/prisma/schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77)
- [server/prisma/schema.prisma:220-228](file://server/prisma/schema.prisma#L220-L228)
## 故障排查指南
- 认证相关
- optionalAuth 在未携带有效 Token 时会使用测试用户兜底;若出现数据归属异常,检查前端是否正确传递 Authorization
- 历史列表为空
- 确认 startDate 是否导致过滤范围过小;检查分页参数 page/pageSize
- 批量删除失败
- 确认 ids 数组格式与长度;查看控制器错误处理返回
- 播放历史异常
- 检查 userId 类型转换;确认唯一索引是否存在重复冲突
- 搜索历史未去重
- 确认服务层是否先删除同用户同关键词旧记录再插入新记录
章节来源
- [server/src/middleware/auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80)
- [server/src/modules/history/history.controller.ts:14-21](file://server/src/modules/history/history.controller.ts#L14-L21)
- [server/src/modules/history/history-batch.controller.ts:17-24](file://server/src/modules/history/history-batch.controller.ts#L17-L24)
- [server/src/modules/player/player.service.ts:46-81](file://server/src/modules/player/player.service.ts#L46-L81)
- [server/src/modules/search/search.service.ts:77-101](file://server/src/modules/search/search.service.ts#L77-L101)
## 结论
历史记录系统通过清晰的模块划分与合理的数据模型设计,实现了播放历史、搜索历史与批量操作的完整闭环。配合 optionalAuth 的可选认证与前端的友好交互,既满足开发调试需求,也保障了生产可用性。后续可在热点数据缓存、冷数据归档与更细粒度的隐私控制上进一步优化。
## 附录
### 历史记录API接口文档
- 获取历史列表
- 方法:GET
- 路径:/api/history
- 认证:可选
- 查询参数:
- page:页码(默认 1)
- pageSize:每页条数(默认 20)
- startDate:起始时间(ISO8601,用于 createdAt >= ...)
- 响应:分页列表与总数、页码信息
- 示例路径:[server/src/modules/history/history.controller.ts:11-64](file://server/src/modules/history/history.controller.ts#L11-L64)
- 批量删除历史
- 方法:POST
- 路径:/api/history/batch-delete
- 认证:可选
- 请求体:
- ids:字符串数组(音频 ID 列表)
- 响应:删除数量
- 示例路径:[server/src/modules/history/history-batch.controller.ts:11-49](file://server/src/modules/history/history-batch.controller.ts#L11-L49)
- 兼容删除(保留 DELETE)
- 方法:DELETE
- 路径:/api/history/batch
- 认证:可选
- 请求体或查询参数:
- ids:字符串数组(音频 ID 列表)
- 响应:删除数量
- 示例路径:[server/src/modules/history/history-batch.controller.ts:52-102](file://server/src/modules/history/history-batch.controller.ts#L52-L102)
- 播放历史相关接口
- 获取播放进度列表:GET /api/player/progress?audioId=...
- 保存播放进度:POST /api/player/progress
- 更新播放进度:PUT /api/player/progress/:audioId
- 删除播放记录:DELETE /api/player/progress/:audioId
- 批量删除播放记录:DELETE /api/player/progress/batch
- 最近播放列表:GET /api/player/recent
- 示例路径:
- [server/src/modules/player/player.controller.ts:13-132](file://server/src/modules/player/player.controller.ts#L13-L132)
- [server/src/modules/player/player.controller.ts:90-107](file://server/src/modules/player/player.controller.ts#L90-L107)
- 搜索历史相关接口
- 获取搜索历史:GET /api/search/history?userId=&limit=
- 保存搜索历史:POST /api/search/history
- 删除单条历史:DELETE /api/search/history?userId=&keyword=
- 清空历史:DELETE /api/search/history/all?userId=
- 示例路径:
- [server/src/modules/search/search.controller.ts:69-169](file://server/src/modules/search/search.controller.ts#L69-L169)
### 数据模型与索引
- AudioRecord
- 关键字段:userId、audioId(唯一)、title、text、wordCount、voiceId、voiceParams、audioUrl、audioDuration、audioSize、status、errorMsg、createdAt、updatedAt、bookId
- 索引:userId、audioId、bookId
- 示例路径:[server/prisma/schema.prisma:352-373](file://server/prisma/schema.prisma#L352-L373)
- PlayRecord
- 关键字段:userId、chapterId、progress、duration、createdAt、updatedAt
- 索引:userId、chapterId(唯一)
- 示例路径:[server/prisma/schema.prisma:63-77](file://server/prisma/schema.prisma#L63-L77)
- SearchHistory
- 关键字段:userId、keyword、createdAt
- 索引:userId、userId+createdAt
- 示例路径:[server/prisma/schema.prisma:220-228](file://server/prisma/schema.prisma#L220-L228)
- HotSearch
- 关键字段:keyword、count、sort、createdAt、updatedAt
- 索引:sort、count
- 示例路径:[server/prisma/schema.prisma:230-240](file://server/prisma/schema.prisma#L230-L240)
### 用户体验与个性化
- 历史页面支持按时间段筛选与关键词搜索,提升内容发现效率
- 播放历史支持最近播放列表,便于继续播放
- 搜索历史去重与热门词统计,辅助个性化推荐与搜索引导
章节来源
- [my-uniapp-vue3/src/pages/history/index.vue:168-360](file://my-uniapp-vue3/src/pages/history/index.vue#L168-L360)
- [server/src/modules/player/player.controller.ts:111-132](file://server/src/modules/player/player.controller.ts#L111-L132)
- [server/src/modules/search/search.service.ts:57-119](file://server/src/modules/search/search.service.ts#L57-L119)
### 隐私保护与合规性
- 可选认证:optionalAuth 在未登录时使用测试用户,避免真实用户数据泄露
- 历史清理:搜索历史限制最大条数并定期清理,降低数据留存风险
- 建议补充:
- 明确历史数据的保留期限与删除策略
- 对敏感字段(如 text)进行脱敏或最小化采集
- 提供用户自助导出/删除历史的功能入口
章节来源
- [server/src/middleware/auth.ts:51-80](file://server/src/middleware/auth.ts#L51-L80)
- [server/src/modules/search/search.service.ts:90-101](file://server/src/modules/search/search.service.ts#L90-L101)