你明白什么是会签?工作流+会签应用
1.什么是會(huì)簽?
?
在流程業(yè)務(wù)管理中,任務(wù)是通常都是由一個(gè)人去處理的,而多個(gè)人同時(shí)處理一個(gè)任務(wù),這種任務(wù)我們稱之為會(huì)簽任務(wù)。這種業(yè)務(wù)需求很常見(jiàn),如一個(gè)請(qǐng)款單,領(lǐng)導(dǎo)審批環(huán)節(jié)中,就需要多個(gè)部門領(lǐng)導(dǎo)簽字。在流程業(yè)務(wù)中,我們可以把每個(gè)領(lǐng)導(dǎo)簽字的環(huán)節(jié)都定義為任務(wù),并且這個(gè)會(huì)簽的人員是不固定的,若固定的我們可以通過(guò)Activiti的并行任務(wù)或串行任務(wù)來(lái)處理。會(huì)簽的引入說(shuō)明,無(wú)非就是為了流程流轉(zhuǎn)至某一環(huán)節(jié)點(diǎn),其審批的人員是動(dòng)態(tài)的,并且需要根據(jù)會(huì)簽審批的結(jié)果實(shí)現(xiàn)流程的不同流轉(zhuǎn)。
2.中國(guó)特色的會(huì)簽需求是什么?
?
會(huì)簽需求主要有以下兩方面:
以下我們就是圍繞以上的需求進(jìn)行擴(kuò)展實(shí)現(xiàn)的
3.Activiti對(duì)于會(huì)簽的實(shí)現(xiàn)
?
BPMN2的標(biāo)準(zhǔn)中并沒(méi)有對(duì)以上這種情景提供完善的支持,因此要在Activiti中實(shí)現(xiàn)會(huì)簽審批,我們需要結(jié)合Activiti提供的流程任務(wù)的多實(shí)例特性,進(jìn)行一些必要的擴(kuò)展,以支持我們的中國(guó)特色的會(huì)簽需求。
會(huì)簽任務(wù)也是一種人工任務(wù),其在activiti的定義中,也是使用UserTask來(lái)定義,但在屬性上我們需要對(duì)這個(gè)定義的類型進(jìn)行特殊的配置,即為多任務(wù)實(shí)例類型(并行或串行)任何一種。另外需要定義會(huì)簽的參與人員,再定義會(huì)簽的完成條件(若不定義,表示其是所有參與人均完成后,流程才往下跳轉(zhuǎn))。
3.1.多實(shí)例的人工任務(wù)配置
?
通過(guò)在UserTask節(jié)點(diǎn)的屬性上配置,如下所示:
其生成的BPMN的配置文件如下所示:
<userTask id=”sid-78A17A9B-1185-48AA-A1CA-611421251D52″ name=”經(jīng)理會(huì)簽”><multiInstanceLoopCharacteristics isSequential=”false” activiti:collection=”${counterSignService.getUsers(execution)}”>
<completionCondition>${counterSignService.isComplete(execution)}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
【說(shuō)明】:
我們就是圍繞著這幾點(diǎn)來(lái)實(shí)現(xiàn)中國(guó)式的流程會(huì)簽的
3.2 會(huì)簽任務(wù)的人員集合計(jì)算處理
?
我們?cè)赟pring容器中定義一個(gè)會(huì)簽服務(wù)類(counterSignService)里面提供兩個(gè)api接口,一個(gè)是獲得任務(wù)的人員集合,另一個(gè)是判斷當(dāng)前任務(wù)是否已經(jīng)完成了會(huì)簽的計(jì)算,其參考代碼如下所示:
package com.redxun.bpm.core.service.sign;import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set;import javax.annotation.Resource;import org.activiti.engine.impl.pvm.delegate.ActivityExecution; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;import com.redxun.bpm.activiti.util.ProcessHandleHelper; import com.redxun.bpm.core.entity.BpmDestNode; import com.redxun.bpm.core.entity.BpmRuPath; import com.redxun.bpm.core.entity.BpmSignData; import com.redxun.bpm.core.entity.IExecutionCmd; import com.redxun.bpm.core.entity.ProcessMessage; import com.redxun.bpm.core.entity.config.MultiTaskConfig; import com.redxun.bpm.core.entity.config.TaskVotePrivConfig; import com.redxun.bpm.core.entity.config.UserTaskConfig; import com.redxun.bpm.core.identity.service.BpmIdentityCalService; import com.redxun.bpm.core.manager.BpmNodeSetManager; import com.redxun.bpm.core.manager.BpmSignDataManager; import com.redxun.bpm.enums.TaskOptionType; import com.redxun.org.api.model.IdentityInfo; import com.redxun.sys.org.entity.OsGroup; import com.redxun.sys.org.entity.OsRelType; import com.redxun.sys.org.entity.OsUser; import com.redxun.sys.org.manager.OsGroupManager; import com.redxun.sys.org.manager.OsUserManager;/*** 會(huì)簽配置服務(wù)類* @author csx**/ public class CounterSignService { @Resource private BpmSignDataManager bpmSignDataManager; @Resource private BpmNodeSetManager bpmNodeSetManager; @ResourceBpmIdentityCalService bpmIdentityCalService; @Resource private OsGroupManager osGroupManager; @Resource private OsUserManager osUserManager;private Log logger=LogFactory.getLog(CounterSignService.class); /*** 獲得會(huì)簽任務(wù)中的人員計(jì)算集合* @param execution* @return*/ public Set<String> getUsers(ActivityExecution execution){logger.debug("enter the CounterSignService ");Set<String> userIds=new LinkedHashSet<String>();String nodeId=execution.getActivity().getId();//1.回退處理通過(guò)BpmRuPath backRuPath=ProcessHandleHelper.getBackPath();if(backRuPath!=null && "YES".equals(backRuPath.getIsMultiple())){String uIds=backRuPath.getUserIds();userIds.addAll(Arrays.asList(uIds.split("[,]"))); execution.setVariable("signUserIds_"+nodeId,uIds);return userIds;}//2.通過(guò)變量來(lái)判斷是否第一次進(jìn)入該方法String signUserIds=(String)execution.getVariable("signUserIds_"+nodeId);if(StringUtils.isNotEmpty(signUserIds)){String[]uIds=signUserIds.split("[,]");userIds.addAll(Arrays.asList(uIds));return userIds;}//3.從界面中的提交變量取用戶IExecutionCmd nextCmd=ProcessHandleHelper.getProcessCmd();BpmDestNode bpmDestNode=nextCmd.getNodeUserMap().get(nodeId);if(bpmDestNode!=null && StringUtils.isNotEmpty(bpmDestNode.getUserIds())){//加至流程變量中,以使后續(xù)繼續(xù)不需要從線程及數(shù)據(jù)庫(kù)中獲取execution.setVariable("signUserIds_"+nodeId,bpmDestNode.getUserIds());execution.setVariable("priority_"+nodeId,bpmDestNode.getPriority());execution.setVariable("expiretime_"+nodeId, bpmDestNode.getExpireTime());String[]uIds=bpmDestNode.getUserIds().split("[,]");userIds.addAll(Arrays.asList(uIds));return userIds;}//4.從數(shù)據(jù)庫(kù)中讀取節(jié)點(diǎn)人員配置獲得參與人員列表Collection<IdentityInfo> idInfoList=bpmIdentityCalService.calNodeUsersOrGroups(execution.getProcessDefinitionId(), execution.getCurrentActivityId(),execution.getVariables());for(IdentityInfo identityInfo:idInfoList){if(IdentityInfo.IDENTIFY_TYPE_USER.equals(identityInfo.getIdentityType())){userIds.add(identityInfo.getIdentityInfoId());}else{List<OsUser> users= osUserManager.getByGroupIdRelTypeId(identityInfo.getIdentityInfoId(), OsRelType.REL_CAT_GROUP_USER_BELONG_ID);for(OsUser u:users){userIds.add(u.getUserId());}}}if(userIds.size()>0){StringBuffer sb=new StringBuffer();for(String uId:userIds){sb.append(uId).append(",");}if(sb.length()>0){sb.deleteCharAt(sb.length()-1);}execution.setVariable("signUserIds_"+nodeId,sb.toString());}else{String name=(String)execution.getActivity().getProperty("name");ProcessMessage msg=ProcessHandleHelper.getProcessMessage();msg.getErrorMsges().add("會(huì)簽節(jié)點(diǎn)["+name+"]沒(méi)有設(shè)置執(zhí)行人員,請(qǐng)聯(lián)系管理員!");}return userIds; }/*** 會(huì)簽是否計(jì)算完成* @param execution* @return*/ public boolean isComplete(ActivityExecution execution){//完成會(huì)簽的次數(shù)Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances");//總循環(huán)次數(shù)Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances");String solId=(String)execution.getVariable("solId");String nodeId=execution.getActivity().getId();UserTaskConfig taskConfig=bpmNodeSetManager.getTaskConfig(solId, nodeId);//獲得任務(wù)及其多實(shí)例的配置,則任務(wù)不進(jìn)行任何投票的設(shè)置及處理,即需要所有投票完成后來(lái)才跳至下一步。if(taskConfig.getMultiTaskConfig()==null){return completeCounter==instanceOfNumbers;}//獲得會(huì)簽的數(shù)據(jù)List<BpmSignData> bpmSignDatas=bpmSignDataManager.getByInstIdNodeId(execution.getProcessInstanceId(), nodeId);MultiTaskConfig multiTask=taskConfig.getMultiTaskConfig();//通過(guò)票數(shù)int passCount=0;//反對(duì)票數(shù)int refuseCount=0;//棄權(quán)票數(shù)int abstainCount=0;for(BpmSignData data:bpmSignDatas){int calCount=1;//棄權(quán)不作票數(shù)統(tǒng)計(jì)if(TaskOptionType.ABSTAIN.name().equals(data.getVoteStatus())){abstainCount++;continue;}String userId=data.getUserId();//檢查是否有特權(quán)的處理if(multiTask.getVotePrivConfigs().size()>0){//計(jì)算用戶的用戶組List<OsGroup> osGroups=osGroupManager.getBelongGroups(userId);for(TaskVotePrivConfig voteConfig:multiTask.getVotePrivConfigs()){//是否在特權(quán)里boolean isInPriv=false;//為用戶類型if(TaskVotePrivConfig.USER.equals(voteConfig.getIdentityType()) && voteConfig.getIdentityIds().contains(userId)){isInPriv=true;}else{//為用戶組類型for(OsGroup osGroup:osGroups){if(voteConfig.getIdentityIds().contains(osGroup.getGroupId())){isInPriv=true;break;}}}//若找到特權(quán),則計(jì)算其值if(isInPriv){calCount=voteConfig.getVoteNums();break;}}}//統(tǒng)計(jì)同意票數(shù)if(TaskOptionType.AGREE.name().equals(data.getVoteStatus())){passCount+=calCount;}else{//統(tǒng)計(jì)反對(duì)票數(shù)refuseCount+=calCount;}}logger.debug("==============================passCount:"+passCount+" refuseCount:" + refuseCount +" abstainCount:"+abstainCount);//是否可以跳出會(huì)簽boolean isNext=false;String result=null;//按投票通過(guò)數(shù)進(jìn)行計(jì)算if(MultiTaskConfig.VOTE_TYPE_PASS.equals(multiTask.getVoteResultType())){//計(jì)算是否通過(guò)//按投票數(shù)進(jìn)行統(tǒng)計(jì)if(MultiTaskConfig.CAL_TYPE_NUMS.equals(multiTask.getCalType())){//代表通過(guò)if(passCount>=multiTask.getVoteValue()){isNext=true;result="PASS";}}else{//按百分比進(jìn)行計(jì)算int resultPercent=new Double(passCount*100/(passCount+refuseCount+abstainCount)).intValue();//代表通過(guò)if(resultPercent>=multiTask.getVoteValue()){isNext=true;result="PASS";}}}else{//按投票反對(duì)數(shù)進(jìn)行計(jì)算//計(jì)算是否通過(guò)//按投票數(shù)進(jìn)行統(tǒng)計(jì)if(MultiTaskConfig.CAL_TYPE_NUMS.equals(multiTask.getCalType())){//代表通過(guò)if(refuseCount>=multiTask.getVoteValue()){isNext=true;result="REFUSE";}}else{//按百分比進(jìn)行計(jì)算int resultPercent=new Double(refuseCount*100/(passCount+refuseCount+abstainCount)).intValue();//代表通過(guò)if(resultPercent>=multiTask.getVoteValue()){isNext=true;result="REFUSE";}}}if((MultiTaskConfig.HANDLE_TYPE_DIRECT.equals(multiTask.getHandleType())&& isNext)//直接處理|| (MultiTaskConfig.HANDLE_TYPE_WAIT_TO.equals(multiTask.getHandleType()) && completeCounter==instanceOfNumbers)){//等待所有的處理完execution.setVariable("voteResult_"+nodeId, result);//刪除該節(jié)點(diǎn)的會(huì)簽數(shù)據(jù)for(BpmSignData data:bpmSignDatas){bpmSignDataManager.deleteObject(data);}return true;}return false;} }?
【說(shuō)明】
以上的代碼的人員計(jì)算有幾個(gè)來(lái)源:
會(huì)簽的投票處理結(jié)果放至流程變量中去,供后續(xù)的分支條件來(lái)處理,我們把會(huì)簽的配置設(shè)置管理如下:
我們提供了按票數(shù)、百分比的投票處理,同時(shí)允許有特權(quán)的用戶的投票規(guī)則以支持靈活的會(huì)簽結(jié)果運(yùn)算。
咨詢了解
QQ: 1950148199
手機(jī):18620763495
電話:020-29026351
總結(jié)
以上是生活随笔為你收集整理的你明白什么是会签?工作流+会签应用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 共享文件的原理
- 下一篇: 【WebRTC】回声抵消(aec、aec