'use client'; import { useEffect, useState, useRef } from 'react'; import QRCode from 'qrcode'; import { apiFetch } from '@/lib/auth'; import { isWeChatBrowser } from '@/lib/wechat'; import { useT } from '@/i18n'; interface PayResult { gatewayOrderId?: string; payUrl?: string; qrcode?: string; codeUrl?: string; redirectUrl?: string; status?: string; } interface Props { open: boolean; orderNo: string; payResult: PayResult; payChannel: 'wxpay' | 'alipay'; onPaid: () => void; onClose: () => void; } export default function PaymentModal({ open, orderNo, payResult, payChannel, onPaid, onClose }: Props) { const t = useT(); const [status, setStatus] = useState<'pending' | 'paid' | 'failed'>('pending'); const [qrDataUrl, setQrDataUrl] = useState(''); const [message, setMessage] = useState(''); const pollingRef = useRef | null>(null); useEffect(() => { if (!open) { setStatus('pending'); setMessage(''); if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; } return; } const qrCode = payResult.qrcode || payResult.codeUrl; const redirectUrl = payResult.payUrl || payResult.redirectUrl; if (payChannel === 'alipay') { setMessage(t.member.alipayRedirect); if (redirectUrl && redirectUrl !== 'mock://pay') { window.open(redirectUrl, '_blank'); } startPolling(); return; } // WeChat NATIVE: render QR code if (qrCode) { QRCode.toDataURL(qrCode, { margin: 1, width: 280 }, (err, url) => { if (!err) setQrDataUrl(url); }); setMessage(t.member.scanQrCode); startPolling(); } // WeChat JSAPI in browser if (isWeChatBrowser() && payResult.gatewayOrderId) { setMessage(t.member.alipayRedirect); startPolling(); } }, [open, payChannel, payResult?.qrcode, payResult?.codeUrl, payResult?.payUrl]); function startPolling() { if (pollingRef.current) clearInterval(pollingRef.current); pollingRef.current = setInterval(async () => { try { const res = await apiFetch(`/payment/wxpay/query?outTradeNo=${orderNo}`); const data = await res.json(); const isPaid = data.trade_state === 'SUCCESS' || data.localStatus === 'PAID' || data.gatewayStatus === 'paid'; if (isPaid) { setStatus('paid'); setMessage(t.member.orderPaid); if (pollingRef.current) clearInterval(pollingRef.current); setTimeout(onPaid, 1500); } } catch {} }, 3000); } useEffect(() => { return () => { if (pollingRef.current) clearInterval(pollingRef.current); }; }, []); if (!open) return null; const title = payChannel === 'alipay' ? t.member.alipay : t.member.wechatPay; const qrCode = payResult.qrcode || payResult.codeUrl; return (
e.stopPropagation()}>

{title}

{payChannel === 'wxpay' && qrCode && (
{qrDataUrl ? ( 支付二维码 ) : (
)}
)} {payChannel === 'alipay' && status === 'pending' && (
💳

{t.member.alipayRedirect}

)} {status === 'paid' ? (

{message}

) : ( <>

{message}

{payChannel === 'alipay' && (payResult.payUrl || payResult.redirectUrl) && ( {t.member.openAlipay} )}
{t.member.waitingPay}
)}
); }