# 用户偏好设置

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

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

## 简介
本文件面向AI有声书生成平台的用户偏好设置模型，围绕UserPreference模型的配置项进行深入解析，包括播放速度、音质、主题、默认音色ID、默认音量、自动播放下一首、仅WiFi下载等个性化设置字段。文档详细说明每个配置项的作用机制、取值范围与业务逻辑，并解释网络相关设置对用户体验的影响。同时提供偏好设置的CRUD操作示例，涵盖用户首次登录时的默认配置初始化、偏好修改更新、设置同步等实现方法。

## 项目结构
用户偏好设置涉及前后端协作：
- 前端（UniApp/Vue3）负责界面展示与交互，调用后端接口并本地持久化。
- 后端（Koa/Prisma）提供REST接口，访问MySQL数据库中的UserPreference表。
- 路由注册将“/api/user/preferences”挂载至偏好设置控制器。

```mermaid
graph TB
subgraph "前端UniApp/Vue3"
FE_Settings["设置页面<br/>index.vue"]
FE_Store["本地存储<br/>storage.ts"]
end
subgraph "后端Koa"
BE_Router["路由注册<br/>app.ts"]
BE_Controller["控制器<br/>preferences.controller.ts"]
BE_Service["服务层<br/>preferences.service.ts"]
end
subgraph "数据库Prisma/MySQL"
DB_Model["UserPreference 模型<br/>schema.prisma"]
end
FE_Settings --> |HTTP 请求| BE_Router
BE_Router --> BE_Controller
BE_Controller --> BE_Service
BE_Service --> DB_Model
FE_Settings --> |本地缓存| FE_Store
```

