chore: Improve subscription billing fallback and UI states

Add a lightweight active-subscription check to skip subscription pre-consume when none exist, reducing unnecessary transactions and locks. In the subscription UI, disable subscription-first options when no active plan is available, show the effective fallback to wallet with a clear notice, and distinguish “invalidated” from “expired” states. Update i18n strings across supported locales to reflect the new messages and status labels.
This commit is contained in:
t0ng7u
2026-02-07 00:57:36 +08:00
parent 8b8ea60b1e
commit 1cc6bf1b45
9 changed files with 92 additions and 12 deletions

View File

@@ -201,6 +201,16 @@ const SubscriptionPlansCard = ({
// 当前订阅信息 - 支持多个订阅
const hasActiveSubscription = activeSubscriptions.length > 0;
const hasAnySubscription = allSubscriptions.length > 0;
const disableSubscriptionPreference = !hasActiveSubscription;
const isSubscriptionPreference =
billingPreference === 'subscription_first' ||
billingPreference === 'subscription_only';
const displayBillingPreference =
disableSubscriptionPreference && isSubscriptionPreference
? 'wallet_first'
: billingPreference;
const subscriptionPreferenceLabel =
billingPreference === 'subscription_only' ? t('仅用订阅') : t('优先订阅');
const planPurchaseCountMap = useMemo(() => {
const map = new Map();
@@ -319,13 +329,25 @@ const SubscriptionPlansCard = ({
</div>
<div className='flex items-center gap-2'>
<Select
value={billingPreference}
value={displayBillingPreference}
onChange={onChangeBillingPreference}
size='small'
optionList={[
{ value: 'subscription_first', label: t('优先订阅') },
{
value: 'subscription_first',
label: disableSubscriptionPreference
? `${t('优先订阅')} (${t('无生效')})`
: t('优先订阅'),
disabled: disableSubscriptionPreference,
},
{ value: 'wallet_first', label: t('优先钱包') },
{ value: 'subscription_only', label: t('仅用订阅') },
{
value: 'subscription_only',
label: disableSubscriptionPreference
? `${t('仅用订阅')} (${t('无生效')})`
: t('仅用订阅'),
disabled: disableSubscriptionPreference,
},
{ value: 'wallet_only', label: t('仅用钱包') },
]}
/>
@@ -344,6 +366,13 @@ const SubscriptionPlansCard = ({
/>
</div>
</div>
{disableSubscriptionPreference && isSubscriptionPreference && (
<Text type='tertiary' size='small'>
{t('已保存偏好为')}
{subscriptionPreferenceLabel}
{t(',当前无生效订阅,将自动使用钱包')}
</Text>
)}
{hasAnySubscription ? (
<>
@@ -364,6 +393,7 @@ const SubscriptionPlansCard = ({
const usagePercent = getUsagePercent(sub);
const now = Date.now() / 1000;
const isExpired = (subscription?.end_time || 0) < now;
const isCancelled = subscription?.status === 'cancelled';
const isActive =
subscription?.status === 'active' && !isExpired;
@@ -386,6 +416,10 @@ const SubscriptionPlansCard = ({
>
{t('生效')}
</Tag>
) : isCancelled ? (
<Tag color='white' size='small' shape='circle'>
{t('已作废')}
</Tag>
) : (
<Tag color='white' size='small' shape='circle'>
{t('已过期')}
@@ -399,7 +433,11 @@ const SubscriptionPlansCard = ({
)}
</div>
<div className='text-xs text-gray-500 mb-2'>
{isActive ? t('至') : t('过期于')}{' '}
{isActive
? t('至')
: isCancelled
? t('作废于')
: t('过期于')}{' '}
{new Date(
(subscription?.end_time || 0) * 1000,
).toLocaleString()}
@@ -471,9 +509,9 @@ const SubscriptionPlansCard = ({
resetLabel ? { label: resetLabel } : null,
totalAmount > 0
? {
label: totalLabel,
tooltip: `${t('原生额度')}${totalAmount}`,
}
label: totalLabel,
tooltip: `${t('原生额度')}${totalAmount}`,
}
: { label: totalLabel },
limitLabel ? { label: limitLabel } : null,
upgradeLabel ? { label: upgradeLabel } : null,
@@ -482,8 +520,9 @@ const SubscriptionPlansCard = ({
return (
<Card
key={plan?.id}
className={`!rounded-xl transition-all hover:shadow-lg w-full h-full ${isPopular ? 'ring-2 ring-purple-500' : ''
}`}
className={`!rounded-xl transition-all hover:shadow-lg w-full h-full ${
isPopular ? 'ring-2 ring-purple-500' : ''
}`}
bodyStyle={{ padding: 0 }}
>
<div className='p-4 h-full flex flex-col'>
@@ -629,9 +668,9 @@ const SubscriptionPlansCard = ({
purchaseLimitInfo={
selectedPlan?.plan?.id
? {
limit: Number(selectedPlan?.plan?.max_purchase_per_user || 0),
count: getPlanPurchaseCount(selectedPlan?.plan?.id),
}
limit: Number(selectedPlan?.plan?.max_purchase_per_user || 0),
count: getPlanPurchaseCount(selectedPlan?.plan?.id),
}
: null
}
onPayStripe={payStripe}

View File

@@ -2729,10 +2729,13 @@
"我的订阅": "My Subscriptions",
"个生效中": "active",
"无生效": "No active",
"已保存偏好为": "Saved preference: ",
",当前无生效订阅,将自动使用钱包": ", no active subscription. Wallet will be used automatically.",
"个已过期": "expired",
"订阅": "Subscription",
"至": "until",
"过期于": "Expires at",
"作废于": "Invalidated at",
"购买套餐后即可享受模型权益": "Enjoy model benefits after purchasing a plan",
"限购": "Limit",
"推荐": "Recommended",

View File

@@ -2692,10 +2692,13 @@
"我的订阅": "Mes abonnements",
"个生效中": "actifs",
"无生效": "Aucun actif",
"已保存偏好为": "Préférence enregistrée : ",
",当前无生效订阅,将自动使用钱包": ", aucun abonnement actif, le portefeuille sera utilisé automatiquement.",
"个已过期": "expirés",
"订阅": "Abonnement",
"至": "jusqu'à",
"过期于": "Expire le",
"作废于": "Invalidé le",
"购买套餐后即可享受模型权益": "Profitez des avantages du modèle après l'achat d'un plan",
"限购": "Limite",
"推荐": "Recommandé",

View File

@@ -2675,10 +2675,13 @@
"我的订阅": "私のサブスクリプション",
"个生效中": "件有効中",
"无生效": "有効なし",
"已保存偏好为": "保存された設定は",
",当前无生效订阅,将自动使用钱包": "、有効なサブスクリプションがないため、自動的にウォレットを使用します",
"个已过期": "件期限切れ",
"订阅": "サブスクリプション",
"至": "まで",
"过期于": "有効期限",
"作废于": "無効化日",
"购买套餐后即可享受模型权益": "プラン購入後にモデル特典を利用できます",
"限购": "購入制限",
"推荐": "おすすめ",

View File

@@ -2705,10 +2705,13 @@
"我的订阅": "Мои подписки",
"个生效中": "активных",
"无生效": "Нет активных",
"已保存偏好为": "Сохранённая настройка: ",
",当前无生效订阅,将自动使用钱包": ", нет активной подписки, автоматически будет использоваться кошелек.",
"个已过期": "истекших",
"订阅": "Подписка",
"至": "до",
"过期于": "Истекает",
"作废于": "Аннулировано",
"购买套餐后即可享受模型权益": "После покупки плана доступны преимущества моделей",
"限购": "Лимит",
"推荐": "Рекомендуется",

View File

@@ -3254,9 +3254,12 @@
"我的订阅": "Đăng ký của tôi",
"个生效中": "gói đăng ký đang hiệu lực",
"无生效": "Không có gói đăng ký hiệu lực",
"已保存偏好为": "Đã lưu tùy chọn: ",
",当前无生效订阅,将自动使用钱包": ", hiện không có gói đăng ký hiệu lực, sẽ tự động dùng ví.",
"个已过期": "gói đăng ký đã hết hạn",
"订阅": "Đăng ký",
"过期于": "Hết hạn vào",
"作废于": "Vô hiệu vào",
"购买套餐后即可享受模型权益": "Mua gói để nhận quyền lợi mô hình",
"限购": "Giới hạn mua",
"推荐": "Đề xuất",

View File

@@ -2714,10 +2714,13 @@
"我的订阅": "我的订阅",
"个生效中": "个生效中",
"无生效": "无生效",
"已保存偏好为": "已保存偏好为",
",当前无生效订阅,将自动使用钱包": ",当前无生效订阅,将自动使用钱包",
"个已过期": "个已过期",
"订阅": "订阅",
"至": "至",
"过期于": "过期于",
"作废于": "作废于",
"购买套餐后即可享受模型权益": "购买套餐后即可享受模型权益",
"限购": "限购",
"推荐": "推荐",