http://man1900.iteye.com/blog/1607753

在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务。这种业务需求也很常见,如一个请款单,领导审批环节中,就需要多个部门领导签字。在流程业务中,我们可以把每个领导签字的环节都定义为任务,但若这样,这个流程业务有一点是固定的,就是签批人是固定的。而任务是由一个领导签完再到另一领导,当然也可以由多个领导同时签字。

传统的用流程业务来解决可以采用以下的做法:


串行会签

并行会签


前者在流程业务中,叫串行会签,也即是由一个领导签完再至另一领导签。后者我们称之为并行会签,表示几个领导同时进行签发,而不清楚最终是谁先签。

以上的解决方式有两大业务需求下是不能满足的,若会签的领导不是固定的,即可以由上一任务审批人提交前随意进行选择,另一种是对于会签业务中,要求若其中一部分领导审批通过,即直接往下走,不需要全部领导进行审批。另外,对于这种情况下,统计最终领导会签的结果也是比较困难的,即对审批单的意见是同意还是否决没有办法清楚。以上两种业务需求也是很常见的日常需求,但我们若采用了固定的流程节点,则不能实现。在这里,可以采用Activiti的节点多实例来处理,以上流程则可以简化为下:



何谓多任务实例节点?在Activiti5上的解析则为动态的多任务节点,可以根据传入的动态人员数进行动态生成任务。生成的任务数则不固定,可以进行并行会签,也可以进行串行会签。会签任务最终是否需要往下执行,由会签设置的规则来进行约束。如我们可以常规去设置“一票通过”、“一票否决”、“少数服务多数”等会签规则。因此,我们需要在会签节点上绑定我们的设计规则。会签规则设置界面如下:


通过会签设计规则,可以清楚最终会签人员的投票结果。其数据结构如下所示:

会签任务的定义本身已经由Activiti来实现了,但需要动态传入动态的人员数

  1. <userTask activiti:assignee="${assignee}" id="SignTask1" name="领导会签">
  2. <extensionElements>
  3. <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create"/>
  4. <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment"/>
  5. <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete"/>
  6. </extensionElements>
  7. <multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}">
  8. <completionCondition>${signComplete.isComplete(execution)}</completionCondition>
  9. </multiInstanceLoopCharacteristics>
  10. </userTask>
 其中,isSequential为true则为串行会签,若为false则为并行会签,而activiti:collection可以来自我们Spring容器中的接口及方法,表示获取会签用户集合,taskUserAssignService.getSignUser(execution)。其获取会签的用户值来自两个方面,一个在界面中指定的会签人员,另一个在后台会签节点上配置的人员。

后台会签节点人员设置

任务审批面上选择下一任务会签人员

<completeCondition>为完成会签的条件signComplete.isComplete(execution),可以在这里根据我们的会签规则及目前的会签情况,决定会签是否完成。其实现如下所示:

最终实现逻辑:
  1. @Override
  2. public boolean isComplete(ActivityExecution execution) {
  3. logger.debug("entert the SignComplete isComplete method...");
  4. String nodeId=execution.getActivity().getId();
  5. String actInstId=execution.getProcessInstanceId();
  6. ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);
  7. //取得会签设置的规则
  8. BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);
  9. //完成会签的次数
  10. Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");
  11. //总循环次数
  12. Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");
  13. //计算投票结果。
  14. VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);
  15. String signResult=voteResult.getSignResult();
  16. boolean isCompleted=voteResult.getIsComplete();
  17. /**
  18. * 会签完成做的动作。
  19. * 1.删除会签的流程变量。
  20. * 2.将会签数据更新为完成。
  21. * 3.设置会签结果变量。
  22. * 4.更新会签节点结果。
  23. * 5.清除会签用户。
  24. */
  25. if(isCompleted){
  26. //删除会签的变量。
  27. //删除 assignee,loopCounter变量。
  28. bpmService.delLoopAssigneeVars(execution.getId());
  29. logger.debug("set the sign result + " + signResult);
  30. //将会签数据更新为完成。
  31. taskSignDataService.batchUpdateCompleted(actInstId, nodeId);
  32. //设置会签的结果
  33. execution.setVariable("signResult_" + nodeId , signResult);
  34. //更新会签节点的状态。
  35. Short status=TaskOpinion.STATUS_PASSED;
  36. if(signResult.equals(SIGN_RESULT_REFUSE)){
  37. status=TaskOpinion.STATUS_NOT_PASSED;
  38. }
  39. //更新会签节点的状态。
  40. bpmProStatusDao.updStatus(actInstId, nodeId,status);
  41. //清除会签用户。
  42. taskUserAssignService.clearSignUser();
  43. }
  44. return isCompleted;
  45. }
  46. **
  47. * 根据会签规则计算投票结果。
  48. * <pre>
  49. .如果会签规则为空,那么需要所有的人同意通过会签,否则不通过。
  50. .否则按照规则计算投票结果。
  51. * </pre>
  52. * @param bpmNodeSign       会签规则
  53. * @param actInstId         流程实例ID
  54. * @param nodeId            节点id名称
  55. * @param completeCounter       循环次数
  56. * @param instanceOfNumbers     总的会签次数。
  57. * @return
  58. */
  59. private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){
  60. VoteResult voteResult=new VoteResult();
  61. //没有会签实例
  62. ){
  63. return voteResult;
  64. }
  65. //投同意票数
  66. Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);
  67. //没有设置会签规则
  68. //(那么得全部会签通过才通过,否则不通过)
  69. if(bpmNodeSign==null){
  70. //还没有完成可以退出。
  71. if(completeCounter<instanceOfNumbers){
  72. return voteResult;
  73. }
  74. else{
  75. //完成了 (全部同意才通过)
  76. if(agreeVotesCounts.equals(instanceOfNumbers)){
  77. return new VoteResult(SIGN_RESULT_PASS,true);
  78. }
  79. else{
  80. return new VoteResult(SIGN_RESULT_REFUSE,true);
  81. }
  82. }
  83. }
  84. //投反对票数
  85. Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);
  86. //检查投票是否完成
  87. if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){
  88. ;
  89. //按同意票数进行决定
  90. if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
  91. percents=agreeVotesCounts/instanceOfNumbers;
  92. //投票同意票符合条件
  93. if(percents>=bpmNodeSign.getVoteAmount()){
  94. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
  95. }
  96. //投票已经全部完成
  97. else if(completeCounter.equals(instanceOfNumbers)){
  98. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
  99. }
  100. }
  101. //按反对票数进行决定
  102. else{
  103. percents=refuseVotesCounts/instanceOfNumbers;
  104. //投票
  105. if(percents>=bpmNodeSign.getVoteAmount()){
  106. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
  107. }
  108. //投票已经全部完成
  109. else if(completeCounter.equals(instanceOfNumbers)){
  110. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
  111. }
  112. }
  113. }
  114. //按绝对票数投票
  115. else{
  116. //按同意票数进行决定
  117. if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){
  118. //投票同意票符合条件
  119. if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){
  120. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
  121. }
  122. //投票已经全部完成
  123. else if(completeCounter.equals(instanceOfNumbers)){
  124. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
  125. }
  126. }
  127. //按反对票数进行决定
  128. else{
  129. //投票
  130. if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){
  131. voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);
  132. }
  133. //投票已经全部完成
  134. else if(completeCounter.equals(instanceOfNumbers)){
  135. voteResult=new VoteResult(SIGN_RESULT_PASS, true);
  136. }
  137. }
  138. }
  139. return voteResult;
  140. }