图表来源
- [app.ts:106](file://server/src/app.ts#L106)
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [preferences.service.ts:8-28](file://server/src/modules/preferences/preferences.service.ts#L8-L28)
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)
- [storage.ts:1-63](file://my-uniapp-vue3/src/utils/storage.ts#L1-L63)

章节来源
- [app.ts:106](file://server/src/app.ts#L106)
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [preferences.service.ts:8-28](file://server/src/modules/preferences/preferences.service.ts#L8-L28)
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)
- [storage.ts:1-63](file://my-uniapp-vue3/src/utils/storage.ts#L1-L63)

## 核心组件
- UserPreference 数据模型：定义用户偏好的字段、默认值与约束。
- 偏好设置控制器：提供获取与更新用户偏好的接口。
- 偏好设置服务层：封装数据库访问逻辑，包含upsert语义的默认初始化与条件更新。
- 前端设置页面：提供UI交互、本地缓存与后端同步。

章节来源
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [preferences.service.ts:8-73](file://server/src/modules/preferences/preferences.service.ts#L8-L73)
- [index.vue:190-208](file://my-uniapp-vue3/src/pages/settings/index.vue#L190-L208)

## 架构总览
用户偏好设置采用“前端界面 + 后端接口 + 数据库模型”的分层设计。前端通过HTTP请求与后端交互，后端通过Prisma ORM访问MySQL；同时前端本地存储用于提升初次加载体验与离线可用性。

```mermaid
sequenceDiagram
participant U as "用户"
participant FE as "前端设置页面<br/>index.vue"
participant API as "后端接口<br/>preferences.controller.ts"
participant SVC as "服务层<br/>preferences.service.ts"
participant DB as "数据库<br/>UserPreference"
U->>FE : 打开设置页面
FE->>FE : 读取本地缓存<br/>uni.getStorageSync('userPreferences')
FE->>API : GET /api/user/preferences
API->>SVC : getPreferences(userId)
SVC->>DB : upsert 默认值
DB-->>SVC : 返回偏好记录
SVC-->>API : 返回偏好数据
API-->>FE : 响应数据
FE->>FE : 合并本地与远端偏好
FE->>FE : 保存到本地缓存
U->>FE : 修改偏好如默认音量
FE->>API : PUT /api/user/preferences
API->>SVC : updatePreferences(userId, data)
SVC->>DB : upsert 条件更新
DB-->>SVC : 返回更新后的记录
SVC-->>API : 返回更新结果
API-->>FE : 响应更新结果
FE->>FE : 同步本地缓存
```

图表来源
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [preferences.service.ts:8-73](file://server/src/modules/preferences/preferences.service.ts#L8-L73)
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)

## 详细组件分析

### UserPreference 数据模型与字段说明
UserPreference模型定义了用户偏好的字段、默认值与约束，确保每个用户拥有独立且完整的偏好记录。

```mermaid
erDiagram
USER ||--o| USER_PREFERENCE : "拥有"
USER_PREFERENCE {
int id PK
int userId UK
float playSpeed
string quality
string theme
string defaultVoiceId
int defaultVolume
boolean autoPlayNext
boolean wifiOnlyDownload
datetime createdAt
datetime updatedAt
}
```

图表来源
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [schema.prisma:34](file://server/prisma/schema.prisma#L34)

字段作用与默认值
- playSpeed：播放速度，默认1.0（1倍速），用于控制TTS播放速率。
- quality：音质模式，默认"standard"（标准），影响音频生成质量与体积。
- theme：主题，默认"light"（浅色），影响界面外观。
- defaultVoiceId：默认音色ID，默认"cherry"，用于生成音频时的默认音色。
- defaultVolume：默认音量，默认50，范围通常为0-100。
- autoPlayNext：自动播放下一首，默认true，提升连续收听体验。
- wifiOnlyDownload：仅WiFi下载，默认false，节省流量并避免产生额外费用。

章节来源
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [preferences.service.ts:17-23](file://server/src/modules/preferences/preferences.service.ts#L17-L23)
- [index.vue:200-208](file://my-uniapp-vue3/src/pages/settings/index.vue#L200-L208)

### 偏好设置控制器与路由
- GET /api/user/preferences：获取当前用户的偏好设置。
- PUT /api/user/preferences：更新部分或全部偏好设置。
- 控制器在开发环境使用测试用户ID，生产环境从上下文提取真实用户ID。

章节来源
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [app.ts:106](file://server/src/app.ts#L106)

### 偏好设置服务层（CRUD与默认初始化）
- getPreferences(userId)：使用upsert语义，若不存在则按默认值创建，存在则返回现有记录。
- updatePreferences(userId, data)：若已有记录则更新，否则按传入数据（缺失字段使用默认值）创建。

```mermaid
flowchart TD
Start(["进入 getPreferences"]) --> Upsert["upsert 用户偏好<br/>不存在则使用默认值创建"]
Upsert --> ReturnPref["返回偏好记录"]
ReturnPref --> End(["结束"])
UpdateStart(["进入 updatePreferences"]) --> FindExisting["查询是否存在记录"]
FindExisting --> Exists{"存在？"}
Exists --> |是| Update["更新记录"]
Exists --> |否| Create["按传入数据创建<br/>缺失字段使用默认值"]
Update --> UpdateEnd(["返回更新结果"])
Create --> UpdateEnd
```

图表来源
- [preferences.service.ts:8-28](file://server/src/modules/preferences/preferences.service.ts#L8-L28)
- [preferences.service.ts:33-73](file://server/src/modules/preferences/preferences.service.ts#L33-L73)

章节来源
- [preferences.service.ts:8-28](file://server/src/modules/preferences/preferences.service.ts#L8-L28)
- [preferences.service.ts:33-73](file://server/src/modules/preferences/preferences.service.ts#L33-L73)

### 前端设置页面与本地缓存
- 初始化：优先从本地缓存加载，再从后端拉取最新偏好，最后合并并写回本地缓存。
- 交互：支持修改默认音色、默认音量、自动播放下一首、仅WiFi下载等。
- 同步：每次修改后调用PUT接口更新后端，并同步本地缓存。

```mermaid
sequenceDiagram
participant Page as "设置页面<br/>index.vue"
participant Local as "本地缓存<br/>uni.getStorageSync"
participant API as "后端接口<br/>preferences.controller.ts"
Page->>Local : 读取本地偏好
Page->>API : GET /api/user/preferences
API-->>Page : 返回偏好数据
Page->>Page : 合并本地与远端偏好
Page->>Local : 写入合并后的偏好
Page->>API : PUT /api/user/preferences修改后
API-->>Page : 返回更新结果
Page->>Local : 同步本地缓存
```

图表来源
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)

章节来源
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)
- [storage.ts:1-63](file://my-uniapp-vue3/src/utils/storage.ts#L1-L63)

### 网络相关设置：仅WiFi下载（wifiOnlyDownload）
- 作用：当开启后，应用在非WiFi环境下阻止自动下载音频，避免产生移动流量费用。
- 业务逻辑：前端在触发下载前检查该开关，后端不直接参与此判断，但可通过接口返回当前偏好供前端决策。
- 用户体验：减少意外流量消耗，提升用户对网络使用的可控性。

章节来源
- [index.vue:266-270](file://my-uniapp-vue3/src/pages/settings/index.vue#L266-L270)
- [schema.prisma:87-88](file://server/prisma/schema.prisma#L87-L88)

### 音色与音量设置
- defaultVoiceId：默认音色ID，前端提供音色选择器，后端存储对应字符串标识。
- defaultVolume：默认音量，前端滑条范围0-100，后端存储整数值。
- 业务逻辑：生成音频时优先使用用户偏好中的音色与音量，允许用户随时调整。

章节来源
- [index.vue:175-187](file://my-uniapp-vue3/src/pages/settings/index.vue#L175-L187)
- [index.vue:254-258](file://my-uniapp-vue3/src/pages/settings/index.vue#L254-L258)
- [schema.prisma:85-86](file://server/prisma/schema.prisma#L85-L86)
- [schema.prisma:86-87](file://server/prisma/schema.prisma#L86-L87)

### 主题设置（theme）
- 支持"light"（浅色）、"dark"（深色）、"auto"（跟随系统）三种模式。
- 前端本地存储主题键值，应用主题变更；与UserPreference中的theme字段配合使用。

章节来源
- [index.vue:167-172](file://my-uniapp-vue3/src/pages/settings/index.vue#L167-L172)
- [schema.prisma:84-85](file://server/prisma/schema.prisma#L84-L85)

### 自动播放下一首（autoPlayNext）
- 当开启时，播放完当前音频后自动播放下一首，提升连续收听体验。
- 与播放器逻辑配合，后端仅存储该偏好值。

章节来源
- [index.vue:260-264](file://my-uniapp-vue3/src/pages/settings/index.vue#L260-L264)
- [schema.prisma:87-88](file://server/prisma/schema.prisma#L87-L88)

## 依赖关系分析
- 控制器依赖服务层，服务层依赖Prisma客户端访问数据库。
- 前端设置页面依赖HTTP请求工具与本地存储工具。
- 路由在应用启动时注册，将"/api/user/preferences"映射到控制器。

```mermaid
graph LR
FE_Index["设置页面<br/>index.vue"] --> FE_Request["HTTP 请求工具"]
FE_Index --> FE_Store["本地存储<br/>storage.ts"]
FE_Request --> BE_Controller["控制器<br/>preferences.controller.ts"]
BE_Controller --> BE_Service["服务层<br/>preferences.service.ts"]
BE_Service --> DB["UserPreference 模型<br/>schema.prisma"]
APP["应用入口<br/>app.ts"] --> BE_Controller
```

图表来源
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)
- [storage.ts:1-63](file://my-uniapp-vue3/src/utils/storage.ts#L1-L63)
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [preferences.service.ts:8-28](file://server/src/modules/preferences/preferences.service.ts#L8-L28)
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [app.ts:106](file://server/src/app.ts#L106)

章节来源
- [app.ts:106](file://server/src/app.ts#L106)
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [preferences.service.ts:8-28](file://server/src/modules/preferences/preferences.service.ts#L8-L28)
- [schema.prisma:79-92](file://server/prisma/schema.prisma#L79-L92)
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)
- [storage.ts:1-63](file://my-uniapp-vue3/src/utils/storage.ts#L1-L63)

## 性能考虑
- 本地缓存优先策略：首次渲染直接使用本地缓存，减少等待时间，随后异步拉取后端数据进行合并。
- upsert语义：避免重复创建，降低数据库写入压力，提高初始化效率。
- 滑条与开关交互：前端即时反馈，减少不必要的网络请求，仅在必要时调用PUT接口。

## 故障排除指南
- 无法获取或保存偏好
  - 检查后端路由是否正确注册至"/api/user/preferences"。
  - 确认用户上下文是否正确传递（开发环境使用测试用户ID）。
  - 查看数据库连接与Prisma迁移状态。
- 本地缓存不同步
  - 确认前端在成功响应后执行了本地缓存写入。
  - 检查跨端存储差异（H5与小程序）。
- 默认值异常
  - 检查服务层upsert默认值逻辑与数据库模型默认值是否一致。

章节来源
- [app.ts:106](file://server/src/app.ts#L106)
- [preferences.controller.ts:12-47](file://server/src/modules/preferences/preferences.controller.ts#L12-L47)
- [preferences.service.ts:8-28](file://server/src/modules/preferences/preferences.service.ts#L8-L28)
- [index.vue:272-309](file://my-uniapp-vue3/src/pages/settings/index.vue#L272-L309)

## 结论
UserPreference模型为AI有声书平台提供了完善的个性化能力，覆盖播放、外观、下载与存储等多个维度。通过前后端协同与本地缓存策略，既保证了用户体验的流畅性，又确保了数据的一致性与可靠性。后续可在保持现有默认值与upsert语义的基础上，进一步扩展更多偏好项并完善边界校验与错误处理。