用户会员信息.md 18 KB

用户会员信息

本文引用的文件

  • server/src/modules/member/member.service.ts
  • server/src/modules/member/member.controller.ts
  • server/src/modules/subscription/subscription.service.ts
  • server/src/modules/subscription/subscription.controller.ts
  • server/src/middleware/usageLimit.ts
  • server/src/types/index.ts
  • server/prisma/schema.prisma
  • 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定义。

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
  • server/src/modules/member/member.service.ts:1-183
  • server/src/modules/subscription/subscription.controller.ts:1-191
  • server/src/modules/subscription/subscription.service.ts:1-938
  • server/src/middleware/usageLimit.ts:1-66
  • server/src/types/index.ts:1-124
  • server/prisma/schema.prisma:10-38

章节来源

  • server/src/modules/member/member.controller.ts:1-90
  • server/src/modules/member/member.service.ts:1-183
  • server/src/modules/subscription/subscription.controller.ts:1-191
  • server/src/modules/subscription/subscription.service.ts:1-938
  • server/src/middleware/usageLimit.ts:1-66
  • server/src/types/index.ts:1-124
  • server/prisma/schema.prisma:10-38

核心组件

  • 会员服务(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
  • server/src/modules/subscription/subscription.service.ts:1-938
  • server/src/middleware/usageLimit.ts:1-66
  • server/src/types/index.ts:1-124
  • server/prisma/schema.prisma:10-38

架构概览

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

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
  • server/src/modules/member/member.service.ts:39-73
  • server/src/modules/subscription/subscription.controller.ts:160-170
  • server/src/modules/subscription/subscription.service.ts:602-649
  • server/prisma/schema.prisma:10-38

详细组件分析

会员状态查询与等级制度

  • 字段定义
    • memberLevel:0=免费版,1=月度会员,2=年度会员
    • memberExpireAt:会员有效期截止时间
    • dailyUsage:当日已使用次数
    • lastUsageDate:上次使用日期(YYYY-MM-DD)
  • 等级权益
    • 免费版:每日3次、每条最多5000字、基础音色
    • 月度会员:每日20次、每条最多50000字、全部音色、优先处理
    • 年度会员:无限次、无字数限制、全部音色、优先处理、专属客服
  • 状态判定

    • 有效条件:memberLevel > 0 且 memberExpireAt 存在且当前时间早于过期时间
    • 日常重置:若 lastUsageDate 不等于今天,则 dailyUsage 清零

      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
  • server/src/types/index.ts:115-124

章节来源

  • server/src/modules/member/member.service.ts:11-73
  • server/src/types/index.ts:115-124

使用量统计机制与每日重置

  • 每日使用次数限制
    • 中间件在请求进入业务逻辑前,检查并重置 dailyUsage
    • 若超过配额则抛出配额超限错误
  • 字数限制
    • 对单次生成的文本字数进行校验,防止超出等级限制
  • 重置策略

    • 以 lastUsageDate 与当前日期比较决定是否重置 dailyUsage

      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
  • server/src/types/index.ts:115-124

章节来源

  • server/src/middleware/usageLimit.ts:1-66
  • server/src/types/index.ts:115-124

订阅周期计算与音频时长配额

  • 字段定义
    • usedAudioMinutes:当月累计使用的音频时长(分钟)
    • subscriptionResetDate:订阅重置日期(用于判断是否需要重置配额)
  • 配额与计费
    • 各等级每月音频时长配额不同
    • 免费版不支持超出配额;其他等级支持超出,按零售价计费
    • 每月1日重置配额:若当前日期与上次重置日期不在同一个月,则重置 usedAudioMinutes 并更新 subscriptionResetDate
  • 算法流程

    • 计算文本长度对应的音频时长(按语速换算)
    • 计算剩余配额与超额分钟数
    • 计算配额内价格与超额价格,得出总费用

      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

章节来源

  • server/src/modules/subscription/subscription.service.ts:519-683

等级升级与到期检测

  • 等级升级
    • 通过创建订单并模拟支付成功,根据产品类型(月/年)更新 memberLevel 与 memberExpireAt
    • 若当前已是会员且未过期,则从到期日延续;否则从当前时间开始
  • 到期检测

    • 会员状态的有效性由 memberLevel > 0 且 memberExpireAt 存在且当前时间早于过期时间决定

      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
  • server/src/modules/member/member.service.ts:75-155

章节来源

  • server/src/modules/member/member.controller.ts:1-90
  • server/src/modules/member/member.service.ts:75-155

使用量统计与扣费流程

  • 预估与检查
    • 通过 getAudioEstimate 获取生成预估,包含配额内/超额分钟数与费用
    • 通过 checkAudioQuota 检查当前额度是否足够
  • 扣费与记录

    • 通过 consumeAudioMinutes 扣除音频时长并记录使用日志

      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
  • server/src/modules/subscription/subscription.service.ts:651-683
  • server/src/modules/subscription/subscription.service.ts:685-724

章节来源

  • server/src/modules/subscription/subscription.service.ts:551-724

依赖关系分析

  • 服务层依赖
    • 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 分别调用对应服务方法

      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
  • server/src/modules/member/member.service.ts:1-183
  • server/src/modules/subscription/subscription.service.ts:1-938
  • server/src/middleware/usageLimit.ts:1-66
  • server/prisma/schema.prisma:10-38

章节来源

  • server/src/types/index.ts:1-124
  • server/src/modules/member/member.service.ts:1-183
  • server/src/modules/subscription/subscription.service.ts:1-938
  • server/src/middleware/usageLimit.ts:1-66
  • server/prisma/schema.prisma:10-38

性能考量

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

故障排查指南

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

章节来源

  • server/src/modules/member/member.service.ts:103-155
  • server/src/modules/subscription/subscription.service.ts:602-649
  • server/src/middleware/usageLimit.ts:26-49

结论

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