style: 全量 prettier 格式化

This commit is contained in:
erio
2026-03-05 23:10:44 +08:00
parent ab961e669a
commit 0a35ba9002
33 changed files with 450 additions and 291 deletions

View File

@@ -16,7 +16,13 @@ interface DashboardData {
avgAmount: number;
};
dailySeries: { date: string; amount: number; count: number }[];
leaderboard: { userId: number; userName: string | null; userEmail: string | null; totalAmount: number; orderCount: number }[];
leaderboard: {
userId: number;
userName: string | null;
userEmail: string | null;
totalAmount: number;
orderCount: number;
}[];
paymentMethods: { paymentType: string; amount: number; count: number; percentage: number }[];
meta: { days: number; generatedAt: string };
}
@@ -79,7 +85,9 @@ function DashboardContent() {
const btnBase = [
'inline-flex items-center rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors',
isDark ? 'border-slate-600 text-slate-200 hover:bg-slate-800' : 'border-slate-300 text-slate-700 hover:bg-slate-100',
isDark
? 'border-slate-600 text-slate-200 hover:bg-slate-800'
: 'border-slate-300 text-slate-700 hover:bg-slate-100',
].join(' ');
const btnActive = [
@@ -97,12 +105,7 @@ function DashboardContent() {
actions={
<>
{DAYS_OPTIONS.map((d) => (
<button
key={d}
type="button"
onClick={() => setDays(d)}
className={days === d ? btnActive : btnBase}
>
<button key={d} type="button" onClick={() => setDays(d)} className={days === d ? btnActive : btnBase}>
{d}
</button>
))}
@@ -116,7 +119,9 @@ function DashboardContent() {
}
>
{error && (
<div className={`mb-4 rounded-lg border p-3 text-sm ${isDark ? 'border-red-800 bg-red-950/50 text-red-400' : 'border-red-200 bg-red-50 text-red-600'}`}>
<div
className={`mb-4 rounded-lg border p-3 text-sm ${isDark ? 'border-red-800 bg-red-950/50 text-red-400' : 'border-red-200 bg-red-50 text-red-600'}`}
>
{error}
<button onClick={() => setError('')} className="ml-2 opacity-60 hover:opacity-100">

View File

@@ -169,7 +169,9 @@ function AdminContent() {
const btnBase = [
'inline-flex items-center rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors',
isDark ? 'border-slate-600 text-slate-200 hover:bg-slate-800' : 'border-slate-300 text-slate-700 hover:bg-slate-100',
isDark
? 'border-slate-600 text-slate-200 hover:bg-slate-800'
: 'border-slate-300 text-slate-700 hover:bg-slate-100',
].join(' ');
return (
@@ -191,7 +193,9 @@ function AdminContent() {
}
>
{error && (
<div className={`mb-4 rounded-lg border p-3 text-sm ${isDark ? 'border-red-800 bg-red-950/50 text-red-400' : 'border-red-200 bg-red-50 text-red-600'}`}>
<div
className={`mb-4 rounded-lg border p-3 text-sm ${isDark ? 'border-red-800 bg-red-950/50 text-red-400' : 'border-red-200 bg-red-50 text-red-600'}`}
>
{error}
<button onClick={() => setError('')} className="ml-2 opacity-60 hover:opacity-100">
@@ -211,8 +215,12 @@ function AdminContent() {
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'),
? 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]}
@@ -221,11 +229,22 @@ function AdminContent() {
</div>
{/* Table */}
<div className={['rounded-xl border', isDark ? 'border-slate-700 bg-slate-800/70' : 'border-slate-200 bg-white shadow-sm'].join(' ')}>
<div
className={[
'rounded-xl border',
isDark ? 'border-slate-700 bg-slate-800/70' : 'border-slate-200 bg-white shadow-sm',
].join(' ')}
>
{loading ? (
<div className={`py-12 text-center ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>...</div>
) : (
<OrderTable orders={orders} onRetry={handleRetry} onCancel={handleCancel} onViewDetail={handleViewDetail} dark={isDark} />
<OrderTable
orders={orders}
onRetry={handleRetry}
onCancel={handleCancel}
onViewDetail={handleViewDetail}
dark={isDark}
/>
)}
</div>
@@ -236,7 +255,10 @@ function AdminContent() {
pageSize={pageSize}
loading={loading}
onPageChange={(p) => setPage(p)}
onPageSizeChange={(s) => { setPageSize(s); setPage(1); }}
onPageSizeChange={(s) => {
setPageSize(s);
setPage(1);
}}
isDark={isDark}
/>

View File

@@ -71,7 +71,13 @@ export async function GET(request: NextRequest) {
`,
// Leaderboard: GROUP BY user_id only, MAX() for name/email
prisma.$queryRaw<
{ user_id: number; user_name: string | null; user_email: string | null; total_amount: string; order_count: bigint }[]
{
user_id: number;
user_name: string | null;
user_email: string | null;
total_amount: string;
order_count: bigint;
}[]
>`
SELECT user_id, MAX(user_name) as user_name, MAX(user_email) as user_email,
SUM(amount)::text as total_amount, COUNT(*) as order_count

View File

@@ -3,7 +3,7 @@ import { verifyAdminToken, unauthorizedResponse } from '@/lib/admin-auth';
import { adminCancelOrder, OrderError } from '@/lib/order/service';
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
if (!await verifyAdminToken(request)) return unauthorizedResponse();
if (!(await verifyAdminToken(request))) return unauthorizedResponse();
try {
const { id } = await params;

View File

@@ -3,7 +3,7 @@ import { verifyAdminToken, unauthorizedResponse } from '@/lib/admin-auth';
import { retryRecharge, OrderError } from '@/lib/order/service';
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
if (!await verifyAdminToken(request)) return unauthorizedResponse();
if (!(await verifyAdminToken(request))) return unauthorizedResponse();
try {
const { id } = await params;

View File

@@ -3,7 +3,7 @@ import { prisma } from '@/lib/db';
import { verifyAdminToken, unauthorizedResponse } from '@/lib/admin-auth';
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
if (!await verifyAdminToken(request)) return unauthorizedResponse();
if (!(await verifyAdminToken(request))) return unauthorizedResponse();
const { id } = await params;

View File

@@ -4,7 +4,7 @@ import { verifyAdminToken, unauthorizedResponse } from '@/lib/admin-auth';
import { Prisma, OrderStatus } from '@prisma/client';
export async function GET(request: NextRequest) {
if (!await verifyAdminToken(request)) return unauthorizedResponse();
if (!(await verifyAdminToken(request))) return unauthorizedResponse();
const searchParams = request.nextUrl.searchParams;
const page = Math.max(1, Number(searchParams.get('page') || '1'));

View File

@@ -10,7 +10,7 @@ const refundSchema = z.object({
});
export async function POST(request: NextRequest) {
if (!await verifyAdminToken(request)) return unauthorizedResponse();
if (!(await verifyAdminToken(request))) return unauthorizedResponse();
try {
const body = await request.json();

View File

@@ -27,9 +27,6 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
return NextResponse.json({ received: true });
} catch (error) {
console.error('Stripe webhook error:', error);
return NextResponse.json(
{ error: 'Webhook processing failed' },
{ status: 400 },
);
return NextResponse.json({ error: 'Webhook processing failed' }, { status: 400 });
}
}

View File

@@ -11,10 +11,7 @@ export async function GET(request: NextRequest) {
try {
const env = getEnv();
const [user, methodLimits] = await Promise.all([
getUser(userId),
queryMethodLimits(env.ENABLED_PAYMENT_TYPES),
]);
const [user, methodLimits] = await Promise.all([getUser(userId), queryMethodLimits(env.ENABLED_PAYMENT_TYPES)]);
return NextResponse.json({
user: {
@@ -29,9 +26,10 @@ export async function GET(request: NextRequest) {
methodLimits,
helpImageUrl: env.PAY_HELP_IMAGE_URL ?? null,
helpText: env.PAY_HELP_TEXT ?? null,
stripePublishableKey: env.ENABLED_PAYMENT_TYPES.includes('stripe') && env.STRIPE_PUBLISHABLE_KEY
? env.STRIPE_PUBLISHABLE_KEY
: null,
stripePublishableKey:
env.ENABLED_PAYMENT_TYPES.includes('stripe') && env.STRIPE_PUBLISHABLE_KEY
? env.STRIPE_PUBLISHABLE_KEY
: null,
},
});
} catch (error) {

View File

@@ -134,17 +134,20 @@ function OrdersContent() {
loadOrders(1, newSize);
};
const filteredOrders =
activeFilter === 'ALL' ? orders : orders.filter((o) => o.status === activeFilter);
const filteredOrders = activeFilter === 'ALL' ? orders : orders.filter((o) => o.status === activeFilter);
const btnClass = [
'inline-flex items-center rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors',
isDark ? 'border-slate-600 text-slate-200 hover:bg-slate-800' : 'border-slate-300 text-slate-700 hover:bg-slate-100',
isDark
? 'border-slate-600 text-slate-200 hover:bg-slate-800'
: 'border-slate-300 text-slate-700 hover:bg-slate-100',
].join(' ');
if (isMobile) {
return (
<div className={`flex min-h-screen items-center justify-center p-4 ${isDark ? 'bg-slate-950 text-slate-100' : 'bg-slate-50 text-slate-900'}`}>
<div
className={`flex min-h-screen items-center justify-center p-4 ${isDark ? 'bg-slate-950 text-slate-100' : 'bg-slate-50 text-slate-900'}`}
>
Tab...
</div>
);
@@ -178,8 +181,14 @@ function OrdersContent() {
subtitle={userInfo?.username || `用户 #${effectiveUserId}`}
actions={
<>
<button type="button" onClick={() => loadOrders(page, pageSize)} className={btnClass}></button>
{!srcHost && <a href={buildScopedUrl('/pay')} className={btnClass}></a>}
<button type="button" onClick={() => loadOrders(page, pageSize)} className={btnClass}>
</button>
{!srcHost && (
<a href={buildScopedUrl('/pay')} className={btnClass}>
</a>
)}
</>
}
>
@@ -208,7 +217,13 @@ function OrdersContent() {
export default function OrdersPage() {
return (
<Suspense fallback={<div className="flex min-h-screen items-center justify-center"><div className="text-gray-500">...</div></div>}>
<Suspense
fallback={
<div className="flex min-h-screen items-center justify-center">
<div className="text-gray-500">...</div>
</div>
}
>
<OrdersContent />
</Suspense>
);

View File

@@ -72,16 +72,18 @@ function StripePopupContent() {
if (isAlipay) {
// Alipay: confirm directly and redirect, no Payment Element needed
stripe.confirmAlipayPayment(clientSecret, {
return_url: buildReturnUrl(),
}).then((result) => {
if (cancelled) return;
if (result.error) {
setStripeError(result.error.message || '支付失败,请重试');
setStripeLoaded(true);
}
// If no error, the page has already been redirected
});
stripe
.confirmAlipayPayment(clientSecret, {
return_url: buildReturnUrl(),
})
.then((result) => {
if (cancelled) return;
if (result.error) {
setStripeError(result.error.message || '支付失败,请重试');
setStripeLoaded(true);
}
// If no error, the page has already been redirected
});
return;
}
@@ -97,7 +99,9 @@ function StripePopupContent() {
setStripeLoaded(true);
});
});
return () => { cancelled = true; };
return () => {
cancelled = true;
};
}, [credentials, isDark, isAlipay, buildReturnUrl]);
// Mount Payment Element (only for non-alipay methods)
@@ -151,12 +155,12 @@ function StripePopupContent() {
if (!credentials) {
return (
<div className={`flex min-h-screen items-center justify-center p-4 ${isDark ? 'bg-slate-950' : 'bg-slate-50'}`}>
<div className={`w-full max-w-md space-y-4 rounded-2xl border p-6 ${isDark ? 'border-slate-700 bg-slate-900' : 'border-slate-200 bg-white'} shadow-lg`}>
<div
className={`w-full max-w-md space-y-4 rounded-2xl border p-6 ${isDark ? 'border-slate-700 bg-slate-900' : 'border-slate-200 bg-white'} shadow-lg`}
>
<div className="flex items-center justify-center py-8">
<div className="h-8 w-8 animate-spin rounded-full border-2 border-[#635bff] border-t-transparent" />
<span className={`ml-3 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
...
</span>
<span className={`ml-3 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>...</span>
</div>
</div>
</div>
@@ -167,18 +171,19 @@ function StripePopupContent() {
if (isAlipay) {
return (
<div className={`flex min-h-screen items-center justify-center p-4 ${isDark ? 'bg-slate-950' : 'bg-slate-50'}`}>
<div className={`w-full max-w-md space-y-4 rounded-2xl border p-6 ${isDark ? 'border-slate-700 bg-slate-900' : 'border-slate-200 bg-white'} shadow-lg`}>
<div
className={`w-full max-w-md space-y-4 rounded-2xl border p-6 ${isDark ? 'border-slate-700 bg-slate-900' : 'border-slate-200 bg-white'} shadow-lg`}
>
<div className="text-center">
<div className="text-3xl font-bold text-blue-600">{'\u00A5'}{amount.toFixed(2)}</div>
<p className={`mt-1 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
: {orderId}
</p>
<div className="text-3xl font-bold text-blue-600">
{'\u00A5'}
{amount.toFixed(2)}
</div>
<p className={`mt-1 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>: {orderId}</p>
</div>
{stripeError ? (
<div className="space-y-3">
<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>
<button
type="button"
onClick={() => window.close()}
@@ -202,20 +207,21 @@ function StripePopupContent() {
return (
<div className={`flex min-h-screen items-center justify-center p-4 ${isDark ? 'bg-slate-950' : 'bg-slate-50'}`}>
<div className={`w-full max-w-md space-y-4 rounded-2xl border p-6 ${isDark ? 'border-slate-700 bg-slate-900' : 'border-slate-200 bg-white'} shadow-lg`}>
<div
className={`w-full max-w-md space-y-4 rounded-2xl border p-6 ${isDark ? 'border-slate-700 bg-slate-900' : 'border-slate-200 bg-white'} shadow-lg`}
>
<div className="text-center">
<div className="text-3xl font-bold text-blue-600">{'\u00A5'}{amount.toFixed(2)}</div>
<p className={`mt-1 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
: {orderId}
</p>
<div className="text-3xl font-bold text-blue-600">
{'\u00A5'}
{amount.toFixed(2)}
</div>
<p className={`mt-1 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>: {orderId}</p>
</div>
{!stripeLoaded ? (
<div className="flex items-center justify-center py-8">
<div className="h-8 w-8 animate-spin rounded-full border-2 border-[#635bff] border-t-transparent" />
<span className={`ml-3 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
...
</span>
<span className={`ml-3 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>...</span>
</div>
) : stripeSuccess ? (
<div className="py-6 text-center">
@@ -234,9 +240,7 @@ function StripePopupContent() {
) : (
<>
{stripeError && (
<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}