Activiti多人会签,1/3的人同意则审批通过的实现
第一步:配置流程
1. 配置审批通过的条件,如下,
线条上配置审批通过条件:${passCount/totalCount >=1/3}
线条上配置审批退回条件:${passCount/totalCount < 1/3}
2. 申请节点添加结束监听器
3. 配置该审批节点结束的条件
Sequential:false,false为并行执行,true为串行执行,此处要设置为并行
Collection: ${partyList},用于执行该会签环节的参与人,此处使用partyList的流程变量
Element variable: party,此处表示的是每一个分支都有一个叫party的流程变量,和上方的assignee结合使用就可以决定该分支应该由谁执行
Completion condition:该节点的结束条件(该条件一定要配置,否则要等所有人都执行完才会结束该节点)
4. 为该审批节点添加创建时的监听器
二:代码部分
1. 申请节点结束时,设置下个审批节点的参与人
监听器内容如下,主要用于设置下个审批节点的参与人
package com.ylkj.base.flow.listener;
import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class MyCompeteistener implements TaskListener {
@Override
public void notify(DelegateTask arg0) {
List<String> userList = new ArrayList<String>();
userList.add("111");
userList.add("222");
userList.add("333");
arg0.setVariable("partyList", userList);
}
}
2. 审批节点创建时的监听器,主要用于分配任务执行人
监听器内容如下:
package com.ylkj.base.flow.listener;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
/**
* 节点创建监听器
* 为节点设置处理人
*/
public class MutiGroupsListener implements TaskListener {
//节点完成的时候调用此监听器
@Override
public void notify(DelegateTask arg0) {
//将通过人数,未通过人数,总数,重新置为0,退回的时候才能重新计算
arg0.setVariable("passCount", "0");
arg0.setVariable("totalCount", "0");
arg0.setVariable("noPassCount", "0");
//为每一个任务设置处理人
String party = (String)arg0.getVariable("party");
arg0.setAssignee(party);
}
}
3. 审批节点有人执行任务时,需要统计执行情况
/* (非 Javadoc)
* <p>Title: completeTask1</p>
* <p>Description: </p>
* @param procInstId 流程实例id
* @param taskId 任务id
* @param variables 流程变量
* @param passflag 审批同意标志(yes/no)
* @see com.ylkj.base.activiti.service.ActivitiService#completeTask1(java.lang.String, java.lang.String, java.util.Map, java.lang.String)
*/
public void completeTask1(String procInstId,String taskId, Map<String, Object> variables,String passflag) {
//获取当前节点的task_def_key_,此段代码主要用于区分多个节点时,审批通过记录数与总数
Task taskQuery = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
List<Task> tasks = processEngine.getTaskService().createTaskQuery().taskName(taskQuery.getName()).processInstanceId(procInstId).list();
int passCount = 0;//审批同意人数
int noPassCount = 0;//审批不同意人数
int totalCount = 0;//任务总人数
//当前的执行情况
String tmpPassCount = processEngine.getRuntimeService().getVariable(procInstId, taskQuery.getTaskDefinitionKey()+"#passCount")+"";
String tmpNoPassCount = processEngine.getRuntimeService().getVariable(procInstId, taskQuery.getTaskDefinitionKey()+"#noPassCount")+"";
String tmpTotal = processEngine.getRuntimeService().getVariable(procInstId, taskQuery.getTaskDefinitionKey()+"#totalCount")+"";
if(!tmpPassCount.equals("null") && !tmpPassCount.trim().equals("")){
passCount = Integer.parseInt(tmpPassCount);
}
if(!tmpNoPassCount.equals("null") && !tmpNoPassCount.trim().equals("")){
noPassCount = Integer.parseInt(tmpNoPassCount);
}
if(tmpTotal.equals("null") || tmpTotal.trim().equals("")){
totalCount = tasks.size();
} else if(!tmpTotal.equals("null") && !tmpTotal.trim().equals("")){
totalCount = Integer.parseInt(tmpTotal);
}
for (Task tmp:tasks) {
if(passflag.equals("yes") && tmp.getId().equals(taskId)){//选择通过则通过人数+1
passCount++;
}
if(passflag.equals("no") && tmp.getId().equals(taskId)){//选择不通过则不通过人数+1
noPassCount++;
}
}
//变量回写记录
variables.put("passCount", passCount);
variables.put("noPassCount", noPassCount);
variables.put("totalCount", totalCount);
variables.put(taskQuery.getTaskDefinitionKey()+"#passCount", passCount);
variables.put(taskQuery.getTaskDefinitionKey()+"#noPassCount", noPassCount);
variables.put(taskQuery.getTaskDefinitionKey()+"#totalCount", totalCount);
processEngine.getTaskService().complete(taskId,variables);
}
4. 流程配置xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="myProcess090301" name="My process090301" isExecutable="true">
<startEvent id="startevent1" name="开始节点"></startEvent>
<userTask id="usertask1" name="申请节点1">
<extensionElements>
<activiti:taskListener event="complete" class="com.ylkj.base.flow.listener.MyCompeteistener"></activiti:taskListener>
</extensionElements>
</userTask>
<userTask id="usertask2" name="审批节点1" activiti:candidateGroups="role1">
<extensionElements>
<activiti:taskListener event="create" class="com.ylkj.base.flow.listener.MutiGroupsListener"></activiti:taskListener>
</extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${partyList}" activiti:elementVariable="party">
<completionCondition>${passCount/totalCount >=1/3}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
<exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
<sequenceFlow id="flow1" name="所有人都不同意" sourceRef="exclusivegateway1" targetRef="usertask1">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${passCount/totalCount < 1/3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow2" name="链接1" sourceRef="usertask2" targetRef="exclusivegateway1"></sequenceFlow>
<sequenceFlow id="flow7" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow8" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow9" name="1/3同意" sourceRef="exclusivegateway1" targetRef="endevent1">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${passCount/totalCount >=1/3}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_myProcess090301">
<bpmndi:BPMNPlane bpmnElement="myProcess090301" id="BPMNPlane_myProcess090301">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="60.0" y="140.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="200.0" y="130.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
<omgdc:Bounds height="55.0" width="105.0" x="440.0" y="130.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
<omgdc:Bounds height="40.0" width="40.0" x="472.0" y="290.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="670.0" y="293.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="472.0" y="310.0"></omgdi:waypoint>
<omgdi:waypoint x="252.0" y="310.0"></omgdi:waypoint>
<omgdi:waypoint x="252.0" y="185.0"></omgdi:waypoint>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="14.0" width="100.0" x="331.0" y="317.0"></omgdc:Bounds>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="492.0" y="185.0"></omgdi:waypoint>
<omgdi:waypoint x="492.0" y="290.0"></omgdi:waypoint>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="14.0" width="30.0" x="492.0" y="185.0"></omgdc:Bounds>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
<omgdi:waypoint x="95.0" y="157.0"></omgdi:waypoint>
<omgdi:waypoint x="200.0" y="157.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
<omgdi:waypoint x="305.0" y="157.0"></omgdi:waypoint>
<omgdi:waypoint x="440.0" y="157.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
<omgdi:waypoint x="512.0" y="310.0"></omgdi:waypoint>
<omgdi:waypoint x="670.0" y="310.0"></omgdi:waypoint>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="14.0" width="39.0" x="520.0" y="317.0"></omgdc:Bounds>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>