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

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

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

 

 

並行會籤

串行會籤

 

104327vtl9q6007tht7q0d.jpg

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


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

 

 

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



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




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

Java代碼  [url=][/url]

  • <userTask activiti:assignee="${assignee}" id="SignTask1" name="領導會籤">  

  • <extensionElements>  

  • <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create"/>  

  • <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment"/>  

  • <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete"/>  

  • </extensionElements>  

  • <multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}">  

  • <completionCondition>${signComplete.isComplete(execution)}</completionCondition>  

  • </multiInstanceLoopCharacteristics>  

  • </userTask>  

 

 

 

 

其中,isSequential爲true則爲串行會籤,若爲false則爲並行會籤,而activiti:collection可以來自我們Spring容器中的接口及方法,表示獲取會籤用戶集合,taskUserAssignService.getSignUser(execution)。其獲取會籤的用戶值來自兩個方面,一個在界面中指定的會籤人員,另一個在後臺會籤節點上配置的人員。

 

 

 

 

後臺會籤節點人員設置

 

 

 

 

<completeCondition>爲完成會籤的條件signComplete.isComplete(execution),可以在這裏根據我們的會籤規則及目前的會籤情況,決定會籤是否完成。其實現如下所示:

最終實現邏輯:
Java代碼  [url=][/url]

..

  • @Override  

  • public boolean isComplete(ActivityExecution execution) {  

  •       

  •     logger.debug("entert the SignComplete isComplete method...");  

  •       

  •     String nodeId=execution.getActivity().getId();  

  •     String actInstId=execution.getProcessInstanceId();  

  •       

  •     ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId);  

  •     //取得會籤設置的規則  

  •     BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId);  

  •     //完成會籤的次數  

  •     Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");  

  •     //總循環次數  

  •     Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");  

  •     //計算投票結果。  

  •     VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers);  

  •       

  •     String signResult=voteResult.getSignResult();  

  •     boolean isCompleted=voteResult.getIsComplete();  

  •       

  •     /**

  •     * 會簽完成做的動作。

  •     * 1.***會籤的流程變量。

  •     * 2.將會籤數據更新爲完成。

  •     * 3.設置會簽結果變量。

  •     * 4.更新會籤節點結果。

  •     * 5.清除會籤用戶。

  •     */  

  •     if(isCompleted){  

  •         //***會籤的變量。  

  •         //*** assignee,loopCounter變量。  

  •         bpmService.delLoopAssigneeVars(execution.getId());  

  •         logger.debug("set the sign result + " + signResult);  

  •         //將會籤數據更新爲完成。  

  •         taskSignDataService.batchUpdateCompleted(actInstId, nodeId);  

  •         //設置會籤的結果  

  •         execution.setVariable("signResult_" + nodeId , signResult);  

  •         //更新會籤節點的狀態。  

  •         Short status=TaskOpinion.STATUS_PASSED;  

  •         if(signResult.equals(SIGN_RESULT_REFUSE)){  

  •             status=TaskOpinion.STATUS_NOT_PASSED;  

  •         }  

  •         //更新會籤節點的狀態。  

  •         bpmProStatusDao.updStatus(actInstId, nodeId,status);  

  •         //清除會籤用戶。  

  •         taskUserAssignService.clearSignUser();  

  •     }  

  •       

  •     return isCompleted;  

  • }  

  •   

  • **  

  • * 根據會籤規則計算投票結果。  

  • * <pre>  

  • * 1.如果會籤規則爲空,那麼需要所有的人同意通過會籤,否則不通過。  

  • * 2.否則按照規則計算投票結果。  

  • * </pre>  

  • * @param bpmNodeSign       會籤規則  

  • * @param actInstId         流程實例ID  

  • * @param nodeId            節點id名稱  

  • * @param completeCounter       循環次數  

  • * @param instanceOfNumbers     總的會籤次數。  

  • * @return  

  • */  

  • private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){  

  •     VoteResult voteResult=new VoteResult();  

  •     //沒有會籤實例  

  •     if(instanceOfNumbers==0){  

  •         return voteResult;  

  •     }  

  •     //投同意票數  

  •     Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId);  

  •     //沒有設置會籤規則  

  •     //(那麼得全部會籤通過才通過,否則不通過)  

  •     if(bpmNodeSign==null){  

  •         //還沒有完成可以退出。  

  •         if(completeCounter<instanceOfNumbers){  

  •             return voteResult;  

  •         }  

  •         else{  

  •             //完成了 (全部同意才通過)  

  •             if(agreeVotesCounts.equals(instanceOfNumbers)){  

  •                 return new VoteResult(SIGN_RESULT_PASS,true);  

  •             }  

  •             else{  

  •                 return new VoteResult(SIGN_RESULT_REFUSE,true);  

  •             }  

  •         }  

  •     }  

  •       

  •     //投反對票數  

  •     Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId);  

  •       

  •     //檢查投票是否完成  

  •     if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){  

  •         float percents=0;  

  •         //按同意票數進行決定  

  •         if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){  

  •             percents=agreeVotesCounts/instanceOfNumbers;  

  •             //投票同意票符合條件  

  •             if(percents>=bpmNodeSign.getVoteAmount()){  

  •                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  

  •             }  

  •             //投票已經全部完成  

  •             else if(completeCounter.equals(instanceOfNumbers)){  

  •                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  

  •             }  

  •         }  

  •         //按反對票數進行決定  

  •         else{  

  •             percents=refuseVotesCounts/instanceOfNumbers;  

  •             //投票  

  •             if(percents>=bpmNodeSign.getVoteAmount()){  

  •                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  

  •             }  

  •             //投票已經全部完成  

  •             else if(completeCounter.equals(instanceOfNumbers)){  

  •                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  

  •             }  

  •         }  

  •     }  

  •     //按絕對票數投票  

  •     else{  

  •         //按同意票數進行決定  

  •         if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){  

  •             //投票同意票符合條件  

  •             if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){  

  •                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  

  •             }  

  •             //投票已經全部完成  

  •             else if(completeCounter.equals(instanceOfNumbers)){  

  •                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  

  •             }  

  •         }  

  •         //按反對票數進行決定  

  •         else{  

  •             //投票  

  •             if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){  

  •                 voteResult=new VoteResult(SIGN_RESULT_REFUSE, true);  

  •             }  

  •             //投票已經全部完成  

  •             else if(completeCounter.equals(instanceOfNumbers)){  

  •                 voteResult=new VoteResult(SIGN_RESULT_PASS, true);  

  •             }  

  •         }  

  •     }  

  •     return voteResult;  

  • }  




最終實現效果,可以在線訪問
http://www.jee-soft.cn:10080/bpm3/login.jsp
csx/1
可以通過訪問流程管理體驗效果
最終展示視頻可以看以下鏈接:
http://www.jee-soft.cn/htsite/html/cpjfw/zxjc/bpmx3/index.html

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章