flowable 实现逐级审批功能

最近有些功能需要用到工作流,于是稍微学习了下,记录一下如何使用
需要实现多审批人逐级审批,上一级审批人通过之后,下级审批人才可以看到审批信息进行审批,全部审批通过之后进入同意事件,有一个人拒绝则进入驳回事件
用了两种方式实现,第一种在流程中绘制好多个审批人,使用时按对应参数填入;第二种使用多实例方式,串行审批。

 

目录

一、固定审批人

流程介绍

具体实现

优缺点

二、多实例串行

流程介绍

具体实现

优缺点


一、固定审批人

流程介绍

绘制好通用的十级层级,后续支持1-10级审批,也可以在某一级固定单个审批人或候选组。

具体实现

用户任务 添加上分配用户和跳过参数
分配用户如果是必填可以不需要跳过参数,不然没有分配又没跳过流程将会停滞

用户任务之后都是对应网关,同意则下一级任务,拒绝则都流转至结束事件

结束事件添加标识和执行监听器

 流程启动填入获取参数代码:
 

/**
 * 服务实现类
 *
 * @author Chill
 */
@Slf4j
@Service
@AllArgsConstructor
public class AudtiServiceImpl extends BaseServiceImpl<AuditMapper, ProcessAudit> implements IAuditService {

	private final IFlowClient flowClient;

	@Override
	@Transactional(rollbackFor = Exception.class)
	// @GlobalTransactional
	public boolean startProcess(ProcessAudit audit) {
		String businessTable = FlowUtil.getBusinessTable(ProcessConstant.AUDIT_KEY);
		if (Func.isEmpty(audit.getId())) {
			// 保存receive
			audit.setApplyTime(DateUtil.now());
			save(audit);
			// 启动流程
			Kv variables = Kv.create()
				.set(ProcessConstant.TASK_VARIABLE_CREATE_USER, AuthUtil.getUserName())
				//taskUser 为选择的审批人
				.set("taskUser1", TaskUtil.getTaskUser(audit.getTaskUser1()))
				.set("taskUser2", TaskUtil.getTaskUser(audit.getTaskUser2()))
				.set("taskUser3", TaskUtil.getTaskUser(audit.getTaskUser3()))
				.set("taskUser4", TaskUtil.getTaskUser(audit.getTaskUser4()))
				.set("taskUser5", TaskUtil.getTaskUser(audit.getTaskUser5()))
				.set("taskUser6", TaskUtil.getTaskUser(audit.getTaskUser6()))
				.set("taskUser7", TaskUtil.getTaskUser(audit.getTaskUser7()))
				.set("taskUser8", TaskUtil.getTaskUser(audit.getTaskUser8()))
				.set("taskUser9", TaskUtil.getTaskUser(audit.getTaskUser9()))
				.set("taskUser10", TaskUtil.getTaskUser(audit.getTaskUser10()))
				//单据id
				.set("auditId", audit.getAuditId())
				//单据No
				.set("auditNo", audit.getAuditNo())
				//单据类型 领用、借用等
				.set("auditType", audit.getAuditType())
				//开启自动跳过
				.set("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true)
				//skip 判断此级是否跳过
				.set("skip1", Func.isNotEmpty(audit.getTaskUser1())?false:true)
				.set("skip2", Func.isNotEmpty(audit.getTaskUser2())?false:true)
				.set("skip3", Func.isNotEmpty(audit.getTaskUser3())?false:true)
				.set("skip4", Func.isNotEmpty(audit.getTaskUser4())?false:true)
				.set("skip5", Func.isNotEmpty(audit.getTaskUser5())?false:true)
				.set("skip6", Func.isNotEmpty(audit.getTaskUser6())?false:true)
				.set("skip7", Func.isNotEmpty(audit.getTaskUser7())?false:true)
				.set("skip8", Func.isNotEmpty(audit.getTaskUser8())?false:true)
				.set("skip9", Func.isNotEmpty(audit.getTaskUser9())?false:true)
				.set("skip10", Func.isNotEmpty(audit.getTaskUser10())?false:true)
				;
			R<BladeFlow> result = flowClient.startProcessInstanceById(audit.getProcessDefinitionId(), FlowUtil.getBusinessKey(businessTable, String.valueOf(audit.getId())), variables);
			if (result.isSuccess()) {
				log.debug("流程已启动,流程ID:" + result.getData().getProcessInstanceId());
				// 返回流程id写入receive
				audit.setProcessInstanceId(result.getData().getProcessInstanceId());
				updateById(audit);
			} else {
				throw new ServiceException("开启流程失败");
			}
		} else {

			updateById(audit);
		}
		return true;
	}

}

 事件结束时调用监听器:
 

@AllArgsConstructor
@Component(value = "auditListener")
/**
 * 事件监听器 用于流程结束进行业务回调
 */
public class TaskBusinessCallListener implements TaskListener, ExecutionListener {
	private final IAssetsClient assetsClient;



