style: 全量 prettier 格式化
This commit is contained in:
@@ -125,9 +125,7 @@ export default function MobileOrderList({
|
||||
{hasMore && (
|
||||
<div ref={sentinelRef} className="py-3 text-center">
|
||||
{loadingMore ? (
|
||||
<span className={['text-xs', isDark ? 'text-slate-400' : 'text-slate-500'].join(' ')}>
|
||||
加载中...
|
||||
</span>
|
||||
<span className={['text-xs', isDark ? 'text-slate-400' : 'text-slate-500'].join(' ')}>加载中...</span>
|
||||
) : (
|
||||
<span className={['text-xs', isDark ? 'text-slate-600' : 'text-slate-300'].join(' ')}>
|
||||
上滑加载更多
|
||||
|
||||
@@ -35,8 +35,7 @@ export default function PaginationBar({
|
||||
{/* 左侧:统计 + 每页大小 */}
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={isDark ? 'text-slate-400' : 'text-slate-500'}>
|
||||
共 {total} 条
|
||||
{totalPages > 1 && `,第 ${page} / ${totalPages} 页`}
|
||||
共 {total} 条{totalPages > 1 && `,第 ${page} / ${totalPages} 页`}
|
||||
</span>
|
||||
|
||||
{onPageSizeChange && (
|
||||
@@ -47,7 +46,9 @@ export default function PaginationBar({
|
||||
key={s}
|
||||
type="button"
|
||||
disabled={loading}
|
||||
onClick={() => { onPageSizeChange(s); }}
|
||||
onClick={() => {
|
||||
onPageSizeChange(s);
|
||||
}}
|
||||
className={[
|
||||
'rounded border px-2 py-1 font-medium transition-colors',
|
||||
pageSize === s
|
||||
|
||||
@@ -27,7 +27,8 @@ const TEXT_GO_PAY = '\u70B9\u51FB\u524D\u5F80\u652F\u4ED8';
|
||||
const TEXT_SCAN_PAY = '\u8BF7\u4F7F\u7528\u652F\u4ED8\u5E94\u7528\u626B\u7801\u652F\u4ED8';
|
||||
const TEXT_BACK = '\u8FD4\u56DE';
|
||||
const TEXT_CANCEL_ORDER = '\u53D6\u6D88\u8BA2\u5355';
|
||||
const TEXT_H5_HINT = '\u652F\u4ED8\u5B8C\u6210\u540E\u8BF7\u8FD4\u56DE\u6B64\u9875\u9762\uFF0C\u7CFB\u7EDF\u5C06\u81EA\u52A8\u786E\u8BA4';
|
||||
const TEXT_H5_HINT =
|
||||
'\u652F\u4ED8\u5B8C\u6210\u540E\u8BF7\u8FD4\u56DE\u6B64\u9875\u9762\uFF0C\u7CFB\u7EDF\u5C06\u81EA\u52A8\u786E\u8BA4';
|
||||
const TERMINAL_STATUSES = new Set(['COMPLETED', 'FAILED', 'CANCELLED', 'EXPIRED', 'REFUNDED', 'REFUND_FAILED']);
|
||||
|
||||
export default function PaymentQRCode({
|
||||
@@ -215,11 +216,7 @@ export default function PaymentQRCode({
|
||||
popupUrl.searchParams.set('theme', dark ? 'dark' : 'light');
|
||||
popupUrl.searchParams.set('method', stripePaymentMethod);
|
||||
|
||||
const popup = window.open(
|
||||
popupUrl.toString(),
|
||||
'stripe_payment',
|
||||
'width=500,height=700,scrollbars=yes',
|
||||
);
|
||||
const popup = window.open(popupUrl.toString(), 'stripe_payment', 'width=500,height=700,scrollbars=yes');
|
||||
if (!popup || popup.closed) {
|
||||
setPopupBlocked(true);
|
||||
return;
|
||||
@@ -228,11 +225,14 @@ export default function PaymentQRCode({
|
||||
const onReady = (event: MessageEvent) => {
|
||||
if (event.source !== popup || event.data?.type !== 'STRIPE_POPUP_READY') return;
|
||||
window.removeEventListener('message', onReady);
|
||||
popup.postMessage({
|
||||
type: 'STRIPE_POPUP_INIT',
|
||||
clientSecret,
|
||||
publishableKey: stripePublishableKey,
|
||||
}, window.location.origin);
|
||||
popup.postMessage(
|
||||
{
|
||||
type: 'STRIPE_POPUP_INIT',
|
||||
clientSecret,
|
||||
publishableKey: stripePublishableKey,
|
||||
},
|
||||
window.location.origin,
|
||||
);
|
||||
};
|
||||
window.addEventListener('message', onReady);
|
||||
};
|
||||
@@ -324,7 +324,9 @@ export default function PaymentQRCode({
|
||||
<div className="text-6xl text-green-600">{'\u2713'}</div>
|
||||
<h2 className="text-xl font-bold text-green-600">{'\u8BA2\u5355\u5DF2\u652F\u4ED8'}</h2>
|
||||
<p className={['text-center text-sm', dark ? 'text-slate-400' : 'text-gray-500'].join(' ')}>
|
||||
{'\u8BE5\u8BA2\u5355\u5DF2\u652F\u4ED8\u5B8C\u6210\uFF0C\u65E0\u6CD5\u53D6\u6D88\u3002\u5145\u503C\u5C06\u81EA\u52A8\u5230\u8D26\u3002'}
|
||||
{
|
||||
'\u8BE5\u8BA2\u5355\u5DF2\u652F\u4ED8\u5B8C\u6210\uFF0C\u65E0\u6CD5\u53D6\u6D88\u3002\u5145\u503C\u5C06\u81EA\u52A8\u5230\u8D26\u3002'
|
||||
}
|
||||
</p>
|
||||
<button
|
||||
onClick={onBack}
|
||||
@@ -339,7 +341,10 @@ export default function PaymentQRCode({
|
||||
return (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<div className="text-center">
|
||||
<div className="text-4xl font-bold text-blue-600">{'\u00A5'}{displayAmount.toFixed(2)}</div>
|
||||
<div className="text-4xl font-bold text-blue-600">
|
||||
{'\u00A5'}
|
||||
{displayAmount.toFixed(2)}
|
||||
</div>
|
||||
{hasFeeDiff && (
|
||||
<div className={['mt-1 text-sm', dark ? 'text-slate-400' : 'text-gray-500'].join(' ')}>
|
||||
到账 ¥{amount.toFixed(2)}
|
||||
@@ -355,7 +360,12 @@ export default function PaymentQRCode({
|
||||
{isStripe ? (
|
||||
<div className="w-full max-w-md space-y-4">
|
||||
{!clientSecret || !stripePublishableKey ? (
|
||||
<div className={['rounded-lg border-2 border-dashed p-8 text-center', dark ? 'border-slate-700' : 'border-gray-300'].join(' ')}>
|
||||
<div
|
||||
className={[
|
||||
'rounded-lg border-2 border-dashed p-8 text-center',
|
||||
dark ? 'border-slate-700' : 'border-gray-300',
|
||||
].join(' ')}
|
||||
>
|
||||
<p className={['text-sm', dark ? 'text-slate-400' : 'text-gray-500'].join(' ')}>
|
||||
支付初始化失败,请返回重试
|
||||
</p>
|
||||
@@ -368,14 +378,15 @@ export default function PaymentQRCode({
|
||||
</span>
|
||||
</div>
|
||||
) : stripeError && !stripeLib ? (
|
||||
<div className="rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-600">
|
||||
{stripeError}
|
||||
</div>
|
||||
<div className="rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-600">{stripeError}</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
ref={stripeContainerRef}
|
||||
className={['rounded-lg border p-4', dark ? 'border-slate-700 bg-slate-900' : 'border-gray-200 bg-white'].join(' ')}
|
||||
className={[
|
||||
'rounded-lg border p-4',
|
||||
dark ? 'border-slate-700 bg-slate-900' : 'border-gray-200 bg-white',
|
||||
].join(' ')}
|
||||
/>
|
||||
{stripeError && (
|
||||
<div className="rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-600">
|
||||
@@ -412,7 +423,14 @@ export default function PaymentQRCode({
|
||||
</button>
|
||||
)}
|
||||
{popupBlocked && (
|
||||
<div className={['rounded-lg border p-3 text-sm', dark ? 'border-amber-700 bg-amber-900/30 text-amber-300' : 'border-amber-200 bg-amber-50 text-amber-700'].join(' ')}>
|
||||
<div
|
||||
className={[
|
||||
'rounded-lg border p-3 text-sm',
|
||||
dark
|
||||
? 'border-amber-700 bg-amber-900/30 text-amber-300'
|
||||
: 'border-amber-200 bg-amber-50 text-amber-700',
|
||||
].join(' ')}
|
||||
>
|
||||
弹出窗口被浏览器拦截,请允许本站弹出窗口后重试
|
||||
</div>
|
||||
)}
|
||||
@@ -437,7 +455,12 @@ export default function PaymentQRCode({
|
||||
) : (
|
||||
<>
|
||||
{qrDataUrl && (
|
||||
<div className={['relative rounded-lg border p-4', dark ? 'border-slate-700 bg-slate-900' : 'border-gray-200 bg-white'].join(' ')}>
|
||||
<div
|
||||
className={[
|
||||
'relative rounded-lg border p-4',
|
||||
dark ? 'border-slate-700 bg-slate-900' : 'border-gray-200 bg-white',
|
||||
].join(' ')}
|
||||
>
|
||||
{imageLoading && (
|
||||
<div className="absolute inset-0 z-10 flex items-center justify-center rounded-lg bg-black/10">
|
||||
<div className="h-8 w-8 animate-spin rounded-full border-2 border-blue-500 border-t-transparent" />
|
||||
@@ -465,7 +488,12 @@ export default function PaymentQRCode({
|
||||
|
||||
{!qrDataUrl && !payUrl && (
|
||||
<div className="text-center">
|
||||
<div className={['rounded-lg border-2 border-dashed p-8', dark ? 'border-slate-700' : 'border-gray-300'].join(' ')}>
|
||||
<div
|
||||
className={[
|
||||
'rounded-lg border-2 border-dashed p-8',
|
||||
dark ? 'border-slate-700' : 'border-gray-300',
|
||||
].join(' ')}
|
||||
>
|
||||
<p className={['text-sm', dark ? 'text-slate-400' : 'text-gray-500'].join(' ')}>{TEXT_SCAN_PAY}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -484,7 +512,9 @@ export default function PaymentQRCode({
|
||||
onClick={onBack}
|
||||
className={[
|
||||
'flex-1 rounded-lg border py-2 text-sm',
|
||||
dark ? 'border-slate-700 text-slate-300 hover:bg-slate-800' : 'border-gray-300 text-gray-600 hover:bg-gray-50',
|
||||
dark
|
||||
? 'border-slate-700 text-slate-300 hover:bg-slate-800'
|
||||
: 'border-gray-300 text-gray-600 hover:bg-gray-50',
|
||||
].join(' ')}
|
||||
>
|
||||
{TEXT_BACK}
|
||||
|
||||
@@ -51,7 +51,8 @@ function CustomTooltip({
|
||||
<p className={['mb-1 text-xs', dark ? 'text-slate-400' : 'text-slate-500'].join(' ')}>{label}</p>
|
||||
{payload.map((p) => (
|
||||
<p key={p.dataKey}>
|
||||
{p.dataKey === 'amount' ? '金额' : '笔数'}: {p.dataKey === 'amount' ? `¥${p.value.toLocaleString()}` : p.value}
|
||||
{p.dataKey === 'amount' ? '金额' : '笔数'}:{' '}
|
||||
{p.dataKey === 'amount' ? `¥${p.value.toLocaleString()}` : p.value}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
@@ -63,8 +64,15 @@ export default function DailyChart({ data, dark }: DailyChartProps) {
|
||||
const tickInterval = data.length > 30 ? Math.ceil(data.length / 12) - 1 : 0;
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<div className={['rounded-xl border p-6', dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm'].join(' ')}>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>每日充值趋势</h3>
|
||||
<div
|
||||
className={[
|
||||
'rounded-xl border p-6',
|
||||
dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>
|
||||
每日充值趋势
|
||||
</h3>
|
||||
<p className={['text-center text-sm py-16', dark ? 'text-slate-500' : 'text-gray-400'].join(' ')}>暂无数据</p>
|
||||
</div>
|
||||
);
|
||||
@@ -74,8 +82,15 @@ export default function DailyChart({ data, dark }: DailyChartProps) {
|
||||
const gridColor = dark ? '#334155' : '#e2e8f0';
|
||||
|
||||
return (
|
||||
<div className={['rounded-xl border p-6', dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm'].join(' ')}>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>每日充值趋势</h3>
|
||||
<div
|
||||
className={[
|
||||
'rounded-xl border p-6',
|
||||
dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>
|
||||
每日充值趋势
|
||||
</h3>
|
||||
<ResponsiveContainer width="100%" height={320}>
|
||||
<LineChart data={data} margin={{ top: 5, right: 20, bottom: 5, left: 10 }}>
|
||||
<CartesianGrid stroke={gridColor} strokeDasharray="3 3" />
|
||||
|
||||
@@ -29,24 +29,14 @@ export default function DashboardStats({ summary, dark }: DashboardStatsProps) {
|
||||
key={card.label}
|
||||
className={[
|
||||
'rounded-xl border p-4',
|
||||
dark
|
||||
? 'border-slate-700 bg-slate-800/60'
|
||||
: 'border-slate-200 bg-white shadow-sm',
|
||||
dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
<p className={['text-xs font-medium', dark ? 'text-slate-400' : 'text-slate-500'].join(' ')}>
|
||||
{card.label}
|
||||
</p>
|
||||
<p className={['text-xs font-medium', dark ? 'text-slate-400' : 'text-slate-500'].join(' ')}>{card.label}</p>
|
||||
<p
|
||||
className={[
|
||||
'mt-1 text-xl font-semibold tracking-tight',
|
||||
card.accent
|
||||
? dark
|
||||
? 'text-indigo-400'
|
||||
: 'text-indigo-600'
|
||||
: dark
|
||||
? 'text-slate-100'
|
||||
: 'text-slate-900',
|
||||
card.accent ? (dark ? 'text-indigo-400' : 'text-indigo-600') : dark ? 'text-slate-100' : 'text-slate-900',
|
||||
].join(' ')}
|
||||
>
|
||||
{card.value}
|
||||
|
||||
@@ -26,15 +26,27 @@ export default function Leaderboard({ data, dark }: LeaderboardProps) {
|
||||
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<div className={['rounded-xl border p-6', dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm'].join(' ')}>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>充值排行榜 (Top 10)</h3>
|
||||
<div
|
||||
className={[
|
||||
'rounded-xl border p-6',
|
||||
dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>
|
||||
充值排行榜 (Top 10)
|
||||
</h3>
|
||||
<p className={['text-center text-sm py-8', dark ? 'text-slate-500' : 'text-gray-400'].join(' ')}>暂无数据</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={['rounded-xl border', dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm'].join(' ')}>
|
||||
<div
|
||||
className={[
|
||||
'rounded-xl border',
|
||||
dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
<h3 className={['px-6 pt-5 pb-2 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>
|
||||
充值排行榜 (Top 10)
|
||||
</h3>
|
||||
@@ -56,7 +68,9 @@ export default function Leaderboard({ data, dark }: LeaderboardProps) {
|
||||
<tr key={entry.userId} className={dark ? 'hover:bg-slate-700/40' : 'hover:bg-gray-50'}>
|
||||
<td className="whitespace-nowrap px-4 py-3 text-sm">
|
||||
{rankStyle ? (
|
||||
<span className={`inline-flex h-6 w-6 items-center justify-center rounded-full text-xs font-bold ${dark ? rankStyle.dark : rankStyle.light}`}>
|
||||
<span
|
||||
className={`inline-flex h-6 w-6 items-center justify-center rounded-full text-xs font-bold ${dark ? rankStyle.dark : rankStyle.light}`}
|
||||
>
|
||||
{rank}
|
||||
</span>
|
||||
) : (
|
||||
@@ -71,7 +85,9 @@ export default function Leaderboard({ data, dark }: LeaderboardProps) {
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
<td className={`whitespace-nowrap px-4 py-3 text-sm font-medium ${dark ? 'text-slate-200' : 'text-slate-900'}`}>
|
||||
<td
|
||||
className={`whitespace-nowrap px-4 py-3 text-sm font-medium ${dark ? 'text-slate-200' : 'text-slate-900'}`}
|
||||
>
|
||||
¥{entry.totalAmount.toLocaleString()}
|
||||
</td>
|
||||
<td className={tdMuted}>{entry.orderCount}</td>
|
||||
|
||||
@@ -84,7 +84,10 @@ export default function OrderDetail({ order, onClose, dark }: OrderDetailProps)
|
||||
>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h3 className="text-lg font-bold">订单详情</h3>
|
||||
<button onClick={onClose} className={dark ? 'text-slate-400 hover:text-slate-200' : 'text-gray-400 hover:text-gray-600'}>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className={dark ? 'text-slate-400 hover:text-slate-200' : 'text-gray-400 hover:text-gray-600'}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
@@ -103,16 +106,31 @@ export default function OrderDetail({ order, onClose, dark }: OrderDetailProps)
|
||||
<h4 className={`mb-3 font-medium ${dark ? 'text-slate-100' : 'text-gray-900'}`}>审计日志</h4>
|
||||
<div className="space-y-2">
|
||||
{order.auditLogs.map((log) => (
|
||||
<div key={log.id} className={`rounded-lg border p-3 ${dark ? 'border-slate-600 bg-slate-700/60' : 'border-gray-100 bg-gray-50'}`}>
|
||||
<div
|
||||
key={log.id}
|
||||
className={`rounded-lg border p-3 ${dark ? 'border-slate-600 bg-slate-700/60' : 'border-gray-100 bg-gray-50'}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium">{log.action}</span>
|
||||
<span className={`text-xs ${dark ? 'text-slate-500' : 'text-gray-400'}`}>{new Date(log.createdAt).toLocaleString('zh-CN')}</span>
|
||||
<span className={`text-xs ${dark ? 'text-slate-500' : 'text-gray-400'}`}>
|
||||
{new Date(log.createdAt).toLocaleString('zh-CN')}
|
||||
</span>
|
||||
</div>
|
||||
{log.detail && <div className={`mt-1 break-all text-xs ${dark ? 'text-slate-400' : 'text-gray-500'}`}>{log.detail}</div>}
|
||||
{log.operator && <div className={`mt-1 text-xs ${dark ? 'text-slate-500' : 'text-gray-400'}`}>操作者: {log.operator}</div>}
|
||||
{log.detail && (
|
||||
<div className={`mt-1 break-all text-xs ${dark ? 'text-slate-400' : 'text-gray-500'}`}>
|
||||
{log.detail}
|
||||
</div>
|
||||
)}
|
||||
{log.operator && (
|
||||
<div className={`mt-1 text-xs ${dark ? 'text-slate-500' : 'text-gray-400'}`}>
|
||||
操作者: {log.operator}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{order.auditLogs.length === 0 && <div className={`text-center text-sm ${dark ? 'text-slate-500' : 'text-gray-400'}`}>暂无日志</div>}
|
||||
{order.auditLogs.length === 0 && (
|
||||
<div className={`text-center text-sm ${dark ? 'text-slate-500' : 'text-gray-400'}`}>暂无日志</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -70,7 +70,10 @@ export default function OrderTable({ orders, onRetry, onCancel, onViewDetail, da
|
||||
return (
|
||||
<tr key={order.id} className={dark ? 'hover:bg-slate-700/40' : 'hover:bg-gray-50'}>
|
||||
<td className="whitespace-nowrap px-4 py-3 text-sm">
|
||||
<button onClick={() => onViewDetail(order.id)} className={dark ? 'text-indigo-400 hover:underline' : 'text-blue-600 hover:underline'}>
|
||||
<button
|
||||
onClick={() => onViewDetail(order.id)}
|
||||
className={dark ? 'text-indigo-400 hover:underline' : 'text-blue-600 hover:underline'}
|
||||
>
|
||||
{order.id.slice(0, 12)}...
|
||||
</button>
|
||||
</td>
|
||||
@@ -79,21 +82,27 @@ export default function OrderTable({ orders, onRetry, onCancel, onViewDetail, da
|
||||
</td>
|
||||
<td className={tdMuted}>{order.userEmail || '-'}</td>
|
||||
<td className={tdMuted}>{order.userNotes || '-'}</td>
|
||||
<td className={`whitespace-nowrap px-4 py-3 text-sm font-medium ${dark ? 'text-slate-200' : ''}`}>¥{order.amount.toFixed(2)}</td>
|
||||
<td className={`whitespace-nowrap px-4 py-3 text-sm font-medium ${dark ? 'text-slate-200' : ''}`}>
|
||||
¥{order.amount.toFixed(2)}
|
||||
</td>
|
||||
<td className="whitespace-nowrap px-4 py-3 text-sm">
|
||||
<span className={`inline-flex rounded-full px-2 py-1 text-xs font-semibold ${dark ? statusInfo.dark : statusInfo.light}`}>
|
||||
<span
|
||||
className={`inline-flex rounded-full px-2 py-1 text-xs font-semibold ${dark ? statusInfo.dark : statusInfo.light}`}
|
||||
>
|
||||
{statusInfo.label}
|
||||
</span>
|
||||
</td>
|
||||
<td className={tdMuted}>
|
||||
{order.paymentType === 'alipay' ? '支付宝' : order.paymentType === 'wechat' ? '微信支付' : order.paymentType === 'stripe' ? 'Stripe' : order.paymentType}
|
||||
</td>
|
||||
<td className={tdMuted}>
|
||||
{order.srcHost || '-'}
|
||||
</td>
|
||||
<td className={tdMuted}>
|
||||
{new Date(order.createdAt).toLocaleString('zh-CN')}
|
||||
{order.paymentType === 'alipay'
|
||||
? '支付宝'
|
||||
: order.paymentType === 'wechat'
|
||||
? '微信支付'
|
||||
: order.paymentType === 'stripe'
|
||||
? 'Stripe'
|
||||
: order.paymentType}
|
||||
</td>
|
||||
<td className={tdMuted}>{order.srcHost || '-'}</td>
|
||||
<td className={tdMuted}>{new Date(order.createdAt).toLocaleString('zh-CN')}</td>
|
||||
<td className="whitespace-nowrap px-4 py-3 text-sm">
|
||||
<div className="flex gap-1">
|
||||
{order.rechargeRetryable && (
|
||||
@@ -119,7 +128,9 @@ export default function OrderTable({ orders, onRetry, onCancel, onViewDetail, da
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
{orders.length === 0 && <div className={`py-12 text-center ${dark ? 'text-slate-500' : 'text-gray-500'}`}>暂无订单</div>}
|
||||
{orders.length === 0 && (
|
||||
<div className={`py-12 text-center ${dark ? 'text-slate-500' : 'text-gray-500'}`}>暂无订单</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,16 +21,30 @@ const TYPE_CONFIG: Record<string, { label: string; light: string; dark: string }
|
||||
export default function PaymentMethodChart({ data, dark }: PaymentMethodChartProps) {
|
||||
if (data.length === 0) {
|
||||
return (
|
||||
<div className={['rounded-xl border p-6', dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm'].join(' ')}>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>支付方式分布</h3>
|
||||
<div
|
||||
className={[
|
||||
'rounded-xl border p-6',
|
||||
dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>
|
||||
支付方式分布
|
||||
</h3>
|
||||
<p className={['text-center text-sm py-8', dark ? 'text-slate-500' : 'text-gray-400'].join(' ')}>暂无数据</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={['rounded-xl border p-6', dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm'].join(' ')}>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>支付方式分布</h3>
|
||||
<div
|
||||
className={[
|
||||
'rounded-xl border p-6',
|
||||
dark ? 'border-slate-700 bg-slate-800/60' : 'border-slate-200 bg-white shadow-sm',
|
||||
].join(' ')}
|
||||
>
|
||||
<h3 className={['mb-4 text-sm font-semibold', dark ? 'text-slate-200' : 'text-slate-800'].join(' ')}>
|
||||
支付方式分布
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
{data.map((method) => {
|
||||
const config = TYPE_CONFIG[method.paymentType] || {
|
||||
@@ -46,7 +60,11 @@ export default function PaymentMethodChart({ data, dark }: PaymentMethodChartPro
|
||||
¥{method.amount.toLocaleString()} · {method.percentage}%
|
||||
</span>
|
||||
</div>
|
||||
<div className={['h-3 w-full overflow-hidden rounded-full', dark ? 'bg-slate-700' : 'bg-slate-100'].join(' ')}>
|
||||
<div
|
||||
className={['h-3 w-full overflow-hidden rounded-full', dark ? 'bg-slate-700' : 'bg-slate-100'].join(
|
||||
' ',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={['h-full rounded-full transition-all', dark ? config.dark : config.light].join(' ')}
|
||||
style={{ width: `${method.percentage}%` }}
|
||||
|
||||
Reference in New Issue
Block a user