'use client'; import { useSearchParams } from 'next/navigation'; import { Suspense, useEffect, useMemo, useState } from 'react'; interface UserInfo { id?: number; username: string; balance: number; } interface MyOrder { id: string; amount: number; status: string; paymentType: string; createdAt: string; } type OrderStatusFilter = 'ALL' | 'PENDING' | 'PAID' | 'COMPLETED' | 'CANCELLED' | 'EXPIRED' | 'FAILED'; const STATUS_TEXT_MAP: Record = { PENDING: '待支付', PAID: '已支付', RECHARGING: '充值中', COMPLETED: '已完成', EXPIRED: '已超时', CANCELLED: '已取消', FAILED: '失败', REFUNDING: '退款中', REFUNDED: '已退款', REFUND_FAILED: '退款失败', }; const FILTER_OPTIONS: { key: OrderStatusFilter; label: string }[] = [ { key: 'ALL', label: '全部' }, { key: 'PENDING', label: '待支付' }, { key: 'COMPLETED', label: '已完成' }, { key: 'CANCELLED', label: '已取消' }, { key: 'EXPIRED', label: '已超时' }, ]; function detectDeviceIsMobile(): boolean { if (typeof window === 'undefined') return false; const ua = navigator.userAgent || ''; const mobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Windows Phone|Mobile/i.test(ua); const smallPhysicalScreen = Math.min(window.screen.width, window.screen.height) <= 768; const touchCapable = navigator.maxTouchPoints > 1; return mobileUA || (touchCapable && smallPhysicalScreen); } function OrdersContent() { const searchParams = useSearchParams(); const userId = Number(searchParams.get('user_id')); const token = (searchParams.get('token') || '').trim(); const theme = searchParams.get('theme') === 'dark' ? 'dark' : 'light'; const uiMode = searchParams.get('ui_mode') || 'standalone'; const isDark = theme === 'dark'; const [isIframeContext, setIsIframeContext] = useState(true); const [isMobile, setIsMobile] = useState(false); const [userInfo, setUserInfo] = useState(null); const [orders, setOrders] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [activeFilter, setActiveFilter] = useState('ALL'); const [resolvedUserId, setResolvedUserId] = useState(null); const isEmbedded = uiMode === 'embedded' && isIframeContext; const hasToken = token.length > 0; const effectiveUserId = resolvedUserId || userId; useEffect(() => { if (typeof window === 'undefined') return; setIsIframeContext(window.self !== window.top); setIsMobile(detectDeviceIsMobile()); }, []); const buildMobilePayOrdersTabUrl = () => { const params = new URLSearchParams(); if (userId && !Number.isNaN(userId)) params.set('user_id', String(userId)); if (token) params.set('token', token); params.set('theme', theme); params.set('ui_mode', uiMode); params.set('tab', 'orders'); return `/pay?${params.toString()}`; }; useEffect(() => { if (!isMobile || isEmbedded || typeof window === 'undefined') return; window.location.replace(buildMobilePayOrdersTabUrl()); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isMobile, isEmbedded, userId, token, theme, uiMode]); const loadOrders = async () => { setLoading(true); setError(''); try { if (!userId || Number.isNaN(userId) || userId <= 0) { setError('无效的用户 ID'); setOrders([]); return; } if (!hasToken) { const res = await fetch(`/api/users/${userId}`); if (res.ok) { const data = await res.json(); setUserInfo({ id: userId, username: (typeof data.displayName === 'string' && data.displayName.trim()) || (typeof data.username === 'string' && data.username.trim()) || (typeof data.email === 'string' && data.email.trim()) || `用户 #${userId}`, balance: typeof data.balance === 'number' ? data.balance : 0, }); } setOrders([]); setError('当前链接未携带登录 token,无法查询“我的订单”。'); return; } const meRes = await fetch(`/api/orders/my?token=${encodeURIComponent(token)}`); if (!meRes.ok) { if (meRes.status === 401) { setError('登录态已失效,请从 Sub2API 重新进入支付页。'); } else { setError('订单加载失败,请稍后重试。'); } setOrders([]); return; } const meData = await meRes.json(); const meUser = meData.user || {}; const meId = Number(meUser.id); if (Number.isInteger(meId) && meId > 0) { setResolvedUserId(meId); } setUserInfo({ id: Number.isInteger(meId) && meId > 0 ? meId : userId, username: (typeof meUser.displayName === 'string' && meUser.displayName.trim()) || (typeof meUser.username === 'string' && meUser.username.trim()) || `用户 #${userId}`, balance: typeof meUser.balance === 'number' ? meUser.balance : 0, }); if (Array.isArray(meData.orders)) { setOrders(meData.orders); } else { setOrders([]); } } catch { setOrders([]); setError('网络错误,请稍后重试。'); } finally { setLoading(false); } }; useEffect(() => { if (isMobile && !isEmbedded) return; loadOrders(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [userId, token, isMobile, isEmbedded]); const filteredOrders = useMemo(() => { if (activeFilter === 'ALL') return orders; return orders.filter((item) => item.status === activeFilter); }, [orders, activeFilter]); const summary = useMemo(() => { const total = orders.length; const pending = orders.filter((item) => item.status === 'PENDING').length; const completed = orders.filter((item) => item.status === 'COMPLETED' || item.status === 'PAID').length; const failed = orders.filter((item) => ['FAILED', 'CANCELLED', 'EXPIRED'].includes(item.status)).length; return { total, pending, completed, failed }; }, [orders]); const formatStatus = (status: string) => STATUS_TEXT_MAP[status] || status; const formatCreatedAt = (value: string) => { const date = new Date(value); if (Number.isNaN(date.getTime())) return value; return date.toLocaleString(); }; const getStatusBadgeClass = (status: string) => { if (['COMPLETED', 'PAID'].includes(status)) { return isDark ? 'bg-emerald-500/20 text-emerald-200' : 'bg-emerald-100 text-emerald-700'; } if (status === 'PENDING') { return isDark ? 'bg-blue-500/20 text-blue-200' : 'bg-blue-100 text-blue-700'; } if (['CANCELLED', 'EXPIRED', 'FAILED'].includes(status)) { return isDark ? 'bg-slate-600 text-slate-200' : 'bg-slate-100 text-slate-700'; } return isDark ? 'bg-slate-700 text-slate-200' : 'bg-slate-100 text-slate-700'; }; const buildScopedUrl = (path: string) => { const params = new URLSearchParams(); if (effectiveUserId) params.set('user_id', String(effectiveUserId)); if (token) params.set('token', token); params.set('theme', theme); params.set('ui_mode', uiMode); return `${path}?${params.toString()}`; }; const payUrl = buildScopedUrl('/pay'); if (isMobile) { return (
正在切换到移动端订单 Tab...
); } if (!effectiveUserId || Number.isNaN(effectiveUserId) || effectiveUserId <= 0) { return (

无效的用户 ID

请从 Sub2API 平台正确访问订单页面

); } return (
Sub2API Secure Pay

我的订单

{userInfo?.username || `用户 #${effectiveUserId}`}

总订单
{summary.total}
待支付
{summary.pending}
已完成
{summary.completed}
异常/关闭
{summary.failed}
{FILTER_OPTIONS.map((item) => ( ))}
{loading ? (
) : error ? (
{error}
) : filteredOrders.length === 0 ? (
暂无符合条件的订单记录
) : ( <>
订单号 金额 支付方式 状态 创建时间
{filteredOrders.map((order) => (
#{order.id.slice(0, 12)}
¥{order.amount.toFixed(2)}
{order.paymentType}
{formatStatus(order.status)}
{formatCreatedAt(order.createdAt)}
))}
)}
); } export default function OrdersPage() { return (
加载中...
} > ); }