chore(points): align types/api with final backend contract - apps/web/src/api/points/types.ts
This commit is contained in:
+175
-165
@@ -1,76 +1,134 @@
|
||||
/**
|
||||
* 积分 & 会员系统 API 类型定义(v2 两档会员制)
|
||||
* 接口契约对齐后端设计文档 membership-points-design-v2.md
|
||||
* 积分系统类型定义
|
||||
* 对齐后端 staging 实测最终契约(2026-09-16)
|
||||
*
|
||||
* Base path: /api/v1/
|
||||
* 会员/订阅相关类型请从 @/api/subscription/types 引入,本文件仅保留积分核心类型。
|
||||
*/
|
||||
|
||||
/** 会员类型 */
|
||||
export type MemberType = "free" | "monthly" | "quarterly" | "yearly"
|
||||
|
||||
/** 积分流水类型 */
|
||||
export type PointsTxType = "earn" | "spend" | "refund"
|
||||
|
||||
/** 积分来源/消耗场景 */
|
||||
/* ================================================================
|
||||
* 场景键
|
||||
* ================================================================ */
|
||||
/**
|
||||
* 积分消耗场景键(9 个)
|
||||
* - ai_script 已拆分为 douyin_extract / ai_rewrite / ai_title,前端禁止再传 ai_script
|
||||
*/
|
||||
export type PointsSource =
|
||||
| "recharge" // 充值
|
||||
| "task_reward" // 任务奖励
|
||||
| "ai_voice" // AI 配音
|
||||
| "ai_video" // AI 视频生成
|
||||
| "ai_digital_human" // AI 数字人
|
||||
| "ai_video" // 智能混剪
|
||||
| "voice_clone_train" // 声音克隆训练
|
||||
| "voice_clone_synth" // 声音克隆合成
|
||||
| "douyin_extract" // 抖音链接提取
|
||||
| "ai_rewrite" // AI 改写文案
|
||||
| "douyin_extract" // 抖音提取文案
|
||||
| "ai_rewrite" // AI 文案改写
|
||||
| "ai_title" // AI 标题生成
|
||||
| "ai_cover" // AI 封面生成
|
||||
| "subscription_bonus" // 会员赠送
|
||||
| "admin_adjust" // 管理员调整
|
||||
| "refund" // 失败退还
|
||||
|
||||
/** 会员 & 积分余额响应 */
|
||||
/** 非消耗场景 source 前缀(用于流水 source 字段) */
|
||||
export type PointsSourceExtra =
|
||||
PointsSource | `refund:${string}` | "recharge" | "sign_up" | "bind_phone" | "gift" | "admin"
|
||||
|
||||
/* ================================================================
|
||||
* 通用
|
||||
* ================================================================ */
|
||||
/** ISO 8601 时间字符串 */
|
||||
export type ISODate = string
|
||||
|
||||
/* ================================================================
|
||||
* 积分余额(GET /points/balance)
|
||||
* ================================================================ */
|
||||
export interface PointsBalance {
|
||||
/** 当前可用积分 */
|
||||
balance: number
|
||||
/** 累计获得 */
|
||||
/** 累计获得积分 */
|
||||
total_earned: number
|
||||
/** 累计消耗 */
|
||||
/** 累计消耗积分 */
|
||||
total_spent: number
|
||||
/** 是否付费会员(free 用户为 false) */
|
||||
/** 是否为付费会员 */
|
||||
is_member: boolean
|
||||
/** 会员类型:monthly / quarterly / yearly;free 用户为 null */
|
||||
member_type: Extract<MemberType, "monthly" | "quarterly" | "yearly"> | null
|
||||
/** 会员到期时间 ISO 字符串 */
|
||||
member_expires_at: string | null
|
||||
/** 今日免费混剪已用次数 */
|
||||
free_clips_used?: number
|
||||
/** 今日免费混剪额度上限 */
|
||||
free_clips_limit?: number
|
||||
/** 今日免费混剪剩余 */
|
||||
free_clips_remaining?: number
|
||||
/** 会员类型(monthly/quarterly/yearly,非会员 null)。推荐使用 /subscription/current 的 plan_id+billing_cycle 做判断 */
|
||||
member_type: "monthly" | "quarterly" | "yearly" | null
|
||||
/** 会员到期时间 */
|
||||
member_expires_at: ISODate | null
|
||||
}
|
||||
|
||||
/** 积分流水记录 */
|
||||
/* ================================================================
|
||||
* 积分规则(GET /points/rules)
|
||||
* ================================================================ */
|
||||
export interface PointsRule {
|
||||
scene_key: PointsSource
|
||||
/** 场景中文名 */
|
||||
name: string
|
||||
/** 基准消耗积分(points_per_use 改名) */
|
||||
base_points: number
|
||||
/** 单位描述,如「次」「分钟」「个」 */
|
||||
unit: string
|
||||
/** 超过30秒后每30秒额外积分(视频/语音类) */
|
||||
extra_per_30s?: number
|
||||
/** 场景说明(后端已补回) */
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface PointsRulesResponse {
|
||||
rules: PointsRule[]
|
||||
/** 非会员消耗倍率(如 1.15) */
|
||||
free_user_multiplier: number
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* 充值包(GET /points/packages)
|
||||
* ================================================================ */
|
||||
export interface PointsPackage {
|
||||
/** 包编码(id 改名) */
|
||||
code: string
|
||||
name: string
|
||||
points: number
|
||||
/** 原价,单位分 */
|
||||
price_cents: number
|
||||
/** 每积分单价(元),展示用 */
|
||||
unit_price: number
|
||||
}
|
||||
|
||||
export interface PointsPackagesResponse {
|
||||
packages: PointsPackage[]
|
||||
/** 当前用户折扣(会员折扣或活动折扣),null 表示无折扣 */
|
||||
user_discount: number | null
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值包前端展示辅助:折后价(分)
|
||||
* 后端废弃 4 档 discounted_price_for_*,前端按 price_cents * (user_discount ?? 1) 计算。
|
||||
*/
|
||||
export function getDiscountPriceCents(pkg: PointsPackage, userDiscount: number | null): number {
|
||||
return Math.round(pkg.price_cents * (userDiscount ?? 1))
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* 积分流水(GET /points/transactions)
|
||||
* ================================================================ */
|
||||
export type PointsTxType = "add" | "deduct"
|
||||
|
||||
export interface PointsTransaction {
|
||||
id: string
|
||||
/** earn / spend / refund */
|
||||
id: number
|
||||
/** 流水类型:add=获得/退款,deduct=消耗 */
|
||||
type: PointsTxType
|
||||
/** 来源场景 */
|
||||
source: PointsSource
|
||||
/** 场景中文名称 */
|
||||
source_name: string
|
||||
/** 变动数量(正数) */
|
||||
/**
|
||||
* 消耗/获得来源:
|
||||
* - 消耗场景直接用 PointsSource 值
|
||||
* - 充值/退款/赠送使用 recharge / refund:<source> / sign_up / bind_phone / gift / admin
|
||||
*/
|
||||
source: string
|
||||
/** 变动数量(绝对值,正负由 type 决定) */
|
||||
amount: number
|
||||
/** 带符号的变动数(收入+,支出-) */
|
||||
signed_amount: number
|
||||
/** 变动后余额 */
|
||||
balance_after: number
|
||||
/** 备注描述 */
|
||||
/** 中文描述 */
|
||||
description: string
|
||||
/** 关联业务 ID */
|
||||
ref_id: string | null
|
||||
created_at: string
|
||||
/** 关联订单/任务 ID,空字符串 "" 表示无关联(不是 null) */
|
||||
ref_id: string
|
||||
created_at: ISODate
|
||||
}
|
||||
|
||||
/** 积分流水分页响应 */
|
||||
export interface PointsTransactionsResponse {
|
||||
items: PointsTransaction[]
|
||||
total: number
|
||||
@@ -78,140 +136,92 @@ export interface PointsTransactionsResponse {
|
||||
page_size: number
|
||||
}
|
||||
|
||||
/** 积分流水查询参数 */
|
||||
export interface PointsTransactionsParams {
|
||||
page?: number
|
||||
page_size?: number
|
||||
type?: PointsTxType
|
||||
source?: PointsSource
|
||||
start_date?: string
|
||||
end_date?: string
|
||||
}
|
||||
|
||||
/** 积分包 */
|
||||
export interface PointsPackage {
|
||||
id: "starter_pack" | "basic_pack" | "pro_pack" | string
|
||||
/** 中文名称 */
|
||||
name: string
|
||||
/** 积分数量 */
|
||||
points: number
|
||||
/** 原价(分) */
|
||||
price: number
|
||||
/** 各会员类型折扣价(分) */
|
||||
discounted_price_for_free: number
|
||||
discounted_price_for_monthly: number
|
||||
discounted_price_for_quarterly: number
|
||||
discounted_price_for_yearly: number
|
||||
}
|
||||
|
||||
/** 积分包列表响应 */
|
||||
export interface PointsPackagesResponse {
|
||||
packages: PointsPackage[]
|
||||
/** 当前用户会员类型,用于前端计算折后价 */
|
||||
user_member_type: MemberType
|
||||
/** 积分单价(元/积分,按会员价计) */
|
||||
unit_price_yuan: number
|
||||
}
|
||||
|
||||
/** 创建充值订单请求 */
|
||||
export interface PointsRechargeRequest {
|
||||
/* ================================================================
|
||||
* 创建充值订单(POST /points/recharge)
|
||||
* ================================================================ */
|
||||
export interface CreateRechargeOrderRequest {
|
||||
/** 充值包 code(字段名保留 package_id 与后端一致) */
|
||||
package_id: string
|
||||
payment_method?: "wechat_pay" | "alipay"
|
||||
}
|
||||
|
||||
/** 订单状态 */
|
||||
export type OrderStatus = "pending" | "paid" | "failed" | "refunded" | "expired"
|
||||
|
||||
/** 充值订单响应 */
|
||||
export interface PointsOrder {
|
||||
export interface CreateRechargeOrderResponse {
|
||||
id: string
|
||||
package_id: string
|
||||
package_name: string
|
||||
order_type: string
|
||||
product_code: string
|
||||
/** 订单金额(分) */
|
||||
amount_cents: number
|
||||
/** 充值积分数量 */
|
||||
points_amount: number
|
||||
price_cents: number
|
||||
original_price_cents: number
|
||||
discount: number
|
||||
currency: "CNY"
|
||||
status: OrderStatus
|
||||
payment_method: string | null
|
||||
payment_id: string | null
|
||||
paid_at: string | null
|
||||
expire_at: string | null
|
||||
created_at: string
|
||||
/** 微信/支付宝支付参数(mock 阶段前端自行处理) */
|
||||
pay_params?: Record<string, string>
|
||||
status: string
|
||||
/**
|
||||
* 支付参数(支付通道未接入时返回空对象 {},前端可透传)
|
||||
*/
|
||||
pay_params: Record<string, unknown>
|
||||
/** 订单过期时间 */
|
||||
expire_at: ISODate
|
||||
created_at: ISODate
|
||||
}
|
||||
|
||||
/** 订阅套餐(月/季/年) */
|
||||
export interface SubscriptionPlan {
|
||||
id: "monthly" | "quarterly" | "yearly"
|
||||
name: string
|
||||
price_cents: number
|
||||
price_yuan: number
|
||||
per_month_yuan: number
|
||||
savings_percent?: number
|
||||
recommended?: boolean
|
||||
billing_label: string
|
||||
}
|
||||
|
||||
/** 当前订阅详情 */
|
||||
export interface SubscriptionCurrent {
|
||||
is_member: boolean
|
||||
member_type: Extract<MemberType, "monthly" | "quarterly" | "yearly"> | null
|
||||
member_type_name: string
|
||||
status: "active" | "expired" | "cancelled" | "none"
|
||||
current_period_start: string | null
|
||||
current_period_end: string | null
|
||||
auto_renew: boolean
|
||||
/** 订阅会员对应的积分折扣 */
|
||||
points_discount: number
|
||||
}
|
||||
|
||||
/** 开通/续费订阅请求 */
|
||||
export interface SubscribeRequest {
|
||||
member_type: "monthly" | "quarterly" | "yearly"
|
||||
payment_method?: "wechat_pay" | "alipay"
|
||||
}
|
||||
|
||||
/** 积分消耗规则 */
|
||||
export interface PointsRule {
|
||||
scene_key: PointsSource
|
||||
scene_name: string
|
||||
/** 每次消耗基础积分(会员价) */
|
||||
points_per_use: number
|
||||
/** 计量单位:条/分钟/次/张 */
|
||||
unit: string
|
||||
/** 额外每 30s 加积分(ai_video 用) */
|
||||
extra_per_30s?: number
|
||||
/** 说明文案 */
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface PointsRulesResponse {
|
||||
rules: PointsRule[]
|
||||
/** 免费用户消耗倍率 */
|
||||
free_user_multiplier: number
|
||||
note: string
|
||||
}
|
||||
|
||||
/** 消费前余额检查请求 */
|
||||
/* ================================================================
|
||||
* 积分预检查(POST /points/check)
|
||||
* ================================================================ */
|
||||
export interface PointsCheckRequest {
|
||||
scene_key: PointsSource
|
||||
/** 单位数量(时长/条数),默认 1 */
|
||||
units?: number
|
||||
/** 数量(units 改名) */
|
||||
quantity: number
|
||||
/** 预计时长(分钟),可选 */
|
||||
duration_minutes?: number
|
||||
}
|
||||
|
||||
/** 消费前余额检查响应 */
|
||||
export interface PointsCheckResponse {
|
||||
/** 是否可以执行 */
|
||||
allowed: boolean
|
||||
/** 需要消耗积分 */
|
||||
required_points: number
|
||||
/** 当前余额 */
|
||||
current_balance: number
|
||||
/** 扣除后剩余 */
|
||||
remaining_after: number
|
||||
/** 是否走免费额度(混剪场景) */
|
||||
/** 是否走免费额度 */
|
||||
is_free_quota: boolean
|
||||
/** 拒绝原因代码 */
|
||||
code?: "INSUFFICIENT_POINTS" | "FREE_QUOTA_EXCEEDED" | "SCENE_NOT_FOUND"
|
||||
message?: string
|
||||
/** 充值页跳转 URL */
|
||||
recharge_url?: string
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* 每日使用情况(GET /usage/daily,新接口)
|
||||
* ================================================================ */
|
||||
export interface DailyUsage {
|
||||
/** 今日已用免费次数 */
|
||||
free_clips_used: number
|
||||
/** 每日免费次数上限 */
|
||||
free_clips_limit: number
|
||||
/** 今日剩余免费次数 */
|
||||
free_clips_remaining: number
|
||||
/** 额度重置时间 */
|
||||
reset_at: ISODate
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* 会员聚合信息(GET /points/subscription/membership,新接口)
|
||||
* ================================================================ */
|
||||
export interface MembershipResponse {
|
||||
is_member: boolean
|
||||
/** 会员类型(monthly/quarterly/yearly,非会员 null) */
|
||||
member_type: "monthly" | "quarterly" | "yearly" | null
|
||||
member_expires_at: ISODate | null
|
||||
/** 当前积分余额(冗余,可与 balance 互校) */
|
||||
points_balance: number
|
||||
/** 最大分辨率,如 "720p" / "1080p" / "4k" */
|
||||
max_resolution: string
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* 错误响应(统一格式 {error:{code,message}})
|
||||
* ================================================================ */
|
||||
export interface ApiError {
|
||||
error: {
|
||||
code: number
|
||||
message: string
|
||||
/** 部分场景会返回,如 unknown scene_key */
|
||||
valid_scenes?: PointsSource[]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user