手把手教你实现一个vue3+ts+nodeJS后台管理系统(九)

420 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情

前言

前面已经将用户模型与角色模型做了关联。但是用户接口添加及返回的信息还不包含角色,所以接下来我们将对用户接口进行改造。

改造接口

添加用户接口

添加用户的时候也要添加用户所选择的角色信息。所以我们在模型定义的文件中为模型添加方法,从而达到添加用户角色的目的。

添加用户角色的重点: 添加用户角色方法应当有两个操作: 1.添加用户的信息,2.在用户角色表添加用户的角色信息。但这里有一个问题,万一我们添加用户信息成功了,但添加用户的角色没有成功,添加用户信息是否是错误的、不应该的?所以下面的代码我用到了sequelize的事务的概念。这里要是有一个操作没有成功就会回滚(即所有操作都不做),要所有操作都成功才提交。

model/user.js

我们添加角色的第一步为添加用户,然后再读取传来的角色id数组,遍历后再添加到用户角色表

...
const UserModel=sequelize.define(...)
// 添加用户的方法
UsersModel.addUser = async function (data) {
  // 首先,我们开始一个事务并将其保存到变量中
  const t = await sequelize.transaction();
  try {
    // 然后,我们进行一些调用以将此事务作为参数传递:
    // 添加用户
    const user = await UsersModel.create(data);
    // 遍历前端传来的用户角色id并添加到用户角色表
    const users_roles = data.role_ids.map(function (role_id) {
      return {
        user_id: user.user_id,
        role_id: role_id
      };
    });
    await UsersRolesModel.bulkCreate(users_roles);
    // 我们提交事务.
    t.commit();
    return true;
  } catch (e) {
    // 如果执行到达此行,则抛出错误.
    // 我们回滚事务.
    t.rollback();
    return e.message;
  }
};
...

然后我们修改一下校验规则文件(添加id数组的校验)和添加用户路由回调函数。

schema/user.js

const role_ids = joi.array().items(joi.number()).required();
// 添加用户接口
exports.add_user_schema = joi.object().keys({
  username,
  password,
  role_ids
});

router_handler/user.js

 ...
 const password = value.password;
  // 加密
  value.password = bcrypt.hashSync(password, 10);
  // 将添加的用户设置为可用
  value.status = 1;
  // 添加用户角色,返回true或错误信息
  const result = UsersModel.addUser(value);
  result.then(function (ret) {
    if (ret=== true) {
      return res.send({
        code: 0,
        message: '新增成功',
        data: ret
      });
    }
  })
 ...

修改角色接口

修改角色方法与添加角色方法基本一致,要做到修改用户的角色时能够修改用户角色表的数据。

但前端传来了一个角色数组,我们得先从用户角色表中取出用户的角色数据将其转为数组,然后比较两个数组再对应进行修改。例如前端传来的角色数组为[1,2],表里例如所存字段信息的是

user_idrole_id
11
13

那么数据库所存的角色信息数组就是[1,3],我们应当将3的角色删掉然后添加2的角色。

那么我们得要获得两个数组的差集。我们用到的是数组的filter方法过滤出交集

// 测试!!!
let arr1 = [1,2,3];
let arr2 = [1,3,4];
let arr3=arr1.filter(function (v) {
  return arr2.indexOf(v) === -1;
});
let arr4 = arr2.filter(function (v) {
  return arr1.indexOf(v) === -1;
});
console.log(arr3);   //    得到[2]为添加的角色数组
console.log(arr4);   //    得到[4]为数据库中要删除的角色数组

我们在utils文件夹下新建一个工具类来定义此数组方法。

utils/tools.js

/**
 * 获取两个数组差集
 * @param arr1
 * @param arr2
 * @returns {*[]}
 */
const minustArr = function (arr1 = [], arr2 = []) {
  return arr1.filter(function (v) {
    return arr2.indexOf(v) === -1;
  });
};
// 导出工具方法
module.exports = {
  minustArr
};

那么我们就可以进行修改角色方法的编写了

model/user.js

const tools=require('../utils/tools')
...
UsersModel.addUser...
UsersModel.updateUser = async function (user_id, data) {
  const t = await sequelize.transaction();
  try {
    // 获得修改时间
    data.update_time = new Date();
    // 先更新用户
    await UsersModel.update(data, {
      where: {
        user_id: user_id
      }
    });
    // 再得到用户角色表中此用户的角色id
    const users_roles = await UsersRolesModel.findAll({
      where: { user_id: user_id }
    });
    // 将表中获得的角色id转换为数组
    const role_ids = users_roles.map(function (item) {
      return item.role_id;
    });
    // 新加的角色加到用户角色表中
    const add_role_ids = tools.minustArr(data.role_ids, role_ids);
    const add_users_roles = add_role_ids.map(function (role_id) {
      return { user_id: user_id, role_id: role_id };
    });
    await UsersRolesModel.bulkCreate(add_users_roles);
    // 删除的角色从用户角色表删除
    const del_role_ids = tools.minustArr(role_ids, data.role_ids);
    if (del_role_ids && del_role_ids.length > 0) {
      await UsersRolesModel.destroy({
        where: {
          user_id: user_id,
          role_id: del_role_ids
        }
      });
    }
    t.commit();
    return true;
  } catch (e) {
    t.rollback();
    return e.message;
  }
};
...

然后同样对校验字段和路由回调函数进行修改。

schema/user.js

// 更新用户接口
exports.update_user_schema = joi.object().keys({
  username: joi.string().alphanum().min(1).max(10),
  status,
  nickname,
  email,
  role_ids     // 角色id数组
});

router_handler/user.js

const result = UsersModel.updateUser(user_id, req.body);
result.then(function (ret) {
    if (ret === true) {
      return res.send({
        code: 0,
        message: '修改成功',
        data: ret
      });
    }
})

删除用户接口

删除用户只需要删除对应用户表的用户和用户角色表该用户id对应的表记录即可

model/user.js

...
UsersModel.delUser = async function (user_ids) {
  const t = await sequelize.transaction();
  try {
    await UsersModel.destroy({
      where: { user_id: user_ids }
    });
    await UsersRolesModel.destroy({
      where: { user_id: user_ids }
    });
    t.commit();
    return true;
  } catch (e) {
    t.rollback();
    return false;
  }
};
...

然后修改回调函数

router_handler/user.js

...
  const user_ids = req.body.user_id;
  UsersModel.delUser(user_ids || []).then(function (user) {
    if (user !== true) {
      return res.send({
        code: 1,
        message: '删除失败',
        data: null
      });
    }
...

获取用户列表和根据id获取用户信息接口

都只需要在获取信息的时候添加上角色信息。在sequelize的关联模块中有include参数可以执行预先加载与查询实例一起带回关联的数据。

先导入角色用户模型

router_handler/user.js

const RolesModel = require('../model/roles');
/**
 * 获取用户列表
 */
 ...
  UsersModel.findAndCountAll({
    attributes: { exclude: ['password'] },
    include:[{model:RolesModel}],    // 预先加载角色模型
    offset: offset,
    limit: limit,
    where: where
  }).then(...)
 /**
 * 根据id获取用户信息接口
 */
 ...
 UsersModel.findOne({
    attributes: { exclude: ['password'] },
    include: [{ model: RolesModel }], // 预先加载角色模型
    where: {
      user_id: user_id
    }
  }).then(...)

测试

因为暂时还没有角色,所以我们先测试获取用户列表

获取用户列表

image.png

可以看到带上了roles字段,说明成功了。下文我们将添加角色信息,到时候看得更加直观。