- {statusLoading ? (
-
- ) : (enableOnlineTopUp || enableStripeTopUp) ? (
-
- {/* 预设充值额度选择 */}
- {(enableOnlineTopUp || enableStripeTopUp) && (
-
-
- {t('选择充值额度')}
-
-
- {presetAmounts.map((preset, index) => (
-
selectPresetAmount(preset)}
- className={`cursor-pointer !rounded-xl transition-all hover:shadow-md ${selectedPreset === preset.value
- ? 'border-blue-500 shadow-md'
- : 'border-slate-200 hover:border-slate-300 dark:border-slate-600 dark:hover:border-slate-500'
- }`}
- bodyStyle={{ textAlign: 'center', padding: '12px' }}
- >
-
-
- {formatLargeNumber(preset.value)}
-
-
- {t('实付')} ¥{(preset.value * priceRatio).toFixed(2)}
-
-
- ))}
+
+ {/* 统计数据 */}
+
+
+
+ {t('账户统计')}
+
+
+ {/* 统计数据 */}
+
+ {/* 当前余额 */}
+
+
+ {renderQuota(userState?.user?.quota)}
+
+
+
+ {t('当前余额')}
- )}
- {/* 自定义充值金额 */}
+ {/* 历史消耗 */}
+
+
+ {renderQuota(userState?.user?.used_quota)}
+
+
+
+ {t('历史消耗')}
+
+
+
+ {/* 请求次数 */}
+
+
+ {userState?.user?.request_count || 0}
+
+
+
+ {t('请求次数')}
+
+
+
+
+
+ }
+ >
+ {/* 在线充值表单 */}
+ {statusLoading ? (
+
+
+
+ ) : (enableOnlineTopUp || enableStripeTopUp) ? (
+
-
+
+ ) : (
+
+ )}
+
- {/* 兑换码充值 Tab */}
-
-
+ {/* 兑换码充值 */}
+
{t('兑换码充值')}
-
+
}
- itemKey="redeem"
>
-
-
-
setRedemptionCode(value)}
- className='!rounded-lg'
- prefix={
}
- showClear
- />
-
-
- {topUpLink && (
+
setRedemptionCode(value)}
+ prefix={ }
+ suffix={
+
}
+ type='primary'
+ theme='solid'
+ onClick={topUp}
+ loading={isSubmitting}
>
- {t('获取兑换码')}
+ {t('兑换额度')}
- )}
-
- {isSubmitting ? t('兑换中...') : t('兑换')}
-
-
-
-
-
-
+
+ }
+ showClear
+ style={{ width: '100%' }}
+ extraText={topUpLink && (
+
+ {t('在找兑换码?')}
+
+ {t('购买兑换码')}
+
+
+ )}
+ />
+
+
+
);
};
diff --git a/web/src/components/topup/RightStatsCard.jsx b/web/src/components/topup/RightStatsCard.jsx
deleted file mode 100644
index 8daa8d35..00000000
--- a/web/src/components/topup/RightStatsCard.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-Copyright (C) 2025 QuantumNous
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see
.
-
-For commercial licensing, please contact support@quantumnous.com
-*/
-
-import React from 'react';
-import { Card, Typography, Divider } from '@douyinfe/semi-ui';
-import { Wallet, Coins, BarChart2 } from 'lucide-react';
-
-const { Text } = Typography;
-
-const RightStatsCard = ({ t, userState, renderQuota }) => {
- return (
-
-
-
-
-
-
{t('当前余额')}
-
{renderQuota(userState?.user?.quota)}
-
-
-
-
-
-
-
{t('历史消耗')}
-
{renderQuota(userState?.user?.used_quota)}
-
-
-
-
-
-
-
{t('请求次数')}
-
{userState?.user?.request_count || 0}
-
-
-
-
- );
-};
-
-export default RightStatsCard;
-
-
diff --git a/web/src/components/topup/index.jsx b/web/src/components/topup/index.jsx
index 4c9a5267..5fada938 100644
--- a/web/src/components/topup/index.jsx
+++ b/web/src/components/topup/index.jsx
@@ -17,7 +17,7 @@ along with this program. If not, see
.
For commercial licensing, please contact support@quantumnous.com
*/
-import React, { useEffect, useState, useContext } from 'react';
+import React, { useEffect, useState, useContext, useRef } from 'react';
import {
API,
showError,
@@ -63,42 +63,25 @@ const TopUp = () => {
const [enableStripeTopUp, setEnableStripeTopUp] = useState(statusState?.status?.enable_stripe_topup || false);
const [statusLoading, setStatusLoading] = useState(true);
- 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 [payMethods, setPayMethods] = useState([]);
+ const affFetchedRef = useRef(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 [presetAmounts, setPresetAmounts] = useState([]);
const [selectedPreset, setSelectedPreset] = useState(null);
- const getUsername = () => {
- if (userState.user) {
- return userState.user.username;
- } else {
- return 'null';
- }
- };
-
const topUp = async () => {
if (redemptionCode === '') {
showInfo(t('请输入兑换码!'));
@@ -117,9 +100,6 @@ const TopUp = () => {
content: t('成功兑换额度:') + renderQuota(data),
centered: true,
});
- setUserQuota((quota) => {
- return quota + data;
- });
if (userState.user) {
const updatedUser = {
...userState.user,
@@ -260,16 +240,13 @@ const TopUp = () => {
};
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);
};
// 获取邀请链接
@@ -310,13 +287,9 @@ const TopUp = () => {
};
useEffect(() => {
- if (userState?.user?.id) {
- setUserDataLoading(false);
- setUserQuota(userState.user.quota);
- } else {
+ if (!userState?.user?.id) {
getUserQuota().then();
}
- getAffLink().then();
setTransferAmount(getQuotaPerUnit());
let payMethods = localStorage.getItem('pay_methods');
@@ -330,9 +303,9 @@ const TopUp = () => {
// 如果没有color,则设置默认颜色
payMethods = payMethods.map((method) => {
if (!method.color) {
- if (method.type === 'zfb') {
+ if (method.type === 'alipay') {
method.color = 'rgba(var(--semi-blue-5), 1)';
- } else if (method.type === 'wx') {
+ } else if (method.type === 'wxpay') {
method.color = 'rgba(var(--semi-green-5), 1)';
} else if (method.type === 'stripe') {
method.color = 'rgba(var(--semi-purple-5), 1)';
@@ -365,14 +338,27 @@ const TopUp = () => {
}
}, [statusState?.status?.enable_stripe_topup]);
+ useEffect(() => {
+ if (affFetchedRef.current) return;
+ affFetchedRef.current = true;
+ getAffLink().then();
+ }, []);
+
useEffect(() => {
if (statusState?.status) {
- setMinTopUp(statusState.status.min_topup || 1);
- setTopUpCount(statusState.status.min_topup || 1);
+ const minTopUpValue = statusState.status.min_topup || 1;
+ setMinTopUp(minTopUpValue);
+ setTopUpCount(minTopUpValue);
setTopUpLink(statusState.status.top_up_link || '');
setEnableOnlineTopUp(statusState.status.enable_online_topup || false);
setPriceRatio(statusState.status.price || 1);
setEnableStripeTopUp(statusState.status.enable_stripe_topup || false);
+
+ // 根据最小充值金额生成预设充值额度选项
+ setPresetAmounts(generatePresetAmounts(minTopUpValue));
+ // 初始化显示实付金额
+ getAmount(minTopUpValue);
+
setStatusLoading(false);
}
}, [statusState?.status]);
@@ -454,6 +440,14 @@ const TopUp = () => {
return num.toString();
};
+ // 根据最小充值金额生成预设充值额度选项
+ const generatePresetAmounts = (minAmount) => {
+ const multipliers = [1, 5, 10, 30, 50, 100, 300, 500];
+ return multipliers.map(multiplier => ({
+ value: minAmount * multiplier
+ }));
+ };
+
return (
{/* 划转模态框 */}
diff --git a/web/src/components/topup/modals/PaymentConfirmModal.jsx b/web/src/components/topup/modals/PaymentConfirmModal.jsx
index 12fcac95..111b9bf9 100644
--- a/web/src/components/topup/modals/PaymentConfirmModal.jsx
+++ b/web/src/components/topup/modals/PaymentConfirmModal.jsx
@@ -85,9 +85,9 @@ const PaymentConfirmModal = ({
if (payMethod) {
return (
<>
- {payMethod.type === 'zfb' ? (
+ {payMethod.type === 'alipay' ? (
- ) : payMethod.type === 'wx' ? (
+ ) : payMethod.type === 'wxpay' ? (
) : payMethod.type === 'stripe' ? (
@@ -99,7 +99,7 @@ const PaymentConfirmModal = ({
);
} else {
// 默认充值方式
- if (payWay === 'zfb') {
+ if (payWay === 'alipay') {
return (
<>
diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json
index 6db0e7ee..56a4236b 100644
--- a/web/src/i18n/locales/en.json
+++ b/web/src/i18n/locales/en.json
@@ -159,7 +159,6 @@
"测试所有已启用通道": "Test all enabled channels",
"更新所有已启用通道余额": "Update balance for all enabled channels",
"刷新": "Refresh",
- "处理中...": "Processing...",
"绑定成功!": "Binding successful!",
"登录成功!": "Login successful!",
"操作失败,重定向至登录界面中...": "Operation failed, redirecting to login page...",
@@ -168,7 +167,7 @@
"渠道": "Channel",
"渠道管理": "Channels",
"令牌": "Tokens",
- "兑换": "Redeem",
+ "兑换额度": "Redeem",
"充值": "Recharge",
"用户": "Users",
"日志": "Logs",
@@ -846,7 +845,6 @@
"充值记录": "Recharge record",
"返利记录": "Rebate record",
"确定要充值 $": "Confirm to top up $",
- "兑换中...": "Redemming",
"微信/支付宝 实付金额:": "WeChat/Alipay actual payment amount:",
"Stripe 实付金额:": "Stripe actual payment amount:",
"支付中...": "Paying",
@@ -857,7 +855,9 @@
"兑换码充值": "Redemption code recharge",
"奖励说明": "Reward description",
"选择支付方式": "Select payment method",
- "处理中": "Processing",
+ "在找兑换码?": "Looking for a redemption code? ",
+ "购买兑换码": "Buy redemption code",
+ "账户统计": "Account statistics",
"账户充值": "Account recharge",
"多种充值方式,安全便捷": "Multiple recharge methods, safe and convenient",
"支付方式": "Payment method",