Springboot +Flowable,会签、或签简单使用(三)

news2024/9/21 4:29:18

一.简介

**会签:**在一个流程中的某一个 Task 上,这个 Task 需要多个用户审批,当多个用户全部审批通过,或者多个用户中的某几个用户审批通过,就算通过。
例如:之前的请假流程,假设这个请假流程需要组长和经理都审批了,才算审批通过,那么就需要设置这个 Task 是会签节点。

**或签:**意思就是 A 的请假流程提交给 B、C、D,但是并不需要 B/C/D 同时审批通过,只需要 B/C/D 中的任意一个审批即可,这就是或签,注意,我这里的表述,只需要 B/C/D 任意一个审批即可,这个审批即可以是审批通过,也可以是审批拒绝,反正只要审批,这个 UserTask 就算完成了。

二.会签流程图

首先来画一下这个请假流程图,这个流程图基本上还是和之前的一样,截图如下:
在这里插入图片描述

三.请假处理

1.前端提交请假流程

2.服务端处理请假请求

3.服务端返回待审批数据

4.服务端批准 OR 拒绝

前4步见上一篇文章,这边不重复写

5.服务端返回流程数据

服务端展示流程数据。就是当用户提交流程之后,想要查看自己的流程处理到哪一步了,截图如下:
在这里插入图片描述
这张图中的数据其实包含了两部分,一部分是已经执行完的流程,还有一部分是正在执行中的流程,所以在查询中,分为两步来完成,代码如下:

public RespBean searchResult() {
    String name = SecurityContextHolder.getContext().getAuthentication().getName();
    List<HistoryInfo> infos = new ArrayList<>();
    //未完成流程
    List<HistoricProcessInstance> unFinishedHistoricProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(name).unfinished().orderByProcessInstanceStartTime().desc().list();
    for (HistoricProcessInstance unFinishedHistoricProcessInstance : unFinishedHistoricProcessInstances) {
        HistoryInfo historyInfo = new HistoryInfo();
        Date startTime = unFinishedHistoricProcessInstance.getStartTime();
        Date endTime = unFinishedHistoricProcessInstance.getEndTime();
        List<HistoricVariableInstance> historicVariableInstances = historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(unFinishedHistoricProcessInstance.getId())
                .list();
        System.out.println("historicVariableInstances = " + historicVariableInstances);
        for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
            String variableName = historicVariableInstance.getVariableName();
            Object value = historicVariableInstance.getValue();
            if ("reason".equals(variableName)) {
                historyInfo.setReason((String) value);
            } else if ("days".equals(variableName)) {
                historyInfo.setDays(Integer.parseInt(value.toString()));
            } else if ("name".equals(variableName)) {
                historyInfo.setName((String) value);
            } else if (variableName.startsWith("approveUser")) {
                historyInfo.getApproveUsers().add((String) value);
            } else if ("userTask".equals(variableName)) {
                historyInfo.getCandidateUsers().add((String) value);
            }
        }
        historyInfo.setStatus(3);
        historyInfo.setStartTime(startTime);
        historyInfo.setEndTime(endTime);
        infos.add(historyInfo);
    }
    //已结束流程
    List<HistoricProcessInstance> finishHistoricProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(name)
            .finished()
            .orderByProcessInstanceStartTime().desc().list();
    for (HistoricProcessInstance historicProcessInstance : finishHistoricProcessInstances) {
        HistoryInfo historyInfo = new HistoryInfo();
        Date startTime = historicProcessInstance.getStartTime();
        Date endTime = historicProcessInstance.getEndTime();
        List<HistoricVariableInstance> historicVariableInstances = historyService.createHistoricVariableInstanceQuery()
                .processInstanceId(historicProcessInstance.getId())
                .list();
        System.out.println(historicVariableInstances);
        for (HistoricVariableInstance historicVariableInstance : historicVariableInstances) {
            String variableName = historicVariableInstance.getVariableName();
            Object value = historicVariableInstance.getValue();
            if ("reason".equals(variableName)) {
                historyInfo.setReason((String) value);
            } else if ("days".equals(variableName)) {
                historyInfo.setDays(Integer.parseInt(value.toString()));
            } else if ("approved".equals(variableName)) {
                Boolean v = (Boolean) value;
                if (v) {
                    historyInfo.setStatus(1);
                } else {
                    historyInfo.setStatus(2);
                }
            } else if ("name".equals(variableName)) {
                historyInfo.setName((String) value);
            } else if (variableName.startsWith("approveUser")) {
                historyInfo.getApproveUsers().add((String) value);
            } else if ("userTask".equals(variableName)) {
                historyInfo.getCandidateUsers().add((String) value);
            }
        }
        historyInfo.setStartTime(startTime);
        historyInfo.setEndTime(endTime);
        infos.add(historyInfo);
    }
    return RespBean.ok("ok", infos);
}

