feat: 订单列表支持分页查询,分页大小可选 20/50/100

- /api/orders/my 新增 page/page_size 参数,返回分页信息和全局状态统计
- 用户订单页:分页控件(首/上/下/末页)+ 分页大小选择,摘要卡片改为全局统计
- 管理员订单页:分页大小选择器(20/50/100)+ 首尾页跳转按钮
This commit is contained in:
erio
2026-03-01 20:04:49 +08:00
parent e4005da38e
commit 292c14b882
3 changed files with 210 additions and 70 deletions

View File

@@ -3,28 +3,44 @@ import { prisma } from '@/lib/db';
import { getCurrentUserByToken } from '@/lib/sub2api/client';
import { deriveOrderState, isRechargeRetryable } from '@/lib/order/status';
const VALID_PAGE_SIZES = [20, 50, 100];
export async function GET(request: NextRequest) {
const token = request.nextUrl.searchParams.get('token')?.trim();
const searchParams = request.nextUrl.searchParams;
const token = searchParams.get('token')?.trim();
if (!token) {
return NextResponse.json({ error: 'token is required' }, { status: 400 });
}
const page = Math.max(1, Number(searchParams.get('page') || '1'));
const rawPageSize = Number(searchParams.get('page_size') || '20');
const pageSize = VALID_PAGE_SIZES.includes(rawPageSize) ? rawPageSize : 20;
try {
const user = await getCurrentUserByToken(token);
const orders = await prisma.order.findMany({
where: { userId: user.id },
orderBy: { createdAt: 'desc' },
take: 20,
select: {
id: true,
amount: true,
status: true,
paymentType: true,
createdAt: true,
paidAt: true,
completedAt: true,
},
});
const where = { userId: user.id };
const [orders, total, statusGroups] = await Promise.all([
prisma.order.findMany({
where,
orderBy: { createdAt: 'desc' },
skip: (page - 1) * pageSize,
take: pageSize,
select: {
id: true,
amount: true,
status: true,
paymentType: true,
createdAt: true,
paidAt: true,
completedAt: true,
},
}),
prisma.order.count({ where }),
prisma.order.groupBy({ by: ['status'], where, _count: true }),
]);
const sc = Object.fromEntries(statusGroups.map((g) => [g.status, g._count]));
return NextResponse.json({
user: {
@@ -48,6 +64,15 @@ export async function GET(request: NextRequest) {
rechargeRetryable: isRechargeRetryable(item),
};
}),
summary: {
total,
pending: sc['PENDING'] || 0,
completed: (sc['COMPLETED'] || 0) + (sc['PAID'] || 0) + (sc['RECHARGING'] || 0),
failed: (sc['FAILED'] || 0) + (sc['CANCELLED'] || 0) + (sc['EXPIRED'] || 0),
},
page,
page_size: pageSize,
total_pages: Math.ceil(total / pageSize),
});
} catch (error) {
console.error('Get my orders error:', error);