Activiti 工作流会签开发设计思路的更多相关文章

  1. Activiti工作流引擎开发系列

    Activiti工作流引擎开发系列-01 作者:Jesai 没有伞的孩子,只能光脚奔跑! 前言: 初次接触工作流这个概念是自从2014年11月份开始,当时是由于我的毕业设计需要,还记得当时我毕业设计的 ...

  2. IOS开发设计思路

    我在做 iOS 开发的时候,发现自己在写程序的时候,常常处于两种状态的切换,我把这两种状态称为软件开发的上帝模式与农民模式.我先给大家介绍一下这两种模式的特点. 上帝模式 处于上帝模式时,我需要构思整 ...

  3. activiti工作流委托功能的设计和实现

    最近公司开发一个项目,客户提出了一个需求,用户在出差的时候,可以将自己的工作进行委托.可以指定委托时间.委托工作内容.指定委托人等等内容. 然后我就上网查询资料,发现activiti工作流本身并不支持 ...

  4. Activiti工作流 安装myeclipse activiti设计插件并生成数据库表

    从零开始学习Activiti工作流,记录下学习过程. 关于工作流的简介没什么好介绍了,只能说是个很有用的东西,数据库中23张表分别有什么用网上也有很详细的介绍,这里也不多加说明.activiti开发中 ...

  5. iOS开发:代码通用性以及其规范 第二篇(猜想iOS中实现TableView内部设计思路(附代码),以类似的思想实现一个通用的进度条)

    在iOS开发中,经常是要用到UITableView的,我曾经思考过这样一个问题,为什么任何种类的model放到TableView和所需的cell里面,都可以正常显示?而我自己写的很多view却只是能放 ...

  6. java工作流快速开发之授权代办的设计

    关键词:工作流快速开发平台  工作流流设计  业务流程管理 Java工作流引擎 asp.net 开源工作流  net开源工作流引擎 开源工作流系统 一.授权代办开发背景 应用需求:项目审批人出差无法及 ...

  7. IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路

    1.引言 在即时通讯网经常能看到各种高大上的高并发.分布式.高性能架构设计方面的文章,平时大家参加的众多开发者大会,主题也都是各种高大上的话题——什么5G啦.AI人工智能啦.什么阿里双11分分钟多少万 ...

  8. asp.net abp模块化开发之通用树2:设计思路及源码解析

    一.前言 上一篇大概说了下abp通用树形模块如何使用,本篇主要分析下设计思路. 日常开发中会用到很多树状结构的数据,比如:产品的多级分类.省市区县,大多数系统也会用到类似“通用字典/数据字典”的功能, ...

  9. JSAAS的Activiti会签开发扩展处理

    1.什么是会签? 在流程业务管理中,任务是通常都是由一个人去处理的,而多个人同时处理一个任务,这种任务我们称之为会签任务.这种业务需求很常见,如一个请款单,领导审批环节中,就需要多个部门领导签字.在流 ...

随机推荐

  1. 单点登录sso规范

    http://jasig.github.io/cas/development/protocol/CAS-Protocol-Specification.html

  2. HW7.8

    import java.util.ArrayList; import java.util.Scanner; public class Solution { public static void mai ...

  3. Umbraco中的权限体系结构

    分为管理用户体系,和成员用户体系,也就是 Users(用户)和Members(成员). 2.1. Users(用户) 用户是对功能操作权限定义的,首先看一下所有Action的Permissions: ...

  4. 高级C++开发工程师综合测试题(风林火山)

    题目要求:代码要求能够直接编译运行 1.       请实现一个函数:凑14:输入很多个整数(1<=数值<=13),任意两个数相加等于14就可以从数组中删除这两个数,求剩余数(按由小到大排 ...

  5. java方法签名

    方法的名字和参数列表称为方法的签名.方法的返回类型不是方法签名的一部分.

  6. Windows下如何检测用户修改了系统时间并且把系统时间改回来

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:Windows下如何检测用户修改了系统时间并且把系统时间改回来.

  7. iOS UITabBarItem 选中图的颜色,设置UIimage的渲染模式

    UITbarController之前有在这篇文章讲解:http://www.cnblogs.com/niit-soft-518/p/4447940.html 如果自定义了UITabBarItem的图片 ...

  8. 【转】suid sgid 详解

    转自:http://www.cnblogs.com/fhefh/archive/2011/09/20/2182155.html 如果你对SUID.SGID仍有迷惑可以好好参考一下! Copyright ...

  9. BZOJ 1143: [CTSC2008]祭祀river 最长反链

    1143: [CTSC2008]祭祀river Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline ...

  10. 基于华为Java编程规范的Eclipse checkStyle.xml

    发现项目组成员代码规范存在较大的问题,于是就在华为编程规范的基础上制定了这份checkStyle.xml文档,至于Eclipse怎么安装checkStyle插件以及该插件怎么使用请自行Google之. ...