芋道-------如何实现工作流退回后重新提交到之前退回的节点

一、概述

      上一节,我们讲过了工作流如何退回到申请人,接下来我们来讲一讲,如何重新提交。这里重新提交可以是再走一遍正常流程,同时也可以是直接跳过中间的步骤,直接继续给上一步退回的人审批。文章中会提及这两种情况。

       首先,我们可以看到,在芋道的工作流中有一个好处是在业务表中与工作流关联起来了,同时也为当前的状态设置了单独的字段。所以这样我们能很容易的判断出来,当前节点处于什么状态。

二、逻辑梳理

    思路如下:首先在流程详情页面中,判断当前的节点的上一个节点是什么状态,然后拿到退回节点的状态,因为下一步我们将根据这个状态,把原本不可更改的详情页,改成可编辑的,这样用户才可以修改后重新提交。然后重新提交后,我们需要对业务表进行更新,同时需要继续启动流程。

总结:1、将task中所有任务按照时间进行排序,找到倒数第二个task即当前节点的上一个。

           2、然后判断result是否为‘5’(驳回),如果是,将标识isRerurn改成true。

           3、修改页面信息,对于申请信息,我们要考虑,何时可编辑,何时只能查看;对于审批任务何时可以显示,何时不需要显示。

           4、后台更新业务表、继续启动流程。

三、代码实现

1、判断当前节点的任务是否是被退回的

      为什么判断的是上一个节点,而不是当前节点,因为,当前节点一定是已经由上一个节点处理过后,才得到的结果。因此,我们要判断是由退回走到当前节点的还是正常流程通过走过来的。

     经过查看后台代码,发现result为5的表示的是当前任务节点是被驳回状态,同时在前台我们可以看到他已经按照时间顺序排好,因此我们只要判断数组中第二个位置的result是否为5即可,这个时候将标识isReturn设为true。

2、修改审批界面 --- 审批任务

    由于如果是重新提交,根据业务需求页面上就不需要审批任务这个模块,只留一个编辑表单信息就可以,所以这里加了条件限制,判断如果不是申请人就不显示审批任务。

3、修改审批界面 --- 申请信息组件值传递

      然后我们将 isReturn 和 runningTasks 这两个参数传到组件中,isReturn是是否是退回的标识,runningTasks是,当前登录人的任务列表。

      因为具体业务的表单信息,属于动态的,所以这里面他们引用了组件,我们需要把参数信息传到对应的表单页面,这样表单页面拿到信息,进而判断出什么时候可以编辑的,什么时候显示的。

     这里讲一下为什么传递这两个参数,首先,我们单纯的知道了什么时候退回,并不能控制住审批信息的显示和编辑,因为如果只是知道当前节点属于退回后的节点,其他人再进入到页面的时候,也会显示重新提交这个界面。

    所以我们还需要判断当前登录的人,是否是要退回到某个节点的人,在进行处理。这个时候,我们发现既有的代码中有一段runningTasks的逻辑,他其实就是将当前任务中需要登录用户处理的任务存起来,这样我们其实只要判断,这个runningTasks中是否有值即可,如果他有值,证明这个节点其实已经走到了当前登录的用户这里了,如果同时他又是退回后的节点,那么它就可以编辑该界面。

