Activiti 工作流會簽開發設計思路


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

在流程業務管理中,任務是通常都是由一個人去處理的,而多個人同時處理一個任務,這種任務我們稱之為會簽任務。這種業務需求也很常見,如一個請款單,領導審批環節中,就需要多個部門領導簽字。在流程業務中,我們可以把每個領導簽字的環節都定義為任務,但若這樣,這個流程業務有一點是固定的,就是簽批人是固定的。而任務是由一個領導簽完再到另一領導,當然也可以由多個領導同時簽字。

傳統的用流程業務來解決可以采用以下的做法:


串行會簽
串行會簽

並行會簽


 

前者在流程業務中,叫串行會簽,也即是由一個領導簽完再至另一領導簽。后者我們稱之為並行會簽,表示幾個領導同時進行簽發,而不清楚最終是誰先簽。


以上的解決方式有兩大業務需求下是不能滿足的,若會簽的領導不是固定的,即可以由上一任務審批人提交前隨意進行選擇,另一種是對於會簽業務中,要求若其中一部分領導審批通過,即直接往下走,不需要全部領導進行審批。另外,對於這種情況下,統計最終領導會簽的結果也是比較困難的,即對審批單的意見是同意還是否決沒有辦法清楚。以上兩種業務需求也是很常見的日常需求,但我們若采用了固定的流程節點,則不能實現。在這里,可以采用Activiti的節點多實例來處理,以上流程則可以簡化為下:


activiti會簽流程設計

何謂多任務實例節點?在Activiti5上的解析則為動態的多任務節點,可以根據傳入的動態人員數進行動態生成任務。生成的任務數則不固定,可以進行並行會簽,也可以進行串行會簽。會簽任務最終是否需要往下執行,由會簽設置的規則來進行約束。如我們可以常規去設置“一票通過”、“一票否決”、“少數服務多數”等會簽規則。因此,我們需要在會簽節點上綁定我們的設計規則。會簽規則設置界面如下:

會簽規則設計

通過會簽設計規則,可以清楚最終會簽人員的投票結果。其數據結構如下所示:
會簽規則表

會簽任務的定義本身已經由Activiti來實現了,但需要動態傳入動態的人員數

