|
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
For commercial licensing, please contact [email protected]
|
|
For commercial licensing, please contact [email protected]
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-import React, { useRef } from 'react';
|
|
|
|
|
|
|
+import React, { useEffect, useRef, useState } from 'react';
|
|
|
import {
|
|
import {
|
|
|
Avatar,
|
|
Avatar,
|
|
|
Typography,
|
|
Typography,
|
|
@@ -32,6 +32,8 @@ import {
|
|
|
Col,
|
|
Col,
|
|
|
Spin,
|
|
Spin,
|
|
|
Tooltip,
|
|
Tooltip,
|
|
|
|
|
+ Tabs,
|
|
|
|
|
+ TabPane,
|
|
|
} from '@douyinfe/semi-ui';
|
|
} from '@douyinfe/semi-ui';
|
|
|
import { SiAlipay, SiWechat, SiStripe } from 'react-icons/si';
|
|
import { SiAlipay, SiWechat, SiStripe } from 'react-icons/si';
|
|
|
import {
|
|
import {
|
|
@@ -41,10 +43,12 @@ import {
|
|
|
BarChart2,
|
|
BarChart2,
|
|
|
TrendingUp,
|
|
TrendingUp,
|
|
|
Receipt,
|
|
Receipt,
|
|
|
|
|
+ Sparkles,
|
|
|
} from 'lucide-react';
|
|
} from 'lucide-react';
|
|
|
import { IconGift } from '@douyinfe/semi-icons';
|
|
import { IconGift } from '@douyinfe/semi-icons';
|
|
|
import { useMinimumLoadingTime } from '../../hooks/common/useMinimumLoadingTime';
|
|
import { useMinimumLoadingTime } from '../../hooks/common/useMinimumLoadingTime';
|
|
|
import { getCurrencyConfig } from '../../helpers/render';
|
|
import { getCurrencyConfig } from '../../helpers/render';
|
|
|
|
|
+import SubscriptionPlansCard from './SubscriptionPlansCard';
|
|
|
|
|
|
|
|
const { Text } = Typography;
|
|
const { Text } = Typography;
|
|
|
|
|
|
|
@@ -83,506 +87,565 @@ const RechargeCard = ({
|
|
|
statusLoading,
|
|
statusLoading,
|
|
|
topupInfo,
|
|
topupInfo,
|
|
|
onOpenHistory,
|
|
onOpenHistory,
|
|
|
|
|
+ subscriptionLoading = false,
|
|
|
|
|
+ subscriptionPlans = [],
|
|
|
|
|
+ billingPreference,
|
|
|
|
|
+ onChangeBillingPreference,
|
|
|
|
|
+ activeSubscriptions = [],
|
|
|
|
|
+ allSubscriptions = [],
|
|
|
|
|
+ reloadSubscriptionSelf,
|
|
|
}) => {
|
|
}) => {
|
|
|
const onlineFormApiRef = useRef(null);
|
|
const onlineFormApiRef = useRef(null);
|
|
|
const redeemFormApiRef = useRef(null);
|
|
const redeemFormApiRef = useRef(null);
|
|
|
|
|
+ const initialTabSetRef = useRef(false);
|
|
|
const showAmountSkeleton = useMinimumLoadingTime(amountLoading);
|
|
const showAmountSkeleton = useMinimumLoadingTime(amountLoading);
|
|
|
- console.log(
|
|
|
|
|
- ' enabled screem ?',
|
|
|
|
|
- enableCreemTopUp,
|
|
|
|
|
- ' products ?',
|
|
|
|
|
- creemProducts,
|
|
|
|
|
- );
|
|
|
|
|
- return (
|
|
|
|
|
- <Card className='!rounded-2xl shadow-sm border-0'>
|
|
|
|
|
- {/* 卡片头部 */}
|
|
|
|
|
- <div className='flex items-center justify-between mb-4'>
|
|
|
|
|
- <div className='flex items-center'>
|
|
|
|
|
- <Avatar size='small' color='blue' className='mr-3 shadow-md'>
|
|
|
|
|
- <CreditCard size={16} />
|
|
|
|
|
- </Avatar>
|
|
|
|
|
- <div>
|
|
|
|
|
- <Typography.Text className='text-lg font-medium'>
|
|
|
|
|
- {t('账户充值')}
|
|
|
|
|
- </Typography.Text>
|
|
|
|
|
- <div className='text-xs'>{t('多种充值方式,安全便捷')}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <Button
|
|
|
|
|
- icon={<Receipt size={16} />}
|
|
|
|
|
- theme='solid'
|
|
|
|
|
- onClick={onOpenHistory}
|
|
|
|
|
- >
|
|
|
|
|
- {t('账单')}
|
|
|
|
|
- </Button>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ const [activeTab, setActiveTab] = useState('topup');
|
|
|
|
|
+ const shouldShowSubscription =
|
|
|
|
|
+ !subscriptionLoading && subscriptionPlans.length > 0;
|
|
|
|
|
|
|
|
- <Space vertical style={{ width: '100%' }}>
|
|
|
|
|
- {/* 统计数据 */}
|
|
|
|
|
- <Card
|
|
|
|
|
- className='!rounded-xl w-full'
|
|
|
|
|
- cover={
|
|
|
|
|
- <div
|
|
|
|
|
- className='relative h-30'
|
|
|
|
|
- style={{
|
|
|
|
|
- '--palette-primary-darkerChannel': '37 99 235',
|
|
|
|
|
- backgroundImage: `linear-gradient(0deg, rgba(var(--palette-primary-darkerChannel) / 80%), rgba(var(--palette-primary-darkerChannel) / 80%)), url('/cover-4.webp')`,
|
|
|
|
|
- backgroundSize: 'cover',
|
|
|
|
|
- backgroundPosition: 'center',
|
|
|
|
|
- backgroundRepeat: 'no-repeat',
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- <div className='relative z-10 h-full flex flex-col justify-between p-4'>
|
|
|
|
|
- <div className='flex justify-between items-center'>
|
|
|
|
|
- <Text strong style={{ color: 'white', fontSize: '16px' }}>
|
|
|
|
|
- {t('账户统计')}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ 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 = (
|
|
|
|
|
+ <Space vertical style={{ width: '100%' }}>
|
|
|
|
|
+ {/* 统计数据 */}
|
|
|
|
|
+ <Card
|
|
|
|
|
+ className='!rounded-xl w-full'
|
|
|
|
|
+ cover={
|
|
|
|
|
+ <div
|
|
|
|
|
+ className='relative h-30'
|
|
|
|
|
+ style={{
|
|
|
|
|
+ '--palette-primary-darkerChannel': '37 99 235',
|
|
|
|
|
+ backgroundImage: `linear-gradient(0deg, rgba(var(--palette-primary-darkerChannel) / 80%), rgba(var(--palette-primary-darkerChannel) / 80%)), url('/cover-4.webp')`,
|
|
|
|
|
+ backgroundSize: 'cover',
|
|
|
|
|
+ backgroundPosition: 'center',
|
|
|
|
|
+ backgroundRepeat: 'no-repeat',
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className='relative z-10 h-full flex flex-col justify-between p-4'>
|
|
|
|
|
+ <div className='flex justify-between items-center'>
|
|
|
|
|
+ <Text strong style={{ color: 'white', fontSize: '16px' }}>
|
|
|
|
|
+ {t('账户统计')}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- {/* 统计数据 */}
|
|
|
|
|
- <div className='grid grid-cols-3 gap-6 mt-4'>
|
|
|
|
|
- {/* 当前余额 */}
|
|
|
|
|
- <div className='text-center'>
|
|
|
|
|
- <div
|
|
|
|
|
- className='text-base sm:text-2xl font-bold mb-2'
|
|
|
|
|
- style={{ color: 'white' }}
|
|
|
|
|
|
|
+ {/* 统计数据 */}
|
|
|
|
|
+ <div className='grid grid-cols-3 gap-6 mt-4'>
|
|
|
|
|
+ {/* 当前余额 */}
|
|
|
|
|
+ <div className='text-center'>
|
|
|
|
|
+ <div
|
|
|
|
|
+ className='text-base sm:text-2xl font-bold mb-2'
|
|
|
|
|
+ style={{ color: 'white' }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {renderQuota(userState?.user?.quota)}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='flex items-center justify-center text-sm'>
|
|
|
|
|
+ <Wallet
|
|
|
|
|
+ size={14}
|
|
|
|
|
+ className='mr-1'
|
|
|
|
|
+ style={{ color: 'rgba(255,255,255,0.8)' }}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Text
|
|
|
|
|
+ style={{
|
|
|
|
|
+ color: 'rgba(255,255,255,0.8)',
|
|
|
|
|
+ fontSize: '12px',
|
|
|
|
|
+ }}
|
|
|
>
|
|
>
|
|
|
- {renderQuota(userState?.user?.quota)}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className='flex items-center justify-center text-sm'>
|
|
|
|
|
- <Wallet
|
|
|
|
|
- size={14}
|
|
|
|
|
- className='mr-1'
|
|
|
|
|
- style={{ color: 'rgba(255,255,255,0.8)' }}
|
|
|
|
|
- />
|
|
|
|
|
- <Text
|
|
|
|
|
- style={{
|
|
|
|
|
- color: 'rgba(255,255,255,0.8)',
|
|
|
|
|
- fontSize: '12px',
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- {t('当前余额')}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ {t('当前余额')}
|
|
|
|
|
+ </Text>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- {/* 历史消耗 */}
|
|
|
|
|
- <div className='text-center'>
|
|
|
|
|
- <div
|
|
|
|
|
- className='text-base sm:text-2xl font-bold mb-2'
|
|
|
|
|
- style={{ color: 'white' }}
|
|
|
|
|
|
|
+ {/* 历史消耗 */}
|
|
|
|
|
+ <div className='text-center'>
|
|
|
|
|
+ <div
|
|
|
|
|
+ className='text-base sm:text-2xl font-bold mb-2'
|
|
|
|
|
+ style={{ color: 'white' }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {renderQuota(userState?.user?.used_quota)}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='flex items-center justify-center text-sm'>
|
|
|
|
|
+ <TrendingUp
|
|
|
|
|
+ size={14}
|
|
|
|
|
+ className='mr-1'
|
|
|
|
|
+ style={{ color: 'rgba(255,255,255,0.8)' }}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Text
|
|
|
|
|
+ style={{
|
|
|
|
|
+ color: 'rgba(255,255,255,0.8)',
|
|
|
|
|
+ fontSize: '12px',
|
|
|
|
|
+ }}
|
|
|
>
|
|
>
|
|
|
- {renderQuota(userState?.user?.used_quota)}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className='flex items-center justify-center text-sm'>
|
|
|
|
|
- <TrendingUp
|
|
|
|
|
- size={14}
|
|
|
|
|
- className='mr-1'
|
|
|
|
|
- style={{ color: 'rgba(255,255,255,0.8)' }}
|
|
|
|
|
- />
|
|
|
|
|
- <Text
|
|
|
|
|
- style={{
|
|
|
|
|
- color: 'rgba(255,255,255,0.8)',
|
|
|
|
|
- fontSize: '12px',
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- {t('历史消耗')}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ {t('历史消耗')}
|
|
|
|
|
+ </Text>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- {/* 请求次数 */}
|
|
|
|
|
- <div className='text-center'>
|
|
|
|
|
- <div
|
|
|
|
|
- className='text-base sm:text-2xl font-bold mb-2'
|
|
|
|
|
- style={{ color: 'white' }}
|
|
|
|
|
|
|
+ {/* 请求次数 */}
|
|
|
|
|
+ <div className='text-center'>
|
|
|
|
|
+ <div
|
|
|
|
|
+ className='text-base sm:text-2xl font-bold mb-2'
|
|
|
|
|
+ style={{ color: 'white' }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {userState?.user?.request_count || 0}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='flex items-center justify-center text-sm'>
|
|
|
|
|
+ <BarChart2
|
|
|
|
|
+ size={14}
|
|
|
|
|
+ className='mr-1'
|
|
|
|
|
+ style={{ color: 'rgba(255,255,255,0.8)' }}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Text
|
|
|
|
|
+ style={{
|
|
|
|
|
+ color: 'rgba(255,255,255,0.8)',
|
|
|
|
|
+ fontSize: '12px',
|
|
|
|
|
+ }}
|
|
|
>
|
|
>
|
|
|
- {userState?.user?.request_count || 0}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className='flex items-center justify-center text-sm'>
|
|
|
|
|
- <BarChart2
|
|
|
|
|
- size={14}
|
|
|
|
|
- className='mr-1'
|
|
|
|
|
- style={{ color: 'rgba(255,255,255,0.8)' }}
|
|
|
|
|
- />
|
|
|
|
|
- <Text
|
|
|
|
|
- style={{
|
|
|
|
|
- color: 'rgba(255,255,255,0.8)',
|
|
|
|
|
- fontSize: '12px',
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- {t('请求次数')}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ {t('请求次数')}
|
|
|
|
|
+ </Text>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- }
|
|
|
|
|
- >
|
|
|
|
|
- {/* 在线充值表单 */}
|
|
|
|
|
- {statusLoading ? (
|
|
|
|
|
- <div className='py-8 flex justify-center'>
|
|
|
|
|
- <Spin size='large' />
|
|
|
|
|
- </div>
|
|
|
|
|
- ) : enableOnlineTopUp || enableStripeTopUp || enableCreemTopUp ? (
|
|
|
|
|
- <Form
|
|
|
|
|
- getFormApi={(api) => (onlineFormApiRef.current = api)}
|
|
|
|
|
- initValues={{ topUpCount: topUpCount }}
|
|
|
|
|
- >
|
|
|
|
|
- <div className='space-y-6'>
|
|
|
|
|
- {(enableOnlineTopUp || enableStripeTopUp) && (
|
|
|
|
|
- <Row gutter={12}>
|
|
|
|
|
- <Col xs={24} sm={24} md={24} lg={10} xl={10}>
|
|
|
|
|
- <Form.InputNumber
|
|
|
|
|
- field='topUpCount'
|
|
|
|
|
- label={t('充值数量')}
|
|
|
|
|
- disabled={!enableOnlineTopUp && !enableStripeTopUp}
|
|
|
|
|
- placeholder={
|
|
|
|
|
- t('充值数量,最低 ') + renderQuotaWithAmount(minTopUp)
|
|
|
|
|
- }
|
|
|
|
|
- value={topUpCount}
|
|
|
|
|
- min={minTopUp}
|
|
|
|
|
- max={999999999}
|
|
|
|
|
- step={1}
|
|
|
|
|
- precision={0}
|
|
|
|
|
- onChange={async (value) => {
|
|
|
|
|
- if (value && value >= 1) {
|
|
|
|
|
- setTopUpCount(value);
|
|
|
|
|
- setSelectedPreset(null);
|
|
|
|
|
- await getAmount(value);
|
|
|
|
|
- }
|
|
|
|
|
- }}
|
|
|
|
|
- onBlur={(e) => {
|
|
|
|
|
- const value = parseInt(e.target.value);
|
|
|
|
|
- if (!value || value < 1) {
|
|
|
|
|
- setTopUpCount(1);
|
|
|
|
|
- getAmount(1);
|
|
|
|
|
- }
|
|
|
|
|
- }}
|
|
|
|
|
- formatter={(value) => (value ? `${value}` : '')}
|
|
|
|
|
- parser={(value) =>
|
|
|
|
|
- value ? parseInt(value.replace(/[^\d]/g, '')) : 0
|
|
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ {/* 在线充值表单 */}
|
|
|
|
|
+ {statusLoading ? (
|
|
|
|
|
+ <div className='py-8 flex justify-center'>
|
|
|
|
|
+ <Spin size='large' />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ) : enableOnlineTopUp || enableStripeTopUp || enableCreemTopUp ? (
|
|
|
|
|
+ <Form
|
|
|
|
|
+ getFormApi={(api) => (onlineFormApiRef.current = api)}
|
|
|
|
|
+ initValues={{ topUpCount: topUpCount }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className='space-y-6'>
|
|
|
|
|
+ {(enableOnlineTopUp || enableStripeTopUp) && (
|
|
|
|
|
+ <Row gutter={12}>
|
|
|
|
|
+ <Col xs={24} sm={24} md={24} lg={10} xl={10}>
|
|
|
|
|
+ <Form.InputNumber
|
|
|
|
|
+ field='topUpCount'
|
|
|
|
|
+ label={t('充值数量')}
|
|
|
|
|
+ disabled={!enableOnlineTopUp && !enableStripeTopUp}
|
|
|
|
|
+ placeholder={
|
|
|
|
|
+ t('充值数量,最低 ') + renderQuotaWithAmount(minTopUp)
|
|
|
|
|
+ }
|
|
|
|
|
+ value={topUpCount}
|
|
|
|
|
+ min={minTopUp}
|
|
|
|
|
+ max={999999999}
|
|
|
|
|
+ step={1}
|
|
|
|
|
+ precision={0}
|
|
|
|
|
+ onChange={async (value) => {
|
|
|
|
|
+ if (value && value >= 1) {
|
|
|
|
|
+ setTopUpCount(value);
|
|
|
|
|
+ setSelectedPreset(null);
|
|
|
|
|
+ await getAmount(value);
|
|
|
}
|
|
}
|
|
|
- extraText={
|
|
|
|
|
- <Skeleton
|
|
|
|
|
- loading={showAmountSkeleton}
|
|
|
|
|
- active
|
|
|
|
|
- placeholder={
|
|
|
|
|
- <Skeleton.Title
|
|
|
|
|
- style={{
|
|
|
|
|
- width: 120,
|
|
|
|
|
- height: 20,
|
|
|
|
|
- borderRadius: 6,
|
|
|
|
|
- }}
|
|
|
|
|
- />
|
|
|
|
|
- }
|
|
|
|
|
- >
|
|
|
|
|
- <Text type='secondary' className='text-red-600'>
|
|
|
|
|
- {t('实付金额:')}
|
|
|
|
|
- <span style={{ color: 'red' }}>
|
|
|
|
|
- {renderAmount()}
|
|
|
|
|
- </span>
|
|
|
|
|
- </Text>
|
|
|
|
|
- </Skeleton>
|
|
|
|
|
|
|
+ }}
|
|
|
|
|
+ onBlur={(e) => {
|
|
|
|
|
+ const value = parseInt(e.target.value);
|
|
|
|
|
+ if (!value || value < 1) {
|
|
|
|
|
+ setTopUpCount(1);
|
|
|
|
|
+ getAmount(1);
|
|
|
}
|
|
}
|
|
|
- style={{ width: '100%' }}
|
|
|
|
|
- />
|
|
|
|
|
- </Col>
|
|
|
|
|
- <Col xs={24} sm={24} md={24} lg={14} xl={14}>
|
|
|
|
|
- <Form.Slot label={t('选择支付方式')}>
|
|
|
|
|
- {payMethods && payMethods.length > 0 ? (
|
|
|
|
|
- <Space wrap>
|
|
|
|
|
- {payMethods.map((payMethod) => {
|
|
|
|
|
- const minTopupVal =
|
|
|
|
|
- Number(payMethod.min_topup) || 0;
|
|
|
|
|
- const isStripe = payMethod.type === 'stripe';
|
|
|
|
|
- const disabled =
|
|
|
|
|
- (!enableOnlineTopUp && !isStripe) ||
|
|
|
|
|
- (!enableStripeTopUp && isStripe) ||
|
|
|
|
|
- minTopupVal > Number(topUpCount || 0);
|
|
|
|
|
-
|
|
|
|
|
- const buttonEl = (
|
|
|
|
|
- <Button
|
|
|
|
|
- key={payMethod.type}
|
|
|
|
|
- theme='outline'
|
|
|
|
|
- type='tertiary'
|
|
|
|
|
- onClick={() => preTopUp(payMethod.type)}
|
|
|
|
|
- disabled={disabled}
|
|
|
|
|
- loading={
|
|
|
|
|
- paymentLoading && payWay === payMethod.type
|
|
|
|
|
- }
|
|
|
|
|
- icon={
|
|
|
|
|
- payMethod.type === 'alipay' ? (
|
|
|
|
|
- <SiAlipay size={18} color='#1677FF' />
|
|
|
|
|
- ) : payMethod.type === 'wxpay' ? (
|
|
|
|
|
- <SiWechat size={18} color='#07C160' />
|
|
|
|
|
- ) : payMethod.type === 'stripe' ? (
|
|
|
|
|
- <SiStripe size={18} color='#635BFF' />
|
|
|
|
|
- ) : (
|
|
|
|
|
- <CreditCard
|
|
|
|
|
- size={18}
|
|
|
|
|
- color={
|
|
|
|
|
- payMethod.color ||
|
|
|
|
|
- 'var(--semi-color-text-2)'
|
|
|
|
|
- }
|
|
|
|
|
- />
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- className='!rounded-lg !px-4 !py-2'
|
|
|
|
|
- >
|
|
|
|
|
- {payMethod.name}
|
|
|
|
|
- </Button>
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- return disabled &&
|
|
|
|
|
- minTopupVal > Number(topUpCount || 0) ? (
|
|
|
|
|
- <Tooltip
|
|
|
|
|
- content={
|
|
|
|
|
- t('此支付方式最低充值金额为') +
|
|
|
|
|
- ' ' +
|
|
|
|
|
- minTopupVal
|
|
|
|
|
- }
|
|
|
|
|
- key={payMethod.type}
|
|
|
|
|
- >
|
|
|
|
|
- {buttonEl}
|
|
|
|
|
- </Tooltip>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <React.Fragment key={payMethod.type}>
|
|
|
|
|
- {buttonEl}
|
|
|
|
|
- </React.Fragment>
|
|
|
|
|
- );
|
|
|
|
|
- })}
|
|
|
|
|
- </Space>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <div className='text-gray-500 text-sm p-3 bg-gray-50 rounded-lg border border-dashed border-gray-300'>
|
|
|
|
|
- {t('暂无可用的支付方式,请联系管理员配置')}
|
|
|
|
|
- </div>
|
|
|
|
|
- )}
|
|
|
|
|
- </Form.Slot>
|
|
|
|
|
- </Col>
|
|
|
|
|
- </Row>
|
|
|
|
|
- )}
|
|
|
|
|
-
|
|
|
|
|
- {(enableOnlineTopUp || enableStripeTopUp) && (
|
|
|
|
|
- <Form.Slot
|
|
|
|
|
- label={
|
|
|
|
|
- <div className='flex items-center gap-2'>
|
|
|
|
|
- <span>{t('选择充值额度')}</span>
|
|
|
|
|
- {(() => {
|
|
|
|
|
- const { symbol, rate, type } = getCurrencyConfig();
|
|
|
|
|
- if (type === 'USD') return null;
|
|
|
|
|
-
|
|
|
|
|
- return (
|
|
|
|
|
- <span
|
|
|
|
|
|
|
+ }}
|
|
|
|
|
+ formatter={(value) => (value ? `${value}` : '')}
|
|
|
|
|
+ parser={(value) =>
|
|
|
|
|
+ value ? parseInt(value.replace(/[^\d]/g, '')) : 0
|
|
|
|
|
+ }
|
|
|
|
|
+ extraText={
|
|
|
|
|
+ <Skeleton
|
|
|
|
|
+ loading={showAmountSkeleton}
|
|
|
|
|
+ active
|
|
|
|
|
+ placeholder={
|
|
|
|
|
+ <Skeleton.Title
|
|
|
style={{
|
|
style={{
|
|
|
- color: 'var(--semi-color-text-2)',
|
|
|
|
|
- fontSize: '12px',
|
|
|
|
|
- fontWeight: 'normal',
|
|
|
|
|
|
|
+ width: 120,
|
|
|
|
|
+ height: 20,
|
|
|
|
|
+ borderRadius: 6,
|
|
|
}}
|
|
}}
|
|
|
- >
|
|
|
|
|
- (1 $ = {rate.toFixed(2)} {symbol})
|
|
|
|
|
|
|
+ />
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ <Text type='secondary' className='text-red-600'>
|
|
|
|
|
+ {t('实付金额:')}
|
|
|
|
|
+ <span style={{ color: 'red' }}>
|
|
|
|
|
+ {renderAmount()}
|
|
|
</span>
|
|
</span>
|
|
|
- );
|
|
|
|
|
- })()}
|
|
|
|
|
- </div>
|
|
|
|
|
- }
|
|
|
|
|
- >
|
|
|
|
|
- <div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2'>
|
|
|
|
|
- {presetAmounts.map((preset, index) => {
|
|
|
|
|
- const discount =
|
|
|
|
|
- preset.discount ||
|
|
|
|
|
- topupInfo?.discount?.[preset.value] ||
|
|
|
|
|
- 1.0;
|
|
|
|
|
- const originalPrice = preset.value * priceRatio;
|
|
|
|
|
- const discountedPrice = originalPrice * discount;
|
|
|
|
|
- const hasDiscount = discount < 1.0;
|
|
|
|
|
- const actualPay = discountedPrice;
|
|
|
|
|
- const save = originalPrice - discountedPrice;
|
|
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ </Skeleton>
|
|
|
|
|
+ }
|
|
|
|
|
+ style={{ width: '100%' }}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ <Col xs={24} sm={24} md={24} lg={14} xl={14}>
|
|
|
|
|
+ <Form.Slot label={t('选择支付方式')}>
|
|
|
|
|
+ {payMethods && payMethods.length > 0 ? (
|
|
|
|
|
+ <Space wrap>
|
|
|
|
|
+ {payMethods.map((payMethod) => {
|
|
|
|
|
+ const minTopupVal = Number(payMethod.min_topup) || 0;
|
|
|
|
|
+ const isStripe = payMethod.type === 'stripe';
|
|
|
|
|
+ const disabled =
|
|
|
|
|
+ (!enableOnlineTopUp && !isStripe) ||
|
|
|
|
|
+ (!enableStripeTopUp && isStripe) ||
|
|
|
|
|
+ minTopupVal > Number(topUpCount || 0);
|
|
|
|
|
|
|
|
- // 根据当前货币类型换算显示金额和数量
|
|
|
|
|
- const { symbol, rate, type } = getCurrencyConfig();
|
|
|
|
|
- const statusStr = localStorage.getItem('status');
|
|
|
|
|
- let usdRate = 7; // 默认CNY汇率
|
|
|
|
|
- try {
|
|
|
|
|
- if (statusStr) {
|
|
|
|
|
- const s = JSON.parse(statusStr);
|
|
|
|
|
- usdRate = s?.usd_exchange_rate || 7;
|
|
|
|
|
- }
|
|
|
|
|
- } catch (e) {}
|
|
|
|
|
|
|
+ const buttonEl = (
|
|
|
|
|
+ <Button
|
|
|
|
|
+ key={payMethod.type}
|
|
|
|
|
+ theme='outline'
|
|
|
|
|
+ type='tertiary'
|
|
|
|
|
+ onClick={() => preTopUp(payMethod.type)}
|
|
|
|
|
+ disabled={disabled}
|
|
|
|
|
+ loading={
|
|
|
|
|
+ paymentLoading && payWay === payMethod.type
|
|
|
|
|
+ }
|
|
|
|
|
+ icon={
|
|
|
|
|
+ payMethod.type === 'alipay' ? (
|
|
|
|
|
+ <SiAlipay size={18} color='#1677FF' />
|
|
|
|
|
+ ) : payMethod.type === 'wxpay' ? (
|
|
|
|
|
+ <SiWechat size={18} color='#07C160' />
|
|
|
|
|
+ ) : payMethod.type === 'stripe' ? (
|
|
|
|
|
+ <SiStripe size={18} color='#635BFF' />
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <CreditCard
|
|
|
|
|
+ size={18}
|
|
|
|
|
+ color={
|
|
|
|
|
+ payMethod.color ||
|
|
|
|
|
+ 'var(--semi-color-text-2)'
|
|
|
|
|
+ }
|
|
|
|
|
+ />
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ className='!rounded-lg !px-4 !py-2'
|
|
|
|
|
+ >
|
|
|
|
|
+ {payMethod.name}
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
- let displayValue = preset.value; // 显示的数量
|
|
|
|
|
- let displayActualPay = actualPay;
|
|
|
|
|
- let displaySave = save;
|
|
|
|
|
|
|
+ return disabled &&
|
|
|
|
|
+ minTopupVal > Number(topUpCount || 0) ? (
|
|
|
|
|
+ <Tooltip
|
|
|
|
|
+ content={
|
|
|
|
|
+ t('此支付方式最低充值金额为') +
|
|
|
|
|
+ ' ' +
|
|
|
|
|
+ minTopupVal
|
|
|
|
|
+ }
|
|
|
|
|
+ key={payMethod.type}
|
|
|
|
|
+ >
|
|
|
|
|
+ {buttonEl}
|
|
|
|
|
+ </Tooltip>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <React.Fragment key={payMethod.type}>
|
|
|
|
|
+ {buttonEl}
|
|
|
|
|
+ </React.Fragment>
|
|
|
|
|
+ );
|
|
|
|
|
+ })}
|
|
|
|
|
+ </Space>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <div className='text-gray-500 text-sm p-3 bg-gray-50 rounded-lg border border-dashed border-gray-300'>
|
|
|
|
|
+ {t('暂无可用的支付方式,请联系管理员配置')}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </Form.Slot>
|
|
|
|
|
+ </Col>
|
|
|
|
|
+ </Row>
|
|
|
|
|
+ )}
|
|
|
|
|
|
|
|
- if (type === 'USD') {
|
|
|
|
|
- // 数量保持USD,价格从CNY转USD
|
|
|
|
|
- displayActualPay = actualPay / usdRate;
|
|
|
|
|
- displaySave = save / usdRate;
|
|
|
|
|
- } else if (type === 'CNY') {
|
|
|
|
|
- // 数量转CNY,价格已是CNY
|
|
|
|
|
- displayValue = preset.value * usdRate;
|
|
|
|
|
- } else if (type === 'CUSTOM') {
|
|
|
|
|
- // 数量和价格都转自定义货币
|
|
|
|
|
- displayValue = preset.value * rate;
|
|
|
|
|
- displayActualPay = (actualPay / usdRate) * rate;
|
|
|
|
|
- displaySave = (save / usdRate) * rate;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ {(enableOnlineTopUp || enableStripeTopUp) && (
|
|
|
|
|
+ <Form.Slot
|
|
|
|
|
+ label={
|
|
|
|
|
+ <div className='flex items-center gap-2'>
|
|
|
|
|
+ <span>{t('选择充值额度')}</span>
|
|
|
|
|
+ {(() => {
|
|
|
|
|
+ const { symbol, rate, type } = getCurrencyConfig();
|
|
|
|
|
+ if (type === 'USD') return null;
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
- <Card
|
|
|
|
|
- key={index}
|
|
|
|
|
|
|
+ <span
|
|
|
style={{
|
|
style={{
|
|
|
- cursor: 'pointer',
|
|
|
|
|
- border:
|
|
|
|
|
- selectedPreset === preset.value
|
|
|
|
|
- ? '2px solid var(--semi-color-primary)'
|
|
|
|
|
- : '1px solid var(--semi-color-border)',
|
|
|
|
|
- height: '100%',
|
|
|
|
|
- width: '100%',
|
|
|
|
|
- }}
|
|
|
|
|
- bodyStyle={{ padding: '12px' }}
|
|
|
|
|
- onClick={() => {
|
|
|
|
|
- selectPresetAmount(preset);
|
|
|
|
|
- onlineFormApiRef.current?.setValue(
|
|
|
|
|
- 'topUpCount',
|
|
|
|
|
- preset.value,
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ color: 'var(--semi-color-text-2)',
|
|
|
|
|
+ fontSize: '12px',
|
|
|
|
|
+ fontWeight: 'normal',
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
|
- <div style={{ textAlign: 'center' }}>
|
|
|
|
|
- <Typography.Title
|
|
|
|
|
- heading={6}
|
|
|
|
|
- style={{ margin: '0 0 8px 0' }}
|
|
|
|
|
- >
|
|
|
|
|
- <Coins size={18} />
|
|
|
|
|
- {formatLargeNumber(displayValue)} {symbol}
|
|
|
|
|
- {hasDiscount && (
|
|
|
|
|
- <Tag style={{ marginLeft: 4 }} color='green'>
|
|
|
|
|
- {t('折').includes('off')
|
|
|
|
|
- ? (
|
|
|
|
|
- (1 - parseFloat(discount)) *
|
|
|
|
|
- 100
|
|
|
|
|
- ).toFixed(1)
|
|
|
|
|
- : (discount * 10).toFixed(1)}
|
|
|
|
|
- {t('折')}
|
|
|
|
|
- </Tag>
|
|
|
|
|
- )}
|
|
|
|
|
- </Typography.Title>
|
|
|
|
|
- <div
|
|
|
|
|
- style={{
|
|
|
|
|
- color: 'var(--semi-color-text-2)',
|
|
|
|
|
- fontSize: '12px',
|
|
|
|
|
- margin: '4px 0',
|
|
|
|
|
- }}
|
|
|
|
|
- >
|
|
|
|
|
- {t('实付')} {symbol}
|
|
|
|
|
- {displayActualPay.toFixed(2)},
|
|
|
|
|
- {hasDiscount
|
|
|
|
|
- ? `${t('节省')} ${symbol}${displaySave.toFixed(2)}`
|
|
|
|
|
- : `${t('节省')} ${symbol}0.00`}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </Card>
|
|
|
|
|
|
|
+ (1 $ = {rate.toFixed(2)} {symbol})
|
|
|
|
|
+ </span>
|
|
|
);
|
|
);
|
|
|
- })}
|
|
|
|
|
|
|
+ })()}
|
|
|
</div>
|
|
</div>
|
|
|
- </Form.Slot>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className='grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2'>
|
|
|
|
|
+ {presetAmounts.map((preset, index) => {
|
|
|
|
|
+ const discount =
|
|
|
|
|
+ preset.discount || topupInfo?.discount?.[preset.value] || 1.0;
|
|
|
|
|
+ const originalPrice = preset.value * priceRatio;
|
|
|
|
|
+ const discountedPrice = originalPrice * discount;
|
|
|
|
|
+ const hasDiscount = discount < 1.0;
|
|
|
|
|
+ const actualPay = discountedPrice;
|
|
|
|
|
+ const save = originalPrice - discountedPrice;
|
|
|
|
|
+
|
|
|
|
|
+ // 根据当前货币类型换算显示金额和数量
|
|
|
|
|
+ const { symbol, rate, type } = getCurrencyConfig();
|
|
|
|
|
+ const statusStr = localStorage.getItem('status');
|
|
|
|
|
+ let usdRate = 7; // 默认CNY汇率
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (statusStr) {
|
|
|
|
|
+ const s = JSON.parse(statusStr);
|
|
|
|
|
+ usdRate = s?.usd_exchange_rate || 7;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) { }
|
|
|
|
|
+
|
|
|
|
|
+ let displayValue = preset.value; // 显示的数量
|
|
|
|
|
+ let displayActualPay = actualPay;
|
|
|
|
|
+ let displaySave = save;
|
|
|
|
|
|
|
|
- {/* Creem 充值区域 */}
|
|
|
|
|
- {enableCreemTopUp && creemProducts.length > 0 && (
|
|
|
|
|
- <Form.Slot label={t('Creem 充值')}>
|
|
|
|
|
- <div className='grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3'>
|
|
|
|
|
- {creemProducts.map((product, index) => (
|
|
|
|
|
|
|
+ if (type === 'USD') {
|
|
|
|
|
+ // 数量保持USD,价格从CNY转USD
|
|
|
|
|
+ displayActualPay = actualPay / usdRate;
|
|
|
|
|
+ displaySave = save / usdRate;
|
|
|
|
|
+ } else if (type === 'CNY') {
|
|
|
|
|
+ // 数量转CNY,价格已是CNY
|
|
|
|
|
+ displayValue = preset.value * usdRate;
|
|
|
|
|
+ } else if (type === 'CUSTOM') {
|
|
|
|
|
+ // 数量和价格都转自定义货币
|
|
|
|
|
+ displayValue = preset.value * rate;
|
|
|
|
|
+ displayActualPay = (actualPay / usdRate) * rate;
|
|
|
|
|
+ displaySave = (save / usdRate) * rate;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
<Card
|
|
<Card
|
|
|
key={index}
|
|
key={index}
|
|
|
- onClick={() => creemPreTopUp(product)}
|
|
|
|
|
- className='cursor-pointer !rounded-2xl transition-all hover:shadow-md border-gray-200 hover:border-gray-300'
|
|
|
|
|
- bodyStyle={{ textAlign: 'center', padding: '16px' }}
|
|
|
|
|
|
|
+ style={{
|
|
|
|
|
+ cursor: 'pointer',
|
|
|
|
|
+ border:
|
|
|
|
|
+ selectedPreset === preset.value
|
|
|
|
|
+ ? '2px solid var(--semi-color-primary)'
|
|
|
|
|
+ : '1px solid var(--semi-color-border)',
|
|
|
|
|
+ height: '100%',
|
|
|
|
|
+ width: '100%',
|
|
|
|
|
+ }}
|
|
|
|
|
+ bodyStyle={{ padding: '12px' }}
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ selectPresetAmount(preset);
|
|
|
|
|
+ onlineFormApiRef.current?.setValue(
|
|
|
|
|
+ 'topUpCount',
|
|
|
|
|
+ preset.value,
|
|
|
|
|
+ );
|
|
|
|
|
+ }}
|
|
|
>
|
|
>
|
|
|
- <div className='font-medium text-lg mb-2'>
|
|
|
|
|
- {product.name}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className='text-sm text-gray-600 mb-2'>
|
|
|
|
|
- {t('充值额度')}: {product.quota}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className='text-lg font-semibold text-blue-600'>
|
|
|
|
|
- {product.currency === 'EUR' ? '€' : '$'}
|
|
|
|
|
- {product.price}
|
|
|
|
|
|
|
+ <div style={{ textAlign: 'center' }}>
|
|
|
|
|
+ <Typography.Title
|
|
|
|
|
+ heading={6}
|
|
|
|
|
+ style={{ margin: '0 0 8px 0' }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Coins size={18} />
|
|
|
|
|
+ {formatLargeNumber(displayValue)} {symbol}
|
|
|
|
|
+ {hasDiscount && (
|
|
|
|
|
+ <Tag style={{ marginLeft: 4 }} color='green'>
|
|
|
|
|
+ {t('折').includes('off')
|
|
|
|
|
+ ? ((1 - parseFloat(discount)) * 100).toFixed(1)
|
|
|
|
|
+ : (discount * 10).toFixed(1)}
|
|
|
|
|
+ {t('折')}
|
|
|
|
|
+ </Tag>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </Typography.Title>
|
|
|
|
|
+ <div
|
|
|
|
|
+ style={{
|
|
|
|
|
+ color: 'var(--semi-color-text-2)',
|
|
|
|
|
+ fontSize: '12px',
|
|
|
|
|
+ margin: '4px 0',
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {t('实付')} {symbol}
|
|
|
|
|
+ {displayActualPay.toFixed(2)},
|
|
|
|
|
+ {hasDiscount
|
|
|
|
|
+ ? `${t('节省')} ${symbol}${displaySave.toFixed(2)}`
|
|
|
|
|
+ : `${t('节省')} ${symbol}0.00`}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</Card>
|
|
</Card>
|
|
|
- ))}
|
|
|
|
|
- </div>
|
|
|
|
|
- </Form.Slot>
|
|
|
|
|
- )}
|
|
|
|
|
- </div>
|
|
|
|
|
- </Form>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <Banner
|
|
|
|
|
- type='info'
|
|
|
|
|
- description={t(
|
|
|
|
|
- '管理员未开启在线充值功能,请联系管理员开启或使用兑换码充值。',
|
|
|
|
|
|
|
+ );
|
|
|
|
|
+ })}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Form.Slot>
|
|
|
)}
|
|
)}
|
|
|
- className='!rounded-xl'
|
|
|
|
|
- closeIcon={null}
|
|
|
|
|
- />
|
|
|
|
|
- )}
|
|
|
|
|
- </Card>
|
|
|
|
|
|
|
|
|
|
- {/* 兑换码充值 */}
|
|
|
|
|
- <Card
|
|
|
|
|
- className='!rounded-xl w-full'
|
|
|
|
|
- title={
|
|
|
|
|
- <Text type='tertiary' strong>
|
|
|
|
|
- {t('兑换码充值')}
|
|
|
|
|
- </Text>
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ {/* Creem 充值区域 */}
|
|
|
|
|
+ {enableCreemTopUp && creemProducts.length > 0 && (
|
|
|
|
|
+ <Form.Slot label={t('Creem 充值')}>
|
|
|
|
|
+ <div className='grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3'>
|
|
|
|
|
+ {creemProducts.map((product, index) => (
|
|
|
|
|
+ <Card
|
|
|
|
|
+ key={index}
|
|
|
|
|
+ onClick={() => creemPreTopUp(product)}
|
|
|
|
|
+ className='cursor-pointer !rounded-2xl transition-all hover:shadow-md border-gray-200 hover:border-gray-300'
|
|
|
|
|
+ bodyStyle={{ textAlign: 'center', padding: '16px' }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className='font-medium text-lg mb-2'>
|
|
|
|
|
+ {product.name}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='text-sm text-gray-600 mb-2'>
|
|
|
|
|
+ {t('充值额度')}: {product.quota}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className='text-lg font-semibold text-blue-600'>
|
|
|
|
|
+ {product.currency === 'EUR' ? '€' : '$'}
|
|
|
|
|
+ {product.price}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Card>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Form.Slot>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </Form>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <Banner
|
|
|
|
|
+ type='info'
|
|
|
|
|
+ description={t(
|
|
|
|
|
+ '管理员未开启在线充值功能,请联系管理员开启或使用兑换码充值。',
|
|
|
|
|
+ )}
|
|
|
|
|
+ className='!rounded-xl'
|
|
|
|
|
+ closeIcon={null}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
|
|
+ </Card>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 兑换码充值 */}
|
|
|
|
|
+ <Card
|
|
|
|
|
+ className='!rounded-xl w-full'
|
|
|
|
|
+ title={
|
|
|
|
|
+ <Text type='tertiary' strong>
|
|
|
|
|
+ {t('兑换码充值')}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ }
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form
|
|
|
|
|
+ getFormApi={(api) => (redeemFormApiRef.current = api)}
|
|
|
|
|
+ initValues={{ redemptionCode: redemptionCode }}
|
|
|
>
|
|
>
|
|
|
- <Form
|
|
|
|
|
- getFormApi={(api) => (redeemFormApiRef.current = api)}
|
|
|
|
|
- initValues={{ redemptionCode: redemptionCode }}
|
|
|
|
|
- >
|
|
|
|
|
- <Form.Input
|
|
|
|
|
- field='redemptionCode'
|
|
|
|
|
- noLabel={true}
|
|
|
|
|
- placeholder={t('请输入兑换码')}
|
|
|
|
|
- value={redemptionCode}
|
|
|
|
|
- onChange={(value) => setRedemptionCode(value)}
|
|
|
|
|
- prefix={<IconGift />}
|
|
|
|
|
- suffix={
|
|
|
|
|
- <div className='flex items-center gap-2'>
|
|
|
|
|
- <Button
|
|
|
|
|
- type='primary'
|
|
|
|
|
- theme='solid'
|
|
|
|
|
- onClick={topUp}
|
|
|
|
|
- loading={isSubmitting}
|
|
|
|
|
|
|
+ <Form.Input
|
|
|
|
|
+ field='redemptionCode'
|
|
|
|
|
+ noLabel={true}
|
|
|
|
|
+ placeholder={t('请输入兑换码')}
|
|
|
|
|
+ value={redemptionCode}
|
|
|
|
|
+ onChange={(value) => setRedemptionCode(value)}
|
|
|
|
|
+ prefix={<IconGift />}
|
|
|
|
|
+ suffix={
|
|
|
|
|
+ <div className='flex items-center gap-2'>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ type='primary'
|
|
|
|
|
+ theme='solid'
|
|
|
|
|
+ onClick={topUp}
|
|
|
|
|
+ loading={isSubmitting}
|
|
|
|
|
+ >
|
|
|
|
|
+ {t('兑换额度')}
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+ showClear
|
|
|
|
|
+ style={{ width: '100%' }}
|
|
|
|
|
+ extraText={
|
|
|
|
|
+ topUpLink && (
|
|
|
|
|
+ <Text type='tertiary'>
|
|
|
|
|
+ {t('在找兑换码?')}
|
|
|
|
|
+ <Text
|
|
|
|
|
+ type='secondary'
|
|
|
|
|
+ underline
|
|
|
|
|
+ className='cursor-pointer'
|
|
|
|
|
+ onClick={openTopUpLink}
|
|
|
>
|
|
>
|
|
|
- {t('兑换额度')}
|
|
|
|
|
- </Button>
|
|
|
|
|
- </div>
|
|
|
|
|
- }
|
|
|
|
|
- showClear
|
|
|
|
|
- style={{ width: '100%' }}
|
|
|
|
|
- extraText={
|
|
|
|
|
- topUpLink && (
|
|
|
|
|
- <Text type='tertiary'>
|
|
|
|
|
- {t('在找兑换码?')}
|
|
|
|
|
- <Text
|
|
|
|
|
- type='secondary'
|
|
|
|
|
- underline
|
|
|
|
|
- className='cursor-pointer'
|
|
|
|
|
- onClick={openTopUpLink}
|
|
|
|
|
- >
|
|
|
|
|
- {t('购买兑换码')}
|
|
|
|
|
- </Text>
|
|
|
|
|
|
|
+ {t('购买兑换码')}
|
|
|
</Text>
|
|
</Text>
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- />
|
|
|
|
|
- </Form>
|
|
|
|
|
- </Card>
|
|
|
|
|
- </Space>
|
|
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form>
|
|
|
|
|
+ </Card>
|
|
|
|
|
+ </Space>
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Card className='!rounded-2xl shadow-sm border-0'>
|
|
|
|
|
+ {/* 卡片头部 */}
|
|
|
|
|
+ <div className='flex items-center justify-between mb-4'>
|
|
|
|
|
+ <div className='flex items-center'>
|
|
|
|
|
+ <Avatar size='small' color='blue' className='mr-3 shadow-md'>
|
|
|
|
|
+ <CreditCard size={16} />
|
|
|
|
|
+ </Avatar>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <Typography.Text className='text-lg font-medium'>
|
|
|
|
|
+ {t('账户充值')}
|
|
|
|
|
+ </Typography.Text>
|
|
|
|
|
+ <div className='text-xs'>{t('多种充值方式,安全便捷')}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ icon={<Receipt size={16} />}
|
|
|
|
|
+ theme='solid'
|
|
|
|
|
+ onClick={onOpenHistory}
|
|
|
|
|
+ >
|
|
|
|
|
+ {t('账单')}
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {shouldShowSubscription ? (
|
|
|
|
|
+ <Tabs type='card' activeKey={activeTab} onChange={setActiveTab}>
|
|
|
|
|
+ <TabPane
|
|
|
|
|
+ tab={
|
|
|
|
|
+ <div className='flex items-center gap-2'>
|
|
|
|
|
+ <Sparkles size={16} />
|
|
|
|
|
+ {t('订阅套餐')}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+ itemKey='subscription'
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className='py-2'>
|
|
|
|
|
+ <SubscriptionPlansCard
|
|
|
|
|
+ t={t}
|
|
|
|
|
+ loading={subscriptionLoading}
|
|
|
|
|
+ plans={subscriptionPlans}
|
|
|
|
|
+ payMethods={payMethods}
|
|
|
|
|
+ enableOnlineTopUp={enableOnlineTopUp}
|
|
|
|
|
+ enableStripeTopUp={enableStripeTopUp}
|
|
|
|
|
+ enableCreemTopUp={enableCreemTopUp}
|
|
|
|
|
+ billingPreference={billingPreference}
|
|
|
|
|
+ onChangeBillingPreference={onChangeBillingPreference}
|
|
|
|
|
+ activeSubscriptions={activeSubscriptions}
|
|
|
|
|
+ allSubscriptions={allSubscriptions}
|
|
|
|
|
+ reloadSubscriptionSelf={reloadSubscriptionSelf}
|
|
|
|
|
+ withCard={false}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </TabPane>
|
|
|
|
|
+ <TabPane
|
|
|
|
|
+ tab={
|
|
|
|
|
+ <div className='flex items-center gap-2'>
|
|
|
|
|
+ <Wallet size={16} />
|
|
|
|
|
+ {t('额度充值')}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+ itemKey='topup'
|
|
|
|
|
+ >
|
|
|
|
|
+ <div className='py-2'>{topupContent}</div>
|
|
|
|
|
+ </TabPane>
|
|
|
|
|
+ </Tabs>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ topupContent
|
|
|
|
|
+ )}
|
|
|
</Card>
|
|
</Card>
|
|
|
);
|
|
);
|
|
|
};
|
|
};
|