# 历史记录 **本文引用的文件** - [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)