feat: list search filters for user/config/role/audit-log/login-log

- user/config/role/audit-log/login-log 列表增加搜索过滤(ListXxxQuery)
- audit-logs/login-logs 新增 dto + listXxx 方法

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-11 12:46:10 +08:00
parent 489d7232e3
commit f516e98f7f
12 changed files with 112 additions and 16 deletions

View File

@ -1,7 +1,7 @@
import { Controller, Get, Query } from '@nestjs/common';
import { PageQuery } from '../common/page.dto.js';
import { Permissions } from '../common/permissions.js';
import { RequirePermissions } from '../auth/decorators.js';
import { ListAuditLogQuery } from './dto.js';
import { AuditLogsService } from './audit-logs.service.js';
@Controller('audit-logs')
@ -10,7 +10,7 @@ export class AuditLogsController {
@Get()
@RequirePermissions(Permissions.audit.list)
list(@Query() q: PageQuery) {
return this.service.paginate(q.page, q.pageSize);
list(@Query() q: ListAuditLogQuery) {
return this.service.listAuditLogs(q);
}
}

View File

@ -2,6 +2,7 @@ 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 { ListAuditLogQuery } from './dto.js';
export interface AuditLogEntry {
tenantCode: string;
@ -37,4 +38,12 @@ export class AuditLogsService extends BaseCrudService {
this.logger.warn({ err }, '审计日志写入失败');
}
}
listAuditLogs(q: ListAuditLogQuery) {
const where: Record<string, unknown> = {};
if (q.username) where.username = { contains: q.username };
if (q.module) where.module = { contains: q.module };
if (q.status) where.status = q.status;
return this.paginate(q.page, q.pageSize, where);
}
}

20
src/audit-logs/dto.ts Normal file
View File

@ -0,0 +1,20 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString } from 'class-validator';
import { PageQuery } from '../common/page.dto.js';
export class ListAuditLogQuery extends PageQuery {
@ApiPropertyOptional({ description: '操作人(模糊)' })
@IsOptional()
@IsString()
username?: string;
@ApiPropertyOptional({ description: '模块(模糊)' })
@IsOptional()
@IsString()
module?: string;
@ApiPropertyOptional({ description: '状态:success/fail' })
@IsOptional()
@IsString()
status?: string;
}

View File

