feat: 添加登陆日志模块
parent
2877bf29fc
commit
a693960017
Binary file not shown.
|
|
@ -1,12 +1,17 @@
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { ConfigService } from '@/config';
|
import { ConfigService } from '@/config';
|
||||||
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
||||||
|
import { EntitySubscripber } from './suscribers/entify.subscriber';
|
||||||
|
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
|
||||||
|
import { RequestMiddleware } from './suscribers/request.middleware';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据库模块
|
* 数据库模块
|
||||||
* @description 基于 `typeorm` 封装
|
* @description 基于 `typeorm` 封装
|
||||||
*/
|
*/
|
||||||
export const DatabaseModule = TypeOrmModule.forRootAsync({
|
@Module({
|
||||||
|
imports: [
|
||||||
|
TypeOrmModule.forRootAsync({
|
||||||
useFactory: (config: ConfigService) => {
|
useFactory: (config: ConfigService) => {
|
||||||
if (config.dbType === 'sqlite') {
|
if (config.dbType === 'sqlite') {
|
||||||
return {
|
return {
|
||||||
|
|
@ -21,4 +26,12 @@ export const DatabaseModule = TypeOrmModule.forRootAsync({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
});
|
}),
|
||||||
|
],
|
||||||
|
providers: [EntitySubscripber],
|
||||||
|
})
|
||||||
|
export class DatabaseModule implements NestModule {
|
||||||
|
configure(consumer: MiddlewareConsumer) {
|
||||||
|
consumer.apply(RequestMiddleware).forRoutes('*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,42 +13,48 @@ export class BaseEntity {
|
||||||
*/
|
*/
|
||||||
@PrimaryGeneratedColumn({ comment: '自增ID' })
|
@PrimaryGeneratedColumn({ comment: '自增ID' })
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
* @example "2022-01-01 10:10:10"
|
* @example "2022-01-01 10:10:10"
|
||||||
*/
|
*/
|
||||||
@CreateDateColumn({ comment: '创建时间' })
|
@CreateDateColumn({ comment: '创建时间' })
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建人ID
|
* 创建人
|
||||||
* @example 1
|
* @example '绝弹(1)'
|
||||||
*/
|
*/
|
||||||
@Column({ comment: '创建人', nullable: true })
|
@Column({ comment: '创建人', nullable: true })
|
||||||
createdBy: number;
|
createdBy: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新时间
|
* 更新时间
|
||||||
* @example "2022-01-02 11:11:11"
|
* @example "2022-01-02 11:11:11"
|
||||||
*/
|
*/
|
||||||
@UpdateDateColumn({ comment: '更新时间' })
|
@UpdateDateColumn({ comment: '更新时间' })
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新人ID
|
* 更新人
|
||||||
* @example 1
|
* @example '绝弹(1)'
|
||||||
*/
|
*/
|
||||||
@Column({ comment: '更新人', nullable: true })
|
@Column({ comment: '更新人', nullable: true })
|
||||||
updatedBy: number;
|
updatedBy: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除时间
|
* 删除时间
|
||||||
* @example "2022-01-03 12:12:12"
|
* @example "2022-01-03 12:12:12"
|
||||||
*/
|
*/
|
||||||
@Exclude()
|
@Exclude()
|
||||||
@DeleteDateColumn({ comment: '删除时间' })
|
@DeleteDateColumn({ comment: '删除时间', select: false })
|
||||||
deleteddAt: Date;
|
deleteddAt: Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除人ID
|
* 删除人ID
|
||||||
* @example 1
|
* @example 1
|
||||||
*/
|
*/
|
||||||
@Exclude()
|
@Exclude()
|
||||||
@Column({ comment: '删除人', nullable: true })
|
@Column({ comment: '删除人', nullable: true, select: false })
|
||||||
deletedBy: number;
|
deletedBy: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { EntitySubscriberInterface, InsertEvent, DataSource, UpdateEvent, SoftRemoveEvent } from 'typeorm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实体订阅器
|
||||||
|
* @description 自动插入创建/更新用户的ID
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class EntitySubscripber implements EntitySubscriberInterface {
|
||||||
|
static request: Request;
|
||||||
|
|
||||||
|
constructor(private datasource: DataSource) {
|
||||||
|
this.datasource.subscribers.push(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static setRequest(req: Request) {
|
||||||
|
this.request = req;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeInsert(event: InsertEvent<any>): void | Promise<any> {
|
||||||
|
event.entity.createdBy = this.getUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeUpdate(event: UpdateEvent<any>): void | Promise<any> {
|
||||||
|
event.entity.updatedBy = this.getUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeSoftRemove(event: SoftRemoveEvent<any>): void | Promise<any> {
|
||||||
|
event.entity.deletedBy = this.getUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser() {
|
||||||
|
const user = EntitySubscripber.request?.user;
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return `${user.nickname}(${user.id})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { EntitySubscripber } from './entify.subscriber';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RequestMiddleware<R extends Request = any, T = any> implements NestMiddleware<R, T> {
|
||||||
|
use(req: R, res: T, next: (error?: any) => void) {
|
||||||
|
EntitySubscripber.setRequest(req);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
|
import { Body, Controller, HttpCode, HttpStatus, Post, UseInterceptors } from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { AuthUserDto } from './dto/auth-user.dto';
|
import { AuthUserDto } from './dto/auth-user.dto';
|
||||||
import { Public } from './jwt';
|
import { Public } from './jwt';
|
||||||
import { LoginedUserVo } from './vo/logined-user.vo';
|
import { LoginedUserVo } from './vo/logined-user.vo';
|
||||||
|
import { AuthLogInterceptor } from '@/monitor/log';
|
||||||
|
|
||||||
@ApiTags('auth')
|
@ApiTags('auth')
|
||||||
@Controller('auth')
|
@Controller('auth')
|
||||||
|
|
@ -16,6 +17,7 @@ export class AuthController {
|
||||||
@Post('login')
|
@Post('login')
|
||||||
@Public()
|
@Public()
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@UseInterceptors(AuthLogInterceptor)
|
||||||
login(@Body() user: AuthUserDto): Promise<LoginedUserVo> {
|
login(@Body() user: AuthUserDto): Promise<LoginedUserVo> {
|
||||||
return this.authService.signIn(user);
|
return this.authService.signIn(user);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ export class AuthService {
|
||||||
throw new UnauthorizedException('密码错误');
|
throw new UnauthorizedException('密码错误');
|
||||||
}
|
}
|
||||||
const loginedUser = Object.assign(new LoginedUserVo(), user);
|
const loginedUser = Object.assign(new LoginedUserVo(), user);
|
||||||
loginedUser.token = await this.jwtService.signAsync({ id: user.id, username: user.username });
|
const { id, username, nickname } = loginedUser;
|
||||||
|
loginedUser.token = await this.jwtService.signAsync({ id, username, nickname });
|
||||||
return loginedUser;
|
return loginedUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
import { PartialType } from '@nestjs/swagger';
|
import { PartialType } from '@nestjs/swagger';
|
||||||
import { CreateRoleDto } from './create-role.dto';
|
import { CreateRoleDto } from './create-role.dto';
|
||||||
|
import { IsInt, IsOptional } from 'class-validator';
|
||||||
|
|
||||||
export class UpdateRoleDto extends PartialType(CreateRoleDto) {}
|
export class UpdateRoleDto extends PartialType(CreateRoleDto) {
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt({ each: true })
|
||||||
|
permissionIds?: number[];
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { BaseEntity } from '@/database';
|
import { BaseEntity } from '@/database';
|
||||||
import { Permission } from '@/modules/permission/entities/permission.entity';
|
import { Permission } from '@/modules/permission/entities/permission.entity';
|
||||||
import { User } from 'src/modules/user';
|
import { User } from 'src/modules/user';
|
||||||
import { Column, Entity, JoinTable, ManyToMany } from 'typeorm';
|
import { Column, Entity, JoinTable, ManyToMany, RelationId } from 'typeorm';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Role extends BaseEntity {
|
export class Role extends BaseEntity {
|
||||||
|
|
@ -11,18 +11,21 @@ export class Role extends BaseEntity {
|
||||||
*/
|
*/
|
||||||
@Column({ comment: '角色名称' })
|
@Column({ comment: '角色名称' })
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色标识
|
* 角色标识
|
||||||
* @example 'admin'
|
* @example 'admin'
|
||||||
*/
|
*/
|
||||||
@Column({ comment: '角色标识' })
|
@Column({ comment: '角色标识' })
|
||||||
slug: string;
|
slug: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色描述
|
* 角色描述
|
||||||
* @example '拥有所有权限'
|
* @example '拥有所有权限'
|
||||||
*/
|
*/
|
||||||
@Column({ comment: '角色描述', nullable: true })
|
@Column({ comment: '角色描述', nullable: true })
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色权限
|
* 角色权限
|
||||||
* @example [1, 2, 3]
|
* @example [1, 2, 3]
|
||||||
|
|
@ -30,6 +33,14 @@ export class Role extends BaseEntity {
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
@ManyToMany(() => Permission, (permission) => permission.roles)
|
@ManyToMany(() => Permission, (permission) => permission.roles)
|
||||||
permissions: Permission[];
|
permissions: Permission[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色权限ID
|
||||||
|
* @example [1, 2, 3]
|
||||||
|
*/
|
||||||
|
@RelationId('permissions')
|
||||||
|
permissionIds: number[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色用户
|
* 角色用户
|
||||||
* @example [1, 2, 3]
|
* @example [1, 2, 3]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { CreateRoleDto } from './dto/create-role.dto';
|
import { CreateRoleDto } from './dto/create-role.dto';
|
||||||
|
|
@ -26,7 +26,16 @@ export class RoleService {
|
||||||
return `This action returns a #${id} role`;
|
return `This action returns a #${id} role`;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id: number, updateRoleDto: UpdateRoleDto) {
|
async update(id: number, updateRoleDto: UpdateRoleDto) {
|
||||||
|
const role = this.roleRepository.findOne({ where: { id } });
|
||||||
|
if (!role) {
|
||||||
|
throw new NotFoundException('角色不存在');
|
||||||
|
}
|
||||||
|
if (updateRoleDto.permissionIds) {
|
||||||
|
const permissions = updateRoleDto.permissionIds.map((id) => ({ id }));
|
||||||
|
await this.roleRepository.save({ id, permissions });
|
||||||
|
delete updateRoleDto.permissionIds;
|
||||||
|
}
|
||||||
return this.roleRepository.update(id, updateRoleDto);
|
return this.roleRepository.update(id, updateRoleDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Role } from '@/modules/role/entities/role.entity';
|
|
||||||
import { IsInt, IsOptional, IsString } from 'class-validator';
|
import { IsInt, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class CreateUserDto {
|
export class CreateUserDto {
|
||||||
|
|
@ -8,12 +7,6 @@ export class CreateUserDto {
|
||||||
*/
|
*/
|
||||||
@IsString()
|
@IsString()
|
||||||
username: string;
|
username: string;
|
||||||
/**
|
|
||||||
* 用户密码
|
|
||||||
* @example 'password'
|
|
||||||
*/
|
|
||||||
@IsString()
|
|
||||||
password: string;
|
|
||||||
/**
|
/**
|
||||||
* 用户昵称
|
* 用户昵称
|
||||||
* @example '绝弹'
|
* @example '绝弹'
|
||||||
|
|
@ -21,17 +14,24 @@ export class CreateUserDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
nickname: string;
|
nickname: string;
|
||||||
/**
|
/**
|
||||||
* 用户头像
|
* 用户密码
|
||||||
* @example './assets/222421415123.png '
|
* @example 'password'
|
||||||
*/
|
*/
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
avatar: string;
|
password?: string;
|
||||||
/**
|
/**
|
||||||
* 用户角色
|
* 头像ID
|
||||||
|
* @example 1
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
avatarId?: number;
|
||||||
|
/**
|
||||||
|
* 角色ID列表
|
||||||
* @example [1, 2, 3]
|
* @example [1, 2, 3]
|
||||||
*/
|
*/
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt({ each: true })
|
@IsInt({ each: true })
|
||||||
roles: Role[];
|
roleIds?: number[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ export class User extends BaseEntity {
|
||||||
* 用户角色
|
* 用户角色
|
||||||
*/
|
*/
|
||||||
@ApiHideProperty()
|
@ApiHideProperty()
|
||||||
@ManyToMany(() => Role, (role) => role.user)
|
@ManyToMany(() => Role, (role) => role.user, { cascade: true })
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
roles: Role[];
|
roles: Role[];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { BaseService } from '@/common/base';
|
import { BaseService } from '@/common/base';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Like, Repository } from 'typeorm';
|
import { In, Like, Repository } from 'typeorm';
|
||||||
import { CreateUserDto } from './dto/create-user.dto';
|
import { CreateUserDto } from './dto/create-user.dto';
|
||||||
import { FindUserDto } from './dto/find-user.dto';
|
import { FindUserDto } from './dto/find-user.dto';
|
||||||
import { UpdateUserDto } from './dto/update-user.dto';
|
import { UpdateUserDto } from './dto/update-user.dto';
|
||||||
|
|
@ -18,8 +18,9 @@ export class UserService extends BaseService {
|
||||||
*/
|
*/
|
||||||
async create(createUserDto: CreateUserDto) {
|
async create(createUserDto: CreateUserDto) {
|
||||||
const user = this.userRepository.create(createUserDto);
|
const user = this.userRepository.create(createUserDto);
|
||||||
if (createUserDto.roles) {
|
if (createUserDto.roleIds) {
|
||||||
user.roles = createUserDto.roles.map((id) => ({ id })) as any;
|
user.roles = createUserDto.roleIds.map((id) => ({ id })) as any;
|
||||||
|
delete createUserDto.roleIds;
|
||||||
}
|
}
|
||||||
await this.userRepository.save(user);
|
await this.userRepository.save(user);
|
||||||
return user.id;
|
return user.id;
|
||||||
|
|
@ -29,7 +30,7 @@ export class UserService extends BaseService {
|
||||||
* 查找所有用户
|
* 查找所有用户
|
||||||
*/
|
*/
|
||||||
async findMany(findUserdto: FindUserDto) {
|
async findMany(findUserdto: FindUserDto) {
|
||||||
const { nickname: _nickname, } = findUserdto;
|
const { nickname: _nickname } = findUserdto;
|
||||||
const nickname = _nickname && Like(`%${_nickname}%`);
|
const nickname = _nickname && Like(`%${_nickname}%`);
|
||||||
const { skip, take } = this.paginizate(findUserdto, { full: true });
|
const { skip, take } = this.paginizate(findUserdto, { full: true });
|
||||||
return this.userRepository.findAndCount({ skip, take, where: { nickname } });
|
return this.userRepository.findAndCount({ skip, take, where: { nickname } });
|
||||||
|
|
@ -46,7 +47,16 @@ export class UserService extends BaseService {
|
||||||
/**
|
/**
|
||||||
* 根据用户id
|
* 根据用户id
|
||||||
*/
|
*/
|
||||||
update(id: number, updateUserDto: UpdateUserDto) {
|
async update(id: number, updateUserDto: UpdateUserDto) {
|
||||||
|
const user = await this.userRepository.findOne({ where: { id } });
|
||||||
|
if (!user) {
|
||||||
|
throw new NotFoundException('用户不存在');
|
||||||
|
}
|
||||||
|
if (updateUserDto.roleIds) {
|
||||||
|
const roles = updateUserDto.roleIds.map((id) => ({ id }));
|
||||||
|
await this.userRepository.save({ id, roles });
|
||||||
|
delete updateUserDto.roleIds;
|
||||||
|
}
|
||||||
return this.userRepository.update(id, updateUserDto);
|
return this.userRepository.update(id, updateUserDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreateLogDto {
|
||||||
|
/**
|
||||||
|
* 字段描述(Swagger用途)
|
||||||
|
* @example 'demo'
|
||||||
|
*/
|
||||||
|
@IsString()
|
||||||
|
demo: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { PaginationDto } from '@/common/response';
|
||||||
|
import { IntersectionType } from '@nestjs/swagger';
|
||||||
|
import { IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class FindLogDto extends IntersectionType(PaginationDto) {
|
||||||
|
/**
|
||||||
|
* 字段描述(Swagger用途)
|
||||||
|
* @example '示例值'
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
demo?: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { PartialType } from '@nestjs/swagger';
|
||||||
|
import { CreateLogDto } from './create-log.dto';
|
||||||
|
|
||||||
|
export class UpdateLogDto extends PartialType(CreateLogDto) {}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { BaseEntity } from '@/database';
|
||||||
|
import { Column, Entity } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity({ orderBy: { id: 'DESC' } })
|
||||||
|
export class AuthLog extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* 用户昵称
|
||||||
|
* @example '绝弹'
|
||||||
|
*/
|
||||||
|
@Column()
|
||||||
|
nickname: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作描述
|
||||||
|
* @example 1
|
||||||
|
*/
|
||||||
|
@Column()
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登陆IP
|
||||||
|
* @example '127.0.0.1'
|
||||||
|
*/
|
||||||
|
@Column()
|
||||||
|
ip: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登陆地址
|
||||||
|
* @example '广东省深圳市'
|
||||||
|
*/
|
||||||
|
@Column()
|
||||||
|
addr: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 浏览器
|
||||||
|
* @example 'chrome'
|
||||||
|
*/
|
||||||
|
@Column()
|
||||||
|
browser: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作系统
|
||||||
|
* @example 'windows 10'
|
||||||
|
*/
|
||||||
|
@Column()
|
||||||
|
os: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
export class Log {}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
export * from './entities/authLog.entity';
|
||||||
|
export * from './log.controller';
|
||||||
|
export * from './log.module';
|
||||||
|
export * from './log.service';
|
||||||
|
export * from './interceptors/authLog.interceptor';
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
||||||
|
import { Observable, tap } from 'rxjs';
|
||||||
|
import { LogService } from '../log.service';
|
||||||
|
|
||||||
|
export class AuthLogInterceptor implements NestInterceptor {
|
||||||
|
constructor(private logger: LogService) {}
|
||||||
|
|
||||||
|
intercept(context: ExecutionContext, next: CallHandler<any>): Observable<any> | Promise<Observable<any>> {
|
||||||
|
return next.handle().pipe(
|
||||||
|
tap({
|
||||||
|
next(data) {
|
||||||
|
console.log('auth ok', data);
|
||||||
|
},
|
||||||
|
error(err) {
|
||||||
|
console.log('auth err', err);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
success() {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { BaseController } from '@/common/base';
|
||||||
|
import { Respond, RespondType } from '@/common/response';
|
||||||
|
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, ParseIntPipe } from '@nestjs/common';
|
||||||
|
import { ApiOkResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { CreateLogDto } from './dto/create-log.dto';
|
||||||
|
import { FindLogDto } from './dto/find-log.dto';
|
||||||
|
import { UpdateLogDto } from './dto/update-log.dto';
|
||||||
|
import { AuthLog } from './entities/authLog.entity';
|
||||||
|
import { LogService } from './log.service';
|
||||||
|
|
||||||
|
@ApiTags('log')
|
||||||
|
@Controller('logs')
|
||||||
|
export class LogController extends BaseController {
|
||||||
|
constructor(private logService: LogService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增日志管理
|
||||||
|
*/
|
||||||
|
@Post()
|
||||||
|
addLog(@Body() createLogDto: CreateLogDto) {
|
||||||
|
return this.logService.create(createLogDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据分页/过滤参数查询日志管理
|
||||||
|
*/
|
||||||
|
@Get()
|
||||||
|
@Respond(RespondType.PAGINATION)
|
||||||
|
@ApiOkResponse({ isArray: true, type: AuthLog })
|
||||||
|
getLogs(@Query() query: FindLogDto) {
|
||||||
|
return this.logService.findMany(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询日志管理
|
||||||
|
*/
|
||||||
|
@Get(':id')
|
||||||
|
getLog(@Param('id', ParseIntPipe) id: number): Promise<AuthLog> {
|
||||||
|
return this.logService.findOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID更新日志管理
|
||||||
|
*/
|
||||||
|
@Patch(':id')
|
||||||
|
updateLog(@Param('id', ParseIntPipe) id: number, @Body() updateLogDto: UpdateLogDto) {
|
||||||
|
return this.logService.update(+id, updateLogDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID删除日志管理
|
||||||
|
*/
|
||||||
|
@Delete(':id')
|
||||||
|
delLog(@Param('id', ParseIntPipe) id: number) {
|
||||||
|
return this.logService.remove(+id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
import { AuthLog } from './entities/authLog.entity';
|
||||||
|
import { LogController } from './log.controller';
|
||||||
|
import { LogService } from './log.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [TypeOrmModule.forFeature([AuthLog])],
|
||||||
|
controllers: [LogController],
|
||||||
|
providers: [LogService],
|
||||||
|
exports: [LogService],
|
||||||
|
})
|
||||||
|
export class LogModule {}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { BaseService } from '@/common/base';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Like, Repository } from 'typeorm';
|
||||||
|
import { CreateLogDto } from './dto/create-log.dto';
|
||||||
|
import { FindLogDto } from './dto/find-log.dto';
|
||||||
|
import { UpdateLogDto } from './dto/update-log.dto';
|
||||||
|
import { AuthLog } from './entities/authLog.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LogService extends BaseService {
|
||||||
|
constructor(@InjectRepository(AuthLog) private logRepository: Repository<AuthLog>) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增日志管理
|
||||||
|
*/
|
||||||
|
async create(createLogDto: CreateLogDto) {
|
||||||
|
const log = this.logRepository.create();
|
||||||
|
await this.logRepository.save(log);
|
||||||
|
return log.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 条件/分页查询
|
||||||
|
*/
|
||||||
|
async findMany(findLogdto: FindLogDto) {
|
||||||
|
const { page, size } = findLogdto;
|
||||||
|
const { skip, take } = this.formatPagination(page, size, true);
|
||||||
|
return this.logRepository.findAndCount({ skip, take });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID查询
|
||||||
|
*/
|
||||||
|
findOne(idOrOptions: number | Partial<AuthLog>) {
|
||||||
|
const where = typeof idOrOptions === 'number' ? { id: idOrOptions } : (idOrOptions as any);
|
||||||
|
return this.logRepository.findOne({ where });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID更新
|
||||||
|
*/
|
||||||
|
update(id: number, updateLogDto: UpdateLogDto) {
|
||||||
|
// return this.logRepository.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID删除(软删除)
|
||||||
|
*/
|
||||||
|
remove(id: number) {
|
||||||
|
return this.logRepository.softDelete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ declare module 'express' {
|
||||||
user?: {
|
user?: {
|
||||||
id: number;
|
id: number;
|
||||||
username: string;
|
username: string;
|
||||||
|
nickname: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue