fix: paginate operational list pages

This commit is contained in:
hectorzhao
2026-07-28 23:20:13 +08:00
parent 87c5b1eccc
commit b8560372cc
40 changed files with 1208 additions and 422 deletions
+12 -6
View File
@@ -30,8 +30,10 @@ export class ChannelsController {
constructor(private readonly channels: ChannelsService, private readonly deletions: DeletionGovernanceService) {}
@Get('channels')
listChannels() {
return this.channels.listChannels();
listChannels(@Query('keyword') keyword?: string, @Query('carrier') carrier?: string, @Query('status') status?: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) {
return page || pageSize
? this.channels.listChannelsPage({ keyword, carrier, status, page: Number(page), pageSize: Number(pageSize) })
: this.channels.listChannels();
}
@Post('channels')
@@ -167,8 +169,10 @@ export class ChannelsController {
}
@Get('report-tasks')
listReportTasks(@Query('tenantId') tenantId?: string, @Query('status') status?: string, @Query('channelId') channelId?: string, @Query('reportType') reportType?: string) {
return this.channels.listReportTasks(tenantId, status, channelId, reportType);
listReportTasks(@Query('tenantId') tenantId?: string, @Query('status') status?: string, @Query('channelId') channelId?: string, @Query('reportType') reportType?: string, @Query('keyword') keyword?: string, @Query('createdAtFrom') createdAtFrom?: string, @Query('createdAtTo') createdAtTo?: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) {
return page || pageSize || keyword || createdAtFrom || createdAtTo
? this.channels.listReportTasksPage({ tenantId, status, channelId, reportType, keyword, createdAtFrom, createdAtTo, page: Number(page), pageSize: Number(pageSize) })
: this.channels.listReportTasks(tenantId, status, channelId, reportType);
}
@Post('report-tasks/generate')
@@ -193,7 +197,9 @@ export class ChannelsController {
}
@Get('report-records')
listReportRecords(@Query('taskId') taskId?: string, @Query('channelId') channelId?: string) {
return this.channels.listReportRecords(taskId, channelId);
listReportRecords(@Query('taskId') taskId?: string, @Query('channelId') channelId?: string, @Query('keyword') keyword?: string, @Query('reportType') reportType?: string, @Query('createdAtFrom') createdAtFrom?: string, @Query('createdAtTo') createdAtTo?: string, @Query('page') page?: string, @Query('pageSize') pageSize?: string) {
return page || pageSize || keyword || reportType || createdAtFrom || createdAtTo
? this.channels.listReportRecordsPage({ taskId, channelId, keyword, reportType, createdAtFrom, createdAtTo, page: Number(page), pageSize: Number(pageSize) })
: this.channels.listReportRecords(taskId, channelId);
}
}
+122
View File
@@ -252,6 +252,27 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
});
}
async listChannelsPage(query: { keyword?: string; carrier?: string; status?: string; page?: number; pageSize?: number }) {
const page = Math.max(1, Math.floor(Number(query.page) || 1));
const pageSize = Math.min(100, Math.max(1, Math.floor(Number(query.pageSize) || 10)));
const where: Prisma.SmsChannelWhereInput = {
status: query.status && query.status !== 'all' ? query.status : { not: 'deleted' },
carrier: query.carrier && query.carrier !== 'all' ? query.carrier : undefined,
name: query.keyword?.trim() ? { contains: query.keyword.trim() } : undefined,
};
const [items, total] = await Promise.all([
this.prisma.smsChannel.findMany({
where,
include: { connectionStates: true },
orderBy: [{ createdAt: 'desc' }, { id: 'desc' }],
skip: (page - 1) * pageSize,
take: pageSize,
}),
this.prisma.smsChannel.count({ where }),
]);
return { items, total, page, pageSize };
}
async createChannel(data: CreateChannelDto) {
assertMoneyUnits(data.unitPrice ?? 0, '通道单价');
const missingFields = ['code', 'name', 'gatewayHost', 'account', 'passwordCipher', 'srcId'].filter((field) => {
@@ -1281,6 +1302,63 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
});
}
async listReportTasksPage(query: {
tenantId?: string;
status?: string;
channelId?: string;
reportType?: string;
keyword?: string;
createdAtFrom?: string;
createdAtTo?: string;
page?: number;
pageSize?: number;
}) {
const page = Math.max(1, Math.floor(Number(query.page) || 1));
const pageSize = Math.min(100, Math.max(1, Math.floor(Number(query.pageSize) || 10)));
const keyword = query.keyword?.trim();
const where: Prisma.ChannelSignatureReportTaskWhereInput = {
tenantId: query.tenantId,
status: query.status,
channelId: query.channelId,
reportType: query.reportType,
signature: { auditStatus: { not: 'deleted' } },
createdAt: query.createdAtFrom || query.createdAtTo ? {
gte: query.createdAtFrom ? new Date(`${query.createdAtFrom}T00:00:00+08:00`) : undefined,
lte: query.createdAtTo ? new Date(`${query.createdAtTo}T23:59:59.999+08:00`) : undefined,
} : undefined,
OR: keyword ? [
{ id: { contains: keyword } },
{ channel: { name: { contains: keyword } } },
{ signature: { name: { contains: keyword } } },
{ signature: { tenant: { name: { contains: keyword } } } },
{ signature: { application: { name: { contains: keyword } } } },
{ drainageInfo: { siteName: { contains: keyword } } },
{ drainageInfo: { url: { contains: keyword } } },
] : undefined,
};
const [items, total] = await Promise.all([
this.prisma.channelSignatureReportTask.findMany({
where,
include: {
signature: { include: { tenant: true, application: true } },
channel: true,
drainageInfo: true,
exportItems: {
include: { exportFile: true, batchItem: { include: { batch: true } } },
orderBy: { id: 'desc' },
take: 1,
},
records: { orderBy: { createdAt: 'desc' }, take: 20 },
},
orderBy: [{ createdAt: 'desc' }, { id: 'desc' }],
skip: (page - 1) * pageSize,
take: pageSize,
}),
this.prisma.channelSignatureReportTask.count({ where }),
]);
return { items, total, page, pageSize };
}
async createReportTask(data: CreateReportTaskDto) {
const reportType = data.reportType ?? 'signature';
if (reportType === 'drainage' && !data.drainageItemId) throw new BadRequestException('drainageItemId is required');
@@ -1414,6 +1492,50 @@ export class ChannelsService implements OnModuleInit, OnModuleDestroy {
});
}
async listReportRecordsPage(query: {
taskId?: string;
channelId?: string;
keyword?: string;
reportType?: string;
createdAtFrom?: string;
createdAtTo?: string;
page?: number;
pageSize?: number;
}) {
const page = Math.max(1, Math.floor(Number(query.page) || 1));
const pageSize = Math.min(100, Math.max(1, Math.floor(Number(query.pageSize) || 10)));
const keyword = query.keyword?.trim();
const where: Prisma.ChannelSignatureReportRecordWhereInput = {
taskId: query.taskId,
channelId: query.channelId,
task: query.reportType ? { reportType: query.reportType } : undefined,
createdAt: query.createdAtFrom || query.createdAtTo ? {
gte: query.createdAtFrom ? new Date(`${query.createdAtFrom}T00:00:00+08:00`) : undefined,
lte: query.createdAtTo ? new Date(`${query.createdAtTo}T23:59:59.999+08:00`) : undefined,
} : undefined,
OR: keyword ? [
{ taskId: { contains: keyword } },
{ action: { contains: keyword } },
{ reason: { contains: keyword } },
{ channel: { name: { contains: keyword } } },
{ task: { signature: { name: { contains: keyword } } } },
{ task: { drainageInfo: { siteName: { contains: keyword } } } },
{ task: { drainageInfo: { url: { contains: keyword } } } },
] : undefined,
};
const [items, total] = await Promise.all([
this.prisma.channelSignatureReportRecord.findMany({
where,
include: { channel: true, task: { include: { signature: true, drainageInfo: true } } },
orderBy: [{ createdAt: 'desc' }, { id: 'desc' }],
skip: (page - 1) * pageSize,
take: pageSize,
}),
this.prisma.channelSignatureReportRecord.count({ where }),
]);
return { items, total, page, pageSize };
}
private async getReportTaskOrThrow(taskId: string) {
const task = await this.prisma.channelSignatureReportTask.findUnique({ where: { id: taskId }, include: { drainageInfo: true } });
if (!task) {