// src/service/user.service.ts import { Body, httpError, Inject, Provide } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Like, Repository } from 'typeorm'; import * as bcrypt from 'bcryptjs'; import { JwtService } from '@midwayjs/jwt'; import { User } from '../entity/user.entity'; import { LoginResDTO } from '../dto/user.dto'; import { plainToInstance } from 'class-transformer'; import { MailService } from './mail.service'; import { AuthCodeService } from './authCode.service'; import { DeviceWhitelistService } from './deviceWhitelist.service'; @Provide() export class UserService { @InjectEntityModel(User) userModel: Repository; @Inject() jwtService: JwtService; @Inject() mailService: MailService; @Inject() authCodeService: AuthCodeService; @Inject() deviceWhitelistService: DeviceWhitelistService; async requestAuthCode(deviceId: string) { const code = await this.authCodeService.generateCode(deviceId); await this.mailService.sendMail( 'info@canpouches.com', 'Your Login Authorization Code', `Your authorization code is: ${code}, valid for 10 minutes.` ); } async login(@Body() body): Promise { const { username, password, deviceId, authCode } = body; const user = await this.userModel.findOne({ where: { username, isActive: true }, }); if (!user || !(await bcrypt.compare(password, user.password))) { throw new Error('用户名或者密码错误'); } const isWhite = await this.deviceWhitelistService.isWhitelisted(deviceId); if (!isWhite) { if (!authCode) { await this.requestAuthCode(deviceId); const err = new httpError.BadRequestError('非白名单设备请填写验证码'); (err as any).code = 10001; // 添加业务错误码 throw err; } const valid = await this.authCodeService.verifyCode(deviceId, authCode); if (!valid) { throw new Error('验证码错误'); } // 校验通过后,将设备加入白名单 await this.deviceWhitelistService.addToWhitelist(deviceId); } // 生成 JWT,包含角色和权限信息 const token = await this.jwtService.sign({ id: user.id, deviceId, username: user.username, isSuper: user.isSuper, }); return { token, //role: user.role, username: user.username, userId: user.id, permissions: user.permissions, }; } // 新增用户(支持可选备注) async addUser(username: string, password: string, remark?: string) { const existingUser = await this.userModel.findOne({ where: { username }, }); if (existingUser) { throw new Error('用户已存在'); } const hashedPassword = await bcrypt.hash(password, 10); const user = this.userModel.create({ username, password: hashedPassword, // 备注字段赋值(若提供) ...(remark ? { remark } : {}), }); return this.userModel.save(user); } // 用户列表支持分页与备注模糊查询(以及可选的布尔过滤) async listUsers( current: number, pageSize: number, filters: { remark?: string; username?: string; isActive?: boolean; isSuper?: boolean; isAdmin?: boolean; } = {}, sorter: { field?: string; order?: 'ASC' | 'DESC'; } = {} ) { // 条件判断:构造 where 条件 const where: Record = {}; if (filters.username) where.username = Like(`%${filters.username}%`); // 用户名精确匹配(如需模糊可改为 Like) if (typeof filters.isActive === 'boolean') where.isActive = filters.isActive; // 按启用状态过滤 if (typeof filters.isSuper === 'boolean') where.isSuper = filters.isSuper; // 按超管过滤 if (typeof filters.isAdmin === 'boolean') where.isAdmin = filters.isAdmin; // 按管理员过滤 if (filters.remark) where.remark = Like(`%${filters.remark}%`); // 备注模糊搜索 const validSortFields = ['id', 'username', 'isActive', 'isSuper', 'isAdmin', 'remark']; const sortField = validSortFields.includes(sorter.field) ? sorter.field : 'id'; const sortOrder = sorter.order === 'ASC' ? 'ASC' : 'DESC'; const [items, total] = await this.userModel.findAndCount({ where, skip: (current - 1) * pageSize, take: pageSize, order: { [sortField]: sortOrder }, }); return { items, total, current, pageSize }; } async toggleUserActive(userId: number, isActive: boolean) { const user = await this.userModel.findOne({ where: { id: userId } }); if (!user) { throw new Error('User not found'); } user.isActive = isActive; return this.userModel.save(user); } // 更新用户信息(支持用户名唯一校验与可选密码修改) async updateUser( userId: number, payload: { username?: string; password?: string; isSuper?: boolean; isAdmin?: boolean; permissions?: string[]; remark?: string; } ) { // 条件判断:查询用户是否存在 const user = await this.userModel.findOne({ where: { id: userId } }); if (!user) { throw new Error('User not found'); } // 条件判断:若提供了新用户名且与原用户名不同,校验唯一性 if (payload.username && payload.username !== user.username) { const exist = await this.userModel.findOne({ where: { username: payload.username } }); if (exist) throw new Error('用户名已存在'); user.username = payload.username; } // 条件判断:若提供密码则进行加密存储 if (payload.password) { user.password = await bcrypt.hash(payload.password, 10); } // 条件判断:更新布尔与权限字段(若提供则覆盖) if (typeof payload.isSuper === 'boolean') user.isSuper = payload.isSuper; if (typeof payload.isAdmin === 'boolean') user.isAdmin = payload.isAdmin; if (Array.isArray(payload.permissions)) user.permissions = payload.permissions; // 条件判断:更新备注(若提供则覆盖) if (typeof payload.remark === 'string') user.remark = payload.remark; // 保存更新 return await this.userModel.save(user); } async getUser(userId: number) { return plainToInstance( User, await this.userModel.findOne({ where: { id: userId } }) ); } }