基于jeecg-boot的flowable流程加签功能实现
更多nbcio-boot功能请看演示系统
gitee源代码地址
后端代码: https://gitee.com/nbacheng/nbcio-boot
前端代码:https://gitee.com/nbacheng/nbcio-vue.git
在线演示(包括H5) : http://122.227.135.243:9888
今天我们实现nbcio-boot的flowable的流程加签功能。
一、加签的几个概念
1、向前加签
任务在 A 这里,A 这个时候需要 B 核对一下,等 B 核对之后又回到 A 这里,这时 A 才能继续自己的任务
2、向后加签
任务在 A 这里,A 这个时候需要 B 处理这个事情,处理完毕之后就不用管了,继续后面的审批环节
3、多实例加签
任务只能对多实例任务进行加签,其它无效
二、前端实现
界面代码如下:
<!--加签流程--><a-modal :z-index="100" :title="addSignTitle" @cancel="addSignOpen = false" :visible.sync="addSignOpen" :width="'40%'" append-to-body><el-form ref="addSignForm" :model="addSignForm" label-width="160px"><el-form-item label="加签类型" prop="addSignType" :rules="[{ required: true, message: '请选择加签类型', trigger: 'blur' }]"><el-radio-group v-model="addSignForm.addSignType" @change="changeAddSignType"><el-radio :label="0">前加签</el-radio><el-radio :label="1">后加签</el-radio><el-radio :label="2">多实例加签</el-radio></el-radio-group></el-form-item><el-form-item label="用户选择" prop="addSignUsers" :rules="[{ required: true, message: '请选择用户', trigger: 'blur' }]"><j-select-user-by-dep v-model="addSignForm.addSignUsers" /></el-form-item><el-form-item label="处理意见" prop="comment" :rules="[{ required: true, message: '请输入处理意见', trigger: 'blur' }]"><el-input type="textarea" v-model="addSignForm.comment" placeholder="请输入处理意见" /></el-form-item><el-form-item label="附件" prop="commentFileDto.fileurl"><j-upload v-model="addSignForm.commentFileDto.fileurl" ></j-upload></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="addSignOpen = false">取 消</el-button><el-button type="primary" @click="addSignComplete(true)">确 定</el-button></span></a-modal>
加签实现代码如下:
/** 加签 */handleAddSign() {this.addSignOpen = true;this.addSignTitle = "前加签流程";},changeAddSignType(val) {this.addSignForm.addSignType = val;if(this.addSignForm.addSignType === 0) {this.addSignTitle = "前加签流程";}if(this.addSignForm.addSignType === 1) {this.addSignTitle = "后加签流程";}if(this.addSignForm.addSignType === 2) {this.addSignTitle = "多实例加签流程";}console.log("changeAddSignType =",val);console.log("this.addSignTitle =",this.addSignTitle);},/** 加签任务 */addSignComplete() {if (!this.addSignForm.addSignUsers ) {this.$message.error("请选择用户");return;}// 流程信息this.addSignForm.deployId = this.$route.query && this.$route.query.deployId;this.addSignForm.taskId = this.$route.query && this.$route.query.taskId;this.addSignForm.procInsId = this.$route.query && this.$route.query.procInsId;this.addSignForm.instanceId = this.$route.query && this.$route.query.procInsId;// 初始化表单this.addSignForm.procDefId = this.$route.query && this.$route.query.procDefId;this.addSignForm.businessKey = this.$route.query && this.$route.query.businessKey;this.addSignForm.category = this.$route.query && this.$route.query.category;this.addSignForm.dataId = this.$route.query && this.$route.query.businessKey;//节点类型this.addSignForm.nodeType = this.$route.query && this.$route.query.nodeType;//online表单id和数据idthis.addSignForm.onlineId = this.$route.query && this.$route.query.onlineId;if (this.addSignForm.category === 'online') {this.addSignForm.onlineDataId = this.$route.query && this.$route.query.businessKey;} //对formdesigner后续加签审批的时候需要用到this.addSignForm.values = this.taskForm.values;console.log("this.addSignForm=",this.addSignForm);if(this.addSignForm.addSignType === 2) {multiInstanceAddSignTask(this.addSignForm).then(response => {this.$message.success(response.message);this.addSignOpen = false;this.goBack();});}else {addSignTask(this.addSignForm).then(response => {this.$message.success(response.message);this.addSignOpen = false;this.goBack();});}},
实现效果图如下:

三、后端主要代码
@Overridepublic void addTasksBefore(String processInstanceId, String assignee, Set<String> assignees, String description) {addTask(processInstanceId, assignee, assignees, description, Boolean.FALSE);}@Overridepublic void addTasksAfter(String processInstanceId, String assignee, Set<String> assignees, String description) {addTask(processInstanceId, assignee, assignees, description, Boolean.TRUE);}@Override@Transactional(rollbackFor = Exception.class)public void addTask(String processInstanceId, String assignee, Set<String> assignees, String description,Boolean flag) {TaskEntityImpl task = (TaskEntityImpl) taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(assignee).singleResult();Assert.notNull(task, String.format("分配人 [%s] 没有待处理任务", assignee));//如果是加签再加签String parentTaskId = task.getParentTaskId();if (StrUtil.isBlank(parentTaskId)) {task.setOwner(assignee);task.setAssignee(null);task.setCountEnabled(true);if (flag) {task.setScopeType("after");} else {task.setScopeType("before");}// 设置任务为空执行者taskService.saveTask(task);}//添加加签数据this.createSignSubTasks(assignee, assignees, task);//添加审批意见String type = flag ? FlowComment.HJQ.getType() : FlowComment.QJQ.getType();taskService.addComment(task.getId(), processInstanceId, type, description);}/*** 创建加签子任务* @param assignees 被加签人* @param assignee 加签人* @param taskEntity 父任务*/private void createSignSubTasks(String assignee, Set<String> assignees, TaskEntity taskEntity) {if (CollectionUtil.isNotEmpty(assignees)) {//1.创建被加签人的任务列表assignees.forEach(userId -> {if (StrUtil.isNotBlank(userId)) {this.createSubTask(taskEntity, taskEntity.getId(), userId);}});String parentTaskId = taskEntity.getParentTaskId();if (StrUtil.isBlank(parentTaskId)) {parentTaskId = taskEntity.getId();}String finalParentTaskId = parentTaskId;//2.创建加签人的任务并执行完毕String taskId = taskEntity.getId();if (StrUtil.isBlank(taskEntity.getParentTaskId())) {Task task = this.createSubTask(taskEntity, finalParentTaskId, assignee);taskId = task.getId();}Task taskInfo = taskService.createTaskQuery().taskId(taskId).singleResult();if (ObjectUtil.isNotNull(taskInfo)) {taskService.complete(taskId);}//如果是候选人,需要删除运行时候选不中的数据。long candidateCount = taskService.createTaskQuery().taskId(parentTaskId).taskCandidateUser(assignee).count();if (candidateCount > 0) {taskService.deleteCandidateUser(parentTaskId, assignee);}}}public String getMultiInstanceActAssigneeParam(String processDefinitionId, String actId) {AtomicReference<String> resultParam = new AtomicReference<>();ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();//获取bpmnModel并转为modelNodeBpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());//获取主流程Process mainProcess = bpmnModel.getMainProcess();//获取用户任务节点类型,深入子流程mainProcess.findFlowElementsOfType(UserTask.class, true).forEach(userTask -> {String userTaskId = userTask.getId();if (userTaskId.equals(actId)) {Object behavior = userTask.getBehavior();if (ObjectUtil.isNotNull(behavior)) {//并行多实例节点if (behavior instanceof ParallelMultiInstanceBehavior) {ParallelMultiInstanceBehavior parallelMultiInstanceBehavior =(ParallelMultiInstanceBehavior) behavior;String collectionElementVariable = parallelMultiInstanceBehavior.getCollectionElementVariable();if (ObjectUtil.isNotEmpty(collectionElementVariable)) {resultParam.set(collectionElementVariable);}}//串行多实例节点if (behavior instanceof SequentialMultiInstanceBehavior) {SequentialMultiInstanceBehavior sequentialMultiInstanceBehavior =(SequentialMultiInstanceBehavior) behavior;String collectionElementVariable = sequentialMultiInstanceBehavior.getCollectionElementVariable();if (ObjectUtil.isNotEmpty(collectionElementVariable)) {resultParam.set(collectionElementVariable);}}}}});return resultParam.get();}
四、实际效果图如下:

相关文章:
基于jeecg-boot的flowable流程加签功能实现
更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: https://gitee.com/nbacheng/nbcio-boot 前端代码:https://gitee.com/nbacheng/nbcio-vue.git 在线演示(包括H5) : http://122.227.135.243:9888 今天我…...
day-03 基于TCP的服务器端/客户端
一.理解TCP和UDP TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种常见的传输层协议,用于在计算机网络中提供可靠的数据传输。 1.TCP: 连接导向:TCP是一种面向连接的…...
匿名对象和一般对象的区别
1.格式的不同 一般对象的格式: Object obj new Object(); 匿名对象的格式: new Object(); 2.作为参数传递机制的不同 2.1先看看一般对象的使用机制 执行步骤: 1.首先程序进入main()函数,执行Object obj,…...
[MyBatis系列⑥]注解开发
🍃作者简介:准大三本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐MyBatis系列①:增删改查 ⭐MyBatis系列②:两种Dao开发方式 ⭐MyBatis系列③:动态SQL ⭐MyBatis系列④:核心…...
[ACL2023] Exploring Lottery Prompts for Pre-trained Language Models
Exploring Lottery Prompts for Pre-trained Language Models 文章链接 清深的工作,比较有意思的一篇。作者先给出假设,对于分类问题,在有限的语料空间内总能找到一个prompt让这个问题分类正确,作者称之为lottery prompt。为此&…...
【Python编程】将同一种图片分类到同一文件夹下,并且将其分类的路径信息写成txt文件进行保存
注:数据结构同上一篇博文类似 一、代码 import os import cv2 import shutilpath0os.getcwd()\\apple\\RGB path1os.getcwd()\\apple\\tof_confidence # path2os.getcwd()\\apple\\tof_depth # path3os.getcwd()\\apple\\tof_depthRGB # path4os.getcwd()\\apple\…...
单例模式的相关知识
饿汉模式 package Thread; class Singleton{private static Singleton instance new Singleton();public static Singleton getInstance(){return instance;}private Singleton(){} }public class demo1 {public static void main(String[] args) {Singleton S1 Singleton.ge…...
vue问题相关记录
1. vue的 nextTick的原理 首先vue实现响应式并不是数据发生变化后dom立即更新,而是按照一定的策略 异步执行dom更新的。 vue在修改数据后,试图不会立即进行更新,而是要等同一事件循环机制内所有数据变化完成之后,在统一更新 next…...
skywalking服务部署
一、前言 Apache SkyWalking 是一个开源的分布式跟踪、监控和诊断系统,旨在帮助用户监控和诊断分布式应用程序、微服务架构和云原生应用的性能和健康状况。它提供了可视化的分析工具,帮助开发人员和运维团队深入了解应用程序的性能、调用链和异常情况 …...
【uni-app】压缩图片并添加水印
总体思路 dom 结点 这里的 cvHeight 和 cvWidth 初始时要设置为你后续需要压缩后的最大宽高。假设我们在图片上传后图片最大为 350 * 350 <u-upload :fileList"baseInfoFormData.entrustFileList" afterRead"afterFileRead" multiple></u-uploa…...
《每天十分钟》-红宝书第4版-变量、作用域与内存
最近有点忙,好长时间没抄经了,今天继续,之前语言基础相对简单,跳过一部分操作符。 变量 js 的变量是特殊的松散类型,由于没有规则定义变量必须包含什么数据类型,变量的值和数据类型在脚本生命期内可以改变…...
NFTScan | 08.21~08.27 NFT 市场热点汇总
欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。周期:2023.08.21~ 2023.08.27 NFT Hot News 01/ NFT 品牌体验平台 Recur 将于 11 月 16 日彻底关闭,此前曾获 5000 万美元融资 8 月 21 日,NFT 品牌体验平台 Recur 在 X…...
【Java 中级】一文精通 Spring MVC - 数据验证(七)
👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主 ⛪️ 个人社区&#x…...
css奇数偶数选择器
前端项目开发中,需要根据行数的奇数和偶数的不同,设置不同的颜色显示,以在视觉上给用户以良好的浏览体验,这里就需要使用css奇数偶数选择器。 主要用的::nth-of-type或者:nth-child。 方式一:nth-child div:nth-chi…...
【算法】双指针求解盛最多水的容器
Problem: 11. 盛最多水的容器 文章目录 题目解析算法原理讲解复杂度Code 题目解析 首先我们来解析一下本题 题目中说到,要找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 那我们现在来看最外侧的两根,一个高度为8&#…...
浅析SAS协议:设备接入与探测
文章目录 SAS设备初始化OOB信号SAS设备间OOB交互场景一:SAS设备两边同时发送SAS COMINIT信号场景二:SAS设备A先发送COMINIT信号场景三:SAS设备B错过COMINIT信号 SAS与SATA设备间OOB交互场景一:SATA设备未响应COMSAS信号场景二&…...
RISC-V IOPMP实际用例-Andes SoC‘s Rapid-k模型
安全之安全(security)博客目录导读 2023 RISC-V中国峰会 安全相关议题汇总 说明:本文参考RISC-V 2023中国峰会如下议题,版权归原作者所有。...
【高阶数据结构】哈希表详解
文章目录 前言1. 哈希的概念2. 哈希冲突3. 哈希函数3.1 直接定址法3.2 除留余数法--(常用)3.3 平方取中法--(了解)3.4 折叠法--(了解)3.5 随机数法--(了解)3.6 数学分析法--(了解) 4. 哈希冲突的解决方法及不同方法对应的哈希表实现4.1 闭散列(开放定址法࿰…...
C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端
1、客户端选择 客户端可以是一个程序或一个设备,这里我以C#WINFORM程序来实现客户机与PLC的Modbustcp服务器通信,开发环境是VS2019,.NET Framework版本是4.7.2 2、创建winform程序 3、引入Nmodbus4协议 找到项目,找到引用&…...
性能调优篇 二、Jvm监控及诊断工具-命令行篇
目录 一、概述1、简单命令行工具 二、jps:查看正在运行的Java程序(掌握)1、是什么?2、测试3、基本语法 三、jstat:查看jvm统计信息(掌握)1、是什么?2、基本语法3、补充 四、jinfo&am…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
