Activiti 工作流会签开发设计思路

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

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

 
串行会签
串行会签
 
并行会签
 
 

 

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

 

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

 
activiti会签流程设计
 
何谓多任务实例节点?在Activiti5上的解析则为动态的多任务节点,可以根据传入的动态人员数进行动态生成任务。生成的任务数则不固定,可以进行并行会签,也可以进行串行会签。会签任务最终是否需要往下执行,由会签设置的规则来进行约束。如我们可以常规去设置“一票通过”、“一票否决”、“少数服务多数”等会签规则。因此,我们需要在会签节点上绑定我们的设计规则。会签规则设置界面如下:
 
会签规则设计
 
通过会签设计规则,可以清楚最终会签人员的投票结果。其数据结构如下所示:
会签规则表
 
会签任务的定义本身已经由Activiti来实现了,但需要动态传入动态的人员数
Xml代码 
  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)。其获取会签的用户值来自两个方面,一个在界面中指定的会签人员,另一个在后台会签节点上配置的人员。
 
会签人员设置
后台会签节点人员设置
 
会签人员设置2
任务审批面上选择下一任务会签人员
 
<completeCondition>为完成会签的条件signComplete.isComplete(execution),可以在这里根据我们的会签规则及目前的会签情况,决定会签是否完成。其实现如下所示:
 
最终实现逻辑:
Java代码 
  1. public boolean isComplete(ActivityExecution execution) {    
  2.         
  3.     logger.debug("entert the SignComplete isComplete method...");    
  4.         
  5.     String nodeId=execution.getActivity().getId();    
  6.     String actInstId=execution.getProcessInstanceId();    
  7.         
  8.     ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);    
  9.     //取得会签设置的规则    
  10.     BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);    
  11.     //完成会签的次数    
  12.     Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");    
  13.     //总循环次数    
  14.     Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");    
  15.     //计算投票结果。    
  16.     VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);    
  17.         
  18.     String signResult=voteResult.getSignResult();    
  19.     boolean isCompleted=voteResult.getIsComplete();    
  20.         
  21.     /**  
  22.     * 会签完成做的动作。  
  23.     * 1.删除会签的流程变量。  
  24.     * 2.将会签数据更新为完成。  
  25.     * 3.设置会签结果变量。  
  26.     * 4.更新会签节点结果。  
  27.     * 5.清除会签用户。  
  28.     */    
  29.     if(isCompleted){    
  30.         //删除会签的变量。    
  31.         //删除 assignee,loopCounter变量。    
  32.         bpmService.delLoopAssigneeVars(execution.getId());    
  33.         logger.debug("set the sign result + " + signResult);    
  34.         //将会签数据更新为完成。    
  35.         taskSignDataService.batchUpdateCompleted(actInstId, nodeId);    
  36.         //设置会签的结果    
  37.         execution.setVariable("signResult_" + nodeId , signResult);    
  38.         //更新会签节点的状态。    
  39.         Short status=TaskOpinion.STATUS_PASSED;    
  40.         if(signResult.equals(SIGN_RESULT_REFUSE)){    
  41.             status=TaskOpinion.STATUS_NOT_PASSED;    
  42.         }    
  43.         //更新会签节点的状态。    
  44.         bpmProStatusDao.updStatus(actInstId, nodeId,status);    
  45.         //清除会签用户。    
  46.         taskUserAssignService.clearSignUser();    
  47.     }    
  48.         
  49.     return isCompleted;    
  50. }    
  51.     
  52. **    
  53.  * 根据会签规则计算投票结果。    
  54.  * <pre>    
  55.  * 1.如果会签规则为空,那么需要所有的人同意通过会签,否则不通过。    
  56.  * 2.否则按照规则计算投票结果。    
  57.  * </pre>    
  58.  * @param bpmNodeSign       会签规则    
  59.  * @param actInstId         流程实例ID    
  60.  * @param nodeId            节点id名称    
  61.  * @param completeCounter       循环次数    
  62.  * @param instanceOfNumbers     总的会签次数。    
  63.  * @return    
  64.  */    
  65. private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){    
  66.     VoteResult voteResult=new VoteResult();    
  67.     //没有会签实例    
  68.     if(instanceOfNumbers==0){    
  69.         return voteResult;    
  70.     }    
  71.     //投同意票数    
  72.     Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);    
  73.     //没有设置会签规则    
  74.     //(那么得全部会签通过才通过,否则不通过)    
  75.     if(bpmNodeSign==null){    
  76.         //还没有完成可以退出。    
  77.         if(completeCounter<instanceOfNumbers){    
  78.             return voteResult;    
  79.         }    
  80.         else{    
  81.             //完成了 (全部同意才通过)    
  82.             if(agreeVotesCounts.equals(instanceOfNumbers)){    
  83.                 return new VoteResult(SIGN_RESULT_PASS,true);    
  84.             }    
  85.             else{    
  86.                 return new VoteResult(SIGN_RESULT_REFUSE,true);    
  87.             }    
  88.         }    
  89.     }    
  90.         
  91.     //投反对票数    
  92.     Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);    
  93.         
  94.     //检查投票是否完成    
  95.     if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){    
  96.         float percents=0;    
  97.         //按同意票数进行决定    
  98.         if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){    
  99.             percents=agreeVotesCounts/instanceOfNumbers;    
  100.             //投票同意票符合条件    
  101.             if(percents>=bpmNodeSign.getVoteAmount()){    
  102.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);    
  103.             }    
  104.             //投票已经全部完成    
  105.             else if(completeCounter.equals(instanceOfNumbers)){    
  106.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);    
  107.             }    
  108.         }    
  109.         //按反对票数进行决定    
  110.         else{    
  111.             percents=refuseVotesCounts/instanceOfNumbers;    
  112.             //投票    
  113.             if(percents>=bpmNodeSign.getVoteAmount()){    
  114.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);    
  115.             }    
  116.             //投票已经全部完成    
  117.             else if(completeCounter.equals(instanceOfNumbers)){    
  118.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);    
  119.             }    
  120.         }    
  121.     }    
  122.     //按绝对票数投票    
  123.     else{    
  124.         //按同意票数进行决定    
  125.         if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){    
  126.             //投票同意票符合条件    
  127.             if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){    
  128.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);    
  129.             }    
  130.             //投票已经全部完成    
  131.             else if(completeCounter.equals(instanceOfNumbers)){    
  132.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);    
  133.             }    
  134.         }    
  135.         //按反对票数进行决定    
  136.         else{    
  137.             //投票    
  138.             if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){    
  139.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);    
  140.             }    
  141.             //投票已经全部完成    
  142.             else if(completeCounter.equals(instanceOfNumbers)){    
  143.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);    
  144.             }    
  145.         }    
  146.     }    
  147.     return voteResult;    
  148. }    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值