113 lines
3.6 KiB
TypeScript
113 lines
3.6 KiB
TypeScript
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),
|
|
});
|
|
}
|
|
}
|