activiti会签

12,Activiti会签功能

activiti6的使用,或签,会签,顺签

activiti学习(十七)——多实例任务的使用(会签功能)

Activiti 用户任务并行动态多实例(多用户执行流程)

Activiti6.0(十一)多实例节点(会签)

2020-10-21Activiti会签以及会签驳回

springboot+activiti6,多人会审流程的实现(无序,有序)

【弄nèng - Activiti6】Activiti6入门篇(七)—— 多实例任务
springboot整合Activiti-多实例任务串行并行配置

activity6 会签以及会签驳回操作

会签

会签的介绍

在流程业务管理中,任务通常是由一个人去处理的,而多个人同时处理1个任务,这种任务我们称之为会签任务。

在实际业务流程中,多实例节点是非常常见的一种场景,常用在多人审批环节,简单说就是某个环节的处理人指派给了多个人,需要这些人全部审批完或部分审批完,流程能自动流转的功能。以我们开发人员的角度看,其本质就是给定一个处理人员范围集合,然后循环该集合,为每一个集合中的元素都执行一遍当前环节,既可以顺序依次执行也可以并发同步执行,即依次会签or普通会签

会签:指同一个审批节点设置多个人,如ABC三人,三人会同时收到审批,需全部同意之后,审批才可到下一审批节点;

会签在中国式流程中是非常常见的需求。例如部门领导下发一个文件,需要部门里面每个员工看完之后提交流程以表示已阅。这时候需要使用activiti中的多实例任务。

多实例任务的图标如下:
在这里插入图片描述
左边的userTask下方是三条竖线,代表并行多实例,右边的userTask下方是三条横线,代表串行多实例。多实例任务,可以理解为该环节要提交多次才会通过,串行多实例一次只有1个任务可提交,并行多实例多个任务可并行提交。

会签的种类

  • 按数量通过:达到一定数量的通过表决后,会签通过
  • 按比例通过:达到一定比例的通过表决后,会签通过
  • 一票否决:只要有一个表决时否定的,会签通过
  • 一票通过:只要有一个表决通过的,会签通过

activiti会签

多实例是在一个普通节点上添加额外的多实例属性,这样被多实例修饰的节点就会执行多次,在BPMN规范中,绝大多数常用节点都可以成为一个多实例节点,最常用的便是 userTask 。

Activiti实现会签是基于多实例任务,将节点设置成多实例,主要通过在UserTask节点的属性上配置。

下面介绍一下activiti中的userTask中多实例任务相关的属性:
在这里插入图片描述

  • 多实例类型
    • NONE:非会签
    • PARALLEL:会签模式,并行触发,同时生成多个任务,即普通会签。
      • 并行代表同时进行,如把任务分给n个人来处理,这n个人同时会收到任务,并且可以同时处理,不受各自的影响
      • 配置了多实例的节点act_ru_task会有多条任务数据
    • SEQUENTIAL:会签模式,顺序触发,依次生成任务,即顺序会签
      • 串行代表工作或任务由一个人完成后,再由另一个人去处理,直至全部完成,每个任务依赖于前一个任务完成。
      • 配置了多实例的节点act_ru_task永远只有一条该节点的数据。
  • loop cardinality:循环基数,手动指定多实例循环几次。只要我们设置了Collection并且不设置loop cardinality的话,那么activiti就会把Collection的长度作为loop cardinality的值,实现了动态配置多实例任务循环次数。但是我们一般不用这个,而是用Completion condition。
  • Collection:动态集合,根据变量传入
  • Element variable:遍历后集合中每一项的别名的变量名称
    • Element variable与Assignee的表达式变量是关联的。Element variable与Collection的关系,类似java中for(String assignee in assigneeList)这样的关系。因此这个流程需要设置多实例任务的Assignee时,我们实际上需要传入流程变量assigneeList。
  • Completion condition:任务结束条件,默认全部完成。当这个属性表示当其值为true时,多实例流程就完成了。
    • 假设项目需要先由一个专家评估小组进行评估,超过60%的人提交了,那环节就通过。我们设计流程图,在Completion condition中设置${nrOfCompletedInstances/nrOfInstances>=0.6},即当任务完成数大于等于任务总数的60%时,多实例任务完成。如果是任意一个人会审通过则进入下一个节点,则修改表达式${nrOfCompletedInstances>0}
    • 这些变量可用于多实例结束条件表达式,可以通过该方式获得这些变量:taskService.getVariable(String taskId, String variableName),也可以通过可以通过execution.getVariable(x)方法获得这些变量。另外,每个创建的分支都会有分支级别的本地变量(比如,其他实例不可见, 不会保存到流程实例级别),也可以将这些变量保存到流程变量中,然后配合监听器、网关结合这些条件作判断,来走不同的分支,比如:回退。
      • nrOfInstances: 会签中总共的实例数
      • nrOfCompletedInstances: 已经完成的实例数量
      • nrOfActiveInstances: 当前活动的实例数量, 即还没有完成的实例数量。对于顺序执行的多实例, 该值始终为1
      • loopCounter: 当前实例所在循环的索引值, 其他实例不可见, 不会保存到流程实例级别

