sysmgr-nest/src/login-logs/login-logs.service.ts
liuyun 537ec4fd91 feat(rbac): 数据权限扩展至组织树与审计/登录日志
- orgs: 列表按可见部门过滤
- audit-logs/login-logs: 按操作人所属部门过滤(self 按 userId/username)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-11 16:24:51 +08:00

59 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Injectable } from '@nestjs/common';
import { InjectPinoLogger, PinoLogger } from 'nestjs-pino';
import { BaseCrudService } from '../common/base-crud.service.js';
import { PrismaService } from '../prisma/prisma.service.js';
import { getRequestContext } from '../common/context/request-context.js';
import { ListLoginLogQuery } from './dto.js';
export interface LoginLogEntry {
tenantCode: string;
username?: string | null;
ip?: string | null;
userAgent?: string | null;
status: string;
message?: string | null;
}
@Injectable()
export class LoginLogsService extends BaseCrudService {
constructor(
prisma: PrismaService,
@InjectPinoLogger(LoginLogsService.name) private readonly logger: PinoLogger,
) {
super(prisma, 'loginLog');
}
/** 写入一条登录日志;失败仅告警,不抛出。 */
async record(data: LoginLogEntry): Promise<void> {
try {
await this.db().create({ data });
} catch (err) {
this.logger.warn({ err }, '登录日志写入失败');
}
}
async listLoginLogs(q: ListLoginLogQuery) {
const ctx = getRequestContext();
const where: Record<string, unknown> = {};
if (q.username) where.username = { contains: q.username };
if (q.status) where.status = q.status;
// 数据权限:仅本人按 username;否则按可见部门内的用户
if (ctx && ctx.dataScope !== 'all') {
if (ctx.dataScope === 'self') {
where.username = ctx.username;
} else {
const usernames = ctx.orgCodes.length
? (
await this.prisma.client.user.findMany({
where: { tenantCode: ctx.tenantCode, orgCode: { in: ctx.orgCodes }, deletedAt: null },
select: { username: true },
})
).map((u) => u.username)
: [];
where.username = { in: usernames };
}
}
return this.paginate(q.page, q.pageSize, where);
}
}