位置: IT常识 - 正文

【工作流Activiti7】3、Activiti7 回退与会签(工作流activity)

编辑:rootadmin
【工作流Activiti7】3、Activiti7 回退与会签

推荐整理分享【工作流Activiti7】3、Activiti7 回退与会签(工作流activity),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:工作流active,工作流activity教程,activiti6.0工作流引擎深度解析,工作流active,工作流引擎activiti表结构和代码详解,工作流activity,工作流引擎activiti功能介绍,工作流activity,内容如对您有帮助,希望把文章链接给更多的朋友!

1.  回退(驳回)

回退的思路就是动态更改节点的流向。先遇水搭桥,最后再过河拆桥。

具体操作如下:

取得当前节点的信息取得当前节点的上一个节点的信息保存当前节点的流向新建流向,由当前节点指向上一个节点将当前节点的流向设置为上面新建的流向当前节点完成任务将当前节点的流向还原取得之前上个节点的执行人设置上个节点的assignee为之前的执行人

代码实现起来可能是这样的: 

@Testpublic void huitui() throws Exception { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery().processInstanceId("55001").singleResult(); backProcess(task);}/** * 驳回 / 回退 * 按照这种方法,可以回退至任意节点 * @param task * @throws Exception */public void backProcess(Task task) throws Exception { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); HistoryService historyService = processEngine.getHistoryService(); RepositoryService repositoryService = processEngine.getRepositoryService(); TaskService taskService = processEngine.getTaskService(); String processInstanceId = task.getProcessInstanceId(); // 获取所有历史任务(按创建时间降序) List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .orderByTaskCreateTime() .desc() .list(); List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery() .processInstanceId(processInstanceId).list(); if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) { return; } // 当前任务 HistoricTaskInstance currentTask = hisTaskList.get(0); // 前一个任务 HistoricTaskInstance lastTask = hisTaskList.get(1); // 当前活动 HistoricActivityInstance currentActivity = hisActivityList.stream().filter(e -> currentTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0); // 前一个活动 HistoricActivityInstance lastActivity = hisActivityList.stream().filter(e -> lastTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0); BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); // 获取前一个活动节点 FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivity.getActivityId()); // 获取当前活动节点 FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId()); // 临时保存当前活动的原始方向 List<SequenceFlow> originalSequenceFlowList = new ArrayList<>(); originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows()); // 清理活动方向 currentFlowNode.getOutgoingFlows().clear(); // 建立新方向 SequenceFlow newSequenceFlow = new SequenceFlow(); newSequenceFlow.setId("newSequenceFlowId"); newSequenceFlow.setSourceFlowElement(currentFlowNode); newSequenceFlow.setTargetFlowElement(lastFlowNode); List<SequenceFlow> newSequenceFlowList = new ArrayList<>(); newSequenceFlowList.add(newSequenceFlow); // 当前节点指向新的方向 currentFlowNode.setOutgoingFlows(newSequenceFlowList); // 完成当前任务 taskService.complete(task.getId()); // 重新查询当前任务 Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult(); if (null != nextTask) { taskService.setAssignee(nextTask.getId(), lastTask.getAssignee()); } // 恢复原始方向 currentFlowNode.setOutgoingFlows(originalSequenceFlowList);}

以请假为例

<process id="holiday" name="holiday" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="填写请假单" activiti:assignee="${assignee1}"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <userTask id="usertask2" name="部门经理审批" activiti:assignee="${assignee2}"></userTask> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow> <userTask id="usertask3" name="人事审批" activiti:candidateUsers="tom,jerry"></userTask> <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow></process>

假设现在已经到“人事审批”这个节点了,当前活动是usertask3

接下来,我们运行上面的代码,回退到上一个节点“部门经理审批”,于是

流程重新从“部门经理审批”节点开始往下走,当流程走完以后

证明,思路正确,写法没啥问题。但是,上面的代码可以简化一下,如下:

/** * 跳到最开始的任务节点(直接打回) * @param task 当前任务 */public void jumpToStart(Task task) { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); HistoryService historyService = processEngine.getHistoryService(); RepositoryService repositoryService = processEngine.getRepositoryService(); TaskService taskService = processEngine.getTaskService(); String processInstanceId = task.getProcessInstanceId(); // 获取所有历史任务(按创建时间升序) List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery() .processInstanceId(processInstanceId) .orderByTaskCreateTime() .asc() .list(); if (CollectionUtils.isEmpty(hisTaskList) || hisTaskList.size() < 2) { return; } // 第一个任务 HistoricTaskInstance startTask = hisTaskList.get(0); // 当前任务 HistoricTaskInstance currentTask = hisTaskList.get(hisTaskList.size() - 1); BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); // 获取第一个活动节点 FlowNode startFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(startTask.getTaskDefinitionKey()); // 获取当前活动节点 FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentTask.getTaskDefinitionKey()); // 临时保存当前活动的原始方向 List<SequenceFlow> originalSequenceFlowList = new ArrayList<>(); originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows()); // 清理活动方向 currentFlowNode.getOutgoingFlows().clear(); // 建立新方向 SequenceFlow newSequenceFlow = new SequenceFlow(); newSequenceFlow.setId("newSequenceFlowId"); newSequenceFlow.setSourceFlowElement(currentFlowNode); newSequenceFlow.setTargetFlowElement(startFlowNode); List<SequenceFlow> newSequenceFlowList = new ArrayList<>(); newSequenceFlowList.add(newSequenceFlow); // 当前节点指向新的方向 currentFlowNode.setOutgoingFlows(newSequenceFlowList); // 完成当前任务 taskService.complete(task.getId()); // 重新查询当前任务 Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult(); if (null != nextTask) { taskService.setAssignee(nextTask.getId(), startTask.getAssignee()); } // 恢复原始方向 currentFlowNode.setOutgoingFlows(originalSequenceFlowList);}

2.  会签

多个人同时处理一个任务,这种任务我们称之为会签任务 。Activiti实现会签是基于多实例任务,将节点设置成多实例,主要通过在UserTask节点的属性上配置。

会签的种类:

按数量通过: 达到一定数量的通过表决后,会签通过。按比例通过: 达到一定比例的通过表决后,会签通过。一票否决: 只要有一个表决时否定的,会签通过。一票通过: 只要有一个表决通过的,会签通过。【工作流Activiti7】3、Activiti7 回退与会签(工作流activity)

每个实例有以下变量:

nrOfInstances: 实例总数

nrOfActiveInstances: 当前激活的(未完成的)实例总数。 如果串行执行,则改值永远是1

nrOfCompletedInstances: 已完成的实例总数

条件${nrOfInstances == nrOfCompletedInstances}表示所有人员审批完成后会签结束。

条件${ nrOfCompletedInstances == 1}表示一个人完成审批,该会签就结束。

其他条件依次类推,同时这里也可以写自己添加的流程变量。

相关文档如下:

下面举个例子:

<process id="countersign" name="countersign" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="申请" activiti:assignee="zhangsan"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <userTask id="usertask2" name="会签审批" activiti:assignee="${approver}"> <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${approverList}" activiti:elementVariable="approver"> <completionCondition>${nrOfCompletedInstances == nrOfInstances}</completionCondition> </multiInstanceLoopCharacteristics> </userTask> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow> <userTask id="usertask3" name="备案" activiti:assignee="tianqi"></userTask> <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow></process>

编写代码:

// 部署流程定义RepositoryService repositoryService = processEngine.getRepositoryService();Deployment deployment = repositoryService.createDeployment() .addClasspathResource("diagram/countersign.bpmn") .name("会签示例") .key("countersign") .deploy();// 启动流程实例RuntimeService runtimeService = processEngine.getRuntimeService();Map<String, Object> variables = new HashMap<>();variables.put("approverList", Arrays.asList("lisi","wangwu","zhaoliu"));ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("countersign", variables);// 完成任务TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processInstanceId("107501").taskAssignee("zhaoliu").singleResult();if (null != task) { taskService.complete(task.getId());}

流程启动后,首先是zhangsan审批

当zhangsan完成自己的任务后,进入会签环节,于是我们看到当前有3个激活的任务

当lisi完成任务以后,当前任务剩下2个

当wangwu和zhaoliu都完成任务了以后,会签任务完成,进入下一个环节

刚才的例子中没有考虑到审批不通过的情况,接下来我们完善一下,考虑下面的流程

