你明⽩什么是会签?⼯作流+会签应⽤
1.什么是会签?
在流程业务管理中,任务是通常都是由⼀个⼈去处理的,⽽多个⼈同时处理⼀个任务,这种任务我们称之为会签任务。这种业务需求很常见,如⼀个请款单,领导审批环节中,就需要多个部门领导签字。在流程业务中,我们可以把每个领导签字的环节都定义为任务,并且这个会签的⼈员是不固定的,若固定的我们可以通过Activiti的并⾏任务或串⾏任务来处理。会签的引⼊说明,⽆⾮就是为了流程流转⾄某⼀环节点,其审批的⼈员是动态的,并且需要根据会签审批的结果实现流程的不同流转。
2.中国特⾊的会签需求是什么?
会签需求主要有以下两⽅⾯:
1. 会签的参与⼈员
2. 会签审批的顺序
3. 会签审批的结果
4. 动态加签
梅花的形容词
以下我们就是围绕以上的需求进⾏扩展实现的
3.Activiti对于会签的实现
BPMN2的标准中并没有对以上这种情景提供完善的⽀持,因此要在Activiti中实现会签审批,我们需要结合Activiti提供的流程任务的多实例特性,进⾏⼀些必要的扩展,以⽀持我们的中国特⾊的会签需求。
会签任务也是⼀种⼈⼯任务,其在activiti的定义中,也是使⽤UrTask来定义,但在属性上我们需要对这个定义的类型进⾏特殊的配置,即为多任务实例类型(并⾏或串⾏)任何⼀种。另外需要定义会签的参与⼈员,再定义会签的完成条件(若不定义,表⽰其是所有参与⼈均完成后,流程才往下跳转)。
3.1.多实例的⼈⼯任务配置
通过在UrTask节点的属性上配置,如下所⽰:
1.png
其⽣成的BPMN的配置⽂件如下所⽰:
<urTask id=”sid-78A17A9B-1185-48AA-A1CA-611421251D52″ name=”经理会签”>
<multiInstanceLoopCharacteristics isSequential=”fal” activiti:collection=”${Urs(execution)}”> <completionCondition>${counterSignService.isComplete(execution)}</completionCondition>
</multiInstanceLoopCharacteristics>
</urTask>
【说明】:
1. isSequential=”fal” 表⽰这是⾮串⾏会签,即为并⾏会签,如三个⼈参与会签,是三个⼈同时收到待办,任务实例是同时产⽣
的。
2. activiti:collection 表⽰是会签的参与⼈员集合,⽤户可以通过定义⾃⾝的服务类来获取
3. completionCondition 表⽰是任务往下跳转的完成条件,返回true是,表⽰条件成⽴,流程会跳⾄下⼀审批环节。
我们就是围绕着这⼏点来实现中国式的流程会签的
3.2 会签任务的⼈员集合计算处理
我们在Spring容器中定义⼀个会签服务类(counterSignService)⾥⾯提供两个api接⼝,⼀个是获得任务的⼈员集合,另⼀个是判断当前
import flect.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 ine.impl.pvm.delegate.ActivityExecution; import s.lang.StringUtils;
import s.logging.Log;
import s.logging.LogFactory;
dxun.bpm.activiti.util.ProcessHandleHelper;
ntity.BpmDestNode;
ntity.BpmRuPath;
ntity.BpmSignData;
ntity.IExecutionCmd;
ntity.ProcessMessage;
fig.MultiTaskConfig;
fig.TaskVotePrivConfig; fig.UrTaskConfig;
identity.rvice.BpmIdentityCalService; anager.BpmNodeSetManager; anager.BpmSignDataManager; ums.TaskOptionType;
del.IdentityInfo;
tity.OsGroup;
走进三亚tity.OsRelType;
tity.OsUr;
anager.OsGroupManager;
anager.OsUrManager;
/**
* 会签配置服务类
* @author csx
*
*/
志愿者活动方案public class CounterSignService {
@Resource
private BpmSignDataManager bpmSignDataManager;
@Resource
private BpmNodeSetManager bpmNodeSetManager;
@Resource
BpmIdentityCalService bpmIdentityCalService;
@Resource互质数是什么意思
private OsGroupManager osGroupManager;
@Resource
private OsUrManager osUrManager;
private Log Log(CounterSignService.class); /**
* 获得会签任务中的⼈员计算集合
* @param execution
* @return
*/
public Set<String> getUrs(ActivityExecution execution){
logger.debug("enter the CounterSignService ");
BpmRuPath BackPath();
if(backRuPath!=null && "YES".IsMultiple())){
String UrIds();
urIds.addAll(Arrays.asList(uIds.split("[,]")));
execution.tVariable("signUrIds_"+nodeId,uIds);
return urIds;
}
//2.通过变量来判断是否第⼀次进⼊该⽅法
String signUrIds=(Variable("signUrIds_"+nodeId);
if(StringUtils.isNotEmpty(signUrIds)){
String[]uIds=signUrIds.split("[,]");
母亲的回忆urIds.addAll(Arrays.asList(uIds));
return urIds;
}
//3.从界⾯中的提交变量取⽤户
IExecutionCmd ProcessCmd();
BpmDestNode NodeUrMap().get(nodeId);
if(bpmDestNode!=null && StringUtils.UrIds())){
//加⾄流程变量中,以使后续继续不需要从线程及数据库中获取
execution.tVariable("signUrIds_"+UrIds());
execution.tVariable("priority_"+Priority());
execution.tVariable("expiretime_"+nodeId, ExpireTime());
String[]UrIds().split("[,]");
urIds.addAll(Arrays.asList(uIds));
return urIds;
}
//4.从数据库中读取节点⼈员配置获得参与⼈员列表
Collection<IdentityInfo> idInfoList=bpmIdentityCalService.ProcessDefinitionId(), CurrentActivityId(),execution
for(IdentityInfo identityInfo:idInfoList){
if(IdentityInfo.IDENTIFY_TYPE_USER.IdentityType())){
urIds.IdentityInfoId());
}el{
List<OsUr> urs= IdentityInfoId(), OsRelType.REL_CAT_GROUP_USER_BELONG_ID);
for(OsUr u:urs){
urIds.UrId());
}
}
}
if(urIds.size()>0){
StringBuffer sb=new StringBuffer();
for(String uId:urIds){
sb.append(uId).append(",");
}
if(sb.length()>0){
sb.deleteCharAt(sb.length()-1);
}
execution.tVariable("signUrIds_"+String());
}el{
String name=(Activity().getProperty("name");
ProcessMessage ProcessMessage();
}
/**
* 会签是否计算完成
* @param execution
* @return
*/
public boolean isComplete(ActivityExecution execution){
//完成会签的次数
Integer completeCounter=(Variable("nrOfCompletedInstances");
//总循环次数
Integer instanceOfNumbers=(Variable("nrOfInstances");
String solId=(Variable("solId");
String Activity().getId();
UrTaskConfig TaskConfig(solId, nodeId);
/
/获得任务及其多实例的配置,则任务不进⾏任何投票的设置及处理,即需要所有投票完成后来才跳⾄下⼀步。
MultiTaskConfig()==null){
return completeCounter==instanceOfNumbers;
}
//获得会签的数据
List<BpmSignData> ProcessInstanceId(), nodeId); MultiTaskConfig MultiTaskConfig();
//通过票数
冷嘲热讽的反义词int passCount=0;
//反对票数
int refuCount=0;
//弃权票数
int abstainCount=0;
for(BpmSignData data:bpmSignDatas){
int calCount=1;
张靓颖妈妈//弃权不作票数统计
if(TaskOptionType.ABSTAIN.name().VoteStatus())){
abstainCount++;
continue;
}
String UrId();
/
/检查是否有特权的处理
VotePrivConfigs().size()>0){
//计算⽤户的⽤户组
List<OsGroup> BelongGroups(urId);
for(TaskVotePrivConfig VotePrivConfigs()){
//是否在特权⾥
boolean isInPriv=fal;
//为⽤户类型
if(TaskVotePrivConfig.USER.IdentityType())
&& IdentityIds().contains(urId)){
isInPriv=true;
}el{//为⽤户组类型
for(OsGroup osGroup:osGroups){
IdentityIds().GroupId())){
isInPriv=true;
break;
}
}
}
//若找到特权,则计算其值
if(isInPriv){
VoteNums();
/
/统计同意票数
if(TaskOptionType.AGREE.name().VoteStatus())){
passCount+=calCount;
}el{//统计反对票数
refuCount+=calCount;
}
}
logger.debug("==============================passCount:"+passCount
+" refuCount:" + refuCount +" abstainCount:"+abstainCount);
//是否可以跳出会签
boolean isNext=fal;
String result=null;
//按投票通过数进⾏计算
if(MultiTaskConfig.VOTE_TYPE_PASS.VoteResultType())){
//计算是否通过
//按投票数进⾏统计
if(MultiTaskConfig.CAL_TYPE_NUMS.CalType())){
//代表通过
if(passCount>=VoteValue()){
isNext=true;
result="PASS";
}
}el{//按百分⽐进⾏计算
int resultPercent=new Double(passCount*100/(passCount+refuCount+abstainCount)).intValue();
//代表通过
if(resultPercent>=VoteValue()){
isNext=true;
result="PASS";
}
}
}el{//按投票反对数进⾏计算
//计算是否通过
//按投票数进⾏统计
if(MultiTaskConfig.CAL_TYPE_NUMS.CalType())){
//代表通过
if(refuCount>=VoteValue()){
isNext=true;
result="REFUSE";
}
}el{//按百分⽐进⾏计算
int resultPercent=new Double(refuCount*100/(passCount+refuCount+abstainCount)).intValue();
//代表通过
if(resultPercent>=VoteValue()){
isNext=true;
result="REFUSE";
}
}
}
if((MultiTaskConfig.HANDLE_TYPE_DIRECT.HandleType())&& isNext)//直接处理
|| (MultiTaskConfig.HANDLE_TYPE_WAIT_TO.HandleType()) && completeCounter==instanceOfNumbers)){//等待所有的处理完 execution.tVariable("voteResult_"+nodeId, result);
//删除该节点的会签数据
for(BpmSignData data:bpmSignDatas){
bpmSignDataManager.deleteObject(data);
}
return true;
}