Skip to content

Nest User 模块

Nest UserModule

ts
import { Module } from "@nestjs/common";
import { UserService } from "./user.service";
import { UserController } from "./user.controller";
// 增加Excel 动态模块
import { ExcelModule } from "../../commonModules/excel/excel.module";
// 增加上传模块
import { UploadModule } from "../../commonModules/upload/upload.module";
// 增加邮箱模块
import { EmailModule } from "../../commonModules/email/email.module";
// 增加加密解密模块
import { CryptoModule } from "../../commonModules/crypto/crypto.module";
@Module({
  imports: [
    ExcelModule.forRoot({ name: "testdemoexcel" }),
    UploadModule,
    EmailModule,
    CryptoModule,
  ],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

Nest UserController

ts
import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  UseGuards,
  Req,
} from "@nestjs/common";
import { UserService } from "./user.service";

// 引入验证机制
import { AuthGuard } from "@nestjs/passport";

// 引入DTO
import { RegisterUserDto, SendEmailDto } from "./dto/register-user.dto";
import { LoginUserDto } from "./dto/login-user.dto";
import { GetInfoUserDto } from "./dto/getinfo-user.dto";
import { UpdateUserDto } from "./dto/update-user.dto";
import { UpdatePasswordDto } from "./dto/updatePassword.dto";
import { UpdateAdminDto } from "./dto/updateAdmin.dto";
import { GetListDto } from "./dto/getList.dto";
import { UpdateFrozenDto } from "./dto/updateFrozenDto.dto";
// 引入守卫
import { UserRegisterGuard } from "../user/guard/userregister.guard";
import { ByGuardpass } from "src/common/guard_pass.decorator";
import { RuleGuard } from "../../common/rule.guard";

// 引入装饰器
import { RBAC } from "../../common/rbac.decorator";
@Controller({
  path: "user",
  version: ["1"],
})
export class UserController {
  constructor(private readonly userService: UserService) {}

  // 发送邮件
  /**
   *
   * @api {POST} /v1/user/sendEmail 发送邮件
   * @apiName 发送邮件
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {String} email 邮箱地址
   *
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {String} response.data 发送成功
   *
   * @apiParamExample  {type} Request-Example:
   * {
   *     email : 26650599@qq.com
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   *     code : 200
   *     message : 操作成功
   *     data : 发送成功
   * }
   *
   *
   */
  @Post("sendEmail")
  @ByGuardpass()
  sendEmail(@Body() body: SendEmailDto) {
    const result = this.userService.sendEmail(body.email);
    return result;
  }

  // 注册
  /**
   *
   * @api {POST} /v1/user/register 注册
   * @apiName 注册
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {String} username 用户名
   * @apiBody  {String} password 密码
   * @apiBody  {String} email 邮箱
   * @apiBody  {String} captcha 验证码
   * @apiBody  {String} phone_number 手机号
   * @apiBody  {String} nick_name 昵称
   * @apiBody  {String} head_pic 头像
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {Object} response.data 返回数据
   * @apiSuccess {String} response.data.token 生成token
   * @apiSuccess {String} response.data.refreshToken 生成refreshToken
   *
   * @apiParamExample  {type} Request-Example:
   * {
   *     email : 26650599@qq.com
   *     username": myadmin,
   *     password: 123456,
   *     email: 26650599@qq.com,
   *     nick_name: 我就是管理员,
   *     captcha: RLHXai,
   *     phone_number:19000000011,
   *     head_pic:https://file.jsopy.com/IMAGES/avatarsmoke.jpg
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   *     token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJOYW1lIjoiYWRtaW4iLCJpYXQiOjE3NjY5MTQxNTksImV4cCI6MTc2NjkxNzc1OX0.LUYrzPWzh6OXF-tCiV-euGvIjrHFxsbbE6092WMh894
   *     refreshToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJOYW1lIjoiYWRtaW4iLCJpYXQiOjE3NjcwMDAwOTUsImV4cCI6MTc2NzAwMzY5NX0.4pK4YphVMQBxGA4w6tjStPIh_prOMkUCkWJLl7ROOU0
   * }
   *
   *
   */
  @Post("register")
  @UseGuards(UserRegisterGuard)
  @ByGuardpass()
  register(@Body() body: RegisterUserDto) {
    const result = this.userService.register(body);
    return result;
  }

  /**
   *
   * @api {POST} /v1/user/login 登录
   * @apiName 登录
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {String} username 用户名
   * @apiBody  {String} password 密码
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {Object} response.data 返回数据
   * @apiSuccess {String} response.data.token 生成token
   * @apiSuccess {String} response.data.refreshToken 生成refreshToken
   *
   * @apiParamExample  {type} Request-Example:
   * {
   *     username": myadmin,
   *     password: 123456,
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   *     token : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJOYW1lIjoiYWRtaW4iLCJpYXQiOjE3NjY5MTQxNTksImV4cCI6MTc2NjkxNzc1OX0.LUYrzPWzh6OXF-tCiV-euGvIjrHFxsbbE6092WMh894
   *     refreshToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsInVzZXJOYW1lIjoiYWRtaW4iLCJpYXQiOjE3NjcwMDAwOTUsImV4cCI6MTc2NzAwMzY5NX0.4pK4YphVMQBxGA4w6tjStPIh_prOMkUCkWJLl7ROOU0
   * }
   *
   *
   */
  @ByGuardpass()
  @UseGuards(AuthGuard("local"))
  @Post("login")
  async login(@Req() req: any) {
    //获取到user信息知道是谁了
    console.log(req.user);
    const result: LoginUserDto = {
      userName: req.user.username,
      userId: req.user.id,
    };
    return this.userService.login({
      userName: result.userName,
      userId: result.userId,
    });
  }

  // 初始化数据

  /**
   *
   * @api {POST} /v1/user/init 初始化
   * @apiName 初始化
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   */
  @ByGuardpass()
  @Post("init")
  async init() {
    await this.userService.init();
    return "初始化数据成功";
  }

  // 测试权限分级
  /**
   *
   * @api {POST} /v1/user/rbac 权限分级
   * @apiName 权限分级
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   */
  @UseGuards(RuleGuard)
  @RBAC(["guest"])
  @Post("rbac")
  async rbac(@Body() body: any) {
    console.log("----");
    console.log(body);
    console.log("-------");
    return "测试";
  }

  /**
   *
   * @api {POST} /v1/user/info 获取详情
   * @apiName 获取个人详情
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {number} id 用户id
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {Object} response.data 返回数据
   * @apiSuccess {number} response.data.id 生成的id
   * @apiSuccess {String} response.data.username 用户名
   * @apiSuccess {String} response.data.nick_name 昵称
   * @apiSuccess {String} response.data.head_pic 头像
   * @apiSuccess {String} response.data.phone_number 手机号
   * @apiSuccess {String} response.data.email 邮箱
   * @apiSuccess {String} response.data.is_frozen 2 代表未冻结 1代表冻结
   * @apiSuccess {String} response.data.is_admin 1 代表超级管理员 2代表普通用户
   *
   * @apiParamExample  {type} Request-Example:
   * {
   *     id: 3,
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   * code: 200,
   * message: "操作成功",
   * data: {
   *  id: 3,
   *  username: myadmin,
   *  nick_name: jsopy,
   *  email: 26650599@qq.com,
   *  head_pic: https://file.jsopy.com/IMAGES/avatarsmoke.jpg,
   *  phone_number: 19000000011,
   *  is_frozen: 2,
   *  is_admin: 2
   * }
   * }
   *
   *
   */

  @Get("info")
  async getinfo(@Body() body: GetInfoUserDto) {
    const result = await this.userService.getInfo(body);
    return result;
  }

  /**
   *
   * @api {POST} /v1/user/update 更新个人信息
   * @apiName 更新个人信息
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {number} id 用户id
   * @apiBody  {String} nick_name 昵称
   * @apiBody  {String} head_pic 头像
   * @apiBody  {String} phone_number 手机号
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {String} response.data 返回数据
   *
   * @apiParamExample  {type} Request-Example:
   * {
   *     id: 3,
   *     nick_name:jsopy-updated,
   *     head_pic:https://file.jsopy.com/IMAGES/avatarmoney.jpg,
   *     phone_number:19000000012
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   *     code: 200,
   *     message: "操作成功",
   *     data: 更新成功
   * }
   *
   *
   */
  @Post("update")
  async update(@Body() body: UpdateUserDto) {
    const result = await this.userService.updateUser(body);
    return result;
  }

  // 修改密码
  /**
   *
   * @api {POST} /v1/user/update_password 更改密码
   * @apiName 更改密码
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {String} oldPassword 旧密码
   * @apiBody  {String} newPassword 新密码
   * @apiBody  {String} confirmNewPassword 确认密码
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {String} response.data 更新成功
   *
   * @apiParamExample  {type} Request-Example:
   * {
   * "oldPassword":"456789",
   * "newPassword":"123456",
   * "confirmNewPassword":"123456"
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   * code: 200,
   * message: "操作成功",
   * data: 更新成功
   *
   *
   */
  @Post("update_password")
  async updatePassword(@Body() body: UpdatePasswordDto, @Req() req: any) {
    console.log(req.userId);
    const userId = req.userId;
    const result = await this.userService.updatePassword(body, userId);
    return result;
  }

  // 提升管理员

  /**
   *
   * @api {POST} /v1/user/update_admin 提升为管理员
   * @apiName 提升为管理员
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {number} id 用户id
   * @apiBody  {String} is_admin 是否是管理员 1就是管理员 2就是普通用户
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {String} response.data 更新成功
   *
   * @apiParamExample  {type} Request-Example:
   * {
   *  id:3,
   *  is_admin:1,
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   * code: 200,
   * message: "操作成功",
   * data: 提升成功
   *
   *
   */
  @Post("update_admin")
  async updateAdmin(@Body() body: UpdateAdminDto) {
    const result = await this.userService.updateAdmin(body);
    return result;
  }
  // 用户列表

  /**
   *
   * @api {GET} /v1/user/getlist 获取所有用户
   * @apiName 获取所有用户
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {Object[]} response.data 数据汇总
   * @apiSuccess {number} response.data.id 生成的id
   * @apiSuccess {String} response.data.username 用户名
   * @apiSuccess {String} response.data.nick_name 昵称
   * @apiSuccess {String} response.data.head_pic 头像
   * @apiSuccess {String} response.data.phone_number 手机号
   * @apiSuccess {String} response.data.email 邮箱
   * @apiSuccess {String} response.data.is_frozen 2 代表未冻结 1代表冻结
   * @apiSuccess {String} response.data.is_admin 1 代表超级管理员 2代表普通用户
   * @apiSuccess {Object} response.data.pagination 数据集合
   * @apiSuccess {Number} response.data.pagination.total 总数
   * @apiSuccess {Number} response.data.pagination.page 当前页
   * @apiSuccess {Number} response.data.pagination.pageSize 每页个数
   * @apiSuccess {Number} response.data.pagination.totalPages 总页数
   * @apiSuccess {Boolean} response.data.pagination.hasNextPage 是否有下一页
   * @apiSuccess {Boolean} response.data.pagination.hasPreviousPage 是否有上一页
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   * code: 200,
   * message: "操作成功",
   * data:{
   * list:[
   *  {
   *  id: 3,
   *  username: myadmin,
   *  nick_name: jsopy,
   *  email: 26650599@qq.com,
   *  head_pic: https://file.jsopy.com/IMAGES/avatarsmoke.jpg,
   *  phone_number: 19000000011,
   *  is_frozen: 2,
   *  is_admin: 2
   * }
   * ],
   * pagination: {
   *   "total": 1,
   *   "page": 1,
   *   "pageSize": 10,
   *   "totalPages": 1,
   *   "hasNextPage": false,
   *   "hasPreviousPage": false
   * }
   * }
   * }
   *
   *
   */
  @Get("getlist")
  async getList(@Body() body: GetListDto) {
    const result = await this.userService.getList(body.page, body.pageSize);
    return result;
  }

  /**
   *
   * @api {POST} /v1/user/update_frozen 冻结和解冻用户
   * @apiName 冻结和解冻用户
   * @apiGroup user
   * @apiVersion  0.0.0
   *
   *
   * @apiBody  {number} id 用户id
   * @apiBody  {String} is_frozen 是否冻结 1就是冻结 2就是解冻
   * @apiSuccess {Object} response 响应数据
   * @apiSuccess {Number} response.code 200
   * @apiSuccess {String} response.message 操作成功
   * @apiSuccess {String} response.data 冻结成功
   *
   * @apiParamExample  {type} Request-Example:
   * {
   *  id:3,
   *  is_frozen:1,
   * }
   *
   *
   * @apiSuccessExample {type} Success-Response:
   * {
   * code: 200,
   * message: "操作成功",
   * data: "冻结成功"
   *
   *
   */

  @Post("update_frozen")
  async updateFrozen(@Body() body: UpdateFrozenDto) {
    const result = await this.userService.updateFrozen(body);
    return result;
  }
}

Nest UserService

ts
import { Inject, Injectable } from "@nestjs/common";
import { PrismadbService } from "../../commonModules/prisma/prisma.service";
import { RedisService } from "../../commonModules/redis/redis.service";
import { JwtAllService } from "../../commonModules/jwt/jwt.service";
import { ExcelService } from "../../commonModules/excel/excel.service";
import { UploadService } from "../../commonModules/upload/upload.service";
// 邮件发送
import { EmailService } from "../../commonModules/email/email.service";
import { customAlphabet } from "nanoid";
// 加密解密
import { CryptoService } from "../../commonModules/crypto/crypto.service";

// 实例化
import { RegisteruserEntity } from "./entities/Registeruser.entity";
import { LoginuserEntity } from "./entities/Loginuser.entity";
import { PermissionsEntity } from "./entities/Permissions.entity";
import { RulesEntity } from "./entities/Rules.entity";
import { GetInfoUserEntity } from "./entities/GetInfoUserEntity.entity";
import { UpdateUserEntity } from "./entities/UpdataUserEntity.entity";
import { UpdatePassWordEntity } from "./entities/UpdatePassWord.entity";
import { UpdateAdminDto } from "./dto/updateAdmin.dto";
// 抛出异常
import { GlobalCheckException } from "../../common/globalcheck.exception";
import { UpdateFrozenDto } from "./dto/updateFrozenDto.dto";

@Injectable()
export class UserService {
  // 数据库
  @Inject()
  private readonly prisma: PrismadbService;

  // redis
  @Inject()
  private readonly redisService: RedisService;

  // JWT
  @Inject()
  private readonly jwtAllService: JwtAllService;

  // Excel
  @Inject()
  private readonly ExcelService: ExcelService;

  // 上传

  @Inject()
  private readonly UploadService: UploadService;

  // 邮件发送
  @Inject()
  private readonly emailService: EmailService;

  // 加密解密
  @Inject()
  private readonly cryptoService: CryptoService;

  // 初始化数据
  async init() {
    // 用户列表
    const user1 = new RegisteruserEntity();
    user1.username = "admin";
    user1.password = this.cryptoService.md5Encrypt("123456");
    user1.email = "admin@qq.com";
    user1.phone_number = "19000000001";
    user1.nick_name = "jsopy_admin";
    user1.head_pic = "https://file.jsopy.com/IMAGES/avatarsmoke.jpg";
    user1.is_admin = 1; // 超级管理员
    user1.is_frozen = 2; // 未冻结

    const user2 = new RegisteruserEntity();
    user2.username = "guest";
    user2.password = this.cryptoService.md5Encrypt("123456");
    user2.email = "guest@qq.com";
    user2.phone_number = "19000000001";
    user2.head_pic = "https://file.jsopy.com/IMAGES/avatarsmoke.jpg";
    user2.is_admin = 2; //普通用户
    user2.is_frozen = 2; // 未冻结
    user2.nick_name = "jsopy_guest";

    // 权限
    const role1 = new RulesEntity();
    role1.name = "超级管理员";

    const role2 = new RulesEntity();
    role2.name = "普通用户";

    // 权限列表
    const permissions1 = new PermissionsEntity();
    permissions1.code = "admin";
    permissions1.description = "admin";

    const permissions2 = new PermissionsEntity();
    permissions2.code = "guest";
    permissions2.description = "user";

    // 添加角色哪个没有外连哪个优先插入 creatMany 不支持嵌套插入 所有有外联不适用
    const permissionarr = [permissions1, permissions2];
    const permissionresult: any[] = [];
    for (let i = 0; i < permissionarr.length; i++) {
      const item = permissionarr[i];
      const result = await this.prisma.permissions.create({ data: item });
      permissionresult.push(result);
    }

    // 角色
    role1.roles_permissions = {
      create: [
        {
          permission_id: permissionresult[0].id,
        },
        {
          permission_id: permissionresult[1].id,
        },
      ],
    };

    role2.roles_permissions = {
      create: [
        {
          permission_id: permissionresult[1].id,
        },
      ],
    };

    // 添加角色
    const rolearr = [role1, role2];
    const roleresult: any[] = [];
    for (let i = 0; i < rolearr.length; i++) {
      const item = rolearr[i];
      const result = await this.prisma.roles.create({ data: item });
      roleresult.push(result);
    }
    console.log(roleresult);

    // 外链 1
    user1.user_roles = {
      create: [
        {
          role_id: roleresult[0].id,
        },
      ],
    };
    // 外链 2
    user2.user_roles = {
      create: [
        {
          role_id: roleresult[1].id,
        },
      ],
    };
    // 添加用户
    const userarr = [user1, user2];
    const userresult: any[] = [];
    for (let i = 0; i < userarr.length; i++) {
      const item = userarr[i];
      const result = await this.prisma.users.create({ data: item });
      userresult.push(result);
    }
    console.log(userresult);
    return "初始化成功";
  }
  // 注册
  async register(body: RegisteruserEntity) {
    console.log(body.email);
    // 先去查询数据库里面有没有
    const result = await this.prisma.users.findFirst({
      where: {
        email: body.email,
      },
    });
    if (!result) {
      // 去掉验证码 直接插入
      let { captcha, ...result } = body;
      // 密码必须md5 加密
      result.password = this.cryptoService.md5Encrypt(result.password);
      // 默认普通用户
      const resultdata = {
        ...result,
        user_roles: {
          create: [
            {
              role_id: 2,
            },
          ],
        },
      };
      // 注册
      const userresult = await this.prisma.users.create({
        data: resultdata,
      });
      // 短 token
      const token = await this.jwtAllService.setToken({
        userId: userresult.id,
        userName: userresult.username,
      });
      // 长 token
      const refreshToken = await this.jwtAllService.setRefreshToken({
        userId: userresult.id,
        userName: userresult.username,
      });
      // 用过一次就删除
      await this.redisService.delkey(`captcha_${body.captcha}`);
      // 生成jwt
      return {
        token,
        refreshToken,
      };
    } else {
      throw new GlobalCheckException("邮箱已经存在");
    }
  }

  // 发送邮件
  async sendEmail(emialAddress: string) {
    // 验证码
    const nanoid = customAlphabet(
      "1234567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ",
      6
    );
    const randomId = nanoid();
    const result = await this.emailService.sendEmail({
      to: emialAddress, // 你要发送的邮件账号
      subject: "邮箱", // 标题
      html: `<h1>这是邮箱验证码${randomId}</h1>`, // 邮件内容
    });
    if (result.messageId) {
      // 存入redis
      const result = await this.redisService.setstr({
        key: `captcha_${randomId}`,
        value: emialAddress,
      });
      return "发送成功";
    } else {
      return "发送失败";
    }
  }

  // 登录
  async login(body: LoginuserEntity) {
    // 短 token
    const token = await this.jwtAllService.setToken({
      userId: body.userId,
      userName: body.userName,
    });
    // 长 token
    const refreshToken = await this.jwtAllService.setRefreshToken({
      userId: body.userId,
      userName: body.userName,
    });
    return {
      token,
      refreshToken,
    };
  }

  // 获取详情
  async getInfo(body: GetInfoUserEntity) {
    const result = await this.prisma.users.findFirst({
      where: {
        id: body.id,
      },
      select: {
        ...Object.fromEntries(
          Object.keys(this.prisma.users.fields).map((key) => [key, true])
        ),
        password: false,
        creat_time: false,
        update_time: false,
      },
    });
    return result;
  }

  // 更新资料
  async updateUser(data: UpdateUserEntity) {
    // 先查询
    const UserSelect = await this.prisma.users.findFirst({
      where: {
        id: data.id,
      },
    });

    if (UserSelect) {
      const updateResult = await this.prisma.users.update({
        where: {
          id: data.id,
        },
        data: {
          ...data,
        },
      });
      if (updateResult) {
        return "更新成功";
      } else {
        throw new GlobalCheckException("更新失败");
      }
    } else {
      throw new GlobalCheckException("用户不存在");
    }
  }

  // 修改密码
  async updatePassword(data: UpdatePassWordEntity, userId: number) {
    // 先查询
    const UserSelect = await this.prisma.users.findFirst({
      where: {
        id: userId,
      },
    });

    if (
      UserSelect?.password == this.cryptoService.md5Encrypt(data.oldPassword)
    ) {
      const result = await this.prisma.users.update({
        where: {
          id: userId,
        },
        data: {
          password: this.cryptoService.md5Encrypt(data.newPassword),
        },
      });
      if (result) {
        return "修改成功";
      } else {
        throw new GlobalCheckException("修改失败");
      }
    } else {
      throw new GlobalCheckException("旧密码错误");
    }
  }

  // 提升管理员
  async updateAdmin(data: UpdateAdminDto) {
    // 先查询
    const UserSelect = await this.prisma.users.findFirst({
      where: {
        id: data.id,
      },
    });

    if (UserSelect?.is_admin !== 1) {
      const result = await this.prisma.users.update({
        where: {
          id: data.id,
        },
        data: {
          is_admin: 1,
        },
      });
      if (result) {
        return "提升成功";
      } else {
        throw new GlobalCheckException("提升失败");
      }
    } else {
      throw new GlobalCheckException("该用户已经是管理员");
    }
  }

  // 查询所有用户
  async getList(page: number = 1, pageSize: number = 10) {
    const result = await this.prisma.users.paginate(page, pageSize, {
      select: {
        ...Object.fromEntries(
          Object.keys(this.prisma.users.fields).map((key) => [key, true])
        ),
        password: false,
        creat_time: false,
        update_time: false,
      },
      orderBy: {
        id: "asc",
      },
    });
    return result;
  }

  // 冻结用户
  async updateFrozen(data: UpdateFrozenDto) {
    // 先查询
    const UserSelect = await this.prisma.users.findFirst({
      where: {
        id: data.id,
      },
    });
    if (UserSelect) {
      const result = await this.prisma.users.update({
        where: {
          id: data.id,
        },
        data: {
          is_frozen: Number(data.is_frozen),
        },
      });
      if (result.is_frozen == 1) {
        return "冻结成功";
      } else {
        return "解冻成功";
      }
    } else {
      throw new GlobalCheckException("用户不存在");
    }
  }
}

User 模块 DTO

getinfo-user.dto.ts

ts
import { IsEmail, IsNotEmpty, MinLength, IsPhoneNumber } from "class-validator";
export class GetInfoUserDto {
  @IsNotEmpty({
    message: "id不能为空",
  })
  id: number;
}

getList.dto.ts

ts
import { IsNotEmpty } from "class-validator";
export class GetListDto {
  @IsNotEmpty({
    message: "page不能为空",
  })
  page: number;

  @IsNotEmpty({
    message: "pagesize不能为空",
  })
  pageSize: number;
}

login-user.dto.ts

ts
import { IsNotEmpty } from "class-validator";

/**
 * 登录用户数据传输对象(DTO)
 * 用于验证和传输登录相关的用户数据
 */
export class LoginUserDto {
  /**
   * 用户名属性
   * 使用class-validator进行验证,确保用户名不为空
   * @type {string}
   */
  @IsNotEmpty({
    message: "用户名不能为空",
  })
  userName: string;

  /**
   * 用户ID属性
   * 使用class-validator进行验证,确保用户ID不为空
   * @type {string}
   */
  @IsNotEmpty({
    message: "id不能为空",
  })
  userId: string;
}

register-user.dto.ts

ts
import { IsEmail, IsNotEmpty, MinLength, IsPhoneNumber } from "class-validator";

export class RegisterUserDto {
  /**
   * 用户名字段
   * 使用class-validator进行验证,确保用户名不为空
   */
  @IsNotEmpty({
    message: "用户名不能为空",
  })
  username: string;

  /**
   * 昵称字段
   * 使用class-validator进行验证,确保昵称不为空
   */
  @IsNotEmpty({
    message: "昵称不能为空",
  })
  nick_name: string;

  /**
   * 密码字段
   * 使用class-validator进行验证,确保密码不为空且长度不少于6位
   */
  @IsNotEmpty({
    message: "密码不能为空",
  })
  @MinLength(6, {
    message: "密码不能少于 6 位",
  })
  password: string;

  /**
   * 邮箱字段
   * 使用class-validator进行验证,确保邮箱不为空且格式正确
   */
  @IsNotEmpty({
    message: "邮箱不能为空",
  })
  @IsEmail(
    {},
    {
      message: "不是合法的邮箱格式",
    }
  )
  email: string;

  /**
   * 验证码字段
   * 必填字段,用于验证用户注册的真实性和安全性
   * 使用class-validator进行验证,确保验证码不为空
   */
  @IsNotEmpty({
    message: "验证码不能为空",
  })
  captcha: string;

  /**
   * 手机号字段
   * 使用class-validator进行验证,确保手机号不为空且格式正确
   */
  @IsNotEmpty({
    message: "手机号不能为空",
  })
  @IsPhoneNumber("CN", {
    message: "请输入正确的手机号",
  })
  phone_number: string;

  /**
   * 头像字段
   * 使用class-validator进行验证,确保头像不为空
   */
  @IsNotEmpty({
    message: "头像不能为空",
  })
  head_pic: string;
}

/**
 * 发送邮件的数据传输对象(DTO)类
 * 用于验证和传输发送邮件所需的数据
 * 使用TypeScript类实现,结合class-validator进行数据验证
 */
export class SendEmailDto {
  /**
   * 邮箱地址
   * @example user@example.com
   */
  @IsNotEmpty({
    message: "用户名不能为空",
  })
  @IsEmail(
    {},
    {
      message: "请输入正确的邮箱",
    }
  )
  email: string;
}

update-user.dto.ts

ts
import { IsNotEmpty } from "class-validator";

export class UpdateUserDto {
  @IsNotEmpty({
    message: "用户ID不能为空",
  })
  id: number;

  @IsNotEmpty({
    message: "昵称不能为空",
  })
  nick_name: string;

  @IsNotEmpty({
    message: "手机号不能为空",
  })
  phone_number: string;

  @IsNotEmpty({
    message: "头像不能为空",
  })
  head_pic: string;
}

updateAdmin.dto.ts

ts
import { IsNotEmpty } from "class-validator";

export class UpdateAdminDto {
  @IsNotEmpty({
    message: "id不能为空",
  })
  id: number;

  @IsNotEmpty({
    message: "is_admin不能为空",
  })
  is_admin: string;
}

updateFrozenDto.dto.ts

ts
import { IsNotEmpty } from "class-validator";
export class UpdateFrozenDto {
  @IsNotEmpty({
    message: "id不能为空",
  })
  id: number;
  @IsNotEmpty({
    message: "id不能为空",
  })
  is_frozen: string;
}

updatePassword.dto.ts

ts
import { IsNotEmpty } from "class-validator";
import { Match } from "./checkpassword";
export class UpdatePasswordDto {
  @IsNotEmpty({
    message: "旧密码不能为空",
  })
  oldPassword: string;

  @IsNotEmpty({
    message: "新密码不能为空",
  })
  newPassword: string;

  @IsNotEmpty({
    message: "密码不能为空",
  })
  @Match("newPassword", { message: "两次输入的密码不一致" })
  confirmNewPassword: string;
}

补充自己写的验证装饰器

  • checkpassword.ts
ts
import {
  registerDecorator,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
} from "class-validator";

// 1. 定义验证逻辑的类
@ValidatorConstraint({ name: "match", async: false })
class MatchConstraint implements ValidatorConstraintInterface {
  validate(value: any, args: ValidationArguments) {
    // [property] 指的是被装饰的属性(例如 confirmPassword)
    // 通过 args.object 获取整个类的实例
    const relatedPropertyName = args.constraints[0]; // 获取传入的要对比的属性名(例如 'password')
    const relatedValue = (args.object as any)[relatedPropertyName];

    // 如果两者值相等,则验证通过
    return value === relatedValue;
  }

  // 2. 自定义错误消息(可选,如果不实现则使用默认消息)
  defaultMessage(args: ValidationArguments) {
    const relatedPropertyName = args.constraints[0];
    return `${args.property} 必须与 ${relatedPropertyName} 一致`;
  }
}

// 3. 创建装饰器函数
export function Match(property: string, validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [property], // 传入要对比的属性名
      validator: MatchConstraint,
    });
  };
}