基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持自定义业务表单流程(三)
更多ruoyi-nbcio功能请看演示系统
gitee源代码地址
前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio
演示地址:RuoYi-Nbcio后台管理系统
相应的后端也要做一些调整
1、启动流程修改如下:
/*** 启动流程实例*/private R startProcess(ProcessDefinition procDef, Map<String, Object> variables) {if (ObjectUtil.isNotNull(procDef) && procDef.isSuspended()) {throw new ServiceException("流程已被挂起,请先激活流程");} // 设置流程发起人Id到流程中,包括变量String userStr = TaskUtils.getUserName();SysUser sysUsr = sysUserService.selectUserByUserName(userStr);setFlowVariables(sysUsr,variables); Map<String, Object> variablesnew = variables;Map<String, Object> usermap = new HashMap<String, Object>();List<String> userlist = new ArrayList<String>();boolean bparallelGateway = false;boolean bapprovedEG = false;//业务数据idString dataId = variables.get("dataId").toString();if(StringUtils.isNotEmpty(dataId)) {//自定义业务表单//设置自定义表单dataid的数据 WfMyBusiness flowmybusiness = wfMyBusinessServiceImpl.getByDataId(variables.get("dataId").toString());String serviceImplName = flowmybusiness.getServiceImplName();WfCallBackServiceI flowCallBackService = (WfCallBackServiceI) SpringContextUtils.getBean(serviceImplName);if (flowCallBackService!=null){Object businessDataById = flowCallBackService.getBusinessDataById(variables.get("dataId").toString());variables.put("formData",businessDataById);}}//获取下个节点信息getNextFlowInfo(procDef, variablesnew, usermap, variables, userlist);//取出两个特殊的变量if(variablesnew.containsKey("bparallelGateway")) {//并行网关bparallelGateway = (boolean) variablesnew.get("bparallelGateway");variablesnew.remove("bparallelGateway");}if(variablesnew.containsKey("bapprovedEG")) {//通用拒绝同意排它网关bapprovedEG = (boolean) variablesnew.get("bapprovedEG");variablesnew.remove("bapprovedEG");}// 发起流程实例ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDef.getId(), variables);// 第一个用户任务为发起人,则自动完成任务//wfTaskService.startFirstTask(processInstance, variables);R<Void> result = setNextAssignee(processInstance, usermap, userlist, sysUsr, variables, bparallelGateway, bapprovedEG); if(StringUtils.isNotEmpty(dataId)) {//自定义业务表单// 流程发起后的自定义业务更新-需要考虑两种情况,第一个发起人审批或跳过List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).active().list();/*======================todo 启动之后 回调以及关键数据保存======================*///如果保存数据前未调用必调的FlowCommonService.initActBusiness方法,就会有问题LoginUser sysUser = commonService.getLoginUser();if(tasks!=null) {SysUser sysTaskUser = new SysUser();List <String> listUser = new ArrayList<String>();List <String> listId = new ArrayList<String>();List <String> listName = new ArrayList<String>();String taskUser = "";String taskid = "";String taskName = "";int taskPriority = 0;for(Task task : tasks) {if(task.getAssignee() != null) {sysTaskUser = commonService.getSysUserByUserName(task.getAssignee());listUser.add(sysTaskUser.getNickName());}listId.add(task.getId());listName.add(task.getName());taskPriority = task.getPriority();}taskUser = listUser.stream().map(String::valueOf).collect(Collectors.joining(","));taskid = listId.stream().map(String::valueOf).collect(Collectors.joining(","));taskName = listName.stream().map(String::valueOf).collect(Collectors.joining(","));WfMyBusiness business = wfMyBusinessServiceImpl.getByDataId(dataId);business.setProcessDefinitionId(procDef.getId());business.setProcessInstanceId(processInstance.getProcessInstanceId());business.setActStatus(ActStatus.doing);business.setProposer(sysUser.getUsername());business.setTaskId(taskid);business.setTaskName(taskName);business.setTaskNameId(taskid);business.setPriority(String.valueOf(taskPriority));business.setDoneUsers("");business.setTodoUsers(taskUser);wfMyBusinessService.updateById(business);//spring容器类名String serviceImplNameafter = business.getServiceImplName();WfCallBackServiceI flowCallBackServiceafter = (WfCallBackServiceI) SpringContextUtils.getBean(serviceImplNameafter);// 流程处理完后,进行回调业务层business.setValues(variables);if (flowCallBackServiceafter!=null)flowCallBackServiceafter.afterFlowHandle(business);}else {WfMyBusiness business = wfMyBusinessServiceImpl.getByDataId(dataId);business.setProcessDefinitionId(procDef.getId());business.setProcessInstanceId(processInstance.getProcessInstanceId());business.setActStatus(ActStatus.pass);business.setProposer(sysUser.getUsername());business.setTaskId("");business.setTaskName("");business.setTaskNameId("");business.setDoneUsers("");business.setTodoUsers("");wfMyBusinessService.updateById(business);//spring容器类名String serviceImplNameafter = business.getServiceImplName();WfCallBackServiceI flowCallBackServiceafter = (WfCallBackServiceI) SpringContextUtils.getBean(serviceImplNameafter);// 流程处理完后,进行回调业务层business.setValues(variables);if (flowCallBackServiceafter!=null)flowCallBackServiceafter.afterFlowHandle(business);}}return result; }
2、获取表单列表修改如下:
/*** 获取历史流程表单信息*/private List<FormConf> processFormList(BpmnModel bpmnModel, HistoricProcessInstance historicProcIns, String dataId) {List<FormConf> procFormList = new ArrayList<>();List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(historicProcIns.getId()).finished().activityTypes(CollUtil.newHashSet(BpmnXMLConstants.ELEMENT_EVENT_START, BpmnXMLConstants.ELEMENT_TASK_USER)).orderByHistoricActivityInstanceStartTime().asc().list();List<String> processFormKeys = new ArrayList<>();for (HistoricActivityInstance activityInstance : activityInstanceList) {// 获取当前节点流程元素信息FlowElement flowElement = ModelUtils.getFlowElementById(bpmnModel, activityInstance.getActivityId());// 获取当前节点表单KeyString formKey = ModelUtils.getFormKey(flowElement);if (formKey == null) {continue;}boolean localScope = Convert.toBool(ModelUtils.getElementAttributeValue(flowElement, ProcessConstants.PROCESS_FORM_LOCAL_SCOPE), false);Map<String, Object> variables;if (localScope) {// 查询任务节点参数,并转换成Mapvariables = historyService.createHistoricVariableInstanceQuery().processInstanceId(historicProcIns.getId()).taskId(activityInstance.getTaskId()).list().stream().collect(Collectors.toMap(HistoricVariableInstance::getVariableName, HistoricVariableInstance::getValue));} else {if (processFormKeys.contains(formKey)) {continue;}variables = historicProcIns.getProcessVariables();processFormKeys.add(formKey);} Map<String, Object> formvariables = new HashedMap<String, Object>();//遍历Mapif(variables.containsKey("variables")) {formvariables = (Map<String, Object>)((Map<String, Object>) variables.get("variables")).get("formValue");}// 非节点表单此处查询结果可能有多条,只获取第一条信息List<WfDeployFormVo> formInfoList = deployFormMapper.selectVoList(new LambdaQueryWrapper<WfDeployForm>().eq(WfDeployForm::getDeployId, historicProcIns.getDeploymentId()).eq(WfDeployForm::getFormKey, formKey).eq(localScope, WfDeployForm::getNodeKey, flowElement.getId()));//@update by Brath:避免空集合导致的NULL空指针WfDeployFormVo formInfo = formInfoList.stream().findFirst().orElse(null);if (ObjectUtil.isNotNull(formInfo)) {// 旧数据 formInfo.getFormName() 为 nullString formName = Optional.ofNullable(formInfo.getFormName()).orElse(StringUtils.EMPTY);String title = localScope ? formName.concat("(" + flowElement.getName() + ")") : formName;FormConf formConf = JsonUtils.parseObject(formInfo.getContent(), FormConf.class);if (null != formConf) {//ProcessFormUtils.fillFormData(formConf, variables);formConf.setTitle(title);formConf.setFormValues(formvariables);procFormList.add(formConf);}}}if(StringUtils.isNoneEmpty(dataId)) {WfMyBusiness business = wfMyBusinessServiceImpl.getByDataId(dataId);String serviceImplName = business.getServiceImplName();WfCallBackServiceI flowCallBackService = (WfCallBackServiceI) SpringContextUtils.getBean(serviceImplName);// 流程处理完后,进行回调业务层if (flowCallBackService!=null){Map<String, Object> customMap = new HashMap<String, Object>();FormConf formConf = new FormConf();Object businessDataById = flowCallBackService.getBusinessDataById(dataId);customMap.put("formData",businessDataById);customMap.put("routeName", business.getRouteName());formConf.setFormValues(customMap);procFormList.add(formConf);}}return procFormList;}
3、效果图如下:
相关文章:
基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持自定义业务表单流程(三)
更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 相应的后端也要做一些调整 1、启动流程修改如下: /*** 启动流程实例*/private R startProce…...
Spring-事务源码解析2
上一篇文章我们介绍了事务开启注解EnableTransactionManagement源码解析《Spring-事务源码解析1》 里面提到了2个关键组件,这里我们分析下Spring如何利用这2个组件来给Bean创建代理对象。 本篇文章我们看下当一个类里面包含了Transactional注解,Spring如…...
基于ssm008医院门诊挂号系统+jsp【附PPT|开题|任务书|万字文档(LW)和搭建文档】
主要功能 后台登录:4个角色 管理员: ①个人中心、修改密码、个人信息 ②药房管理、护士管理、医生管理、病人信息管理、科室信息管理、挂号管理、诊断信息管理、病例库管理、开药信息管理、药品信息管理、收费信息管理 药房: ①个人中心、修…...
【Linux常用命令11】Linux文件与权限详解
权限 r :读权限,用数字4表示 w :写权限,用数字2表示 x :执行权限,用数字1表示 常用权限 644:代表所有者拥有读、写权限,而所属组和其他人拥有只读权限。 755:代表所有…...
BAT026:删除当前目录指定文件夹以外的文件夹
引言:编写批处理程序,实现删除当前目录指定文件夹以外的文件夹。 一、新建Windows批处理文件 参考博客: CSDNhttps://mp.csdn.net/mp_blog/creation/editor/132137544 二、写入批处理代码 1.右键新建的批处理文件,点击【编辑】…...
Python浏览器自动化
如果你正在进行手机爬虫的工作,并且希望通过模拟浏览器行为来抓取数据,那么Pyppeteer将会是你的理想选择。Pyppeteer是一个强大的Python库,它可以让你控制浏览器进行自动化操作,如点击按钮、填写表单等,从而实现数据的…...
基于tornado BELLE 搭建本地的web 服务
我的github 将BELLE 封装成web 后端服务,采用tornado 框架 import timeimport torch import torch.nn as nnfrom gptq import * from modelutils import * from quant import *from transformers import AutoTokenizer import sys import json #import lightgbm a…...
信息系统漏洞与风险管理制度
1、总则 1.1、目的 为了进一步规范XXXXX单位信息系统风险管理活动,提升风险管理工作的可操纵性和适用性,使信息网络正常运行,防止网络攻击,保证业务的正常进行,依据XXXXX单位员的相关规范和标准规定,特制…...
Hadoop3教程(十七):MapReduce之ReduceJoin案例分析
文章目录 (113)ReduceJoin案例需求分析(114)ReduceJoin案例代码实操 - TableBean(115)ReduceJoin案例代码实操 - TableMapper(116)ReduceJoin案例代码实操 - Reducer及Driver参考文献…...
BAT026:删除当前目录及子目录下的空文件夹
引言:编写批处理程序,实现批量删除当前目录及子目录下的空文件夹。 一、新建Windows批处理文件 参考博客: CSDNhttps://mp.csdn.net/mp_blog/creation/editor/132137544 二、写入批处理代码 1.右键新建的批处理文件,点击【编辑…...
nodejs+vue网课学习平台
目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性:…...
Can Language Models Make Fun? A Case Study in Chinese Comical Crosstalk
本文是LLM系列文章,针对《Can Language Models Make Fun? A Case Study in Chinese Comical Crosstalk》的翻译。 语言模型能制造乐趣吗?中国滑稽相声个案研究 摘要1 引言2 问题定义3 数据集4 使用自动评估生成基准5 人工评估6 讨论7 结论与未来工作 摘要 语言是…...
阿里云云服务器实例使用教学
目录 云服务器免费试用 详细步骤 Xshell 远程连接 云服务器免费试用 阿里云云服务器网址:阿里云免费试用 - 阿里云 详细步骤 访问阿里云免费试用。单击页面右上方的登录/注册按钮,并根据页面提示完成账号登录(已有阿里云账号)…...
promisify 是 Node.js 标准库 util 模块中的一个函数
promisify 是 Node.js 标准库 util 模块中的一个函数。它用于将遵循 Node.js 回调风格的函数转换为返回 Promise 的函数。这使得你可以使用 async/await 语法来等待异步操作完成,从而让异步代码看起来更像同步代码。 在 Node.js 的回调风格中,函数通常接…...
ArcGIS在VUE框架中的构建思想
项目快要上线了,出乎意料的有些空闲时间。想着就把其他公司开发的一期代码里面,把关于地图方面的代码给优化一下。试运行的时候,客户说控制台有很多飘红的报错,他们很在意,虽然很不情愿,但能改的就给改了吧…...
【Overload游戏引擎细节分析】视图投影矩阵计算与摄像机
本文只罗列公式,不做具体的推导。 OpenGL本身没有摄像机(Camera)的概念,但我们为了产品上的需求与编程上的方便,一般会抽象一个摄像机组件。摄像机类似于人眼,可以建立一个本地坐标系。相机的位置是坐标原点,摄像机的朝…...
什么是云原生?零基础学云原生难吗?
伴随着云计算的浪潮,云原生概念也应运而生,而且火得一塌糊涂,但真正谈起“云原生”,大多数非 IT 从业者的认知往往仅限于将服务应用放入云端,在云上处理业务。实际上,云原生远不止于此。 现在越来越多的企…...
Ubuntu18.04下载安装基于使用QT的pcl1.13+vtk8.2,以及卸载
一、QVTKWidget、QVTKWidget2、QVTKOpenGLWidget、QVTKOpenGLNativeWidget 区别 1.Qt版本 Qt5.4以前版本:QVTKWidget2/QVTKWidget。 Qt5.4以后版本:QVTKOpenGLWidget/QVTKOpenGLWidget。 2.VTK版本(Qt版本为5.4之后) 在VTK8.2以前的版本:QVT…...
7 使用Docker容器管理的tomcat容器中的项目连接mysql数据库
1、查看容器的IP 1)进入容器 docker exec -it mysql-test /bin/bash 2)显示hosts文件内容 cat /etc/hosts 这里容器的ip为172.17.0.2 除了上面的方法外,也可以在容器外使用docker inspect查看容器的IP docker inspect mysql-test 以下为…...
双节前把我的网站重构了一遍
赶在中秋国庆假期前,终于将我的网站(https://spacexcode.com/[1])结构定好了,如之前所说,这个网站的定位就是作为自己的前端知识沉淀。内容大致从:前端涉及的基础知识分类汇总(知识库࿰…...
基于 nodejs+vue网上考勤系统
目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性:…...
以数智化指标管理,驱动光伏能源行业的市场推进
近年来,碳中和、碳达峰等降低碳排放、提升环境健康度的政策和技术改进正在不断地被社会所认可和引起重视,也被越来越多的企业在生产运营和基础建设中列为重要目标之一。而光伏能源行业作为全球绿色能源、新能源的优秀解决方案,充分利用太阳能…...
lv8 嵌入式开发-网络编程开发 18 广播与组播的实现
目录 1 广播 1.1 什么是广播? 1.2 广播地址 1.3 广播的实现 2 组播 2.1 分类的IP地址 2.2 多播 IP 地址 2.3 组播的实现 1 广播 1.1 什么是广播? 数据包发送方式只有一个接受方,称为单播 如果同时发给局域网中的所有主机࿰…...
前端面试题个人笔记(后面继续更新完善)
文章目录 填空题部分简答题部分 if有好答案请各位大佬们在底下评论上,感谢 填空题部分 1、常见的css选择器 2、getElementById获取元素的(DOM)对象 简答题部分 1、介绍一下你对RESTful API的理解以及它的优势? 答: …...
软件设计之工厂方法模式
工厂方法模式指定义一个创建对象的接口,让子类决定实例化哪一个类。 结构关系如下: 可以看到,客户端创建了两个接口,一个AbstractFactory,负责创建产品,一个Product,负责产品的实现。ConcreteF…...
【Linux】shell运行原理及权限
主页点击直达:个人主页 我的小仓库:代码仓库 C语言偷着笑:C语言专栏 数据结构挨打小记:初阶数据结构专栏 Linux被操作记:Linux专栏 LeetCode刷题掉发记:LeetCode刷题 算法:算法专栏 C头疼…...
OA系统和ERP系统有什么区别?
在当今的企业管理领域,协同办公管理系统和ERP系统是两个非常重要的工具。它们在企业的日常运营中扮演着不同的角色,有着各自独特的功能和优势。那么,OA系统和ERP系统到底有什么区别呢?协同办公管理系统又是如何在这两者之间发挥协…...
c语言之strcat函数使用和实现
文章目录 前言一、strcat函数使用二、实现方法 前言 c语言之strcat 函数使用和实现 一、strcat函数使用 原型: char *strcat ( char * destination, const char * source );strcat追加拷贝,追加到目标空间后面,目标空间必须足够大,能容纳下…...
Halo-Theme-Hao文档:如何设置导航栏?
本篇文章会教你如何配置导航栏,最终效果参考如下。 感谢 Lanbin、小孙同学 等同学的贡献(语雀参与编辑)。 1标题 进入站点后台 点击左侧面板中的 主题 点击上方的 导航 修改 标题字段即可 2主菜单 主菜单即网站导航栏中间部分的菜单 进入站点…...
【Java学习之道】Java网络编程API介绍
引言 在Java中,进行网络编程的主要方式是通过Java网络编程API。这些API提供了一组类和接口,用于创建网络应用,如TCP和UDP通信、URL访问等。在这一节中,我们将带你领略Java网络编程API的魅力。 一、InetAddress InetAddress类是表…...
免费网站建设新技术/谷歌seo优化公司
1、了解tomcatTomcat不是一个完整意义上的Jave EE(j2ee)服务器,因为它没有提供完整的Java EE企业应用平台的API。但是由于Tomcat遵循apache开源协议,并且对当前Java开发框架开源组件Structs、Spring和Hibernate等实现完美支持&…...
做app一定要做网站吗/榜单优化
thrift需要使用对应语法编写接口用于生成对应语言的接口,本文简单介绍会用到的数据类型 基础类型 bool/byte/i16/i32/i64/double/string 其中没有无符号整型类型。 containers 集合类 list/set/map structs 自定义将多个字段封装起来的数据类型,每个字段…...
网站建设相关关键词/武汉seo网络营销推广
发布一个k8s部署视频:https://edu.csdn.net/course/detail/26967 课程内容:各种k8s部署方式。包括minikube部署,kubeadm部署,kubeasz部署,rancher部署,k3s部署。包括开发测试环境部署k8s,和生产…...
wordpress相册打造的视频弹出/如何制作个人网站
首款骁龙870平板官宣:联想小新平板 5月25日 见预热了许久的联想小新平板,终于揭开了神秘的面纱,联想小新官博昨天发布官宣消息:真香价 5月25日 19:30分 平板发布会见。根据联想小新官博预热来看,此次发布会…...
做网站需要公司吗/广州网站运营专注乐云seo
By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 ROCKCHIP I2C 开发指南概述1. I2C 流程1.1 Trasmint only mode(I2C_CON[1:0]=2’b00)1.2 Mix mode (I2C_CON[1:0]=2’b01 or I2C_CON[…...
wordpress分类编辑器/深圳市seo上词贵不贵
-- 最快的从库搭建方法0,准备从库第一次数据备份,临时锁所有表开启窗口1mysql> flush tables with read lock;Query OK, 0 rows affected (0.00 sec)mysql> show master status;------------------------------------------------------------| Fi…...