<process id="countersign" name="countersign" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="申请" activiti:assignee="zhangsan"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <userTask id="usertask2" name="会签审批" activiti:assignee="${approver}"> <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${approverList}" activiti:elementVariable="approver"> <completionCondition>${nrOfCompletedInstances / nrOfInstances == 1 || pass == false}</completionCondition> </multiInstanceLoopCharacteristics> </userTask> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow> <userTask id="usertask3" name="备案" activiti:assignee="tianqi"></userTask> <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway> <sequenceFlow id="flow5" sourceRef="usertask2" targetRef="exclusivegateway1"></sequenceFlow> <sequenceFlow id="flow6" name="通过" sourceRef="exclusivegateway1" targetRef="usertask3"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass == true}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="flow7" name="拒绝" sourceRef="exclusivegateway1" targetRef="usertask1"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass == false}]]></conditionExpression> </sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow8" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow></process>

在会签审批完成任务时就要加上流程变量pass了

RuntimeService runtimeService = processEngine.getRuntimeService();TaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().processInstanceId("152501").taskAssignee("lisi").singleResult();if (null != task) { Map<String, Object> variables = new HashMap<>(); variables.put("pass", true);// variables.put("pass", false); taskService.complete(task.getId(), variables); runtimeService.getVariable(task.getExecutionId(), "nrOfCompletedInstances");}

zhaoliu审批的时候pass传的false,于是流程又走到zhangsan那里,流程重新又走了一遍才全部完成

回退和会签就先讲到这里 

本文链接地址:https://www.jiuchutong.com/zhishi/277908.html 转载请保留说明!

上一篇:局域网故障怎么排除?(局域网故障可能的原因)

下一篇:win1020H2打开第三方软件模糊的解决方法(win10打开第二个桌面快捷键)

  • 苹果13耳机插哪里(苹果13耳机插哪个孔)

    苹果13耳机插哪里(苹果13耳机插哪个孔)

  • 华为手机如何关闭开发者模式(华为手机如何关闭负一屏)

    华为手机如何关闭开发者模式(华为手机如何关闭负一屏)

  • 唯品会已下架和已抢光区别(唯品会下架是什么意思)

    唯品会已下架和已抢光区别(唯品会下架是什么意思)

  • opporeno7pro处理器多少(opporeno7pro处理器和IQOO9Pro处理器比较)

    opporeno7pro处理器多少(opporeno7pro处理器和IQOO9Pro处理器比较)

  • 电脑下面的任务栏跑到上面去了怎么办(电脑下面的任务栏怎么隐藏)

    电脑下面的任务栏跑到上面去了怎么办(电脑下面的任务栏怎么隐藏)

  • 钉钉开摄像头分屏会被发现吗(钉钉开摄像头分屏老师能看见吗)

    钉钉开摄像头分屏会被发现吗(钉钉开摄像头分屏老师能看见吗)

  • 联想小新没有网线接口怎么办(联想小新没有网线接口)

    联想小新没有网线接口怎么办(联想小新没有网线接口)

  • 华为ldn-al00手机是什么型号(华为ldnal00手机价格是多少钱)

    华为ldn-al00手机是什么型号(华为ldnal00手机价格是多少钱)

  • 华为p30拍照模糊(华为p30拍照模糊不能聚焦)

    华为p30拍照模糊(华为p30拍照模糊不能聚焦)

  • 微信拉入黑名单聊天记录会没了吗(微信拉入黑名单对方会有提示吗)

    微信拉入黑名单聊天记录会没了吗(微信拉入黑名单对方会有提示吗)

  • 手机显示有电却自动关机(手机显示有电却自动关机是主屏坏了吗)

    手机显示有电却自动关机(手机显示有电却自动关机是主屏坏了吗)

  • 微信提示有未读信息可看不到咋回事(怎么设置微信来消息不显示内容)

    微信提示有未读信息可看不到咋回事(怎么设置微信来消息不显示内容)

  • 钉钉一个手机号可以在两个手机上登录吗(钉钉一个手机号可以登录几个手机)

    钉钉一个手机号可以在两个手机上登录吗(钉钉一个手机号可以登录几个手机)

  • 手机完全卡死了怎么办(手机完全卡死了开不了机)

    手机完全卡死了怎么办(手机完全卡死了开不了机)

  • c语言源程序名的后缀是(c语言源程序名词解释)

    c语言源程序名的后缀是(c语言源程序名词解释)

  • qq闪照怎么弄秒数(qq闪照怎么弄3秒)

    qq闪照怎么弄秒数(qq闪照怎么弄3秒)

  • wps怎么弄成文本格式(wps怎么将文本转成表格)

    wps怎么弄成文本格式(wps怎么将文本转成表格)

  • 拼多多没砍完可以买吗(拼多多没砍成)

    拼多多没砍完可以买吗(拼多多没砍成)

  • vivox23和x23幻彩版手机壳一样吗(vivox23和x23幻彩版外观有什么区别)

    vivox23和x23幻彩版手机壳一样吗(vivox23和x23幻彩版外观有什么区别)

  • 怎样去掉故事锁屏(故事屏锁怎样取消)

    怎样去掉故事锁屏(故事屏锁怎样取消)

  • 腾讯大王卡淘宝免流吗(腾讯大王卡)

    腾讯大王卡淘宝免流吗(腾讯大王卡)

  • 微信朋友验证消息太长怎么看完(微信朋友验证消息怎么关闭)

    微信朋友验证消息太长怎么看完(微信朋友验证消息怎么关闭)

  • 苹果xr没有录屏吗(iphonexr没有录屏功能是什么原因)

    苹果xr没有录屏吗(iphonexr没有录屏功能是什么原因)

  • 探究前端的跑马灯效果是如何用css实现的(前端处理map)

    探究前端的跑马灯效果是如何用css实现的(前端处理map)

  • 借款利息收入是企业收入吗
  • 查询一般纳税人资格证明
  • 新个税年终奖计算公式
  • 帮忙劳务派遣
  • 境外公司汇款给境内个人
  • 佣金收入交什么税费
  • 存货占营业收入的意义
  • 资产负债表不平的原因有哪些
  • 购进农产品取得专用发票
  • 预付房租摊销账务处理
  • 抵扣红字发票税点是多少
  • 公司代缴员工个税
  • 租赁费支出可以在税前扣除吗
  • 微信支付对公账户
  • 房贷利息在哪里能看到
  • 通用机打发票能报销不
  • 诉讼费和保全费什么时候能退还
  • 电子承兑到期收款怎么做账务
  • 销售后换回产品的账务处理怎么做?
  • 企业所得税为15%的企业
  • 四项服务加计扣除政策2023
  • 投标费用属于什么会计科目
  • 合同签订后税率调整
  • 质保金算合同资产
  • 上市公司现金分红怎么派发
  • mac系统怎么删除用户
  • 网页浏览器字体颜色怎么改
  • 冲销货款的会计分录
  • 企业转让房产所得税税率
  • kb4586853更新
  • 采购合同付款违约条款怎么签
  • 如何申请菜鸟驿站快递代理点
  • 世界上最早的计算机是
  • 增资后股权转让
  • 后续追加投资如何处理
  • uniapph5微信支付
  • h5页面内嵌到微信
  • vue设置背景图片透明度
  • 标书注意事项与如何制作标书
  • 销售边角料的会计分录
  • 企业收到工程款会计分录
  • 基本户理财产品有哪些
  • 安装centos7.2
  • 税控服务费全额抵扣怎么申报
  • access的数据源在哪里设置
  • 其他应收款期末借方余额表示什么意思
  • 到期无法收回的银行承兑汇票计入什么科目
  • 工程预付税金如何计算
  • 个人工资税收怎么计算年收入
  • 哪些费用计入管理费用开办费
  • 收到银行本票计入什么科目
  • 办理股权转让需要多久时间
  • 销售开票怎么做会计分录
  • 整个期间影响损耗的因素
  • 停车费专用发票
  • 返聘退休人员工资标准
  • mysql进阶之路
  • win7宽带自动拨号设置
  • win7如何打开远程桌面连接
  • win7宽带连接错误651怎么办
  • iconv.exe
  • win7系统ctfmon在哪个文件夹
  • Win7系统如何打开磁盘管理工具
  • 系统应用没有相机
  • win10wifi总是掉线
  • 实用的linux命令
  • unity udim
  • react父组件触发子组件方法
  • python转换语句
  • javascript制作简易计算机
  • ANDROID手机客户端软件开发工程师
  • JavaScript 事件对象介绍
  • jQuery 判断复选框是否选中
  • unity2018.4破解
  • jquery源码解析
  • 税务实地核实工作程序
  • 电脑多窗口同步操作
  • 如何理解计算消费税时的(1
  • 西安市地方税务局高新技术产业开发区分局
  • 深化财税体制改革完善税收制度心得体会
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设