'use client'; import { useState } from 'react'; interface PaymentFormProps { userId: number; userName?: string; userBalance?: number; enabledPaymentTypes: string[]; minAmount: number; maxAmount: number; onSubmit: (amount: number, paymentType: string) => Promise; loading?: boolean; dark?: boolean; } const QUICK_AMOUNTS = [10, 20, 50, 100, 200, 500]; const AMOUNT_TEXT_PATTERN = /^\d*(\.\d{0,2})?$/; function hasValidCentPrecision(num: number): boolean { return Math.abs(Math.round(num * 100) - num * 100) < 1e-8; } export default function PaymentForm({ userId, userName, userBalance, enabledPaymentTypes, minAmount, maxAmount, onSubmit, loading, dark = false, }: PaymentFormProps) { const [amount, setAmount] = useState(''); const [paymentType, setPaymentType] = useState(enabledPaymentTypes[0] || 'alipay'); const [customAmount, setCustomAmount] = useState(''); const handleQuickAmount = (val: number) => { setAmount(val); setCustomAmount(String(val)); }; const handleCustomAmountChange = (val: string) => { if (!AMOUNT_TEXT_PATTERN.test(val)) { return; } setCustomAmount(val); if (val === '') { setAmount(''); return; } const num = parseFloat(val); if (!isNaN(num) && num > 0 && hasValidCentPrecision(num)) { setAmount(num); } else { setAmount(''); } }; const selectedAmount = amount || 0; const isValid = selectedAmount >= minAmount && selectedAmount <= maxAmount && hasValidCentPrecision(selectedAmount); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!isValid || loading) return; await onSubmit(selectedAmount, paymentType); }; const isAlipay = (type: string) => type === 'alipay'; return (
{/* User Info */}
充值账户
{userName || `用户 #${userId}`}
{userBalance !== undefined && (
当前余额: {userBalance.toFixed(2)}
)}
{/* Quick Amount Selection */}
{QUICK_AMOUNTS.map((val) => ( ))}
{/* Custom Amount */}
¥ handleCustomAmountChange(e.target.value)} placeholder={`${minAmount} - ${maxAmount}`} className={[ 'w-full rounded-lg border py-3 pl-8 pr-4 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500', dark ? 'border-slate-700 bg-slate-900 text-slate-100' : 'border-gray-300 bg-white text-gray-900', ].join(' ')} />
{customAmount !== '' && !isValid && (
{'\u91D1\u989D\u9700\u5728\u8303\u56F4\u5185\uFF0C\u4E14\u6700\u591A\u652F\u6301 2 \u4F4D\u5C0F\u6570\uFF08\u7CBE\u786E\u5230\u5206\uFF09'}
)} {/* Payment Type */}
{enabledPaymentTypes.map((type) => ( ))}
{/* Submit */}
); }