feat(admin-v2): add billing management page
- Plan cards with feature comparison and pricing - Usage progress bars with quota visualization - Alipay/WeChat Pay method selection modal - Payment status polling with auto-refresh on success - Navigation + route registration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
101
admin-v2/src/services/billing.ts
Normal file
101
admin-v2/src/services/billing.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import request, { withSignal } from './request'
|
||||
|
||||
// === Types ===
|
||||
|
||||
export interface BillingPlan {
|
||||
id: string
|
||||
name: string
|
||||
display_name: string
|
||||
description: string | null
|
||||
price_cents: number
|
||||
currency: string
|
||||
interval: string
|
||||
features: Record<string, unknown>
|
||||
limits: Record<string, unknown>
|
||||
is_default: boolean
|
||||
sort_order: number
|
||||
status: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface Subscription {
|
||||
id: string
|
||||
account_id: string
|
||||
plan_id: string
|
||||
status: string
|
||||
current_period_start: string
|
||||
current_period_end: string
|
||||
trial_end: string | null
|
||||
canceled_at: string | null
|
||||
cancel_at_period_end: boolean
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface UsageQuota {
|
||||
id: string
|
||||
account_id: string
|
||||
period_start: string
|
||||
period_end: string
|
||||
input_tokens: number
|
||||
output_tokens: number
|
||||
relay_requests: number
|
||||
hand_executions: number
|
||||
pipeline_runs: number
|
||||
max_input_tokens: number | null
|
||||
max_output_tokens: number | null
|
||||
max_relay_requests: number | null
|
||||
max_hand_executions: number | null
|
||||
max_pipeline_runs: number | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface SubscriptionInfo {
|
||||
plan: BillingPlan
|
||||
subscription: Subscription | null
|
||||
usage: UsageQuota
|
||||
}
|
||||
|
||||
export interface PaymentResult {
|
||||
payment_id: string
|
||||
trade_no: string
|
||||
pay_url: string
|
||||
amount_cents: number
|
||||
}
|
||||
|
||||
export interface PaymentStatus {
|
||||
id: string
|
||||
method: string
|
||||
amount_cents: number
|
||||
currency: string
|
||||
status: string
|
||||
}
|
||||
|
||||
// === Service ===
|
||||
|
||||
export const billingService = {
|
||||
listPlans: (signal?: AbortSignal) =>
|
||||
request.get<BillingPlan[]>('/billing/plans', withSignal({}, signal))
|
||||
.then((r) => r.data),
|
||||
|
||||
getPlan: (id: string, signal?: AbortSignal) =>
|
||||
request.get<BillingPlan>(`/billing/plans/${id}`, withSignal({}, signal))
|
||||
.then((r) => r.data),
|
||||
|
||||
getSubscription: (signal?: AbortSignal) =>
|
||||
request.get<SubscriptionInfo>('/billing/subscription', withSignal({}, signal))
|
||||
.then((r) => r.data),
|
||||
|
||||
getUsage: (signal?: AbortSignal) =>
|
||||
request.get<UsageQuota>('/billing/usage', withSignal({}, signal))
|
||||
.then((r) => r.data),
|
||||
|
||||
createPayment: (data: { plan_id: string; payment_method: 'alipay' | 'wechat' }) =>
|
||||
request.post<PaymentResult>('/billing/payments', data).then((r) => r.data),
|
||||
|
||||
getPaymentStatus: (id: string, signal?: AbortSignal) =>
|
||||
request.get<PaymentStatus>(`/billing/payments/${id}`, withSignal({}, signal))
|
||||
.then((r) => r.data),
|
||||
}
|
||||
Reference in New Issue
Block a user