'use client'; import { useSearchParams } from 'next/navigation'; import { useEffect, useState, Suspense } from 'react'; import { applyLocaleToSearchParams, pickLocaleText, resolveLocale, type Locale } from '@/lib/locale'; import type { PublicOrderStatusSnapshot } from '@/lib/order/status'; import { buildOrderStatusUrl } from '@/lib/order/status-url'; type WindowWithAlipayBridge = Window & { AlipayJSBridge?: { call: (name: string, params?: unknown, callback?: (...args: unknown[]) => void) => void; }; }; function tryCloseViaAlipayBridge(): boolean { const bridge = (window as WindowWithAlipayBridge).AlipayJSBridge; if (!bridge?.call) { return false; } try { bridge.call('closeWebview'); return true; } catch { return false; } } function closeCurrentWindow() { if (tryCloseViaAlipayBridge()) { return; } let settled = false; const handleBridgeReady = () => { if (settled) { return; } settled = true; document.removeEventListener('AlipayJSBridgeReady', handleBridgeReady); if (!tryCloseViaAlipayBridge()) { window.close(); } }; document.addEventListener('AlipayJSBridgeReady', handleBridgeReady, { once: true }); window.setTimeout(() => { if (settled) { return; } settled = true; document.removeEventListener('AlipayJSBridgeReady', handleBridgeReady); window.close(); }, 250); } function getStatusConfig( order: PublicOrderStatusSnapshot | null, locale: Locale, hasAccessToken: boolean, isDark = false, ) { if (!order) { return locale === 'en' ? { label: 'Payment Error', color: isDark ? 'text-red-400' : 'text-red-600', icon: '✗', message: hasAccessToken ? 'Unable to load the order status. Please try again later.' : 'Missing order access token. Please go back to the recharge page.', } : { label: '支付异常', color: isDark ? 'text-red-400' : 'text-red-600', icon: '✗', message: hasAccessToken ? '未查询到订单状态,请稍后重试。' : '订单访问凭证缺失,请返回原充值页查看订单结果。', }; } if (order.rechargeSuccess) { return locale === 'en' ? { label: 'Recharge Successful', color: isDark ? 'text-green-400' : 'text-green-600', icon: '✓', message: 'Your balance has been credited successfully.', } : { label: '充值成功', color: isDark ? 'text-green-400' : 'text-green-600', icon: '✓', message: '余额已成功到账!', }; } if (order.paymentSuccess) { if (order.rechargeStatus === 'paid_pending' || order.rechargeStatus === 'recharging') { return locale === 'en' ? { label: 'Top-up Processing', color: isDark ? 'text-blue-400' : 'text-blue-600', icon: '⟳', message: 'Payment succeeded, and the balance top-up is being processed.', } : { label: '充值处理中', color: isDark ? 'text-blue-400' : 'text-blue-600', icon: '⟳', message: '支付成功,余额正在充值中...', }; } if (order.rechargeStatus === 'failed') { return locale === 'en' ? { label: 'Payment Successful', color: isDark ? 'text-amber-400' : 'text-amber-600', icon: '!', message: 'Payment succeeded, but the balance top-up has not completed yet. Please check again later or contact the administrator.', } : { label: '支付成功', color: isDark ? 'text-amber-400' : 'text-amber-600', icon: '!', message: '支付成功,但余额充值暂未完成,请稍后查看订单结果或联系管理员。', }; } } if (order.status === 'PENDING') { return locale === 'en' ? { label: 'Awaiting Payment', color: isDark ? 'text-yellow-400' : 'text-yellow-600', icon: '⏳', message: 'The order has not been paid yet.', } : { label: '等待支付', color: isDark ? 'text-yellow-400' : 'text-yellow-600', icon: '⏳', message: '订单尚未完成支付。', }; } if (order.status === 'EXPIRED') { return locale === 'en' ? { label: 'Order Expired', color: isDark ? 'text-slate-400' : 'text-gray-500', icon: '⏰', message: 'This order has expired. Please create a new order.', } : { label: '订单已超时', color: isDark ? 'text-slate-400' : 'text-gray-500', icon: '⏰', message: '订单已超时,请重新充值。', }; } if (order.status === 'CANCELLED') { return locale === 'en' ? { label: 'Order Cancelled', color: isDark ? 'text-slate-400' : 'text-gray-500', icon: '✗', message: 'This order has been cancelled.', } : { label: '订单已取消', color: isDark ? 'text-slate-400' : 'text-gray-500', icon: '✗', message: '订单已被取消。', }; } return locale === 'en' ? { label: 'Payment Error', color: isDark ? 'text-red-400' : 'text-red-600', icon: '✗', message: 'Please contact the administrator.', } : { label: '支付异常', color: isDark ? 'text-red-400' : 'text-red-600', icon: '✗', message: '请联系管理员处理。' }; } function ResultContent() { const searchParams = useSearchParams(); const outTradeNo = searchParams.get('out_trade_no') || searchParams.get('order_id'); const accessToken = searchParams.get('access_token'); const isPopup = searchParams.get('popup') === '1'; const theme = searchParams.get('theme') === 'dark' ? 'dark' : 'light'; const locale = resolveLocale(searchParams.get('lang')); const isDark = theme === 'dark'; const text = { checking: pickLocaleText(locale, '查询支付结果中...', 'Checking payment result...'), back: pickLocaleText(locale, '返回', 'Back'), closeSoon: pickLocaleText(locale, '此窗口将在 3 秒后自动关闭', 'This window will close automatically in 3 seconds'), closeNow: pickLocaleText(locale, '立即关闭窗口', 'Close now'), orderId: pickLocaleText(locale, '订单号', 'Order ID'), unknown: pickLocaleText(locale, '未知', 'Unknown'), }; const [orderState, setOrderState] = useState(null); const [loading, setLoading] = useState(true); const [isInPopup, setIsInPopup] = useState(false); useEffect(() => { if (isPopup || window.opener) { setIsInPopup(true); } }, [isPopup]); useEffect(() => { if (!outTradeNo || !accessToken || accessToken.length < 10) { setLoading(false); return; } const checkOrder = async () => { try { const res = await fetch(buildOrderStatusUrl(outTradeNo, accessToken)); if (res.ok) { const data = (await res.json()) as PublicOrderStatusSnapshot; setOrderState(data); } } catch { } finally { setLoading(false); } }; checkOrder(); const timer = setInterval(checkOrder, 3000); const timeout = setTimeout(() => clearInterval(timer), 30000); return () => { clearInterval(timer); clearTimeout(timeout); }; }, [outTradeNo, accessToken]); const shouldAutoClose = Boolean(orderState?.paymentSuccess); const goBack = () => { if (isInPopup) { closeCurrentWindow(); return; } if (window.history.length > 1) { window.history.back(); return; } const params = new URLSearchParams(); params.set('theme', theme); applyLocaleToSearchParams(params, locale); window.location.replace(`/pay?${params.toString()}`); }; useEffect(() => { if (!isInPopup || !shouldAutoClose) return; const timer = setTimeout(() => { closeCurrentWindow(); }, 3000); return () => clearTimeout(timer); }, [isInPopup, shouldAutoClose]); if (loading) { return (
{text.checking}
); } const display = getStatusConfig(orderState, locale, Boolean(accessToken), isDark); return (
{display.icon}

{display.label}

{display.message}

{isInPopup ? ( shouldAutoClose && (

{text.closeSoon}

) ) : ( )}

{text.orderId}: {outTradeNo || text.unknown}

); } function ResultPageFallback() { const searchParams = useSearchParams(); const locale = resolveLocale(searchParams.get('lang')); const isDark = searchParams.get('theme') === 'dark'; return (
{pickLocaleText(locale, '加载中...', 'Loading...')}
); } export default function PayResultPage() { return ( }> ); }