整体上分为两部分,前面是查询未执行完的流程,后面是查询已经执行完毕的流程。对于未执行完的流程,我们在 historyInfo 中设置 status 为 3,表示待审批。当我们去读取一个流程的历史变量时,有一个以 approveUser 开头的变量,这个就表示这个流程已经被谁审批过了,我们将这个存到一个 List 集合中,将来返回给前端。流程的历史变量中还有一个 userTask,表示这个流程中这个节点待审批的用户都有谁,我们也将之保存到 List 集合中,将来返回给前端。

6.前端渲染审批数据

最后,看看前端如何渲染第5步返回的数据,HTML代码如下:

<div>
    <el-tag>历史请假列表</el-tag>
    <el-table border strip :data="historyInfos">
        <el-table-column prop="name" label="姓名"></el-table-column>
        <el-table-column prop="startTime" label="提交时间"></el-table-column>
        <el-table-column prop="endTime" label="审批时间"></el-table-column>
        <el-table-column prop="reason" label="事由"></el-table-column>
        <el-table-column prop="days" label="天数"></el-table-column>
        <el-table-column label="审批人">
            <template #default="scope">
                <template v-for="(cu,i) in scope.row.candidateUsers" :key="i">
                    <el-tag v-if="scope.row.approveUsers.indexOf(cu)!=-1" type="success">
                        {{cu}}
                    </el-tag>
                    <el-tag v-else style="color: gray">{{cu}}</el-tag>
                </template>
            </template>
        </el-table-column>
        <el-table-column label="状态">
            <template #default="scope">
                <el-tag type="success" v-if="scope.row.status==1">已通过</el-tag>
                <el-tag type="danger" v-else-if="scope.row.status==2">已拒绝</el-tag>
                <el-tag type="info" v-else>待审批</el-tag>
            </template>
        </el-table-column>
    </el-table>
</div>

可以看到,在审批人这个字段中,先去遍历显示这个流程所有的审批人(candidateUsers),在遍历的过程中,如果发现这个用户存在于 approveUsers 集合中,就表示这个用户已经审批,用绿色的 el-tag 显示,否则表示这个用户还没有审批,就用灰色的 el-tag 显示。

四.或签

或签: 就是 A 的请假流程提交给 B、C、D,但是并不需要 B/C/D 同时审批通过,只需要 B/C/D 中的任意一个审批即可,这就是或签,注意,我这里的表述,只需要 B/C/D 任意一个审批即可,这个审批即可以是审批通过,也可以是审批拒绝,反正只要审批,这个 UserTask 就算完成了。

将会签改为或签只需要修改一下 UserTask 的属性即可,截图如下:
在这里插入图片描述
完成条件(多实例)这里改为了 ${nrOfCompletedInstances >= 1},表示只要有一个同意或者拒绝,这个 UserTask 就算过了。

改完之后,重新下载这个流程图的 XML 文件,并放到前文中的代码上去运行,就可以看到或签效果了。

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

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

相关文章

【笔试强训选择题】Day15.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01; 文章目录 前言 一、…

Linux Shell 实现一键部署二进制Python

python 前言 Python由荷兰数学和计算机科学研究学会的吉多范罗苏姆于1990年代初设计&#xff0c;作为一门叫做ABC语言的替代品。 Python提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。Python语法和动态类型&#xff0c;以及解释型语言的本质&#xff0c;使…

监控知识体系

从来没讲过运维&#xff0c;因为我觉得运维这种东西不需要太多的知识面&#xff0c;然后我一个做了运维朋友告诉我大错特错&#xff0c;他就是从3K的运维一步步到40K的&#xff0c;甚至笑着说&#xff1a;我现在感觉自己什么都能做。 既然讲&#xff0c;就讲最重要的吧。 监控…

接口自动化测试分层设计与实践总结

本文以笔者当前使用的自动化测试项目为例&#xff0c;浅谈分层设计的思路&#xff0c;不涉及到具体的代码细节和某个框架的实现原理&#xff0c;重点关注在分层前后的使用对比&#xff0c;可能会以一些伪代码为例来说明举例。 接口测试三要素&#xff1a; 参数构造 发起请求&a…

NA、商业和分销市场通盘布局,华为“四大角色”浮出水面

作者 | 曾响铃 文 | 响铃说 数字经济深化发展&#xff0c;谋求数字化转型的行业、企业客户&#xff0c;越来越渴望满足自身需求的产品或解决方案。 这给从事转型服务的ICT厂商们提出了新的挑战。 在客户面前&#xff0c;拥有核心技术与支持能力的企业&#xff0c;与进击数字…

yolov1

1、对precision&#xff08;精确度&#xff09;和recall&#xff08;召回度&#xff09;的理解 1、TP TN FP FN的概念 TP&#xff08;True Positives&#xff09;意思就是被分为了正样本&#xff0c;而且分对了。 TN&#xff08;True Negatives&#xff09;意思就是被分为了负…

原装美国Agilent安捷伦34970A数据采集仪

Agilent安捷伦34970A数据采集仪 3槽主机&#xff0c;内置GPIB和RS232接口 6 1/2 位&#xff08;22 位&#xff09;内部 DMM&#xff0c;每秒扫描多达 250 个通道&#xff08;选件 001 不可用&#xff09; 8个开关和控制插件模块可供选择 内置信号调理可测量热电偶、RTD 和热敏电…

