消费管理
访问控制
访问控制解决的问题是:用户付完钱了,怎么判断他有没有权限使用你的服务?
Pay4SaaS 把这套逻辑封装成了 useAccess Hook 和 useService 方法,前端直接调用即可。
首页 Hero 区(
components/landing/Hero.tsx)有完整的前端调用示例,包括权限判断、消费积分、赠送积分三种场景。
useAccess Hook
import { useAccess } from '@/hooks/useAccess'
function MyComponent() {
const { status, loading, error, refreshStatus, useService } = useAccess()
if (loading) return <div>加载中...</div>
if (!status.allowed) {
return <div>请先订阅或购买积分</div>
}
return <div>欢迎使用!</div>
}status 对象
status 包含完整的用户访问信息:
{
allowed: boolean, // 是否有权限使用
accessType: AccessType, // 权限类型
details: {
hasSubscription: boolean, // 是否有订阅
subscriptionPlan: string, // 订阅计划(basic/pro/max)
subscriptionStatus: string, // 订阅状态
subscriptionBillingCycle: string, // 计费周期(monthly/yearly)
subscriptionEndDate: string, // 到期时间
subscriptionProvider: string, // 支付方式
hasLifetime: boolean, // 是否为买断用户
lifetimePlan: string, // 买断计划
availableCredits: number, // 可用积分
quota: { // 配额信息(仅配额订阅模式)
monthlyLimit: number,
used: number,
remaining: number,
resetDate: string
},
isUnlimited: boolean, // 是否无限使用
hasUsedTrial: boolean, // 是否已使用过试用
}
}accessType 值
| 值 | 说明 |
|---|---|
subscription_unlimited | 用户通过无限订阅获得权限 |
subscription_quota | 用户通过配额订阅获得权限 |
lifetime | 用户通过买断获得权限 |
credits | 用户通过积分获得权限 |
none | 无权限 |
useService —— 消费一次服务
当用户点击"生成"、"使用"等按钮时,调用 useService 来记录一次消费:
const { useService } = useAccess()
async function handleGenerate() {
const result = await useService(
'article_generation', // 服务类型(自定义字符串)
1, // 消费数量(可选,默认 1)
'生成了一篇博客文章', // 描述(可选)
'article-123' // 关联 ID(可选)
)
if (result.success) {
// 消费成功,继续业务逻辑
console.log('剩余积分:', result.remainingCredits)
} else {
// 消费失败
console.log('错误:', result.message)
}
}useService 的返回值:
{
success: boolean,
accessType: AccessType, // 实际使用的权限类型
remainingCredits: number, // 剩余积分
message: string, // 提示信息
error?: string // 错误码
}四种模式下的行为差异
积分模式(credits)
allowed= 积分 > 0useService扣 1 个积分- 积分用完
allowed变为false
无限订阅(subscription_unlimited)
allowed= 有活跃订阅(包括试用期)useService只记录用量,不扣积分isUnlimited=true
配额订阅(subscription_quota)
allowed= 有配额剩余 或 有可用积分useService按优先级扣减:配额 → 赠送积分 → 购买积分- 配额每月自动重置
买断制(lifetime)
allowed= 有买断记录useService只记录用量,不扣积分isUnlimited=true
前端 vs 后端 对照
判断权限
前端页面:
const { status } = useAccess()
if (!status.allowed) {
return <div>请先订阅或购买积分</div>
}后端 API Route / Server Action:
import { checkUserAccess } from '@/lib/payment/access'
const access = await checkUserAccess(userId)
if (!access.allowed) {
return Response.json({ error: 'No access' }, { status: 403 })
}消费服务(判断权限 + 扣积分)
前端页面:
const { useService } = useAccess()
const result = await useService('article_generation', 1)
if (result.success) {
console.log('剩余积分:', result.remainingCredits)
}后端 API Route / Server Action:
import { fastConsumeService } from '@/lib/payment/access'
const result = await fastConsumeService(
userId,
1, // 消费数量
'article_generation', // 服务类型
'生成文章', // 描述(可选)
relatedId // 关联 ID(可选)
)
if (!result.success) {
return Response.json({ error: result.message }, { status: 403 })
}fastConsumeService 是优化过的快速路径,直接通过数据库 RPC 原子扣减积分/配额,性能更好。