import { useEffect, useRef, useState } from 'react' import QRCode from 'qrcode' import { createOrder, orderStatus } from '../lib/site-api' // 官网购买支付弹窗:下单 → 微信 code_url 画二维码 → 轮询单态。 // 复用后端支付链路(下单/回调/查单/掉单补偿全共用),与桌面端/联调台同一套。 const POLL_MS = 2500 type Phase = 'creating' | 'waiting' | 'paid' | 'expired' export function PayDialog({ item, onClose, }: { item: { kind: 'sub' | 'pack'; id: string; name: string; priceFen: number } onClose: (paid: boolean) => void }) { const [qr, setQr] = useState('') const [phase, setPhase] = useState('creating') const [err, setErr] = useState('') const [warn, setWarn] = useState('') const orderRef = useRef('') useEffect(() => { let alive = true let timer: number | null = null void (async () => { try { const o = await createOrder(item.kind === 'sub' ? { planId: item.id } : { packId: item.id }) if (!alive) return orderRef.current = o.order_id setQr(await QRCode.toDataURL(o.code_url, { width: 220, margin: 1 })) setPhase('waiting') const tick = async () => { if (!alive) return try { const s = await orderStatus(orderRef.current) if (!alive) return setWarn(s.warn ?? '') if (s.status === 'paid') { setPhase('paid') window.setTimeout(() => onClose(true), 900) return } if (s.status === 'expired' || s.status === 'failed') { setPhase('expired') return } } catch { /* 单次失败忽略 */ } timer = window.setTimeout(() => void tick(), POLL_MS) } timer = window.setTimeout(() => void tick(), POLL_MS) } catch (e) { if (alive) setErr((e as Error).message) } })() return () => { alive = false if (timer) window.clearTimeout(timer) } }, [item, onClose]) return (
onClose(phase === 'paid')}>
e.stopPropagation()}>

微信支付 · {item.name}

{err ? (

{err}

) : phase === 'creating' ? (

正在生成支付二维码…

) : ( <>
微信支付二维码 {(phase === 'paid' || phase === 'expired') && (
{phase === 'paid' ? '✅ 支付成功' : '二维码已失效'}
)}
¥{(item.priceFen / 100).toFixed(2)}
{phase === 'waiting' &&
微信扫一扫完成支付
}
)} {warn &&

{warn}

}
) }