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

news2025/1/13 13:52:52

一、概述

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

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

二、逻辑梳理

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

总结: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); 就是退回后还按照正常顺序流程走的写法 ;而现在的写法是重新提交后直接跳到退回的那个节点

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

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

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

相关文章

2、windows环境下vscode开发c/c++环境配置(一)

前言&#xff1a;VSCode是微软出的一款轻量级编辑器&#xff0c;它本身只是一款文本编辑器而已&#xff0c;并不是一个集成开发环境(IDE)&#xff0c;几乎所有功能都是以插件扩展的形式所存在的。因此&#xff0c;我们想用它编程&#xff0c;不只是把vscode下载下来就行&#x…

MQ最终一致性理论与实践

MQ最终一致性理论与实践 原理 分布式事务无论是2PC&3PC还是TCC&#xff0c;基本都遵守XA协议的思想&#xff0c;但全局事务方案并发性较差&#xff1b; 最终一致性方案指的是将最有可能出错的业务以本地事务的方式完成后&#xff0c;采用不断重试的方式&#xff08;不限…

Sora内测申请详细教程

Sora内测申请详细教程 Sora 的创作能力&#xff0c;已经让很多人震惊了&#xff0c;自己制作电影的时代来了&#xff0c;以前做个短视频觉得已经够满足了&#xff0c;现在人人都能成为导演。 这几天大家都在等什么时候能用上&#xff0c;我给他分享一个可能提前用上Sora的方法…

Panalog大数据日志审计系统libres_syn_delete.php存在命令执行漏洞

文章目录 前言声明一、Panalog大数据日志审计系统简介二、漏洞描述三、影响版本四、漏洞复现五、整改意见 前言 Panalog大数据日志审计系统定位于将大数据产品应用于高校、 公安、 政企、 医疗、 金融、 能源等行业之中&#xff0c;针对网络流量的信息进行日志留存&#xff0c…

MyBatis学习总结

MyBatis分页如何实现 分页分为 逻辑分页&#xff1a;查询出所有的数据缓存到内存里面&#xff0c;在从内存中筛选出需要的数据进行分页 物理分页&#xff1a;直接用数据库语法进行分页limit mybatis提供四种方法分页&#xff1a; 直接在sql语句中分页&#xff0c;传递分页参数…

多进程(1)

1> 使用多个进程实现文件拷贝 #include<myhead.h> int main(int argc, const char *argv[]) {pid_t pid;pidfork();int fdr;char buf;if((fdropen(argv[1],O_RDONLY))-1){perror("open error");return -1;}int lenlseek(fdr,0,SEEK_END)-lseek(fdr,0,SEEK_…

openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优

文章目录 openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优224.1 全局并发队列224.2 局部并发队列 openGauss学习笔记-224 openGauss性能调优-系统调优-数据库系统参数调优-数据库并发队列参数调优 数据库提供两种手段进行并发队…

掌握社区店选址技巧,提升商业成功率

对于想开实体店或创业的人来说&#xff0c;选址是决定商业成功的关键因素之一。本人在社区店开鲜奶吧5年时间&#xff0c;我将分享一些实用的社区店选址技巧&#xff0c;帮助你提升商业成功率。 1、人口密度和流量&#xff1a; 选择人口密集、流量大的社区&#xff0c;这样可以…

redis scan命令导致cpu飙升

一.背景 今天下午Redis的cpu占用突然异常升高&#xff0c;一度占用达到了90%&#xff0c;触发了钉钉告警&#xff0c;之后又回到正常水平&#xff0c;跟DBA沟通&#xff0c;他说主要是下面这个语句的问题 SCAN 0 MATCH fastUser:6136* COUNT 10000这个语句的执行时长很短&…

苍穹外卖学习-----2024/02/19

1.开发环境搭建 我的git截图我使用的datagrip 运行sql学习到jwt令牌一种新的配置方式&#xff0c;写配置文件学习到了build属性nginx解决跨域的问题2.导入接口的文档 结果如图所示 3.Swagger /*** 通过knife4j生成接口文档* return*/Beanpublic Docket docket() {ApiInfo api…

论文阅读——ONE-PEACE

ONE-PEACE: EXPLORING ONE GENERAL REPRESENTATION MODEL TOWARD UNLIMITED MODALITIES 适应不同模态并且支持多模态交互。 预训练任务不仅能提取单模态信息&#xff0c;还能模态间对齐。 预训练任务通用且直接&#xff0c;使得他们可以应用到不同模态。 各个模态独立编码&am…

阿里云服务器多少钱一台?61元一年您看行吗?

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

Python简单小案例之 筷手美女下载保存本地

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 知识点: 动态数据抓包 requests发送请求 开发环境: python 3.8 运行代码 解释器 pycharm 2022.3 辅助敲代码 编辑器 requests pip install requests &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&…

【C++】类与对象(构造函数、析构函数、拷贝构造函数、常引用)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 类的6个默认成员函数 构造函数 特性 析构函数 特性 析构的顺序 拷贝构造函数 特性 常引用 前言 &…

频谱仿真平台HTZ Communications为私有5G建设铺平道路

韩国的国家监管机构韩国通信委员会&#xff08;KCA&#xff09;计划在德思特频谱仿真平台HTZ Communications的支持下加快扩大无线电接入范围&#xff0c;提升全国电信服务的质量和效率。 韩国通信委员会&#xff08;KCA&#xff09;在韩国的监管环境中扮演着至关重要的角色&am…

Spring6学习技术|IoC+基于xml管理bean

学习材料 尚硅谷Spring零基础入门到进阶&#xff0c;一套搞定spring6全套视频教程&#xff08;源码级讲解&#xff09; IoC 控制反转。是一种设计思想。 1.获取bean对象的方法 通过id&#xff0c;通过class&#xff0c;和双重方式。 ApplicationContext context new Cla…

云呐智能运维硬件包括哪些?智能运维体系包括哪些?

智能运维体系时&#xff0c;能够详细了解该体系包含的各个组成部分。具体来说&#xff0c;我们应该知道智能运维体系中涉及的软件组件有哪些&#xff0c;以及这些组件是如何相互协作以实现高效运维的。此外&#xff0c;智能运维体系中使用的硬件设备感兴趣。列举了智能运维硬件…

测试工具之压测工具JMeter(一)

有时候我们接到的需求是秒杀或者抽奖类的功能开发&#xff0c;这时候可能会在某一时间点大量请求并发&#xff0c;我们手工自测很难发现一些高并发场景下的问题&#xff0c;这时候可以借助一些压测工具帮我们模拟出大量请求来测试我们的接口是否能满足业务要求。JMeter是Apache…

数据分析 — 招聘数据爬取和分析

目录 一、数据获取二、词云图语法1、jieba 分词2、词云图 一、数据获取 需求&#xff1a; 招聘数据获取地址&#xff1a;https://careers.tencent.com/home.html 获取字段&#xff1a;岗位的名称、岗位职责、发布时间 import pandas as pd # 导入 Pandas 库并使用别名 pd im…

深度学习——概念引入

深度学习 深度学习简介深度学习分类根据网络结构划分&#xff1a;循环神经网络卷积神经网络 根据学习方式划分&#xff1a;监督学习无监督学习半监督学习 根据应用领域划分&#xff1a;计算机视觉自然语言处理语音识别生物信息学 深度学习简介 深度学习&#xff08;Deep Learni…