• 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. }  
  • 相关阅读:
    错误 1 类,结构或接口成员声明中的标记"="无效
    转asp.net中的App_GlobalResources和App_LocalResources使用
    input type=file 上传文件样式美化(转载)
    Postman Post请求上传文件
    vuex 、store、state (转载)
    ES5、ES2015、ECMAScript6(转载)
    axios 用法简介(转载)
    js中const,var,let区别(转载)
    C#开发微信公众平台-就这么简单(附Demo)转载
    什么是 Native、Web App、Hybrid、React Native 和 Weex?(转载)
  • 原文地址:https://www.cnblogs.com/bluejoe/p/5115944.html
Copyright © 2020-2023  润新知