# 用户会员信息
**本文引用的文件**
- [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)
## 目录
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
会员接口路由"]
SVC_MEMBER["member.service.ts
会员状态/订单/支付模拟"]
CTRL_SUB["subscription.controller.ts
订阅接口路由"]
SVC_SUB["subscription.service.ts
订阅/配额/计费/用量"]
MW_USAGE["usageLimit.ts
每日使用次数限制中间件"]
TYPES["types/index.ts
类型与配额常量"]
PRISMA["prisma/schema.prisma
数据库模型"]
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 等字段,结合服务层的权益配置、使用限制中间件与订阅计费算法,实现了清晰的会员等级制度与使用量统计机制。开发者可基于现有接口与算法快速扩展新功能,如更细粒度的权限控制、多语言音色支持、阶梯定价策略等。