最近有些功能需要用到工作流,于是稍微学习了下,记录一下如何使用 需要实现多审批人逐级审批,上一级审批人通过之后,下级审批人才可以看到审批信息进行审批,全部审批通过之后进入同意事件,有一个人拒绝则进入驳回事件 用了两种方式实现,第一种在流程中绘制好多个审批人,使用时按对应参数填入;第二种使用多实例方式,串行审批。
?
目录
一、固定审批人
流程介绍
具体实现
优缺点
二、多实例串行
流程介绍
具体实现
优缺点
一、固定审批人
流程介绍
绘制好通用的十级层级,后续支持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.多实例不支持候选组 (也可能是我还没发现怎么做)
|