会签示例

准备工作

继续使用 进阶篇 中activiti.cfg.xml、log4j.properties、logback.xml、pom.xml

会签流程图

设置会签任务完成条件:${nrOfInstances==nrOfCompletedInstances},即当所有人都审批通过后,该会签任务才算完成。其中,collection可以直接使用userList,也可以使用${userList}

在这里插入图片描述

<?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/processdef">
  <process id="multi-instance-key" name="multi-instance-name" isExecutable="true">
    <documentation>多实例任务</documentation>
    <startEvent id="startEvent1"></startEvent>
    <userTask id="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391" name="组内会议申请" activiti:assignee="${applicant}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE" name="组员决议" activiti:assignee="${user}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="userList" activiti:elementVariable="user">
        <completionCondition>${nrOfInstances==nrOfCompletedInstances}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <sequenceFlow id="sid-CCBF6CFB-8B45-44DB-AFDA-BBEED7B101F1" sourceRef="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391" targetRef="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE"></sequenceFlow>
    <sequenceFlow id="sid-191B7829-C06F-4605-B6A7-F84E15129903" sourceRef="startEvent1" targetRef="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391"></sequenceFlow>
    <userTask id="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93" name="部门主管审批" activiti:assignee="MrChen">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-DCC15BB4-B214-4469-A05A-5C68A4FE4721" sourceRef="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE" targetRef="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93"></sequenceFlow>
    <endEvent id="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084"></endEvent>
    <sequenceFlow id="sid-0B36CF60-848C-45DF-BD36-EEA0994EAD86" sourceRef="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93" targetRef="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_multi-instance-key">
    ...
  </bpmndi:BPMNDiagram>
</definitions>
重置activiti数据库
/**
 * 重置activiti数据库
 */
@Test
public void test_01() {

    ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault()
            .setDatabaseSchemaUpdate(ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_DROP_CREATE)
            .buildProcessEngine();

}
部署流程
/**
 * 部署流程
 */
@Test
public void test_02() {

    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    RepositoryService repositoryService = processEngine.getRepositoryService();

    Deployment deploy = repositoryService
            .createDeployment()
            .addClasspathResource("process/multi-instance-name.bpmn20.xml")
            .key("multi-inst-deploy-key")
            .name("multi-inst-deploy-name")
            .deploy();

    log.info("部署id: {}", deploy.getId());
    log.info("部署key: {}", deploy.getKey());
    log.info("部署name: {}", deploy.getName());

    /* 输出如下: 
		    部署id: 1
		    部署key: multi-inst-deploy-key
		    部署name: multi-inst-deploy-name
    */

    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
    log.info("流程定义id: {}", processDefinition.getId());
    log.info("流程定义key: {}", processDefinition.getKey());
    log.info("流程定义name: {}", processDefinition.getName());

    /* 输出如下: 
		    流程定义id: multi-instance-key:1:3
		    流程定义key: multi-instance-key
		    流程定义name: multi-instance-name
    */
}
开启流程

因为 组内会议申请 需要applicant变量,所以开启该流程时,需要指定该变量

