Java 与 MySQL 的绝妙结合:打造高效审批流程
👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书福利
全栈前后端分离博客项目 1.0 版本完结啦,2.0 正在更新中..., 演示链接:http://116.62.199.48/ ,全程手摸手,后端 + 前端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,直到项目上线。目前已更新了170小节,累计28w+字,讲解图:1162张,还在持续爆肝中.. 后续还会上新更多项目,目标是将Java领域典型的项目都整一波,如秒杀系统, 在线商城, IM即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,已有640+小伙伴加入(早鸟价超低)
1流程思路分析
审批流程🐱💻
1.串行流程
当前节点审批完成后,下一次节点才能进行操作,例如经理通过之后,总监才能审批;
2.并行流程
一个审批节点需要多人联审。一般有两种方式:会签、或签;
会签:
注意:别跟串行审批混淆。会签的多个角色是平行的,没有上下级关系、前后顺序。
例如:在某项文件、合同、决策或其他重要事项上,需要多个相关人员进行确认、批准或签署的情况下,参与该过程的人员同时批准,这时会签就能很大程度上提高效率,顺便也能解决人情世故的问题~~。
会签支持并签:
业务模式支持:"全部投票"、"按投票比例"、"按投票通过比例"、支持设置 "百分比" 和 "分数" 两种方式。
或签(也有叫"竞签"、"串签"):指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,只要其中任意一人审批即可到下一审批节点;
3.条件流程
根据不同规则,走不同流程
例如报销5000以下直属领导审批就行,5000~10000需要总监审批。
4.混合流程
就是上述的流程混合运用;
例如请假的正常流程是到直属领导审批,3天以上需要总监审批。5天以上需要总裁审批。
审批动作🙋♀️
通过: 通过申请,流转到下一人。原因选填。 驳回: 驳回到发起人、驳回到上一环节、驳回到之前的某一环节 保存: 保存当前填写的信息。 转交: 转交给某人审批 加签: 处理者可以在审批时临时增加审核人员 抄送: 抄送人会知晓审核过程,但不进行操作
执行动作👩🎓
申请: 针对当前业务表单信息发起申请,开始审批流程的传递。分为2部分:由申请提交人手动发起申请、由程序自动判断满足触发规则的数据自动发起申请;另外还要注意的2点:是否允许提交人撤销(是、否)、记录编辑(不可编辑、管理员可编辑、管理员和审批人都可编辑 );
通过: 当前步骤处理通过,进入下一步骤,若为末步骤,则流程处理完成;
退回: 将步骤退回至上一步骤,即返回至上一处理人处,若为首步骤,则不进行退回;
否决: 将步骤直接结束,执行结束动作拒绝活动,不再进行操作,或者回退至第一步骤;
撤回: 若当前步骤已处理,下一处理人未处理的情况下可进行撤回操作。
节点状态🕵️♀️
提交人: 未提交、已提交、处理中、已结束。
处理人: 待处理、已处理。
创建业务工单: 提交人登录系统之后,选择想要发起的业务工单,填写业务工单。填写完成可以选择提交或者保存;
未提交: 列表中显示所有保存但未提交的业务工单,未提交列表中的业务工单都没有业务工单编号(唯一),状态为“未提交”。提交人可以选择某个业务工单后能方便对其进行修改、删除和提交;
已提交: 列表显示所有已经提交的业务工单,有业务工单编号,并显示(未处理)。提交后的业务工单进入处理流程,提交人无法进行修改和删除;
处理中: 列表显示所有提交并已经有节点处理的业务工单,提交人可以查询某个业务工单的处理进度;
已结束: 列表显示所有已经处理完成的业务工单;
待处理: 列表显示所有待处理业务工单;
已处理: 列表显示所有当前处理人已处理的业务工单,既被当前处理人流转到下一个流程节点的业务工单;
2UI预览🛹
3表设计🚧
流程配置表🚗
CREATE TABLE `approval_config` (
`approval_config_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花算法',
`corp_id` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '企业ID',
`node_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '节点名称',
`form_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '表单ID 属于那个表单的流程',
`approval_auto_pass` tinyint(1) DEFAULT '0' COMMENT '审批节点人员相同时自动通过[1:true;0:false]',
`current_node_approver_type` tinyint DEFAULT NULL COMMENT '审批人类型[1:发起人自己;2:指定角色;3:指定人员;4:表单内人员];注:1/3/4存userid、2存roleId',
`current_node_approver` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '待审批人如果是角色就是角色ID,如果是其他则是userId格式:[xxx,xxx]',
`care_of` tinyint(1) DEFAULT NULL COMMENT '允许审批人转交[1:true;2:false]',
`approval_type` tinyint DEFAULT NULL COMMENT '审批类型[1:会签:2:或签]',
`approval_node` int DEFAULT NULL COMMENT '审批节点[取值:1~N 从小到大;0:发起节点 、1:是第一个节点、 2:第二个节点 N:是第N个节点;最大的是结束节点]',
`carbon_copy_recipients_type` tinyint DEFAULT '1' COMMENT '抄送人类型[1:发起人自己;2:指定角色;3:指定人员;4:表单内人员]',
`carbon_copy_recipients` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '抄送人userId 数组格式',
`create_time` datetime DEFAULT NULL COMMENT '规则创建时间;默认拿最新的',
`group_id` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '分组[标识那些节点是同一个组的]',
`visible_fields` json DEFAULT NULL COMMENT '可见字段:[{"bt": false, "kj": true, "kx": true, "field": "create_time", "children": "purchase_requisition_details"}];\r\nkj:可见;kx:可写;kb:必填。如果是最后一个节点就需要单独拉一个配置',
PRIMARY KEY (`approval_config_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批流程节点规则配置表';
审批流程发起表🚓
CREATE TABLE `approval_info` (
`approval_info_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花算法',
`corp_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '企业ID',
`approval_config_group_id` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '规则表的groupID',
`form_id` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '表单ID 属于那个表单',
`founder` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '发起人',
`launch_time` datetime NOT NULL COMMENT '发起时间',
`end_state` tinyint(1) DEFAULT '0' COMMENT '是否结束流程[1是]',
`end_time` datetime DEFAULT NULL COMMENT '流程结束时间',
`object_id` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '关联某条数据',
`process_progress` int DEFAULT '0' COMMENT '用来记录整个流程进行到那个节点',
`record_node_history` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '记录历史经历节点,英文逗号分隔0,1,2,1,2,3 最后一个值和当前节点同步',
PRIMARY KEY (`approval_info_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批流程发起表';
审批记录表🚕
CREATE TABLE `approval_record` (
`approval_record_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花算法',
`corp_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '企业ID',
`approval_info_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '审批发起表approval_info',
`form_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '表单ID 属于那个表单的流程',
`approver_user_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '审批人or 转交人 userId',
`approver_time` datetime NOT NULL COMMENT '审批时间',
`approver_opinions` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '审批意见',
`approver_result` tinyint NOT NULL COMMENT '审批结果[1:同意;2:拒绝:3:转交]',
`transferee` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '被转交人userId;approver_result=3时必填',
`transferee_text` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '转交备注(此字段暂时无用)',
`accessory_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '附件数组',
`approver_node` tinyint NOT NULL COMMENT '属于个节点的审批记录',
`approver_count` tinyint DEFAULT '1' COMMENT '审批次数默认1; 例:当节点B是会签,且有人同意,有人拒绝,当拒绝后会返回上一个节点A。当再次进入节点B时,用来区分,此审批记录是第一次记录还是第二次审批记录或者第N次',
PRIMARY KEY (`approval_record_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批记录表';
抄送记录表🛺
CREATE TABLE `approval_carbon_copy` (
`carbon_copy_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '雪花',
`corp_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '企业ID',
`form_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '属于那个表单',
`approval_info_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '推送那条审批的ID',
`user_id` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT '接收抄送人',
`create_time` datetime NOT NULL COMMENT '抄送时间',
`read` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已读[1:已读;0:未读]',
`approval_node` tinyint NOT NULL COMMENT '那个节点抄送的',
PRIMARY KEY (`carbon_copy_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='审批抄送记录表';
4思路👩🎓👩🎓
流程配置
1.通过流程节点规则配置表,配置每个节点的审批人、抄送人、审批规则、可见、可写、必填字段的规则等(可以给不同的表单配置不同的审批规则)。
2.配置完毕即可,每次新增数据,读取流程规则配置表,生成一条审批流程发起记录,记录发起人,发起时间,关联某条流程规则(旧数据还是使用旧流程),流程当前节点等。
3.每个节点的审批人、抄送人、可见、可写、必填字段都是根据流程规则配置表中动态配置。
5代码🥇
审批按钮
@Transactional(rollbackFor = Exception.class)
public ResultUtils approval(String token, ApprovalDTO param) {
String corpId = TokenUtils.getCorpId(token);
String userId = TokenUtils.getUserId(token);
LocalDateTime time = LocalDateTime.now();
// 找到当前数据待审批节点,是否需要自己审批,或者已经审批过
ApprovalInfo info = approvalInfoMapper.selectOne(new QueryWrapper<ApprovalInfo>().eq("corp_id", corpId).eq("object_id", param.getObjectId())
.eq("form_id", param.getFormId()).select("approval_info_id", "process_progress", "record_node_history", "end_state",
"approval_config_group_id","founder"));
Assert.isFalse(info.getEndState(), ErrorMsg.msg18);
Integer currentNode = info.getProcessProgress();// 当前节点
// 每个节点的审批设置
List<ApprovalConfig> approvalConfigs = approvalConfigMapper.selectList(new QueryWrapper<ApprovalConfig>().eq("corp_id", corpId)
.eq("group_id", info.getApprovalConfigGroupId())
.eq("form_id", param.getFormId()).select("approval_auto_pass", "current_node_approver_type", "visible_fields",
"current_node_approver", "care_of", "approval_type", "approval_node", "carbon_copy_recipients_type", "carbon_copy_recipients"));
Map<Integer, ApprovalConfig> configMap = approvalConfigs.stream().collect(Collectors.toMap(ApprovalConfig::getApprovalNode, ApprovalConfig -> ApprovalConfig));
ApprovalConfig config = configMap.get(info.getProcessProgress());
List<String> historyNode = Lists.newArrayList(info.getRecordNodeHistory().split(","));
// 历史节点需要剔除最后一个
historyNode.remove(historyNode.size() - 1);
Bag bag = new HashBag(historyNode);
int count = bag.getCount(currentNode.toString());// 这个节点历史是否出现过
count = count == 0 ? 1 : (count + 1); // 用于标注这个节点是否多次审批
if (param.getType() == 3) {
// 转交
ApprovalRecord record = new ApprovalRecord();
record.setApprovalRecordId(SnowFlakeUtil.getDefaultSnowFlakeId() + "");
record.setCorpId(corpId);
record.setApprovalInfoId(info.getApprovalInfoId());
record.setFormId(param.getFormId());
record.setApproverUserId(userId);
record.setApproverTime(time);
record.setApproverOpinions(param.getMessage());
record.setApproverResult(param.getType());
record.setTransferee(param.getTransfereeUserId());
if (ObjectUtil.isNotEmpty(param.getAccessoryUrl())) {
record.setAccessoryUrl(JSONUtil.toJsonStr(param.getAccessoryUrl()));
}
record.setApproverNode(info.getProcessProgress().byteValue());
record.setApproverCount(new Byte(count + ""));
approvalRecordMapper.insertSelective(record);
return ResultUtils.success();
}
ApprovalRecord records = approvalRecordMapper.selectOne(new QueryWrapper<ApprovalRecord>()
.eq("corp_id", corpId).eq("form_id", param.getFormId())
.eq("approver_user_id", userId).eq("approval_info_id", info.getApprovalInfoId())
.eq("approver_node", currentNode).eq("approver_count", count));
Assert.isFalse(ObjectUtil.isNotEmpty(records) && StrUtil.isNotBlank(records.getTransferee()), ErrorMsg.msg29);
Assert.isFalse(ObjectUtil.isNotEmpty(records), ErrorMsg.msg16);
// 查询是否是被转交人
List<String> transferees = approvalRecordMapper.findTransferee(corpId, param.getFormId(), info.getApprovalInfoId(), currentNode, count);
if (CollUtil.isEmpty(transferees)) {
// 1.是否需要自己审批
if (config.getCurrentNodeApproverType() == 2) {
// 指定角色
// 查询自己拥有那些角色
List<UserRole> userRoles = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", userId).eq("corp_id", corpId)
.select("role_id"));
List<String> roleIds = userRoles.stream().map(key -> key.getRoleId()).collect(Collectors.toList());
List<Integer> currentNodeApproverRoleId = JSONUtil.toList(config.getCurrentNodeApprover().toString(), Integer.class);
ArrayList<String> integers = new ArrayList<>(roleIds);
boolean b = integers.retainAll(currentNodeApproverRoleId);// 存在交集则返回true
Assert.isFalse(!b, ErrorMsg.msg17);
} else if (config.getCurrentNodeApproverType()==3){
// 指定人员 用户ID
List<String> currentNodeApproverUserId = JSONUtil.toList(config.getCurrentNodeApprover().toString(), String.class);
boolean contains = currentNodeApproverUserId.contains(userId);
Assert.isFalse(!contains, ErrorMsg.msg17);
} else if (config.getCurrentNodeApproverType() == 1) {
// 发起人自己
Assert.isFalse(!info.getFounder().equals(userId), ErrorMsg.msg17);
}
}
if (param.getType() == 2) {
// 拒绝
approvalRefuse(info, approvalConfigs, param, userId, corpId, count, time);
return ResultUtils.success();
}
// 判断了需要自己审批之后,先编辑数据,然后在进行审批操作
JSONObject paramData = param.getMainData();
approvalEditData(corpId, paramData, time, userId, param.getFormId());
// 进行审批操作
if (param.getType() == 1) {
// 同意
approvalAgreeing(currentNode, info, configMap, param, userId, corpId, time, param.getObjectId());
}
return ResultUtils.success();
}
审批按钮-拒绝
/**
* 审批按钮-拒绝
*
* @param info 当前数据的审批详情
* @param approvalConfigs 审批规则
* @param param 参数
* @param userId 当前审批人id
* @param corpId 企业id
* @param count 审批次数
*/
private void approvalRefuse(ApprovalInfo info, List<ApprovalConfig> approvalConfigs, ApprovalDTO param, String userId, String corpId, int count, LocalDateTime time) {
// 生成审批记录
ApprovalRecord record = new ApprovalRecord();
record.setApprovalRecordId(SnowFlakeUtil.getDefaultSnowFlakeId() + "");
record.setCorpId(corpId);
record.setApprovalInfoId(info.getApprovalInfoId());
record.setFormId(param.getFormId());
record.setApproverUserId(userId);
record.setApproverTime(time);
record.setApproverOpinions(param.getMessage());
record.setApproverResult(param.getType());
if (ObjectUtil.isNotEmpty(param.getAccessoryUrl())) {
record.setAccessoryUrl(JSONUtil.toJsonStr(param.getAccessoryUrl()));
}
record.setApproverNode(info.getProcessProgress().byteValue());
record.setApproverCount(new Byte(count + ""));
approvalRecordMapper.insertSelective(record);
// 回滚上一个节点
info.setProcessProgress(info.getProcessProgress() - 1);
info.setRecordNodeHistory(info.getRecordNodeHistory() + "," + info.getProcessProgress());
// info.setCurrentState(1);
approvalInfoMapper.updateByPrimaryKeySelective(info);
if (info.getProcessProgress() == 0) {
// 如果回到第一个节点,数据状态则变成初始
String formCode = fromConfigMapper.findFormCode(corpId, param.getFormId());
commonMapper.updateDataState(formCode, 0, param.getObjectId(), corpId);
}
}
审批按钮-同意
/**
* 审批按钮-同意
*
* @param currentNode 处理的当前节点
* @param info 流程详情
* @param configMap 配置集合 key=节点;val=配置
* @param param 参数
* @param userId 当前审批人userId
* @param corpId 企业ID
* @param time 当前时间
*/
private void approvalAgreeing(Integer currentNode, ApprovalInfo info, Map<Integer, ApprovalConfig> configMap,
ApprovalDTO param, String userId, String corpId, LocalDateTime time, String objectId) {
// 查询这个节点以前是否审批过
List<String> historyNode = Lists.newArrayList(info.getRecordNodeHistory().split(","));// 历史节点需要剔除最后一个
historyNode.remove(historyNode.size() - 1);
Bag bag = new HashBag(historyNode);
int count = bag.getCount(currentNode.toString());// 这个节点历史是否出现过
count = count == 0 ? 1 : count + 1; // 用于标注这个节点是否多次审批
// 生成审批记录
ApprovalRecord record2 = new ApprovalRecord();
record2.setApprovalRecordId(SnowFlakeUtil.getDefaultSnowFlakeId() + "");
record2.setCorpId(corpId);
record2.setApprovalInfoId(info.getApprovalInfoId());
record2.setFormId(param.getFormId());
record2.setApproverUserId(userId);
record2.setApproverTime(time);
record2.setApproverOpinions(param.getMessage());
record2.setApproverResult(param.getType());
if (ObjectUtil.isNotEmpty(param.getAccessoryUrl())) {
record2.setAccessoryUrl(JSONUtil.toJsonStr(param.getAccessoryUrl()));
}
record2.setApproverNode(currentNode.byteValue());
record2.setApproverCount(new Byte(count + ""));
approvalRecordMapper.insertSelective(record2);
// 获取当前节点配置
ApprovalConfig currentConfig = configMap.get(currentNode);
if (currentConfig.getApprovalType() == 1) {// 1会签
// 判断是否是最后一个审批的,如果不是return出去
List<String> userIds = null;
if (currentConfig.getCurrentNodeApproverType() == 2) {
// 角色id
// 查询自己拥有那些角色
List<UserRole> userRoles = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", userId)
.eq("corp_id", corpId).select("user_id"));
userIds = userRoles.stream().map(key -> key.getUserId()).collect(Collectors.toList());
} else if (currentConfig.getCurrentNodeApproverType()==3){
// 用户ID
userIds = JSONUtil.toList(currentConfig.getCurrentNodeApprover().toString(), String.class);
} else if (currentConfig.getCurrentNodeApproverType() == 1) {
// 发起人自己
userIds = Arrays.asList(info.getFounder());
}
// 查询已经审批的人!=待审批人数则不是最后一个人
// 1.查询已经审批的人数
Integer count1 = approvalRecordMapper.selectCount(new QueryWrapper<ApprovalRecord>().eq("corp_id", corpId).eq("approval_info_id", info.getApprovalInfoId())
.eq("form_id", param.getFormId()).eq("approver_node", currentNode).eq("approver_count", count));
if (userIds.size() != count1) {
return;// 不是最后一个可以退出
}
}
Integer nextNode = currentNode + 1;
// 更新流程信息
info.setProcessProgress(nextNode);
info.setRecordNodeHistory(info.getRecordNodeHistory() + "," + info.getProcessProgress());
// info.setCurrentState(2);
// 到这里如果不是或签,就是会签是最后一个人同意可以判断进入下一个节点
// 判断下一个节点是不是最后一个节点,如果是可以结束节点了,不是则继续往下递归
if ((configMap.keySet().size() - 1) == nextNode) {
info.setEndTime(time);
info.setEndState(true);// 结束流程
approvalInfoMapper.updateByPrimaryKeySelective(info);
// 数据状态变成生效
String formCode = fromConfigMapper.findFormCode(corpId, param.getFormId());
commonMapper.updateDataState(formCode, 2, objectId, corpId);
return;
}
approvalInfoMapper.updateByPrimaryKeySelective(info);
// 校验下一个配置是否需要审批
ApprovalConfig nextConfig = configMap.get(nextNode);// 下一个节点的配置
List<RuleVO> rule = JSONUtil.toList(JSONUtil.parseArray(nextConfig.getVisibleFields()), RuleVO.class);
for (RuleVO ruleVO : rule) {
if (ruleVO.getKx()) {
return;// 判断是否开了可写,如果开了可写,不管有没有开相同审批人自动通过,都不能往下走
}
}
if (nextConfig.getApprovalAutoPass()) {
// 开了 审批人员相同自动通过
// 1.是否需要自己审批
if (nextConfig.getCurrentNodeApproverType() == 2) {
// 角色id
// 查询自己拥有那些角色
List<UserRole> userRoles = userRoleMapper.selectList(new QueryWrapper<UserRole>().eq("user_id", userId).eq("corp_id", corpId).select("role_id"));
List<String> roleIds = userRoles.stream().map(key -> key.getRoleId()).collect(Collectors.toList());
List<Integer> currentNodeApproverRoleId = JSONUtil.toList(nextConfig.getCurrentNodeApprover().toString(), Integer.class);
ArrayList<String> integers = new ArrayList<>(roleIds);
boolean b = integers.retainAll(currentNodeApproverRoleId);// 存在交集返回true
if (!b) return;
} else {
// 用户ID
List<String> currentNodeApproverUserId = JSONUtil.toList(nextConfig.getCurrentNodeApprover().toString(), String.class);
boolean contains = currentNodeApproverUserId.contains(userId);
if (!contains) return;
}
// 需要自己审批
approvalAgreeing(nextNode, info, configMap, param, userId, corpId, time, objectId);
}
// approvalRecordMapper.insertSelective(record2);
}
合并权限(如果最后一个节点存在多个自定义权限组,就需要合并)
/**
* 合并权限组
*
* @param roleIds 当前用户拥有的角色
* @param dbPowerGroup 自定义权限组
*/
private List<RuleVO> mergePowerGroup(List<String> roleIds, List<PowerGroup> dbPowerGroup) {
List<RuleVO> result = new ArrayList<>();
// 判断当前自定义权限组是否包含 当前用户的角色
for (PowerGroup power : dbPowerGroup) {
List<Integer> dbRoleIds = JSONUtil.toList(power.getRoleId().toString(), Integer.class);
List<String> retainAll = new ArrayList<>(roleIds);
retainAll.retainAll(dbRoleIds);
if (retainAll.size() != 0) {// 存在交集,证明这个自定义权限组有当前操作用户
List<RuleVO> rule = JSONUtil.toList(JSONUtil.parseArray(power.getVisibleFields()), RuleVO.class);
Map<String, RuleVO> tempMapDB = rule.stream().collect(Collectors.toMap(ruleVo -> ruleVo.getChildren() + ruleVo.getField(), RuleVO -> RuleVO));
if (CollUtil.isEmpty(result)) {
result = rule;
} else {
Map<String, RuleVO> tempListMap = result.stream().collect(Collectors.toMap(ruleVo -> ruleVo.getChildren() + ruleVo.getField(), RuleVO -> RuleVO));
if (tempMapDB.keySet().size() > result.size()) {// 如果B权限组字段比A权限组多,就拿多的一方进行循环
for (RuleVO item : rule) {
RuleVO ruleVO = tempListMap.get(item.getChildren() + item.getField());
if (ruleVO.getBt()) {
item.setBt(ruleVO.getBt());
}
if (ruleVO.getKj()) {
item.setKj(ruleVO.getKj());
}
if (ruleVO.getKx()) {
item.setKx(ruleVO.getKx());
}
}
result = rule;
} else {
// 否则就拿A权限组遍历
for (RuleVO item : result) {
// 合并组成新的规则,如果A规则为true,B规则为false,则取true的一方
RuleVO ruleDB = tempMapDB.get(item.getChildren() + item.getField());
if (ruleDB.getBt()) {
item.setBt(ruleDB.getBt());
}
if (ruleDB.getKj()) {
item.setKj(ruleDB.getKj());
}
if (ruleDB.getKx()) {
item.setKx(ruleDB.getKx());
}
}
}
}
}
}
return result;
}
👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书福利
全栈前后端分离博客项目 1.0 版本完结啦,2.0 正在更新中..., 演示链接:http://116.62.199.48/ ,全程手摸手,后端 + 前端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,直到项目上线。目前已更新了170小节,累计28w+字,讲解图:1162张,还在持续爆肝中.. 后续还会上新更多项目,目标是将Java领域典型的项目都整一波,如秒杀系统, 在线商城, IM即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,已有640+小伙伴加入(早鸟价超低)
1. 我的私密学习小圈子~
最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。
PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。
点“在看”支持小哈呀,谢谢啦