feat: improve operations diagnostics and channel management

This commit is contained in:
hectorzhao
2026-08-09 14:27:19 +08:00
parent 44352aeb2f
commit 4724b9db6a
65 changed files with 1211 additions and 293 deletions
+48 -6
View File
@@ -45,31 +45,51 @@ export class ReportsService implements OnModuleInit, OnModuleDestroy {
async listReconciliation(query: ReportListQuery) {
const { page, pageSize, skip } = pagination(query);
const where = reconciliationWhere(query);
const [items, total] = await Promise.all([
const [items, total, aggregate] = await Promise.all([
this.prisma.dailyReconciliationReport.findMany({ where, orderBy: [{ reportDate: 'desc' }, { tenantName: 'asc' }, { applicationName: 'asc' }], skip, take: pageSize }),
this.prisma.dailyReconciliationReport.count({ where }),
this.prisma.dailyReconciliationReport.aggregate({ where, _sum: reportVolumeSumSelection }),
]);
return { items, total, page, pageSize };
return { items, total, page, pageSize, summary: volumeSummary(aggregate._sum) };
}
async listProfit(query: ReportListQuery) {
const { page, pageSize, skip } = pagination(query);
const { dimensionType, where } = profitWhere(query);
const [items, total] = await Promise.all([
const [items, total, aggregate] = await Promise.all([
this.prisma.dailyProfitReport.findMany({ where, orderBy: [{ reportDate: 'desc' }, { dimensionName: 'asc' }], skip, take: pageSize }),
this.prisma.dailyProfitReport.count({ where }),
this.prisma.dailyProfitReport.aggregate({
where,
_sum: { ...reportVolumeSumSelection, revenueCents: true, refundCents: true, costCents: true, profitCents: true },
}),
]);
return { items, total, page, pageSize, dimensionType };
const summary = {
...volumeSummary(aggregate._sum),
revenueCents: Number(aggregate._sum.revenueCents ?? 0),
refundCents: Number(aggregate._sum.refundCents ?? 0),
costCents: Number(aggregate._sum.costCents ?? 0),
profitCents: Number(aggregate._sum.profitCents ?? 0),
// 利润率必须用全量筛选结果的合计利润/合计收入重新计算,不能对每日百分比求和或简单平均。
profitRateBps: ratioBps(Number(aggregate._sum.profitCents ?? 0), Number(aggregate._sum.revenueCents ?? 0)),
};
return { items, total, page, pageSize, dimensionType, summary };
}
async listQuality(query: ReportListQuery) {
const { page, pageSize, skip } = pagination(query);
const { dimensionType, where } = qualityWhere(query);
const [items, total] = await Promise.all([
const [items, total, aggregate] = await Promise.all([
this.prisma.dailyQualityReport.findMany({ where, orderBy: [{ sentUnits: 'desc' }, { reportDate: 'desc' }, { dimensionName: 'asc' }], skip, take: pageSize }),
this.prisma.dailyQualityReport.count({ where }),
this.prisma.dailyQualityReport.aggregate({ where, _sum: reportVolumeSumSelection }),
]);
return { items, total, page, pageSize, dimensionType };
const summary = {
...volumeSummary(aggregate._sum),
// 成功率按全量筛选结果的成功量/发送量重新计算,避免分页和分组大小导致失真。
successRateBps: ratioBps(Number(aggregate._sum.successUnits ?? 0), Number(aggregate._sum.sentUnits ?? 0)),
};
return { items, total, page, pageSize, dimensionType, summary };
}
async exportReconciliation(query: ReportListQuery) {
@@ -516,6 +536,28 @@ function pagination(query: ReportListQuery) {
return { page, pageSize, skip: (page - 1) * pageSize };
}
const reportVolumeSumSelection = {
submittedUnits: true,
sentUnits: true,
unknownUnits: true,
successUnits: true,
failedUnits: true,
} as const;
function volumeSummary(sum: { submittedUnits?: number | null; sentUnits?: number | null; unknownUnits?: number | null; successUnits?: number | null; failedUnits?: number | null }) {
return {
submittedUnits: Number(sum.submittedUnits ?? 0),
sentUnits: Number(sum.sentUnits ?? 0),
unknownUnits: Number(sum.unknownUnits ?? 0),
successUnits: Number(sum.successUnits ?? 0),
failedUnits: Number(sum.failedUnits ?? 0),
};
}
function ratioBps(numerator: number, denominator: number) {
return denominator === 0 ? 0 : Math.round(numerator * 10_000 / denominator);
}
function reconciliationWhere(query: ReportListQuery): Prisma.DailyReconciliationReportWhereInput {
return { reportDate: dateFilter(query.dateFrom, query.dateTo), tenantId: query.tenantId || undefined, applicationId: query.applicationId || undefined };
}