一、表单可配置
一个简单的可配置表单的思路
前端部分bpmn
将流程编号改成可选择的编号(即多个流预先约定好,然后让用户进行选择)
二、流程启动,候选人拾取,任务办理
之前说过候选人前端部分多选的实现。
现在到后端activiti
,流程启动,根据业务id
(自己的业务数据来看)生成任务
-
之前的审批流流转工作流(
xml
中定义代理人${assignee}
,每次通过传入一个用户
来定义下一个待办节点的处理人即给assignee定义
)工作流跑通记录DEBUG,审批流流转工作流的流程跑通 -
现在不设置代理人
${assignee}
,直接选定一批候选人candidateUsers
,然后在任务开启前,给定两个主要参数(业务id,选定用来拾取任务的candidateUsers
) -
业务保存—流程启动—任务创建
//doAudit方法,根据业务id判断任务是否存在,startNewFlow方法启动流程
// 根据业务id启动任务
//XXX 自己的业务实体
private void doAudit(XXX xxx) {
// 当前登录用户
String currentUsername = SysUser.getCurrentUser().getUsername();
// businessKey设为模型版本id
String businessKey = xxx.getId();
// 根据businessKey获取当前任务id
String taskId = auditService.getActiveTaskIdByBusinessKey(businessKey);
// 若该流程还不存在,并且check属性为空,则表示为起始编辑节点,则启动新的流程
// 这里假定所有审批节点都包含check属性
if (taskId == null && modelAuditDto.getAuditResult() == null) {
if(!startNewFlow(modelAuditDto)) {
throw new ApplicationRunException("流程启动失败。");
} else {
// 若流程启动成功,则指定由启动者本人来完成第一个任务
taskId = auditService.getActiveTaskIdByBusinessKey(businessKey);
auditService.setCandidateUsersByTaskId(taskId, Arrays.asList(currentUsername));
}
}
// 若taskId为空,但check属性不为空,也即为评审节点的办理,则抛出异常
if(taskId == null && modelAuditDto.getAuditResult() != null) {
throw new ApplicationRunException("任务不存在,该任务可能已经被其他人办理。");
}
// 接着,处理当前活动任务
// 获取当前活动任务的候选人列表
List<String> candidateUsers = auditService.getCandidateUsersByTaskId(taskId);
// 判断当前用户是否在候选人列表中
if(!candidateUsers.contains(currentUsername)) {
throw new ApplicationRunException("失败,当前登录用户无权办理该任务。");
}
// 办理任务
completeCurrentTask(taskId, xxx.getAuditResult());
}
- 流程启动,任务创建
// 根据约定的编号(也就是现在的多个表单的意义,来匹配我们的状态,启动指定的流程)
private boolean startNewFlow(XXX xxx) {
String processDefinitionKey;
switch (xxx.getState()) {
case BaseConstants.xxx_STATE:
processDefinitionKey = modelAuditDto.getModelType() + "_xxx_audit";
break;
case BaseConstants.xxx_STATE:
processDefinitionKey = "xxx_audit";
break;
case BaseConstants.xxx_STATE:
processDefinitionKey = "xxx_audit";
break;
default:
processDefinitionKey = "xxx_audit";
}
// 拼接审批流程实例的名称为:流程实例名拼接
String instanceName = xxx.getxxxName() + "_" + xxx.getxxx();
// 审批流程实例的businessKey设为业务的id
String businessKey = xxx.getId();
// 启动流程,暂时不传递任何额外参数给起始节点
return auditService.startProcess(processDefinitionKey, businessKey, instanceName, new HashMap<>(0));
}
- 办理任务
completeCurrentTask
private void completeCurrentTask(String taskId, String auditResult) {
// 解析必要的任务变量
// 这里暂时在流程设计时约定只有一个名为check的变量,用于表示评审结果为通过(1)或拒绝(0)
Map<String, Object> variables = new HashMap<>(1);
if(auditResult != null && !auditResult.isEmpty()) {
variables.put("check", Integer.parseInt(auditResult));
}
// 办理当前节点,即activiti的taskService.setAssignee()---即设置当前用户为代理人(办理人),控制能操作任务的人
//再taskService.complete()
auditService.completeTaskByTaskId(taskId, variables);
}
- 业务id用于开启一个任务,然后可以通过任务
BusinessKey(业务id)
判断是否任务已经存在 - 再任务启动后,再弹出流程中配置的
candidateUsers
选择哪些候选人拾取刚启动的这个任务,让他们在待办中出现可处理的下一节点任务,如果没有candidateUsers
可选,即下一个节点不可办(结束节点),如此实现配置多节点的流程
// 当前审批任务处理完成之后,下级任务将成为活动任务,获取其默认候选人,返回给前端让其从中选择。
// 若默认候选人列表为空,在假定流程设计没有错误的情况下,前端可以认为下个节点不是评审节点(如结束节点),而不用弹出选择框
List<String> candidateUsers;
String nextTaskId = auditService.getActiveTaskIdByBusinessKey(xxx.getId());
if(nextTaskId != null) {
candidateUsers = auditService.getCandidateUsersByTaskId(nextTaskId);
} else {
candidateUsers = new ArrayList<>(0);
}