Camunda会签、或签、比例签

💖专栏简介

✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。

✔️文章中只包含演示核心代码及测试数据,完整代码可查看作者的开源项目snail-camunda

✔️请给snail-camunda 点颗星吧😘

💖说在前面

请无视标题,无论是或签还是比例签都是会签,只是该节点通过的规则不同。本文将演示会签通过的三种规则:【所有人审批通过】、【一人审批通过】、【按比例投票】。

注意:设置的是通过规则,对于驳回操作均为一人驳回则驳回。

💖设计流程定义

在《认识BPMN2.0》中提及用户任务可以直接分配给单个用户、用户列表或组列表,本文将演示分配给单个用户、用户列表两种方式,用户组在后续文章中也会演示。

以下变量名是在整个过程中比较重要的,结合示例理解并使用

  • nrOfInstances : 实例总数
  • nrOfActiveInstances:当前活动的实例的数量。对于串行而言该值始终为1
  • nrOfCompletedInstances:已经完成的实例数
  • loopCounter :循环计数器
  • Loop cardinality:循环基数
  • Collection:会签人数的集合
  • Element variable:变量元素。选择Collection时必选,为collection集合每次遍历的元素。
  • Completion condition:完成条件

用户任务分配给单个用户可按如下图所示设置:

一人通过 通常被称为【或签】,设置完成条件:

${nrOfCompletedInstances == 1}

还需注意变量元素名和Assignee中设置的变量名保持一致。类似于在Java中的fori循环,变量名是i,使用该变量时也应该用i。

比例通过和全部通过就不截图了,完成条件分别改为:

//已完成的实例数占总实例数的三成以上就算通过
${nrOfCompletedInstances/nrOfInstances > 0.3}
//已完成的实例数 等于 总实例数才算通过
${nrOfCompletedInstances == nrOfInstances}