/**
 * 开启流程
 */
@Test
public void test_03() {

    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    RuntimeService runtimeService = processEngine.getRuntimeService();
    TaskService taskService = processEngine.getTaskService();

	// 流程变量
    HashMap<String, Object> variables = new HashMap<>();
    variables.put("applicant", "zzhua");

	// 开启流程
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("multi-instance-key","business-001",variables);

    log.info("流程实例id: {}", processInstance.getId());
    /* 输出如下: 
			流程实例id: 7501
	*/
}

此时,数据库表act_ru_execution 中数据如下:
在这里插入图片描述
数据库表act_ru_task 中数据如下:
在这里插入图片描述
数据库表act_ru_variable 中数据如下:
在这里插入图片描述

完成组内会议审批申请

完成流程图上第1个任务(必须传入变量userList,否则会报错),流程进入会签任务。可以看到任务表中会有3个任务

/**
 * 完成组内会议审批申请
 */
@Test
public void test_03() {

    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();
    
    HashMap<String, Object> vars = new HashMap<>();
    List<String> userList = new ArrayList<>();
    Collections.addAll(userList, "zs", "ls", "ww");
    
    vars.put("userList", userList);

    Task task = taskService.createTaskQuery().processInstanceId("7501").singleResult();
    
    taskService.complete(task.getId(), vars);
    
    log.info("完成组内会议审批申请");

}

此时,数据库表act_ru_execution 中数据如下:
在这里插入图片描述
数据库表act_ru_task 中数据如下:
在这里插入图片描述
数据库表act_ru_variable 中数据如下:
在这里插入图片描述

生成流程图

生成该流程实例此时的流程图
在这里插入图片描述

/**
 * 生成流程图
 *
 */
@Test
public void generateImage() throws IOException {

    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    TaskService taskService = processEngine.getTaskService();
    RuntimeService runtimeService = processEngine.getRuntimeService();
    RepositoryService repositoryService = processEngine.getRepositoryService();
    HistoryService historyService = processEngine.getHistoryService();

    HistoricTaskInstance historicTaskInstance = historyService
            .createHistoricTaskInstanceQuery()
            .orderByTaskCreateTime().desc()
            .list().get(0);

    BpmnModel model = repositoryService.getBpmnModel(historicTaskInstance.getProcessDefinitionId());

    ProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();

    //lastTask是当前任务执行到的位置
    List<HistoricActivityInstance> lastTasks =
            historyService.createHistoricActivityInstanceQuery()
                    // 指定流程实例id-processInstanceId
                    .processInstanceId(historicTaskInstance.getProcessInstanceId())
                    // 按时间降序排序
                    .orderByHistoricActivityInstanceStartTime()
                    .desc()
                    .list();

    // 拿到最后1个时间执行的活动实例id
    List<String> lastTask = lastTasks.stream()
            .map(HistoricActivityInstance::getActivityId)
            .limit(1)
            .collect(Collectors.toList());

    lastTask.add(lastTasks.get(0).getActivityId());

    //七个参数分别是:
    //  BPMNModel
    //  高光节点
    //  高光顺序流
    //  活动字体名称
    //  标签字体名称
    //  批注字体名称
    //  生成默认关系图
    //  默认关系图映像文件名
    InputStream inputStream = generator.generateDiagram(model, lastTask, Collections.emptyList(), "宋体", "宋体", "宋体", true, "test");

    String imageName = "image-" + Instant.now().getEpochSecond() + ".svg";
    FileUtils.copyInputStreamToFile(inputStream, new File("process/" + imageName));

}

完成会签任务

由于该会签任务是并行执行的,所以指定的审批人可以各自完成自己的任务即可,不需要按照顺序完成。

/**
 * 完成会签任务
 */
