基于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…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
