|
@@ -59,6 +59,13 @@ const TopUp = () => {
|
|
|
statusState?.status?.enable_online_topup || false,
|
|
statusState?.status?.enable_online_topup || false,
|
|
|
);
|
|
);
|
|
|
const [priceRatio, setPriceRatio] = useState(statusState?.status?.price || 1);
|
|
const [priceRatio, setPriceRatio] = useState(statusState?.status?.price || 1);
|
|
|
|
|
+
|
|
|
|
|
+ const [stripeAmount, setStripeAmount] = useState(0.0);
|
|
|
|
|
+ const [stripeMinTopUp, setStripeMinTopUp] = useState(statusState?.status?.stripe_min_topup || 1);
|
|
|
|
|
+ const [stripeTopUpCount, setStripeTopUpCount] = useState(statusState?.status?.stripe_min_topup || 1);
|
|
|
|
|
+ const [enableStripeTopUp, setEnableStripeTopUp] = useState(statusState?.status?.enable_stripe_topup || false);
|
|
|
|
|
+ const [stripeOpen, setStripeOpen] = useState(false);
|
|
|
|
|
+
|
|
|
const [userQuota, setUserQuota] = useState(0);
|
|
const [userQuota, setUserQuota] = useState(0);
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
const [open, setOpen] = useState(false);
|
|
const [open, setOpen] = useState(false);
|
|
@@ -161,6 +168,7 @@ const TopUp = () => {
|
|
|
showError(t('管理员未开启在线充值!'));
|
|
showError(t('管理员未开启在线充值!'));
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+ setPayWay(payment);
|
|
|
setPaymentLoading(true);
|
|
setPaymentLoading(true);
|
|
|
try {
|
|
try {
|
|
|
await getAmount();
|
|
await getAmount();
|
|
@@ -168,7 +176,6 @@ const TopUp = () => {
|
|
|
showError(t('充值数量不能小于') + minTopUp);
|
|
showError(t('充值数量不能小于') + minTopUp);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- setPayWay(payment);
|
|
|
|
|
setOpen(true);
|
|
setOpen(true);
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
showError(t('获取金额失败'));
|
|
showError(t('获取金额失败'));
|
|
@@ -186,7 +193,6 @@ const TopUp = () => {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
setConfirmLoading(true);
|
|
setConfirmLoading(true);
|
|
|
- setOpen(false);
|
|
|
|
|
try {
|
|
try {
|
|
|
const res = await API.post('/api/user/pay', {
|
|
const res = await API.post('/api/user/pay', {
|
|
|
amount: parseInt(topUpCount),
|
|
amount: parseInt(topUpCount),
|
|
@@ -227,8 +233,67 @@ const TopUp = () => {
|
|
|
console.log(err);
|
|
console.log(err);
|
|
|
showError(t('支付请求失败'));
|
|
showError(t('支付请求失败'));
|
|
|
} finally {
|
|
} finally {
|
|
|
|
|
+ setOpen(false);
|
|
|
|
|
+ setConfirmLoading(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const stripePreTopUp = async () => {
|
|
|
|
|
+ if (!enableStripeTopUp) {
|
|
|
|
|
+ showError(t('管理员未开启在线充值!'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ setPayWay('stripe');
|
|
|
|
|
+ setPaymentLoading(true);
|
|
|
|
|
+ try {
|
|
|
|
|
+ await getStripeAmount();
|
|
|
|
|
+ if (stripeTopUpCount < stripeMinTopUp) {
|
|
|
|
|
+ showError(t('充值数量不能小于') + stripeMinTopUp);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ setStripeOpen(true);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ showError(t('获取金额失败'));
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setPaymentLoading(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const onlineStripeTopUp = async () => {
|
|
|
|
|
+ if (stripeAmount === 0) {
|
|
|
|
|
+ await getStripeAmount();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (stripeTopUpCount < stripeMinTopUp) {
|
|
|
|
|
+ showError(t('充值数量不能小于') + stripeMinTopUp);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ setConfirmLoading(true);
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await API.post('/api/user/stripe/pay', {
|
|
|
|
|
+ amount: parseInt(stripeTopUpCount),
|
|
|
|
|
+ payment_method: 'stripe',
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res !== undefined) {
|
|
|
|
|
+ const { message, data } = res.data;
|
|
|
|
|
+ if (message === 'success') {
|
|
|
|
|
+ processStripeCallback(data);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showError(data);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showError(res);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.log(err);
|
|
|
|
|
+ showError(t('支付请求失败'));
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setStripeOpen(false);
|
|
|
setConfirmLoading(false);
|
|
setConfirmLoading(false);
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const processStripeCallback = (data) => {
|
|
|
|
|
+ window.open(data.pay_link, '_blank');
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const getUserQuota = async () => {
|
|
const getUserQuota = async () => {
|
|
@@ -327,6 +392,10 @@ const TopUp = () => {
|
|
|
setTopUpLink(statusState.status.top_up_link || '');
|
|
setTopUpLink(statusState.status.top_up_link || '');
|
|
|
setEnableOnlineTopUp(statusState.status.enable_online_topup || false);
|
|
setEnableOnlineTopUp(statusState.status.enable_online_topup || false);
|
|
|
setPriceRatio(statusState.status.price || 1);
|
|
setPriceRatio(statusState.status.price || 1);
|
|
|
|
|
+
|
|
|
|
|
+ setStripeMinTopUp(statusState.status.stripe_min_topup || 1);
|
|
|
|
|
+ setStripeTopUpCount(statusState.status.stripe_min_topup || 1);
|
|
|
|
|
+ setEnableStripeTopUp(statusState.status.enable_stripe_topup || false);
|
|
|
}
|
|
}
|
|
|
}, [statusState?.status]);
|
|
}, [statusState?.status]);
|
|
|
|
|
|
|
@@ -334,6 +403,10 @@ const TopUp = () => {
|
|
|
return amount + ' ' + t('元');
|
|
return amount + ' ' + t('元');
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const renderStripeAmount = () => {
|
|
|
|
|
+ return stripeAmount + ' ' + t('元');
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
const getAmount = async (value) => {
|
|
const getAmount = async (value) => {
|
|
|
if (value === undefined) {
|
|
if (value === undefined) {
|
|
|
value = topUpCount;
|
|
value = topUpCount;
|
|
@@ -361,10 +434,42 @@ const TopUp = () => {
|
|
|
setAmountLoading(false);
|
|
setAmountLoading(false);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const getStripeAmount = async (value) => {
|
|
|
|
|
+ if (value === undefined) {
|
|
|
|
|
+ value = stripeTopUpCount
|
|
|
|
|
+ }
|
|
|
|
|
+ setAmountLoading(true);
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await API.post('/api/user/stripe/amount', {
|
|
|
|
|
+ amount: parseFloat(value),
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res !== undefined) {
|
|
|
|
|
+ const { message, data } = res.data;
|
|
|
|
|
+ // showInfo(message);
|
|
|
|
|
+ if (message === 'success') {
|
|
|
|
|
+ setStripeAmount(parseFloat(data));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setStripeAmount(0);
|
|
|
|
|
+ Toast.error({ content: '错误:' + data, id: 'getAmount' });
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showError(res);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.log(err);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setAmountLoading(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const handleCancel = () => {
|
|
const handleCancel = () => {
|
|
|
setOpen(false);
|
|
setOpen(false);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const handleStripeCancel = () => {
|
|
|
|
|
+ setStripeOpen(false);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
const handleTransferCancel = () => {
|
|
const handleTransferCancel = () => {
|
|
|
setOpenTransfer(false);
|
|
setOpenTransfer(false);
|
|
|
};
|
|
};
|
|
@@ -374,6 +479,9 @@ const TopUp = () => {
|
|
|
setTopUpCount(preset.value);
|
|
setTopUpCount(preset.value);
|
|
|
setSelectedPreset(preset.value);
|
|
setSelectedPreset(preset.value);
|
|
|
setAmount(preset.value * priceRatio);
|
|
setAmount(preset.value * priceRatio);
|
|
|
|
|
+
|
|
|
|
|
+ setStripeTopUpCount(preset.value);
|
|
|
|
|
+ setStripeAmount(preset.value);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// 格式化大数字显示
|
|
// 格式化大数字显示
|
|
@@ -496,6 +604,25 @@ const TopUp = () => {
|
|
|
</div>
|
|
</div>
|
|
|
</Modal>
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
+ <Modal
|
|
|
|
|
+ title={t('确定要充值吗')}
|
|
|
|
|
+ visible={stripeOpen}
|
|
|
|
|
+ onOk={onlineStripeTopUp}
|
|
|
|
|
+ onCancel={handleStripeCancel}
|
|
|
|
|
+ maskClosable={false}
|
|
|
|
|
+ size='small'
|
|
|
|
|
+ centered
|
|
|
|
|
+ confirmLoading={confirmLoading}
|
|
|
|
|
+ >
|
|
|
|
|
+ <p>
|
|
|
|
|
+ {t('充值数量')}:{stripeTopUpCount}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <p>
|
|
|
|
|
+ {t('实付金额')}:{renderStripeAmount()}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <p>{t('是否确认充值?')}</p>
|
|
|
|
|
+ </Modal>
|
|
|
|
|
+
|
|
|
<div className='grid grid-cols-1 lg:grid-cols-12 gap-6'>
|
|
<div className='grid grid-cols-1 lg:grid-cols-12 gap-6'>
|
|
|
{/* 左侧充值区域 */}
|
|
{/* 左侧充值区域 */}
|
|
|
<div className='lg:col-span-7 space-y-6 w-full'>
|
|
<div className='lg:col-span-7 space-y-6 w-full'>
|
|
@@ -798,7 +925,7 @@ const TopUp = () => {
|
|
|
</>
|
|
</>
|
|
|
)}
|
|
)}
|
|
|
|
|
|
|
|
- {!enableOnlineTopUp && (
|
|
|
|
|
|
|
+ {!enableOnlineTopUp && !enableStripeTopUp && (
|
|
|
<Banner
|
|
<Banner
|
|
|
type='warning'
|
|
type='warning'
|
|
|
description={t(
|
|
description={t(
|
|
@@ -809,6 +936,89 @@ const TopUp = () => {
|
|
|
/>
|
|
/>
|
|
|
)}
|
|
)}
|
|
|
|
|
|
|
|
|
|
+ {enableStripeTopUp && (
|
|
|
|
|
+ <>
|
|
|
|
|
+ {/* 桌面端显示的自定义金额和支付按钮 */}
|
|
|
|
|
+ <div className='hidden md:block space-y-4'>
|
|
|
|
|
+ <Divider style={{ margin: '24px 0' }}>
|
|
|
|
|
+ <Text className='text-sm font-medium'>
|
|
|
|
|
+ {t(!enableOnlineTopUp ? '或输入自定义金额' : 'Stripe')}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ </Divider>
|
|
|
|
|
+
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <div className='flex justify-between mb-2'>
|
|
|
|
|
+ <Text strong>{t('充值数量')}</Text>
|
|
|
|
|
+ {amountLoading ? (
|
|
|
|
|
+ <Skeleton.Title
|
|
|
|
|
+ style={{ width: '80px', height: '16px' }}
|
|
|
|
|
+ />
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <Text type='tertiary'>
|
|
|
|
|
+ {t('实付金额:') + renderStripeAmount()}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <InputNumber
|
|
|
|
|
+ disabled={!enableStripeTopUp}
|
|
|
|
|
+ placeholder={
|
|
|
|
|
+ t('充值数量,最低 ') + renderQuotaWithAmount(stripeMinTopUp)
|
|
|
|
|
+ }
|
|
|
|
|
+ value={stripeTopUpCount}
|
|
|
|
|
+ min={stripeMinTopUp}
|
|
|
|
|
+ max={999999999}
|
|
|
|
|
+ step={1}
|
|
|
|
|
+ precision={0}
|
|
|
|
|
+ onChange={async (value) => {
|
|
|
|
|
+ if (value && value >= 1) {
|
|
|
|
|
+ setStripeTopUpCount(value);
|
|
|
|
|
+ setSelectedPreset(null);
|
|
|
|
|
+ await getStripeAmount(value);
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ onBlur={(e) => {
|
|
|
|
|
+ const value = parseInt(e.target.value);
|
|
|
|
|
+ if (!value || value < 1) {
|
|
|
|
|
+ setStripeTopUpCount(1);
|
|
|
|
|
+ getStripeAmount(1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ size='large'
|
|
|
|
|
+ className='w-full'
|
|
|
|
|
+ formatter={(value) => (value ? `${value}` : '')}
|
|
|
|
|
+ parser={(value) =>
|
|
|
|
|
+ value ? parseInt(value.replace(/[^\d]/g, '')) : 0
|
|
|
|
|
+ }
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <Text strong className='block mb-3'>
|
|
|
|
|
+ {t('选择支付方式')}
|
|
|
|
|
+ </Text>
|
|
|
|
|
+ <div className='grid grid-cols-1 gap-3'>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ key='stripe'
|
|
|
|
|
+ type='primary'
|
|
|
|
|
+ onClick={() => stripePreTopUp()}
|
|
|
|
|
+ size='large'
|
|
|
|
|
+ disabled={!enableStripeTopUp}
|
|
|
|
|
+ loading={paymentLoading && payWay === 'stripe'}
|
|
|
|
|
+ icon={<CreditCard size={16} />}
|
|
|
|
|
+ style={{
|
|
|
|
|
+ height: '40px',
|
|
|
|
|
+ color: '#b161fe',
|
|
|
|
|
+ }}
|
|
|
|
|
+ className='transition-all hover:shadow-md w-full'
|
|
|
|
|
+ >
|
|
|
|
|
+ <span className='ml-1'>Stripe</span>
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </>
|
|
|
|
|
+ )}
|
|
|
|
|
+
|
|
|
<Divider style={{ margin: '24px 0' }}>
|
|
<Divider style={{ margin: '24px 0' }}>
|
|
|
<Text className='text-sm font-medium'>{t('兑换码充值')}</Text>
|
|
<Text className='text-sm font-medium'>{t('兑换码充值')}</Text>
|
|
|
</Divider>
|
|
</Divider>
|