feat(subscription): load vip and credit plans from api

This commit is contained in:
2026-06-26 15:09:27 +08:00
parent abf6d5ae88
commit 49b67064f7
15 changed files with 748 additions and 50 deletions
+1
View File
@@ -15,6 +15,7 @@ export class PaymentPlan {
declare readonly originalAmountCents: number | null;
declare readonly dailyPriceCents: number | null;
declare readonly currency: string;
declare readonly pricingTier: string;
declare readonly vipDays: number | null;
declare readonly dolAmount: number | null;
@@ -0,0 +1,69 @@
{
"code": 200,
"message": "success",
"success": true,
"data": {
"plans": [
{
"plan_id": "credit_1000",
"plan_name": "1000 Credits",
"order_type": "credit_recharge",
"amount_cents": 990,
"original_amount_cents": null,
"daily_price_cents": null,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": null,
"dol_amount": 1000
},
{
"plan_id": "credit_2000",
"plan_name": "2000 Credits",
"order_type": "credit_recharge",
"amount_cents": 1690,
"original_amount_cents": null,
"daily_price_cents": null,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": null,
"dol_amount": 2000
},
{
"plan_id": "credit_3000",
"plan_name": "3000 Credits",
"order_type": "credit_recharge",
"amount_cents": 2290,
"original_amount_cents": null,
"daily_price_cents": null,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": null,
"dol_amount": 3000
},
{
"plan_id": "credit_5000",
"plan_name": "5000 Credits",
"order_type": "credit_recharge",
"amount_cents": 3490,
"original_amount_cents": null,
"daily_price_cents": null,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": null,
"dol_amount": 5000
},
{
"plan_id": "credit_10000",
"plan_name": "10000 Credits",
"order_type": "credit_recharge",
"amount_cents": 6490,
"original_amount_cents": null,
"daily_price_cents": null,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": null,
"dol_amount": 10000
}
]
}
}
@@ -0,0 +1,45 @@
{
"code": 200,
"message": "success",
"success": true,
"data": {
"plans": [
{
"plan_id": "vip_monthly",
"plan_name": "月度会员",
"order_type": "vip_monthly",
"amount_cents": 1999,
"original_amount_cents": 2499,
"daily_price_cents": 66,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": 30,
"dol_amount": null
},
{
"plan_id": "vip_quarterly",
"plan_name": "季度会员",
"order_type": "vip_quarterly",
"amount_cents": 4999,
"original_amount_cents": 5999,
"daily_price_cents": 55,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": 90,
"dol_amount": null
},
{
"plan_id": "vip_yearly",
"plan_name": "年度会员",
"order_type": "vip_yearly",
"amount_cents": 17999,
"original_amount_cents": 19999,
"daily_price_cents": 49,
"currency": "USD",
"pricing_tier": "T1",
"vip_days": 365,
"dol_amount": null
}
]
}
}
@@ -7,6 +7,7 @@ import type {
CreatePaymentOrderResponse,
PayChannel,
PaymentOrderStatusResponse,
PaymentPlan,
PaymentPlansResponse,
PaymentVipStatusResponse,
} from "@/data/dto/payment";
@@ -16,6 +17,12 @@ export interface IPaymentRepository {
/** 获取套餐列表。 */
getPlans(): Promise<Result<PaymentPlansResponse>>;
/** 获取会员套餐列表。 */
getVipPlans(): Promise<Result<PaymentPlan[]>>;
/** 获取积分套餐列表。 */
getCreditPlans(): Promise<Result<PaymentPlan[]>>;
/** 创建支付订单。 */
createOrder(
planId: string,
@@ -10,6 +10,7 @@ import {
CreatePaymentOrderResponse,
PayChannel,
PaymentOrderStatusResponse,
PaymentPlan,
PaymentPlansResponse,
PaymentVipStatusResponse,
} from "@/data/dto/payment";
@@ -25,6 +26,22 @@ export class PaymentRepository implements IPaymentRepository {
return Result.wrap(() => this.api.getPlans());
}
/** 获取会员套餐列表。 */
async getVipPlans(): Promise<Result<PaymentPlan[]>> {
return Result.wrap(async () => {
const response = await this.api.getPlans();
return response.plans.filter(isVipPaymentPlan);
});
}
/** 获取积分套餐列表。 */
async getCreditPlans(): Promise<Result<PaymentPlan[]>> {
return Result.wrap(async () => {
const response = await this.api.getPlans();
return response.plans.filter(isCreditPaymentPlan);
});
}
/** 创建支付订单。 */
async createOrder(
planId: string,
@@ -54,3 +71,23 @@ export class PaymentRepository implements IPaymentRepository {
/** 全局单例。 */
export const paymentRepository = new PaymentRepository(paymentApi);
export function isVipPaymentPlan(plan: PaymentPlan): boolean {
const orderType = plan.orderType.toLowerCase();
const planId = plan.planId.toLowerCase();
return orderType.startsWith("vip_") || planId.startsWith("vip_");
}
export function isCreditPaymentPlan(plan: PaymentPlan): boolean {
const orderType = plan.orderType.toLowerCase();
const planId = plan.planId.toLowerCase();
return (
plan.dolAmount !== null ||
orderType.startsWith("dol_") ||
orderType.startsWith("credit_") ||
planId.startsWith("dol_") ||
planId.startsWith("credit_") ||
orderType.includes("credit") ||
planId.includes("credit")
);
}
+3
View File
@@ -11,6 +11,7 @@ const PaymentPlanWireSchema = z.object({
original_amount_cents: z.number().nullable().default(null),
daily_price_cents: z.number().nullable().default(null),
currency: z.string(),
pricing_tier: z.string(),
vip_days: z.number().nullable(),
dol_amount: z.number().nullable(),
});
@@ -28,6 +29,7 @@ export const PaymentPlanSchema = z
original_amount_cents: data.originalAmountCents,
daily_price_cents: data.dailyPriceCents,
currency: data.currency,
pricing_tier: data.pricingTier,
vip_days: data.vipDays,
dol_amount: data.dolAmount,
};
@@ -42,6 +44,7 @@ export const PaymentPlanSchema = z
originalAmountCents: data.original_amount_cents,
dailyPriceCents: data.daily_price_cents,
currency: data.currency,
pricingTier: data.pricing_tier,
vipDays: data.vip_days,
dolAmount: data.dol_amount,
}));