4、修改审批界面 --- 申请信息界面
<template>
  <div class="app-container">
    <!-- <el-form ref="form" :model="form" label-width="100px">
      <el-form-item label="开始时间:" prop="startTime">
        {{ parseTime(form.startTime, "{y}-{m}-{d}") }}
      </el-form-item>
      <el-form-item label="结束时间:" prop="endTime">
        {{ parseTime(form.endTime, "{y}-{m}-{d}") }}
      </el-form-item>
      <el-form-item label="请假类型:" prop="type">
        <dict-tag :type="DICT_TYPE.BPM_OA_LEAVE_TYPE" :value="form.type" />
      </el-form-item>
      <el-form-item label="原因:" prop="reason"> {{ form.reason }}</el-form-item>
    </el-form> -->
    <!-- 对话框(添加 / 修改) -->
    <el-form ref="form" :model="form" label-width="100px">
      <el-form-item label="开始时间:" prop="startTime">
        <template v-if="isReturn && runningTasks.length != 0">
          <el-date-picker
            v-model="form.startTime"
            type="date"
            :editable="!isReturn"
          ></el-date-picker>
        </template>
        <template v-else>
          {{ parseTime(form.startTime, "{y}-{m}-{d}") }}
        </template>
      </el-form-item>
      <el-form-item label="结束时间:" prop="endTime">
        <template v-if="isReturn && runningTasks.length != 0">
          <el-date-picker
            v-model="form.endTime"
            type="date"
            :editable="!isReturn"
          ></el-date-picker>
        </template>
        <template v-else>
          {{ parseTime(form.endTime, "{y}-{m}-{d}") }}
        </template>
      </el-form-item>
      <el-form-item label="请假类型:" prop="type">
        <template v-if="isReturn && runningTasks.length != 0">
          <el-select v-model="form.type">
            <el-option
              v-for="dict in typeDictData"
              :key="parseInt(dict.value)"
              :label="dict.label"
              :value="parseInt(dict.value)"
            />
          </el-select>
        </template>
        <template v-else>
          <dict-tag :type="DICT_TYPE.BPM_OA_LEAVE_TYPE" :value="form.type" />
        </template>
      </el-form-item>
      <el-form-item label="原因:" prop="reason">
        <template v-if="isReturn && runningTasks.length != 0">
          <el-input v-model="form.reason"></el-input>
        </template>
        <template v-else>
          {{ form.reason }}
        </template>
      </el-form-item>
      <el-form-item v-if="isReturn && runningTasks.length != 0">
        <el-button type="primary" @click="submitForm">重新提交</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import { updateLeave, getLeave } from "@/api/bpm/leave";
import { getDictDatas, DICT_TYPE } from "@/utils/dict";
export default {
  name: "BpmOALeaveDetail",
  components: {},
  props: {
    id: {
      type: [String, Number],
      default: undefined,
    },
    isReturn: {
      type: [Boolean],
      default: undefined,
    },
    runningTasks: {
      type: [Array],
      default: undefined,
    },
  },

  data() {
    return {
      leaveId: Number, // 请假编号
      // 表单参数
      form: {
        startTime: undefined,
        endTime: undefined,
        type: undefined,
        reason: undefined,
      },

      typeDictData: getDictDatas(DICT_TYPE.BPM_OA_LEAVE_TYPE),
    };
  },
  created() {
    this.leaveId = this.id || this.$route.query.id;
    if (!this.leaveId) {
      this.$message.error("未传递 id 参数,无法查看 OA 请假信息");
      return;
    }
    console.log(
      "🚀 ~ runningTasks:",
      this.isReturn,
      this.runningTasks,
      this.runningTasks.length
    );
    this.getDetail();
  },
  methods: {
    /** 获得请假信息 */
    getDetail() {
      getLeave(this.leaveId).then((response) => {
        this.form = response.data;
      });
    },
    /** 提交按钮 */
    submitForm() {
      this.$refs["form"].validate((valid) => {
        if (!valid) {
          return;
        }
        // 添加的提交
        updateLeave(this.form).then((response) => {
          this.$modal.msgSuccess("重新提交成功!");
          this.$tab.closeOpenPage({ path: "/bpm/oa/leave" });
        });
      });
    },
  },
};
</script>
5、后台处理
Controller:
    @PutMapping("/update")
    public CommonResult<Long> updateLeave(@RequestBody BpmOALeaveUpdateReqVO updateReqVO){
        return success(leaveService.updateLeave(updateReqVO));
    }
Service :
    Long updateLeave( BpmOALeaveUpdateReqVO updateReqVO);

ServiceIml:

    public Long updateLeave(BpmOALeaveUpdateReqVO updateReqVO) {
        // 插入 OA 请假单
        long day = LocalDateTimeUtil.between(updateReqVO.getStartTime(), updateReqVO.getEndTime()).toDays();
        BpmOALeaveDO leave = BpmOALeaveConvert.INSTANCE.convert(updateReqVO).setUserId(SecurityFrameworkUtils.getLoginUserId()).setDay(day)
                .setId(updateReqVO.getId())
                .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
        leaveMapper.updateById(leave);
        List<BpmTaskRespVO> taskList = taskService.getTaskListByProcessInstanceId(updateReqVO.getProcessInstanceId());
        List<String> returnTaskKeyList = new ArrayList<>();
        returnTaskKeyList.add(taskList.get(0).getDefinitionKey());
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(updateReqVO.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(returnTaskKeyList, // 当前要跳转的节点列表( 1 或多)
                        taskList.get(1).getDefinitionKey()) // targetKey 跳转到的节点(1)
                .changeState();
        // 更新任务拓展表为通过 审批记录中添加对应节点信息
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(taskList.get(0).getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
                        .setReason("重新提交"));
        // 更新 BPM 流程
        //taskService.approveTask(getLoginUserId(), reqVO);

        leaveMapper.updateById(new BpmOALeaveDO().setId(leave.getId()).setProcessInstanceId(updateReqVO.getProcessInstanceId()));
        return leave.getId();
    }

注释中的 taskService.approveTask(getLoginUserId(), reqVO); 就是退回后还按照正常顺序流程走的写法 ;而现在的写法是重新提交后直接跳到退回的那个节点

以上就是实现工作流退回后重新提交到之前退回的节点全部流程。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

4.5 Verilog 条件语句

关键词&#xff1a;if&#xff0c;选择器 条件语句 条件&#xff08;if&#xff09;语句用于控制执行语句要根据条件判断来确定是否执行。 条件语句用关键字 if 和 else 来声明&#xff0c;条件表达式必须在圆括号中。 条件语句使用结构说明如下&#xff1a; if (conditio…

软件自动化运行工具开发需要用到的代码!

在软件开发领域&#xff0c;自动化运行工具扮演着至关重要的角色&#xff0c;这些工具不仅提高了开发效率&#xff0c;还降低了人为错误的风险&#xff0c;为了实现软件自动化运行&#xff0c;开发者需要掌握一系列编程语言和工具&#xff0c;并编写相应的代码。 本文将分享一…

Nginx网络服务

一、Nginx概述 1.1Nginx介绍 Nginx&#xff1a; 一款高新能、轻量级Web服务软件稳定性高系统资源消耗低对HTTP并发连接的处理能力高单台物理服务器可支持30 000&#xff5e;50 000个并发请求。 Nginx 是开源、高性能、高可靠的 Web 和反向代理服务器&#xff0c;而且支持热部…

Day22--learning English

一、积累 1.wool 2.stern 3.resolute 4.feisty 5.pickle 6.quail 7.frame 8.hose 9.ravish 10.Base on what 11.nimble 12.shutter 13.spawn 14.shiver 15.blanket 16.squat 17.braise 18.jam tomorrow 19.drip 20.repercussion 二、练习 1.牛津原译 Wool [ wʊl ] [名词] 1.…

Linux篇:指令

一 基本常识&#xff1a; 1. 文件文件内容文件的属性 2. 文件的操作对文件内容的操作对文件属性的操作 3. 文件的类型&#xff1a; d&#xff1a;目录文件 -&#xff1a;普通文件 4. 指令是可执行程序&#xff0c;指令的代码文件在系统的某一个位置存在的。/u…

鸿蒙-基于ArkTS声明式开发的简易备忘录,适合新人学习,可用于大作业

本文地址&#xff1a;https://blog.csdn.net/qq_40785165/article/details/136161182?spm1001.2014.3001.5502&#xff0c;转载请附上此链接 大家好&#xff0c;我是小黑&#xff0c;一个还没秃头的程序员~~~ 不知不觉已经有很长一段时间没有分享过自己写的东西了&#xff0…

Nginx操作

文章目录 Nginx使用操作1. 安装nginx2. docker启动nginx3. 目录介绍4. 更改站点内容&#xff0c;初试一下(此步骤可以省略)5. nginx配置文件结构5.1 http配置示例5.2 server配置 Nginx使用操作 服务器: ubuntudocker内操作nginx 1. 安装nginx # 1. 查询nginx版本 sudo docker…

Atcoder ABC340 C - Divide and Divide

Divide and Divide&#xff08;分而治之&#xff09; 时间限制&#xff1a;2s 内存限制&#xff1a;1024MB 【原题地址】 所有图片源自Atcoder&#xff0c;题目译文源自脚本Atcoder Better! 点击此处跳转至原题 【问题描述】 【输入格式】 【输出格式】 【样例1】 【样例…

《Solidity 简易速速上手小册》第5章:智能合约的安全性(2024 最新版)

文章目录 5.1 安全性的重要性5.1.1 基础知识解析深入理解安全性的多维度影响智能合约安全的关键要素 5.1.2 重点案例&#xff1a;防止重入攻击案例 Demo&#xff1a;构建一个防重入的提款合约案例代码WithdrawContract.sol 测试和验证拓展功能 5.1.3 拓展案例 1&#xff1a;预防…

拿捏c语言指针(下)

前言 此篇讲解的主要是函数与指针的那些事~ 书接上回 拿捏c语言指针&#xff08;上&#xff09;和 拿捏c语言指针&#xff08;中&#xff09; ​​​​​​没有看的小伙伴要抓紧喽~ 欢迎关注​​个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#x…

STM32_ESP8266 连接阿里云 操作图解

一、烧录MQTT固件 ESP8266出厂时&#xff0c;默认是&#xff1a;AT固件。连接阿里云需要&#xff1a;MQTT固件。 因此&#xff0c;我们需要给8266重新烧录 MQTT固件。 针对“魔女开发板&#xff0c;ESP8266模块烧录MQTT固件&#xff0c;图解教程如下&#xff1a; ESP8266 烧录 …

【Vuforia+Unity】AR01实现单张多张图片识别产生对应数字内容

1.官网注册 Home | Engine Developer Portal 2.下载插件SDK&#xff0c;导入Unity 3.官网创建数据库上传图片&#xff0c;官网处理成数据 下载好导入Unity&#xff01; 下载好导入Unity&#xff01; 下载好导入Unity&#xff01; 下载好导入Unity&#xff01; 4.在Unity设…

在 Vue 中将 DOM 导出为图片

你好&#xff0c;我是小白Coding日志&#xff0c;一个热爱技术的程序员。在这里&#xff0c;我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客&#xff0c;一起在技术的世界里探索前行吧&#xff01; 在日常的工作中&…

五种多目标优化算法(MOGWO、MOJS、NSWOA、MOPSO、MOAHA)性能对比(提供MATLAB代码)

一、5种多目标优化算法简介 1.1MOGWO 1.2MOJS 1.3NSWOA 1.4MOPSO 1.5MOAHA 二、5种多目标优化算法性能对比 为了测试5种算法的性能将其求解9个多目标测试函数&#xff08;zdt1、zdt2 、zdt3、 zdt4、 zdt6 、Schaffer、 Kursawe 、Viennet2、 Viennet3&#xff09;&#xff0…

基于物联网智慧公厕的多功能城市智慧驿站

在现代城市发展中&#xff0c;智慧化已经成为了一个不可或缺的趋势。而多功能城市智慧驿站&#xff0c;作为智慧城市建设的一部分&#xff0c;以物联网智慧公厕为基础&#xff0c;集合了诸多功能于一身&#xff0c;成为了城市中不容忽视的存在。多功能城市智慧驿站也称为轻松的…

05 扩展组件:自定义CheckBox组件

系列文章目录 01 Qt自定义风格控件的基本原则-CSDN博客 02 从QLabel聊起&#xff1a;自定义控件扩展-图片控件-CSDN博客 03 从QLabel聊起&#xff1a;自定义控件扩展-文本控件-CSDN博客 04 自定义Button组件&#xff1a;令人抓狂的QToolButton文本图标居中问题-CSDN博客 目…

【深度优先】【广度优先】Leetcode 104 二叉树的最大深度 Leetcode 111 二叉树的最小深度 Leetcode 110 平衡二叉树

【深度优先】【广度优先】Leetcode 104 二叉树的最大深度 Leetcode 111 二叉树的最小深度 Leetcode 110 平衡二叉树 Leetcode 104 二叉树的最大深度解法1 深度优先 递归法 后序&#xff1a;左右中解法2 广度优先&#xff1a;层序遍历 Leetcode 111 二叉树的最小深度解法1 深度…

SNAT与DNAT公私网地址转换

前言 SNAT和DNAT是两种重要的网络地址转换技术&#xff0c;它们允许内部网络中的多个主机共享单个公共IP地址&#xff0c;或者将公共IP地址映射到内部网络中的特定主机。这些技术在构建企业级网络和互联网应用程序时非常重要&#xff0c;因为它们可以帮助保护内部网络安全&…

ONLYOFFICE 8.0:引领数字化办公新纪元

目录 前言 软件安装 软件启动 软件新版本特性 个人评价 总结 前言 在当今快节奏的数字化世界中&#xff0c;高效的办公软件已成为企业竞争力的关键因素。ONLYOFFICE&#xff0c;作为全球领先的办公解决方案提供商&#xff0c;始终致力于通过技术创新来优化用户体验。如今…

阿里云的流量价格表_2024阿里云服务器流量费用表

阿里云服务器宽带按使用流量怎么收费的&#xff1f;价格为0.8元/GB&#xff0c;地域不同流量价格也不同&#xff0c;北京、杭州、上海、深圳等中国大陆地域是0.8元每GB&#xff0c;中国香港是1元/GB&#xff0c;美国流量0.5元1GB、日本流量0.6元、韩国流量0.8元&#xff0c;阿里…