From 880f0211f31c5265b60c35f5ddd1dc844342fe13 Mon Sep 17 00:00:00 2001 From: erio Date: Tue, 3 Mar 2026 03:31:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=AE=A1=E7=90=86=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=20PayPageLayout=20=E5=B8=83=E5=B1=80?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=20dark=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 管理后台使用与充值页面相同的 PayPageLayout 组件,OrderTable 和 OrderDetail 组件新增 dark prop,所有样式支持暗色模式切换。 Co-Authored-By: Claude Opus 4.6 --- src/app/admin/page.tsx | 55 ++++++++++++------- src/components/admin/OrderDetail.tsx | 27 +++++----- src/components/admin/OrderTable.tsx | 79 +++++++++++++++------------- 3 files changed, 92 insertions(+), 69 deletions(-) diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 1f3e794..2d20e32 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -5,6 +5,7 @@ import { useState, useEffect, useCallback, Suspense } from 'react'; import OrderTable from '@/components/admin/OrderTable'; import OrderDetail from '@/components/admin/OrderDetail'; import PaginationBar from '@/components/PaginationBar'; +import PayPageLayout from '@/components/PayPageLayout'; interface AdminOrder { id: string; @@ -43,6 +44,10 @@ interface AdminOrderDetail extends AdminOrder { function AdminContent() { const searchParams = useSearchParams(); const token = searchParams.get('token'); + const theme = searchParams.get('theme') === 'dark' ? 'dark' : 'light'; + const uiMode = searchParams.get('ui_mode') || 'standalone'; + const isDark = theme === 'dark'; + const isEmbedded = uiMode === 'embedded'; const [orders, setOrders] = useState([]); const [total, setTotal] = useState(0); @@ -88,8 +93,11 @@ function AdminContent() { if (!token) { return ( -
-
缺少管理员凭证
+
+
+

缺少管理员凭证

+

请从 Sub2API 平台正确访问管理页面

+
); } @@ -154,22 +162,29 @@ function AdminContent() { }; return ( -
-
-

Sub2ApiPay 订单管理

+ 刷新 -
- + } + > {error && ( -
+
{error} -
@@ -184,9 +199,12 @@ function AdminContent() { setStatusFilter(s); setPage(1); }} - className={`rounded-full px-3 py-1 text-sm transition-colors ${ - statusFilter === s ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200' - }`} + className={[ + 'rounded-full px-3 py-1 text-sm transition-colors', + statusFilter === s + ? (isDark ? 'bg-indigo-500/30 text-indigo-200 ring-1 ring-indigo-400/40' : 'bg-blue-600 text-white') + : (isDark ? 'bg-slate-800 text-slate-400 hover:bg-slate-700' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'), + ].join(' ')} > {statusLabels[s]} @@ -194,11 +212,11 @@ function AdminContent() {
{/* Table */} -
+
{loading ? ( -
加载中...
+
加载中...
) : ( - + )}
@@ -210,11 +228,12 @@ function AdminContent() { loading={loading} onPageChange={(p) => setPage(p)} onPageSizeChange={(s) => { setPageSize(s); setPage(1); }} + isDark={isDark} /> {/* Order Detail */} - {detailOrder && setDetailOrder(null)} />} -
+ {detailOrder && setDetailOrder(null)} dark={isDark} />} + ); } diff --git a/src/components/admin/OrderDetail.tsx b/src/components/admin/OrderDetail.tsx index 60eed16..ecc1815 100644 --- a/src/components/admin/OrderDetail.tsx +++ b/src/components/admin/OrderDetail.tsx @@ -39,9 +39,10 @@ interface OrderDetailProps { auditLogs: AuditLog[]; }; onClose: () => void; + dark?: boolean; } -export default function OrderDetail({ order, onClose }: OrderDetailProps) { +export default function OrderDetail({ order, onClose, dark }: OrderDetailProps) { const fields = [ { label: '订单号', value: order.id }, { label: '用户ID', value: order.userId }, @@ -78,46 +79,46 @@ export default function OrderDetail({ order, onClose }: OrderDetailProps) { return (
e.stopPropagation()} >

订单详情

-
{fields.map(({ label, value }) => ( -
-
{label}
-
{value}
+
+
{label}
+
{value}
))}
{/* Audit Logs */}
-

审计日志

+

审计日志

{order.auditLogs.map((log) => ( -
+
{log.action} - {new Date(log.createdAt).toLocaleString('zh-CN')} + {new Date(log.createdAt).toLocaleString('zh-CN')}
- {log.detail &&
{log.detail}
} - {log.operator &&
操作者: {log.operator}
} + {log.detail &&
{log.detail}
} + {log.operator &&
操作者: {log.operator}
}
))} - {order.auditLogs.length === 0 &&
暂无日志
} + {order.auditLogs.length === 0 &&
暂无日志
}
diff --git a/src/components/admin/OrderTable.tsx b/src/components/admin/OrderTable.tsx index 3797e4c..43c4c23 100644 --- a/src/components/admin/OrderTable.tsx +++ b/src/components/admin/OrderTable.tsx @@ -1,7 +1,5 @@ 'use client'; -import { useState } from 'react'; - interface Order { id: string; userId: number; @@ -24,67 +22,72 @@ interface OrderTableProps { onRetry: (orderId: string) => void; onCancel: (orderId: string) => void; onViewDetail: (orderId: string) => void; + dark?: boolean; } -const STATUS_LABELS: Record = { - PENDING: { label: '待支付', className: 'bg-yellow-100 text-yellow-800' }, - PAID: { label: '已支付', className: 'bg-blue-100 text-blue-800' }, - RECHARGING: { label: '充值中', className: 'bg-blue-100 text-blue-800' }, - COMPLETED: { label: '已完成', className: 'bg-green-100 text-green-800' }, - EXPIRED: { label: '已超时', className: 'bg-gray-100 text-gray-800' }, - CANCELLED: { label: '已取消', className: 'bg-gray-100 text-gray-800' }, - FAILED: { label: '充值失败', className: 'bg-red-100 text-red-800' }, - REFUNDING: { label: '退款中', className: 'bg-orange-100 text-orange-800' }, - REFUNDED: { label: '已退款', className: 'bg-purple-100 text-purple-800' }, - REFUND_FAILED: { label: '退款失败', className: 'bg-red-100 text-red-800' }, +const STATUS_LABELS: Record = { + PENDING: { label: '待支付', light: 'bg-yellow-100 text-yellow-800', dark: 'bg-yellow-500/20 text-yellow-300' }, + PAID: { label: '已支付', light: 'bg-blue-100 text-blue-800', dark: 'bg-blue-500/20 text-blue-300' }, + RECHARGING: { label: '充值中', light: 'bg-blue-100 text-blue-800', dark: 'bg-blue-500/20 text-blue-300' }, + COMPLETED: { label: '已完成', light: 'bg-green-100 text-green-800', dark: 'bg-green-500/20 text-green-300' }, + EXPIRED: { label: '已超时', light: 'bg-gray-100 text-gray-800', dark: 'bg-slate-600/30 text-slate-400' }, + CANCELLED: { label: '已取消', light: 'bg-gray-100 text-gray-800', dark: 'bg-slate-600/30 text-slate-400' }, + FAILED: { label: '充值失败', light: 'bg-red-100 text-red-800', dark: 'bg-red-500/20 text-red-300' }, + REFUNDING: { label: '退款中', light: 'bg-orange-100 text-orange-800', dark: 'bg-orange-500/20 text-orange-300' }, + REFUNDED: { label: '已退款', light: 'bg-purple-100 text-purple-800', dark: 'bg-purple-500/20 text-purple-300' }, + REFUND_FAILED: { label: '退款失败', light: 'bg-red-100 text-red-800', dark: 'bg-red-500/20 text-red-300' }, }; -export default function OrderTable({ orders, onRetry, onCancel, onViewDetail }: OrderTableProps) { +export default function OrderTable({ orders, onRetry, onCancel, onViewDetail, dark }: OrderTableProps) { + const thCls = `px-4 py-3 text-left text-xs font-medium uppercase ${dark ? 'text-slate-400' : 'text-gray-500'}`; + const tdMuted = `whitespace-nowrap px-4 py-3 text-sm ${dark ? 'text-slate-400' : 'text-gray-500'}`; + return (
- - +
+ - - - - - - - - + + + + + + + + - + {orders.map((order) => { const statusInfo = STATUS_LABELS[order.status] || { label: order.status, - className: 'bg-gray-100 text-gray-800', + light: 'bg-gray-100 text-gray-800', + dark: 'bg-slate-600/30 text-slate-400', }; return ( - + - + - - -
订单号用户金额状态支付方式来源创建时间操作订单号用户金额状态支付方式来源创建时间操作
- -
{order.userName || '-'}
-
{order.userEmail || `ID: ${order.userId}`}
+
{order.userName || '-'}
+
{order.userEmail || `ID: ${order.userId}`}
¥{order.amount.toFixed(2)}¥{order.amount.toFixed(2)} - + {statusInfo.label} + {order.paymentType === 'alipay' ? '支付宝' : '微信支付'} + {order.srcHost || '-'} + {new Date(order.createdAt).toLocaleString('zh-CN')} @@ -92,7 +95,7 @@ export default function OrderTable({ orders, onRetry, onCancel, onViewDetail }: {order.rechargeRetryable && ( @@ -100,7 +103,7 @@ export default function OrderTable({ orders, onRetry, onCancel, onViewDetail }: {order.status === 'PENDING' && ( @@ -112,7 +115,7 @@ export default function OrderTable({ orders, onRetry, onCancel, onViewDetail }: })}
- {orders.length === 0 &&
暂无订单
} + {orders.length === 0 &&
暂无订单
}
); }