import { Injectable, NotFoundException } from '@nestjs/common'; import { Prisma } from '@prisma/client'; import { eventNamesForUserLogCategory, resolveUserLogCategory } from '@dukang/shared-types'; import { PrismaService } from '../../common/prisma/prisma.module'; import { serializeBigInt } from '../../common/decorators/current-user.decorator'; import type { AdminUserLogsQueryDto } from './dto/admin-query.dto'; @Injectable() export class AdminUserLogsService { constructor(private readonly prisma: PrismaService) {} async list(query: AdminUserLogsQueryDto) { const page = query.page ?? 1; const pageSize = query.pageSize ?? 20; const where: Prisma.LogUserAnalyticsWhereInput = {}; if (query.userId) { where.userId = BigInt(query.userId); } else if (query.phone || query.userNo) { const userWhere: Prisma.UserWhereInput = {}; if (query.phone) userWhere.phone = { contains: query.phone }; if (query.userNo) userWhere.userNo = { contains: query.userNo }; const users = await this.prisma.user.findMany({ where: userWhere, select: { id: true }, take: 100, }); if (users.length === 0) { return { items: [], total: 0, page, pageSize }; } where.userId = { in: users.map((u) => u.id) }; } if (query.eventName) { where.eventName = query.eventName; } else if (query.category) { const names = eventNamesForUserLogCategory(query.category); if (names?.length) { where.eventName = { in: names }; } } if (query.from || query.to) { where.createdAt = { ...(query.from ? { gte: new Date(query.from) } : {}), ...(query.to ? { lte: new Date(query.to) } : {}), }; } const [rows, total] = await Promise.all([ this.prisma.logUserAnalytics.findMany({ where, orderBy: { createdAt: 'desc' }, skip: (page - 1) * pageSize, take: pageSize, }), this.prisma.logUserAnalytics.count({ where }), ]); const userIds = [...new Set(rows.map((r) => r.userId).filter((id): id is bigint => id != null))]; const users = userIds.length ? await this.prisma.user.findMany({ where: { id: { in: userIds } }, select: { id: true, userNo: true, phone: true, nickname: true }, }) : []; const userMap = new Map(users.map((u) => [u.id.toString(), u])); return serializeBigInt({ items: rows.map((row) => { const user = row.userId ? userMap.get(row.userId.toString()) : undefined; return { id: row.id, userId: row.userId, userNo: user?.userNo ?? null, phone: user?.phone ?? null, nickname: user?.nickname ?? null, category: resolveUserLogCategory(row.eventName), eventName: row.eventName, clientApp: row.clientApp, refType: row.refType, refId: row.refId, extraJson: row.extraJson, createdAt: row.createdAt, }; }), total, page, pageSize, }); } async detail(id: bigint) { const row = await this.prisma.logUserAnalytics.findUnique({ where: { id } }); if (!row) throw new NotFoundException('日志不存在'); const user = row.userId ? await this.prisma.user.findUnique({ where: { id: row.userId }, select: { id: true, userNo: true, phone: true, nickname: true }, }) : null; return serializeBigInt({ ...row, userNo: user?.userNo ?? null, phone: user?.phone ?? null, nickname: user?.nickname ?? null, category: resolveUserLogCategory(row.eventName), }); } }