好吧,直接把流程定义放上来:

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1o78fuh" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.19.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0"><bpmn:process id="Process_19w1rrm" isExecutable="true" camunda:historyTimeToLive="180"><bpmn:startEvent id="StartEvent_1"><bpmn:outgoing>Flow_0g1nmt1</bpmn:outgoing></bpmn:startEvent><bpmn:sequenceFlow id="Flow_0g1nmt1" sourceRef="StartEvent_1" targetRef="root" /><bpmn:userTask id="root" name="发起人" camunda:assignee="${initiator}"><bpmn:incoming>Flow_0g1nmt1</bpmn:incoming><bpmn:outgoing>Flow_178rknz</bpmn:outgoing></bpmn:userTask><bpmn:sequenceFlow id="Flow_178rknz" sourceRef="root" targetRef="Activity_0163wxf" /><bpmn:userTask id="Activity_0163wxf" name="一人通过" camunda:assignee="${assignee}"><bpmn:incoming>Flow_178rknz</bpmn:incoming><bpmn:outgoing>Flow_1t1uand</bpmn:outgoing><bpmn:multiInstanceLoopCharacteristics camunda:collection="${userOneList}" camunda:elementVariable="assignee"><bpmn:completionCondition xsi:type="bpmn:tFormalExpression">${nrOfCompletedInstances == 1}</bpmn:completionCondition></bpmn:multiInstanceLoopCharacteristics></bpmn:userTask><bpmn:sequenceFlow id="Flow_1t1uand" sourceRef="Activity_0163wxf" targetRef="Activity_1hgbacv" /><bpmn:userTask id="Activity_1hgbacv" name="比例通过" camunda:assignee="${assignee}"><bpmn:incoming>Flow_1t1uand</bpmn:incoming><bpmn:outgoing>Flow_1giv9ue</bpmn:outgoing><bpmn:multiInstanceLoopCharacteristics camunda:collection="${userTwoList}" camunda:elementVariable="assignee"><bpmn:completionCondition xsi:type="bpmn:tFormalExpression">${nrOfCompletedInstances/nrOfInstances &gt; 0.3 }</bpmn:completionCondition></bpmn:multiInstanceLoopCharacteristics></bpmn:userTask><bpmn:userTask id="Activity_14cwgmh" name="全部通过" camunda:assignee="${assignee}"><bpmn:incoming>Flow_1giv9ue</bpmn:incoming><bpmn:outgoing>Flow_0xb5gog</bpmn:outgoing><bpmn:multiInstanceLoopCharacteristics camunda:collection="${userThreeList}" camunda:elementVariable="assignee"><bpmn:completionCondition xsi:type="bpmn:tFormalExpression">${nrOfCompletedInstances == nrOfInstances}</bpmn:completionCondition></bpmn:multiInstanceLoopCharacteristics></bpmn:userTask><bpmn:endEvent id="Event_0a7muzc"><bpmn:incoming>Flow_0xb5gog</bpmn:incoming></bpmn:endEvent><bpmn:sequenceFlow id="Flow_0xb5gog" sourceRef="Activity_14cwgmh" targetRef="Event_0a7muzc" /><bpmn:sequenceFlow id="Flow_1giv9ue" sourceRef="Activity_1hgbacv" targetRef="Activity_14cwgmh" /></bpmn:process><bpmndi:BPMNDiagram id="BPMNDiagram_1"><bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_19w1rrm"><bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1"><dc:Bounds x="179" y="99" width="36" height="36" /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_0fh3xaa_di" bpmnElement="root"><dc:Bounds x="270" y="77" width="100" height="80" /><bpmndi:BPMNLabel /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_06ae8hl_di" bpmnElement="Activity_0163wxf"><dc:Bounds x="430" y="77" width="100" height="80" /><bpmndi:BPMNLabel /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_0edrq19_di" bpmnElement="Activity_1hgbacv"><dc:Bounds x="590" y="77" width="100" height="80" /><bpmndi:BPMNLabel /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Activity_1j25q3g_di" bpmnElement="Activity_14cwgmh"><dc:Bounds x="760" y="77" width="100" height="80" /><bpmndi:BPMNLabel /></bpmndi:BPMNShape><bpmndi:BPMNShape id="Event_0a7muzc_di" bpmnElement="Event_0a7muzc"><dc:Bounds x="912" y="99" width="36" height="36" /></bpmndi:BPMNShape><bpmndi:BPMNEdge id="Flow_0g1nmt1_di" bpmnElement="Flow_0g1nmt1"><di:waypoint x="215" y="117" /><di:waypoint x="270" y="117" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_178rknz_di" bpmnElement="Flow_178rknz"><di:waypoint x="370" y="117" /><di:waypoint x="430" y="117" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_1t1uand_di" bpmnElement="Flow_1t1uand"><di:waypoint x="530" y="117" /><di:waypoint x="590" y="117" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_0xb5gog_di" bpmnElement="Flow_0xb5gog"><di:waypoint x="860" y="117" /><di:waypoint x="912" y="117" /></bpmndi:BPMNEdge><bpmndi:BPMNEdge id="Flow_1giv9ue_di" bpmnElement="Flow_1giv9ue"><di:waypoint x="690" y="117" /><di:waypoint x="760" y="117" /></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram>
</bpmn:definitions>

💖部署流程定义

在resources下新建目录bpmn用于存放流程定义文件,启动项目后调用部署接口:

/*** 流程定义相关接口* @author lonewalker*/
@RequestMapping("/process/definition")
@AllArgsConstructor
@RestController
public class ProcessDefinitionController {private final RepositoryService repositoryService;/*** 部署流程定义** @return 提示信息*/@PostMapping("/deploy")public String deployProcessDefinition(){repositoryService.createDeployment().addClasspathResource("bpmn/2.bpmn").name("演示").deploy();return "部署成功";}
}

💖流程实例测试