Java代碼   收藏代碼
  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. @Override  
  2. public boolean isComplete(ActivityExecution execution) {  
  3.       
  4.     logger.debug("entert the SignComplete isComplete method...");  
  5.       
  6.     String nodeId=execution.getActivity().getId();  
  7.     String actInstId=execution.getProcessInstanceId();  
  8.       
  9.     ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);  
  10.     //取得會簽設置的規則  
  11.     BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);  
  12.     //完成會簽的次數  
  13.     Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");  
  14.     //總循環次數  
  15.     Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");  
  16.     //計算投票結果。  
  17.     VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);  
  18.       
  19.     String signResult=voteResult.getSignResult();  
  20.     boolean isCompleted=voteResult.getIsComplete();  
  21.       
  22.     /** 
  23.     * 會簽完成做的動作。 
  24.     * 1.刪除會簽的流程變量。 
  25.     * 2.將會簽數據更新為完成。 
  26.     * 3.設置會簽結果變量。 
  27.     * 4.更新會簽節點結果。 
  28.     * 5.清除會簽用戶。 
  29.     */  
  30.     if(isCompleted){  
  31.         //刪除會簽的變量。  
  32.         //刪除 assignee,loopCounter變量。  
  33.         bpmService.delLoopAssigneeVars(execution.getId());  
  34.         logger.debug("set the sign result + " + signResult);  
  35.         //將會簽數據更新為完成。  
  36.         taskSignDataService.batchUpdateCompleted(actInstId, nodeId);  
  37.         //設置會簽的結果  
  38.         execution.setVariable("signResult_" + nodeId , signResult);  
  39.         //更新會簽節點的狀態。  
  40.         Short status=TaskOpinion.STATUS_PASSED;  
  41.         if(signResult.equals(SIGN_RESULT_REFUSE)){  
  42.             status=TaskOpinion.STATUS_NOT_PASSED;  
  43.         }  
  44.         //更新會簽節點的狀態。  
  45.         bpmProStatusDao.updStatus(actInstId, nodeId,status);  
  46.         //清除會簽用戶。  
  47.         taskUserAssignService.clearSignUser();  
  48.     }  
  49.       
  50.     return isCompleted;  
  51. }  
  52.   
  53. **  
  54.  * 根據會簽規則計算投票結果。  
  55.  * <pre>  
  56.  * 1.如果會簽規則為空,那么需要所有的人同意通過會簽,否則不通過。  
  57.  * 2.否則按照規則計算投票結果。  
  58.  * </pre>  
  59.  * @param bpmNodeSign       會簽規則  
  60.  * @param actInstId         流程實例ID  
  61.  * @param nodeId            節點id名稱  
  62.  * @param completeCounter       循環次數  
  63.  * @param instanceOfNumbers     總的會簽次數。  
  64.  * @return  
  65.  */  
  66. private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){  
  67.     VoteResult voteResult=new VoteResult();  
  68.     //沒有會簽實例  
  69.     if(instanceOfNumbers==0){  
  70.         return voteResult;  
  71.     }  
  72.     //投同意票數  
  73.     Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);  
  74.     //沒有設置會簽規則  
  75.     //(那么得全部會簽通過才通過,否則不通過)  
  76.     if(bpmNodeSign==null){  
  77.         //還沒有完成可以退出。  
  78.         if(completeCounter<instanceOfNumbers){  
  79.             return voteResult;  
  80.         }  
  81.         else{  
  82.             //完成了 (全部同意才通過)  
  83.             if(agreeVotesCounts.equals(instanceOfNumbers)){  
  84.                 return new VoteResult(SIGN_RESULT_PASS,true);  
  85.             }  
  86.             else{  
  87.                 return new VoteResult(SIGN_RESULT_REFUSE,true);  
  88.             }  
  89.         }  
  90.     }  
  91.       
  92.     //投反對票數  
  93.     Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);  
  94.       
  95.     //檢查投票是否完成  
  96.     if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){  
  97.         float percents=0;  
  98.         //按同意票數進行決定  
  99.         if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){  
  100.             percents=agreeVotesCounts/instanceOfNumbers;  
  101.             //投票同意票符合條件  
  102.             if(percents>=bpmNodeSign.getVoteAmount()){  
  103.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  
  104.             }  
  105.             //投票已經全部完成  
  106.             else if(completeCounter.equals(instanceOfNumbers)){  
  107.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  
  108.             }  
  109.         }  
  110.         //按反對票數進行決定  
  111.         else{  
  112.             percents=refuseVotesCounts/instanceOfNumbers;  
  113.             //投票  
  114.             if(percents>=bpmNodeSign.getVoteAmount()){  
  115.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  
  116.             }  
  117.             //投票已經全部完成  
  118.             else if(completeCounter.equals(instanceOfNumbers)){  
  119.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  
  120.             }  
  121.         }  
  122.     }  
  123.     //按絕對票數投票  
  124.     else{  
  125.         //按同意票數進行決定  
  126.         if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){  
  127.             //投票同意票符合條件  
  128.             if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){  
  129.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  
  130.             }  
  131.             //投票已經全部完成  
  132.             else if(completeCounter.equals(instanceOfNumbers)){  
  133.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  
  134.             }  
  135.         }  
  136.         //按反對票數進行決定  
  137.         else{  
  138.             //投票  
  139.             if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){  
  140.                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  
  141.             }  
  142.             //投票已經全部完成  
  143.             else if(completeCounter.equals(instanceOfNumbers)){  
  144.                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  
  145.             }  
  146.         }  
  147.     }  
  148.     return voteResult;  
  149. }  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM