基于jeecg-boot的flowable流程加签功能实现

news2024/12/23 8:26:07

   

更多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和数据id
        this.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();
          });
        }
      },

实现效果图如下:

三、后端主要代码

@Override
	public void addTasksBefore(String processInstanceId, String assignee, Set<String> assignees, String description) {
		addTask(processInstanceId, assignee, assignees, description, Boolean.FALSE);
		
	}

	@Override
	public 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并转为modelNode
        BpmnModel 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();
    }

四、实际效果图如下:

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

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

相关文章

【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 )

文章目录 一、变量的本质 - 引入 " 引用 " 概念1、变量的本质 - 内存别名2、引入 " 引用 " 概念 - 已定义变量的内存别名3、" 引用 " 的优点 二、引用语法简介1、语法说明2、代码示例 - 引用的定义和使用 三、引用做函数参数1、普通引用必须初始…

minikube安装

minikube也是需要docker环境的&#xff0c;首先看一下docker 下载docker.repo源到本地 通过repo里面查找最新的docker 开始安装docker 修改docker 下载加速地址&#xff0c; systemctl deamon-reload 下载minikube minikube start | minikube curl -LO https://storage.goog…

Mybatis(二)映射文件配置与动态SQL

Mybatis&#xff08;二&#xff09;映射文件配置 1.Mybatis映射文件配置 1.入参 1.1.parameterType(了解) CRUD标签都有一个属性parameterType&#xff0c;底层的statement通过它指定接收的参数类型。入参数据有以下几种类型&#xff1a;HashMap&#xff0c;基本数据类型&a…

会计资料基础

会计资料 1.会计要素及确认与计量 1.1 会计基础 1.2 六项会计要素小结 1.3 利润的确认条件 1.3.1 利润的定义和确认条件 1.4 会计要素及确认条件 2.六项会计要素 2.1 资产的特征及其确认条件 这部分资产可以给企业带来经济收益&#xff0c;但是如果不能带来经济利益&#xff…

提升团队合作效率:企业网盘的文件管理和协作利用方法

随着信息技术的飞速发展&#xff0c;企业越来越依赖于网络和云服务来提高工作效率。在这样的背景下&#xff0c;企业网盘作为一种重要的在线存储和协作工具&#xff0c;正在被越来越多的企业所采用。本文将探讨如何利用企业网盘进行文件管理和协作&#xff0c;从而构建高效的团…

Windows快捷键常用介绍,提高工作(摸鱼)效率

一&#xff1a;背景 本文主要是讲解Windows电脑常见的快捷键&#xff0c;包括ctrl快捷键&#xff0c;win快捷键&#xff0c;不管是开发人员还是普通办公人员&#xff0c;都是很方便的。我们平时没事操作都是用鼠标去选择对应的功能&#xff0c;或者在我的电脑--控制面板寻找&a…

把matlab的m文件打包成单独的可执行文件

安装Matlab Compiler Adds-on在app里找到Application Compiler 选择要打包的文件matlab单独的运行程序的话需要把依赖的库做成runtime. 这里有两个选项. 上面那个是需要对方在联网的情况下安装, 安装包较小.下面那个是直接把runtime打包成安装程序, 大概由你的程序依赖的库的多…

谷粒商城环境搭建一:Docker容器部署

Docker容器部署 VMware虚拟机安装 参考&#xff1a;VMware虚拟机安装Linux教程 Docker安装 Linux安装Docker # 1.更新apt包索引 sudo apt-get update# 2.安装以下包以使apt可以通过HTTPS使用存储库&#xff08;repository&#xff09; sudo apt-get install -y apt-transpor…

滑动窗口介绍

1.基本概念 利用单调性&#xff0c;使用同向双指针&#xff0c;两个指针之间形成一个窗口 子串与子数组都是连续的一段子序列时不连续的 2.为什么可以用滑动窗口&#xff1f; 暴力解决时发现两个指针不需要回退&#xff08;没必要回退&#xff0c;一定不会符合结果&#xf…

什么是有效的预测性维护 ?

在现代制造业的背景下&#xff0c;设备的可靠性和生产效率成为了企业追求的关键目标。而预测性维护&#xff08;Predictive Maintenance&#xff0c;简称PdM&#xff09;作为一种先进的维护策略&#xff0c;逐渐成为了实现这些目标的重要工具。然而&#xff0c;什么是有效的预测…

2023年国赛数学建模思路 - 案例:随机森林

文章目录 1 什么是随机森林&#xff1f;2 随机深林构造流程3 随机森林的优缺点3.1 优点3.2 缺点 4 随机深林算法实现 建模资料 ## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 什么是随机森林&#xff…

AP9235 dc-dc升压恒流电源驱动IC 2.8-30V 输出电流2A SOT23-6

概述 AP9235B 系列是一款固定振荡频率、恒流输出的升压型DC/DC转换器&#xff0c;非常适合于移动电话、PDA、数码相机等电子产品的背光驱动。输出电压可达30V &#xff0c;3.2V输入电压可以驱动六个串联LED&#xff0c; 2.5V输入电压可以驱动两路并联LED&#xff08;每路串联…

你不知道的 malloc 内幕

你不知道的 malloc 内幕 1. 引言&#xff1a;一个例子例1例2 2. 基础概念2.1 内存管理发展过程2.2 虚拟存储器2.3 内存分配机制2.4 VMA2.4.1 进程的 VMA2.4.2 vma 分析 3. 实例分析3.1 malloc 到底干了啥3.2 memset 的偷天换日3.2.1 虚拟地址转物理地址3.2.2 page fault 3.3 fr…

线程池UncaughtExceptionHandler无效?可能是使用方式不对

背景 在业务处理中&#xff0c;使用了线程池来提交任务执行&#xff0c;但是今天修改了一小段代码&#xff0c;发现任务未正确执行。而且看了相关日志&#xff0c;也并未打印结果。 源码简化版如下&#xff1a; 首先&#xff0c;自定义了一个线程池 public class NamedThrea…

iMX6ULL QT环境配置 | CMake在Linux下的交叉编译环境搭建及使用

习惯了使用cmake&#xff0c;再也不想回到手写makefile的年代了。相比手写makefile&#xff0c;使用cmake则像是实现了机动化&#xff0c;管理项目工程的编译变得很简单了。况且cmake很流行&#xff0c;linux下的很多软件源码包&#xff0c;很多也都使用了cmake的方式编译。因此…

大数据课程K4——Spark的DAGRDD依赖关系

文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Spark的DAG; ⚪ 掌握Spark的RDD的依赖关系; ⚪ 了解Spark对于DAG的Stage的划分; 一、DAG概念 1. 概述 Spark会根据用户提交的计算逻辑中的RDD的转换和动作来生成RDD之间的依赖关…

Android JNI系列详解之AS创建Native C++项目

一、前提 Android Studio版本&#xff1a;Android Studio Electric Eel | 2022.1.1 Patch 1 二、创建Native C项目 1.新建项目 2.选择新建Native C项目 3.New Project 4.选择C标准库的支持版本 5.项目自带的默认生成的代码 6.buil.gradle中也自带了CMakeList的配置&#xff08;…

详细了解G1、了解G1、G1垃圾收集器详解、G1垃圾回收器简单调优

4.详细了解G1&#xff1a; 4.1.一&#xff1a;什么是垃圾回收 4.2.了解G1 4.3.G1 Yong GC 4.4.G1 Mix GC 4.5.三色标记算法 4.6.调优实践 5.G1垃圾收集器详解 5.1.G1垃圾收集器 5.2.G1的堆内存划分 5.3.G1的运行过程 5.4.三色标记 5.4.1.漏标问题 5.5.记忆集与卡表 5.6.安全点与…

开发小技巧(逐步完善)

一、验证码 1&#xff09;将 大小写字母 和 数字 存储在字符数组中 2&#xff09;用随机数的方式生成随机码 3&#xff09;采用字符串的方式存储验证码即可 import java.util.Random;public class TEST {public static void main(String[] args) {char[] chs new char[62];//…

小程序中的全局配置以及常用的配置项(window,tabBar)

全局配置文件和常用的配置项 app.json: pages:是一个数组&#xff0c;用于记录当前小程序所有页面的存放路径&#xff0c;可以通过它来创建页面 window:全局设置小程序窗口的外观(导航栏&#xff0c;背景&#xff0c;页面的主体) tabBar:设置小程序底部的 tabBar效果 style:是否…