@Test
public void test_04() {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();

    Task task = taskService.createTaskQuery().taskAssignee("ls").singleResult();
    
    log.info("任务id: {}", task.getId());
    log.info("任务定义key: {}", task.getTaskDefinitionKey());
    log.info("任务所属流程实例id: {}", task.getProcessInstanceId());
    log.info("任务所属执行实例id: {}", task.getExecutionId());
    log.info("任务所属流程定义id: {}", task.getProcessDefinitionId());
    /* 输出如下:
			任务id: 10020
			任务定义key: sid-57AB53D8-1E45-494F-9014-9DE289B7CAA
			任务所属流程实例id: 7501
			任务所属执行实例id: 10008
			任务所属流程定义id: multi-instance-key:1:3
	*/

    taskService.complete(task.getId());
    log.info("并行-完成组内决议会签任务");

}

当lisi完成任务时,我们可以看到任务表会删除1项任务,执行实例表lisi所处的执行实例IS_ACTIVE被置为0,在流程变量表中,nrOfCompletedInstances加1,nrOfActiveInstances减1

数据库表 act_ru_execution
在这里插入图片描述

数据库表act_ru_task在这里插入图片描述
数据库表act_ru_variable
在这里插入图片描述

当zs和ww都完成任务后,观察表数据变化,并生成此时的流程图,可以看到当ls,zs,ww都完成任务时,流程才进入到下1个节点

数据库表 act_ru_execution
在这里插入图片描述
数据库表act_ru_task在这里插入图片描述
数据库表act_ru_variable在这里插入图片描述
此时,流程图:
在这里插入图片描述

一票通过

修改流程图

通过设置自定义变量pass,放入到完成条件中。指定该会签任务完成的人,仍然是:zs、ls、ww。首先,zs审批了该任务(传入pass为false,如果不传的话会报错,或者在组员会议任务节点的监听器中的create时,设置该pass变量(设置为false)比较合适 — 已测试)。然后由于ww有一票通过权,因此,ww审批的时候,带上pass为true,这样,该会签任务就已经完成了,流程流转到下一个节点,并不需要ls审批通过(ls的任务会被删除掉)。
在这里插入图片描述

<?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/processdef">
  <process id="multi-instance-key" name="multi-instance-name" isExecutable="true">
    <documentation>多实例任务</documentation>
    <startEvent id="startEvent1"></startEvent>
    <userTask id="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391" name="组内会议申请" activiti:assignee="${applicant}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE" name="组员决议" activiti:assignee="${user}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="userList" activiti:elementVariable="user">
        <completionCondition>${pass==true||nrOfInstances==nrOfCompletedInstances}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <sequenceFlow id="sid-CCBF6CFB-8B45-44DB-AFDA-BBEED7B101F1" sourceRef="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391" targetRef="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE"></sequenceFlow>
    <sequenceFlow id="sid-191B7829-C06F-4605-B6A7-F84E15129903" sourceRef="startEvent1" targetRef="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391"></sequenceFlow>
    <userTask id="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93" name="部门主管审批" activiti:assignee="MrChen">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-DCC15BB4-B214-4469-A05A-5C68A4FE4721" sourceRef="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE" targetRef="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93"></sequenceFlow>
    <endEvent id="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084"></endEvent>
    <sequenceFlow id="sid-0B36CF60-848C-45DF-BD36-EEA0994EAD86" sourceRef="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93" targetRef="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_multi-instance-key">
    ...
  </bpmndi:BPMNDiagram>
</definitions>
代码

zs完成会签任务,传入pass为false

/**
 * zs完成会签任务
 */
@Test
public void test_04() {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();

    Task task = taskService.createTaskQuery().taskAssignee("zs").singleResult();
    
    HashMap<String, Object> vars = new HashMap<>();
    vars.put("pass", false); // 侵入性过大, 可使用TaskListener监听器 — create时机

    taskService.complete(task.getId(),vars);
    log.info("并行-完成组内决议会签任务");

}

ww完成会签任务,此时,该会签任务已经完成,流转到下一个节点,并不需要zs完成任务(zs对应的任务会被删除),ww实现了一票通过。

/**
 * ww完成会签任务
 */
@Test
public void test_04() {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();

    Task task = taskService.createTaskQuery().taskAssignee("ww").singleResult();
    
    HashMap<String, Object> vars = new HashMap<>();
    vars.put("pass", true);

    taskService.complete(task.getId(),vars);
    log.info("并行-完成组内决议会签任务");

}

一票否决

一票否决通过:自定义变量 + 多实例会签 + 排它网关 + 任务监听器,实现。完成会签任务的条件设置为:${pass>=0||nrOfInstances==nrOfCompletedInstances}(注意>须替换为&gt;),当传入的pass大于等于0时,结束当前会签任务,然后再根据排它网关的条件:当pass==0时,正常流转到下一个节点。当pass>0时,直接结束。其中,在会签任务审批过程中时,需要传入pass变量,或者使用监听器,在会签任务节点一创建的时候,就使用delegateTask设置pass变量,否则会报错,此处,通过监听器实现。

修改流程图

在这里插入图片描述

<?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/processdef">
  <process id="multi-instance-key" name="multi-instance-name" isExecutable="true">
    <documentation>多实例任务</documentation>
    <startEvent id="startEvent1"></startEvent>
    <userTask id="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391" name="组内会议申请" activiti:assignee="${applicant}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE" name="组员决议" activiti:assignee="${user}">
      <extensionElements>
        <activiti:taskListener event="create" class="com.zzhua.listener.PassTaskListener"></activiti:taskListener>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="userList" activiti:elementVariable="user">
        <completionCondition>${pass&gt;=0||nrOfInstances==nrOfCompletedInstances}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <sequenceFlow id="sid-CCBF6CFB-8B45-44DB-AFDA-BBEED7B101F1" sourceRef="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391" targetRef="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE"></sequenceFlow>
    <sequenceFlow id="sid-191B7829-C06F-4605-B6A7-F84E15129903" sourceRef="startEvent1" targetRef="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391"></sequenceFlow>
    <userTask id="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93" name="部门主管审批" activiti:assignee="MrChen">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <endEvent id="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084"></endEvent>
    <exclusiveGateway id="sid-4D2E052A-A3FF-4AEC-87B9-6524563B7EB6"></exclusiveGateway>
    <sequenceFlow id="sid-2C076C0E-C1B0-4586-A76A-72A4331D8F78" sourceRef="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE" targetRef="sid-4D2E052A-A3FF-4AEC-87B9-6524563B7EB6"></sequenceFlow>
    <sequenceFlow id="sid-0B36CF60-848C-45DF-BD36-EEA0994EAD86" sourceRef="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93" targetRef="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084"></sequenceFlow>
    <sequenceFlow id="sid-F9262C3B-CDA9-4CD9-8C0D-FF2AE034C36E" name="${pass==0}同意" sourceRef="sid-4D2E052A-A3FF-4AEC-87B9-6524563B7EB6" targetRef="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass==0}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="sid-EDF96502-20E1-40EF-AE79-D929D86F2263" name="${pass&gt;0}不同意" sourceRef="sid-4D2E052A-A3FF-4AEC-87B9-6524563B7EB6" targetRef="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass>0}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_multi-instance-key">
    <bpmndi:BPMNPlane bpmnElement="multi-instance-key" id="BPMNPlane_multi-instance-key">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="75.0" y="145.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-7049DB96-D3D3-4855-BD40-D3DF80C22391" id="BPMNShape_sid-7049DB96-D3D3-4855-BD40-D3DF80C22391">
        <omgdc:Bounds height="80.0" width="100.0" x="165.0" y="120.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE" id="BPMNShape_sid-57AB53D8-1E45-494F-9014-9DE289B7CAAE">
        <omgdc:Bounds height="80.0" width="100.0" x="345.0" y="120.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93" id="BPMNShape_sid-3CC5544F-6C77-4CD8-B561-CCD1AAA5AA93">
        <omgdc:Bounds height="80.0" width="100.0" x="675.0" y="120.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084" id="BPMNShape_sid-85751F91-AB42-4CF8-92D9-A9D71A1CC084">
        <omgdc:Bounds height="28.0" width="28.0" x="855.0" y="146.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-4D2E052A-A3FF-4AEC-87B9-6524563B7EB6" id="BPMNShape_sid-4D2E052A-A3FF-4AEC-87B9-6524563B7EB6">
        <omgdc:Bounds height="40.0" width="40.0" x="510.0" y="140.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-0B36CF60-848C-45DF-BD36-EEA0994EAD86" id="BPMNEdge_sid-0B36CF60-848C-45DF-BD36-EEA0994EAD86">
        <omgdi:waypoint x="775.0" y="160.0"></omgdi:waypoint>
        <omgdi:waypoint x="855.0" y="160.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-F9262C3B-CDA9-4CD9-8C0D-FF2AE034C36E" id="BPMNEdge_sid-F9262C3B-CDA9-4CD9-8C0D-FF2AE034C36E">
        <omgdi:waypoint x="549.5489690721649" y="160.45103092783506"></omgdi:waypoint>
        <omgdi:waypoint x="675.0" y="160.12853470437017"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-191B7829-C06F-4605-B6A7-F84E15129903" id="BPMNEdge_sid-191B7829-C06F-4605-B6A7-F84E15129903">
        <omgdi:waypoint x="105.0" y="160.0"></omgdi:waypoint>
        <omgdi:waypoint x="165.0" y="160.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-2C076C0E-C1B0-4586-A76A-72A4331D8F78" id="BPMNEdge_sid-2C076C0E-C1B0-4586-A76A-72A4331D8F78">
        <omgdi:waypoint x="445.0" y="160.18450184501845"></omgdi:waypoint>
        <omgdi:waypoint x="510.4259259259259" y="160.42592592592592"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-EDF96502-20E1-40EF-AE79-D929D86F2263" id="BPMNEdge_sid-EDF96502-20E1-40EF-AE79-D929D86F2263">
        <omgdi:waypoint x="530.5" y="179.5"></omgdi:waypoint>
        <omgdi:waypoint x="530.5" y="261.8000030517578"></omgdi:waypoint>
        <omgdi:waypoint x="869.0" y="261.8000030517578"></omgdi:waypoint>
        <omgdi:waypoint x="869.0" y="174.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-CCBF6CFB-8B45-44DB-AFDA-BBEED7B101F1" id="BPMNEdge_sid-CCBF6CFB-8B45-44DB-AFDA-BBEED7B101F1">
        <omgdi:waypoint x="265.0" y="160.0"></omgdi:waypoint>
        <omgdi:waypoint x="345.0" y="160.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
