# 用户会员信息

<cite>
**本文引用的文件**
- [server/src/modules/member/member.service.ts](file://server/src/modules/member/member.service.ts)
- [server/src/modules/member/member.controller.ts](file://server/src/modules/member/member.controller.ts)
- [server/src/modules/subscription/subscription.service.ts](file://server/src/modules/subscription/subscription.service.ts)
- [server/src/modules/subscription/subscription.controller.ts](file://server/src/modules/subscription/subscription.controller.ts)
- [server/src/middleware/usageLimit.ts](file://server/src/middleware/usageLimit.ts)
- [server/src/types/index.ts](file://server/src/types/index.ts)
- [server/prisma/schema.prisma](file://server/prisma/schema.prisma)
- [server/prisma/migrations/20260422105352_add_content_status/migration.sql](file://server/prisma/migrations/20260422105352_add_content_status/migration.sql)
</cite>

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

## 简介
本文件面向AI有声书生成平台的用户会员信息模型，系统性阐述以下关键字段与业务逻辑：
- 会员等级数值 memberLevel
- 会员过期时间 memberExpireAt
- 每日使用量 dailyUsage
- 累计音频使用分钟数 usedAudioMinutes
- 订阅重置日期 subscriptionResetDate

重点解释会员等级制度、使用量统计机制、订阅周期计算，并说明这些字段如何协同实现会员权益管理与使用限制。同时提供会员状态查询、等级升级、使用量统计等核心功能的实现路径与算法流程图，帮助开发者快速定位与扩展相关能力。

## 项目结构
会员与订阅相关的核心代码分布在服务层、控制器层、中间件与类型定义中，数据库模型由Prisma Schema定义。

```mermaid
graph TB
subgraph "前端"
UI["页面/接口调用"]
end
subgraph "后端"
CTRL_MEMBER["member.controller.ts<br/>会员接口路由"]
SVC_MEMBER["member.service.ts<br/>会员状态/订单/支付模拟"]
CTRL_SUB["subscription.controller.ts<br/>订阅接口路由"]
SVC_SUB["subscription.service.ts<br/>订阅/配额/计费/用量"]
MW_USAGE["usageLimit.ts<br/>每日使用次数限制中间件"]
TYPES["types/index.ts<br/>类型与配额常量"]
PRISMA["prisma/schema.prisma<br/>数据库模型"]
end
UI --> CTRL_MEMBER
UI --> CTRL_SUB
CTRL_MEMBER --> SVC_MEMBER
CTRL_SUB --> SVC_SUB
SVC_MEMBER --> PRISMA
SVC_SUB --> PRISMA
MW_USAGE --> PRISMA
SVC_MEMBER --> TYPES
SVC_SUB --> TYPES
```

图表来源
- [server/src/modules/member/member.controller.ts:1-90](file://server/src/modules/member/member.controller.ts#L1-L90)
- [server/src/modules/member/member.service.ts:1-183](file://server/src/modules/member/member.service.ts#L1-L183)
- [server/src/modules/subscription/subscription.controller.ts:1-191](file://server/src/modules/subscription/subscription.controller.ts#L1-L191)
- [server/src/modules/subscription/subscription.service.ts:1-938](file://server/src/modules/subscription/subscription.service.ts#L1-L938)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/prisma/schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38)

章节来源
- [server/src/modules/member/member.controller.ts:1-90](file://server/src/modules/member/member.controller.ts#L1-L90)
- [server/src/modules/member/member.service.ts:1-183](file://server/src/modules/member/member.service.ts#L1-L183)
- [server/src/modules/subscription/subscription.controller.ts:1-191](file://server/src/modules/subscription/subscription.controller.ts#L1-L191)
- [server/src/modules/subscription/subscription.service.ts:1-938](file://server/src/modules/subscription/subscription.service.ts#L1-L938)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/prisma/schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38)

## 核心组件
- 会员服务（member.service.ts）
  - 提供会员权益查询、会员状态查询、订单创建、模拟支付成功、订单列表查询等功能。
  - 关键字段：memberLevel、memberExpireAt、dailyUsage、lastUsageDate。
- 订阅服务（subscription.service.ts）
  - 提供订阅套餐、Token余额、音频时长余额、配额检查、计费估算、用量扣除等能力。
  - 关键字段：usedAudioMinutes、subscriptionResetDate。
- 使用限制中间件（usageLimit.ts）
  - 在请求进入业务逻辑前，校验每日使用次数与字数限制，并自动重置dailyUsage。
- 类型与配额（types/index.ts）
  - 定义会员等级枚举、配额常量、用户接口类型等。
- 数据库模型（prisma/schema.prisma）
  - 定义User、Order、Subscription、TokenBalance、TokenUsage等表及字段。

章节来源
- [server/src/modules/member/member.service.ts:1-183](file://server/src/modules/member/member.service.ts#L1-L183)
- [server/src/modules/subscription/subscription.service.ts:1-938](file://server/src/modules/subscription/subscription.service.ts#L1-L938)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/prisma/schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38)

## 架构概览
会员与订阅模块通过控制器暴露REST接口，服务层封装业务规则，中间件在入口处进行使用限制校验，Prisma负责数据持久化。

```mermaid
sequenceDiagram
participant Client as "客户端"
participant CtrlMember as "会员控制器"
participant SvcMember as "会员服务"
participant CtrlSub as "订阅控制器"
participant SvcSub as "订阅服务"
participant DB as "数据库(Prisma)"
Client->>CtrlMember : GET /member/status
CtrlMember->>SvcMember : getMemberStatus(userId)
SvcMember->>DB : 查询User(含memberLevel/dailyUsage/lastUsageDate)
DB-->>SvcMember : 返回用户数据
SvcMember-->>CtrlMember : 返回会员状态
CtrlMember-->>Client : 状态响应
Client->>CtrlSub : GET /subscription/audio-balance
CtrlSub->>SvcSub : getUserAudioBalance(userId)
SvcSub->>DB : 查询User(含usedAudioMinutes/subscriptionResetDate)
DB-->>SvcSub : 返回用户数据
SvcSub-->>CtrlSub : 返回音频余额
CtrlSub-->>Client : 余额响应
```

图表来源
- [server/src/modules/member/member.controller.ts:20-30](file://server/src/modules/member/member.controller.ts#L20-L30)
- [server/src/modules/member/member.service.ts:39-73](file://server/src/modules/member/member.service.ts#L39-L73)
- [server/src/modules/subscription/subscription.controller.ts:160-170](file://server/src/modules/subscription/subscription.controller.ts#L160-L170)
- [server/src/modules/subscription/subscription.service.ts:602-649](file://server/src/modules/subscription/subscription.service.ts#L602-L649)
- [server/prisma/schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38)

## 详细组件分析

### 会员状态查询与等级制度
- 字段定义
  - memberLevel：0=免费版，1=月度会员，2=年度会员
  - memberExpireAt：会员有效期截止时间
  - dailyUsage：当日已使用次数
  - lastUsageDate：上次使用日期（YYYY-MM-DD）
- 等级权益
  - 免费版：每日3次、每条最多5000字、基础音色
  - 月度会员：每日20次、每条最多50000字、全部音色、优先处理
  - 年度会员：无限次、无字数限制、全部音色、优先处理、专属客服
- 状态判定
  - 有效条件：memberLevel > 0 且 memberExpireAt 存在且当前时间早于过期时间
  - 日常重置：若 lastUsageDate 不等于今天，则 dailyUsage 清零

```mermaid
flowchart TD
Start(["进入 getMemberStatus"]) --> LoadUser["查询用户信息"]
LoadUser --> Today["获取今日日期(YYYY-MM-DD)"]
Today --> CheckReset{"lastUsageDate == 今日?"}
CheckReset -- 否 --> ResetDaily["dailyUsage = 0"]
CheckReset -- 是 --> KeepDaily["保持 dailyUsage"]
ResetDaily --> CalcQuota["根据 memberLevel 计算配额"]
KeepDaily --> CalcQuota
CalcQuota --> Valid{"memberLevel>0 且 memberExpireAt>now?"}
Valid -- 是 --> Ok["返回有效状态"]
Valid -- 否 --> Expired["返回无效状态"]
Ok --> End(["结束"])
Expired --> End
```

图表来源
- [server/src/modules/member/member.service.ts:39-73](file://server/src/modules/member/member.service.ts#L39-L73)
- [server/src/types/index.ts:115-124](file://server/src/types/index.ts#L115-L124)

章节来源
- [server/src/modules/member/member.service.ts:11-73](file://server/src/modules/member/member.service.ts#L11-L73)
- [server/src/types/index.ts:115-124](file://server/src/types/index.ts#L115-L124)

### 使用量统计机制与每日重置
- 每日使用次数限制
  - 中间件在请求进入业务逻辑前，检查并重置 dailyUsage
  - 若超过配额则抛出配额超限错误
- 字数限制
  - 对单次生成的文本字数进行校验，防止超出等级限制
- 重置策略
  - 以 lastUsageDate 与当前日期比较决定是否重置 dailyUsage

```mermaid
flowchart TD
Enter(["进入 usageLimitMiddleware"]) --> HasUserId{"存在userId?"}
HasUserId -- 否 --> Allow["设置无限制配额并放行"]
HasUserId -- 是 --> LoadUser["查询用户"]
LoadUser --> Today["获取今日日期"]
Today --> CheckLast{"lastUsageDate != 今日?"}
CheckLast -- 是 --> Update["更新 dailyUsage=0, lastUsageDate=今日"]
CheckLast -- 否 --> Skip["跳过重置"]
Update --> CheckQuota{"dailyUsage >= dailyLimit?"}
Skip --> CheckQuota
CheckQuota -- 是 --> Over["抛出配额超限错误"]
CheckQuota -- 否 --> Pass["放行到下一个中间件/处理器"]
```

图表来源
- [server/src/middleware/usageLimit.ts:7-49](file://server/src/middleware/usageLimit.ts#L7-L49)
- [server/src/types/index.ts:115-124](file://server/src/types/index.ts#L115-L124)

章节来源
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/src/types/index.ts:115-124](file://server/src/types/index.ts#L115-L124)

### 订阅周期计算与音频时长配额
- 字段定义
  - usedAudioMinutes：当月累计使用的音频时长（分钟）
  - subscriptionResetDate：订阅重置日期（用于判断是否需要重置配额）
- 配额与计费
  - 各等级每月音频时长配额不同
  - 免费版不支持超出配额；其他等级支持超出，按零售价计费
  - 每月1日重置配额：若当前日期与上次重置日期不在同一个月，则重置 usedAudioMinutes 并更新 subscriptionResetDate
- 算法流程
  - 计算文本长度对应的音频时长（按语速换算）
  - 计算剩余配额与超额分钟数
  - 计算配额内价格与超额价格，得出总费用

```mermaid
flowchart TD
Start(["进入 getUserAudioBalance"]) --> LoadUser["查询用户"]
LoadUser --> GetLevel["获取 memberLevel 与月度配额"]
GetLevel --> CheckReset{"subscriptionResetDate 是否存在?"}
CheckReset -- 否 --> InitReset["初始化重置日期为当前时间"]
CheckReset -- 是 --> CompareMonth{"当前月份是否变化?"}
CompareMonth -- 是 --> Reset["usedAudioMinutes=0, 更新subscriptionResetDate"]
CompareMonth -- 否 --> Keep["保持原值"]
InitReset --> Compute["返回余额信息"]
Reset --> Compute
Keep --> Compute
Compute --> End(["结束"])
```

图表来源
- [server/src/modules/subscription/subscription.service.ts:602-649](file://server/src/modules/subscription/subscription.service.ts#L602-L649)

章节来源
- [server/src/modules/subscription/subscription.service.ts:519-683](file://server/src/modules/subscription/subscription.service.ts#L519-L683)

### 等级升级与到期检测
- 等级升级
  - 通过创建订单并模拟支付成功，根据产品类型（月/年）更新 memberLevel 与 memberExpireAt
  - 若当前已是会员且未过期，则从到期日延续；否则从当前时间开始
- 到期检测
  - 会员状态的有效性由 memberLevel > 0 且 memberExpireAt 存在且当前时间早于过期时间决定

```mermaid
sequenceDiagram
participant Client as "客户端"
participant Ctrl as "会员控制器"
participant Svc as "会员服务"
participant DB as "数据库(Prisma)"
Client->>Ctrl : POST /member/order {productType}
Ctrl->>Svc : createOrder(userId, productType)
Svc->>DB : 创建订单
DB-->>Svc : 返回订单
Svc-->>Ctrl : 返回订单号与金额
Ctrl-->>Client : 订单创建成功
Client->>Ctrl : POST /member/pay/mock {orderNo}
Ctrl->>Svc : mockPaymentSuccess(orderNo, userId)
Svc->>DB : 查询订单与用户
Svc->>Svc : 计算到期时间(延续或从现在开始)
Svc->>DB : 更新用户memberLevel与memberExpireAt
DB-->>Svc : 更新成功
Svc-->>Ctrl : 返回升级结果
Ctrl-->>Client : 支付成功
```

图表来源
- [server/src/modules/member/member.controller.ts:32-70](file://server/src/modules/member/member.controller.ts#L32-L70)
- [server/src/modules/member/member.service.ts:75-155](file://server/src/modules/member/member.service.ts#L75-L155)

章节来源
- [server/src/modules/member/member.controller.ts:1-90](file://server/src/modules/member/member.controller.ts#L1-L90)
- [server/src/modules/member/member.service.ts:75-155](file://server/src/modules/member/member.service.ts#L75-L155)

### 使用量统计与扣费流程
- 预估与检查
  - 通过 getAudioEstimate 获取生成预估，包含配额内/超额分钟数与费用
  - 通过 checkAudioQuota 检查当前额度是否足够
- 扣费与记录
  - 通过 consumeAudioMinutes 扣除音频时长并记录使用日志

```mermaid
flowchart TD
Start(["生成音频前"]) --> Estimate["getAudioEstimate(userId, textLength)"]
Estimate --> Check["checkAudioQuota(userId, textLength)"]
Check --> Allowed{"allowed?"}
Allowed -- 否 --> Deny["拒绝生成并提示原因"]
Allowed -- 是 --> Consume["consumeAudioMinutes(userId, textLength)"]
Consume --> Update["更新 usedAudioMinutes 并写入TokenUsage"]
Update --> Done(["完成"])
Deny --> Done
```

图表来源
- [server/src/modules/subscription/subscription.service.ts:726-766](file://server/src/modules/subscription/subscription.service.ts#L726-L766)
- [server/src/modules/subscription/subscription.service.ts:651-683](file://server/src/modules/subscription/subscription.service.ts#L651-L683)
- [server/src/modules/subscription/subscription.service.ts:685-724](file://server/src/modules/subscription/subscription.service.ts#L685-L724)

章节来源
- [server/src/modules/subscription/subscription.service.ts:551-724](file://server/src/modules/subscription/subscription.service.ts#L551-L724)

## 依赖关系分析
- 服务层依赖
  - member.service.ts 依赖 types/index.ts 的配额常量与 MemberLevel 类型
  - subscription.service.ts 依赖 types/index.ts 的 MemberLevel 类型
  - usageLimit.ts 依赖 types/index.ts 的配额常量与 MemberLevel 类型
- 数据层依赖
  - 所有服务通过 Prisma 访问 User、Order、TokenBalance、TokenUsage 等模型
- 控制器依赖
  - member.controller.ts 与 subscription.controller.ts 分别调用对应服务方法

```mermaid
graph LR
Types["types/index.ts"] --> MemberSvc["member.service.ts"]
Types --> SubSvc["subscription.service.ts"]
Types --> UsageMW["usageLimit.ts"]
MemberSvc --> Prisma["prisma/schema.prisma"]
SubSvc --> Prisma
UsageMW --> Prisma
MemberCtrl["member.controller.ts"] --> MemberSvc
SubCtrl["subscription.controller.ts"] --> SubSvc
```

图表来源
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/src/modules/member/member.service.ts:1-183](file://server/src/modules/member/member.service.ts#L1-L183)
- [server/src/modules/subscription/subscription.service.ts:1-938](file://server/src/modules/subscription/subscription.service.ts#L1-L938)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/prisma/schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38)

章节来源
- [server/src/types/index.ts:1-124](file://server/src/types/index.ts#L1-L124)
- [server/src/modules/member/member.service.ts:1-183](file://server/src/modules/member/member.service.ts#L1-L183)
- [server/src/modules/subscription/subscription.service.ts:1-938](file://server/src/modules/subscription/subscription.service.ts#L1-L938)
- [server/src/middleware/usageLimit.ts:1-66](file://server/src/middleware/usageLimit.ts#L1-L66)
- [server/prisma/schema.prisma:10-38](file://server/prisma/schema.prisma#L10-L38)

## 性能考量
- 数据访问
  - 使用Prisma查询用户信息时尽量复用已有连接与事务，避免重复查询
- 缓存策略
  - 对高频读取的会员权益与配额可考虑短期缓存，降低数据库压力
- 计算复杂度
  - 音频时长计算与配额检查均为O(1)，整体开销较小
- 重置逻辑
  - 每月重置配额仅在首次访问时触发，后续直接读取缓存或内存中的用户状态

## 故障排查指南
- 会员状态异常
  - 检查 memberExpireAt 是否为空或已过期
  - 确认 memberLevel 是否为 0 或 1/2
- 每日使用次数限制
  - 确认 lastUsageDate 是否正确更新为今日
  - 检查 dailyUsage 是否被重置为 0
- 音频时长配额不足
  - 检查 usedAudioMinutes 与 subscriptionResetDate 是否按月重置
  - 确认当前等级是否支持超出配额
- 订单与支付
  - 检查订单状态是否为 pending，支付后是否更新为 paid
  - 确认到期时间计算逻辑（延续或从现在开始）

章节来源
- [server/src/modules/member/member.service.ts:103-155](file://server/src/modules/member/member.service.ts#L103-L155)
- [server/src/modules/subscription/subscription.service.ts:602-649](file://server/src/modules/subscription/subscription.service.ts#L602-L649)
- [server/src/middleware/usageLimit.ts:26-49](file://server/src/middleware/usageLimit.ts#L26-L49)

## 结论
本会员信息模型通过 memberLevel、memberExpireAt、dailyUsage、usedAudioMinutes、subscriptionResetDate 等字段，结合服务层的权益配置、使用限制中间件与订阅计费算法，实现了清晰的会员等级制度与使用量统计机制。开发者可基于现有接口与算法快速扩展新功能，如更细粒度的权限控制、多语言音色支持、阶梯定价策略等。