import React, { useEffect, useState, useContext } from 'react'; import { API, showError, showInfo, showSuccess, renderQuota, renderQuotaWithAmount, copy, getQuotaPerUnit } from '../../helpers'; import { Avatar, Typography, Card, Button, Modal, Toast, Input, InputNumber, Banner, Skeleton, Divider, } from '@douyinfe/semi-ui'; import { SiAlipay, SiWechat } from 'react-icons/si'; import { useTranslation } from 'react-i18next'; import { UserContext } from '../../context/User'; import { StatusContext } from '../../context/Status/index.js'; import { useTheme } from '../../context/Theme'; import { CreditCard, Gift, Link as LinkIcon, Copy, Users, User, Coins } from 'lucide-react'; const { Text, Title } = Typography; const TopUp = () => { const { t } = useTranslation(); const [userState, userDispatch] = useContext(UserContext); const [statusState] = useContext(StatusContext); const theme = useTheme(); const [redemptionCode, setRedemptionCode] = useState(''); const [topUpCode, setTopUpCode] = useState(''); const [amount, setAmount] = useState(0.0); const [minTopUp, setMinTopUp] = useState(statusState?.status?.min_topup || 1); const [topUpCount, setTopUpCount] = useState(statusState?.status?.min_topup || 1); const [topUpLink, setTopUpLink] = useState(statusState?.status?.top_up_link || ''); const [enableOnlineTopUp, setEnableOnlineTopUp] = useState(statusState?.status?.enable_online_topup || false); const [priceRatio, setPriceRatio] = useState(statusState?.status?.price || 1); const [userQuota, setUserQuota] = useState(0); const [isSubmitting, setIsSubmitting] = useState(false); const [open, setOpen] = useState(false); const [payWay, setPayWay] = useState(''); const [userDataLoading, setUserDataLoading] = useState(true); const [amountLoading, setAmountLoading] = useState(false); const [paymentLoading, setPaymentLoading] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); // 邀请相关状态 const [affLink, setAffLink] = useState(''); const [openTransfer, setOpenTransfer] = useState(false); const [transferAmount, setTransferAmount] = useState(0); // 预设充值额度选项 const [presetAmounts, setPresetAmounts] = useState([ { value: 5 }, { value: 10 }, { value: 30 }, { value: 50 }, { value: 100 }, { value: 300 }, { value: 500 }, { value: 1000 } ]); const [selectedPreset, setSelectedPreset] = useState(null); const getUsername = () => { if (userState.user) { return userState.user.username; } else { return 'null'; } }; const getUserRole = () => { if (!userState.user) return t('普通用户'); switch (userState.user.role) { case 100: return t('超级管理员'); case 10: return t('管理员'); case 0: default: return t('普通用户'); } }; const topUp = async () => { if (redemptionCode === '') { showInfo(t('请输入兑换码!')); return; } setIsSubmitting(true); try { const res = await API.post('/api/user/topup', { key: redemptionCode, }); const { success, message, data } = res.data; if (success) { showSuccess(t('兑换成功!')); Modal.success({ title: t('兑换成功!'), content: t('成功兑换额度:') + renderQuota(data), centered: true, }); setUserQuota((quota) => { return quota + data; }); if (userState.user) { const updatedUser = { ...userState.user, quota: userState.user.quota + data }; userDispatch({ type: 'login', payload: updatedUser }); } setRedemptionCode(''); } else { showError(message); } } catch (err) { showError(t('请求失败')); } finally { setIsSubmitting(false); } }; const openTopUpLink = () => { if (!topUpLink) { showError(t('超级管理员未设置充值链接!')); return; } window.open(topUpLink, '_blank'); }; const preTopUp = async (payment) => { if (!enableOnlineTopUp) { showError(t('管理员未开启在线充值!')); return; } setPaymentLoading(true); try { await getAmount(); if (topUpCount < minTopUp) { showError(t('充值数量不能小于') + minTopUp); return; } setPayWay(payment); setOpen(true); } catch (error) { showError(t('获取金额失败')); } finally { setPaymentLoading(false); } }; const onlineTopUp = async () => { if (amount === 0) { await getAmount(); } if (topUpCount < minTopUp) { showError('充值数量不能小于' + minTopUp); return; } setConfirmLoading(true); setOpen(false); try { const res = await API.post('/api/user/pay', { amount: parseInt(topUpCount), top_up_code: topUpCode, payment_method: payWay, }); if (res !== undefined) { const { message, data } = res.data; if (message === 'success') { let params = data; let url = res.data.url; let form = document.createElement('form'); form.action = url; form.method = 'POST'; let isSafari = navigator.userAgent.indexOf('Safari') > -1 && navigator.userAgent.indexOf('Chrome') < 1; if (!isSafari) { form.target = '_blank'; } for (let key in params) { let input = document.createElement('input'); input.type = 'hidden'; input.name = key; input.value = params[key]; form.appendChild(input); } document.body.appendChild(form); form.submit(); document.body.removeChild(form); } else { showError(data); } } else { showError(res); } } catch (err) { console.log(err); showError(t('支付请求失败')); } finally { setConfirmLoading(false); } }; const getUserQuota = async () => { setUserDataLoading(true); let res = await API.get(`/api/user/self`); const { success, message, data } = res.data; if (success) { setUserQuota(data.quota); userDispatch({ type: 'login', payload: data }); } else { showError(message); } setUserDataLoading(false); }; // 获取邀请链接 const getAffLink = async () => { const res = await API.get('/api/user/aff'); const { success, message, data } = res.data; if (success) { let link = `${window.location.origin}/register?aff=${data}`; setAffLink(link); } else { showError(message); } }; // 划转邀请额度 const transfer = async () => { if (transferAmount < getQuotaPerUnit()) { showError(t('划转金额最低为') + ' ' + renderQuota(getQuotaPerUnit())); return; } const res = await API.post(`/api/user/aff_transfer`, { quota: transferAmount, }); const { success, message } = res.data; if (success) { showSuccess(message); setOpenTransfer(false); getUserQuota().then(); } else { showError(message); } }; // 复制邀请链接 const handleAffLinkClick = async () => { await copy(affLink); showSuccess(t('邀请链接已复制到剪切板')); }; useEffect(() => { if (userState?.user?.id) { setUserDataLoading(false); setUserQuota(userState.user.quota); } else { getUserQuota().then(); } getAffLink().then(); setTransferAmount(getQuotaPerUnit()); }, []); useEffect(() => { if (statusState?.status) { setMinTopUp(statusState.status.min_topup || 1); setTopUpCount(statusState.status.min_topup || 1); setTopUpLink(statusState.status.top_up_link || ''); setEnableOnlineTopUp(statusState.status.enable_online_topup || false); setPriceRatio(statusState.status.price || 1); } }, [statusState?.status]); const renderAmount = () => { return amount + ' ' + t('元'); }; const getAmount = async (value) => { if (value === undefined) { value = topUpCount; } setAmountLoading(true); try { const res = await API.post('/api/user/amount', { amount: parseFloat(value), top_up_code: topUpCode, }); if (res !== undefined) { const { message, data } = res.data; if (message === 'success') { setAmount(parseFloat(data)); } else { setAmount(0); Toast.error({ content: '错误:' + data, id: 'getAmount' }); } } else { showError(res); } } catch (err) { console.log(err); } setAmountLoading(false); }; const handleCancel = () => { setOpen(false); }; const handleTransferCancel = () => { setOpenTransfer(false); }; // 选择预设充值额度 const selectPresetAmount = (preset) => { setTopUpCount(preset.value); setSelectedPreset(preset.value); setAmount(preset.value * priceRatio); }; // 格式化大数字显示 const formatLargeNumber = (num) => { return num.toString(); }; return (
{/* 划转模态框 */} {t('划转邀请额度')}
} visible={openTransfer} onOk={transfer} onCancel={handleTransferCancel} maskClosable={false} size="small" centered >
{t('可用邀请额度')}
{t('划转额度')} ({t('最低') + renderQuota(getQuotaPerUnit())}) setTransferAmount(value)} size="large" className="w-full" />
{/* 充值确认模态框 */} {t('充值确认')} } visible={open} onOk={onlineTopUp} onCancel={handleCancel} maskClosable={false} size="small" centered confirmLoading={confirmLoading} >
{t('充值数量')}: {renderQuotaWithAmount(topUpCount)}
{t('实付金额')}: {amountLoading ? ( ) : ( {renderAmount()} )}
{t('支付方式')}: {payWay === 'zfb' ? (
{t('支付宝')}
) : (
{t('微信')}
)}
{/* 左侧充值区域 */}
{/* 在线充值卡片 */}
{t('在线充值')} {t('快速方便的充值方式')}
{userDataLoading ? ( ) : (
{getUsername()} ({getUserRole()}) {getUsername()}
)}
} >
{/* 账户余额信息 */}
{t('当前余额')} {userDataLoading ? ( ) : (
{renderQuota(userState?.user?.quota || userQuota)}
)}
{t('历史消耗')} {userDataLoading ? ( ) : (
{renderQuota(userState?.user?.used_quota || 0)}
)}
{enableOnlineTopUp && ( <> {/* 预设充值额度卡片网格 */}
{t('选择充值额度')}
{presetAmounts.map((preset, index) => ( selectPresetAmount(preset)} className={`cursor-pointer !rounded-2xl transition-all hover:shadow-md ${selectedPreset === preset.value ? 'border-blue-500' : 'border-gray-200 hover:border-gray-300' }`} bodyStyle={{ textAlign: 'center' }} >
{formatLargeNumber(preset.value)}
{t('实付')} ¥{(preset.value * priceRatio).toFixed(2)}
))}
{/* 桌面端显示的自定义金额和支付按钮 */}
{t('或输入自定义金额')}
{t('充值数量')} {amountLoading ? ( ) : ( {t('实付金额:') + renderAmount()} )}
{ 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); } }} size="large" className="w-full" formatter={(value) => value ? `${value}` : ''} parser={(value) => value ? parseInt(value.replace(/[^\d]/g, '')) : 0} />
)} {!enableOnlineTopUp && ( )} {t('兑换码充值')}
{t('使用兑换码快速充值')}
setRedemptionCode(value)} size="large" />
{topUpLink && ( )}
{/* 右侧邀请信息卡片 */}
{t('邀请奖励')} {t('邀请好友获得额外奖励')}
} >
{t('待使用收益')}
{renderQuota(userState?.user?.aff_quota || 0)}
{t('总收益')}
{renderQuota(userState?.user?.aff_history_quota || 0)}
{t('邀请人数')}
{userState?.user?.aff_count || 0}
{t('邀请链接')} } > {t('复制')} } />
{t('邀请好友注册,好友充值后您可获得相应奖励')}
{t('通过划转功能将奖励额度转入到您的账户余额中')}
{t('邀请的好友越多,获得的奖励越多')}
{/* 移动端底部固定的自定义金额和支付区域 */} {enableOnlineTopUp && (
{t('充值数量')} {amountLoading ? ( ) : ( {t('实付金额:') + renderAmount()} )}
{ 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); } }} className="w-full" formatter={(value) => value ? `${value}` : ''} parser={(value) => value ? parseInt(value.replace(/[^\d]/g, '')) : 0} />
)} ); }; export default TopUp;