代码

监听器代码

public class PassTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        if ("create".equals(delegateTask.getEventName())) {
            // pass设置为-1, 表示默认不使用一票通过或一票否决
            delegateTask.setVariable("pass", -1);
        }
    }
}

通过设置自定义变量pass,放入到完成条件中。指定该会签任务完成的人,仍然是:zs、ls、ww。首先,zs审批了该任务(在组员会议任务节点的监听器中的create时,已设置该pass变量(设置为-1)),然后,进入完成条件判断,发现没满足,因此当前会签任务仍需要继续(每完成1次会签任务,就判断一下会签完成条件是否满足)。然后由于ww有一票否决权,因此,ww审批的时候,带上pass为1,然后,进入完成条件判断,发现条件满足,所以该会签任务就已经完成了(并不需要ls审批通过(ls的任务会被删除掉)),流程流转到排它网关,排它网关得到当前变量pass为1,直接走向结束的分支。

zs完成会签任务

/**
 * zs完成会签任务
 */
@Test
public void test_04() {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();

    Task task = taskService.createTaskQuery().taskAssignee("zs").singleResult();

    HashMap<String, Object> vars = new HashMap<>();

    taskService.complete(task.getId(),vars);
    log.info("并行-完成组内决议会签任务");

}

ww完成会签任务,并传入pass为1,该会签任务结束

/**
 * ww完成会签任务
 */
@Test
public void test_04() {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    TaskService taskService = processEngine.getTaskService();

    Task task = taskService.createTaskQuery().taskAssignee("ww").singleResult();
 
    HashMap<String, Object> vars = new HashMap<>();

    vars.put("pass", 1);

    taskService.complete(task.getId(),vars);
    log.info("并行-完成组内决议会签任务");

}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值