// 引入lodash库，lodash是一个实用的JavaScript工具库，提供了许多便捷的函数来处理数组、对象、字符串等数据类型，帮助简化常见的编程任务，例如这里后续可能会用到它提供的对象和数组操作相关的方法。
var _ = require('lodash');
// 引入Node.js的path模块，主要用于处理文件路径相关的操作，像拼接、解析文件路径等，以便准确地引入其他模块所在的文件位置。
var path = require("path");
// 引入自定义的 `DAO` 模块，从代码中拼接的路径来看，它应该位于项目根目录下的 `dao/DAO` 文件中，这个模块大概率封装了与数据库操作相关的通用方法，例如查询、插入、更新等操作，用于不同数据模型的处理。
var dao = require(path.join(process.cwd(), "dao/DAO"));
// 引入自定义的 `PermissionAPIDAO` 模块，同样通过拼接路径的方式引入，位于 `dao/PermissionAPIDAO` 文件中，推测该模块主要负责与权限相关的数据访问操作，比如获取权限数据等功能。
var permissionAPIDAO = require(path.join(process.cwd(), "dao/PermissionAPIDAO"));

// 定义一个名为 `getPermissionsResult` 的函数，它的主要作用是根据传入的权限相关的键值和权限ID列表，来构建权限结果对象，这个对象将按照权限的层级结构（一、二、三级菜单对应的权限）进行组织。
function getPermissionsResult(permissionKeys, permissionIds) {
    // 创建一个空对象，用于存储最终整理好的权限结果，它将以权限ID为键，对应权限的详细信息（包含子权限信息等）为值进行存储。
    var permissionsResult = {};

    // 处理一级菜单
    // 遍历权限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`，用于在处理二级菜单权限时，暂时存储二级菜单权限的相关信息，后续会将这些信息整理到对应的一级菜单权限的 `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]);
            }
        }
    }

    // 处理三级菜单
    // 又一次遍历权限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 回调函数，用于接收获取角色和权限数据的操作结果，若操作成功则传递包含数据的参数，若失败则传递错误信息参数。
 */
module.exports.getAllRoles = function(cb) {
    // 调用 `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": []
                };

                // 调用 `getPermissionsResult` 函数，传入整理好的权限键值对象（`permissionKeys`）和当前角色的权限ID数组（`permissionIds`），
                // 该函数会根据这些信息构建出对应的权限层级结构信息，并返回结果，然后将返回的结果（权限层级结构信息）赋值给当前角色结果对象的 `children` 属性，
                // 这样就将角色信息和其对应的权限信息关联起来了，形成了包含角色和权限层级结构的完整信息对象。
                roleResult.children = _.values(getPermissionsResult(permissionKeys, permissionIds));

                // 将当前角色的完整信息对象添加到 `rolesResult` 数组中，完成一个角色及其权限信息的整理和存储，后续循环会处理其他角色信息，直到所有角色信息都处理完毕。
                rolesResult.push(roleResult);
            }

            // 当所有角色的信息以及对应的权限层级结构信息都整理完成后，通过回调函数 `cb` 返回整理好的结果数组（`rolesResult`），
            // 此时表示获取所有用户的角色和权限信息操作成功，调用者可以接收到完整的数据进行后续的业务处理，比如展示角色权限列表、进行权限验证等操作。
            cb(null, rolesResult);

        });

    });
}
//这段代码整体围绕获取用户角色和权限信息展开，先分别从不同的数据访问模块获取角色数据和权限数
//据，然后通过一系列处理（构建权限层级结构、关联角色和权限信息等），最终将整合好的结果通过回调
//函数返回给调用者，在权限管理相关的业务场景中具有重要作用，例如在系统后台展示不同用户角色所拥
//有的权限菜单等功能时会用到这样的代码逻辑。
/**
 * 添加角色
 * 此函数用于向系统中添加新的角色信息，接收角色相关的参数以及一个回调函数，根据参数验证和数据库操作的结果，通过回调函数返回相应的信息给调用者。
 * 
 * @param  {[type]}   params 包含角色信息的参数对象，预期包含角色名称（roleName）、角色描述（roleDesc）等相关信息，具体结构由业务需求决定。
 * @param  {Function} cb     回调函数，用于接收添加角色操作的结果，若操作成功则传递包含新添加角色详细信息的参数，若失败则传递错误信息参数。
 */