/*** 流程实例相关接口** @author lonewalker*/
@RequestMapping("/process/instance")
@RequiredArgsConstructor
@RestController
public class ProcessInstanceController {private final RuntimeService runtimeService;private final TaskService taskService;/*** 根据流程定义key发起流程实例** @param requestParam 请求参数* @return 流程实例id*/@PostMapping("/startProcessInstanceByKey")public String startProcessInstanceByKey(@RequestBody StartProcessRequest requestParam) {Map<String, Object> paramMap = new HashMap<>(8);List<String> userOneList = new ArrayList<>();List<String> userTwoList = new ArrayList<>();List<String> userThreeList = new ArrayList<>();//一人通过节点的审批人userOneList.add("10086");userOneList.add("10087");//比例通过节点的审批人userTwoList.add("10087");userTwoList.add("10088");userTwoList.add("10089");userTwoList.add("10090");userTwoList.add("10091");//全部通过节点的审批人userThreeList.add("10090");userThreeList.add("10091");paramMap.put("initiator", "10086");paramMap.put("userOneList", userOneList);paramMap.put("userTwoList", userTwoList);paramMap.put("userThreeList", userThreeList);ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(requestParam.getProcessDefinitionKey(), requestParam.getBusinessKey(), paramMap);return processInstance.getProcessInstanceId();}/*** 完成单个任务** @param requestParam 请求参数* @return 任务所在节点信息*/@PostMapping("/completeSingleTask")public Boolean completeSingleTask(@RequestBody @Validated CompleteTaskRequest requestParam) {taskService.complete(requestParam.getTaskId());return true;}
}

发起流程实例后让流程来到【一人通过】节点

在【比例通过】节点设置完成条件是通过人数占总人数的三成,所以只需两个人审批通过即通过:

两人审批通过后是符合预期来到最后一个节点

查看任务的历史表【act_hi_taskinst】,两个任务被完成,其他任务则被删除了。

💖扩展

多实例节点可以配置串行或并行。三条垂直线表示实例将并行执行,而三条水平线表示顺序执行

该部分就不单独做演示了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/668611.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EasyX图形库学习(二、文字输出)

目录 一、文字绘制函数 字体属性结构体:logfont 文字输出 outtextxy 在指定位置输出字符串。 ​编辑 但如果直接使用,可能有以下报错&#xff1a; 三种解决方案&#xff1a; 将一个int类型的分数,输出到图形界面上 如果直接使用&#xff1a; 会把score输入进去根据A…

ROS从入门到精通4-1:Docker安装与常用命令总结

目录 0 专栏介绍1 Docker与机器人应用2 Docker安装步骤3 Docker常用命令3.1 创建与启动容器3.2 暂停与删除容器3.3 容器文件拷贝3.4 构建镜像与上下文 0 专栏介绍 本专栏旨在通过对ROS的系统学习&#xff0c;掌握ROS底层基本分布式原理&#xff0c;并具有机器人建模和应用ROS进…

【文件增量备份系统】前端项目构建

文章目录 创建项目安装项目依赖引入element plus组件下载组件在main.js中使用组件测试 整合路由router下载组件创建路由管理器index.js使用路由App.vue上面使用 <router-view />测试 整合axios下载组件工具类axiosRequest.js工具类使用 创建项目 damwangrunqindeMBP dev…

车载测试中:如何处理 bug

一&#xff1a;Jira 提交 bug 包含那些内容 二&#xff1a;如何处理现上 bug 三&#xff1a;车载相关的 bug 如何定位 四&#xff1a;遇到 bug &#xff0c;复现不出来怎么办 五&#xff1a;bug 的处理流程 一&#xff1a;Jira 提交 bug 包含那些内容二&#xff1a;如何处理现上…

Java设计模式-模板方法模式(14)

行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对…

uniapp android和微信小程序如何实现PDF在线预览

Hello大家好&#xff01;我是咕噜铁蛋&#xff0c;UniApp在开发移动应用时提供了跨平台的解决方案&#xff0c;能够同时支持Android和iOS系统&#xff0c;而微信小程序则是一种轻量级的应用形式&#xff0c;可以在微信内直接运行。本文将探讨如何利用UniApp和微信小程序实现PDF…

k8s学习-Kubernetes的网络

Kubernetes作为编排引擎管理着分布在不同节点上的容器和Pod。Pod、Service、外部组件之间需要⼀种可靠的方找到彼此并进行通信&#xff0c;Kubernetes网络则负责提供这个保障。 1.1 Kubernetes网络模型 Container-to-Container的网络 当Pod被调度到某个节点&#xff0c;Pod中…

java数组学习

目录 1.数组概念 2.数组的定义 3.数组的静态初始化 4.地址值 5.数组元素访问 6.索引 7.数组的遍历 8.数组的动态初始化 9.数组两种初始化方式的区别 10.数组常见问题 1.数组概念 数组是一种容器&#xff0c;可以同来存储同种数据类型的多个值。但是数组容器在存储数据…

Redis核心技术与实战【学习笔记】 - 24.Redis 脑裂

简述 所谓脑裂&#xff0c;就是指在主从集群中&#xff0c;同时有两个主节点&#xff0c;它们都能接收写请求。而脑裂最直接的影响就是客户端不知道该往哪个主节点写入数据&#xff0c;结果就是不同的客户端会往不同的主机诶点上写入数据。而且&#xff0c;严重的话&#xff0…

从零开始手写mmo游戏从框架到爆炸(三)— 服务启动接口与网络事件监听器

上一章我们完成了netty服务启动的相关抽象&#xff08;https://blog.csdn.net/money9sun/article/details/136025471&#xff09;&#xff0c;这一章我们再新增一个全局的服务启动类&#xff0c;方便后续扩展。 服务启动 新增的两个类如下&#xff1a; 定义一个接口IServer …

Elasticsearch:使用 Inference API 进行语义搜索

在我之前的文章 “Elastic Search 8.12&#xff1a;让 Lucene 更快&#xff0c;让开发人员更快”&#xff0c;我有提到 Inference API。这些功能的核心部分始终是灵活的第三方模型管理&#xff0c;使客户能够利用当今市场上下载最多的向量数据库及其选择的转换器模型。在今天的…

框架学习Maven

声明&#xff1a;本文来源于黑马程序员PDF讲义 做为一名Java开发工程师&#xff0c;后端 Web开发技术是我们学习的重点&#xff0c;后端Web开发技术的学习&#xff0c;我们会先学习Java项目的构建工具&#xff1a;Maven 初识Maven Maven是Apache旗下的一个开源项目&#xff…

Verilog实现2进制码与BCD码的互相转换

1、什么是BCD码&#xff1f; BCD码是一种2进制的数字编码形式&#xff0c;用4位2进制数来表示1位10进制中的0~9这10个数。这种编码技术&#xff0c;最常用于会计系统的设计里&#xff0c;因为会计制度经常需要对很长的数字做准确的计算。相对于一般的浮点式记数法&#xff0c;…

2019年江苏省职教高考计算机技能考试——一道程序改错题的分析

题目&#xff1a;函数将str字符串中的5个数字字符串转换为整数&#xff0c;并保存在二维数组m的最后一行&#xff0c;各元素为3、-4、16、18、6。并经函数move处理后&#xff0c;运行结果如下&#xff1a; 18 6 3 -4 16 16 18 6 3 -4 -4 16 …

香港倾斜模型3DTiles数据漫游

谷歌地球全香港地区倾斜摄影数据&#xff0c;通过工具转换成3DTiles格式&#xff0c;将这份数据完美加载到三维数字地球Cesium上进行完美呈现&#xff0c;打造香港地区三维倾斜数据覆盖&#xff0c;完美呈现香港城市壮美以及维多利亚港繁荣景象。再由12.5米高分辨率地形数据&am…

【开源】JAVA+Vue+SpringBoot实现二手车交易系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手车档案管理模块2.3 车辆预约管理模块2.4 车辆预定管理模块2.5 车辆留言板管理模块2.6 车辆资讯管理模块 三、系统设计3.1 E-R图设计3.2 可行性分析3.2.1 技术可行性分析3.2.2 操作可行性3.2.3 经济…

02.05

1.单链表 main #include "1list_head.h" int main(int argc, const char *argv[]) { //创建链表之前链表为空Linklist headNULL;int n;datatype element;printf("please enter n:");scanf("%d",&n);for(int i0;i<n;i){printf("ple…

IDEA新建文件夹后右击不能创建class类排错方法

目录 1 查看自身文件名是否为关键词 2 查看是否被“蓝色文件夹”给包含了 3 检查设置那边的class模板 4 报错解决 1 查看自身文件名是否为关键词 如下使用了 Java中的关键词"class"所以才无法创建包 ---------------------------------------------------------…

量化交易学习4(投资组合基本认识)

1 如何衡量投资组合的收益率 1.1 投资组合收益率的计算方法 1.2 投资组合的绝对收益率和相对收益率 2 如何衡量投资组合的风险 2.1 风险的定义 风险是指在未来可能发生的不确定性事件所带来的潜在损失。 在投资领域中&#xff0c;风险通常指投资所面临的不确定性和潜在的损失…

自学Python第二十二天- Django框架(六) django的实用插件:cron、APScheduler

django-crontab 和 django-cron 有时候需要django在后台不断的执行一个任务&#xff0c;简单的可以通过中间件来实现&#xff0c;但是中间件是根据请求触发的。如果需要定时执行任务&#xff0c;则需要使用到一些插件。 django-crontab 和 django-cron 是常用的用于处理定时任…