fix: 付费订阅bug

This commit is contained in:
imeepos
2025-11-12 16:07:58 +08:00
parent 5e4f9b1292
commit daf9cca667
9 changed files with 1182 additions and 184 deletions

78
lib/api/pricing.ts Normal file
View File

@@ -0,0 +1,78 @@
import { apiRequest } from './client';
export interface StripePricingItem {
price_id: string;
product_id: string;
name: string;
amount: string;
recurring?: {
interval: string;
interval_count: number;
};
metadata?: {
grant_token?: string;
[key: string]: any;
};
feature_list?: string[];
is_highlight?: boolean;
highlight_text?: string;
metered_price_id?: string;
}
export interface StripePricingTableResponse {
pricing_table_items: StripePricingItem[];
}
export interface CreditPlan {
amountInCents: number;
credits: number;
popular?: boolean;
}
/**
* 获取 Stripe 订阅套餐列表
*/
export async function getStripePlans(): Promise<{
success: boolean;
data?: StripePricingTableResponse;
message?: string;
}> {
try {
const response = await apiRequest<{ success: boolean; data: StripePricingTableResponse }>(
'/api/stripe/plans',
{
method: 'GET',
requiresAuth: false,
}
);
if (!response.success || !response.data) {
return {
success: false,
message: 'Failed to fetch pricing data',
};
}
return {
success: true,
data: response.data,
};
} catch (error) {
console.error('Failed to fetch Stripe plans:', error);
return {
success: false,
message: error instanceof Error ? error.message : 'Unknown error',
};
}
}
/**
* 从 API 数据中提取计划名称列表
*/
export function getPlanNames(pricingData?: StripePricingTableResponse | null): string[] {
if (!pricingData?.pricing_table_items) return [];
return pricingData.pricing_table_items
.filter(item => item.recurring?.interval === 'month')
.map(item => item.name || 'basic');
}

86
lib/api/transactions.ts Normal file
View File

@@ -0,0 +1,86 @@
import { authClient } from '../auth/client';
export type TransactionKind = 'obtained' | 'consumed';
export interface Transaction {
id: string;
title: string;
happenedAt: string;
amount: number;
kind: TransactionKind;
}
export interface TransactionsResponse {
success: boolean;
data: Transaction[];
message?: string;
}
/**
* 获取用户积分交易记录
* 通过 subscription.meterEvent 获取消费记录,通过订阅历史获取充值记录
*/
export async function getUserTransactions(): Promise<TransactionsResponse> {
try {
const { data: subscriptions, error } = await authClient.subscription.list({});
if (error) {
return {
success: false,
data: [],
message: error.message || '获取交易记录失败',
};
}
const transactions: Transaction[] = [];
// 从订阅中提取 meter events (消费记录)
subscriptions?.forEach((sub: any) => {
if (sub.type === 'metered' && sub.meterEvents) {
sub.meterEvents.forEach((event: any) => {
const value = parseInt(event.payload?.value || '0');
if (value > 0) {
transactions.push({
id: event.id || `event-${Date.now()}-${Math.random()}`,
title: event.event_name === 'token_usage' ? 'Token消费' : '积分消费',
happenedAt: event.createdAt || new Date().toISOString(),
amount: -value,
kind: 'consumed',
});
}
});
}
// 提取充值记录 (从订阅创建或续费事件)
if (sub.createdAt) {
const grantToken = parseInt(sub.plan?.metadata?.grant_token || '0');
if (grantToken > 0) {
transactions.push({
id: `sub-${sub.id}`,
title: `订阅充值 - ${sub.plan?.name || '未知套餐'}`,
happenedAt: sub.createdAt,
amount: grantToken,
kind: 'obtained',
});
}
}
});
// 按时间倒序排序
transactions.sort((a, b) =>
new Date(b.happenedAt).getTime() - new Date(a.happenedAt).getTime()
);
return {
success: true,
data: transactions,
};
} catch (error) {
console.error('Failed to get user transactions:', error);
return {
success: false,
data: [],
message: '网络错误,请稍后重试',
};
}
}