module.exports.createRole = function (params, cb) {
    // 首先验证传入的参数中角色名称（roleName）是否存在，如果不存在，则直接通过回调函数返回错误信息，表示角色名称不能为空，因为角色名称是角色的重要标识，不可或缺。
    if (!params.roleName) return cb("角色名称不能为空");
    // 如果传入的参数中角色描述（roleDesc）不存在，则将其默认设置为空字符串，说明角色描述在某些情况下可以为空，这里进行了一个默认值的处理。
    if (!params.roleDesc) params.roleDesc = "";

    // 调用 `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` 返回包含新创建角色详细信息的对象，包含角色ID（roleId）、角色名称（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 回调函数，用于接收获取角色详情操作的结果，若成功则传递包含角色详细信息的参数，若失败则传递错误信息参数。
 */
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` 返回包含角色详细信息的对象，包含角色ID（roleId）、角色名称（roleName）、角色描述（roleDesc）以及角色权限描述（rolePermissionDesc）等信息，方便调用者获取并使用这些详情信息。
        cb(null, {
            "roleId": role.role_id,
            "roleName": role.role_name,
            "roleDesc": role.role_desc,
            "rolePermissionDesc": role.ps_ca
        });
    });
}

/**
 * 更新角色信息
 * 此函数用于根据传入的角色相关参数，对已存在的角色信息进行更新操作，主要涉及更新角色名称和角色描述等信息，通过回调函数返回更新后的角色详细信息或者错误提示给调用者。
 * 
 * @param  {[type]}   params 包含要更新的角色信息的参数对象，预期包含角色ID（id）、角色名称（roleName）、角色描述（roleDesc）等相关信息，具体结构由业务需求决定。
 * @param  {Function} cb     回调函数，用于接收更新角色信息操作的结果，若成功则传递包含更新后角色详细信息的参数，若失败则传递错误信息参数。
 */
module.exports.updateRole = function (params, cb) {
    // 首先验证传入的参数是否存在，如果不存在，则直接通过回调函数返回错误信息，表示参数不能为空，因为没有参数无法确定要更新哪个角色以及更新哪些内容。
    if (!params) return cb("参数不能为空");
    // 接着验证参数中的角色ID（id）是否存在，如果不存在，则通过回调函数返回错误信息，表示角色ID不能为空，因为没有角色ID无法准确找到要更新信息的目标角色。
    if (!params.id) return cb("角色ID不能为空");
    // 进一步验证角色ID是否可以转换为数字类型，如果不能转换成功（即不是有效的数字），则通过回调函数返回错误信息，表示角色ID必须为数字，以确保能准确地在数据库中定位到对应的角色记录进行更新操作。
    if (isNaN(parseInt(params.id))) return cb("角色ID必须为数字");

    // 创建一个空对象，用于存储要更新的角色信息，后续会根据传入的参数情况，将需要更新的字段和对应的值添加到这个对象中，然后传递给数据库更新操作的方法。
    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"` 指明要操作的数据模型（对应数据库中的数据表），确定要更新的目标数据表。
    // 第二个参数传入角色ID，用于准确找到数据库中对应的角色记录进行更新。
    // 第三个参数传入 `updateInfo` 对象，包含了要更新的具体字段和对应的值，告知数据库要更新哪些信息。
    // 第四个参数是一个回调函数，用于处理更新操作完成后的结果情况，根据操作是否成功返回相应的信息给回调函数 `cb`。
    dao.update("RoleModel", params.id, updateInfo, function (err, newRole) {
        // 如果在更新操作过程中出现错误（`err` 不为 `null`），比如数据库更新语句执行失败、违反数据约束等原因，就通过回调函数 `cb` 返回错误信息，表示更新角色信息失败，告知调用者操作未成功及原因。
        if (err) return cb("更新角色信息失败");
        // 如果更新操作成功，通过回调函数 `cb` 返回包含更新后角色详细信息的对象，包含角色ID（roleId）、角色名称（roleName）、角色描述（roleDesc）以及角色权限描述（rolePermissionDesc）等信息，方便调用者获取更新后的角色详情进行后续操作。
        cb(null, {
            "roleId": newRole.role_id,
            "roleName": newRole.role_name,
            "roleDesc": newRole.role_desc,
            "rolePermissionDesc": newRole.ps_ca
        });
    });
}