linux基础(IO)中

目录&#xff1a; 1.回顾上一篇的文件系统调用接口 2.返回值文件描述符 3.文件描述符分配规则 ---------------------------------------------------------------------------------------------------------------------------- 1.回顾上一篇的文件系统调用接口 open &…

【数据结构】二叉树进阶题目练习

文章目录 二叉树创建字符串二叉树的分层遍历1二叉树的分层遍历2给定一个二叉树, 找到该树中两个指定节点的最近公共祖先二叉树搜索树转换成排序双向链表二叉树展开为链表根据一棵树的前序遍历与中序遍历构造二叉树根据一棵树的中序遍历与后序遍历构造二叉树二叉树的前序遍历 非…

学爬虫,吃牢饭,卑微前端小丑复制antd的icon图标真的太难啦,我用python几秒扒完

目标需求 最近用reactviteantd写了个后管项目&#xff0c;在菜单管理中&#xff0c;需要用户选择菜单的icon图标。 如下&#xff1a; 而在react中使用antd UI库&#xff0c;每个组件都是需要单独导入的&#xff0c;也就是说&#xff0c;如果我要用到所有icon&#xff0c;我需…

亚马逊云科技进一步加快BMW Group的Analytics步伐

BMW Group和亚马逊云科技于2020年宣布达成全面战略合作。本次合作的目标是通过将数据分析置于决策中心&#xff0c;进一步加快BMW Group的创新步伐。本次合作的一个关键要素是进一步开发BMW Group的云数据中心&#xff08;CDH&#xff09;。这是在云端管理全公司数据和数据解决…

windows_exporter 部署

目录 - 配置服务- 配置prometheus - 配置服务 下载地址&#xff1a; https://github.com/prometheus-community/windows_exporter/releases 从github上下载windows_exporter.msi&#xff08;我下载的是windows_exporter-0.22.0-amd64.msi&#xff09;cmd命令&#xff1a;msie…

对 API 中敏感数据检测,用这个插件就好了

Postcat 中的 openDLP 插件基于 openDLP 开源项目&#xff0c;针对 Postcat 场景实现了敏感 API 发现功能&#xff0c;通过扫描 API 文档&#xff0c;识别该 API 是否可能是一个涉及敏感数据的 API。 目前内置支持 17 类敏感数据类型&#xff0c;可以通过自定义正则支持更多类型…

2023年安全岗秋招经验分享,纯干货,建议收藏!

需要准备的几个方向 简历自我介绍计算机网络操作系统&#xff08;操作系统原理&#xff0c;Linux&#xff0c;Windows&#xff09;数据库算法&#xff08;Leetcode&#xff09;编程语言&#xff08;Python,C,go等&#xff09;安全知识&#xff08;很多很杂&#xff0c;建议根据…

python3 爬虫相关学习3:response= requests.get(url)的各种属性

目录 1 requests.get(url) 的各种属性&#xff0c;也就是response的各种属性 2 下面进行测试 2.1 response.text 1.2 response.content.decode() 1.2.1 response.content.decode() 或者 response.content.decode("utf-8") 1.2.2 response.content.decode(…

实验室信息管理系统源码,LIS系统源码

云LIS系统是医院信息管理的重要组成部分之一&#xff0c;系统集申请、采样、核收、计费、检验、审核、发布、质控、查询、耗材控制等检验科工作为一体的网络管理系统。LIS系统不仅是自动接收检验数据&#xff0c;打印检验报告&#xff0c;系统保存检验信息的工具&#xff0c;而…

平抑风电波动的电-氢混合储能容量优化配置(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

22届硕士,去年秋招拿了字节跳动offer,有一说一,不是很难进

自从抖音短视频APP火了之后&#xff0c;起公司字节跳动也逐渐向着大厂靠拢&#xff0c;相信大家都已经对这家公司很熟悉了&#xff0c;尤其是近几年来&#xff0c;对它的认识也在不断刷新&#xff0c;它惊人的发展速度确实让行业内人刮目相看&#xff0c;如今很多年轻人也想要挤…

【工作记录】springsecurity从入门到实战(一)

一、介绍 在web应用开发中&#xff0c;安全无疑是十分重要的&#xff0c;目前最流行的安全框架莫过于shiro和springsecurity了。 以下是二者简单的一个对比: SpringSecurityShiro基本功能完善完善文档完善程度强大强大社区支持度依托于Spring&#xff0c;社区支持强大强大集…

Flutter仿写微信导航栏快速实现页面导航

文章目录 前言使用TabBar实现TabBar介绍TabBar的重要属性说明TabBarView介绍TabBarView的重要属性TabBar总结TabBar实现底部导航的例子 BottomNavigationBar实现BottomNavigationBar介绍BottomNavigationBar实现底部导航栏的例子 总结BottomNavigationBarTabBar根据实际情况选择…