Activiti6.0 多实例并发子流程和汇签
Activiti6.0 生成流程图和已审批待、待审批节点高亮
Activiti6 集成代码前后端
由于客户需求,添加撤回到已审批的任意节点功能,所以这边记录一下.
代码如下:
pom
<properties>
<activiti.version>6.0.0activiti.version>
properties>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-springartifactId>
<version>${activiti.version}version>
<exclusions>
<exclusion>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-json-converterartifactId>
<version>${activiti.version}version>
dependency>
getRunNodes 根据任务id查询已经执行的任务节点信息
/**
* 根据任务id查询已经执行的任务节点信息
*/
@Override
public DynamicFormConf getRunNodes(tring taskId) {
DynamicFormConf dynamicFormConf = new DynamicFormConf();
// 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(taskId)
.activityType("userTask") //用户任务
.finished() //已经执行的任务节点
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
// 已执行的节点ID集合
if(StringUtils.isNotEmpty(historicActivityInstanceList)){
Map<String,String> map= new LinkedHashMap<String,String>();
// map = historicActivityInstanceList.stream().collect(Collectors.toMap(HistoricActivityInstance::getActivityId,HistoricActivityInstance::getActivityName,(k1,k2)->k1));
for (HistoricActivityInstance historicActivityInstance:historicActivityInstanceList){
if(!map.containsKey(historicActivityInstance.getActivityId())){
map.put(historicActivityInstance.getActivityId(),historicActivityInstance.getActivityName());
}
}
dynamicFormConf.setRunNodes(map);
}
return dynamicFormConf;
}
runNodes 驳回到指定节点
/**
* 驳回到指定节点
* @param approvalOpinionVO //申请流程 审批信息
* @param task //任务信息
* @param map
* @return
*/
@Override
public boolean runNodes(ApprovalOpinionVO approvalOpinionVO, Task task, Map<String, Object> map) {
String myTaskId = null;
//判断当前用户是否为该节点处理人
if (UserUtils.getUserId().equals(task.getAssignee())) {
myTaskId = task.getId();
}
//如果当前节点处理人不是该用户,就无法进行驳回操作
if (null == myTaskId) {
throw new CustomException("当前用户无法驳回");
}
//获取当前节点
String currActivityId = task.getTaskDefinitionKey();
String processDefinitionId = task.getProcessDefinitionId();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currActivityId);
if (null == currFlow) {
List<SubProcess> subProcessList = bpmnModel.getMainProcess().findFlowElementsOfType(SubProcess.class, true);
for (SubProcess subProcess : subProcessList) {
FlowElement flowElement = subProcess.getFlowElement(currActivityId);
if (flowElement != null) {
currFlow = (FlowNode) flowElement;
break;
}
}
}
//获取目标节点
FlowNode targetFlow = (FlowNode) bpmnModel.getFlowElement(approvalOpinionVO.getRunNodeId());
//如果不是同一个流程(子流程)不能驳回
if (!(currFlow.getParentContainer().equals(targetFlow.getParentContainer()))) {
throw new CustomException("此处无法进行驳回操作");
}
//记录原活动方向
List<SequenceFlow> oriSequenceFlows = Lists.newArrayList();
oriSequenceFlows.addAll(currFlow.getOutgoingFlows());
//清理活动方向
currFlow.getOutgoingFlows().clear();
//建立新的方向
List<SequenceFlow> newSequenceFlows = Lists.newArrayList();
SequenceFlow newSequenceFlow = new SequenceFlow();
String uuid = UUID.randomUUID().toString().replace("-", "");
newSequenceFlow.setId(uuid);
newSequenceFlow.setSourceFlowElement(currFlow); //原节点
newSequenceFlow.setTargetFlowElement(targetFlow); //目标节点
newSequenceFlows.add(newSequenceFlow);
currFlow.setOutgoingFlows(newSequenceFlows);
//审批意见叠加
//variables 审批意见 act_ru_variable 变量表
Map<String, Object> variables = task.getProcessVariables();
//拒绝,通过,驳回 驳回指定节点
List<ApprovalOpinionDTO> approvalOpinionDTOs = new ArrayList<>();
//获取工作流审批记录
Object options = variables.get(Constant.ACT_APPLY_OPINION_LIST);
if (null != options) {
approvalOpinionDTOs = JSONObject.parseArray(options.toString(), ApprovalOpinionDTO.class);
}
//添加审批过后的返回提升信息
//ApprovalOpinionConverter 实体类转换器(没有 vo dto 等要求的可以不用转换,直接用一个类就可以了)
ApprovalOpinionDTO applyOpinionDTO = ApprovalOpinionConverter.INSTANCE.vo2dto(approvalOpinionVO);
applyOpinionDTO.setFlagStr(applyOpinionDTO.getTaskNodeName()+"撤回到"+targetFlow.getName());
approvalOpinionDTOs.add(applyOpinionDTO);
map.put(Constant.ACT_APPLY_OPINION_LIST, JSONObject.toJSONString(approvalOpinionDTOs));
//完成节点任务
taskService.complete(task.getId(), map);
//恢复原方向
currFlow.setOutgoingFlows(oriSequenceFlows);
return true;
}
handleApproval 审批处理
/**
* 审批处理
*
* @param approvalOpinionVO
* @return
*/
@Override
public boolean handleApproval(ApprovalOpinionVO approvalOpinionVO) {
Task task = taskService.createTaskQuery()
.taskTenantId(UserUtils.getTenantId()) //租户
.taskId(approvalOpinionVO.getTaskId())
.includeProcessVariables() //节点审批信息
.singleResult();
if (task == null) {
throw new CustomException("流程未启动或已执行完成");
}
if (StringUtils.isNotEmpty(task.getAssignee()) && !UserUtils.getUserId().equals(task.getAssignee())) {
throw new CustomException("当前用户不是审核人,无法进行审核");
}
//task.getAssignee() 获取审批人
if (StringUtils.isEmpty(task.getAssignee())) {
Set candidates = getCandiates(task.getId());
if (candidates.isEmpty()) {
throw new CustomException("当前用户不是审核人,无法进行审核");
}
if (candidates.contains(UserUtils.getUserId())) {
taskService.claim(task.getId(), UserUtils.getUserId());
}
}
//获取流程变量
Map processVariables = task.getProcessVariables();
approvalOpinionVO.setCreateTime(new Date());
approvalOpinionVO.setOpId(UserUtils.getUserId());
approvalOpinionVO.setOpName(SystemUtil.getCurrUserDto().getName());
approvalOpinionVO.setTaskNodeName(task.getName());
Map map = Maps.newHashMap();
map.put(Constant.ACT_TASK_FLAG, approvalOpinionVO.getFlag()); //审批操作 结果
//驳回操作
// if (DictEnum.APPLY_APPROVAL_OPINION_REJECT.getKey().equals(approvalOpinionVO.getFlag())) {
// return rejected(approvalOpinionVO, task, map);
// }
//驳回到指定步骤
if(DictEnum.APPLY_APPROVAL_OPINION_ASSIGN.getKey().equals(approvalOpinionVO.getFlag())){
return runNodes(approvalOpinionVO, task, map);
}
// 审批信息叠加
List opinionDTOS = new ArrayList<>();
Object options = processVariables.get(Constant.ACT_APPLY_OPINION_LIST);
if (options != null) {
opinionDTOS = JSONObject.parseArray(options.toString(), ApprovalOpinionDTO.class);
}
ApprovalOpinionDTO applyOpinionDTO = ApprovalOpinionConverter.INSTANCE.vo2dto(approvalOpinionVO);
opinionDTOS.add(applyOpinionDTO);
map.put(Constant.ACT_APPLY_OPINION_LIST, JSONObject.toJSONString(opinionDTOS));
taskService.complete(applyOpinionDTO.getTaskId(), map);
return true;
}
/*补充知识点
*complete(String taskId, Map variables)
*参数:taskId(对应act_ru_task中的id_),variables(下一次任务所需要的参数)
*作用:完成这一次任务,并且下一步任务需要流程变量的
*/
DynamicFormConf
/**
* 动态表单配置
*
* @author Create by YLL
* @date 2020/4/1 14:37
*/
@Data
public class DynamicFormConf implements Serializable {
/**
* 审批操作类型
*/
private Map approvalTypeFlag;
/**
* 是否可以修改表单
*/
private boolean writable;
/**
* 字段是否可编辑(批量控制)
*/
private boolean fieldWritable;
/**
* 是否可以指定下一步办理人
*/
private boolean nextAssign;
/**
* 存放已经执行的节点信息
*/
private Map runNodes;
}
ApprovalOpinionVO
/**
* 申请流程 审批信息
*
* @author LEN
*/
@Data
public class ApprovalOpinionVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 审批人id
*/
private String opId;
/**
* 审批人姓名
*/
private String opName;
/**
* 审批意见
*/
private String opinion;
/**
* 审批时间
*/
private Date createTime;
/**
* 是否通过 0拒绝,1同意,2驳回
*/
private String flag;
/**
* 流程任务id
*/
private String taskId;
/**
* 当前节点名称
*/
private String taskNodeName;
/**
* 附件
*/
private List<AttachmentEntityImpl> attachments;
/**
* 下一步审核人是否默认 0 默认,1 审批人指定
*/
private String defNextAssignee;
/**
* 指定的下一步审核人
*/
private UserDTO nextAssignee;
/**
* 驳回到指定节点id
*/
private String runNodeId;
/**
* id
*/
private String id;
}
ApprovalOpinionDTO
/**
* 申请流程 审批信息
*
* @author LEN
*/
@Data
public class ApprovalOpinionDTO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 审批人id
*/
private String opId;
/**
* 审批人姓名
*/
private String opName;
/**
* 审批意见
*/
private String opinion;
/**
* 审批时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* DIctEnum 流程审批操作类型:
* 是否通过 0拒绝,1同意,2驳回。。。
*/
private String flag;
/**
* 审批结果对应的字典值
*/
private String flagStr;
/**
* 流程id
*/
private String taskId;
/**
* 当前节点名称
*/
private String taskNodeName;
/**
* 附件
*/
private List<AttachmentEntityImpl> attachments;
/**
* 下一步审核人是否默认 0 默认,1 审批人指定
*/
private String defNextAssignee;
/**
* 指定的下一步审核人
*/
private UserDTO nextAssignee;
/**
* 驳回到指定节点id
*/
private String runNodeId;
/**
* 节点样式
*/
private String style;
}
Constant 自定义系统常量
/**
* 系统常量
*
* @author len.sun
* @data 2018-01-14
*/
public class Constant {
/**
* 工作流 审批记录
*/
public static final String ACT_APPLY_OPINION_LIST = "applyOpinionList";
}
ApprovalOpinionConverter 实体类转换器
没有 vo dto 等要求的项目可以不用转换,直接用一个类就可以了
/**
* 申请实体类转换器
*
* @Auther len.sun
* @Date 2019/6/15
*/
@Mapper
public abstract class ApprovalOpinionConverter {
public static ApprovalOpinionConverter INSTANCE = Mappers.getMapper(ApprovalOpinionConverter.class);
/**
* vo转dto
* @param vo
* @return
*/
public abstract ApprovalOpinionDTO vo2dto(ApprovalOpinionVO vo);
}
欢迎大家留言点赞和讨论
如有转载请标明出处