/** * 订阅/会员 API 封装 * 对齐后端 staging 实测最终契约(2026-09-16) * * Base path: /api/v1/ * 所有请求走 apiClient(已配置 baseURL=/api/v1 和 token 拦截器)。 */ import apiClient from "../client" import type { SubscriptionInfo, SubscriptionPlan, SubscriptionPlansResponse, BillingRecord, ChangePlanRequest, ChangePlanResponse, ToggleAutoRenewRequest, } from "./types" const MOCK_DELAY = 500 const MOCK_SUBSCRIPTION: SubscriptionInfo = { id: "sub_mock_001", plan_id: "free", plan_name: "免费版", status: "active", billing_cycle: "monthly", current_period_start: new Date(Date.now() - 30 * 86400_000).toISOString(), current_period_end: new Date(Date.now() + 30 * 86400_000).toISOString(), amount: 0, auto_renew: false, created_at: new Date(Date.now() - 30 * 86400_000).toISOString(), } const MOCK_PLANS: SubscriptionPlan[] = [ { plan_id: "free", name: "免费版", price_cents: 0, monthly_price_cents: 0, duration_days: 0, points_discount: 1, features: { max_resolution: "720p", free_clips_daily: 3 }, }, { plan_id: "monthly", name: "月度会员", price_cents: 1990, monthly_price_cents: 1990, duration_days: 30, points_discount: 0.9, features: { max_resolution: "1080p", free_clips_daily: 10 }, }, { plan_id: "quarterly", name: "季度会员", price_cents: 3990, monthly_price_cents: 1330, duration_days: 90, points_discount: 0.85, features: { max_resolution: "1080p", free_clips_daily: 15 }, }, { plan_id: "yearly", name: "年度会员", price_cents: 15900, monthly_price_cents: 1325, duration_days: 365, points_discount: 0.8, features: { max_resolution: "4k", free_clips_daily: 30 }, }, ] const MOCK_BILLING: BillingRecord[] = [] const isMock = () => (process.env.POINTS_API_MOCK as string | undefined) === "true" /** 获取当前订阅 */ export const getCurrentSubscription = async (): Promise => { if (isMock()) { await new Promise((r) => setTimeout(r, MOCK_DELAY)) return { ...MOCK_SUBSCRIPTION } } const { data } = await apiClient.get("/subscription/current") return data } /** 获取所有订阅档位 */ export const getSubscriptionPlans = async (): Promise => { if (isMock()) { await new Promise((r) => setTimeout(r, MOCK_DELAY)) return { plans: MOCK_PLANS.map((p) => ({ ...p, features: { ...p.features } })) } } const { data } = await apiClient.get("/subscription/plans") return data } /** 获取账单记录 */ export const getBillingRecords = async (): Promise => { if (isMock()) { await new Promise((r) => setTimeout(r, MOCK_DELAY)) return MOCK_BILLING.map((r) => ({ ...r })) } const { data } = await apiClient.get("/subscription/billing-records") return data } /** 升级/降级套餐 */ export const changePlan = async (request: ChangePlanRequest): Promise => { if (isMock()) { await new Promise((r) => setTimeout(r, MOCK_DELAY * 2)) const plan = MOCK_PLANS.find((p) => p.plan_id === request.target_plan_id) if (!plan) return { success: false, message: "套餐不存在" } const newSub: SubscriptionInfo = { ...MOCK_SUBSCRIPTION, plan_id: plan.plan_id, plan_name: plan.name, billing_cycle: request.billing_cycle, amount: plan.price_cents, status: "pending", current_period_start: new Date().toISOString(), current_period_end: new Date(Date.now() + plan.duration_days * 86400_000).toISOString(), auto_renew: true, } return { success: true, message: "订阅变更成功(mock,支付通道待接入)", new_subscription: newSub, } } const { data } = await apiClient.post("/subscription/change-plan", request) return data } /** 取消订阅(到期后失效) */ export const cancelSubscription = async (): Promise<{ success: boolean; message: string }> => { if (isMock()) { await new Promise((r) => setTimeout(r, MOCK_DELAY)) return { success: true, message: "已取消订阅,到期后将不再续费" } } const { data } = await apiClient.post("/subscription/cancel") return data } /** 切换自动续费 */ export const toggleAutoRenew = async ( req: ToggleAutoRenewRequest, ): Promise<{ success: boolean; message: string }> => { if (isMock()) { await new Promise((r) => setTimeout(r, MOCK_DELAY)) return { success: true, message: req.enabled ? "已开启自动续费" : "已关闭自动续费" } } const { data } = await apiClient.post("/subscription/toggle-auto-renew", req) return data }