feat: multi-module iteration

This commit is contained in:
2026-08-04 21:38:49 +08:00
parent 9d96c73246
commit 71f508e02b
1366 changed files with 202004 additions and 0 deletions
@@ -0,0 +1,161 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import {
eventNamesForPartnerLogCategory,
resolvePartnerLogCategory,
} from '@dukang/shared-types';
import { PrismaService } from '../../common/prisma/prisma.module';
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
import type { AdminPartnerLogsQueryDto } from './dto/admin-query.dto';
@Injectable()
export class AdminPartnerLogsService {
constructor(private readonly prisma: PrismaService) {}
async list(query: AdminPartnerLogsQueryDto) {
const page = query.page ?? 1;
const pageSize = query.pageSize ?? 20;
const partnerAccountIds = await this.resolvePartnerAccountIds(query);
if (partnerAccountIds && partnerAccountIds.length === 0) {
return { items: [], total: 0, page, pageSize };
}
const where = this.buildWhere(query, partnerAccountIds);
const [rows, total] = await Promise.all([
this.prisma.logPartnerAnalytics.findMany({
where,
orderBy: { createdAt: 'desc' },
skip: (page - 1) * pageSize,
take: pageSize,
}),
this.prisma.logPartnerAnalytics.count({ where }),
]);
const items = await this.enrichRows(rows);
return serializeBigInt({ items, total, page, pageSize });
}
async detail(id: string) {
const row = await this.prisma.logPartnerAnalytics.findUnique({ where: { id: BigInt(id) } });
if (!row) throw new NotFoundException('日志不存在');
const [item] = await this.enrichRows([row]);
return serializeBigInt(item);
}
private buildWhere(
query: AdminPartnerLogsQueryDto,
partnerAccountIds?: bigint[],
): Prisma.LogPartnerAnalyticsWhereInput {
const where: Prisma.LogPartnerAnalyticsWhereInput = {};
if (partnerAccountIds) where.partnerAccountId = { in: partnerAccountIds };
if (query.partnerAccountId) where.partnerAccountId = BigInt(query.partnerAccountId);
const categoryEvents = query.eventName
? [query.eventName]
: query.category
? eventNamesForPartnerLogCategory(query.category)
: undefined;
if (categoryEvents?.length) where.eventName = { in: categoryEvents };
if (query.from || query.to) {
where.createdAt = {
...(query.from ? { gte: new Date(query.from) } : {}),
...(query.to ? { lte: new Date(query.to) } : {}),
};
}
return where;
}
private async expandPrimaryWithChildren(primaryIds: bigint[]): Promise<bigint[]> {
if (!primaryIds.length) return [];
const children = await this.prisma.partnerAccount.findMany({
where: { parentAccountId: { in: primaryIds } },
select: { id: true },
});
return [...primaryIds, ...children.map((c) => c.id)];
}
private async resolvePartnerAccountIds(
query: AdminPartnerLogsQueryDto,
): Promise<bigint[] | undefined> {
if (query.partnerAccountId) return [BigInt(query.partnerAccountId)];
if (query.partnerId) {
return this.expandPrimaryWithChildren([BigInt(query.partnerId)]);
}
if (query.phone) {
const accounts = await this.prisma.partnerAccount.findMany({
where: { phone: { contains: query.phone } },
select: { id: true },
take: 200,
});
return accounts.map((a) => a.id);
}
if (query.companyName) {
const primaries = await this.prisma.partnerAccount.findMany({
where: { isPrimary: 1, companyName: { contains: query.companyName } },
select: { id: true },
take: 100,
});
return this.expandPrimaryWithChildren(primaries.map((a) => a.id));
}
return undefined;
}
private async enrichRows(
rows: Array<{
id: bigint;
partnerAccountId: bigint;
eventName: string;
clientApp: string | null;
refType: string | null;
refId: bigint | null;
extraJson: unknown;
createdAt: Date;
}>,
) {
const accountIds = [...new Set(rows.map((r) => r.partnerAccountId))];
const accounts = accountIds.length
? await this.prisma.partnerAccount.findMany({
where: { id: { in: accountIds } },
select: {
id: true,
name: true,
phone: true,
companyName: true,
isPrimary: true,
parentAccountId: true,
staffRole: true,
parent: { select: { id: true, companyName: true } },
},
})
: [];
const accountMap = new Map(accounts.map((a) => [a.id.toString(), a] as const));
return rows.map((row) => {
const account = accountMap.get(row.partnerAccountId.toString());
const isSubAccount = !!account?.parentAccountId;
const primaryId = isSubAccount
? account?.parent?.id?.toString() ?? null
: account?.id.toString() ?? null;
return {
id: row.id.toString(),
partnerId: primaryId ?? row.partnerAccountId.toString(),
partnerAccountId: row.partnerAccountId.toString(),
accountName: account?.name ?? null,
accountPhone: account?.phone ?? null,
companyName: isSubAccount ? null : account?.companyName ?? null,
isSubAccount,
staffRole: account?.staffRole ?? null,
category: resolvePartnerLogCategory(row.eventName),
eventName: row.eventName,
clientApp: row.clientApp,
refType: row.refType,
refId: row.refId?.toString() ?? null,
extraJson: (row.extraJson as Record<string, unknown> | null) ?? null,
createdAt: row.createdAt,
};
});
}
}