diff --git a/web/src/components/topup/RechargeCard.jsx b/web/src/components/topup/RechargeCard.jsx
index 264c965b..1ce02309 100644
--- a/web/src/components/topup/RechargeCard.jsx
+++ b/web/src/components/topup/RechargeCard.jsx
@@ -17,7 +17,7 @@ along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
-import React, { useRef } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
import {
Avatar,
Typography,
@@ -32,6 +32,8 @@ import {
Col,
Spin,
Tooltip,
+ Tabs,
+ TabPane,
} from '@douyinfe/semi-ui';
import { SiAlipay, SiWechat, SiStripe } from 'react-icons/si';
import {
@@ -41,10 +43,12 @@ import {
BarChart2,
TrendingUp,
Receipt,
+ Sparkles,
} from 'lucide-react';
import { IconGift } from '@douyinfe/semi-icons';
import { useMinimumLoadingTime } from '../../hooks/common/useMinimumLoadingTime';
import { getCurrencyConfig } from '../../helpers/render';
+import SubscriptionPlansCard from './SubscriptionPlansCard';
const { Text } = Typography;
@@ -83,16 +87,497 @@ const RechargeCard = ({
statusLoading,
topupInfo,
onOpenHistory,
+ subscriptionLoading = false,
+ subscriptionPlans = [],
+ billingPreference,
+ onChangeBillingPreference,
+ activeSubscriptions = [],
+ allSubscriptions = [],
+ reloadSubscriptionSelf,
}) => {
const onlineFormApiRef = useRef(null);
const redeemFormApiRef = useRef(null);
+ const initialTabSetRef = useRef(false);
const showAmountSkeleton = useMinimumLoadingTime(amountLoading);
- console.log(
- ' enabled screem ?',
- enableCreemTopUp,
- ' products ?',
- creemProducts,
+ const [activeTab, setActiveTab] = useState('topup');
+ const shouldShowSubscription =
+ !subscriptionLoading && subscriptionPlans.length > 0;
+
+ useEffect(() => {
+ if (initialTabSetRef.current) return;
+ if (subscriptionLoading) return;
+ setActiveTab(shouldShowSubscription ? 'subscription' : 'topup');
+ initialTabSetRef.current = true;
+ }, [shouldShowSubscription, subscriptionLoading]);
+
+ useEffect(() => {
+ if (!shouldShowSubscription && activeTab !== 'topup') {
+ setActiveTab('topup');
+ }
+ }, [shouldShowSubscription, activeTab]);
+ const topupContent = (
+
+ {/* 统计数据 */}
+
+
+
+
+ {t('账户统计')}
+
+
+
+ {/* 统计数据 */}
+
+ {/* 当前余额 */}
+
+
+ {renderQuota(userState?.user?.quota)}
+
+
+
+
+ {t('当前余额')}
+
+
+
+
+ {/* 历史消耗 */}
+
+
+ {renderQuota(userState?.user?.used_quota)}
+
+
+
+
+ {t('历史消耗')}
+
+
+
+
+ {/* 请求次数 */}
+
+
+ {userState?.user?.request_count || 0}
+
+
+
+
+ {t('请求次数')}
+
+
+
+
+
+
+ }
+ >
+ {/* 在线充值表单 */}
+ {statusLoading ? (
+
+
+
+ ) : enableOnlineTopUp || enableStripeTopUp || enableCreemTopUp ? (
+
+
+ {creemProducts.map((product, index) => (
+
creemPreTopUp(product)}
+ className='cursor-pointer !rounded-2xl transition-all hover:shadow-md border-gray-200 hover:border-gray-300'
+ bodyStyle={{ textAlign: 'center', padding: '16px' }}
+ >
+
+ {product.name}
+
+
+ {t('充值额度')}: {product.quota}
+
+
+ {product.currency === 'EUR' ? '€' : '$'}
+ {product.price}
+
+
+ ))}
+
+
+ )}
+
+
+ ) : (
+
+ )}
+
+
+ {/* 兑换码充值 */}
+
+ {t('兑换码充值')}
+
+ }
+ >
+ setRedemptionCode(value)}
+ prefix={}
+ suffix={
+
+
+
+ }
+ showClear
+ style={{ width: '100%' }}
+ extraText={
+ topUpLink && (
+
+ {t('在找兑换码?')}
+
+ {t('购买兑换码')}
+
+
+ )
+ }
+ />
+
+
+
);
+
return (
{/* 卡片头部 */}
@@ -117,472 +602,50 @@ const RechargeCard = ({
-
- {/* 统计数据 */}
-
-
-
-
- {t('账户统计')}
-
-
-
- {/* 统计数据 */}
-
- {/* 当前余额 */}
-
-
- {renderQuota(userState?.user?.quota)}
-
-
-
-
- {t('当前余额')}
-
-
-
-
- {/* 历史消耗 */}
-
-
- {renderQuota(userState?.user?.used_quota)}
-
-
-
-
- {t('历史消耗')}
-
-
-
-
- {/* 请求次数 */}
-
-
- {userState?.user?.request_count || 0}
-
-
-
-
- {t('请求次数')}
-
-
-
-
+ {shouldShowSubscription ? (
+
+
+
+ {t('订阅套餐')}
-
- }
- >
- {/* 在线充值表单 */}
- {statusLoading ? (
-
-
-
- ) : enableOnlineTopUp || enableStripeTopUp || enableCreemTopUp ? (
-
-
- {creemProducts.map((product, index) => (
-
creemPreTopUp(product)}
- className='cursor-pointer !rounded-2xl transition-all hover:shadow-md border-gray-200 hover:border-gray-300'
- bodyStyle={{ textAlign: 'center', padding: '16px' }}
- >
-
- {product.name}
-
-
- {t('充值额度')}: {product.quota}
-
-
- {product.currency === 'EUR' ? '€' : '$'}
- {product.price}
-
-
- ))}
-
-
- )}
-
-
- ) : (
-
- )}
-
-
- {/* 兑换码充值 */}
-
- {t('兑换码充值')}
-
- }
- >
- setRedemptionCode(value)}
- prefix={}
- suffix={
-
-
-
- }
- showClear
- style={{ width: '100%' }}
- extraText={
- topUpLink && (
-
- {t('在找兑换码?')}
-
- {t('购买兑换码')}
-
-
- )
- }
- />
-
-
-
+
+
+
+
+
+
+ {t('额度充值')}
+
+ }
+ itemKey='topup'
+ >
+ {topupContent}
+
+
+ ) : (
+ topupContent
+ )}
);
};
diff --git a/web/src/components/topup/SubscriptionPlansCard.jsx b/web/src/components/topup/SubscriptionPlansCard.jsx
index e9d25e54..54b4506b 100644
--- a/web/src/components/topup/SubscriptionPlansCard.jsx
+++ b/web/src/components/topup/SubscriptionPlansCard.jsx
@@ -19,7 +19,6 @@ For commercial licensing, please contact support@quantumnous.com
import React, { useMemo, useState } from 'react';
import {
- Avatar,
Badge,
Button,
Card,
@@ -33,7 +32,7 @@ import {
} from '@douyinfe/semi-ui';
import { API, showError, showSuccess, renderQuota } from '../../helpers';
import { getCurrencyConfig } from '../../helpers/render';
-import { Crown, RefreshCw, Sparkles } from 'lucide-react';
+import { RefreshCw, Sparkles } from 'lucide-react';
import SubscriptionPurchaseModal from './modals/SubscriptionPurchaseModal';
import {
formatSubscriptionDuration,
@@ -83,6 +82,7 @@ const SubscriptionPlansCard = ({
activeSubscriptions = [],
allSubscriptions = [],
reloadSubscriptionSelf,
+ withCard = true,
}) => {
const [open, setOpen] = useState(false);
const [selectedPlan, setSelectedPlan] = useState(null);
@@ -241,33 +241,9 @@ const SubscriptionPlansCard = ({
return Math.round((used / total) * 100);
};
- return (
-
+ const cardContent = (
+ <>
{/* 卡片头部 */}
-
-
-
-
-
-
-
{t('订阅套餐')}
-
{t('购买订阅获得模型额度/次数')}
-
-
- {/* 扣费策略 - 右上角 */}
-
-
-
{loading ? (
{/* 我的订阅骨架屏 */}
@@ -281,7 +257,7 @@ const SubscriptionPlansCard = ({
{/* 套餐列表骨架屏 */}
-
+
{[1, 2, 3].map((i) => (
{/* 当前订阅状态 */}
-
-
+
+
{t('我的订阅')}
{hasActiveSubscription ? (
)}
-
- }
- onClick={handleRefresh}
- loading={refreshing}
- />
+
+
+
+ }
+ onClick={handleRefresh}
+ loading={refreshing}
+ />
+
{hasAnySubscription ? (
@@ -451,7 +440,7 @@ const SubscriptionPlansCard = ({
{/* 可购买套餐 - 标准定价卡片 */}
{plans.length > 0 ? (
-
+
{plans.map((p, index) => {
const plan = p?.plan;
const totalAmount = Number(plan?.total_amount || 0);
@@ -482,9 +471,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,
@@ -493,9 +482,8 @@ const SubscriptionPlansCard = ({
return (
@@ -583,7 +571,7 @@ const SubscriptionPlansCard = ({
const buttonEl = (