dj 8 months ago
parent 244e592e30
commit e62d12ded9

File diff suppressed because it is too large Load Diff

@ -1,244 +1,384 @@
// 引入Node.js的path模块用于处理文件路径相关操作通过 `path.join` 方法将当前工作目录(`process.cwd()`)与相对路径拼接起来,
// 从而准确地引入自定义的 `dao/ManagerDAO` 模块所在的路径,该模块大概率封装了与管理员数据操作相关的数据库访问方法,比如查询、计数等操作。
var path = require("path");
var managersDAO = require(path.join(process.cwd(),"dao/ManagerDAO"));
// 引入自定义的 `ManagerDAO` 模块,用于执行与管理员数据相关的数据库操作,例如按照特定条件查询管理员信息、统计符合条件的管理员数量等,它是获取管理员数据的关键模块。
var managersDAO = require(path.join(process.cwd(), "dao/ManagerDAO"));
// 引入 `node-php-password` 库,可能用于密码相关的处理操作(虽然从当前代码来看暂未体现其具体使用场景,但可能在涉及管理员密码验证、加密等功能时会用到)。
var Password = require("node-php-password");
// 引入日志记录模块,通过调用 `../modules/logger` 模块中导出的 `logger` 函数来获取一个日志记录器对象,用于记录在获取管理员相关操作过程中的各种日志信息,方便调试和排查问题。
var logger = require('../modules/logger').logger();
/**
* 获取所有管理员
* @param {[type]} conditions 查询条件
* 此函数用于根据传入的查询条件获取符合要求的管理员信息并通过回调函数将查询结果包含管理员列表以及相关统计信息或错误信息返回给调用者
* 常用于管理员列表展示等业务场景中根据不同的筛选条件展示相应的管理员数据
*
* @param {[type]} conditions 查询条件它是一个对象包含了用于筛选管理员信息的相关参数遵循特定的规范格式具体如下
* 查询条件统一规范
* conditions
{
"query" : 关键词查询,
"pagenum" : 页数,
"pagesize" : 每页长度
}
* @param {Function} cb 回调函数
* {
* "query" : 关键词查询用于进行模糊搜索等操作比如根据管理员姓名手机号等关键信息来筛选管理员该字段可以为空字符串表示不进行关键词查询
* "pagenum" : 页数用于分页查询指定要获取的是第几页的数据必须是合法的正整数否则会被判定为参数不合法
* "pagesize" : 每页长度用于分页查询指定每页显示的管理员记录数量同样必须是合法的正整数否则会被判定为参数不合法
* }
* @param {Function} cb 回调函数用于接收获取管理员操作的结果若成功获取到管理员数据则传递包含管理员列表以及相关统计信息如总记录数当前页码等的对象作为参数若出现错误情况如参数不合法数据库查询失败等则传递相应的错误信息字符串作为参数
*/
module.exports.getAllManagers = function(conditions,cb) {
if(!conditions.pagenum) return cb("pagenum 参数不合法");
if(!conditions.pagesize) return cb("pagesize 参数不合法");
// 通过关键词获取管理员数量
managersDAO.countByKey(conditions["query"],function(err,count) {
key = conditions["query"];
pagenum = parseInt(conditions["pagenum"]);
pagesize = parseInt(conditions["pagesize"]);
pageCount = Math.ceil(count / pagesize);
offset = (pagenum - 1) * pagesize;
if(offset >= count) {
offset = count;
}
limit = pagesize;
managersDAO.findByKey(key,offset,limit,function(err,managers){
var retManagers = [];
for(idx in managers) {
var manager = managers[idx];
var role_name = manager.role_name;
if(!manager.role_id) {
role_name = "超级管理员"
}
retManagers.push({
"id": manager.mg_id,
"role_name":role_name,
"username":manager.mg_name,
"create_time":manager.mg_time,
"mobile":manager.mg_mobile,
"email":manager.mg_email,
"mg_state":manager.mg_state == 1
});
}
var resultDta = {};
resultDta["total"] = count;
resultDta["pagenum"] = pagenum;
resultDta["users"] = retManagers;
cb(err,resultDta);
});
});
}
module.exports.getAllManagers = function (conditions, cb) {
// 首先验证传入的查询条件(`conditions`)中的 `pagenum` 参数是否存在,如果不存在,说明页码参数不符合要求,直接通过回调函数 `cb` 返回错误信息,表示 `pagenum` 参数不合法,
// 因为分页查询需要明确的页码信息,页码通常为正整数,若不传该参数则无法正确进行分页操作,告知调用者参数不符合要求。
if (!conditions.pagenum) return cb("pagenum 参数不合法");
// 同样验证 `conditions` 中的 `pagesize` 参数是否存在,如果不存在,说明每页显示记录数参数不符合要求,直接通过回调函数 `cb` 返回错误信息,表示 `pagesize` 参数不合法,
// 因为分页查询需要明确每页显示多少条记录,该参数通常为正整数,若不传则无法正确进行分页操作,告知调用者参数不符合要求。
if (!conditions.pagesize) return cb("pagesize 参数不合法");
// 通过关键词获取管理员数量
// 调用 `managersDAO` 模块的 `countByKey` 方法,传入 `conditions["query"]`(即关键词查询参数,可能用于在数据库中进行模糊查询等操作来统计符合该关键词的管理员数量),
// 该方法是一个异步操作,通过回调函数来处理查询统计的结果情况,若成功则返回符合条件的管理员记录总数(`count`),用于后续的分页计算等操作。
managersDAO.countByKey(conditions["query"], function (err, count) {
// 获取查询条件中的关键词(`key`),赋值为 `conditions["query"]`,方便后续在查询管理员记录等操作中使用该关键词进行筛选,它可能是用于模糊匹配管理员的某些关键信息(如姓名、手机号等)的字符串。
key = conditions["query"];
// 将查询条件中的 `pagenum` 参数转换为整数类型,赋值给 `pagenum` 变量,确保页码参数是合法的数字格式,用于后续的分页相关计算和操作,例如计算偏移量等。
pagenum = parseInt(conditions["pagenum"]);
// 将查询条件中的 `pagesize` 参数转换为整数类型,赋值给 `pagesize` 变量,同样确保每页记录数参数是合法的数字格式,用于分页操作中的相关计算,如计算总页数、限制查询记录数量等。
pagesize = parseInt(conditions["pagesize"]);
// 计算总页数,通过将符合关键词条件的管理员记录总数(`count`)除以每页显示记录数(`pagesize`),然后使用 `Math.ceil` 函数向上取整,得到总共需要的页数,
// 该总页数可用于判断传入的页码是否超出合理范围等情况,确保分页查询的完整性和正确性。
pageCount = Math.ceil(count / pagesize);
// 计算分页查询的偏移量(`offset`),通过公式 `(当前页码 - 1) * 每页显示记录数` 来确定从数据库中的哪条记录开始查询,
// 例如当前页码为 `1` 时,偏移量为 `0`,表示从第一条记录开始查询;页码为 `2` 时,偏移量为 `pagesize`,表示从第 `pagesize + 1` 条记录开始查询,以此类推,
// 这个偏移量用于数据库查询语句中指定查询的起始位置,实现分页功能。
offset = (pagenum - 1) * pagesize;
// 如果计算出的偏移量大于等于记录总数(`count`),说明传入的页码可能超出了合理范围(比如总共有 `100` 条记录,每页显示 `10` 条,传入页码 `11` 就会出现这种情况),
// 此时将偏移量设置为记录总数,避免查询出现错误,相当于查询最后一页(可能不满一页的情况)的数据,保证分页查询的健壮性。
if (offset >= count) {
offset = count;
}
// 获取每页显示记录数(`pagesize`),赋值给 `limit` 变量,在后续的数据库查询操作中用于指定每次查询获取的管理员记录数量上限,确保分页查询按设定的每页数量返回数据。
limit = pagesize;
// 调用 `managersDAO` 模块的 `findByKey` 方法,按照关键词(`key`)以及分页相关的偏移量(`offset`)和限制数量(`limit`)来查询符合条件的管理员记录,
// 该方法是一个异步操作,通过回调函数来处理查询结果,若成功则返回查询到的管理员记录数组(`managers`),每个元素是一个包含管理员详细信息的对象,后续会对这些信息进行整理和封装后返回给调用者。
managersDAO.findByKey(key, offset, limit, function (err, managers) {
// 创建一个空数组 `retManagers`,用于存储经过整理和格式化后的管理员信息,将原始查询到的管理员记录中的部分关键信息提取并按照统一格式进行封装,方便后续返回给调用者使用。
var retManagers = [];
// 遍历查询到的管理员记录数组 `managers`,通过索引 `idx` 来访问每个管理员信息对象,对每个管理员的信息进行整理和格式化操作,提取需要展示给调用者的关键信息,并添加到 `retManagers` 数组中。
for (idx in managers) {
var manager = managers[idx];
var role_name = manager.role_name;
// 如果管理员信息中的 `role_id` 不存在(可能表示未明确分配角色或者特殊情况),则将角色名称默认设置为 `超级管理员`,这是一种根据角色标识来处理角色名称显示的逻辑,确保有合理的角色名称展示给调用者。
if (!manager.role_id) {
role_name = "超级管理员"
}
// 将整理好的管理员关键信息按照特定格式封装成一个新的对象,并添加到 `retManagers` 数组中这些信息包括管理员ID`id`)、角色名称(`role_name`)、用户名(`username`)、
// 创建时间(`create_time`)、手机号(`mobile`)、邮箱(`email`)以及状态信息(`mg_state`,将数据库中的数字状态值转换为布尔类型,方便调用者理解和使用,例如 `1` 可能表示启用状态,转换后为 `true`)。
retManagers.push({
"id": manager.mg_id,
"role_name": role_name,
"username": manager.mg_name,
"create_time": manager.mg_time,
"mobile": manager.mg_mobile,
"email": manager.mg_email,
"mg_state": manager.mg_state == 1
});
}
// 创建一个空对象 `resultDta`,用于存储最终要返回给调用者的结果信息,包含符合条件的管理员记录总数(`total`)、当前页码(`pagenum`)以及整理好的管理员信息列表(`users`,即 `retManagers` 数组),
// 这样将查询结果和相关统计信息统一封装后返回给调用者,方便调用者进行后续的业务处理,比如在前端页面展示管理员列表、进行分页导航等操作。
var resultDta = {};
resultDta["total"] = count;
resultDta["pagenum"] = pagenum;
resultDta["users"] = retManagers;
// 将包含管理员相关信息和统计数据的 `resultDta` 对象通过回调函数 `cb` 返回给调用者,表示查询操作成功完成,调用者可以根据这些信息进行后续的业务操作,比如展示管理员列表、根据状态进行筛选等操作。
cb(err, resultDta);
});
});
}
//这段代码实现了根据特定查询条件获取管理员信息并进行分页处理的功能,通过对数据库操作的封装以及
//数据的整理和格式化,能够方便地为调用者提供符合要求的管理员列表数据以及相关统计信息,常用于
//管理系统中管理员列表展示等业务场景。
/**
* 创建管理员
* 此函数用于创建新的管理员账号接收包含管理员相关信息的参数对象以及一个回调函数
* 通过检查用户名是否已存在对密码进行加密处理等操作后将新管理员信息插入数据库若操作成功则返回创建后的管理员关键信息若失败则返回相应错误信息给回调函数
*
* @param {[type]} user 用户数据集
* @param {Function} cb 回调函数
* @param {[type]} user 用户数据集它是一个对象应包含创建管理员所需的各种信息例如用户名`username`密码`password`手机号`mobile`邮箱`email`角色ID`rid`等关键信息具体格式和字段要求由业务逻辑决定
* @param {Function} cb 回调函数用于接收创建管理员操作的结果若成功创建管理员则传递包含创建后的管理员关键信息如ID用户名手机号等的对象作为参数若出现错误情况如用户名已存在数据库插入失败等则传递相应的错误信息字符串作为参数
*/
module.exports.createManager = function(params,cb) {
managersDAO.exists(params.username,function(err,isExists){
if(err) return cb(err);
if(isExists) {
return cb("用户名已存在");
}
managersDAO.create({
"mg_name":params.username,
"mg_pwd":Password.hash(params.password),
"mg_mobile":params.mobile,
"mg_email":params.email,
"mg_time":(Date.parse(new Date())/1000),
"role_id":params.rid
},function(err,manager){
if(err) return cb("创建失败");
result = {
"id" : manager.mg_id,
"username" : manager.mg_name,
"mobile" : manager.mg_mobile,
"email" : manager.mg_email,
"role_id" : manager.role_id,
"create_time":manager.mg_time
};
cb(null,result);
});
});
module.exports.createManager = function (params, cb) {
// 调用 `managersDAO` 模块的 `exists` 方法,传入要创建的管理员的用户名(`params.username`),用于检查该用户名在数据库中是否已经存在,
// 该方法是一个异步操作,通过回调函数返回检查结果,若存在则 `isExists` 为 `true`,否则为 `false`,以此来判断是否能继续创建该管理员账号。
managersDAO.exists(params.username, function (err, isExists) {
// 如果在检查用户名是否存在的过程中出现错误(`err` 不为 `null`),比如数据库查询出现问题(连接故障、查询语句执行错误等),则直接通过回调函数 `cb` 返回错误信息,告知调用者操作出现问题及原因,终止创建操作。
if (err) return cb(err);
// 如果检查发现用户名已经存在(`isExists` 为 `true`),说明不能再使用该用户名创建新的管理员账号,直接通过回调函数 `cb` 返回相应的错误信息,表示用户名已存在,告知调用者需要更换用户名后再尝试创建操作。
if (isExists) {
return cb("用户名已存在");
}
// 调用 `managersDAO` 模块的 `create` 方法来执行创建管理员的数据库操作,传入一个包含管理员关键信息的对象,
// 其中对密码进行了加密处理(使用 `Password.hash` 函数,可能是通过特定的加密算法将明文密码转换为加密后的密文,以提高安全性),
// 同时包含用户名、手机号、邮箱、创建时间获取当前时间并转换为合适的时间戳格式方便数据库存储和后续查询对比等操作以及角色ID等信息
// 该方法是一个异步操作,通过回调函数来处理数据库插入操作完成后的结果情况,若成功则返回创建后的管理员对象(`manager`),可从中提取关键信息返回给调用者,若失败则返回相应错误信息告知调用者创建失败。
managersDAO.create({
"mg_name": params.username,
"mg_pwd": Password.hash(params.password),
"mg_mobile": params.mobile,
"mg_email": params.email,
"mg_time": (Date.parse(new Date()) / 1000),
"role_id": params.rid
}, function (err, manager) {
// 如果在创建管理员的数据库插入操作过程中出现错误(`err` 不为 `null`),比如违反数据库约束(可能某些字段长度限制、唯一性约束等问题)、数据库写入故障等原因,
// 则直接通过回调函数 `cb` 返回错误信息,表示创建失败,告知调用者创建管理员操作未成功及原因。
if (err) return cb("创建失败");
// 如果管理员创建成功,将创建后的管理员对象(`manager`)中的关键信息提取出来,按照特定格式封装成一个新的对象(`result`
// 这些关键信息包括管理员ID`id`)、用户名(`username`)、手机号(`mobile`)、邮箱(`email`、角色ID`role_id`)以及创建时间(`create_time`),方便统一返回给调用者展示或后续使用。
result = {
"id": manager.mg_id,
"username": manager.mg_name,
"mobile": manager.mg_mobile,
"email": manager.mg_email,
"role_id": manager.role_id,
"create_time": manager.mg_time
};
// 将包含创建后管理员关键信息的 `result` 对象通过回调函数 `cb` 返回给调用者,表示管理员创建成功,调用者可以获取这些信息进行后续操作,比如记录新管理员信息、进行权限分配等业务操作。
cb(null, result);
});
});
}
/**
* 更新管理员信息
* 此函数用于更新指定管理员的部分信息接收包含要更新的管理员信息的参数对象以及一个回调函数
* 通过调用数据库更新操作来修改管理员的手机号邮箱等信息根据传入的参数确定具体更新的字段若操作成功则返回更新后的管理员关键信息若失败则返回相应错误信息给回调函数
*
* @param {[type]} params 管理员信息
* @param {Function} cb 回调函数
* @param {[type]} params 管理员信息它是一个对象包含要更新的管理员相关信息例如管理员ID`id`用于确定要更新的具体管理员记录以及要更新的手机号`mobile`邮箱`email`等字段信息具体更新哪些字段由传入的参数决定
* @param {Function} cb 回调函数用于接收更新管理员操作的结果若成功更新管理员信息则传递包含更新后的管理员关键信息如ID用户名手机号等的对象作为参数若出现错误情况如数据库更新失败等则传递相应的错误信息字符串作为参数
*/
module.exports.updateManager = function(params,cb) {
managersDAO.update(
{
"mg_id":params.id,
"mg_mobile":params.mobile,
"mg_email":params.email
},
function(err,manager) {
if(err) return cb(err);
cb(null,{
"id":manager.mg_id,
"username":manager.mg_name,
"role_id":manager.role_id,
"mobile":manager.mg_mobile,
"email":manager.mg_email
});
}
)
module.exports.updateManager = function (params, cb) {
// 调用 `managersDAO` 模块的 `update` 方法来执行更新管理员信息的数据库操作,
// 传入两个参数,第一个参数是一个对象,用于指定更新的条件以及要更新的部分字段信息,这里通过 `{"mg_id":params.id, "mg_mobile":params.mobile, "mg_email":params.email}` 指定了根据管理员ID`params.id`)来确定要更新的记录,
// 同时更新该记录对应的手机号(`mg_mobile`)和邮箱(`mg_email`)字段的值(使用传入的 `params.mobile` 和 `params.email` 的值进行更新),
// 第二个参数是一个回调函数,用于处理数据库更新操作完成后的结果情况,若成功则返回更新后的管理员对象(`manager`),可从中提取关键信息返回给调用者,若失败则返回相应错误信息告知调用者更新失败。
managersDAO.update(
{
"mg_id": params.id,
"mg_mobile": params.mobile,
"mg_email": params.email
},
function (err, manager) {
// 如果在更新管理员信息的数据库操作过程中出现错误(`err` 不为 `null`),比如违反数据库约束(例如手机号格式不符合要求、邮箱唯一性冲突等问题)、数据库更新语句执行错误等原因,
// 则直接通过回调函数 `cb` 返回错误信息,告知调用者操作出现问题及原因,终止更新操作。
if (err) return cb(err);
// 如果管理员信息更新成功,将更新后的管理员对象(`manager`)中的关键信息提取出来,按照特定格式封装成一个新的对象返回给调用者,
// 这些关键信息包括管理员ID`id`)、用户名(`username`、角色ID`role_id`)、手机号(`mobile`)以及邮箱(`email`),方便调用者获取更新后的管理员信息进行后续操作,比如展示更新后的管理员详情等业务操作。
cb(null, {
"id": manager.mg_id,
"username": manager.mg_name,
"role_id": manager.role_id,
"mobile": manager.mg_mobile,
"email": manager.mg_email
});
}
)
}
/**
* 通过管理员 ID 获取管理员信息
* 此函数用于根据传入的管理员ID从数据库中获取对应的管理员详细信息接收管理员ID以及一个回调函数
* 通过调用数据库查询操作查找指定ID的管理员记录若找到则返回管理员关键信息若未找到或者出现查询错误则返回相应错误信息给回调函数
*
* @param {[type]} id 管理员 ID
* @param {Function} cb 回调函数
* @param {[type]} id 管理员 ID用于唯一确定要获取信息的管理员记录是从数据库中查询对应管理员的关键标识
* @param {Function} cb 回调函数用于接收获取管理员信息操作的结果若成功获取到管理员信息则传递包含管理员关键信息如ID角色ID用户名手机号邮箱等的对象作为参数若出现错误情况如数据库查询失败管理员不存在等则传递相应的错误信息字符串作为参数
*/
module.exports.getManager = function(id,cb) {
managersDAO.show(id,function(err,manager){
if(err) return cb(err);
if(!manager) return cb("该管理员不存在");
cb(
null,
{
"id":manager.mg_id,
"rid":manager.role_id,
"username":manager.mg_name,
"mobile":manager.mg_mobile,
"email":manager.mg_email
}
);
});
module.exports.getManager = function (id, cb) {
// 调用 `managersDAO` 模块的 `show` 方法来执行查询指定ID管理员信息的数据库操作传入管理员ID`id`)作为查询条件,
// 该方法是一个异步操作,通过回调函数来处理查询结果,若成功则返回对应的管理员对象(`manager`),若未找到对应的管理员记录或者出现查询错误(`err` 不为 `null`),则通过回调函数返回相应错误信息告知调用者。
managersDAO.show(id, function (err, manager) {
// 如果在查询管理员信息的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库连接问题、查询语句执行错误等原因,
// 则直接通过回调函数 `cb` 返回错误信息,告知调用者操作出现问题及原因,终止获取信息操作。
if (err) return cb(err);
// 如果查询结果没有获取到对应的管理员(`!manager`,即 `manager` 为 `null`说明该管理员ID不存在通过回调函数 `cb` 返回相应的错误信息,表示该管理员不存在,告知调用者无法获取对应的管理员信息。
if (!manager) return cb("该管理员不存在");
// 如果成功获取到管理员信息,将管理员对象(`manager`)中的关键信息提取出来,按照特定格式封装成一个新的对象返回给调用者,
// 这些关键信息包括管理员ID`id`、角色ID`rid`)、用户名(`mg_name`,这里重命名为 `username` 方便调用者理解和使用统一的命名规范)、手机号(`mg_mobile`)以及邮箱(`mg_email`
// 方便调用者获取管理员详细信息进行后续操作,比如展示管理员详情、进行权限判断等业务操作。
cb(
null,
{
"id": manager.mg_id,
"rid": manager.role_id,
"username": manager.mg_name,
"mobile": manager.mg_mobile,
"email": manager.mg_email
}
);
});
}
/**
* 通过管理员 ID 进行删除操作
* 此函数用于根据传入的管理员ID从数据库中删除对应的管理员记录接收管理员ID以及一个回调函数
* 通过调用数据库删除操作来移除指定ID的管理员记录若操作成功则返回空值表示删除成功若失败则返回相应错误信息给回调函数
*
* @param {[type]} id 管理员ID
* @param {Function} cb 回调函数
* @param {[type]} id 管理员ID用于唯一确定要删除的管理员记录是从数据库中定位并删除对应管理员的关键标识
* @param {Function} cb 回调函数用于接收删除管理员操作的结果若成功删除管理员记录则传递 `null` 表示操作成功若出现错误情况如数据库删除失败等则传递相应的错误信息字符串作为参数
*/
module.exports.deleteManager = function(id,cb) {
managersDAO.destroy(id,function(err){
if(err) return cb("删除失败");
cb(null);
});
module.exports.deleteManager = function (id, cb) {
// 调用 `managersDAO` 模块的 `destroy` 方法来执行删除指定ID管理员记录的数据库操作传入管理员ID`id`)作为删除条件,
// 该方法是一个异步操作,通过回调函数来处理操作结果,若成功删除则回调函数无额外返回数据(通常返回 `null` 表示操作成功),若出现错误(`err` 不为 `null`)则返回相应错误信息告知调用者删除失败。
managersDAO.destroy(id, function (err) {
// 如果在删除管理员记录的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库权限不足、违反外键约束(若存在关联其他表的数据时可能出现此问题)、数据库删除语句执行错误等原因,
// 则直接通过回调函数 `cb` 返回错误信息,表示删除失败,告知调用者删除管理员操作未成功及原因。
if (err) return cb("删除失败");
// 如果管理员记录删除成功,通过回调函数 `cb` 返回 `null`,表示删除操作顺利完成,告知调用者可以进行后续相关业务操作,比如刷新管理员列表等操作。
cb(null);
});
}
/**
* 为管理员设置角色
* 此函数用于为指定的管理员设置新的角色接收管理员ID和角色ID以及一个回调函数
* 通过先查询管理员是否存在再执行数据库更新操作来修改管理员对应的角色ID字段值若操作成功则返回更新后的管理员关键信息若失败则返回相应错误信息给回调函数
*
* @param {[type]} id 管理员ID
* @param {[type]} rid 角色ID
* @param {Function} cb 回调函数
* @param {[type]} id 管理员ID用于唯一确定要设置角色的管理员记录是从数据库中定位对应管理员的关键标识
* @param {[type]} rid 角色ID用于指定要为管理员设置的新角色的唯一标识通过更新操作将该角色ID关联到对应的管理员记录上
* @param {Function} cb 回调函数用于接收为管理员设置角色操作的结果若成功为管理员设置了新角色则传递包含更新后的管理员关键信息如ID角色ID用户名手机号邮箱等的对象作为参数若出现错误情况如管理员ID不存在数据库更新失败等则传递相应的错误信息字符串作为参数
*/
module.exports.setRole = function(id,rid,cb) {
managersDAO.show(id,function(err,manager){
if(err || !manager) cb("管理员ID不存在");
managersDAO.update({"mg_id":manager.mg_id,"role_id":rid},function(err,manager){
if(err) return cb("设置失败");
cb(null,{
"id":manager.mg_id,
"rid":manager.role_id,
"username":manager.mg_name,
"mobile":manager.mg_mobile,
"email":manager.mg_email,
});
});
})
module.exports.setRole = function (id, rid, cb) {
// 调用 `managersDAO` 模块的 `show` 方法来执行查询指定ID管理员信息的数据库操作传入管理员ID`id`)作为查询条件,
// 该方法是一个异步操作,通过回调函数来处理查询结果,若成功则返回对应的管理员对象(`manager`),若未找到对应的管理员记录或者出现查询错误(`err` 不为 `null`则通过回调函数返回相应错误信息告知调用者管理员ID不存在终止设置角色操作。
managersDAO.show(id, function (err, manager) {
// 如果在查询管理员信息的过程中出现错误(`err` 不为 `null`),或者查询结果没有获取到对应的管理员(`!manager`说明管理员ID不存在或者出现其他查询问题
// 通过回调函数 `cb` 返回相应的错误信息表示管理员ID不存在告知调用者无法为不存在的管理员设置角色终止操作。
if (err ||!manager) cb("管理员ID不存在");
// 调用 `managersDAO` 模块的 `update` 方法来执行更新管理员角色ID的数据库操作传入两个参数
// 第一个参数是一个对象用于指定更新的条件以及要更新的角色ID字段信息这里通过 `{"mg_id":manager.mg_id,"role_id":rid}` 指定了根据管理员的实际ID`manager.mg_id`)来确定要更新的记录,
// 并将角色ID字段`role_id`更新为传入的新角色ID`rid`)的值,第二个参数是一个回调函数,用于处理数据库更新操作完成后的结果情况,若成功则返回更新后的管理员对象(`manager`),可从中提取关键信息返回给调用者,若失败则返回相应错误信息告知调用者设置失败。
managersDAO.update({"mg_id": manager.mg_id, "role_id": rid}, function (err, manager) {
// 如果在更新管理员角色ID的数据库操作过程中出现错误`err` 不为 `null`比如违反数据库约束例如角色ID不存在、不满足关联关系等问题、数据库更新语句执行错误等原因
// 则直接通过回调函数 `cb` 返回错误信息,表示设置失败,告知调用者设置管理员角色操作未成功及原因。
if (err) return cb("设置失败");
// 如果管理员角色ID更新成功将更新后的管理员对象`manager`)中的关键信息提取出来,按照特定格式封装成一个新的对象返回给调用者,
// 这些关键信息包括管理员ID`id`、角色ID`rid`)、用户名(`mg_name`,重命名为 `username`)、手机号(`mg_mobile`)以及邮箱(`mg_email`
// 方便调用者获取更新后的管理员信息进行后续操作,比如查看管理员角色变更后的权限情况等业务操作。
cb(null, {
"id": manager.mg_id,
"rid": manager.role_id,
"username": manager.mg_name,
"mobile": manager.mg_mobile,
"email": manager.mg_email,
});
});
})
}
module.exports.updateMgrState = function(id,state,cb) {
managersDAO.show(id,function(err,manager){
if(err || !manager) cb("管理员ID不存在");
managersDAO.update({"mg_id":manager.mg_id,"mg_state":state},function(err,manager){
if(err) return cb("设置失败");
cb(null,{
"id":manager.mg_id,
"rid":manager.role_id,
"username":manager.mg_name,
"mobile":manager.mg_mobile,
"email":manager.mg_email,
"mg_state":manager.mg_state ? 1 : 0
});
});
})
module.exports.updateMgrState = function (id, state, cb) {
// 调用 `managersDAO` 模块的 `show` 方法来执行查询指定ID管理员信息的数据库操作传入管理员ID`id`)作为查询条件,
// 该方法是一个异步操作,通过回调函数来处理查询结果,若成功则返回对应的
// 先调用 `managersDAO` 模块的 `show` 方法,根据传入的管理员 `id` 去数据库中查询对应的管理员信息。
// 这是一个异步操作,会传入一个回调函数来处理查询结果,在回调函数中接收可能出现的错误信息 `err` 以及查询到的管理员对象 `manager`。
managersDAO.show(id, function (err, manager) {
// 如果在查询管理员信息的过程中出现错误(`err` 不为 `null`),或者没有查询到对应的管理员(`!manager`,即 `manager` 为 `null`
// 说明管理员ID不存在或者出现了数据库查询相关的问题此时通过回调函数 `cb` 返回错误信息“管理员ID不存在”告知调用者无法进行后续操作因为要操作的管理员对象不存在。
if (err ||!manager) cb("管理员ID不存在");
// 如果查询到了对应的管理员信息,接下来调用 `managersDAO` 模块的 `update` 方法,尝试更新该管理员的状态信息。
// 传入一个对象作为更新条件和要更新的数据,对象中 `{"mg_id":manager.mg_id,"mg_state":state}` 表示根据当前查询到的管理员的实际 `mg_id` 来确定要更新的记录,
// 并将 `mg_state` 字段更新为传入的 `state` 参数值,同样这是一个异步操作,通过传入的回调函数来处理更新操作的结果。
managersDAO.update({"mg_id": manager.mg_id, "mg_state": state}, function (err, manager) {
// 如果在更新管理员状态的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库更新语句执行失败、违反数据约束等原因,
// 则通过回调函数 `cb` 返回错误信息“设置失败”,告知调用者更新管理员状态的操作没有成功,方便调用者进行相应的错误处理或提示给用户等操作。
if (err) return cb("设置失败");
// 如果管理员状态更新成功,通过回调函数 `cb` 返回一个包含更新后管理员关键信息的对象。
// 其中包括管理员 `id``manager.mg_id`)、角色 `id``manager.role_id`)、用户名(`manager.mg_name`)、手机号(`manager.mg_mobile`)、邮箱(`manager.mg_email`)以及更新后的状态信息(`mg_state`
// 这里对 `mg_state` 进行了一个简单的处理,将其转换为 `1`(如果 `mg_state` 为真)或 `0`(如果 `mg_state` 为假)的格式,方便后续业务逻辑中对状态的判断和使用,然后将整个对象返回给调用者,告知调用者更新操作已完成且返回了最新的管理员信息。
cb(null, {
"id": manager.mg_id,
"rid": manager.role_id,
"username": manager.mg_name,
"mobile": manager.mg_mobile,
"email": manager.mg_email,
"mg_state": manager.mg_state? 1 : 0
});
});
})
}
/**
* 管理员登录
* @param {[type]} username 用户名
* @param {[type]} password 密码
* @param {Function} cb 回调
* 此函数用于处理管理员登录的逻辑接收用户名和密码作为参数以及一个回调函数用于返回登录操作的结果
* 通过查询数据库验证用户名是否存在检查用户权限及状态等多步操作判断登录是否成功若成功则返回管理员相关信息若失败则返回相应的错误信息给回调函数
*
* @param {[type]} username 用户名是管理员登录时输入的标识信息用于在数据库中查找对应的管理员记录
* @param {[type]} password 密码是管理员登录时输入的密码信息用于和数据库中存储的加密密码进行比对验证
* @param {Function} cb 回调函数用于接收管理员登录操作的结果若登录成功则传递包含管理员关键信息如ID角色ID用户名手机号邮箱等的对象作为参数若出现错误情况如用户名不存在用户无权限密码错误等则传递相应的错误信息字符串作为参数
*/
module.exports.login = function(username,password,cb) {
logger.debug('login => username:%s,password:%s',username,password);
logger.debug(username);
managersDAO.findOne({"mg_name":username},function(err,manager) {
logger.debug(err);
if(err || !manager) return cb("用户名不存在");
if(manager.role_id < 0) {
return cb("该用户没有权限登录");
}
if(manager.role_id != 0 && manager.mg_state != 1) {
return cb("该用户已经被禁用");
}
if(Password.verify(password, manager.mg_pwd)){
cb(
null,
{
"id":manager.mg_id,
"rid":manager.role_id,
"username":manager.mg_name,
"mobile":manager.mg_mobile,
"email":manager.mg_email,
}
);
} else {
return cb("密码错误");
}
});
}
module.exports.login = function (username, password, cb) {
// 使用 `logger` 对象的 `debug` 方法记录调试信息,输出登录操作时传入的用户名和密码信息,方便在开发调试阶段查看登录时的参数情况,有助于排查问题,例如查看是否传入了正确的用户名和密码值。
logger.debug('login => username:%s,password:%s', username, password);
// 再次使用 `logger` 对象的 `debug` 方法记录调试信息,单独输出用户名信息,进一步方便在调试时查看用户名相关情况,比如确认用户名是否符合预期格式等。
logger.debug(username);
// 调用 `managersDAO` 模块的 `findOne` 方法,根据传入的用户名(`{"mg_name":username}`)去数据库中查找对应的管理员记录,
// 这是一个异步操作,通过传入的回调函数来处理查询结果,在回调函数中接收可能出现的错误信息 `err` 以及查询到的管理员对象 `manager`。
managersDAO.findOne({"mg_name": username}, function (err, manager) {
// 使用 `logger` 对象的 `debug` 方法记录调试信息,输出查询管理员过程中出现的错误信息 `err`,方便在调试时查看是否出现了数据库查询相关的错误以及具体错误内容,有助于定位问题所在。
logger.debug(err);
// 如果在查询管理员的过程中出现错误(`err` 不为 `null`),或者没有查询到对应的管理员(`!manager`,即 `manager` 为 `null`
// 说明用户名不存在或者出现了数据库查询相关的问题,此时通过回调函数 `cb` 返回错误信息“用户名不存在”,告知调用者登录操作失败,因为找不到对应的管理员账号,方便调用者进行相应的提示给用户等操作。
if (err ||!manager) return cb("用户名不存在");
// 如果查询到的管理员的角色 `id``manager.role_id`)小于 `0`,说明该用户可能不符合正常的权限设定规则(具体含义由业务逻辑定义,可能是特殊标记表示无登录权限等情况),
// 此时通过回调函数 `cb` 返回错误信息“该用户没有权限登录”,告知调用者该管理员账号不能用于登录,可能需要联系相关人员处理权限问题等操作。
if (manager.role_id < 0) {
return cb("该用户没有权限登录");
}
// 如果管理员的角色 `id` 不等于 `0`(可能表示不是超级管理员之类具有特殊权限的角色)且管理员的状态(`manager.mg_state`)不等于 `1`(通常 `1` 表示启用状态,`0` 表示禁用等其他状态,具体由业务逻辑定义),
// 说明该用户虽然存在且有相应角色,但当前处于被禁用状态,此时通过回调函数 `cb` 返回错误信息“该用户已经被禁用”,告知调用者该管理员账号不能登录,可能需要联系管理员进行账号启用等操作。
if (manager.role_id!= 0 && manager.mg_state!= 1) {
return cb("该用户已经被禁用");
}
// 使用 `Password` 模块的 `verify` 方法来验证输入的密码(`password`)与数据库中存储的该管理员的加密密码(`manager.mg_pwd`)是否匹配,
// 如果匹配成功(即密码验证通过),说明登录信息正确,通过回调函数 `cb` 返回一个包含管理员关键信息的对象,
// 这些信息包括管理员 `id``manager.mg_id`)、角色 `id``manager.role_id`)、用户名(`manager.mg_name`)、手机号(`manager.mg_mobile`)、邮箱(`manager.mg_email`),方便后续业务逻辑根据登录后的管理员信息进行相应操作,比如进入管理系统主界面、记录登录日志等操作。
if (Password.verify(password, manager.mg_pwd)) {
cb(
null,
{
"id": manager.mg_id,
"rid": manager.role_id,
"username": manager.mg_name,
"mobile": manager.mg_mobile,
"email": manager.mg_email,
}
);
} else {
// 如果密码验证不通过,说明输入的密码错误,通过回调函数 `cb` 返回错误信息“密码错误”,告知调用者登录失败,方便调用者进行相应的提示给用户等操作,比如提示用户重新输入密码。
return cb("密码错误");
}
});
}
//这段代码实现了管理员相关的重要操作逻辑,包括更新管理员状态以及管理员登录验证等功能。通过与数
//据库的交互以及各种条件判断,保证了这些操作的准确性和安全性,同时借助日志记录方便了调试与问
//题排查。

@ -1,90 +1,132 @@
// 引入lodash库用于处理各种数据结构提供了如对象操作、数组处理、排序等很多实用的工具函数在后续代码中会频繁使用到。
var _ = require('lodash');
// 引入Node.js的path模块主要用于处理文件路径相关操作通过 `path.join` 方法拼接当前工作目录(`process.cwd()`)和相对路径,来准确引入自定义的 `dao/DAO` 和 `dao/PermissionAPIDAO` 模块所在的路径。
var path = require("path");
var dao = require(path.join(process.cwd(),"dao/DAO"));
var permissionAPIDAO = require(path.join(process.cwd(),"dao/PermissionAPIDAO"));
// 引入自定义的 `DAO` 模块,该模块应该封装了通用的数据访问操作方法,例如查询、获取单条记录等操作,对应不同的数据模型(如 `RoleModel` 等)与数据库进行交互,执行相关的数据操作。
var dao = require(path.join(process.cwd(), "dao/DAO"));
// 引入自定义的 `PermissionAPIDAO` 模块,推测这个模块主要用于权限相关数据的访问操作,比如获取权限列表等功能,同样是与数据库进行交互来获取权限数据,为后续构建菜单数据提供基础信息。
var permissionAPIDAO = require(path.join(process.cwd(), "dao/PermissionAPIDAO"));
/**
* 获取左侧菜单数据
* 此函数用于根据用户信息获取对应的左侧菜单数据通过回调函数将获取到的菜单数据成功时或错误信息失败时返回给调用者以用于前端页面展示菜单等相关业务操作
*
* @param {Function} cb 回调函数
* @param {Function} cb 回调函数用于接收获取左侧菜单数据操作的结果若成功获取到菜单数据则传递菜单数据对象作为参数若出现错误情况如无权限数据库查询失败等则传递相应的错误信息字符串作为参数
*/
module.exports.getLeftMenus = function(userInfo,cb) {
if(!userInfo) return cb("无权限访问");
module.exports.getLeftMenus = function (userInfo, cb) {
// 首先验证传入的用户信息(`userInfo`)是否存在,如果不存在则说明无法确定用户身份及权限等情况,直接通过回调函数 `cb` 返回错误信息,表示无权限访问,终止后续操作。
if (!userInfo) return cb("无权限访问");
// 定义一个内部函数 `authFn`用于根据角色ID`rid`)以及角色已有的权限信息(`keyRolePermissions`)来获取并整理权限数据,构建成菜单结构形式的数据,最终通过回调函数 `cb` 返回处理后的结果。
var authFn = function (rid, keyRolePermissions, cb) {
// 调用 `permissionAPIDAO` 模块的 `list` 方法来获取所有的权限数据,该方法内部大概率会执行数据库查询操作,从数据库中获取权限相关的记录信息,它是一个异步操作,通过回调函数来处理查询结果。
permissionAPIDAO.list(function (err, permissions) {
// 如果在获取权限数据的过程中出现错误(`err` 不为 `null`),比如数据库查询失败(可能是连接问题、权限不足、表不存在等原因),则直接通过回调函数 `cb` 返回错误信息,表示获取权限数据失败,让调用者知晓操作出现问题及原因。
if (err) return cb("获取权限数据失败");
var authFn = function(rid,keyRolePermissions,cb) {
permissionAPIDAO.list(function(err,permissions){
if(err) return cb("获取权限数据失败");
var keyPermissions = _.keyBy(permissions,'ps_id');
var rootPermissionsResult = {};
// 处理一级菜单
for(idx in permissions) {
// 使用 `lodash` 的 `keyBy` 函数,将获取到的权限数据(`permissions`按照权限ID`ps_id`进行转换生成一个以权限ID为键对应权限详细信息为值的对象结构
// 方便后续通过权限ID快速查找对应的权限详情在构建菜单数据结构以及判断权限关联等操作中能更高效地获取所需信息。
var keyPermissions = _.keyBy(permissions, 'ps_id');
permission = permissions[idx];
if(permission.ps_level == 0) {
if(rid != 0) {
if(!keyRolePermissions[permission.ps_id]) continue;;
}
rootPermissionsResult[permission.ps_id] = {
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path,
"children":[],
"order":permission.ps_api_order
};
}
}
// 创建一个空对象 `rootPermissionsResult`用于存储最终整理好的菜单数据结构它将以一级菜单权限的权限ID为键对应权限的详细信息包含子菜单信息等为值进行存储作为菜单结构的顶层节点。
var rootPermissionsResult = {};
// 处理二级菜单
for(idx in permissions) {
permission = permissions[idx];
if(permission.ps_level == 1) {
if(rid != 0) {
if(!keyRolePermissions[permission.ps_id]) continue;;
}
parentPermissionResult = rootPermissionsResult[permission.ps_pid];
if(parentPermissionResult) {
parentPermissionResult.children.push({
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path,
"children":[],
"order":permission.ps_api_order
});
}
}
}
// 排序
result = _.values(rootPermissionsResult);
result = _.sortBy(result,"order");
for(idx in result) {
subresult = result[idx];
subresult.children = _.sortBy(subresult.children,"order");
}
// 处理一级菜单
// 遍历获取到的权限数据数组 `permissions`,通过索引 `idx` 来访问每个权限信息对象,针对每个权限进行相关处理,构建一级菜单对应的权限信息结构并添加到 `rootPermissionsResult` 对象中。
for (idx in permissions) {
permission = permissions[idx];
// 如果当前权限的层级(`ps_level`为0表示它是一级菜单权限进行以下操作来构建一级菜单数据结构。
if (permission.ps_level == 0) {
// 如果角色ID`rid`不等于0意味着不是特殊的默认角色可能是普通用户角色等情况此时需要进一步判断当前权限是否在该角色已有的权限列表中通过 `keyRolePermissions` 对象来检查),
// 如果当前权限不在角色权限列表中(`!keyRolePermissions[permission.ps_id]`),则使用 `continue` 跳过本次循环,不将该权限添加到一级菜单数据结构中,因为该角色没有此权限对应的菜单显示权限。
if (rid!= 0) {
if (!keyRolePermissions[permission.ps_id]) continue;
}
// 如果满足添加条件角色ID为0或者权限在角色权限列表中则将当前一级菜单权限的相关信息按照特定结构添加到 `rootPermissionsResult` 对象中,
// 包括权限ID、权限名称`authName`)、对应的接口路径(`ps_api_path`,可能用于前端路由跳转等操作)、初始化一个空的子菜单数组(`children`)以及权限的显示顺序(`order`,用于后续菜单排序)。
rootPermissionsResult[permission.ps_id] = {
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path,
"children": [],
"order": permission.ps_api_order
};
}
}
cb(null,result);
});
}
// 处理二级菜单
// 再次遍历权限数据数组 `permissions`,同样对每个权限进行检查和相关处理,这次是构建二级菜单对应的权限信息结构,并关联到对应的一级菜单权限下,完善菜单数据的层级结构。
for (idx in permissions) {
permission = permissions[idx];
if (permission.ps_level == 1) {
// 如果角色ID`rid`不等于0同样需要判断当前二级菜单权限是否在该角色已有的权限列表中通过 `keyRolePermissions` 对象来检查),
// 如果不在角色权限列表中,则使用 `continue` 跳过本次循环,不处理该权限,因为角色没有此权限对应的菜单显示权限。
if (rid!= 0) {
if (!keyRolePermissions[permission.ps_id]) continue;
}
// 根据当前二级菜单权限的父级权限ID`ps_pid`),从 `rootPermissionsResult` 中获取对应的一级菜单权限结果对象,后续将把当前二级菜单权限添加到这个一级菜单权限的子菜单列表中。
parentPermissionResult = rootPermissionsResult[permission.ps_pid];
if (parentPermissionResult) {
// 将当前二级菜单权限的相关信息按照特定结构添加到对应的一级菜单权限结果对象的子菜单数组(`children`)中,建立起二级菜单与一级菜单的层级关系,
// 包括权限ID、权限名称、对应的接口路径、初始化一个空的子菜单数组用于后续可能存在的三级菜单等继续添加以及权限的显示顺序。
parentPermissionResult.children.push({
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path,
"children": [],
"order": permission.ps_api_order
});
}
}
}
rid = userInfo.rid;
if(rid == 0) {
authFn(rid,null,cb);
} else {
dao.show("RoleModel",userInfo.rid,function(err,role){
if(err || !role) return cb("无权限访问");
rolePermissions = role.ps_ids.split(",")
keyRolePermissions = {}
for(idx in rolePermissions) {
keyRolePermissions[rolePermissions[idx]] = true;
}
// 排序
// 首先使用 `_.values` 获取 `rootPermissionsResult` 对象中的值(即整理好的菜单数据结构,包含一级菜单及其子菜单信息),形成一个数组 `result`,方便后续进行排序操作。
result = _.values(rootPermissionsResult);
// 使用 `_.sortBy` 函数按照每个菜单对象中的 `order` 属性(权限的显示顺序)对 `result` 数组进行排序,使得一级菜单按照指定的顺序排列,提升菜单展示的合理性和美观性。
result = _.sortBy(result, "order");
// 遍历排序后的一级菜单数组 `result`,对每个一级菜单下的子菜单数组(`subresult.children`)同样使用 `_.sortBy` 函数按照 `order` 属性进行排序,
// 保证二级菜单在各自的一级菜单下也按照指定顺序排列,进一步完善菜单数据的有序性,方便前端按照顺序展示菜单。
for (idx in result) {
subresult = result[idx];
subresult.children = _.sortBy(subresult.children, "order");
}
authFn(rid,keyRolePermissions,cb);
})
}
}
// 将整理好并排序后的菜单数据结构通过回调函数 `cb` 返回给调用者,表示成功获取并处理好了左侧菜单数据,调用者可以根据这个数据结构进行后续的操作,
// 比如将菜单数据传递给前端框架进行菜单渲染展示等业务操作。
cb(null, result);
});
}
// 获取用户信息中的角色ID`rid`用于后续判断用户角色情况以及相应的权限处理角色ID是区分不同用户角色、确定权限范围的重要标识。
rid = userInfo.rid;
// 如果角色ID`rid`等于0可能表示特殊的默认角色例如超级管理员等拥有全部权限的角色直接调用 `authFn` 函数传入角色ID以及 `null`(因为默认角色无需再额外判断权限是否在角色权限列表中),
// 让 `authFn` 函数去获取并整理所有权限数据构建菜单结构,最终通过回调函数 `cb` 返回结果。
if (rid == 0) {
authFn(rid, null, cb);
} else {
// 如果角色ID不等于0说明是普通用户角色等情况需要先获取该角色对应的详细信息以确定其拥有的权限列表进而根据权限来构建菜单数据结构。
// 调用 `dao` 模块的 `show` 方法来获取指定角色ID`userInfo.rid`)对应的角色信息,该方法内部会执行数据库查询操作,查找对应角色的记录,它是一个异步操作,通过回调函数来处理查询结果。
dao.show("RoleModel", userInfo.rid, function (err, role) {
// 如果在获取角色信息的过程中出现错误(`err` 不为 `null`),或者查询结果没有获取到对应的角色(`!role`),说明可能出现权限问题(比如角色不存在、无权限查询角色信息等情况),
// 则直接通过回调函数 `cb` 返回错误信息,表示无权限访问,终止后续操作,告知调用者无法获取菜单数据及原因。
if (err ||!role) return cb("无权限访问");
// 将获取到的角色对象中的权限ID字符串`ps_ids`可能是以逗号分隔的权限ID列表进行分割得到一个权限ID数组 `rolePermissions`,方便后续判断每个权限是否属于该角色。
rolePermissions = role.ps_ids.split(",");
// 创建一个空对象 `keyRolePermissions`用于以权限ID为键值为 `true` 的形式来存储该角色拥有的权限信息,方便后续快速判断某个权限是否在该角色的权限范围内。
keyRolePermissions = {};
// 遍历权限ID数组 `rolePermissions`将每个权限ID作为键添加到 `keyRolePermissions` 对象中,并将对应的值设置为 `true`,构建角色权限的快速查找结构。
for (idx in rolePermissions) {
keyRolePermissions[rolePermissions[idx]] = true;
}
// 调用 `authFn` 函数传入角色ID`rid`)以及构建好的角色权限查找对象(`keyRolePermissions`),让 `authFn` 函数根据该角色的权限情况去获取并整理权限数据,构建菜单结构,最终通过回调函数 `cb` 返回结果。
authFn(rid, keyRolePermissions, cb);
})
}
}
//这段代码整体实现了根据用户角色信息获取对应的左侧菜单数据的功能,通过对不同角色(如超级管理员
//和普通用户角色)的权限判断和处理,构建出具有层级结构且有序排列的菜单数据,适用于权限管理与前
//端菜单展示相关的应用开发场景,能够根据用户权限灵活展示不同的菜单内容。

@ -1,292 +1,484 @@
// 引入lodash库用于处理各种数据结构提供了很多便捷的工具函数例如对象克隆、数组求和、遍历等操作在后续多个函数中会用到。
var _ = require('lodash');
// 引入Node.js的path模块用于处理文件路径相关操作此处用于准确引入自定义的 `dao/DAO` 模块所在的路径。
var path = require("path");
// 引入 `orm` 库,可能用于对象关系映射相关操作,从代码中看,像是用于构建数据库查询条件等功能(例如使用 `orm.like` 方法),方便与数据库进行交互。
var orm = require("orm");
var dao = require(path.join(process.cwd(),"dao/DAO"));
// 引入自定义的 `DAO` 模块,该模块应该封装了与数据库操作相关的通用方法,例如创建、查询、更新等操作,对应不同的数据模型(如 `OrderModel`、`OrderGoodModel` 等)进行数据库层面的操作。
var dao = require(path.join(process.cwd(), "dao/DAO"));
// 引入 `bluebird` 库,用于处理异步操作的 `Promise`,使得异步代码可以用更清晰的链式调用方式书写,提高代码的可读性和可维护性,在多个函数中用于包装异步操作并返回 `Promise` 对象。
var Promise = require("bluebird");
// 引入 `uniqid` 库,用于生成唯一的标识符,在创建订单相关逻辑中可能用于生成订单编号等唯一标识信息。
var uniqid = require('uniqid');
// 定义 `doCheckOrderParams` 函数,用于对创建或更新订单时传入的参数进行合法性检查和预处理,将处理后的参数信息以 `Promise` 的形式返回。
function doCheckOrderParams(params) {
return new Promise(function(resolve,reject) {
var info = {};
if(params.order_id) info.order_id = params.order_id;
if(!params.order_id) {
if(!params.user_id) return reject("用户ID不能为空");
if(isNaN(parseInt(params.user_id))) return reject("用户ID必须是数字");
info.user_id = params.user_id;
}
if(!params.order_id) info.order_number = "itcast-" + uniqid();
if(!params.order_price) return reject("订单价格不能为空");
if(isNaN(parseFloat(params.order_price))) return reject("订单价格必须为数字");
info.order_price = params.order_price;
if(params.order_pay){
info.order_pay = params.order_pay;
} else {
info.order_pay = '0';
}
if(params.is_send) {
if(params.is_send == 1) {
info.is_send = '是';
} else {
info.is_send = '否';
}
} else {
info.is_send = '否';
}
if(params.trade_no) {
info.trade_no = '否';
} else {
info.trade_no = '';
}
if(params.order_fapiao_title) {
if(params.order_fapiao_title != '个人' && params.order_fapiao_title != '公司')
return reject("发票抬头必须是 个人 或 公司");
info.order_fapiao_title = params.order_fapiao_title;
} else {
info.order_fapiao_title = "个人";
}
if(params.order_fapiao_company) {
info.order_fapiao_company = params.order_fapiao_company;
} else {
info.order_fapiao_company = "";
}
if(params.order_fapiao_content) {
info.order_fapiao_content= params.order_fapiao_content;
} else {
info.order_fapiao_content= "";
}
if(params.consignee_addr) {
info.consignee_addr = params.consignee_addr;
} else {
info.consignee_addr = "";
}
if(params.goods) {
info.goods = params.goods;
}
info.pay_status = '0';
if(params.order_id) info.create_time = (Date.parse(new Date())/1000);
info.update_time = (Date.parse(new Date())/1000);
resolve(info);
});
// 返回一个新的 `Promise` 对象,在其内部进行参数验证和信息整理逻辑,通过 `resolve` 和 `reject` 来控制 `Promise` 的状态(成功或失败)。
return new Promise(function (resolve, reject) {
// 创建一个空对象 `info`,用于存储经过整理和验证后的订单相关信息,后续会根据传入的参数情况,将符合要求的信息添加到这个对象中。
var info = {};
// 如果传入的参数中包含 `order_id`,则将其直接添加到 `info` 对象中,`order_id` 可能用于表示已存在的订单的唯一标识,后续操作可能会基于此判断是更新还是创建新订单等情况。
if (params.order_id) info.order_id = params.order_id;
// 如果传入的参数中不包含 `order_id`,则进行以下额外的参数验证和信息补充操作,意味着可能是要创建一个新订单,所以需要更多必要参数的验证。
if (!params.order_id) {
// 首先验证用户ID`user_id`)是否存在,如果不存在则直接通过 `reject` 拒绝这个 `Promise`并返回错误信息表示用户ID不能为空因为创建订单通常需要关联用户信息用户ID是关键标识之一。
if (!params.user_id) return reject("用户ID不能为空");
// 进一步验证用户ID是否可以转换为数字类型如果不能转换成功即不是有效的数字则通过 `reject` 拒绝 `Promise`并返回错误信息表示用户ID必须是数字以确保能准确在数据库中关联到对应的用户记录等操作。
if (isNaN(parseInt(params.user_id))) return reject("用户ID必须是数字");
// 如果用户ID验证通过则将其添加到 `info` 对象中,作为新订单关联的用户标识信息。
info.user_id = params.user_id;
}
// 如果没有传入 `order_id`,意味着创建新订单,此时生成一个唯一的订单编号(格式为 `"itcast-"` 加上通过 `uniqid` 库生成的唯一标识符),并添加到 `info` 对象中作为订单的编号信息。
if (!params.order_id) info.order_number = "itcast-" + uniqid();
// 验证订单价格(`order_price`)是否存在,如果不存在则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示订单价格不能为空,因为订单价格是订单的重要属性之一,不可或缺。
if (!params.order_price) return reject("订单价格不能为空");
// 进一步验证订单价格是否可以转换为数字类型(这里使用 `parseFloat` 是因为价格可能包含小数部分),如果不能转换成功则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示订单价格必须为数字,以保证数据的合法性和符合数据库存储要求。
if (isNaN(parseFloat(params.order_price))) return reject("订单价格必须为数字");
// 如果订单价格验证通过,则将其添加到 `info` 对象中,作为订单的价格信息。
info.order_price = params.order_price;
// 如果传入了 `order_pay` 参数,则将其值直接添加到 `info` 对象中,用于表示订单的支付情况等相关信息;如果没有传入,则默认设置为 `'0'`,表示未支付或初始支付状态,具体含义由业务逻辑决定。
if (params.order_pay) {
info.order_pay = params.order_pay;
} else {
info.order_pay = '0';
}
// 根据传入的 `is_send` 参数来设置订单的发货状态信息,如果 `is_send` 参数为 `1`,则将发货状态设置为 `'是'`;如果为其他值(包括未传入该参数的情况),则默认设置为 `'否'`,同样具体的状态表示和业务含义由业务逻辑决定。
if (params.is_send) {
if (params.is_send == 1) {
info.is_send = '是';
} else {
info.is_send = '否';
}
} else {
info.is_send = '否';
}
// 根据传入的 `trade_no` 参数来设置交易编号相关信息,如果传入了该参数则设置为 `'否'`(这里设置的值看起来有点奇怪,可能需要根据实际业务逻辑进一步确认是否正确),如果没有传入则设置为空字符串,可能后续会根据实际交易情况进行更新等操作。
if (params.trade_no) {
info.trade_no = '否';
} else {
info.trade_no = '';
}
// 验证发票抬头(`order_fapiao_title`)相关信息,如果传入了该参数,则进行进一步验证,判断其值是否为 `'个人'` 或 `'公司'`,如果不是则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示发票抬头必须是 `'个人'` 或 `'公司'`
// 如果验证通过或者没有传入该参数(则默认设置为 `'个人'`),则将其添加到 `info` 对象中,作为订单的发票抬头信息。
if (params.order_fapiao_title) {
if (params.order_fapiao_title!= '个人' && params.order_fapiao_title!= '公司')
return reject("发票抬头必须是 个人 或 公司");
info.order_fapiao_title = params.order_fapiao_title;
} else {
info.order_fapiao_title = "个人";
}
// 如果传入了 `order_fapiao_company` 参数,则将其值添加到 `info` 对象中,用于存储发票对应的公司信息(如果有);如果没有传入则设置为空字符串,可能表示没有对应的公司信息或者留空待后续补充等情况。
if (params.order_fapiao_company) {
info.order_fapiao_company = params.order_fapiao_company;
} else {
info.order_fapiao_company = "";
}
// 如果传入了 `order_fapiao_content` 参数,则将其值添加到 `info` 对象中,用于存储发票内容相关信息;如果没有传入则设置为空字符串,可能表示没有特定的发票内容或者留空待填写等情况。
if (params.order_fapiao_content) {
info.order_fapiao_content = params.order_fapiao_content;
} else {
info.order_fapiao_content = "";
}
// 如果传入了 `consignee_addr` 参数,则将其值添加到 `info` 对象中,用于存储收件人地址信息;如果没有传入则设置为空字符串,可能表示没有填写收件人地址或者留空待补充等情况。
if (params.consignee_addr) {
info.consignee_addr = params.consignee_addr;
} else {
info.consignee_addr = "";
}
// 如果传入了 `goods` 参数(可能是订单商品相关信息,例如商品列表等内容),则将其直接添加到 `info` 对象中,后续在创建订单等操作中可能会进一步处理这些商品信息。
if (params.goods) {
info.goods = params.goods;
}
// 设置订单的支付状态初始值为 `'0'`,表示未支付或默认支付状态,具体含义由业务逻辑决定,后续可能会根据实际支付情况进行更新。
info.pay_status = '0';
// 如果传入了 `order_id`,意味着可能是更新订单操作,此时设置订单的创建时间为当前时间(通过获取当前日期时间并转换为时间戳,再除以 `1000`,可能是为了符合数据库存储的时间格式要求等情况),并添加到 `info` 对象中。
if (params.order_id) info.create_time = (Date.parse(new Date()) / 1000);
// 设置订单的更新时间为当前时间(同样进行时间戳转换操作),添加到 `info` 对象中,用于记录订单信息最后更新的时间点,方便后续查询、统计等业务操作使用。
info.update_time = (Date.parse(new Date()) / 1000);
// 如果所有参数验证和信息整理都顺利完成,则通过 `resolve` 方法将整理好的 `info` 对象传递出去,使得 `Promise` 状态变为已完成(成功),后续可以通过 `.then` 方法获取并使用这个 `info` 对象进行后续操作。
resolve(info);
});
}
// 定义 `doCreateOrder` 函数,用于在数据库中创建新的订单记录,接收经过验证和整理后的订单信息(`info`),以 `Promise` 的形式返回创建订单操作的结果(成功则包含创建后的订单相关信息,失败则返回错误信息)。
function doCreateOrder(info) {
return new Promise(function(resolve,reject) {
dao.create("OrderModel",_.clone(info),function(err,newOrder){
if(err) return reject("创建订单失败");
info.order = newOrder;
resolve(info);
});
});
// 返回一个新的 `Promise` 对象,在其内部执行创建订单的数据库操作,并通过 `resolve` 和 `reject` 控制 `Promise` 的状态。
return new Promise(function (resolve, reject) {
// 调用 `dao` 模块的 `create` 方法来执行创建订单的数据库操作,第一个参数 `"OrderModel"` 表示要操作的数据模型(对应数据库中的订单数据表),
// 第二个参数使用 `_.clone(info)` 通过 `lodash` 库的克隆函数对传入的 `info` 对象进行克隆,避免在数据库操作过程中对原始数据造成意外修改,然后将克隆后的数据作为要插入数据库的订单信息,
// 第三个参数是一个回调函数,用于处理数据库插入操作完成后的结果情况,根据操作是否成功返回相应的信息给 `Promise` 的 `resolve` 或 `reject`。
dao.create("OrderModel", _.clone(info), function (err, newOrder) {
// 如果在创建订单的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库插入语句执行失败、违反数据约束等原因,则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示创建订单失败,让调用者知晓操作未成功及原因。
if (err) return reject("创建订单失败");
// 如果订单创建成功,将创建后的订单对象(`newOrder`)添加到传入的 `info` 对象的 `order` 属性中(这样可以将订单相关的更多信息整合在一起方便后续操作),然后通过 `resolve` 方法将包含订单信息的 `info` 对象传递出去,
// 使得 `Promise` 状态变为已完成(成功),后续可以通过 `.then` 方法获取并使用这个包含订单详细信息的 `info` 对象进行进一步操作,比如添加订单商品等操作。
info.order = newOrder;
resolve(info);
});
});
}
// 定义 `doCreateOrderGood` 函数,用于在数据库中创建订单商品记录,接收订单商品相关信息(`orderGood`),以 `Promise` 的形式返回创建订单商品操作的结果(成功则返回创建后的订单商品对象,失败则返回错误信息)。
function doCreateOrderGood(orderGood) {
return new Promise(function(resolve,reject) {
dao.create("OrderGoodModel",orderGood,function(err,newOrderGood){
if(err) return reject("创建订单商品失败");
resolve(newOrderGood);
});
});
}
// 返回一个新的 `Promise` 对象,在其内部执行创建订单商品的数据库操作,并通过 `resolve` 和 `reject` 控制 `Promise` 的状态。
return new Promise(function (resolve, reject) {
// 调用 `dao` 模块的 `create` 方法来执行创建订单商品的数据库操作,第一个参数 `"OrderGoodModel"` 表示要操作的数据模型(对应数据库中的订单商品数据表),
// 第二个参数直接传入 `orderGood` 对象,它包含了要插入数据库的订单商品相关信息,比如商品名称、价格等信息,第三个参数是一个回调函数,用于处理数据库插入操作完成后的结果情况,根据操作是否成功返回相应的信息给 `Promise` 的 `resolve` 或 `reject`。
dao.create("OrderGoodModel", orderGood, function (err, newOrderGood) {
// 如果在创建订单商品的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库插入语句执行失败、违反数据约束等原因,则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示创建订单商品失败,让调用者知晓操作未成功及原因。
if (err) return reject("创建订单商品失败");
// 如果订单商品创建成功,则通过 `resolve` 方法将创建后的订单商品对象(`newOrderGood`)传递出去,使得 `Promise` 状态变为已完成(成功),后续可以通过 `.then` 方法获取并使用这个对象进行进一步操作,比如关联到对应的订单等操作。
resolve(newOrderGood);
});
});
}
// 定义 `doAddOrderGoods` 函数,用于将多个订单商品信息添加到对应的订单中,接收包含订单和商品信息的对象(`info`),以 `Promise` 的形式返回添加商品操作完成后的结果(成功则返回包含完整订单及商品信息的对象,失败则返回错误信息)。
function doAddOrderGoods(info) {
return new Promise(function(resolve,reject) {
if(!info.order) return reject("订单对象未创建");
var orderGoods = info.goods;
if(orderGoods && orderGoods.length > 0) {
var fns = [];
var goods_total_price = _.sum(_.map(orderGoods,"goods_price"));
_(orderGoods).forEach(function(orderGood){
orderGood.order_id = info.order.order_id;
orderGood.goods_total_price = goods_total_price;
fns.push(doCreateOrderGood(orderGood));
});
Promise.all(fns)
.then(function(results){
info.order.goods = results;
resolve(info);
})
.catch(function(error){
if(error) return reject(error);
});
} else {
resolve(info);
}
});
// 返回一个新的 `Promise` 对象,在其内部执行添加订单商品到订单的相关逻辑,并通过 `resolve` 和 `reject` 控制 `Promise` 的状态。
return new Promise(function (resolve, reject) {
// 首先验证传入的 `info` 对象中是否包含已创建的订单对象(`order` 属性),如果不存在则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示订单对象未创建,因为后续操作需要基于已存在的订单来添加商品信息,所以订单对象必须存在。
if (!info.order) return reject("订单对象未创建");
// 获取传入的 `info` 对象中的商品信息(`goods` 属性),它可能是一个包含多个订单商品对象的数组,每个对象包含商品的具体信息,比如商品价格、数量等,后续会遍历这个数组来逐个创建订单商品记录并关联到订单上。
var orderGoods = info.goods;
// 如果存在订单商品信息(即 `orderGoods` 不为空且长度大于 `0`),则进行以下添加订单商品的操作。
if (orderGoods && orderGoods.length > 0) {
// 创建一个空数组 `fns`,用于存储多个创建订单商品的异步操作函数(每个函数返回一个 `Promise`),后续会使用 `Promise.all` 来并行执行这些异步操作,提高效率。
var fns = [];
// 使用 `lodash` 的 `sum` 函数和 `map` 函数计算所有订单商品的总价格,`_.map` 函数先从每个订单商品对象中提取 `goods_price` 字段的值形成一个新的价格数组,然后 `_.sum` 函数对这个价格数组进行求和操作,得到商品总价格,方便后续记录和使用。
var goods_total_price = _.sum(_.map(orderGoods, "goods_price"));
// 使用 `lodash` 的 `forEach` 函数遍历订单商品数组 `orderGoods`,对于每个订单商品对象(`orderGood`)进行以下操作,将商品关联到对应的订单上并准备创建商品记录。
_(orderGoods).forEach(function (orderGood) {
// 将当前订单商品对象的 `order_id` 属性设置为对应的订单的 `order_id`(从 `info.order.order_id` 获取),这样建立起订单商品与订单的关联关系,表明该商品属于哪个订单。
orderGood.order_id = info.order.order_id;
// 将当前订单商品对象的 `goods_total_price` 属性设置为前面计算好的商品总价格,可能用于记录该订单下所有商品的总价等相关业务用途,具体含义由业务逻辑决定。
orderGood.goods_total_price = goods_total_price;
// 将创建当前订单商品记录的异步操作函数(通过调用 `doCreateOrderGood` 函数返回的 `Promise`)添加到 `fns` 数组中,准备后续并行执行这些创建操作。
fns.push(doCreateOrderGood(orderGood));
});
// 使用 `Promise.all` 函数并行执行 `fns` 数组中所有的创建订单商品的异步操作
// 以下是 `doAddOrderGoods` 函数剩余部分的注释
// `Promise.all` 会并行执行 `fns` 数组中的所有异步操作(即创建各个订单商品记录的 `Promise`),当所有异步操作都成功完成后,
// 会执行 `.then` 回调函数中的逻辑,将创建订单商品操作返回的结果数组(`results`,每个元素对应一个创建成功的订单商品对象)
// 设置为 `info.order` 对象的 `goods` 属性值,这样就将创建好的订单商品与对应的订单关联起来了,然后通过 `resolve` 方法将包含完整订单及商品信息的 `info` 对象传递出去,
// 使得 `Promise` 状态变为已完成(成功),表示添加订单商品到订单的操作成功完成,后续可以通过 `.then` 方法获取并使用这个 `info` 对象进行进一步操作。
Promise.all(fns)
.then(function (results) {
info.order.goods = results;
resolve(info);
})
// 如果在并行执行创建订单商品的异步操作过程中,有任何一个操作出现错误(例如某个商品记录创建失败),则会进入 `.catch` 回调函数,
// 这里直接将错误信息通过 `reject` 拒绝 `Promise`,并将错误信息返回给调用者,告知调用者添加订单商品操作出现问题及具体的错误原因。
.catch(function (error) {
if (error) return reject(error);
});
// 如果没有订单商品信息(即 `orderGoods` 为空或长度为0说明不需要添加订单商品直接通过 `resolve` 方法将传入的 `info` 对象传递出去,
// 表示添加订单商品操作顺利完成(因为本身就没有商品需要添加),`Promise` 状态变为已完成(成功),后续可以继续进行其他相关操作。
} else {
resolve(info);
}
});
}
// 定义 `doGetAllOrderGoods` 函数,用于获取指定订单的所有商品信息,接收包含订单相关信息的对象(`info`),以 `Promise` 的形式返回获取操作的结果(成功则返回包含订单及商品列表信息的对象,失败则返回错误信息)。
function doGetAllOrderGoods(info) {
return new Promise(function(resolve,reject) {
if(!info.order) return reject("订单对象未创建");
dao.list("OrderGoodModel",{"columns":{"order_id":info.order.order_id}},function(err,orderGoods){
if(err) return reject("获取订单商品列表失败");
info.order.goods = orderGoods;
resolve(info);
})
});
return new Promise(function (resolve, reject) {
// 首先验证传入的 `info` 对象中是否包含已创建的订单对象(`order` 属性),如果不存在则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示订单对象未创建,
// 因为获取订单商品信息需要基于已存在的订单来查询对应的商品记录,所以订单对象必须存在才能进行后续操作。
if (!info.order) return reject("订单对象未创建");
// 调用 `dao` 模块的 `list` 方法来获取指定订单的商品信息,第一个参数 `"OrderGoodModel"` 表示要操作的数据模型(对应数据库中的订单商品数据表),
// 第二个参数是一个对象,用于指定查询条件,这里通过 `{"columns":{"order_id":info.order.order_id}}` 设置只查询 `order_id` 与传入的订单对象的 `order_id` 匹配的商品记录,
// 即获取指定订单下的所有商品信息,第三个参数是一个回调函数,用于处理查询操作完成后的结果情况,根据操作是否成功返回相应的信息给 `Promise` 的 `resolve` 或 `reject`。
dao.list("OrderGoodModel", { "columns": { "order_id": info.order.order_id } }, function (err, orderGoods) {
// 如果在获取订单商品列表的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库查询语句执行失败、连接问题等原因,则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示获取订单商品列表失败,让调用者知晓操作未成功及原因。
if (err) return reject("获取订单商品列表失败");
// 如果查询成功,将获取到的订单商品列表(`orderGoods`,是一个包含多个订单商品对象的数组)设置为 `info.order` 对象的 `goods` 属性值,这样就将获取到的商品信息关联到对应的订单上了,
// 然后通过 `resolve` 方法将包含完整订单及商品信息的 `info` 对象传递出去,使得 `Promise` 状态变为已完成(成功),后续可以通过 `.then` 方法获取并使用这个 `info` 对象进行进一步操作,比如展示订单详情等操作。
info.order.goods = orderGoods;
resolve(info);
})
});
}
// 定义 `doGetOrder` 函数用于获取指定订单的详细信息接收包含订单ID相关信息的对象`info`),以 `Promise` 的形式返回获取操作的结果(成功则返回包含订单详细信息的对象,失败则返回错误信息)。
function doGetOrder(info) {
return new Promise(function(resolve,reject) {
dao.show("OrderModel",info.order_id,function(err,newOrder){
if(err) return reject("获取订单详情失败");
if(!newOrder) return reject("订单ID不能存在");
info.order = newOrder;
resolve(info);
})
});
return new Promise(function (resolve, reject) {
// 调用 `dao` 模块的 `show` 方法来获取指定订单的详细信息,第一个参数 `"OrderModel"` 表示要操作的数据模型(对应数据库中的订单数据表),
// 第二个参数传入 `info.order_id`,作为查询条件,用于查找数据库中对应 `order_id` 的订单记录,获取其详细信息,第三个参数是一个回调函数,用于处理查询操作完成后的结果情况,根据操作是否成功返回相应的信息给 `Promise` 的 `resolve` 或 `reject`。
dao.show("OrderModel", info.order_id, function (err, newOrder) {
// 如果在获取订单详情的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库查询语句执行失败、连接问题等原因,则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示获取订单详情失败,让调用者知晓操作未成功及原因。
if (err) return reject("获取订单详情失败");
// 如果查询结果中没有获取到对应的订单(`newOrder` 为 `null`),则通过 `reject` 拒绝 `Promise`并返回错误信息表示订单ID不存在因为没有找到对应订单记录说明传入的订单ID可能有误或者该订单不存在告知调用者操作出现问题及原因。
if (!newOrder) return reject("订单ID不能存在");
// 如果成功获取到订单详情信息,将获取到的订单对象(`newOrder`)设置为 `info.order` 属性值,这样就将获取到的详细订单信息整合到传入的 `info` 对象中了,
// 然后通过 `resolve` 方法将包含订单详细信息的 `info` 对象传递出去,使得 `Promise` 状态变为已完成(成功),后续可以通过 `.then` 方法获取并使用这个 `info` 对象进行进一步操作,比如添加商品、更新订单等操作。
info.order = newOrder;
resolve(info);
})
});
}
// 定义 `doUpdateOrder` 函数,用于更新指定订单的信息,接收包含订单相关信息的对象(`info`),以 `Promise` 的形式返回更新操作的结果(成功则返回包含更新后订单详细信息的对象,失败则返回错误信息)。
function doUpdateOrder(info) {
return new Promise(function(resolve,reject) {
dao.update("OrderModel",info.order_id,_.clone(info),function(err,newOrder){
if(err) return reject("更新失败");
info.order = newOrder;
resolve(info);
});
});
}
module.exports.createOrder = function(params,cb) {
doCheckOrderParams(params)
.then(doCreateOrder)
.then(doAddOrderGoods)
.then(function(info) {
cb(null,info.order);
})
.catch(function(err) {
cb(err);
});
return new Promise(function (resolve, reject) {
// 调用 `dao` 模块的 `update` 方法来执行更新订单信息的数据库操作,第一个参数 `"OrderModel"` 表示要操作的数据模型(对应数据库中的订单数据表),
// 第二个参数传入 `info.order_id`,用于准确找到数据库中要更新的订单记录,第三个参数使用 `_.clone(info)` 通过 `lodash` 库的克隆函数对传入的 `info` 对象进行克隆,避免在数据库操作过程中对原始数据造成意外修改,然后将克隆后的数据作为要更新的订单信息,
// 第四个参数是一个回调函数,用于处理更新操作完成后的结果情况,根据操作是否成功返回相应的信息给 `Promise` 的 `resolve` 或 `reject`。
dao.update("OrderModel", info.order_id, _.clone(info), function (err, newOrder) {
// 如果在更新订单信息的数据库操作过程中出现错误(`err` 不为 `null`),比如数据库更新语句执行失败、违反数据约束等原因,则通过 `reject` 拒绝 `Promise`,并返回错误信息,表示更新失败,让调用者知晓操作未成功及原因。
if (err) return reject("更新失败");
// 如果订单信息更新成功,将更新后的订单对象(`newOrder`)设置为 `info.order` 属性值,这样就将更新后的订单详细信息整合到传入的 `info` 对象中了,
// 然后通过 `resolve` 方法将包含更新后订单详细信息的 `info` 对象传递出去,使得 `Promise` 状态变为已完成(成功),后续可以通过 `.then` 方法获取并使用这个 `info` 对象进行进一步操作,比如获取更新后的订单商品信息等操作。
info.order = newOrder;
resolve(info);
});
});
}
// 对外暴露 `createOrder` 函数,用于创建新的订单,接收订单相关参数(`params`)和一个回调函数(`cb`),在内部通过一系列异步操作(参数验证、创建订单、添加订单商品等)来完成订单创建流程,
// 最后通过回调函数将创建成功后的订单信息返回给调用者,若在创建过程中出现错误则通过回调函数返回相应的错误信息。
module.exports.createOrder = function (params, cb) {
// 首先调用 `doCheckOrderParams` 函数对传入的订单参数进行合法性检查和预处理,该函数返回一个 `Promise`,如果参数验证通过则会传递处理好的订单信息,否则会返回错误信息拒绝 `Promise`。
doCheckOrderParams(params)
// 使用 `.then` 方法链式调用 `doCreateOrder` 函数,当 `doCheckOrderParams` 成功完成
// 链式调用 `doCreateOrder` 函数,在 `doCheckOrderParams` 函数对订单参数验证和预处理成功后(即 `Promise` 被成功 `resolve`
// 会将处理好的订单信息作为参数传递给 `doCreateOrder` 函数,用于执行创建订单的数据库操作。
.then(doCreateOrder)
// 继续链式调用 `doAddOrderGoods` 函数,当 `doCreateOrder` 函数成功创建订单(其返回的 `Promise` 被成功 `resolve`)后,
// 会将包含创建好的订单信息的对象传递给 `doAddOrderGoods` 函数,以便执行添加订单商品的相关操作,将商品与订单进行关联并创建商品记录等操作。
.then(doAddOrderGoods)
// 当 `doAddOrderGoods` 函数执行完成且操作成功(返回的 `Promise` 被成功 `resolve`)后,会进入这个 `.then` 回调函数,
// 此时参数 `info` 包含了完整的订单及商品相关信息,通过回调函数 `cb` 将最终的订单对象(`info.order`)返回给调用者,
// 表示订单创建流程全部成功完成,调用者可以获取订单详细信息进行后续的业务操作,比如展示订单详情、进行订单状态更新等操作。
.then(function (info) {
cb(null, info.order);
})
// 如果在整个 `doCheckOrderParams` -> `doCreateOrder` -> `doAddOrderGoods` 的链式异步操作过程中,任何一个环节出现错误(即 `Promise` 被 `reject`
// 都会进入这个 `.catch` 回调函数,直接将错误信息通过回调函数 `cb` 返回给调用者,告知调用者订单创建过程出现问题以及具体的错误原因,方便调用者进行相应的错误处理和提示给用户等操作。
.catch(function (err) {
cb(err);
});
}
module.exports.getAllOrders = function(params,cb){
var conditions = {};
if(!params.pagenum || params.pagenum <= 0) return cb("pagenum 参数错误");
if(!params.pagesize || params.pagesize <= 0) return cb("pagesize 参数错误");
conditions["columns"] = {};
if(params.user_id) {
conditions["columns"]["user_id"] = params.user_id;
}
if(params.pay_status) {
conditions["columns"]["pay_status"] = params.pay_status;
}
if(params.is_send) {
if(params.is_send == 1) {
conditions["columns"]["is_send"] = '是';
} else {
conditions["columns"]["is_send"] = '否';
}
}
if(params.order_fapiao_title) {
if(params.order_fapiao_title == 1) {
conditions["columns"]["order_fapiao_title"] = '个人';
} else {
conditions["columns"]["order_fapiao_title"] = '公司';
}
}
if(params.order_fapiao_company) {
conditions["columns"]["order_fapiao_company"] = orm.like("%" + params.order_fapiao_company + "%");
}
if(params.order_fapiao_content) {
conditions["columns"]["order_fapiao_content"] = orm.like("%" + params.order_fapiao_content + "%");
}
if(params.consignee_addr) {
conditions["columns"]["consignee_addr"] = orm.like("%" + params.consignee_addr + "%");
}
dao.countByConditions("OrderModel",conditions,function(err,count){
if(err) return cb(err);
pagesize = params.pagesize;
pagenum = params.pagenum;
pageCount = Math.ceil(count / pagesize);
offset = (pagenum - 1) * pagesize;
if(offset >= count) {
offset = count;
}
limit = pagesize;
// 构建条件
conditions["offset"] = offset;
conditions["limit"] = limit;
// conditions["only"] =
conditions["order"] = "-create_time";
dao.list("OrderModel",conditions,function(err,orders){
if(err) return cb(err);
var resultDta = {};
resultDta["total"] = count;
resultDta["pagenum"] = pagenum;
resultDta["goods"] = _.map(orders,function(order){
return order;//_.omit(order,);
});
cb(err,resultDta);
})
});
// 对外暴露 `getAllOrders` 函数,用于获取满足特定条件的所有订单信息,接收查询相关参数(`params`)和一个回调函数(`cb`
// 通过构建查询条件、分页处理等操作从数据库中获取订单数据,并将结果和相关统计信息通过回调函数返回给调用者,若操作过程中出现错误则返回相应错误信息。
module.exports.getAllOrders = function (params, cb) {
// 创建一个空对象 `conditions`,用于存储后续构建的数据库查询条件,这些条件将用于筛选出符合要求的订单记录。
var conditions = {};
// 验证传入的 `params.pagenum` 参数是否存在且大于 `0``pagenum` 通常表示当前页码,用于分页查询操作。
// 如果不存在或者小于等于 `0`,则不符合分页查询的基本要求,直接通过回调函数 `cb` 返回错误信息,表示 `pagenum` 参数错误,告知调用者参数不符合要求。
if (!params.pagenum || params.pagenum <= 0) return cb("pagenum 参数错误");
// 同样验证传入的 `params.pagesize` 参数是否存在且大于 `0``pagesize` 通常表示每页显示的记录数,也是分页查询的关键参数之一。
// 如果不存在或者小于等于 `0`,则不符合分页查询的要求,通过回调函数 `cb` 返回错误信息,表示 `pagesize` 参数错误,告知调用者参数不符合要求。
if (!params.pagesize || params.pagesize <= 0) return cb("pagesize 参数错误");
// 在 `conditions` 对象中初始化 `columns` 属性为一个空对象,`columns` 属性用于存放具体的查询条件字段和对应的值,
// 这些条件将构成数据库查询语句中的 `WHERE` 子句部分,用于精确筛选出需要的订单记录。
conditions["columns"] = {};
// 如果传入的参数中包含 `user_id`表示调用者希望根据用户ID来筛选订单将 `user_id` 及其对应的值添加到 `conditions["columns"]` 对象中,
// 这样在数据库查询时就只会获取该用户ID对应的订单记录方便按用户维度查询订单信息具体业务含义取决于系统的用户与订单关联设计。
if (params.user_id) {
conditions["columns"]["user_id"] = params.user_id;
}
// 如果传入的参数中包含 `pay_status`,表示调用者希望根据订单的支付状态来筛选订单,将 `pay_status` 及其对应的值添加到 `conditions["columns"]` 对象中,
// 使得数据库查询只返回支付状态符合该条件的订单记录,例如可以查询已支付、未支付等不同支付状态的订单,具体支付状态的表示和业务逻辑由系统定义。
if (params.pay_status) {
conditions["columns"]["pay_status"] = params.pay_status;
}
// 根据传入的 `is_send` 参数来设置查询条件中的发货状态相关信息,用于筛选出发货状态符合要求的订单记录。
// 如果 `is_send` 参数为 `1`,则将 `conditions["columns"]["is_send"]` 设置为 `'是'`,表示查询已发货的订单;
// 如果为其他值(包括未传入该参数的情况),则默认设置为 `'否'`,表示查询未发货的订单,具体发货状态的表示和业务含义由业务逻辑决定。
if (params.is_send) {
if (params.is_send == 1) {
conditions["columns"]["is_send"] = '是';
} else {
conditions["columns"]["is_send"] = '否';
}
}
// 根据传入的 `order_fapiao_title` 参数来设置查询条件中的发票抬头相关信息,用于筛选出发票抬头符合要求的订单记录。
// 如果 `order_fapiao_title` 参数为 `1`,则将 `conditions["columns"]["order_fapiao_title"]` 设置为 `'个人'`
// 如果为其他值(通常应该是对应 `'公司'` 的标识,具体由业务逻辑确定),则设置为 `'公司'`,以此来区分不同发票抬头类型的订单,满足按发票抬头查询订单的业务需求。
if (params.order_fapiao_title) {
if (params.order_fapiao_title == 1) {
conditions["columns"]["order_fapiao_title"] = '个人';
} else {
conditions["columns"]["order_fapiao_title"] = '公司';
}
}
// 如果传入的参数中包含 `order_fapiao_company`,则使用 `orm` 库提供的 `like` 方法构建模糊查询条件,
// 将 `order_fapiao_company` 及其对应的值(通过 `%` 包裹传入值,表示匹配包含该值的任意字符串)添加到 `conditions["columns"]` 对象中,
// 这样可以查询发票对应的公司名称包含指定内容的订单记录,方便在不完全知道公司全称等情况下进行模糊筛选,满足根据发票公司相关信息查找订单的业务场景。
if (params.order_fapiao_company) {
conditions["columns"]["order_fapiao_company"] = orm.like("%" + params.order_fapiao_company + "%");
}
// 如果传入的参数中包含 `order_fapiao_content`,同样使用 `orm` 库的 `like` 方法构建模糊查询条件,
// 将 `order_fapiao_content` 及其对应的值(用 `%` 包裹传入值构建模糊匹配模式)添加到 `conditions["columns"]` 对象中,
// 以便查询发票内容包含指定内容的订单记录,满足按发票内容部分信息来查找订单的业务需求,例如查找包含特定服务或商品描述的发票对应的订单。
if (params.order_fapiao_content) {
conditions["columns"]["order_fapiao_content"] = orm.like("%" + params.order_fapiao_content + "%");
}
// 如果传入的参数中包含 `consignee_addr`,使用 `orm` 库的 `like` 方法构建模糊查询条件,
// 将 `consignee_addr` 及其对应的值(用 `%` 包裹传入值形成模糊匹配模式)添加到 `conditions["columns"]` 对象中,
// 这样就能查询收件人地址包含指定内容的订单记录,方便在只记得部分地址信息等情况下筛选订单,满足按收件人地址部分内容查找订单的业务场景。
if (params.consignee_addr) {
conditions["columns"]["consignee_addr"] = orm.like("%" + params.consignee_addr + "%");
}
// 调用 `dao` 模块的 `countByConditions` 方法来统计满足前面构建的查询条件的订单记录总数,
// 第一个参数 `"OrderModel"` 表示要操作的数据模型,即对应数据库中的订单数据表,明确从哪个表中统计记录数量;
// 第二个参数传入 `conditions` 对象作为查询条件,告知数据库按照这些条件去筛选并统计符合要求的订单记录数量;
// 第三个参数是一个回调函数,用于处理统计操作完成后的结果情况,根据操作是否成功返回相应的信息给回调函数 `cb`,若成功则返回统计的记录总数,用于后续的分页计算等操作。
dao.countByConditions("OrderModel", conditions, function (err, count) {
// 如果在统计订单记录总数的过程中出现错误(`err` 不为 `null`),比如数据库查询语句执行失败、连接问题等原因,
// 则直接通过回调函数 `cb` 返回错误信息给调用者,表示操作出现问题及具体的错误原因,告知调用者无法获取订单总数进行分页操作。
if (err) return cb(err);
// 获取传入的每页显示记录数参数 `params.pagesize`,赋值给变量 `pagesize`,方便后续在分页计算等操作中使用该值,保持代码的可读性。
pagesize = params.pagesize;
// 获取传入的当前页码参数 `params.pagenum`,赋值给变量 `pagenum`,同样用于后续的分页相关计算和操作,使代码逻辑更清晰。
pagenum = params.pagenum;
// 计算总页数,通过将满足条件的订单记录总数(`count`)除以每页显示记录数(`pagesize`),然后向上取整(使用 `Math.ceil` 函数)得到总页数,
// 这个总页数用于判断分页情况以及限制页码范围等操作,确保分页查询的合理性和完整性。
pageCount = Math.ceil(count / pagesize);
// 计算分页查询的偏移量(`offset`),通过公式 `(当前页码 - 1) * 每页显示记录数` 来确定从哪条记录开始查询,
// 例如当前页码为 `1` 时,偏移量为 `0`,表示从第一条记录开始查询;页码为 `2` 时,偏移量为 `pagesize`,表示从第 `pagesize + 1` 条记录开始查询,以此类推。
offset = (pagenum - 1) * pagesize;
// 如果计算出的偏移量大于等于记录总数(`count`),说明传入的页码可能超出了合理范围(比如总共有 `100` 条记录,每页显示 `10` 条,传入页码 `11` 就会出现这种情况),
// 此时将偏移量设置为记录总数,避免查询出现错误,相当于查询最后一页(可能不满一页的情况)的数据,保证分页查询的健壮性。
if (offset >= count) {
offset = count;
}
// 获取每页显示记录数 `pagesize`,赋值给变量 `limit`,在后续构建数据库查询条件时用于指定每页获取的记录数量,确保分页查询按设定的每页数量返回数据。
limit = pagesize;
// 在 `conditions` 对象中添加 `offset` 属性,并将前面计算好的偏移量赋值给它,用于告知数据库查询从哪条记录开始获取,构建分页查询的偏移量条件,实现分页功能。
conditions["offset"] = offset;
// 在 `conditions` 对象中添加 `limit` 属性,并将每页显示记录数(`limit`)赋值给它,用于告知数据库每次查询获取的记录数量上限,与 `offset` 配合实现分页查询,获取指定页的数据。
conditions["limit"] = limit;
// 这里原本可能是要设置 `conditions["only"]` 的相关内容(可能用于指定只查询某些特定字段等操作,但代码中未完整实现),暂时保留注释状态,可能后续需要根据业务需求补充完善。
// conditions["only"] =
// 在 `conditions` 对象中添加 `order` 属性,并设置值为 `"-create_time"`,用于指定数据库查询结果的排序方式,
// 这里表示按照订单创建时间倒序排列(`-` 号表示倒序,`create_time` 为订单创建时间字段),使得最新创建的订单排在前面,方便展示最新的数据等业务场景使用。
conditions["order"] = "-create_time";
// 调用 `dao` 模块的 `list` 方法来执行实际的数据库查询操作,获取满足前面构建的所有条件(包括筛选条件、分页条件、排序条件等)的订单记录列表,
// 第一个参数 `"OrderModel"` 明确要操作的数据模型,即从订单数据表中查询数据;
// 第二个参数传入 `conditions` 对象,包含了完整的查询条件信息,告知数据库如何筛选、分页以及排序数据;
// 第三个参数是一个回调函数,用于处理查询操作完成后的结果情况,根据操作是否成功返回相应的信息给回调函数 `cb`,若成功则返回查询到的订单记录列表以及相关统计信息,供调用者进行后续的业务处理。
dao.list("OrderModel", conditions, function (err, orders) {
// 如果在查询订单记录列表的过程中出现错误(`err` 不为 `null`),比如数据库查询语句执行失败、连接问题等原因,
// 则直接通过回调函数 `cb` 返回错误信息给调用者,表示操作出现问题及具体的错误原因,告知调用者无法获取订单列表数据。
if (err) return cb(err);
// 创建一个空对象 `resultDta`,用于存储最终要返回给调用者的结果信息,包含订单记录总数、当前页码以及订单记录列表等内容,方便调用者统一获取和处理查询结果。
var resultDta = {};
// 将前面统计得到的满足条件的订单记录总数(`count`)赋值给 `resultDta` 对象的 `total` 属性,方便调用者获取总的订单数量信息,例如用于展示分页导航中的总记录数等功能。
resultDta["total"] = count;
// 将传入的当前页码参数(`params.pagenum`)赋值给 `resultDta` 对象的 `pagenum` 属性,方便调用者知晓当前查询的是第几页数据,用于分页相关的展示和逻辑处理。
resultDta["pagenum"] = pagenum;
// 使用 `lodash` 库的 `map` 函数遍历查询到的订单记录列表(`orders`),对每个订单记录(`order`)进行处理,
// 这里暂时只是直接返回每个订单记录(后续可能可以根据业务需求进一步处理订单记录,比如省略某些敏感字段等,代码中 `_.omit(order,)` 可能就是预留的这种处理方式但未完整实现),
// 将处理后的订单记录数组赋值给 `resultDta` 对象的 `goods` 属性(这里 `goods` 命名可能不太准确,更合适的可能是 `orders` 之类的表示订单列表的名称,具体要根据业务逻辑确定),方便调用者获取具体的订单记录数据进行展示、分析等操作。
resultDta["goods"] = _.map(orders, function (order) {
return order; // _.omit(order,);
});
// 将包含订单记录总数、当前页码以及订单记录列表等完整信息的 `resultDta` 对象通过回调函数 `cb` 返回给调用者,
// 表示查询操作成功完成,调用者可以根据这些信息进行后续的业务处理,比如在前端页面展示订单列表、进行分页导航等操作。
cb(err, resultDta);
})
});
}
module.exports.getOrder = function(orderId,cb) {
if(!orderId) return cb("用户ID不能为空");
if(isNaN(parseInt(orderId))) return cb("用户ID必须是数字");
doGetOrder({"order_id":orderId})
.then(doGetAllOrderGoods)
.then(function(info){
cb(null,info.order);
})
.catch(function(err) {
cb(err);
});
// 对外暴露 `getOrder` 函数用于获取指定订单的详细信息接收订单ID`orderId`)和一个回调函数(`cb`
// 通过一系列异步操作(先获取订单基本信息,再获取对应的订单商品信息)来整合完整的订单详情,最后通过回调函数返回给调用者,若出现错误则返回相应错误信息。
module.exports.getOrder = function (orderId, cb) {
// 首先验证传入的订单ID`orderId`)是否存在,如果不存在则通过回调函数 `cb` 返回错误信息表示用户ID不能为空
// 这里可能是表述上的小问题更准确应该是订单ID不能为空因为没有订单ID无法确定要获取哪个订单的详细信息告知调用者参数不符合要求。
if (!orderId) return cb("用户ID不能为空");
// 进一步验证订单ID是否可以转换为数字类型如果不能转换成功即不是有效的数字则通过回调函数 `cb` 返回错误信息表示用户ID必须是数字
// 因为通常在数据库中订单ID是以数字形式存储和使用的需要传入合法的数字类型的订单ID才能准确查询到对应的订单记录告知调用者参数不符合要求。
if (isNaN(parseInt(orderId))) return cb("用户ID必须是数字");
// 调用 `doGetOrder` 函数传入包含订单ID的对象`{"order_id":orderId}`),用于获取指定订单的基本信息,`doGetOrder` 函数返回一个 `Promise
// 将传入的 `orderId` 参数赋值给 `params` 对象中的 `order_id` 属性,这样 `params` 对象就包含了要更新的订单的标识信息,
// 后续在进行订单参数验证等操作时,可以基于这个完整的 `params` 对象来处理,确保更新操作针对正确的订单进行。
params["order_id"] = orderId;
// 调用 `doCheckOrderParams` 函数对包含了订单ID以及其他可能的更新参数在 `params` 对象中)进行合法性检查和预处理,
// 该函数返回一个 `Promise`,若参数验证通过会传递处理好的订单信息,若验证不通过则会返回相应的错误信息拒绝 `Promise`。
doCheckOrderParams(params)
// 使用 `.then` 方法链式调用 `doUpdateOrder` 函数,当 `doCheckOrderParams` 函数成功完成(即参数验证通过并整理好信息)后,
// 会将处理后的包含订单相关信息的对象传递给 `doUpdateOrder` 函数,由它执行更新订单信息的数据库操作,
// `doUpdateOrder` 函数同样返回一个 `Promise`,成功则包含更新后的订单详细信息,失败则返回错误信息。
.then(doUpdateOrder)
// 继续链式调用 `doGetAllOrderGoods` 函数,当 `doUpdateOrder` 成功更新订单信息后,会将包含更新后订单信息的对象传递给 `doGetAllOrderGoods` 函数,
// 由它执行获取该订单所有商品信息的操作,`doGetAllOrderGoods` 函数返回的 `Promise` 成功则返回包含完整订单及商品信息的对象,失败则返回错误信息。
.then(doGetAllOrderGoods)
// 当 `doGetAllOrderGoods` 函数执行完成且操作成功(返回的 `Promise` 被成功 `resolve`)后,会进入这个 `.then` 回调函数,
// 此时参数 `info` 包含了完整的更新后的订单及商品相关信息,通过回调函数 `cb` 将最终的订单对象(`info.order`)返回给调用者,
// 表示订单更新流程全部成功完成,调用者可以获取更新后的订单详细信息进行后续的业务操作,比如展示最新的订单详情、根据新的订单状态进行相应处理等操作。
.then(function (info) {
cb(null, info.order);
})
// 如果在整个 `doCheckOrderParams` -> `doUpdateOrder` -> `doGetAllOrderGoods` 的链式异步操作过程中,任何一个环节出现错误(即 `Promise` 被 `reject`
// 都会进入这个 `.catch` 回调函数,直接将错误信息通过回调函数 `cb` 返回给调用者,告知调用者订单更新过程出现问题以及具体的错误原因,方便调用者进行相应的错误处理和提示给用户等操作。
.catch(function (err) {
cb(err);
});
}
module.exports.updateOrder = function(orderId,params,cb) {
if(!orderId) return cb("用户ID不能为空");
if(isNaN(parseInt(orderId))) return cb("用户ID必须是数字");
params["order_id"] = orderId;
doCheckOrderParams(params)
.then(doUpdateOrder)
.then(doGetAllOrderGoods)
.then(function(info){
cb(null,info.order);
})
.catch(function(err) {
cb(err);
});
}
//这段代码整体实现了更新订单信息的功能逻辑,通过对传入参数的验证、订单信息更新以及获取更新后订
//单商品信息等一系列步骤,保证了订单更新操作的完整性和准确性,并且通过回调函数将最终结果或错误
//信息返回给调用者,方便在外部进行相应的业务处理和错误提示。

@ -1,121 +1,176 @@
// 引入lodash库它提供了很多实用的函数来方便地处理JavaScript中的数据例如对数组、对象进行操作等后续代码中会多次使用到它提供的相关功能。
var _ = require('lodash');
// 引入Node.js的path模块主要用于处理文件路径相关的操作像拼接、解析文件路径等这里用于准确地引入自定义的 `dao/DAO` 模块所在的文件位置,该模块大概率用于数据库操作相关的功能封装。
var path = require("path");
var dao = require(path.join(process.cwd(),"dao/DAO"));
// 引入自定义的 `DAO` 模块,通过拼接当前工作目录(`process.cwd()`)和相对路径的方式找到并引入该模块,这个模块应该封装了通用的数据访问操作方法,例如查询、插入、更新等操作,具体操作的数据表等信息会在调用相应方法时传入。
var dao = require(path.join(process.cwd(), "dao/DAO"));
// 定义 `reportOne` 函数,该函数主要用于获取并处理 `ReportOneModel` 相关的报表数据,最终将处理好的数据以特定格式通过回调函数返回给调用者。
function reportOne(cb) {
dao.list("ReportOneModel",null,function(err,result){
if(err) return cb("获取报表数据失败");
var areaKeyResult = {};
var areaKeys = _.union(_.map(result,"rp1_area"));
var dateKeys = _.union(_.map(result,function(record){
str = record["rp1_date"].getFullYear() + "-" + (record["rp1_date"].getMonth() + 1) + "-" + record["rp1_date"].getDate()
console.log(str);
return str;
}));
for(var idx in result) {
var record = result[idx];
var dateKey = record["rp1_date"].getFullYear() + "-" + (record["rp1_date"].getMonth() + 1) + "-" + record["rp1_date"].getDate();
if(!areaKeyResult[record["rp1_area"]]) {
areaKeyResult[record["rp1_area"]] = {};
}
areaKeyResult[record["rp1_area"]][dateKey] = record;
}
// 格式输出
var series = [];
_(areaKeys).forEach(function(areaKey){
var data = []
_(dateKeys).forEach(function(dateKey){
console.log("areaKey:" + areaKey + "," + "dateKey:" + dateKey);
if(areaKeyResult[areaKey][dateKey]) {
data.push(areaKeyResult[areaKey][dateKey]["rp1_user_count"]);
} else {
data.push(0);
}
})
series.push({
name:areaKey,
type:'line',
stack: '总量',
areaStyle: {normal: {}},
data:data
})
});
data = {
legend: {
data : areaKeys
},
yAxis : [
{
type : 'value'
}
],
xAxis : [
{
data :dateKeys
}
],
series : series
};
cb(null,data);
});
// 调用 `dao` 模块的 `list` 方法来获取 `ReportOneModel` 对应的数据,这里第一个参数 `"ReportOneModel"` 可能是表示要查询的数据模型名称,对应数据库中的具体数据表,
// 第二个参数 `null` 可能表示查询条件(这里暂时没有传递具体查询条件,可能是获取该表的所有数据的意思),第三个参数是一个回调函数,用于处理查询操作完成后的结果情况。
dao.list("ReportOneModel", null, function (err, result) {
// 如果在获取报表数据的过程中出现错误(`err` 不为 `null`),比如数据库查询失败(可能是连接问题、权限不足、表不存在等原因),则直接通过回调函数 `cb` 返回错误信息,表示获取报表数据失败,让调用者知晓操作出现问题及原因。
if (err) return cb("获取报表数据失败");
// 创建一个空对象 `areaKeyResult`用于后续按照区域area和日期date来存储和整理报表数据以方便构建最终需要返回的格式化数据结构。
var areaKeyResult = {};
// 使用 `lodash` 的 `union` 和 `map` 函数来获取报表数据中所有不重复的区域信息(`rp1_area` 字段),将其整理为一个数组并赋值给 `areaKeys`。
// `_.map` 函数用于从 `result` 数组中的每个对象提取 `rp1_area` 字段的值,形成一个新的数组,然后 `_.union` 函数对这个新数组进行去重操作,得到唯一的区域值数组。
var areaKeys = _.union(_.map(result, "rp1_area"));
// 使用 `lodash` 的 `union` 函数结合一个匿名函数来获取报表数据中所有不重复的日期信息(经过格式化后的日期字符串),并赋值给 `dateKeys`。
// 匿名函数内先将日期对象(`rp1_date` 字段)格式化为 `年-月-日` 的字符串形式,然后返回该字符串,`_.union` 函数对这些格式化后的日期字符串进行去重操作,得到唯一的日期值数组。
var dateKeys = _.union(_.map(result, function (record) {
str = record["rp1_date"].getFullYear() + "-" + (record["rp1_date"].getMonth() + 1) + "-" + record["rp1_date"].getDate();
console.log(str);
return str;
}));
// 遍历获取到的报表数据 `result`,通过索引 `idx` 来访问每个数据记录对象,进行后续的数据整理操作,将数据按照区域和日期的维度进行重新组织。
for (var idx in result) {
var record = result[idx];
var dateKey = record["rp1_date"].getFullYear() + "-" + (record["rp1_date"].getMonth() + 1) + "-" + record["rp1_date"].getDate();
// 如果 `areaKeyResult` 对象中还不存在当前记录的区域键(`record["rp1_area"]`),则创建一个以该区域为键的空对象,用于后续存储该区域下不同日期的数据。
if (!areaKeyResult[record["rp1_area"]]) {
areaKeyResult[record["rp1_area"]] = {};
}
// 将当前记录按照日期键(`dateKey`)存储到对应的区域对象下,这样就构建了一个以区域为一级键,日期为二级键,对应报表记录为值的嵌套对象结构,方便后续按区域和日期查找数据。
areaKeyResult[record["rp1_area"]][dateKey] = record;
}
// 格式输出
// 创建一个空数组 `series`用于存储最终要返回的数据格式中的系列series信息每个元素代表不同区域的数据系列在图表展示等场景中通常对应不同的线条或图形。
var series = [];
// 使用 `lodash` 的 `forEach` 函数遍历 `areaKeys` 数组,对于每个区域键(`areaKey`)进行以下操作,构建每个区域对应的图表数据系列信息。
_(areaKeys).forEach(function (areaKey) {
var data = [];
// 使用 `lodash` 的 `forEach` 函数遍历 `dateKeys` 数组,对于每个日期键(`dateKey`)进行以下操作,构建当前区域在不同日期下的数据点信息。
_(dateKeys).forEach(function (dateKey) {
console.log("areaKey:" + areaKey + "," + "dateKey:" + dateKey);
// 如果在 `areaKeyResult` 中根据当前区域键(`areaKey`)和日期键(`dateKey`)能找到对应的报表记录,则将该记录中的用户数量(`rp1_user_count` 字段)添加到 `data` 数组中,
// 表示该区域在该日期下的用户数量数据点;如果找不到对应的记录,则添加 `0`,表示该日期下该区域没有相应的数据(可能是缺失或未统计等情况)。
if (areaKeyResult[areaKey][dateKey]) {
data.push(areaKeyResult[areaKey][dateKey]["rp1_user_count"]);
} else {
data.push(0);
}
})
// 将构建好的当前区域的数据系列信息(包含区域名称、图表类型、样式以及数据点数组等)添加到 `series` 数组中,完成一个区域的数据系列构建。
series.push({
name: areaKey,
type: 'line',
stack: '总量',
areaStyle: { normal: {} },
data: data
})
});
// 构建最终要返回的数据对象包含图例legend、y轴yAxis、x轴xAxis以及系列series等信息符合常见的图表数据格式要求用于在前端图表库等场景中进行展示。
data = {
legend: {
data: areaKeys
},
yAxis: [
{
type: 'value'
}
],
xAxis: [
{
data: dateKeys
}
],
series: series
};
// 将整理好的最终数据对象通过回调函数 `cb` 返回给调用者,表示 `reportOne` 函数成功获取并处理好了报表数据,调用者可以根据这个数据格式进行后续的操作,比如传递给前端进行图表渲染展示等。
cb(null, data);
});
}
// 定义 `reportTwo` 函数,该函数用于获取并处理 `ReportTwoModel` 相关的报表数据,将数据按照日期进行整理后通过回调函数返回给调用者。
function reportTwo(cb) {
dao.list("ReportTwoModel",null,function(err,result){
if(err) return cb("获取报表数据失败");
var dateKeyResult = {};
for(var idx in result) {
var record = result[idx];
var dateKey = record["rp2_date"].getFullYear() + "-" + (record["rp2_date"].getMonth() + 1) + "-" + record["rp2_date"].getDate();
if(!dateKeyResult[dateKey]) {
dateKeyResult[dateKey] = [];
}
dateKeyResult[dateKey].push(record);
}
cb(null,dateKeyResult);
});
// 调用 `dao` 模块的 `list` 方法来获取 `ReportTwoModel` 对应的数据,参数含义与 `reportOne` 函数中调用时类似,第一个参数指定要查询的数据表对应的模型名称,第二个参数为查询条件(这里是 `null`,获取全部数据),第三个参数处理查询结果。
dao.list("ReportTwoModel", null, function (err, result) {
// 如果在获取报表数据过程中出现错误(`err` 不为 `null`),比如数据库查询失败,就通过回调函数 `cb` 返回错误信息,表示获取报表数据失败,让调用者知晓操作出现问题及原因。
if (err) return cb("获取报表数据失败");
// 创建一个空对象 `dateKeyResult`,用于按照日期来存储和整理报表数据,后续会将相同日期的数据记录存储在以日期为键的数组中。
var dateKeyResult = {};
// 遍历获取到的报表数据 `result`,通过索引 `idx` 来访问每个数据记录对象,进行后续的数据整理操作,将数据按照日期维度进行重新组织。
for (var idx in result) {
var record = result[idx];
var dateKey = record["rp2_date"].getFullYear() + "-" + (record["rp2_date"].getMonth() + 1) + "-" + record["rp2_date"].getDate();
// 如果 `dateKeyResult` 对象中还不存在当前记录的日期键(`dateKey`),则创建一个以该日期为键的空数组,用于存储该日期下的所有报表记录。
if (!dateKeyResult[dateKey]) {
dateKeyResult[dateKey] = [];
}
// 将当前报表记录添加到对应日期键的数组中,这样就构建了一个以日期为键,对应日期下所有报表记录为值的对象结构,方便后续按日期查找和处理数据。
dateKeyResult[dateKey].push(record);
}
// 将整理好的按照日期分组的报表数据对象通过回调函数 `cb` 返回给调用者,表示 `reportTwo` 函数成功获取并整理好了报表数据,调用者可以根据这个数据结构进行后续的操作,比如进一步统计分析每个日期下的数据情况等。
cb(null, dateKeyResult);
});
}
// 定义 `reportThree` 函数,目前该函数为空,可能后续会用于实现获取和处理第三种报表数据相关的逻辑,暂时没有具体功能实现代码。
function reportThree(cb) {
}
// 定义 `reportFour` 函数,目前该函数为空,可能后续会用于实现获取和处理第四种报表数据相关的逻辑,暂时没有具体功能实现代码。
function reportFour(cb) {
}
module.exports.reports = function(typeid,cb) {
console.log(typeid);
switch (parseInt(typeid)) {
case 1:
reportOne(function(err,result){
if(err) return cb(err);
cb(null,result);
});
break;
case 2:
reportTwo(function(err,result){
if(err) return cb(err);
cb(null,result);
});
break;
case 3:
reportThree(function(err,result){
if(err) return cb(err);
cb(null,result);
});
break;
case 4:
reportFour(function(err,result){
if(err) return cb(err);
cb(null,result);
});
break;
default:
cb("类型出错");
break;
}
}
// 对外暴露 `reports` 函数根据传入的报表类型ID`typeid`)来调用相应的报表处理函数(如 `reportOne`、`reportTwo` 等并将处理结果通过回调函数返回给调用者若类型ID不合法则返回错误信息。
module.exports.reports = function (typeid, cb) {
console.log(typeid);
// 将传入的报表类型ID`typeid`)转换为整数类型,然后通过 `switch` 语句根据不同的类型值来执行相应的操作,调用对应的报表处理函数来获取和处理报表数据。
switch (parseInt(typeid)) {
case 1:
// 如果类型ID为1则调用 `reportOne` 函数来获取和处理第一种报表数据,`reportOne` 函数内部会进行数据库查询、数据整理等操作,最终返回处理好的数据,
// 这里通过回调函数接收 `reportOne` 函数返回的数据,如果出现错误(`err` 不为 `null`),则直接将错误信息通过外层的回调函数 `cb` 返回给调用者;
// 如果没有错误,则将 `reportOne` 函数返回的处理后的数据通过 `cb` 返回给调用者。
reportOne(function (err, result) {
if (err) return cb(err);
cb(null, result);
});
break;
case 2:
// 如果类型ID为2则调用 `reportTwo` 函数来获取和处理第二种报表数据,处理逻辑与 `reportOne` 类似,根据 `reportTwo` 函数的执行结果通过回调函数 `cb` 返回相应的信息给调用者。
reportTwo(function (err, result) {
if (err) return cb(err);
cb(null, result);
});
break;
case 3:
// 如果类型ID为3则调用 `reportThree` 函数来获取和处理第三种报表数据,目前该函数为空,后续可补充具体逻辑来实现相应功能并通过回调函数返回结果给调用者。
reportThree(function (err, result) {
if (err) return cb(err);
cb(null, result);
});
break;
case 4:
// 如果类型ID为4则调用 `reportFour` 函数来获取和处理第四种报表数据,目前该函数为空,后续可补充具体逻辑来实现相应功能并通过回调函数返回结果给调用者。
reportFour(function (err, result) {
if (err) return cb(err);
cb(null, result);
});
break;
default:
// 如果传入的报表类型ID不属于1 - 4的范围则通过回调函数 `cb` 返回错误信息表示类型出错告知调用者传入的报表类型ID不符合要求。
cb("类型出错");
break;
}
}
//这段代码整体构建了一个报表数据获取与处理的模块,根据不同的报表类型 ID调用相应的内部函数来获
//取特定报表模型的数据,并进行整理和格式化,最终通过回调函数将处理好的数据返回给调用者,方便
//在其他模块中进一步使用这些报表数据进行展示、分析等操作,适用于有报表相关业务需求的应用开发场景。

@ -1,94 +1,118 @@
// 引入lodash库它是一个功能强大的JavaScript工具库提供了许多便捷的函数来处理各种数据类型比如数组、对象的操作等在后续代码中用于数据的转换、整理等操作。
var _ = require('lodash');
// 引入Node.js的path模块主要用于处理文件路径相关的操作像拼接、解析文件路径等这里用于准确地引入自定义的 `dao/PermissionAPIDAO` 模块所在的文件位置。
var path = require("path");
var dao = require(path.join(process.cwd(),"dao/PermissionAPIDAO"));
// 引入自定义的 `PermissionAPIDAO` 模块,通过拼接当前工作目录(`process.cwd()`)和相对路径的方式找到并引入该模块,推测这个模块封装了与权限数据访问相关的操作,比如查询权限数据等功能。
var dao = require(path.join(process.cwd(), "dao/PermissionAPIDAO"));
// 获取所有权限
module.exports.getAllRights = function(type,cb) {
if(!type || (type != "list" && type != "tree")) {
cb("参数类型错误");
}
dao.list(function(err,permissions){
if(err) return cb("获取权限数据失败");
if(type == "list") {
var result = [];
for(idx in permissions) {
permission = permissions[idx];
result.push({
"id" : permission.ps_id,
"authName" : permission.ps_name,
"level" : permission.ps_level,
"pid" : permission.ps_pid,
"path": permission.ps_api_path
});
}
cb(null,result);
} else {
var keyCategories = _.keyBy(permissions,'ps_id');
// 显示一级
var permissionsResult = {};
// 处理一级菜单
for(idx in permissions) {
permission = permissions[idx];
if(permission && permission.ps_level == 0) {
permissionsResult[permission.ps_id] = {
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path,
"pid" : permission.ps_pid,
"children":[]
};
}
}
// 此函数用于获取系统中的所有权限信息,并根据传入的参数类型,以不同的格式返回权限数据,通过回调函数将结果或错误信息传递给调用者。
module.exports.getAllRights = function (type, cb) {
// 首先对传入的参数 `type` 进行验证,如果 `type` 不存在(即 `!type`),或者 `type` 的值既不是 `"list"` 也不是 `"tree"`,说明参数不符合要求,
// 则直接通过回调函数 `cb` 返回错误信息,表示参数类型错误,告知调用者传入的参数不符合函数预期的格式要求。
if (!type || (type!= "list" && type!= "tree")) {
cb("参数类型错误");
}
// 临时存储二级返回结果
tmpResult = {};
// 处理二级菜单
for(idx in permissions) {
permission = permissions[idx];
if(permission && permission.ps_level == 1) {
// 调用 `dao` 模块的 `list` 方法来获取权限数据,这个方法内部大概率会执行数据库查询等操作来获取所有的权限记录信息,它是一个异步操作,通过回调函数来处理获取数据后的结果情况。
dao.list(function (err, permissions) {
// 如果在获取权限数据的过程中出现错误(`err` 不为 `null`),比如数据库查询失败(可能是连接问题、权限不足、表不存在等原因),则直接通过回调函数 `cb` 返回错误信息,表示获取权限数据失败,让调用者知晓操作出现问题及原因。
if (err) return cb("获取权限数据失败");
parentPermissionResult = permissionsResult[permission.ps_pid];
if(parentPermissionResult) {
tmpResult[permission.ps_id] = {
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path,
"pid" : permission.ps_pid,
"children":[]
}
parentPermissionResult.children.push(tmpResult[permission.ps_id]);
}
}
}
// 根据传入的参数 `type` 的值来决定如何处理和返回权限数据。如果 `type` 的值为 `"list"`,表示要以列表形式返回权限数据。
if (type == "list") {
// 创建一个空数组 `result`,用于存储整理后的权限数据,后续会将每个权限的相关信息按照特定格式添加到这个数组中。
var result = [];
// 遍历获取到的权限数据数组 `permissions`,通过索引 `idx` 来访问每个权限信息对象,进行后续的处理,将每个权限的关键信息提取出来并整理成指定格式后添加到 `result` 数组中。
for (idx in permissions) {
permission = permissions[idx];
result.push({
"id": permission.ps_id,
"authName": permission.ps_name,
"level": permission.ps_level,
"pid": permission.ps_pid,
"path": permission.ps_api_path
});
}
// 将整理好的权限数据数组 `result` 通过回调函数 `cb` 返回给调用者,表示获取权限数据成功且以列表形式返回了相应的数据,调用者可以根据这个格式的数据进行后续的业务处理,比如展示权限列表等操作。
cb(null, result);
} else {
// 如果 `type` 的值为 `"tree"`,表示要以树形结构返回权限数据,更直观地展示权限之间的层级关系,以下是构建树形结构权限数据的相关逻辑。
// 处理三级菜单
for(idx in permissions) {
permission = permissions[idx];
if(permission && permission.ps_level == 2) {
// 使用 `lodash` 的 `keyBy` 函数,将获取到的权限数据(`permissions`按照权限ID`ps_id`进行转换生成一个以权限ID为键对应权限详细信息为值的对象结构
// 方便后续通过权限ID快速查找对应的权限详情在构建树形结构以及关联不同层级权限时能更高效地获取所需信息。
var keyCategories = _.keyBy(permissions, 'ps_id');
parentPermissionResult = tmpResult[permission.ps_pid];
// 显示一级
// 创建一个空对象 `permissionsResult`用于存储最终整理好的树形结构权限数据它将以一级权限的权限ID为键对应权限的详细信息包含子权限信息等为值进行存储作为树形结构的顶层节点。
var permissionsResult = {};
if(parentPermissionResult) {
parentPermissionResult.children.push({
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path,
"pid" : permission.ps_pid + "," + keyCategories[permission.ps_pid].ps_pid
});
}
}
}
// 处理一级菜单
// 遍历权限数据数组 `permissions`,通过索引 `idx` 来访问每个权限信息对象,针对每个权限进行相关处理,构建一级菜单对应的权限信息结构并添加到 `permissionsResult` 对象中。
for (idx in permissions) {
permission = permissions[idx];
// 如果当前权限存在(即 `permission` 不为 `null`),并且该权限的层级(`ps_level`为0表示它是一级菜单权限那么就将其相关信息按照特定结构添加到 `permissionsResult` 对象中。
if (permission && permission.ps_level == 0) {
permissionsResult[permission.ps_id] = {
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path,
"pid": permission.ps_pid,
"children": []
};
}
}
cb(null,_.values(permissionsResult));
// 临时存储二级返回结果
// 创建一个临时对象 `tmpResult`,用于在处理二级菜单权限时,暂时存储二级菜单权限的相关信息,后续会将这些信息整理到对应的一级菜单权限的 `children` 数组中,以构建完整的树形结构。
tmpResult = {};
// 处理二级菜单
// 再次遍历权限数据数组 `permissions`,同样对每个权限进行检查和相关处理,这次是构建二级菜单对应的权限信息结构,并关联到对应的一级菜单权限下。
for (idx in permissions) {
permission = permissions[idx];
if (permission && permission.ps_level == 1) {
// 根据当前二级菜单权限的父级权限ID`ps_pid`),从 `permissionsResult` 中获取对应的一级菜单权限结果对象,后续将把当前二级菜单权限添加到这个一级菜单权限的子权限列表中。
parentPermissionResult = permissionsResult[permission.ps_pid];
if (parentPermissionResult) {
tmpResult[permission.ps_id] = {
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path,
"pid": permission.ps_pid,
"children": []
}
// 将当前二级菜单权限对象添加到对应的一级菜单权限结果对象的 `children` 数组中,建立起层级关系,表示二级菜单权限隶属于对应的一级菜单权限。
parentPermissionResult.children.push(tmpResult[permission.ps_id]);
}
}
}
}
});
}
// 处理三级菜单
// 又一次遍历权限数据数组 `permissions`,针对每个权限进行处理,构建三级菜单对应的权限信息结构,并关联到对应的二级菜单权限下,完善整个权限树形结构。
for (idx in permissions) {
permission = permissions[idx];
if (permission && permission.ps_level == 2) {
// 根据当前三级菜单权限的父级权限ID`ps_pid`),从 `tmpResult` 中获取对应的二级菜单权限结果对象,后续将把当前三级菜单权限添加到这个二级菜单权限的子权限列表中。
parentPermissionResult = tmpResult[permission.ps_pid];
if (parentPermissionResult) {
// 将当前三级菜单权限的相关信息按照特定结构,添加到对应的二级菜单权限结果对象的 `children` 数组中,建立起三级菜单权限与二级菜单权限的隶属关系。
// 这里对于 `pid` 属性的赋值除了当前权限的父级权限ID还添加了父级权限的父级权限ID通过 `keyCategories[permission.ps_pid].ps_pid` 获取),
// 可能是为了更详细地记录权限的层级关联信息,具体含义要根据业务需求来确定,这样构建出更完整的权限层级结构信息。
parentPermissionResult.children.push({
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path,
"pid": permission.ps_pid + "," + keyCategories[permission.ps_pid].ps_pid
});
}
}
}
// 使用 `_.values` 获取 `permissionsResult` 对象中的值(即整理好的树形结构权限数据),然后通过回调函数 `cb` 返回这些数据给调用者,
// 表示获取权限数据成功且以树形结构返回了相应的数据,调用者可以根据这个格式的数据进行后续的业务处理,比如在权限管理页面以树形菜单形式展示权限等操作。
cb(null, _.values(permissionsResult));
}
});
}
//这段代码整体围绕获取系统所有权限信息展开,根据传入的不同参数类型,能够以列表形式或者树形结构
//形式返回权限数据,通过一系列的数据处理和层级构建操作,满足了不同业务场景下对权限数据展示和
//使用的需求,在权限管理相关的应用开发中具有重要作用。

@ -1,257 +1,374 @@
// 引入lodash库lodash是一个实用的JavaScript工具库提供了许多便捷的函数来处理数组、对象、字符串等数据类型帮助简化常见的编程任务例如这里后续可能会用到它提供的对象和数组操作相关的方法。
var _ = require('lodash');
// 引入Node.js的path模块主要用于处理文件路径相关的操作像拼接、解析文件路径等以便准确地引入其他模块所在的文件位置。
var path = require("path");
var dao = require(path.join(process.cwd(),"dao/DAO"));
var permissionAPIDAO = require(path.join(process.cwd(),"dao/PermissionAPIDAO"));
// 引入自定义的 `DAO` 模块,从代码中拼接的路径来看,它应该位于项目根目录下的 `dao/DAO` 文件中,这个模块大概率封装了与数据库操作相关的通用方法,例如查询、插入、更新等操作,用于不同数据模型的处理。
var dao = require(path.join(process.cwd(), "dao/DAO"));
// 引入自定义的 `PermissionAPIDAO` 模块,同样通过拼接路径的方式引入,位于 `dao/PermissionAPIDAO` 文件中,推测该模块主要负责与权限相关的数据访问操作,比如获取权限数据等功能。
var permissionAPIDAO = require(path.join(process.cwd(), "dao/PermissionAPIDAO"));
function getPermissionsResult(permissionKeys,permissionIds) {
var permissionsResult = {};
// 定义一个名为 `getPermissionsResult` 的函数它的主要作用是根据传入的权限相关的键值和权限ID列表来构建权限结果对象这个对象将按照权限的层级结构一、二、三级菜单对应的权限进行组织。
function getPermissionsResult(permissionKeys, permissionIds) {
// 创建一个空对象用于存储最终整理好的权限结果它将以权限ID为键对应权限的详细信息包含子权限信息等为值进行存储。
var permissionsResult = {};
// 处理一级菜单
for(idx in permissionIds) {
if(!permissionIds[idx] || permissionIds[idx] == "") continue;
permissionId = parseInt(permissionIds[idx]);
permission = permissionKeys[permissionId];
if(permission && permission.ps_level == 0) {
permissionsResult[permission.ps_id] = {
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path,
"children":[]
};
}
}
// 处理一级菜单
// 遍历权限ID列表通过索引 `idx` 来访问每个权限ID这个循环将对每个权限ID进行相关处理构建一级菜单对应的权限信息结构。
for (idx in permissionIds) {
// 如果当前权限ID不存在或者为空字符串则跳过本次循环继续处理下一个权限ID这样可以排除无效的权限ID情况。
if (!permissionIds[idx] || permissionIds[idx] == "") continue;
// 将当前权限ID转换为整数类型确保在后续操作中比如作为对象的键进行查找等操作使用合适的数据类型因为权限ID在业务逻辑中通常被视为数字标识。
permissionId = parseInt(permissionIds[idx]);
// 根据权限ID从 `permissionKeys` 中获取对应的权限信息对象,这里的 `permissionKeys` 应该是一个以权限ID为键权限详细信息为值的对象结构方便通过权限ID快速查找对应权限详情。
permission = permissionKeys[permissionId];
// 如果获取到了对应的权限信息,并且该权限的层级(`ps_level`为0表示它是一级菜单权限那么就将其相关信息按照特定结构添加到 `permissionsResult` 对象中。
if (permission && permission.ps_level == 0) {
permissionsResult[permission.ps_id] = {
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path,
"children": []
};
}
}
// 临时存储二级返回结果
tmpResult = {};
// 处理二级菜单
for(idx in permissionIds) {
if(!permissionIds[idx] || permissionIds[idx] == "") continue;
permissionId = parseInt(permissionIds[idx]);
permission = permissionKeys[permissionId];
if(permission && permission.ps_level == 1) {
parentPermissionResult = permissionsResult[permission.ps_pid];
if(parentPermissionResult) {
tmpResult[permission.ps_id] = {
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path,
"children":[]
}
parentPermissionResult.children.push(tmpResult[permission.ps_id]);
}
}
}
// 临时存储二级返回结果
// 创建一个临时对象 `tmpResult`,用于在处理二级菜单权限时,暂时存储二级菜单权限的相关信息,后续会将这些信息整理到对应的一级菜单权限的 `children` 数组中。
tmpResult = {};
// 处理二级菜单
// 再次遍历权限ID列表同样对每个权限ID进行检查和相关处理这次是构建二级菜单对应的权限信息结构并关联到对应的一级菜单权限下。
for (idx in permissionIds) {
if (!permissionIds[idx] || permissionIds[idx] == "") continue;
permissionId = parseInt(permissionIds[idx]);
permission = permissionKeys[permissionId];
if (permission && permission.ps_level == 1) {
// 根据当前二级菜单权限的父级权限ID`ps_pid`),从 `permissionsResult` 中获取对应的一级菜单权限结果对象,后续将把当前二级菜单权限添加到这个一级菜单权限的子权限列表中。
parentPermissionResult = permissionsResult[permission.ps_pid];
if (parentPermissionResult) {
// 将当前二级菜单权限的相关信息按照特定结构存储到 `tmpResult` 对象中同样以权限ID为键方便后续引用和操作。
tmpResult[permission.ps_id] = {
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path,
"children": []
}
// 将当前二级菜单权限对象添加到对应的一级菜单权限结果对象的 `children` 数组中,建立起层级关系,表示二级菜单权限隶属于对应的一级菜单权限。
parentPermissionResult.children.push(tmpResult[permission.ps_id]);
}
}
}
// 处理三级菜单
for(idx in permissionIds) {
if(!permissionIds[idx] || permissionIds[idx] == "") continue;
permissionId = parseInt(permissionIds[idx]);
permission = permissionKeys[permissionId];
if(permission && permission.ps_level == 2) {
parentPermissionResult = tmpResult[permission.ps_pid];
if(parentPermissionResult) {
parentPermissionResult.children.push({
"id":permission.ps_id,
"authName":permission.ps_name,
"path":permission.ps_api_path
});
}
}
}
return permissionsResult;
// 处理三级菜单
// 又一次遍历权限ID列表针对每个权限ID进行处理构建三级菜单对应的权限信息结构并关联到对应的二级菜单权限下完善整个权限层级结构。
for (idx in permissionIds) {
if (!permissionIds[idx] || permissionIds[idx] == "") continue;
permissionId = parseInt(permissionIds[idx]);
permission = permissionKeys[permissionId];
if (permission && permission.ps_level == 2) {
// 根据当前三级菜单权限的父级权限ID`ps_pid`),从 `tmpResult` 中获取对应的二级菜单权限结果对象,后续将把当前三级菜单权限添加到这个二级菜单权限的子权限列表中。
parentPermissionResult = tmpResult[permission.ps_pid];
if (parentPermissionResult) {
// 将当前三级菜单权限的相关信息按照特定结构,直接添加到对应的二级菜单权限结果对象的 `children` 数组中,建立起三级菜单权限与二级菜单权限的隶属关系。
parentPermissionResult.children.push({
"id": permission.ps_id,
"authName": permission.ps_name,
"path": permission.ps_api_path
});
}
}
}
// 返回整理好的权限结果对象,这个对象按照层级结构包含了各级菜单权限的详细信息,可供其他函数或模块进一步使用,例如在权限展示、权限验证等业务场景中使用。
return permissionsResult;
}
/**
* 获取所有用户的角色 & 权限
* 此函数主要用于从数据库或其他数据源中获取所有用户的角色信息以及对应的权限信息然后进行整理和关联最终通过回调函数返回整理好的结果给调用者
*
* @param {Function} cb 回调函数
* @param {Function} cb 回调函数用于接收获取角色和权限数据的操作结果若操作成功则传递包含数据的参数若失败则传递错误信息参数
*/
module.exports.getAllRoles = function(cb) {
dao.list("RoleModel",null,function(err,roles) {
if(err) return cb("获取角色数据失败");
permissionAPIDAO.list(function(err,permissions){
if(err) return cb("获取权限数据失败");
var permissionKeys = _.keyBy(permissions,'ps_id');
var rolesResult = [];
for(idx in roles) {
role = roles[idx];
permissionIds = role.ps_ids.split(",");
roleResult = {
"id" : role.role_id,
"roleName" : role.role_name,
"roleDesc" : role.role_desc,
"children" : []
};
// 调用 `dao` 模块的 `list` 方法,尝试获取角色数据。第一个参数 `"RoleModel"` 可能是表示要查询的数据模型名称,用于在 `DAO` 模块内部确定要操作的具体数据表或数据集合,
// 第二个参数 `null` 可能表示查询条件(这里暂时没有传递具体查询条件,可能是获取所有角色数据的意思),第三个参数是一个回调函数,用于处理查询操作完成后的结果情况。
dao.list("RoleModel", null, function (err, roles) {
// 如果在获取角色数据的过程中出现错误(`err` 不为 `null`),比如数据库查询失败(可能是连接问题、权限不足、表不存在等原因),则直接通过传入的回调函数 `cb` 返回错误信息,表示获取角色数据失败。
if (err) return cb("获取角色数据失败");
// 如果角色数据获取成功,接着调用 `permissionAPIDAO` 模块的 `list` 方法,尝试获取权限数据,同样它内部会执行相应的数据库查询等操作来获取权限相关的记录信息。
permissionAPIDAO.list(function (err, permissions) {
// 如果在获取权限数据过程中出现错误,就通过回调函数 `cb` 返回相应的错误信息,表示获取权限数据失败,这样调用者就能知晓操作出现问题的环节以及具体的错误提示。
if (err) return cb("获取权限数据失败");
// 使用lodash的 `keyBy` 函数,将获取到的权限数据(`permissions`按照权限ID`ps_id`进行转换生成一个以权限ID为键对应权限详细信息为值的对象结构方便后续通过权限ID快速查找权限详情
// 这在构建权限层级结构等操作中会很方便,避免了多次遍历数组查找对应权限的麻烦。
var permissionKeys = _.keyBy(permissions, 'ps_id');
// 创建一个空数组,用于存储最终整理好的包含角色和对应权限层级结构信息的结果对象,后续会将每个角色及其关联的权限信息依次添加到这个数组中。
var rolesResult = [];
// 遍历获取到的角色数据数组,通过索引 `idx` 来访问每个角色信息对象,进行后续的处理,将角色信息和对应的权限信息进行关联整合。
for (idx in roles) {
role = roles[idx];
// 将当前角色的权限ID字符串可能是以逗号分隔的多个权限ID进行分割得到一个权限ID数组方便后续根据这些权限ID去查找和构建对应的权限层级结构信息。
permissionIds = role.ps_ids.split(",");
// 创建一个对象,用于存储当前角色的基本信息以及即将整理好的权限层级结构信息,按照特定的格式进行初始化,后续会逐步填充完整信息。
roleResult = {
"id": role.role_id,
"roleName": role.role_name,
"roleDesc": role.role_desc,
"children": []
};
roleResult.children = _.values(getPermissionsResult(permissionKeys,permissionIds));
// 调用 `getPermissionsResult` 函数,传入整理好的权限键值对象(`permissionKeys`和当前角色的权限ID数组`permissionIds`
// 该函数会根据这些信息构建出对应的权限层级结构信息,并返回结果,然后将返回的结果(权限层级结构信息)赋值给当前角色结果对象的 `children` 属性,
// 这样就将角色信息和其对应的权限信息关联起来了,形成了包含角色和权限层级结构的完整信息对象。
roleResult.children = _.values(getPermissionsResult(permissionKeys, permissionIds));
rolesResult.push(roleResult);
}
// 将当前角色的完整信息对象添加到 `rolesResult` 数组中,完成一个角色及其权限信息的整理和存储,后续循环会处理其他角色信息,直到所有角色信息都处理完毕。
rolesResult.push(roleResult);
}
cb(null,rolesResult);
// 当所有角色的信息以及对应的权限层级结构信息都整理完成后,通过回调函数 `cb` 返回整理好的结果数组(`rolesResult`
// 此时表示获取所有用户的角色和权限信息操作成功,调用者可以接收到完整的数据进行后续的业务处理,比如展示角色权限列表、进行权限验证等操作。
cb(null, rolesResult);
});
});
}
});
});
}
//这段代码整体围绕获取用户角色和权限信息展开,先分别从不同的数据访问模块获取角色数据和权限数
//据,然后通过一系列处理(构建权限层级结构、关联角色和权限信息等),最终将整合好的结果通过回调
//函数返回给调用者,在权限管理相关的业务场景中具有重要作用,例如在系统后台展示不同用户角色所拥
//有的权限菜单等功能时会用到这样的代码逻辑。
/**
* 添加角色
* 此函数用于向系统中添加新的角色信息接收角色相关的参数以及一个回调函数根据参数验证和数据库操作的结果通过回调函数返回相应的信息给调用者
*
* @param {[type]} params [description]
* @param {Function} cb [description]
* @param {[type]} params 包含角色信息的参数对象预期包含角色名称roleName角色描述roleDesc等相关信息具体结构由业务需求决定
* @param {Function} cb 回调函数用于接收添加角色操作的结果若操作成功则传递包含新添加角色详细信息的参数若失败则传递错误信息参数
*/
module.exports.createRole = function(params,cb) {
if(!params.roleName) return cb("角色名称不能为空");
if(!params.roleDesc) params.roleDesc = "";
module.exports.createRole = function (params, cb) {
// 首先验证传入的参数中角色名称roleName是否存在如果不存在则直接通过回调函数返回错误信息表示角色名称不能为空因为角色名称是角色的重要标识不可或缺。
if (!params.roleName) return cb("角色名称不能为空");
// 如果传入的参数中角色描述roleDesc不存在则将其默认设置为空字符串说明角色描述在某些情况下可以为空这里进行了一个默认值的处理。
if (!params.roleDesc) params.roleDesc = "";
dao.create("RoleModel",{"role_name":params.roleName,"role_desc":params.roleDesc,"ps_ids":""},function(err,role){
if(err) return cb("创建角色失败");
cb(null,{
"roleId" : role.role_id,
"roleName" : role.role_name,
"roleDesc" : role.role_desc
});
})
// 调用 `dao` 模块的 `create` 方法来执行创建角色的数据库操作。
// 第一个参数 `"RoleModel"` 可能是用于指定要操作的数据模型名称,对应数据库中的相关数据表,告知 `dao` 模块操作哪个表来插入新的角色记录。
// 第二个参数是一个对象包含了要插入数据库的角色信息以键值对形式表示字段和对应的值这里将角色名称、角色描述以及权限ID列表初始为空字符串等信息传递进去准备插入数据库。
// 第三个参数是一个回调函数,用于处理数据库插入操作完成后的结果情况,根据操作是否成功返回相应的信息给回调函数 `cb`。
dao.create("RoleModel", { "role_name": params.roleName, "role_desc": params.roleDesc, "ps_ids": "" }, function (err, role) {
// 如果在数据库插入操作过程中出现错误(`err` 不为 `null`),比如数据库连接问题、插入语句执行失败等原因,就通过回调函数 `cb` 返回错误信息,表示创建角色失败,让调用者知晓操作未成功以及失败原因。
if (err) return cb("创建角色失败");
// 如果角色创建成功,通过回调函数 `cb` 返回包含新创建角色详细信息的对象包含角色IDroleId、角色名称roleName以及角色描述roleDesc等信息方便调用者获取新角色的相关详情进行后续操作。
cb(null, {
"roleId": role.role_id,
"roleName": role.role_name,
"roleDesc": role.role_desc
});
})
}
/**
* 通过角色 ID 获取角色详情
* 该函数根据传入的角色ID从数据库中查询并获取对应角色的详细信息通过回调函数将查询结果返回给调用者若参数不符合要求或查询出现错误也会通过回调函数返回相应的错误提示
*
* @param {[type]} id 角色ID
* @param {Function} cb 回调函数
* @param {[type]} id 角色ID用于唯一标识要查询详情的角色应该为有效的数字类型由调用者传入
* @param {Function} cb 回调函数用于接收获取角色详情操作的结果若成功则传递包含角色详细信息的参数若失败则传递错误信息参数
*/
module.exports.getRoleById = function(id,cb){
if(!id) return cb("角色ID不能为空");
if(isNaN(parseInt(id))) return cb("角色ID必须为数字");
dao.show("RoleModel",id,function(err,role){
if(err) return cb("获取角色详情失败");
cb(null,{
"roleId" : role.role_id,
"roleName" : role.role_name,
"roleDesc" : role.role_desc,
"rolePermissionDesc" : role.ps_ca
});
});
module.exports.getRoleById = function (id, cb) {
// 首先验证传入的角色ID是否存在如果不存在则直接通过回调函数返回错误信息表示角色ID不能为空因为没有ID无法确定要查询哪个角色的详情。
if (!id) return cb("角色ID不能为空");
// 进一步验证角色ID是否可以转换为数字类型如果不能转换成功即不是有效的数字则通过回调函数返回错误信息表示角色ID必须为数字因为在系统设计中角色ID通常以数字形式存储和使用以准确查找对应记录。
if (isNaN(parseInt(id))) return cb("角色ID必须为数字");
// 调用 `dao` 模块的 `show` 方法尝试从数据库中获取指定角色ID对应的角色详情信息。
// 第一个参数 `"RoleModel"` 指明要操作的数据模型(对应数据库中的数据表),用于确定查询的目标数据表。
// 第二个参数传入角色ID作为查询条件让 `dao` 模块根据此ID查找对应的角色记录。
// 第三个参数是一个回调函数,用于处理查询操作完成后的结果情况,根据是否查询到数据以及是否出现错误等情况返回相应的信息给回调函数 `cb`。
dao.show("RoleModel", id, function (err, role) {
// 如果在查询过程中出现错误(`err` 不为 `null`),比如数据库查询语句执行失败、连接问题等原因,就通过回调函数 `cb` 返回错误信息,表示获取角色详情失败,告知调用者操作出现问题及原因。
if (err) return cb("获取角色详情失败");
// 如果查询成功,通过回调函数 `cb` 返回包含角色详细信息的对象包含角色IDroleId、角色名称roleName、角色描述roleDesc以及角色权限描述rolePermissionDesc等信息方便调用者获取并使用这些详情信息。
cb(null, {
"roleId": role.role_id,
"roleName": role.role_name,
"roleDesc": role.role_desc,
"rolePermissionDesc": role.ps_ca
});
});
}
/**
* 更新角色信息
* 此函数用于根据传入的角色相关参数对已存在的角色信息进行更新操作主要涉及更新角色名称和角色描述等信息通过回调函数返回更新后的角色详细信息或者错误提示给调用者
*
* @param {[type]} role 角色对象
* @param {Function} cb 回调函数
* @param {[type]} params 包含要更新的角色信息的参数对象预期包含角色IDid角色名称roleName角色描述roleDesc等相关信息具体结构由业务需求决定
* @param {Function} cb 回调函数用于接收更新角色信息操作的结果若成功则传递包含更新后角色详细信息的参数若失败则传递错误信息参数
*/
module.exports.updateRole = function(params,cb){
if(!params) return cb("参数不能为空");
if(!params.id) return cb("角色ID不能为空");
if(isNaN(parseInt(params.id))) return cb("角色ID必须为数字");
module.exports.updateRole = function (params, cb) {
// 首先验证传入的参数是否存在,如果不存在,则直接通过回调函数返回错误信息,表示参数不能为空,因为没有参数无法确定要更新哪个角色以及更新哪些内容。
if (!params) return cb("参数不能为空");
// 接着验证参数中的角色IDid是否存在如果不存在则通过回调函数返回错误信息表示角色ID不能为空因为没有角色ID无法准确找到要更新信息的目标角色。
if (!params.id) return cb("角色ID不能为空");
// 进一步验证角色ID是否可以转换为数字类型如果不能转换成功即不是有效的数字则通过回调函数返回错误信息表示角色ID必须为数字以确保能准确地在数据库中定位到对应的角色记录进行更新操作。
if (isNaN(parseInt(params.id))) return cb("角色ID必须为数字");
updateInfo = {};
if(params.roleName) {
updateInfo["role_name"] = params.roleName;
}
if(params.roleDesc) {
updateInfo["role_desc"] = params.roleDesc;
}
// 创建一个空对象,用于存储要更新的角色信息,后续会根据传入的参数情况,将需要更新的字段和对应的值添加到这个对象中,然后传递给数据库更新操作的方法。
updateInfo = {};
// 如果传入的参数中包含角色名称roleName则将角色名称信息添加到 `updateInfo` 对象中,键为 `"role_name"`,对应的值就是传入的角色名称,准备用于更新数据库中的角色名称字段。
if (params.roleName) {
updateInfo["role_name"] = params.roleName;
}
// 如果传入的参数中包含角色描述roleDesc则将角色描述信息添加到 `updateInfo` 对象中,键为 `"role_desc"`,对应的值就是传入的角色描述,准备用于更新数据库中的角色描述字段。
if (params.roleDesc) {
updateInfo["role_desc"] = params.roleDesc;
}
dao.update("RoleModel",params.id,updateInfo,function(err,newRole) {
if(err) return cb("更新角色信息失败");
cb(null,{
"roleId":newRole.role_id,
"roleName":newRole.role_name,
"roleDesc":newRole.role_desc,
"rolePermissionDesc" : newRole.ps_ca
});
});
// 调用 `dao` 模块的 `update` 方法来执行角色信息的更新操作。
// 第一个参数 `"RoleModel"` 指明要操作的数据模型(对应数据库中的数据表),确定要更新的目标数据表。
// 第二个参数传入角色ID用于准确找到数据库中对应的角色记录进行更新。
// 第三个参数传入 `updateInfo` 对象,包含了要更新的具体字段和对应的值,告知数据库要更新哪些信息。
// 第四个参数是一个回调函数,用于处理更新操作完成后的结果情况,根据操作是否成功返回相应的信息给回调函数 `cb`。
dao.update("RoleModel", params.id, updateInfo, function (err, newRole) {
// 如果在更新操作过程中出现错误(`err` 不为 `null`),比如数据库更新语句执行失败、违反数据约束等原因,就通过回调函数 `cb` 返回错误信息,表示更新角色信息失败,告知调用者操作未成功及原因。
if (err) return cb("更新角色信息失败");
// 如果更新操作成功,通过回调函数 `cb` 返回包含更新后角色详细信息的对象包含角色IDroleId、角色名称roleName、角色描述roleDesc以及角色权限描述rolePermissionDesc等信息方便调用者获取更新后的角色详情进行后续操作。
cb(null, {
"roleId": newRole.role_id,
"roleName": newRole.role_name,
"roleDesc": newRole.role_desc,
"rolePermissionDesc": newRole.ps_ca
});
});
}
/**
* 对角色进行授权
* 该函数用于更新角色的权限信息根据传入的角色ID和权限列表将权限信息更新到对应的角色记录中通过回调函数返回更新后的角色相关信息或者错误提示给调用者
*
* @param {[type]} rights "," 分割的权限列表
* @param {Function} cb 回调函数
* @param {[type]} rid 角色ID用于唯一标识要授权的角色应该为有效的数字类型由调用者传入以确定操作的目标角色
* @param {Function} rights "," 分割的权限列表通常是一串表示权限ID的字符串用于更新角色所拥有的权限信息格式由业务需求决定
* @param {Function} cb 回调函数用于接收更新角色权限操作的结果若成功则传递包含更新后角色部分详细信息的参数若失败则传递错误信息参数
*/
module.exports.updateRoleRight = function(rid,rights,cb) {
if(!rid) return cb("角色ID不能为空");
if(isNaN(parseInt(rid))) return cb("角色ID必须为数字");
module.exports.updateRoleRight = function (rid, rights, cb) {
// 首先验证传入的角色IDrid是否存在如果不存在则通过回调函数返回错误信息表示角色ID不能为空因为没有角色ID无法确定要对哪个角色进行授权操作。
if (!rid) return cb("角色ID不能为空");
// 进一步验证角色ID是否可以转换为数字类型如果不能转换成功即不是有效的数字则通过回调函数返回错误信息表示角色ID必须为数字确保能准确在数据库中定位到对应的角色记录进行权限更新操作。
if (isNaN(parseInt(rid))) return cb("角色ID必须为数字");
// 注意这里需要更新权限描述信息字段
// 暂时实现
//
dao.update("RoleModel",rid,{"ps_ids":rights},function(err,newRole) {
if(err) return cb("更新权限失败");
cb(null,{
"roleId":newRole.role_id,
"roleName":newRole.role_name
});
});
// 注意这里需要更新权限描述信息字段,目前暂时实现的逻辑如下(可能后续需要进一步完善或调整)。
// 调用 `dao` 模块的 `update` 方法来执行角色权限的更新操作。
// 第一个参数 `"RoleModel"` 指明要操作的数据模型(对应数据库中的数据表),确定要更新的目标数据表是角色表。
// 第二个参数传入角色ID用于准确找到数据库中对应的角色记录进行权限更新。
// 第三个参数传入一个对象,其中 `"ps_ids"` 键对应的值为传入的权限列表rights表示将角色的权限ID列表字段更新为新传入的权限信息以此实现对角色的授权操作。
// 第四个参数是一个回调函数,用于处理更新操作完成后的结果情况,根据操作是否成功返回相应的信息给回调函数 `cb`。
dao.update("RoleModel", rid, { "ps_ids": rights }, function (err, newRole) {
// 如果在更新操作过程中出现错误(`err` 不为 `null`),比如数据库更新语句执行失败、数据格式不符合要求等原因,就通过回调函数 `cb` 返回错误信息,表示更新权限失败,告知调用者操作未成功及原因。
if (err) return cb("更新权限失败");
// 如果更新操作成功,通过回调函数 `cb` 返回包含更新后角色部分详细信息的对象包含角色IDroleId、角色名称roleName等信息方便调用者获取更新后的部分角色详情进行后续操作这里返回的信息可根据实际业务需求进一步调整完善。
cb(null, {
"roleId": newRole.role_id,
"roleName": newRole.role_name
});
});
}
/**
* 删除权限
* 此函数用于从角色的权限列表中删除指定的权限涉及获取角色信息处理权限列表更新角色信息以及重新获取相关权限数据等操作最后通过回调函数返回处理后的权限相关结果或者错误提示给调用者
*
* @param {[type]} rid 权限ID
* @param {[type]} deletedRightId 删除的权限ID
* @param {Function} cb 回调函数
* @param {[type]} rid 权限ID这里可能是角色的相关ID用于唯一标识要操作的角色由调用者传入以确定要删除权限的目标角色
* @param {[type]} deletedRightId 删除的权限ID用于指定要从角色权限列表中删除的具体权限应该为有效的数字类型其格式和业务含义由系统的权限管理设计决定
* @param {Function} cb 回调函数用于接收删除权限操作的结果若成功则传递包含处理后权限相关信息的参数若失败则传递错误信息参数
*/
module.exports.deleteRoleRight = function(rid,deletedRightId,cb) {
daoModule.findOne("RoleModel",{"role_id":rid},function(err,role){
if(err || !role) return cb("获取角色信息失败",false);
ps_ids = role.ps_ids.split(",");
new_ps_ids = [];
for(idx in ps_ids) {
ps_id = ps_ids[idx];
if(parseInt(deletedRightId) == parseInt(ps_id)) {
continue;
}
new_ps_ids.push(ps_id);
}
new_ps_ids_string = new_ps_ids.join(",");
role.ps_ids = new_ps_ids_string;
role.save(function(err,newRole) {
if(err) return cb("删除权限失败");
permissionAPIDAO.list(function(err,permissions){
if(err) return cb("获取权限数据失败");
permissionIds = newRole.ps_ids.split(",");
var permissionKeys = _.keyBy(permissions,'ps_id');
return cb(null,_.values(getPermissionsResult(permissionKeys,permissionIds)));
});
module.exports.deleteRoleRight = function (rid, deletedRightId, cb) {
// 调用 `daoModule`(这里可能是 `dao` 模块,也许是代码中的一个小笔误,具体要看实际的模块引用情况)的 `findOne` 方法尝试从数据库中查找指定角色ID对应的角色信息。
// 第一个参数 `"RoleModel"` 指明要操作的数据模型(对应数据库中的数据表),确定要查询的是角色数据表。
// 第二个参数传入一个对象,其中 `"role_id"` 键对应的值为传入的角色IDrid以此作为查询条件查找对应的角色记录。
// 第三个参数是一个回调函数,用于处理查询操作完成后的结果情况,根据是否查询到数据以及是否出现错误等情况返回相应的信息给回调函数 `cb`。
daoModule.findOne("RoleModel", { "role_id": rid }, function (err, role) {
// 如果在查询过程中出现错误(`err` 不为 `null`)或者没有查询到对应的角色(`role` 为 `null`),比如数据库查询失败、没有符合条件的角色记录等原因,就通过回调函数 `cb` 返回错误信息,表示获取角色信息失败,同时返回 `false`(具体这个 `false` 的用途可能要结合调用处的逻辑来看),告知调用者操作出现问题及原因。
if (err ||!role) return cb("获取角色信息失败", false);
// 将获取到的角色的权限ID列表字符串以逗号分隔的多个权限ID进行分割得到一个权限ID数组方便后续对每个权限ID进行处理判断要删除的权限是否在其中等操作。
ps_ids = role.ps_ids.split(",");
// 创建一个新的空数组用于存储处理后的权限ID列表即删除指定权限ID后的剩余权限ID列表后续会将不需要删除的权限ID添加到这个数组中。
new_ps_ids = [];
// 遍历分割后的权限ID数组通过索引 `idx` 来访问每个权限ID进行后续的处理判断每个权限ID是否需要删除。
for (idx in ps_ids) {
ps_id = ps_ids[idx];
// 如果当前权限ID转换为数字后与要删除的权限ID也转换为数字后相等则表示当前权限就是要删除的权限跳过本次循环不将其添加到新的权限ID列表中实现删除该权限的目的。
if (parseInt(deletedRightId) == parseInt(ps_id)) {
continue;
}
// 如果当前权限ID不是要删除的权限ID则将其添加到新的权限ID列表 `new_ps_ids` 中,保留该权限。
new_ps_ids.push(ps_id);
}
// 将处理后的权限ID数组重新转换为以逗号分隔的字符串形式以便更新回角色的权限ID列表字段中保持数据格式的一致性符合数据库存储和业务逻辑的要求。
new_ps_ids_string = new_ps_ids.join(",");
role.ps_ids = new_ps_ids_string;
// 调用角色对象的 `save` 方法(这里假设角色对象有对应的保存方法,用于将更新后的角色信息保存回数据库,实现对角色权限列表的更新操作),将更新后的角色信息保存到数据库中。
// 该方法同样是一个异步操作,通过回调函数来处理保存操作完成后的结果情况,根据操作是否成功返回相应的信息给回调函数 `cb`。
role.save(function (err, newRole) {
// 如果在保存操作过程中出现错误(`err` 不为 `null`),比如数据库更新语句执行失败、违反数据约束等原因,就通过回调函数 `cb` 返回错误信息,表示删除权限失败,告知调用者操作未成功及原因。
if (err) return cb("删除权限失败");
// 如果保存操作成功,即角色的权限信息已成功更新,接着调用 `permissionAPIDAO` 模块的 `list` 方法,尝试获取权限数据,可能是为了重新整理和返回更新后的权限相关信息,具体取决于业务需求。
// 以下代码块是 `deleteRoleRight` 函数剩余部分的注释
});
});
}
// 如果权限数据获取成功将更新后的角色权限ID列表以逗号分隔的字符串形式再次进行分割得到权限ID数组用于后续构建权限相关的结果结构。
permissionIds = newRole.ps_ids.split(",");
// 使用 `lodash` 库的 `keyBy` 函数,将获取到的所有权限数据(`permissions`按照权限ID`ps_id`进行转换生成一个以权限ID为键对应权限详细信息为值的对象结构。
// 这样方便后续通过权限ID快速查找对应的权限详情在构建权限层级结构等操作中能更高效地获取所需信息。
var permissionKeys = _.keyBy(permissions, 'ps_id');
// 调用 `getPermissionsResult` 函数,传入整理好的权限键值对象(`permissionKeys`和当前角色更新后的权限ID数组`permissionIds`
// 该函数会根据这些信息构建出对应的权限层级结构信息,并返回结果,然后使用 `_.values` 获取结果对象中的值(即权限层级结构相关信息),最终通过回调函数 `cb` 返回这些信息给调用者,
// 调用者可以根据返回的权限相关信息进行后续的业务处理,比如展示角色最新的权限情况等操作。
return cb(null, _.values(getPermissionsResult(permissionKeys, permissionIds)));
// 整个 `deleteRoleRight` 函数结束的括号,对应函数开头的 `function(rid, deletedRightId, cb)`,表示该函数定义结束,主要实现了从角色的权限列表中删除指定权限,并重新整理和返回相关权限信息的功能。
});
});
}
/**
* 删除角色
* 此函数用于根据传入的角色ID从数据库中删除对应的角色记录通过回调函数返回操作结果成功则返回 `true`失败则返回相应错误信息给调用者
*
* @param {[type]} id 角色ID
* @param {Function} cb 回调函数
* @param {[type]} id 角色ID用于唯一标识要删除的角色应该为有效的数字类型由调用者传入以准确找到数据库中对应的角色记录进行删除操作
* @param {Function} cb 回调函数用于接收删除角色操作的结果若成功则传递 `true` 表示操作成功若失败则传递错误信息参数告知调用者操作出现的问题
*/
module.exports.deleteRole = function(id,cb){
if(!id) return cb("角色ID不能为空");
if(isNaN(parseInt(id))) return cb("角色ID必须为数字");
dao.destroy("RoleModel",id,function(err){
if(err) return cb("删除失败");
cb(null,true);
})
module.exports.deleteRole = function (id, cb) {
// 首先验证传入的角色ID是否存在如果不存在则通过回调函数返回错误信息表示角色ID不能为空因为没有角色ID无法确定要删除哪个角色的记录。
if (!id) return cb("角色ID不能为空");
// 进一步验证角色ID是否可以转换为数字类型如果不能转换成功即不是有效的数字则通过回调函数返回错误信息表示角色ID必须为数字以确保能在数据库中准确找到对应的角色记录进行删除因为通常角色ID在数据库中是以数字形式存储和使用的。
if (isNaN(parseInt(id))) return cb("角色ID必须为数字");
// 调用 `dao` 模块的 `destroy` 方法来执行删除角色的数据库操作。
// 第一个参数 `"RoleModel"` 指明要操作的数据模型(对应数据库中的数据表),确定要删除的是角色数据表中对应的记录。
// 第二个参数传入角色ID作为删除操作的条件让数据库删除对应ID的角色记录。
// 第三个参数是一个回调函数,用于处理删除操作完成后的结果情况,根据操作是否成功返回相应的信息给回调函数 `cb`。
dao.destroy("RoleModel", id, function (err) {
// 如果在删除操作过程中出现错误(`err` 不为 `null`),比如数据库删除语句执行失败、违反外键约束等原因,就通过回调函数 `cb` 返回错误信息,表示删除失败,告知调用者操作未成功及原因。
if (err) return cb("删除失败");
// 如果删除操作成功,通过回调函数 `cb` 返回 `true`,告知调用者角色已成功从数据库中删除,调用者可以根据此结果进行后续的业务处理,比如刷新相关的角色列表展示等操作。
cb(null, true);
})
}
/**
* 权限验证函数
* 该函数用于验证指定角色通过角色ID标识对于某个服务`serviceName`中的某个动作`actionName`是否具有相应的权限通过回调函数返回验证结果成功或失败给调用者
*
* @param {[type]} rid 角色ID
* @param {[type]} serviceName 服务名
* @param {[type]} actionName 动作名方法
* @param {Function} cb 回调函数
* @param {[type]} rid 角色ID用于唯一标识要验证权限的角色需要为有效的数字类型由调用者传入以确定操作的目标角色
* @param {[type]} serviceName 服务名代表系统中的某个服务模块用于确定权限验证的范围具体的服务名称由业务系统定义比如可能是 "用户管理服务""订单服务"
* @param {[type]} actionName 动作名方法表示在对应服务中具体的操作动作例如 "创建用户""查询订单" 用于精确验证角色对某个具体操作是否有权限
* @param {Function} cb 回调函数用于接收权限验证操作的结果若角色具有对应权限则传递 `true`若没有权限则传递 `false`若出现错误则传递相应的错误信息参数告知调用者验证过程出现的问题
*/
module.exports.authRight = function(rid,serviceName,actionName,cb) {
permissionAPIDAO.authRight(rid,serviceName,actionName,function(err,pass) {
cb(err,pass);
});
}
module.exports.authRight = function (rid, serviceName, actionName, cb) {
// 调用 `permissionAPIDAO` 模块的 `authRight` 方法来执行权限验证的具体业务逻辑这个方法内部应该会根据传入的角色ID、服务名和动作名等信息
// 去查询相关的权限数据(可能是数据库中的权限表等存储位置),判断该角色是否具备执行对应操作的权限,它同样是一个异步操作,通过回调函数来返回结果。
permissionAPIDAO.authRight(rid, serviceName, actionName, function (err, pass) {
// 直接将 `permissionAPIDAO.authRight` 方法回调函数中的结果(`err` 表示错误信息,`pass` 表示权限验证是否通过的布尔值),原封不动地通过外层的回调函数 `cb` 返回给调用者,
// 使得调用者可以获取到权限验证的最终结果以及可能出现的错误信息,以便进行后续的业务处理,比如根据权限情况决定是否允许用户执行某个操作等。
cb(err, pass);
});
}
//这段代码整体涵盖了角色相关操作(添加、获取详情、更新、授权、删除等)以及权限验证的功能,通过
//与相应的数据访问对象dao、permissionAPIDAO 等)交互,实现了对角色和权限信息在数据库层面
//的操作以及相关业务逻辑处理,在权限管理系统等应用场景中起着关键作用,保障了系统中不同角色对
//各项服务操作的权限控制。

@ -1,4 +1,13 @@
// 用户登录
module.exports.login = function(username,password,cb) {
console.log("登录 %s %s",username,password);
}
// 以下代码通过 `module.exports` 将一个名为 `login` 的函数暴露出去,使得其他模块可以引入并使用这个函数来实现用户登录相关的功能。
// `login` 函数接收三个参数,分别是 `username`(用户名)、`password`(密码)以及 `cb`(回调函数),用于处理用户登录的逻辑以及后续的结果反馈。
module.exports.login = function(username, password, cb) {
// 在函数内部,使用 `console.log` 打印出一条日志信息,用于记录当前正在进行登录操作以及对应的用户名和密码信息。
// 这在调试或者查看系统运行时的操作记录时会比较有用,可以直观地看到有哪些用户正在尝试登录系统。
// 这里使用了类似格式化字符串的方式,将 `username` 和 `password` 的值嵌入到日志信息中输出。
console.log("登录 %s %s", username, password);
}
//不过需要注意的是,目前这个 login 函数只是简单地打印了登录信息,并没有真正实现完整的登录逻辑,比
//如验证用户名和密码是否正确(通常需要与数据库或其他存储用户信息的地方进行交互比对),以及根据验
//证结果调用传入的回调函数 cb 返回相应的结果(比如成功登录返回用户信息、失败返回错误提示等)等操
//作。如果要使其成为一个实用的登录功能函数,还需要进一步补充完善相应的业务逻辑代码。
Loading…
Cancel
Save