'use client'; import { useSearchParams } from 'next/navigation'; import { useState, useEffect, useCallback, Suspense } from 'react'; import OrderTable from '@/components/admin/OrderTable'; import OrderDetail from '@/components/admin/OrderDetail'; interface AdminOrder { id: string; userId: number; userName: string | null; userEmail: string | null; amount: number; status: string; paymentType: string; createdAt: string; paidAt: string | null; completedAt: string | null; failedReason: string | null; expiresAt: string; } interface AdminOrderDetail extends AdminOrder { rechargeCode: string; paymentTradeNo: string | null; refundAmount: number | null; refundReason: string | null; refundAt: string | null; forceRefund: boolean; failedAt: string | null; updatedAt: string; clientIp: string | null; paymentSuccess?: boolean; rechargeSuccess?: boolean; rechargeStatus?: string; auditLogs: { id: string; action: string; detail: string | null; operator: string | null; createdAt: string }[]; } function AdminContent() { const searchParams = useSearchParams(); const token = searchParams.get('token'); const [orders, setOrders] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(20); const [totalPages, setTotalPages] = useState(1); const [statusFilter, setStatusFilter] = useState(''); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [detailOrder, setDetailOrder] = useState(null); const fetchOrders = useCallback(async () => { if (!token) return; setLoading(true); try { const params = new URLSearchParams({ token, page: String(page), page_size: String(pageSize) }); if (statusFilter) params.set('status', statusFilter); const res = await fetch(`/api/admin/orders?${params}`); if (!res.ok) { if (res.status === 401) { setError('管理员凭证无效'); return; } throw new Error('请求失败'); } const data = await res.json(); setOrders(data.orders); setTotal(data.total); setTotalPages(data.total_pages); } catch (e) { setError('加载订单列表失败'); } finally { setLoading(false); } }, [token, page, pageSize, statusFilter]); useEffect(() => { fetchOrders(); }, [fetchOrders]); if (!token) { return (
缺少管理员凭证
); } const handleRetry = async (orderId: string) => { if (!confirm('确认重试充值?')) return; try { const res = await fetch(`/api/admin/orders/${orderId}/retry?token=${token}`, { method: 'POST', }); if (res.ok) { fetchOrders(); } else { const data = await res.json(); setError(data.error || '重试失败'); } } catch { setError('重试请求失败'); } }; const handleCancel = async (orderId: string) => { if (!confirm('确认取消该订单?')) return; try { const res = await fetch(`/api/admin/orders/${orderId}/cancel?token=${token}`, { method: 'POST', }); if (res.ok) { fetchOrders(); } else { const data = await res.json(); setError(data.error || '取消失败'); } } catch { setError('取消请求失败'); } }; const handleViewDetail = async (orderId: string) => { try { const res = await fetch(`/api/admin/orders/${orderId}?token=${token}`); if (res.ok) { const data = await res.json(); setDetailOrder(data); } } catch { setError('加载订单详情失败'); } }; const statuses = ['', 'PENDING', 'PAID', 'RECHARGING', 'COMPLETED', 'EXPIRED', 'CANCELLED', 'FAILED', 'REFUNDED']; const statusLabels: Record = { '': '全部', PENDING: '待支付', PAID: '已支付', RECHARGING: '充值中', COMPLETED: '已完成', EXPIRED: '已超时', CANCELLED: '已取消', FAILED: '充值失败', REFUNDED: '已退款', }; return (

Sub2ApiPay 订单管理

{error && (
{error}
)} {/* Filters */}
{statuses.map((s) => ( ))}
{/* Table */}
{loading ? (
加载中...
) : ( )}
{/* Pagination */}
共 {total} 条,每页 {[20, 50, 100].map((s) => ( ))}
{totalPages > 1 && (
{page} / {totalPages}
)}
{/* Order Detail */} {detailOrder && setDetailOrder(null)} />}
); } export default function AdminPage() { return (
加载中...
} >
); }