用户服务 UserService
数据库的操作主要是在 Service 里做,UserService 主要是给 UserController 提供服务,也可以提供给其他模块调用:
import {
BadRequestException,
Injectable,
InternalServerErrorException,
Logger,
Req,
} from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Like, Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { Role } from './entities/role.entity';
import { ListUserDto } from './dto/list-user.dto';
import { ResetPasswordDto } from './dto/reset-password.dto';
import {
removeUnnecessaryData,
setCreatedUser,
setDeletedUser,
setUpdatedUser,
} from 'src/utils';
import { UpdatePasswordDto } from './dto/update-password.dto';
@Injectable()
export class UserService {
private logger = new Logger('UserService');
constructor(
@InjectRepository(User) private readonly userRepository: Repository<User>,
@InjectRepository(Role) private readonly roleRepository: Repository<Role>,
) {}
// 获取用户权限列表
roleList() {
return this.roleRepository.find();
}
async findRoleById(id: number): Promise<Role> {
if (!id) {
throw new BadRequestException('id必填');
}
return await this.roleRepository.findOne({
where: { id },
});
}
async create(createUserDto: CreateUserDto, @Req() req) {
this.logger.log('@@@@ 创建用户参数:', createUserDto);
// 检查roleId是否存在
const role = await this.findRoleById(createUserDto.roleId || 4);
if (!role) {
this.logger.warn(`id为${createUserDto.roleId}的角色没有找到`);
throw new BadRequestException(
`id为${createUserDto.roleId}的角色没有找到`,
);
}
// 检查account是否已存在
const account = await this.userRepository.findOne({
where: { account: createUserDto.account },
});
if (account) {
this.logger.warn(`账号${createUserDto.account}已存在,不能重复创建`);
throw new BadRequestException(
`账号${createUserDto.account}已存在,不能重复创建`,
);
}
// 创建用户实体
const user = this.userRepository.create(createUserDto);
user.roleType = role.type;
user.roleWeight = role.weight;
user.roleName = role.name;
// 设置密码哈希
const passwordHash: string = await user.setPasswordHash(
createUserDto.password,
);
user.passwordHash = passwordHash;
const createdUser = setCreatedUser(req, user);
this.logger.log('@@@@ 创建用户实体 createdUser', createdUser);
try {
return await this.userRepository.save(createdUser);
} catch (error) {
this.logger.error('@@@@ 新建账号失败:', error);
throw new InternalServerErrorException('新建账号失败');
}
}
async findAll(query: ListUserDto) {
try {
const queryParams = {
account: query?.account || null,
username: query.username ? Like(`%${query.username}%`) : null,
roleId: query?.roleId || null,
isDeleted: 0,
};
const data = await this.userRepository.find({
where: queryParams,
});
return removeUnnecessaryData(data);
} catch (error) {
this.logger.error('@@@@ 账号列表查询失败:', error);
throw new InternalServerErrorException('账号列表查询失败');
}
}
async findAllByPage(query: ListUserDto) {
try {
const queryParams = {
id: query?.id || null,
account: query?.account ? Like(`%${query.account}%`) : null,
username: query.username ? Like(`%${query.username}%`) : null,
roleId: query?.roleId || null,
isDeleted: 0,
};
const [data, total] = await this.userRepository.findAndCount({
where: queryParams,
order: {
id: 'DESC',
},
skip: (query.pageNum - 1) * query.pageSize,
take: query.pageSize,
});
return {
list: removeUnnecessaryData(data),
pageNum: Number(query.pageNum),
pageSize: Number(query.pageSize),
total,
};
} catch (error) {
this.logger.error('@@@@ 账号列表查询失败:', error);
throw new InternalServerErrorException('账号列表查询失败');
}
}
async findOne(id: number) {
if (!id) {
throw new BadRequestException('id必填');
}
try {
const data = await this.userRepository.findOne({
where: { id, isDeleted: 0 },
});
delete data.passwordHash;
delete data.isDeleted;
return data;
} catch (error) {
this.logger.error('@@@@ 账号查询失败:', error);
throw new InternalServerErrorException('账号查询失败');
}
}
async findByIds(ids: number[]): Promise<User[]> {
try {
const data = await this.userRepository.find({
where: { id: In(ids), isDeleted: 0 },
});
return removeUnnecessaryData(data);
} catch (error) {
this.logger.error('@@@@ 账号批量查询失败:', error);
throw new InternalServerErrorException('账号批量查询失败');
}
}
// 更新用户
async update(id: number, updateUserDto: UpdateUserDto, @Req() req) {
if (!id) {
throw new BadRequestException('id必填');
}
const user = await this.userRepository.findOneBy({
id,
});
if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
throw new BadRequestException(
`当前角色权限过低,无法对${user.account}进行该操作`,
);
}
const role = await this.roleRepository.findOneBy({
id: updateUserDto.roleId,
});
user.roleType = role.type;
user.roleWeight = role.weight;
user.roleName = role.name;
try {
// 设置更新用户信息
const updatedUser = setUpdatedUser(req, user);
this.logger.log('@@@ 更新用户 updatedUser', updatedUser);
return await this.userRepository.update(id, updatedUser);
} catch (error) {
this.logger.error('@@@@ 更新账号失败:', error);
throw new InternalServerErrorException('更新账号失败');
}
}
// 重置登录密码
async resetPassword(body: ResetPasswordDto, @Req() req) {
const user = await this.userRepository.findOneBy({
id: body.id,
});
if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
throw new BadRequestException(
`当前角色权限过低,无法对${user.account}进行该操作`,
);
}
if (body.confirmPassword !== body.newPassword) {
throw new BadRequestException('新密码与确认密码不一致');
}
try {
// 设置密码哈希
const passwordHash: string = await user.setPasswordHash(body.newPassword);
user.passwordHash = passwordHash;
// 设置更新用户信息
const updatedUser = setUpdatedUser(req, user);
this.logger.log('@@@ 重置登录密码 updatedUser', updatedUser);
return await this.userRepository.update(body.id, updatedUser);
} catch (error) {
this.logger.error('@@@@ 更新密码失败:', error);
throw new InternalServerErrorException('更新密码失败');
}
}
// 更新密码
async userUpdatePassword(body: UpdatePasswordDto, @Req() req) {
// 旧密码和新密码比较
if (body.oldPassword === body.newPassword) {
throw new BadRequestException('旧密码不能和新密码相同');
}
// 新密码和确认密码比较
if (body.confirmPassword !== body.newPassword) {
throw new BadRequestException('新密码与确认密码不一致');
}
// 调用数据库验证用户旧密码
const user: User = await this.userRepository.findOneBy({
id: req.user.userId,
});
const isPassword = await user.validatePassword(body.oldPassword);
if (!isPassword) {
throw new BadRequestException('旧密码错误,请确认后重新输入');
}
try {
this.logger.log('@@@@ 修改账户密码 body', body);
// 修改账户密码
const passwordHash: string = await user.setPasswordHash(body.newPassword);
user.passwordHash = passwordHash;
// 设置更新用户信息
const updatedUser = setUpdatedUser(req, user);
return await this.userRepository.update(user.id, updatedUser);
} catch (error) {
this.logger.error('@@@@ 修改账户密码失败:', error);
throw new InternalServerErrorException('修改账户密码失败');
}
}
// 软删除单个用户
async softDeleteUser(id: number, @Req() req) {
if (!id) {
throw new BadRequestException('id必填');
}
const user = await this.userRepository.findOneBy({
id,
});
if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
throw new BadRequestException(
`当前角色权限过低,无法对${user.account}进行该操作`,
);
}
try {
const removedUser = setDeletedUser(req, user);
this.logger.log('@@@ 软删除单个用户 removedUser', removedUser);
return await this.userRepository.update(id, removedUser);
} catch (error) {
this.logger.error('@@@@ 删除账号失败:', error);
throw new InternalServerErrorException('删除账号失败');
}
}
// 软删除批量用户
async softDeleteUsers(ids: number[], @Req() req) {
for (const id of ids) {
const user = await this.userRepository.findOneBy({
id,
});
if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
throw new BadRequestException(
`当前角色权限过低,无法对${user.account}进行该操作`,
);
break;
}
}
try {
const user = new User();
const removedUser = setDeletedUser(req, user);
this.logger.log('@@@ 软删除批量用户 removedUser', removedUser);
return await this.userRepository.update(ids, removedUser);
} catch (error) {
this.logger.error('@@@@ 批量删除账号失败:', error);
throw new InternalServerErrorException('批量删除账号失败');
}
}
}
用户模型 UserModule
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { Role } from './entities/role.entity';
import { ExcelModule } from 'src/common/excel/excel.module';
import { MetricsService } from 'src/common/metrics/metrics.service';
@Module({
imports: [TypeOrmModule.forFeature([User, Role]), ExcelModule],
controllers: [UserController],
providers: [UserService, MetricsService],
exports: [UserService], // 导出UserService以便其他模块可以使用
})
export class UserModule {}