	@Override
	public void notify(DelegateTask delegateTask) {
		String processInstanceId = delegateTask.getProcessInstanceId();
		//执行回调
//		this.callBack(processInstanceId, clazzName.getExpressionText(), method.getExpressionText(), version.getExpressionText(), params.getExpressionText());
	}

	@Override
	public void notify(DelegateExecution delegateExecution) {
//		String processInstanceId = delegateExecution.getProcessInstanceId();
		if (delegateExecution.getVariableInstances().get("auditId") != null) {
			if (delegateExecution.getEventName().equals("end")) {
				switch (delegateExecution.getCurrentActivityId()) {
					case "refuse":
						//驳回
						R refuse = assetsClient.flowAuditNo(Long.valueOf(delegateExecution.getVariableInstances().get("auditId").getTextValue())
							, "", delegateExecution.getVariableInstances().get("auditType").getTextValue(), 4);
						if (refuse.getCode() != 200) {
							throw new RuntimeException();
						}
						break;
					case "agree":
						//通过
						R agree = assetsClient.flowAuditNo(Long.valueOf(delegateExecution.getVariableInstances().get("auditId").getTextValue())
							, "", delegateExecution.getVariableInstances().get("auditType").getTextValue(), 3);
						if (agree.getCode() != 200) {
							throw new RuntimeException();
						}
						break;
				}
			}
		}

	}


}

优缺点

优点:
1.界面一览清晰
2.流程明确
3.方便后续定制化调整

缺点:
1.绘制复杂
2.需要设置的条件多
3.不支持动态增加下一签
4.审批人越多则视图越繁琐

二、多实例串行

流程介绍

直接使用活动的多实例串行模式既可实现逐级审批(并行模式可以实现会签、或签)

具体实现

 用户任务配置多实例类型、集合、完成条件、元素变量、分配用户
 

完成条件通过这几个变量来决定
 

nrOfInstances 一共有多少个实例
nrOfCompletedInstances 已经完成的实例个数
nrOfActiveInstances 未完成的实例个数


全部完成:

${nrOfCompletedInstances==nrOfInstances}

由于我的前端是多个流程公用一个页面,传入参数名称固定的,所以使用循环加反射获取了一下选择的审批人,再填入list中
 

/**
 * 服务实现类
 * 通用审批流(多级&逐级)
 * @author Chill
 */
@Slf4j
@Service
@AllArgsConstructor
public class SerialAuditServiceImpl extends BaseServiceImpl<AuditMapper, ProcessAudit> implements ISerialAuditService {

	private final IFlowClient flowClient;

	@Override
	@Transactional(rollbackFor = Exception.class)
	// @GlobalTransactional
	public boolean startProcess(ProcessAudit audit) {
		String businessTable = FlowUtil.getBusinessTable(ProcessConstant.SERIAL_AUDIT_KEY);
		if (Func.isEmpty(audit.getId())) {
			audit.setApplyTime(DateUtil.now());
			save(audit);
			List<String> taskUserList = new ArrayList<>();
			Method method=null;
			for (int i = 1; i <= 10; i++) {
				try {
					 method = audit.getClass().getMethod("getTaskUser" + i);
					if (Func.isNotEmpty(method.invoke(audit))) {
						taskUserList.add(TaskUtil.getTaskUser((String) method.invoke(audit)));
					} else {
						break;
					}
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
			// 启动流程
			Kv variables = Kv.create()
				.set(ProcessConstant.TASK_VARIABLE_CREATE_USER, AuthUtil.getUserName())
				//taskUserList 为选择的审批人列表
				.set("taskUserList", taskUserList)
				//单据id
				.set("auditId", audit.getAuditId())
				//单据No
				.set("auditNo", audit.getAuditNo())
				//单据类型 领用、借用等
				.set("auditType", audit.getAuditType());
			R<BladeFlow> result = flowClient.startProcessInstanceById(audit.getProcessDefinitionId(), FlowUtil.getBusinessKey(businessTable, String.valueOf(audit.getId())), variables);
			if (result.isSuccess()) {
				log.debug("流程已启动,流程ID:" + result.getData().getProcessInstanceId());
				// 返回流程id写入receive
				audit.setProcessInstanceId(result.getData().getProcessInstanceId());
				updateById(audit);
			} else {
				throw new ServiceException("开启流程失败");
			}
		} else {

			updateById(audit);
		}
		return true;
	}

}

优缺点

优点:
1.界面一览清晰
2.流程十分简洁明了
3.支持动态增减审批人
4.配置简单

缺点:
1.多实例不支持在流程中固定审批人
2.多实例不支持候选组
(也可能是我还没发现怎么做)

猜你喜欢

转载自blog.csdn.net/qq_17798399/article/details/123424189