From d43b04cb5c02032453957366945548666ea56c8d Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 7 Mar 2026 04:16:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=89=8D=E7=AB=AF=E6=9A=97=E8=89=B2?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E8=A1=A5=E5=85=A8=E3=80=81Unicode=20?= =?UTF-8?q?=E5=8F=AF=E8=AF=BB=E5=8C=96=E3=80=81UI=20=E4=BC=98=E5=8C=96=201?= =?UTF-8?q?2=20=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PaymentQRCode 13 处 Unicode 转义替换为可读中文 - RefundDialog 完整暗色模式 + Escape 键关闭 - PayResult 页面添加暗色模式支持 - OrderStatus 使用 dark prop 调整样式 - PaymentForm 选中态暗色对比度修复 - OrderDetail 英文标签改中文 + Escape 键 - Pay 页面错误提示暗色适配 - 倒计时最后 60 秒脉动提醒 - 全局 CSS 添加中文字体栈 - MobileOrderList HTML 实体替换 Co-Authored-By: Claude Opus 4.6 --- src/app/globals.css | 1 + src/app/pay/page.tsx | 11 ++++- src/app/pay/result/page.tsx | 29 +++++++++---- src/app/pay/stripe-popup/page.tsx | 10 ++--- src/components/MobileOrderList.tsx | 2 +- src/components/OrderStatus.tsx | 7 +++- src/components/PaymentForm.tsx | 4 +- src/components/PaymentQRCode.tsx | 49 +++++++++++++--------- src/components/admin/OrderDetail.tsx | 15 +++++-- src/components/admin/RefundDialog.tsx | 59 +++++++++++++++++++++------ 10 files changed, 132 insertions(+), 55 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index bd08704..a346e3a 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -8,4 +8,5 @@ body { background: var(--background); color: var(--foreground); + font-family: system-ui, -apple-system, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; } diff --git a/src/app/pay/page.tsx b/src/app/pay/page.tsx index 8ac006d..4494832 100644 --- a/src/app/pay/page.tsx +++ b/src/app/pay/page.tsx @@ -346,7 +346,16 @@ function PayContent() { ) : undefined } > - {error &&
{error}
} + {error && ( +
+ {error} +
+ )} {step === 'form' && isMobile && (
(null); const [loading, setLoading] = useState(true); @@ -64,8 +66,8 @@ function ResultContent() { if (loading) { return ( -
-
查询支付结果中...
+
+
查询支付结果中...
); } @@ -73,20 +75,27 @@ function ResultContent() { const isPending = status === 'PENDING'; return ( -
-
+
+
{isSuccess ? ( <>

{status === 'COMPLETED' ? '充值成功' : '充值处理中'}

-

+

{status === 'COMPLETED' ? '余额已成功到账!' : '支付成功,余额正在充值中...'}

{isInPopup && (
-

此窗口将在 3 秒后自动关闭

+

+ 此窗口将在 3 秒后自动关闭 +

); diff --git a/src/app/pay/stripe-popup/page.tsx b/src/app/pay/stripe-popup/page.tsx index 87fbff3..33910fb 100644 --- a/src/app/pay/stripe-popup/page.tsx +++ b/src/app/pay/stripe-popup/page.tsx @@ -177,14 +177,14 @@ function StripePopupContent() { >
- {'\u00A5'} + {'¥'} {amount.toFixed(2)}

订单号: {orderId}

{stripeError ? (
-
{stripeError}
+
{stripeError}
diff --git a/src/components/PaymentForm.tsx b/src/components/PaymentForm.tsx index e6e650b..0a72c89 100644 --- a/src/components/PaymentForm.tsx +++ b/src/components/PaymentForm.tsx @@ -258,7 +258,7 @@ export default function PaymentForm({ ? 'cursor-not-allowed border-slate-700 bg-slate-800/50 opacity-50' : 'cursor-not-allowed border-gray-200 bg-gray-50 opacity-50' : isSelected - ? `${meta?.selectedBorder || 'border-blue-500'} ${meta?.selectedBg || 'bg-blue-50'} text-slate-900 shadow-sm` + ? `${meta?.selectedBorder || 'border-blue-500'} ${meta?.selectedBg || 'bg-blue-50'} ${dark ? 'text-slate-100' : 'text-slate-900'} shadow-sm` : dark ? 'border-slate-700 bg-slate-900 text-slate-200 hover:border-slate-500' : 'border-gray-300 bg-white text-slate-700 hover:border-gray-400', @@ -272,7 +272,7 @@ export default function PaymentForm({ 今日额度已满 ) : meta?.sublabel ? ( {meta.sublabel} diff --git a/src/components/PaymentQRCode.tsx b/src/components/PaymentQRCode.tsx index ce5452d..46a8fe8 100644 --- a/src/components/PaymentQRCode.tsx +++ b/src/components/PaymentQRCode.tsx @@ -28,14 +28,13 @@ interface PaymentQRCodeProps { isMobile?: boolean; } -const TEXT_EXPIRED = '\u8BA2\u5355\u5DF2\u8D85\u65F6'; -const TEXT_REMAINING = '\u5269\u4F59\u652F\u4ED8\u65F6\u95F4'; -const TEXT_GO_PAY = '\u70B9\u51FB\u524D\u5F80\u652F\u4ED8'; -const TEXT_SCAN_PAY = '\u8BF7\u4F7F\u7528\u652F\u4ED8\u5E94\u7528\u626B\u7801\u652F\u4ED8'; -const TEXT_BACK = '\u8FD4\u56DE'; -const TEXT_CANCEL_ORDER = '\u53D6\u6D88\u8BA2\u5355'; -const TEXT_H5_HINT = - '\u652F\u4ED8\u5B8C\u6210\u540E\u8BF7\u8FD4\u56DE\u6B64\u9875\u9762\uFF0C\u7CFB\u7EDF\u5C06\u81EA\u52A8\u786E\u8BA4'; +const TEXT_EXPIRED = '订单已超时'; +const TEXT_REMAINING = '剩余支付时间'; +const TEXT_GO_PAY = '点击前往支付'; +const TEXT_SCAN_PAY = '请使用支付应用扫码支付'; +const TEXT_BACK = '返回'; +const TEXT_CANCEL_ORDER = '取消订单'; +const TEXT_H5_HINT = '支付完成后请返回此页面,系统将自动确认'; export default function PaymentQRCode({ orderId, @@ -57,6 +56,7 @@ export default function PaymentQRCode({ const displayAmount = payAmountProp ?? amount; const hasFeeDiff = payAmountProp !== undefined && payAmountProp !== amount; const [timeLeft, setTimeLeft] = useState(''); + const [timeLeftSeconds, setTimeLeftSeconds] = useState(Infinity); const [expired, setExpired] = useState(false); const [qrDataUrl, setQrDataUrl] = useState(''); const [imageLoading, setImageLoading] = useState(false); @@ -264,13 +264,16 @@ export default function PaymentQRCode({ if (diff <= 0) { setTimeLeft(TEXT_EXPIRED); + setTimeLeftSeconds(0); setExpired(true); return; } + const totalSeconds = Math.floor(diff / 1000); const minutes = Math.floor(diff / 60000); const seconds = Math.floor((diff % 60000) / 1000); setTimeLeft(`${minutes}:${seconds.toString().padStart(2, '0')}`); + setTimeLeftSeconds(totalSeconds); }; updateTimer(); @@ -340,18 +343,16 @@ export default function PaymentQRCode({ if (cancelBlocked) { return (
-
{'\u2713'}
-

{'\u8BA2\u5355\u5DF2\u652F\u4ED8'}

+
{'✓'}
+

{'订单已支付'}

- { - '\u8BE5\u8BA2\u5355\u5DF2\u652F\u4ED8\u5B8C\u6210\uFF0C\u65E0\u6CD5\u53D6\u6D88\u3002\u5145\u503C\u5C06\u81EA\u52A8\u5230\u8D26\u3002' - } + {'该订单已支付完成,无法取消。充值将自动到账。'}

); @@ -361,7 +362,7 @@ export default function PaymentQRCode({
- {'\u00A5'} + {'¥'} {displayAmount.toFixed(2)}
{hasFeeDiff && ( @@ -369,7 +370,7 @@ export default function PaymentQRCode({ 到账 ¥{amount.toFixed(2)}
)} -
+
{expired ? TEXT_EXPIRED : `${TEXT_REMAINING}: ${timeLeft}`}
@@ -397,7 +398,10 @@ export default function PaymentQRCode({
) : stripeError && !stripeLib ? ( -
{stripeError}
+
{stripeError}
) : ( <>
-
{'\u2713'}
+
{'✓'}

支付成功,正在处理订单...

@@ -514,7 +518,7 @@ export default function PaymentQRCode({ )}

- {`\u8BF7\u6253\u5F00${channelLabel}\u626B\u4E00\u626B\u5B8C\u6210\u652F\u4ED8`} + {`请打开${channelLabel}扫一扫完成支付`}

)} @@ -536,7 +540,12 @@ export default function PaymentQRCode({ {!expired && token && ( diff --git a/src/components/admin/OrderDetail.tsx b/src/components/admin/OrderDetail.tsx index b9e0901..e76096b 100644 --- a/src/components/admin/OrderDetail.tsx +++ b/src/components/admin/OrderDetail.tsx @@ -1,5 +1,6 @@ 'use client'; +import { useEffect } from 'react'; import { getPaymentDisplayInfo } from '@/lib/pay-utils'; interface AuditLog { @@ -45,6 +46,14 @@ interface OrderDetailProps { } export default function OrderDetail({ order, onClose, dark }: OrderDetailProps) { + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose(); + }; + document.addEventListener('keydown', handleKeyDown); + return () => document.removeEventListener('keydown', handleKeyDown); + }, [onClose]); + const fields = [ { label: '订单号', value: order.id }, { label: '用户ID', value: order.userId }, @@ -52,9 +61,9 @@ export default function OrderDetail({ order, onClose, dark }: OrderDetailProps) { label: '邮箱', value: order.userEmail || '-' }, { label: '金额', value: `¥${order.amount.toFixed(2)}` }, { label: '状态', value: order.status }, - { label: 'Payment OK', value: order.paymentSuccess ? 'yes' : 'no' }, - { label: 'Recharge OK', value: order.rechargeSuccess ? 'yes' : 'no' }, - { label: 'Recharge Status', value: order.rechargeStatus || '-' }, + { label: '支付成功', value: order.paymentSuccess ? 'yes' : 'no' }, + { label: '充值成功', value: order.rechargeSuccess ? 'yes' : 'no' }, + { label: '充值状态', value: order.rechargeStatus || '-' }, { label: '支付渠道', value: getPaymentDisplayInfo(order.paymentType).channel }, { label: '提供商', value: getPaymentDisplayInfo(order.paymentType).provider || '-' }, { label: '充值码', value: order.rechargeCode }, diff --git a/src/components/admin/RefundDialog.tsx b/src/components/admin/RefundDialog.tsx index a50676b..8a6974a 100644 --- a/src/components/admin/RefundDialog.tsx +++ b/src/components/admin/RefundDialog.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; interface RefundDialogProps { orderId: string; @@ -9,6 +9,7 @@ interface RefundDialogProps { onCancel: () => void; warning?: string; requireForce?: boolean; + dark?: boolean; } export default function RefundDialog({ @@ -18,11 +19,20 @@ export default function RefundDialog({ onCancel, warning, requireForce, + dark = false, }: RefundDialogProps) { const [reason, setReason] = useState(''); const [force, setForce] = useState(false); const [loading, setLoading] = useState(false); + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') onCancel(); + }; + document.addEventListener('keydown', handleKeyDown); + return () => document.removeEventListener('keydown', handleKeyDown); + }, [onCancel]); + const handleConfirm = async () => { setLoading(true); try { @@ -34,30 +44,50 @@ export default function RefundDialog({ return (
-
e.stopPropagation()}> -

确认退款

+
e.stopPropagation()} + > +

确认退款

-
-
订单号
+
+
订单号
{orderId}
-
-
退款金额
+
+
退款金额
¥{amount.toFixed(2)}
- {warning &&
{warning}
} + {warning && ( +
+ {warning} +
+ )}
- + setReason(e.target.value)} placeholder="请输入退款原因(可选)" - className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:border-blue-500 focus:outline-none" + className={[ + 'w-full rounded-lg border px-3 py-2 text-sm focus:border-blue-500 focus:outline-none', + dark ? 'border-slate-600 bg-slate-800 text-slate-100' : 'border-gray-300 bg-white text-gray-900', + ].join(' ')} />
@@ -67,7 +97,7 @@ export default function RefundDialog({ type="checkbox" checked={force} onChange={(e) => setForce(e.target.checked)} - className="rounded border-gray-300" + className={['rounded', dark ? 'border-slate-600' : 'border-gray-300'].join(' ')} /> 强制退款(余额可能扣为负数) @@ -77,7 +107,12 @@ export default function RefundDialog({