@ -1,8 +1,7 @@
import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common';
import { PageQuery } from '../common/page.dto.js';
import { Permissions } from '../common/permissions.js';
import { AuditLog, RequirePermissions } from '../auth/decorators.js';
import { CreateConfigDto, UpdateConfigDto } from './dto.js';
import { CreateConfigDto, ListConfigQuery, UpdateConfigDto } from './dto.js';
import { ConfigsService } from './configs.service.js';
@Controller('configs')
@ -11,8 +10,8 @@ export class ConfigsController {
@Get()
@RequirePermissions(Permissions.config.list)
list(@Query() q: PageQuery) {
return this.service.paginate(q.page, q.pageSize);
list(@Query() q: ListConfigQuery) {
return this.service.listConfigs(q);
}
@Get(':id')

View File

@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { BaseCrudService } from '../common/base-crud.service.js';
import { PrismaService } from '../prisma/prisma.service.js';
import { CreateConfigDto, UpdateConfigDto } from './dto.js';
import { CreateConfigDto, ListConfigQuery, UpdateConfigDto } from './dto.js';
@Injectable()
export class ConfigsService extends BaseCrudService {
@ -16,4 +16,11 @@ export class ConfigsService extends BaseCrudService {
updateConfig(id: string, dto: UpdateConfigDto) {
return this.update(id, { ...dto });
}
listConfigs(q: ListConfigQuery) {
const where: Record<string, unknown> = {};
if (q.key) where.key = { contains: q.key };
if (q.value) where.value = { contains: q.value };
return this.paginate(q.page, q.pageSize, where);
}
}

View File

@ -1,5 +1,6 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { PageQuery } from '../common/page.dto.js';
export class CreateConfigDto {
@ApiProperty({ description: '配置 key(租户内唯一)' })
@ -29,3 +30,15 @@ export class UpdateConfigDto {
@IsString()
remark?: string;
}
export class ListConfigQuery extends PageQuery {
@ApiPropertyOptional({ description: '键名(模糊)' })
@IsOptional()
@IsString()
key?: string;
@ApiPropertyOptional({ description: '值(模糊)' })
@IsOptional()
@IsString()
value?: string;
}

15
src/login-logs/dto.ts Normal file
View File

@ -0,0 +1,15 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString } from 'class-validator';
import { PageQuery } from '../common/page.dto.js';
export class ListLoginLogQuery extends PageQuery {
@ApiPropertyOptional({ description: '用户名(模糊)' })
@IsOptional()
@IsString()
username?: string;
@ApiPropertyOptional({ description: '状态:success/fail' })
@IsOptional()
@IsString()
status?: string;
}

View File

@ -1,7 +1,7 @@
import { Controller, Get, Query } from '@nestjs/common';
import { PageQuery } from '../common/page.dto.js';
import { Permissions } from '../common/permissions.js';
import { RequirePermissions } from '../auth/decorators.js';
import { ListLoginLogQuery } from './dto.js';
import { LoginLogsService } from './login-logs.service.js';
@Controller('login-logs')
@ -10,7 +10,7 @@ export class LoginLogsController {
@Get()
@RequirePermissions(Permissions.loginLog.list)
list(@Query() q: PageQuery) {
return this.service.paginate(q.page, q.pageSize);
list(@Query() q: ListLoginLogQuery) {
return this.service.listLoginLogs(q);
}
}

View File

@ -2,6 +2,7 @@ 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 { ListLoginLogQuery } from './dto.js';
export interface LoginLogEntry {
tenantCode: string;
@ -29,4 +30,11 @@ export class LoginLogsService extends BaseCrudService {
this.logger.warn({ err }, '登录日志写入失败');
}
}
listLoginLogs(q: ListLoginLogQuery) {
const where: Record<string, unknown> = {};
if (q.username) where.username = { contains: q.username };
if (q.status) where.status = q.status;
return this.paginate(q.page, q.pageSize, where);
}
}

View File

@ -1,5 +1,6 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsArray, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { PageQuery } from '../common/page.dto.js';
export class CreateRoleDto {
@ApiProperty({ description: '角色编码' })
@ -51,3 +52,20 @@ export class AssignResourcesDto {
@IsString({ each: true })
resourceCodes!: string[];
}
export class ListRoleQuery extends PageQuery {
@ApiPropertyOptional({ description: '角色名称(模糊)' })
@IsOptional()
@IsString()
name?: string;
@ApiPropertyOptional({ description: '角色编码(模糊)' })
@IsOptional()
@IsString()
code?: string;
@ApiPropertyOptional({ description: '状态:enabled/disabled' })
@IsOptional()
@IsString()
status?: string;
}

View File

@ -1,8 +1,7 @@
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common';
import { PageQuery } from '../common/page.dto.js';
import { Permissions } from '../common/permissions.js';
import { AuditLog, RequirePermissions } from '../auth/decorators.js';
import { AssignResourcesDto, CreateRoleDto, UpdateRoleDto } from './dto.js';
import { AssignResourcesDto, CreateRoleDto, ListRoleQuery, UpdateRoleDto } from './dto.js';
import { RolesService } from './roles.service.js';
@Controller('roles')
@ -11,8 +10,8 @@ export class RolesController {
@Get()
@RequirePermissions(Permissions.role.list)
list(@Query() q: PageQuery) {
return this.service.paginate(q.page, q.pageSize);
list(@Query() q: ListRoleQuery) {
return this.service.listRoles(q);
}
@Get(':id')

View File

@ -3,7 +3,7 @@ import { BaseCrudService } from '../common/base-crud.service.js';
import { PrismaService } from '../prisma/prisma.service.js';
import { RedisService } from '../common/redis/redis.service.js';
import { getRequestContext } from '../common/context/request-context.js';
import { AssignResourcesDto, CreateRoleDto, UpdateRoleDto } from './dto.js';
import { AssignResourcesDto, CreateRoleDto, ListRoleQuery, UpdateRoleDto } from './dto.js';
@Injectable()
export class RolesService extends BaseCrudService {
@ -22,6 +22,14 @@ export class RolesService extends BaseCrudService {
return this.update(id, { ...dto });
}
listRoles(q: ListRoleQuery) {
const where: Record<string, unknown> = {};
if (q.name) where.name = { contains: q.name };
if (q.code) where.code = { contains: q.code };
if (q.status) where.status = q.status;
return this.paginate(q.page, q.pageSize, where);
}
async assignedResources(roleCode: string) {
const ctx = getRequestContext()!;
const rows = await this.prisma.client.roleResource.findMany({