/**
 * 对角色进行授权
 * 该函数用于更新角色的权限信息，根据传入的角色ID和权限列表，将权限信息更新到对应的角色记录中，通过回调函数返回更新后的角色相关信息或者错误提示给调用者。
 * 
 * @param  {[type]}   rid    角色ID，用于唯一标识要授权的角色，应该为有效的数字类型，由调用者传入，以确定操作的目标角色。
 * @param  {Function} rights 以 "," 分割的权限列表，通常是一串表示权限ID的字符串，用于更新角色所拥有的权限信息，格式由业务需求决定。
 * @param  {Function} cb     回调函数，用于接收更新角色权限操作的结果，若成功则传递包含更新后角色部分详细信息的参数，若失败则传递错误信息参数。
 */
module.exports.updateRoleRight = function (rid, rights, cb) {
    // 首先验证传入的角色ID（rid）是否存在，如果不存在，则通过回调函数返回错误信息，表示角色ID不能为空，因为没有角色ID无法确定要对哪个角色进行授权操作。
    if (!rid) return cb("角色ID不能为空");
    // 进一步验证角色ID是否可以转换为数字类型，如果不能转换成功（即不是有效的数字），则通过回调函数返回错误信息，表示角色ID必须为数字，确保能准确在数据库中定位到对应的角色记录进行权限更新操作。
    if (isNaN(parseInt(rid))) return cb("角色ID必须为数字");

    // 注意这里需要更新权限描述信息字段，目前暂时实现的逻辑如下（可能后续需要进一步完善或调整）。

    // 调用 `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` 返回包含更新后角色部分详细信息的对象，包含角色ID（roleId）、角色名称（roleName）等信息，方便调用者获取更新后的部分角色详情进行后续操作，这里返回的信息可根据实际业务需求进一步调整完善。
        cb(null, {
            "roleId": newRole.role_id,
            "roleName": newRole.role_name
        });
    });
}

/**
 * 删除权限
 * 此函数用于从角色的权限列表中删除指定的权限，涉及获取角色信息、处理权限列表、更新角色信息以及重新获取相关权限数据等操作，最后通过回调函数返回处理后的权限相关结果或者错误提示给调用者。
 * 
 * @param  {[type]}   rid            权限ID，这里可能是角色的相关ID，用于唯一标识要操作的角色，由调用者传入，以确定要删除权限的目标角色。
 * @param  {[type]}   deletedRightId 删除的权限ID，用于指定要从角色权限列表中删除的具体权限，应该为有效的数字类型，其格式和业务含义由系统的权限管理设计决定。
 * @param  {Function} cb             回调函数，用于接收删除权限操作的结果，若成功则传递包含处理后权限相关信息的参数，若失败则传递错误信息参数。
 */
module.exports.deleteRoleRight = function (rid, deletedRightId, cb) {
    // 调用 `daoModule`（这里可能是 `dao` 模块，也许是代码中的一个小笔误，具体要看实际的模块引用情况）的 `findOne` 方法，尝试从数据库中查找指定角色ID对应的角色信息。
    // 第一个参数 `"RoleModel"` 指明要操作的数据模型（对应数据库中的数据表），确定要查询的是角色数据表。
    // 第二个参数传入一个对象，其中 `"role_id"` 键对应的值为传入的角色ID（rid），以此作为查询条件，查找对应的角色记录。
    // 第三个参数是一个回调函数，用于处理查询操作完成后的结果情况，根据是否查询到数据以及是否出现错误等情况返回相应的信息给回调函数 `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 回调函数，用于接收删除角色操作的结果，若成功则传递 `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          回调函数，用于接收权限验证操作的结果，若角色具有对应权限则传递 `true`，若没有权限则传递 `false`，若出现错误则传递相应的错误信息参数，告知调用者验证过程出现的问题。
 */
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 等）交互，实现了对角色和权限信息在数据库层面
//的操作以及相关业务逻辑处理，在权限管理系统等应用场景中起着关键作用，保障了系统中不同角色对
//各项服务操作的权限控制。