From 6fd986201957042fc766570aee1b3c65b8e1e497 Mon Sep 17 00:00:00 2001 From: JiaJun <2394389886@qq.com> Date: Fri, 10 Jul 2026 14:21:49 +0800 Subject: [PATCH] =?UTF-8?q?refactor(game):=20=E9=87=8D=E6=9E=84=E6=8F=90?= =?UTF-8?q?=E7=8E=B0=E5=8A=9F=E8=83=BD=E4=B8=AD=E7=9A=84=E9=92=BB=E7=9F=B3?= =?UTF-8?q?=E9=87=91=E9=A2=9D=E8=8C=83=E5=9B=B4=E8=AE=A1=E7=AE=97=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除硬编码的快速提现金额配置,改为动态计算钻石金额边界 - 添加新的辅助函数 getWithdrawDiamondBounds 和 getQuickWithdrawAmounts - 在桌面和移动端提现组件中调整钻石金额字段的位置 - 更新初始金额设置逻辑以使用新的钻石边界计算 - 优化快速金额选择卡片的ID生成方式,包含支付渠道和类型信息 - 添加对支付方法最小/最大金额限制的支持 --- .../components/desktop/desktop-withdraw.tsx | 112 +++++++------- .../components/mobile/mobile-withdraw.tsx | 106 ++++++------- src/hooks/use-withdraw-vm.ts | 139 ++++++++++++++---- 3 files changed, 219 insertions(+), 138 deletions(-) diff --git a/src/features/game/components/desktop/desktop-withdraw.tsx b/src/features/game/components/desktop/desktop-withdraw.tsx index 593a13a..00771ee 100644 --- a/src/features/game/components/desktop/desktop-withdraw.tsx +++ b/src/features/game/components/desktop/desktop-withdraw.tsx @@ -390,62 +390,6 @@ function DesktopWithdraw() { >
- - handleAmountChange(vm.amount - 1)} - onPlus={() => handleAmountChange(vm.amount + 1)} - /> - {hasSubmitted && vm.amountRequiredError ? ( -
- {t('gameDesktop.withdraw.errors.amountRequired')} -
- ) : null} - {hasSubmitted && vm.amountExceedsBalance ? ( -
- {t('gameDesktop.withdraw.errors.amountExceedsBalance')} -
- ) : null} - {hasSubmitted && vm.amountBelowPaymentMinimum ? ( -
- {t('gameDesktop.withdraw.errors.amountBelowPaymentMinimum', { - amount: vm.paymentMinimumAmountLabel, - })} -
- ) : null} - {hasSubmitted && vm.amountAbovePaymentMaximum ? ( -
- {t('gameDesktop.withdraw.errors.amountAbovePaymentMaximum', { - amount: vm.paymentMaximumAmountLabel, - })} -
- ) : null} -
- -
-
-
- {vm.quickAmounts.map((option) => ( - - handleQuickAmountSelect(option.id, option.diamonds) - } - /> - ))} -
-
- @@ -516,6 +460,62 @@ function DesktopWithdraw() {
+ + handleAmountChange(vm.amount - 1)} + onPlus={() => handleAmountChange(vm.amount + 1)} + /> + {hasSubmitted && vm.amountRequiredError ? ( +
+ {t('gameDesktop.withdraw.errors.amountRequired')} +
+ ) : null} + {hasSubmitted && vm.amountExceedsBalance ? ( +
+ {t('gameDesktop.withdraw.errors.amountExceedsBalance')} +
+ ) : null} + {hasSubmitted && vm.amountBelowPaymentMinimum ? ( +
+ {t('gameDesktop.withdraw.errors.amountBelowPaymentMinimum', { + amount: vm.paymentMinimumAmountLabel, + })} +
+ ) : null} + {hasSubmitted && vm.amountAbovePaymentMaximum ? ( +
+ {t('gameDesktop.withdraw.errors.amountAbovePaymentMaximum', { + amount: vm.paymentMaximumAmountLabel, + })} +
+ ) : null} +
+ +
+
+
+ {vm.quickAmounts.map((option) => ( + + handleQuickAmountSelect(option.id, option.diamonds) + } + /> + ))} +
+
+
- - handleAmountChange(vm.amount - 1)} - onPlus={() => handleAmountChange(vm.amount + 1)} - /> - {hasSubmitted && vm.amountRequiredError ? ( -
- {t('gameDesktop.withdraw.errors.amountRequired')} -
- ) : null} - {hasSubmitted && vm.amountExceedsBalance ? ( -
- {t('gameDesktop.withdraw.errors.amountExceedsBalance')} -
- ) : null} - {hasSubmitted && vm.amountBelowPaymentMinimum ? ( -
- {t('gameDesktop.withdraw.errors.amountBelowPaymentMinimum', { - amount: vm.paymentMinimumAmountLabel, - })} -
- ) : null} - {hasSubmitted && vm.amountAbovePaymentMaximum ? ( -
- {t('gameDesktop.withdraw.errors.amountAbovePaymentMaximum', { - amount: vm.paymentMaximumAmountLabel, - })} -
- ) : null} -
- -
- {vm.quickAmounts.map((option) => ( - - handleQuickAmountSelect(option.id, option.diamonds) - } - /> - ))} -
- @@ -500,6 +447,59 @@ function MobileWithdraw() {
+ + handleAmountChange(vm.amount - 1)} + onPlus={() => handleAmountChange(vm.amount + 1)} + /> + {hasSubmitted && vm.amountRequiredError ? ( +
+ {t('gameDesktop.withdraw.errors.amountRequired')} +
+ ) : null} + {hasSubmitted && vm.amountExceedsBalance ? ( +
+ {t('gameDesktop.withdraw.errors.amountExceedsBalance')} +
+ ) : null} + {hasSubmitted && vm.amountBelowPaymentMinimum ? ( +
+ {t('gameDesktop.withdraw.errors.amountBelowPaymentMinimum', { + amount: vm.paymentMinimumAmountLabel, + })} +
+ ) : null} + {hasSubmitted && vm.amountAbovePaymentMaximum ? ( +
+ {t('gameDesktop.withdraw.errors.amountAbovePaymentMaximum', { + amount: vm.paymentMaximumAmountLabel, + })} +
+ ) : null} +
+ +
+ {vm.quickAmounts.map((option) => ( + + handleQuickAmountSelect(option.id, option.diamonds) + } + /> + ))} +
+ diff --git a/src/hooks/use-withdraw-vm.ts b/src/hooks/use-withdraw-vm.ts index 24a2c36..9a73f1b 100644 --- a/src/hooks/use-withdraw-vm.ts +++ b/src/hooks/use-withdraw-vm.ts @@ -2,7 +2,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { DEFAULT_WITHDRAW_CONFIG, - QUICK_FIAT_AMOUNTS, WITHDRAW_EMAIL_PATTERN, WITHDRAW_PHONE_PATTERN, } from '@/constants' @@ -10,22 +9,76 @@ import { useDepositWithdrawConfig } from '@/hooks/use-deposit-withdraw-config' import { useAuthStore } from '@/store' import type { DepositWithdrawConfig } from '@/type' +const QUICK_WITHDRAW_OPTION_COUNT = 6 + +interface WithdrawDiamondBounds { + maximumDiamonds: number + minimumDiamonds: number +} + function formatNumber(locale: string, value: number) { return new Intl.NumberFormat(locale).format(value) } -function getInitialWithdrawAmount( +function getInitialWithdrawAmount(bounds: WithdrawDiamondBounds | null) { + return bounds?.minimumDiamonds ?? 0 +} + +function getWithdrawDiamondBounds( selectedExchangeRate: number, maxWithdrawAmount: number, -) { - if (maxWithdrawAmount <= 0) { - return 0 + minimumFiatAmount: number | null, + maximumFiatAmount: number | null, +): WithdrawDiamondBounds | null { + if (selectedExchangeRate <= 0 || maxWithdrawAmount <= 0) { + return null } - return Math.min( - maxWithdrawAmount, - Math.max(1, Math.round(QUICK_FIAT_AMOUNTS[0] / selectedExchangeRate)), + const minimumDiamonds = Math.max( + 1, + minimumFiatAmount === null + ? 1 + : Math.ceil(minimumFiatAmount / selectedExchangeRate), ) + const methodMaximumDiamonds = + maximumFiatAmount === null + ? maxWithdrawAmount + : Math.floor(maximumFiatAmount / selectedExchangeRate) + const maximumDiamonds = Math.min(maxWithdrawAmount, methodMaximumDiamonds) + + if (maximumDiamonds < minimumDiamonds) { + return null + } + + return { + maximumDiamonds, + minimumDiamonds, + } +} + +function getQuickWithdrawAmounts(bounds: WithdrawDiamondBounds) { + const { maximumDiamonds, minimumDiamonds } = bounds + const availableOptionCount = maximumDiamonds - minimumDiamonds + 1 + + if (availableOptionCount <= QUICK_WITHDRAW_OPTION_COUNT) { + return Array.from( + { length: availableOptionCount }, + (_, index) => minimumDiamonds + index, + ) + } + + const amounts = new Set([minimumDiamonds, maximumDiamonds]) + const span = maximumDiamonds - minimumDiamonds + + for (let index = 1; index < QUICK_WITHDRAW_OPTION_COUNT - 1; index += 1) { + amounts.add( + Math.round( + minimumDiamonds + (span * index) / (QUICK_WITHDRAW_OPTION_COUNT - 1), + ), + ) + } + + return [...amounts].sort((left, right) => left - right) } function getCurrencyExchangeRate( @@ -170,6 +223,21 @@ export function useWithdrawVm() { const selectedPaymentMaximumAmount = selectedPaymentMethod ? toOptionalNumber(selectedPaymentMethod.maximumAmount) : null + const withdrawDiamondBounds = useMemo( + () => + getWithdrawDiamondBounds( + selectedExchangeRate, + maxWithdrawAmount, + selectedPaymentMinimumAmount, + selectedPaymentMaximumAmount, + ), + [ + maxWithdrawAmount, + selectedExchangeRate, + selectedPaymentMaximumAmount, + selectedPaymentMinimumAmount, + ], + ) const amountBelowPaymentMinimum = amount > 0 && selectedPaymentMinimumAmount !== null && @@ -274,13 +342,11 @@ export function useWithdrawVm() { }, [bankCode, sortedBanks]) useEffect(() => { - if (!hasInitializedAmount && selectedExchangeRate > 0) { - setAmount( - getInitialWithdrawAmount(selectedExchangeRate, maxWithdrawAmount), - ) + if (!hasInitializedAmount && withdrawDiamondBounds) { + setAmount(getInitialWithdrawAmount(withdrawDiamondBounds)) setHasInitializedAmount(true) } - }, [hasInitializedAmount, maxWithdrawAmount, selectedExchangeRate, setAmount]) + }, [hasInitializedAmount, setAmount, withdrawDiamondBounds]) useEffect(() => { if (amount > maxWithdrawAmount) { @@ -289,19 +355,26 @@ export function useWithdrawVm() { }, [amount, maxWithdrawAmount, setAmount]) const quickAmounts = useMemo(() => { - if (!selectedCurrency || selectedExchangeRate <= 0) { + if (!selectedCurrency || !withdrawDiamondBounds) { return [] } - return QUICK_FIAT_AMOUNTS.map((fiatAmount) => ({ - diamonds: Math.min( - maxWithdrawAmount, - Math.max(1, Math.round(fiatAmount / selectedExchangeRate)), - ), - id: `quick-${selectedCurrency.code}-${fiatAmount}`, - preview: `${selectedCurrency.code} ${formatNumber(locale, fiatAmount)}`, + return getQuickWithdrawAmounts(withdrawDiamondBounds).map((diamonds) => ({ + diamonds, + id: `quick-${paymentChannelCode}-${paymentType}-${selectedCurrency.code}-${diamonds}`, + preview: `${selectedCurrency.code} ${formatNumber( + locale, + diamonds * selectedExchangeRate, + )}`, })) - }, [locale, maxWithdrawAmount, selectedCurrency, selectedExchangeRate]) + }, [ + locale, + paymentChannelCode, + paymentType, + selectedCurrency, + selectedExchangeRate, + withdrawDiamondBounds, + ]) const resetForm = useCallback(() => { const nextPaymentChannelCode = sortedPayChannels[0]?.code ?? '' @@ -311,6 +384,7 @@ export function useWithdrawVm() { ) ?? null const nextCurrency = getChannelCurrencies(config, nextPaymentChannel)[0] ?? null + const nextPaymentMethod = nextPaymentChannel?.methods[0] ?? null const nextExchangeRate = nextCurrency ? getCurrencyExchangeRate( config, @@ -318,16 +392,23 @@ export function useWithdrawVm() { nextCurrency.withdrawCoinsPerFiatValue || 1, ) : 0 - - setAmountState( - nextExchangeRate > 0 - ? getInitialWithdrawAmount(nextExchangeRate, maxWithdrawAmount) - : 0, + const nextWithdrawDiamondBounds = getWithdrawDiamondBounds( + nextExchangeRate, + maxWithdrawAmount, + nextPaymentMethod + ? toOptionalNumber(nextPaymentMethod.minimumAmount) + : null, + nextPaymentMethod + ? toOptionalNumber(nextPaymentMethod.maximumAmount) + : null, ) - setHasInitializedAmount(true) + const nextAmount = getInitialWithdrawAmount(nextWithdrawDiamondBounds) + + setAmountState(nextAmount) + setHasInitializedAmount(nextAmount > 0) setCurrencyCode(nextCurrency?.code ?? '') setPaymentChannelCode(nextPaymentChannelCode) - setPaymentType(nextPaymentChannel?.methods[0]?.code ?? '') + setPaymentType(nextPaymentMethod?.code ?? '') setBankCode('') setHolderName('') setBankAccount('')