# 用户会员信息 **本文引用的文件** - [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 等字段,结合服务层的权益配置、使用限制中间件与订阅计费算法,实现了清晰的会员等级制度与使用量统计机制。开发者可基于现有接口与算法快速扩展新功能,如更细粒度的权限控制、多语言音色支持、阶梯定价策略等。