Align console behavior with operator routing and image workflow expectations
Constraint: Must preserve current exchange-rate logic, same-group routing boundary, and temporary image-file behavior while fixing UX-visible inconsistencies. Rejected: Large frontend chunk refactor | introduced risky circular chunking and did not improve deliverability for this rollout. Confidence: medium Scope-risk: moderate Directive: Keep channel failover constrained to the selected group and preserve Beijing-day semantics for user cache dashboard metrics. Tested: go test ./controller ./model ./service ./common -count=1; npm run build; remote smoke on source deployment at http://38.76.218.56:18081/ plus /api/status and /api/image-studio/settings. Not-tested: Browser-driven end-to-end verification of every console page interaction.
This commit is contained in:
@@ -17,7 +17,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Avatar,
|
||||
Typography,
|
||||
@@ -105,6 +105,21 @@ const RechargeCard = ({
|
||||
const [activeTab, setActiveTab] = useState('topup');
|
||||
const shouldShowSubscription =
|
||||
!subscriptionLoading && subscriptionPlans.length > 0;
|
||||
const nonWaffoPayMethods = useMemo(
|
||||
() => (payMethods || []).filter((method) => method.type !== 'waffo'),
|
||||
[payMethods],
|
||||
);
|
||||
const currencyConfig = useMemo(() => getCurrencyConfig(), []);
|
||||
const usdExchangeRate = useMemo(() => {
|
||||
const statusStr = localStorage.getItem('status');
|
||||
try {
|
||||
if (statusStr) {
|
||||
const status = JSON.parse(statusStr);
|
||||
return status?.usd_exchange_rate || 7;
|
||||
}
|
||||
} catch (e) {}
|
||||
return 7;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialTabSetRef.current) return;
|
||||
@@ -291,11 +306,11 @@ const RechargeCard = ({
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Col>
|
||||
{payMethods && payMethods.filter(m => m.type !== 'waffo').length > 0 && (
|
||||
{nonWaffoPayMethods.length > 0 && (
|
||||
<Col xs={24} sm={24} md={24} lg={14} xl={14}>
|
||||
<Form.Slot label={t('选择支付方式')}>
|
||||
<Space wrap>
|
||||
{payMethods.filter(m => m.type !== 'waffo').map((payMethod) => {
|
||||
{nonWaffoPayMethods.map((payMethod) => {
|
||||
const minTopupVal = Number(payMethod.min_topup) || 0;
|
||||
const isStripe = payMethod.type === 'stripe';
|
||||
const disabled =
|
||||
@@ -366,22 +381,18 @@ const RechargeCard = ({
|
||||
label={
|
||||
<div className='flex items-center gap-2'>
|
||||
<span>{t('选择充值额度')}</span>
|
||||
{(() => {
|
||||
const { symbol, rate, type } = getCurrencyConfig();
|
||||
if (type === 'USD') return null;
|
||||
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
color: 'var(--semi-color-text-2)',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'normal',
|
||||
}}
|
||||
>
|
||||
(1 $ = {rate.toFixed(2)} {symbol})
|
||||
</span>
|
||||
);
|
||||
})()}
|
||||
{currencyConfig.type !== 'USD' && (
|
||||
<span
|
||||
style={{
|
||||
color: 'var(--semi-color-text-2)',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'normal',
|
||||
}}
|
||||
>
|
||||
(1 ¥ = {currencyConfig.rate.toFixed(2)}{' '}
|
||||
{currencyConfig.symbol})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
@@ -396,15 +407,7 @@ const RechargeCard = ({
|
||||
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) { }
|
||||
const { symbol, rate, type } = currencyConfig;
|
||||
|
||||
let displayValue = preset.value; // 显示的数量
|
||||
let displayActualPay = actualPay;
|
||||
@@ -412,16 +415,16 @@ const RechargeCard = ({
|
||||
|
||||
if (type === 'USD') {
|
||||
// 数量保持USD,价格从CNY转USD
|
||||
displayActualPay = actualPay / usdRate;
|
||||
displaySave = save / usdRate;
|
||||
displayActualPay = actualPay / usdExchangeRate;
|
||||
displaySave = save / usdExchangeRate;
|
||||
} else if (type === 'CNY') {
|
||||
// 数量转CNY,价格已是CNY
|
||||
displayValue = preset.value * usdRate;
|
||||
displayValue = preset.value * usdExchangeRate;
|
||||
} else if (type === 'CUSTOM') {
|
||||
// 数量和价格都转自定义货币
|
||||
displayValue = preset.value * rate;
|
||||
displayActualPay = (actualPay / usdRate) * rate;
|
||||
displaySave = (save / usdRate) * rate;
|
||||
displayActualPay = (actualPay / usdExchangeRate) * rate;
|
||||
displaySave = (save / usdExchangeRate) * rate;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -540,7 +543,7 @@ const RechargeCard = ({
|
||||
{t('充值额度')}: {product.quota}
|
||||
</div>
|
||||
<div className='text-lg font-semibold text-blue-600'>
|
||||
{product.currency === 'EUR' ? '€' : '$'}
|
||||
{product.currency === 'EUR' ? '€' : '¥'}
|
||||
{product.price}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user