使用背景:
如果你觉得使用activity工作流很繁琐,或者觉得接口对接很麻烦,那么你需要一套自定义的简易工作流,它能实现工作流已有的核心部分功能,自己数据库里面创建工作流表,可以横向扩展,你想审批就审批,想随时驳回就驳回,日志自己记录。。。。一切自己动手,那么直接上代码:这里的代码是部分代码,里面缺失的部分自行处理,但关注的还是这个实现逻辑,只有了解的实现逻辑用起来才会更顺手。
简单说明一下:枚举控制流程模板,然后自己建表实现工作流相关的功能;
建表语句:
工作流程信息表flow_info:
flow_id:流程id
flow_name:流程名称
flow_node_code_path:流程路径(节点code集合,逗号拼接)
flow_status:当前流程状态[1.发起,2.审批中,3.审批结束,4.被驳回,5.挂起]
..........
工作流程信息表flow_node:
flow_node_id:流程节点id
flow_node_code:流程节点code
flow_node_name:流程节点名称
flow_info_id:工作流程id
flow_node_approve_users:流程节点审批人集合,逗号隔开
flow_approve_param:流程节点审批条件
flow_node_status:流程节点状态[1.开始,2.审批中,3.审批完成]
..........
工作流程信息表flow_record:
flow_record_id:流程日志id
flow_info_id:工作流程id
flow_node_code:流程节点code
flow_record_type:流程日志操作类型[1.发起流程类型,2.审批类型,3.驳回类型,4.流程挂起类型]
flow_record_content:流程日志内容
..........
模板类:这里是核心模板流程图,里面配置了你这个流程图所有的节点信息,和节点的信息和参数配置,并在自己的init方法中设置好网关(判断条件的节点条件参数);
@Slf4j
public enum ApproveFlowEnum implements IWfNodeBaseEnum {
START("approve_01", "流程节点开始", null, "approve_02", null, "start"),
HEAD_APPROVE("approve_02", "组长审批", 1, "approve_03", null, "node"),
PERSONAL_APPROVE("approve_03", "人事审批", 1, "approve_04", null, "node"),
PRESIDENT_APPROVE("approve_04", "总经理审批", 1, "approve_05", null, "node"),
END("approve_05", "流程节点结束", 1, null, null, "end");
private final ApproveFlowEnum[] approveFlowEnums = ApproveFlowEnum.values();
private Map<String, ApproveFlowEnum> flowCodeEnumMap;
/**
* nodeCode:当前节点code(唯一)
* nodeName:当前节点名称
* nodeApproveParam:设置当前节点需要达到几个人审批才算通过
* nextNodeCode:下一个节点的code
* nextNodeMap:下一个节点的信息(这里是记录有判断条件的下一个节点信息,在PostConstruct中去配置,或者在构造方法中去设置)
* nodeDesc:当前节点标识(主要表示用于起点和终点的判断,当然后期也可以维护成很多判断条件,但是终点的end标记很重要,用于判断该流程是否已经结束)
*/
private String nodeCode;
private String nodeName;
private Integer nodeApproveParam;
private String nextNodeCode;
private Map<String, String> nextNodeMap;
private String nodeDesc;
ApproveFlowEnum(String nodeCode, String nodeName, Integer nodeApproveParam, String nextNodeCode, Map<String, String> nextNodeMap,
String nodeDesc) {
this.nodeCode = nodeCode;
this.nodeName = nodeName;
this.nodeApproveParam = nodeApproveParam;
this.nextNodeCode = nextNodeCode;
this.nextNodeMap = nextNodeMap;
this.nodeDesc = nodeDesc;
}
/**
* 核心配置(这块内容可以在PostConstruct配置,也可以在构造函数中设置)
* 用于构建流程控制语句的流转规则
* 如果是一条直线简单流程,那么这里不需要设置(这里只配置流程判断条件情况)
* 某个节点的nextNodeMap的条件语句(类似于在画流程图的时候网关设置判断流转参数)
*/
@PostConstruct
public void init() {
for (ApproveFlowEnum approveFlowEnum : approveFlowEnums) {
//这里手动设置有需要判断的节点参数设置(类似于网关节点)
if (ObjectUtils.isEmpty(approveFlowEnum.getNextNodeCode())) {
if ("approve_02".equals(approveFlowEnum.getNodeCode())) {
Map<String, String> map = new HashMap<>();
map.put("1", "approve_02");
approveFlowEnum.setNextNodeMap(map);
}
}
}
flowCodeEnumMap = Arrays.stream(approveFlowEnums)
.collect(Collectors.toMap(ApproveFlowEnum::getNodeCode, Function.identity()));
log.info("审批工作流初始化完成++++++++++++++++++++++++++");
}
@Override
public IWfNodeBaseEnum getEnumByNodeCode(String nodeCode) {
return flowCodeEnumMap.get(nodeCode);
}
@Override
public List<IWfNodeBaseEnum> getAllEnumInfo() {
ApproveFlowEnum[] approveFlowEnums = ApproveFlowEnum.values();
return Arrays.asList(approveFlowEnums);
}
@Override
public String getNodeCode() {
return nodeCode;
}
public void setNodeCode(String nodeCode) {
this.nodeCode = nodeCode;
}
@Override
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
@Override
public String getNodeDesc() {
return nodeDesc;
}
@Override
public Integer getNodeApproveParam() {
return nodeApproveParam;
}
public void setNodeApproveParam(Integer nodeApproveParam) {
this.nodeApproveParam = nodeApproveParam;
}
@Override
public String getNextNodeCode(String nodeCode) {
return flowCodeEnumMap.get(nodeCode).getNodeCode();
}
@Override
public String getNextNodeCode() {
return nextNodeCode;
}
public void setNextNodeCode(String nextNodeCode) {
this.nextNodeCode = nextNodeCode;
}
@Override
public Map<String, String> getNextNodeMap() {
return nextNodeMap;
}
public void setNextNodeMap(Map<String, String> nextNodeMap) {
this.nextNodeMap = nextNodeMap;
}
public void setNodeDesc(String nodeDesc) {
this.nodeDesc = nodeDesc;
}
}
父级模板模式的借口限定借口类:主要定义工作流中涉及到的方法,比如初始化、驳回、审批、挂起等等场景方法,其数据信息都在对应的子类中:
/**
* 工作流包装类
*
* @author IT701820-tp
*/
public interface IWfNodeBaseEnum {
/**
* 获取初始化第一个节点信息
*
* @param nodeCode 节点code
* @return 枚举信息
*/
IWfNodeBaseEnum getEnumByNodeCode(String nodeCode);
/**
* 获取节点名称
*
* @return 节点值
*/
String getNodeName();
/**
* 获取节点审批条件参数
*
* @return 参数值(满足几个人才算审批通过)
*/
Integer getNodeApproveParam();
/**
* 获取下一节点code
*
* @param nodeCode 当前节点
* @return 节点值
*/
String getNextNodeCode(String nodeCode);
/**
* 获取下一节点枚举信息
*
* @param nodeCode 当前节点
* @param param 有网关参数的时候的参数配置(可以为null)
* @return 枚举信息值
*/
default IWfNodeBaseEnum getNextNodeEnum(String nodeCode, String param) {
List<IWfNodeBaseEnum> allEnumInfo = getAllEnumInfo();
Map<String, IWfNodeBaseEnum> flowCodeEnumMap = allEnumInfo.stream()
.collect(Collectors.toMap(IWfNodeBaseEnum::getNodeCode, Function.identity()));
IWfNodeBaseEnum nextNodeEnum = getNextNodeEnum(nodeCode);
if (!ObjectUtils.isEmpty(nextNodeEnum)) {
return nextNodeEnum;
}
//获取当前节点信息
IWfNodeBaseEnum approveFlowEnum = flowCodeEnumMap.get(nodeCode);
Map<String, String> nextNodeMap = approveFlowEnum.getNextNodeMap();
String nextNodeCode = nextNodeMap.get(param);
return flowCodeEnumMap.get(nextNodeCode);
}
/**
* 获取所有枚举信息
*
* @return 枚举信息
*/
List<IWfNodeBaseEnum> getAllEnumInfo();
/**
* 获取节点code
*
* @return 节点值
*/
String getNodeCode();
/**
* 获取下一节点枚举信息(没有参数的获取方式,直接流转到下一个流程)
*
* @param nodeCode 当前节点
* @return 枚举信息值
*/
default IWfNodeBaseEnum getNextNodeEnum(String nodeCode) {
List<IWfNodeBaseEnum> allEnumInfo = getAllEnumInfo();
Map<String, IWfNodeBaseEnum> flowCodeEnumMap = allEnumInfo.stream()
.collect(Collectors.toMap(IWfNodeBaseEnum::getNodeCode, Function.identity()));
//获取当前节点信息
IWfNodeBaseEnum approveFlowEnum = flowCodeEnumMap.get(nodeCode);
String nextNodeCode = approveFlowEnum.getNextNodeCode();
if (!ObjectUtils.isEmpty(nextNodeCode)) {
return flowCodeEnumMap.get(nextNodeCode);
}
return null;
}
/**
* 获取当前枚举的下一个code(带有条件的)
*
* @return 节点值
*/
Map<String, String> getNextNodeMap();
/**
* 获取当前枚举的下一个code
*
* @return 节点值
*/
String getNextNodeCode();
/**
* 获取初始化第一个节点信息
*
* @return 枚举信息
*/
default IWfNodeBaseEnum getInitEnum() {
List<IWfNodeBaseEnum> allEnumInfo = getAllEnumInfo();
for (IWfNodeBaseEnum iWfNodeBaseEnum : allEnumInfo) {
if ("start".equals(iWfNodeBaseEnum.getNodeDesc())) {
return iWfNodeBaseEnum;
}
}
return null;
}
/**
* 获取节点标志(开始节点,审批节点,结束节点)
*
* @return 节点标志值
*/
String getNodeDesc();
}
具体的业务实现类:
/**
* 工作流操作业务类
*
* @author IT701820-tp
*/
@Service
@Slf4j
public class FlowInfoService {
@Resource
FlowInfoMapper flowInfoMapper;
@Resource
FlowNodeMapper flowNodeMapper;
@Resource
FlowRecordMapper flowRecordMapper;
@Resource
PtlTodoTaskMapper ptlTodoTaskMapper;
@Resource
SysUserMapper sysUserMapper;
@Resource
SysYhtUserSyncMapper sysYhtUserSyncMapper;
@Resource
private ApiService apiService;
@Value("${yht.sys.approve.schema}")
private String schema;
/**
* 1.新增flowInfo表信息(开始状态);
* 2.新增flowNodeInfo表信息,把该流程对应的所有节点信息初始化表中,并设置第一个节点的审批人信息和状态,和下一个节点发送代办信息;
* 3.新增flowRecordInfo表信息,新增一条流程开始日志。
*
* @param approveFlowDto: flowName 流程名称
* userList 下个节点的审批人集合
* nextAction 一事通代办的跳转页面地址
* recordContent 流程节点的日志信息
*/
@Transactional(rollbackFor = Exception.class)
public FlowInfoEntity initFlow(Class<IWfNodeBaseEnum> enumClass, ApproveFlowDto approveFlowDto)
throws InstantiationException, IllegalAccessException {
//保存流程信息
IWfNodeBaseEnum iWfNodeBaseEnum = enumClass.newInstance();
IWfNodeBaseEnum initEnum = iWfNodeBaseEnum.getInitEnum();
FlowInfoEntity flowInfoEntity = new FlowInfoEntity();
flowInfoEntity.setFlowId(UUIDUtil.getUUIDKey());
flowInfoEntity.setFlowName(approveFlowDto.getFlowName());
flowInfoEntity.setFlowNodeCodePath(initEnum.getNodeCode());
flowInfoEntity.setFlowStatus(FlowConstants.FLOW_BEGIN);
flowInfoEntity.setCreatorId("370124");
flowInfoEntity.setCreatedTime(new Date());
flowInfoMapper.insertSelective(flowInfoEntity);
//保存流程节点信息
List<FlowNodeEntity> nodeEntityList = new ArrayList<>();
List<IWfNodeBaseEnum> wfNodeBaseEnumList = iWfNodeBaseEnum.getAllEnumInfo();
String firstNodeCode = null;
for (IWfNodeBaseEnum wfNodeBaseEnum : wfNodeBaseEnumList) {
FlowNodeEntity flowNodeEntity = new FlowNodeEntity();
flowNodeEntity.setFlowNodeId(UUIDUtil.getUUIDKey());
flowNodeEntity.setFlowNodeCode(wfNodeBaseEnum.getNodeCode());
flowNodeEntity.setFlowInfoId(flowInfoEntity.getFlowId());
if (FlowConstants.FLOW_NODE_STATUS_START.equals(wfNodeBaseEnum.getNodeDesc())) {
firstNodeCode = wfNodeBaseEnum.getNodeCode();
}
//只针对下一个节点设置发起待办
if (!ObjectUtils.isEmpty(firstNodeCode)) {
String nextNodeCode = wfNodeBaseEnum.getNextNodeEnum(firstNodeCode).getNodeCode();
if (nextNodeCode.equals(wfNodeBaseEnum.getNodeCode())) {
//仅限于初始化第一个节点的审批人
flowNodeEntity.setFlowNodeApproveUsers(StringUtils.join(approveFlowDto.getUserList(), ","));
//将这些审批人userList发送待办
executeTodoTask(approveFlowDto.getUserList(), flowInfoEntity, wfNodeBaseEnum, approveFlowDto.getNextAction());
firstNodeCode = null;
}
}
flowNodeEntity.setFlowNodeName(wfNodeBaseEnum.getNodeName());
flowNodeEntity.setFlowApproveParam(wfNodeBaseEnum.getNodeApproveParam());
//只对开始的节点修改状态为已完成
if (FlowConstants.FLOW_NODE_STATUS_START.equals(wfNodeBaseEnum.getNodeDesc())) {
flowNodeEntity.setFlowNodeStatus(FlowConstants.FLOW_NODE_DONE);
} else {
flowNodeEntity.setFlowNodeStatus(FlowConstants.FLOW_NODE_APPROVE);
}
nodeEntityList.add(flowNodeEntity);
}
flowNodeMapper.insertList(nodeEntityList);
//记录流程日志
FlowRecordEntity flowRecord = new FlowRecordEntity();
flowRecord.setFlowRecordId(UUIDUtil.getUUIDKey());
flowRecord.setFlowInfoId(flowInfoEntity.getFlowId());
List<IWfNodeBaseEnum> iWfNodeBaseEnumList = wfNodeBaseEnumList.stream()
.filter(s -> FlowConstants.FLOW_NODE_STATUS_START.equals(s.getNodeDesc())).collect(Collectors.toList());
flowRecord.setFlowNodeCode(iWfNodeBaseEnumList.get(0).getNodeCode());
flowRecord.setFlowRecordType(FlowConstants.FLOW_RECORD_START);
flowRecord.setFlowRecordContent(approveFlowDto.getRecordContent());
flowRecord.setCreatorId("370124");
flowRecord.setCreatedTime(new Date());
flowRecordMapper.insert(flowRecord);
return flowInfoEntity;
}
/**
* 发布代办信息
*/
private void executeTodoTask(List<String> userList, FlowInfoEntity flowInfoEntity, IWfNodeBaseEnum wfNodeBaseEnum, String nextAction) {
List<PtlTodoTaskEntity> ptlTodoTaskEntities = new ArrayList<>();
List<YstTaskEntity> ystTaskEntityList = new ArrayList<>();
for (String user : userList) {
PtlTodoTaskEntity nextPtlTodoTaskEntity = new PtlTodoTaskEntity();
nextPtlTodoTaskEntity.setTodoTaskId(UUIDUtil.getUUIDKey());
nextPtlTodoTaskEntity.setNodeId(wfNodeBaseEnum.getNodeCode());
nextPtlTodoTaskEntity.setBusModule(FlowConstants.FLOW_MODULE);
nextPtlTodoTaskEntity.setBusId(flowInfoEntity.getFlowId());
nextPtlTodoTaskEntity.setBusName(flowInfoEntity.getFlowName());
nextPtlTodoTaskEntity.setHandleUserId(user);
SysUserInfoDto userInfoDto = sysUserMapper.getUserInfoByUserId(user);
if (!ObjectUtils.isEmpty(userInfoDto)) {
nextPtlTodoTaskEntity.setHandleUserDeptId(userInfoDto.getOrgId());
}
nextPtlTodoTaskEntity.setCreatorId("370124");
nextPtlTodoTaskEntity.setCreatedTime(new Date());
ptlTodoTaskEntities.add(nextPtlTodoTaskEntity);
//同步发送一号通代办
YstTaskEntity ystTaskEntity = new YstTaskEntity();
ystTaskEntity.setSysSchema(schema);
ystTaskEntity.setNextAction(nextAction);
ystTaskEntity.setRefKey(flowInfoEntity.getFlowId());
ystTaskEntity.setTitle(flowInfoEntity.getFlowName() + "-");
ystTaskEntity.setTaskType(wfNodeBaseEnum.getNodeCode());
SysYhtUserSyncEntity sysYhtUserSyncEntity = sysYhtUserSyncMapper.selectOpenId(user);
ystTaskEntity.setUserId(sysYhtUserSyncEntity.getOpenId());
ystTaskEntity.setCreatorId(flowInfoEntity.getCreatorId());
ystTaskEntityList.add(ystTaskEntity);
}
if (!CollectionUtils.isEmpty(ystTaskEntityList)) {
List<List<YstTaskEntity>> device = com.cmbchina.itrisk.base.utils.CollectionUtils.device(ystTaskEntityList, 20);
device.forEach(list -> apiService.syncYhtTodoTaskBatchCreat(list));
}
ptlTodoTaskMapper.insertBatch(ptlTodoTaskEntities);
}
/**
* 审批一个流程
* 1.根据当前流程,添加流程的节点路径,修改流程的状态;
* 2.如果该节点审批完成,设置流程节点的关联人信息
* 3.记录流程日志
* 1.如果查询到审批通过人数达到节点审批条件值
* 1>修改当前节点的审批状态;
* 2>发送下一批人的代办任务
* 4.如果流程审批结束,修改该工作流为已删除(成为历史数据),当前节点所有待办任务删除,并给下个节点发布待办任务
*
* @param approveFlowDto: nextAction:待办的跳转地址信息
* flowInfoId:该流程信息id
* flowNodeCode:当前审批的节点
* param:审批的节点参数(可以为null,null的情况就是没有条件参数,直接往下走)
* userList:下一次审批的人员列表集合
* @return Integer 1:审批完成;2:还在审批中
*/
@Transactional(rollbackFor = Exception.class)
public Integer executeFlow(Class<IWfNodeBaseEnum> enumClass, ApproveFlowDto approveFlowDto)
throws InstantiationException, IllegalAccessException {
String flowInfoId = approveFlowDto.getFlowId();
String flowNodeCode = approveFlowDto.getFlowNodeCode();
List<String> userList = approveFlowDto.getUserList();
if (ObjectUtils.isEmpty(flowInfoId)) {
throw new BusinessException("审批流程id不能为空!!!");
}
if (ObjectUtils.isEmpty(flowNodeCode)) {
throw new BusinessException("审批流程节点code不能为空!!!");
}
if (CollectionUtils.isEmpty(approveFlowDto.getUserList())) {
throw new BusinessException("审批人不能为空!!!");
}
FlowInfoEntity flowInfoEntity = flowInfoMapper.selectByPrimaryKey(flowInfoId);
if (FlowConstants.FLOW_PENDING.equals(flowInfoEntity.getFlowStatus())) {
throw new BusinessException("该流程已处于挂起状态,请解除挂起之后再发起审批");
}
//1.根据当前流程,添加流程的节点路径,修改流程的状态;
IWfNodeBaseEnum iWfNodeBaseEnum = enumClass.newInstance();
//记录流程日志(先记日志,后续需要计算日志的值)
FlowRecordEntity flowRecord = new FlowRecordEntity();
flowRecord.setFlowRecordId(UUIDUtil.getUUIDKey());
flowRecord.setFlowInfoId(flowInfoEntity.getFlowId());
flowRecord.setFlowNodeCode(flowNodeCode);
flowRecord.setFlowRecordType(FlowConstants.FLOW_RECORD_START);
flowRecord.setFlowRecordContent(approveFlowDto.getRecordContent());
flowRecord.setCreatorId("370124");
flowRecord.setCreatedTime(new Date());
flowRecordMapper.insert(flowRecord);
//判断当前节点是否有审批人数量限制(用该参数和审批日志中的数量进行对比)
IWfNodeBaseEnum nodeEnum = iWfNodeBaseEnum.getEnumByNodeCode(flowNodeCode);
Integer nodeApproveParam = nodeEnum.getNodeApproveParam();
//表示当前节点还在审批阶段,直接返回不需要后续操作,参数从日志中查询同意审批个数
//获取下一个节点信息
IWfNodeBaseEnum nextNodeEnum = iWfNodeBaseEnum.getNextNodeEnum(flowNodeCode, approveFlowDto.getParam());
FlowRecordEntity record = new FlowRecordEntity();
record.setFlowInfoId(flowInfoId);
record.setFlowNodeCode(flowNodeCode);
List<FlowRecordEntity> flowRecordList = flowRecordMapper.selectByParam(record);
if (nodeApproveParam > flowRecordList.size()) {
String flowNodeCodePath = flowInfoEntity.getFlowNodeCodePath();
List<String> nodeCodePathList = Arrays.asList(flowNodeCodePath.split(","));
if (!nodeCodePathList.contains(flowNodeCode)) {
flowInfoEntity.setFlowNodeCodePath(flowNodeCodePath + "," + flowNodeCode);
//该情况表示流程还未结束(不需要发待办)
if (!FlowConstants.FLOW_NODE_STATUS_END.equals(nextNodeEnum.getNodeDesc())) {
flowInfoEntity.setFlowStatus(FlowConstants.FLOW_APPROVE);
}
flowInfoMapper.updateByPrimaryKeySelective(flowInfoEntity);
}
return 2;
}
//2.当前节点已经审批完成,设置流程节点的关联人信息
IWfNodeBaseEnum enumByNodeCode = iWfNodeBaseEnum.getEnumByNodeCode(flowNodeCode);
FlowNodeEntity flowNodeEntity = new FlowNodeEntity();
flowNodeEntity.setFlowInfoId(flowInfoEntity.getFlowId());
flowNodeEntity.setFlowNodeCode(enumByNodeCode.getNodeCode());
FlowNodeEntity nodeEntity = flowNodeMapper.selectByEntity(flowNodeEntity);
nodeEntity.setFlowNodeStatus(FlowConstants.FLOW_NODE_DONE);
nodeEntity.setLastModifierId("370124");
nodeEntity.setLastModifiedTime(new Date());
flowNodeMapper.updateByPrimaryKey(nodeEntity);
//如果当前节点审批都完成,删除当前节点所有的待办任务(待办转已办)
ptlTodoTaskMapper.batchDeleteByBusIds(Collections.singletonList(nodeEntity.getFlowNodeId()));
//判断该流程是否结束(下一个节点是否是end标记)
//重新获取该流程
FlowInfoEntity flowInfo = flowInfoMapper.selectByPrimaryKey(flowInfoId);
String flowNodeCodePath = flowInfo.getFlowNodeCodePath();
if (FlowConstants.FLOW_NODE_STATUS_END.equals(nextNodeEnum.getNodeDesc())) {
if (FlowConstants.FLOW_NODE_STATUS_END.equals(nextNodeEnum.getNodeDesc())) {
flowInfo.setFlowStatus(FlowConstants.FLOW_END);
flowInfo.setFlowNodeCodePath(flowNodeCodePath + "," + nextNodeEnum.getNodeCode());
flowInfoMapper.updateByPrimaryKeySelective(flowInfo);
return 1;
}
}
//如果流程还未结束,设置下一个节点的状态和发送代办
FlowNodeEntity flowNode = new FlowNodeEntity();
flowNode.setFlowInfoId(flowInfoEntity.getFlowId());
flowNode.setFlowNodeCode(nextNodeEnum.getNodeCode());
FlowNodeEntity nextNodeEntity = flowNodeMapper.selectByEntity(flowNodeEntity);
nextNodeEntity.setFlowNodeApproveUsers(StringUtils.join(userList, ","));
nextNodeEntity.setFlowNodeStatus(FlowConstants.FLOW_NODE_APPROVE);
nextNodeEntity.setLastModifierId("370124");
nextNodeEntity.setLastModifiedTime(new Date());
flowNodeMapper.updateByPrimaryKey(nextNodeEntity);
//将这些审批人userList发送代办
if (!CollectionUtils.isEmpty(userList)) {
executeTodoTask(userList, flowInfoEntity, nodeEnum, approveFlowDto.getNextAction());
}
return 2;
}
/**
* 驳回工作流信息(flowNodeCode为空相当于是默认设置第一个start节点,不为空是跳转到具体的节点中)
* 1.修改工作流的流程状态为已驳回(任何时候都可以驳回)
* 2.添加流程工作日志
* 3.驳回的时候将该流程节点的审批人全部重置到第一个节点(并给第一个节点的人发送代办)
*/
@Transactional(rollbackFor = Exception.class)
public void rejectFlow(Class<IWfNodeBaseEnum> enumClass, ApproveFlowDto approveFlowDto)
throws InstantiationException, IllegalAccessException {
//更新该流程的状态和链路路径
IWfNodeBaseEnum iWfNodeBaseEnum = enumClass.newInstance();
FlowInfoEntity flowInfoEntity = flowInfoMapper.selectByPrimaryKey(approveFlowDto.getFlowId());
if (FlowConstants.FLOW_PENDING.equals(flowInfoEntity.getFlowStatus())) {
throw new BusinessException("该流程已处于挂起状态,请解除挂起之后再发起审批");
}
flowInfoEntity.setFlowStatus(FlowConstants.FLOW_REJECT);
String flowNodeCodePath = flowInfoEntity.getFlowNodeCodePath();
String flowNodeCode = approveFlowDto.getFlowNodeCode();
String startCode;
if (ObjectUtils.isEmpty(flowNodeCode)) {
startCode = flowNodeCodePath.split(",")[0];
flowInfoEntity.setFlowNodeCodePath(startCode);
} else {
//校验跳回的节点是否在该流程中
List<String> nodeCodeList = Arrays.asList(flowNodeCodePath.split(","));
if (!nodeCodeList.contains(flowNodeCode)) {
throw new BusinessException("跳转的节点code不在该流程的工作节点中,跳转失败");
}
startCode = flowNodeCodePath.split(flowNodeCode)[0];
flowInfoEntity.setFlowNodeCodePath(startCode + "," + flowNodeCode);
startCode = flowNodeCode;
}
flowInfoEntity.setLastModifierId("370124");
flowInfoEntity.setLastModifiedTime(new Date());
flowInfoMapper.updateByPrimaryKeySelective(flowInfoEntity);
//记录流程日志
FlowRecordEntity flowRecord = new FlowRecordEntity();
flowRecord.setFlowRecordId(UUIDUtil.getUUIDKey());
flowRecord.setFlowInfoId(flowInfoEntity.getFlowId());
flowRecord.setFlowRecordType(FlowConstants.FLOW_RECORD_REJECT);
flowRecord.setFlowRecordContent(approveFlowDto.getRecordContent());
flowRecord.setCreatorId("370124");
flowRecord.setCreatedTime(new Date());
flowRecordMapper.insert(flowRecord);
//修改流程节点的信息
List<FlowNodeEntity> flowNodeEntityList = flowNodeMapper.selectByFlowInfoId(approveFlowDto.getFlowId());
List<FlowNodeEntity> entityList = flowNodeEntityList.stream()
.filter(s -> !ObjectUtils.isEmpty(s.getFlowNodeApproveUsers())).collect(Collectors.toList());
String flowPath = flowNodeCodePath.split(flowNodeCode)[0];
String approveNodeCode = startCode + flowPath.split(startCode)[1];
//获取需要修改的节点信息
List<String> updateNodeCodeLost = Arrays.asList(approveNodeCode.split(","));
List<FlowNodeEntity> nodeEntityList = entityList.stream()
.filter(s -> updateNodeCodeLost.contains(s.getFlowNodeCode())).collect(Collectors.toList());
for (FlowNodeEntity flowNodeEntity : nodeEntityList) {
flowNodeEntity.setFlowNodeApproveUsers("");
flowNodeEntity.setFlowNodeStatus(FlowConstants.FLOW_NODE_APPROVE);
flowNodeEntity.setLastModifierId("370124");
flowNodeEntity.setLastModifiedTime(new Date());
}
flowNodeMapper.updateBatch(nodeEntityList);
//删除往后节点的代办信息
List<String> flowNodeIdList = nodeEntityList.stream().map(FlowNodeEntity::getFlowNodeId).collect(Collectors.toList());
ptlTodoTaskMapper.batchDeleteByBusIds(flowNodeIdList);
//重新发送下一节点代办,将这些审批人userList发送代办
executeTodoTask(approveFlowDto.getUserList(), flowInfoEntity, iWfNodeBaseEnum.getNextNodeEnum(startCode), approveFlowDto.getNextAction());
}
/**
* 获取整条链路直接从流程数据中获取(在每次执行审批流程之后都会更新当前链路code字段)
*/
public List<IWfNodeBaseEnum> getLinkNode(Class<IWfNodeBaseEnum> enumClass, String flowId)
throws InstantiationException, IllegalAccessException {
IWfNodeBaseEnum iWfNodeBaseEnum = enumClass.newInstance();
FlowInfoEntity flowInfoEntity = flowInfoMapper.selectByPrimaryKey(flowId);
String flowNodeCodePath = flowInfoEntity.getFlowNodeCodePath();
if (ObjectUtils.isEmpty(flowNodeCodePath)) {
throw new BusinessException("异常数据,流程路径不能为空");
}
String[] nodeCodeList = flowNodeCodePath.split(",");
List<IWfNodeBaseEnum> list = new ArrayList<>();
for (String nodeCode : nodeCodeList) {
IWfNodeBaseEnum wfNodeEnum = iWfNodeBaseEnum.getEnumByNodeCode(nodeCode);
list.add(wfNodeEnum);
}
return list;
}
/**
* 任务挂起
* 1.修改该流程为挂起状态;
* 2.在提交的时候校验该流程是否挂起,挂起的流程不能提交流程
*
* @param flowId 流程id
* @param pending 是否挂起,true的时候是设置为挂起,false取消挂起
*/
public void executeFlow(String flowId, Boolean pending) {
FlowInfoEntity flowInfoEntity = flowInfoMapper.selectByPrimaryKey(flowId);
if (pending) {
flowInfoEntity.setFlowStatus(FlowConstants.FLOW_PENDING);
flowInfoMapper.updateByPrimaryKey(flowInfoEntity);
} else {
flowInfoEntity.setFlowStatus(FlowConstants.FLOW_APPROVE);
flowInfoMapper.updateByPrimaryKey(flowInfoEntity);
}
}
}