会签任务是工作流里一个比较觉见的任务方式,意思是一个处理任务需要多个人同时处理,然后汇总多个人的意见,决定流程下一步该如何执行。在JBPM4里,并没有会签这个概念,其只有并行任务的处理方式,如下所示:
这种方式会签的任务数量是固定的,并且任务名称也不一样,不能由用户来动态决定有多少人参与会签的任务。当然我们可以让中间那部分只有一个节点,然后根据用户在后台设置了多少人参与或在流程运行过程中,动态知道有多少人参与这个任务,动态创建并发的任务(不过这样实现上有一点困难,需要扩展jbpm的api相对多一些)
而另一种相对比较完善的解决方案是可以用一个任务来代表会签任务,而在流程运行至该任务节点的时候,根据当前有多少人参与这流程,动态生成该任务下的会签子任务,这样可以使得每个会签的参与人都可以在待办事项中看到该任务。这种办法实现上相对容易得多,因为jbpm4本身对子任务的动态创建支持得比较好。
joffice2就是基于这种方式来解决会签的配置及处理。那么,如何汇总会签任务的投票意见呢?我们知道,日常的会签常见的方式有:一票否决,一票通过,全票通过,半数通过等。其实现无非是分为两种,按投票数的绝对票数,另一种是按投票占的百份比数,投票决策又分为两种:通过或拒绝(反对),投票过程中会有通过,反对或弃权的动作。因此,在后台上我们设置某个节点若为会签时,其会签的投票决策方式信息包括如下:
并且我们希望在执行会签任务的时候,会签的参与人员均可以填写意见及选择投票的类型(如同意,反对,弃权),如:
那么投票的情况如何处理,以下为投票的决策处理方式:
为什么要在后面加上流程变量decisionType呢,这里就是为了下一任务可以根据上一任务的会签结果来决定如何往下执行的,我们可以在后续的任务或条件结点中,通过这个变量的值,来决定其如何往下执行。若该变量的值为“pass"表示上一步会签的结果是同意,否则为反对。
如我们有一流程:
那么在分支节点上,我们插入我们需要流程执行的分支决定代码,并且根据这个分支决定代码决定往下一步时执行的路径。于是我们在分支上加上干预的代码如下所示:
根据上面的逻辑判断,我们把完成会签任务的代码展示部分如下:
- /**
- * 完成会签子任务
- * @param parentTask 父任务
- * @param subTask 子任务
- * @param variables 任务中的流程变量
- */
- private void completeSignSubTask(TaskImpl parentTask,TaskImpl subTask,String signalName,Map variables){
- //看目前还有多少子任务
- int subTasksSize=parentTask.getSubTasks().size();
- //检查会签的配置情况
- ProcessInstance pi=((TaskImpl)parentTask).getProcessInstance();
- ProcessDefinition pd=repositoryService.createProcessDefinitionQuery().processDefinitionId(pi.getProcessDefinitionId()).uniqueResult();
- //取得该任务的后台人员配置
- ProUserAssign assignSetting=proUserAssignService.getByDeployIdActivityName(pd.getDeploymentId(), parentTask.getActivityName());
- evict(subTask);
- evict(parentTask);
- if(assignSetting!=null){
- //取得会签配置
- TaskSign taskSign=taskSignService.findByAssignId(assignSetting.getAssignId());
- if(taskSign!=null){//按照配置执行任务跳转
- //是否完成父任务
- boolean isFinishSupTask=false;
- //查看用户投的是哪一种票(同意还是不同意还是弃权)
- Short isAgree=(Short)variables.get(FlowConstants.SIGN_VOTE_TYPE);
- if(isAgree==null){//若为空,则认为是投通过票
- isAgree=TaskSign.DECIDE_TYPE_PASS;
- }
- //1.保存投票信息
- taskSignDataService.addVote(parentTask.getId(),isAgree);
- //加上子任务的流程变量
- taskService.setVariables(subTask.getId(),variables);
- //2.完成子任务
- taskService.completeTask(subTask.getId());
- //3.检查其投票数是否已满足后台会签配置条件
- //3.1根据后台配置的投票类型,取得投票的总数
- Long voteCounts=taskSignDataService.getVoteCounts(parentTask.getId(),taskSign.getDecideType());
- if(taskSign.getVoteCounts()!=null){//按绝对投票数来进行
- if(voteCounts>=taskSign.getVoteCounts()){
- isFinishSupTask=true;
- }
- }else if(taskSign.getVotePercents()!=null){//按投票百分比来进行
- //取到动态有多少子任务
- Integer taskSignCounts=(Integer)taskService.getVariable(parentTask.getId(), "taskSignCounts");
- if(taskSignCounts==null || taskSignCounts==0){
- taskSignCounts=1;
- }
- BigDecimal totalSubTasks=new BigDecimal(taskSignCounts);
- //当前投票后占的百分比
- BigDecimal tempPercent=new BigDecimal(voteCounts).divide(totalSubTasks);
- Integer curPercent=new Integer(tempPercent.multiply(new BigDecimal(100)).intValue());
- if(curPercent>=taskSign.getVotePercents()){
- isFinishSupTask=true;
- }
- }
- //若投票完成后,把投票结果存在decisionType变量里,方便在后台通过脚本根据投票的结果进行跳转
- Map varsMap=new HashMap();
- //当前会签子任务完成后,若投票的情况已经满足后台的会签设置条件
- //或没有满足会签设置的情况,并且会签所有子任务均已经完成
- if(isFinishSupTask || (!isFinishSupTask && subTasksSize==1) ){
- String passRefuse=null;
- if(isFinishSupTask){//所有子任务完成,满足会签条件设置
- passRefuse=TaskSign.DECIDE_TYPE_PASS==taskSign.getDecideType()?"pass":"refuse";
- }else{//所有子任务完成,不满足会签条件设置
- passRefuse=taskSign.getDecideType()==TaskSign.DECIDE_TYPE_PASS?"refuse":"pass";
- }
- logger.debug("会签投票结果:"+ passRefuse);
- varsMap.put("decisionType",passRefuse);
- taskService.setVariables(parentTask.getId(),varsMap);
- //完成父任务
- taskService.completeTask(parentTask.getId(),signalName);
- }
- }else{//没有设置对应的会签配置,则认为会签是全部完成后才能往下执行
- logger.error("Task "+parentTask.getActivityName()+" is not config right sign config in process admin console.");
- if(((TaskImpl)parentTask).getSubTasks().size()==1){//若只有当前子任务,则表示可以结束目前这个任务
- taskService.setVariables(subTask.getId(),variables);
- //完成子任务
- taskService.completeTask(subTask.getId());
- //完成父任务
- taskService.completeTask(parentTask.getId(),signalName);
- }else{
- taskService.setVariables(subTask.getId(), variables);
- //完成子任务后,直接返回则可
- taskService.completeTask(subTask.getId());
- return ;
- }
- }
- }else{
- //TODO
- logger.error("Task "+parentTask.getActivityName()+"is not config the setting in process admin console.");
- }
- }
/** * 完成会签子任务 * @param parentTask 父任务 * @param subTask 子任务 * @param variables 任务中的流程变量 */ private void completeSignSubTask(TaskImpl parentTask,TaskImpl subTask,String signalName,Map variables){ //看目前还有多少子任务 int subTasksSize=parentTask.getSubTasks().size(); //检查会签的配置情况 ProcessInstance pi=((TaskImpl)parentTask).getProcessInstance(); ProcessDefinition pd=repositoryService.createProcessDefinitionQuery().processDefinitionId(pi.getProcessDefinitionId()).uniqueResult(); //取得该任务的后台人员配置 ProUserAssign assignSetting=proUserAssignService.getByDeployIdActivityName(pd.getDeploymentId(), parentTask.getActivityName()); evict(subTask); evict(parentTask); if(assignSetting!=null){ //取得会签配置 TaskSign taskSign=taskSignService.findByAssignId(assignSetting.getAssignId()); if(taskSign!=null){//按照配置执行任务跳转 //是否完成父任务 boolean isFinishSupTask=false; //查看用户投的是哪一种票(同意还是不同意还是弃权) Short isAgree=(Short)variables.get(FlowConstants.SIGN_VOTE_TYPE); if(isAgree==null){//若为空,则认为是投通过票 isAgree=TaskSign.DECIDE_TYPE_PASS; } //1.保存投票信息 taskSignDataService.addVote(parentTask.getId(),isAgree); //加上子任务的流程变量 taskService.setVariables(subTask.getId(),variables); //2.完成子任务 taskService.completeTask(subTask.getId()); //3.检查其投票数是否已满足后台会签配置条件 //3.1根据后台配置的投票类型,取得投票的总数 Long voteCounts=taskSignDataService.getVoteCounts(parentTask.getId(),taskSign.getDecideType()); if(taskSign.getVoteCounts()!=null){//按绝对投票数来进行 if(voteCounts>=taskSign.getVoteCounts()){ isFinishSupTask=true; } }else if(taskSign.getVotePercents()!=null){//按投票百分比来进行 //取到动态有多少子任务 Integer taskSignCounts=(Integer)taskService.getVariable(parentTask.getId(), "taskSignCounts"); if(taskSignCounts==null || taskSignCounts==0){ taskSignCounts=1; } BigDecimal totalSubTasks=new BigDecimal(taskSignCounts); //当前投票后占的百分比 BigDecimal tempPercent=new BigDecimal(voteCounts).divide(totalSubTasks); Integer curPercent=new Integer(tempPercent.multiply(new BigDecimal(100)).intValue()); if(curPercent>=taskSign.getVotePercents()){ isFinishSupTask=true; } } //若投票完成后,把投票结果存在decisionType变量里,方便在后台通过脚本根据投票的结果进行跳转 Map varsMap=new HashMap(); //当前会签子任务完成后,若投票的情况已经满足后台的会签设置条件 //或没有满足会签设置的情况,并且会签所有子任务均已经完成 if(isFinishSupTask || (!isFinishSupTask && subTasksSize==1) ){ String passRefuse=null; if(isFinishSupTask){//所有子任务完成,满足会签条件设置 passRefuse=TaskSign.DECIDE_TYPE_PASS==taskSign.getDecideType()?"pass":"refuse"; }else{//所有子任务完成,不满足会签条件设置 passRefuse=taskSign.getDecideType()==TaskSign.DECIDE_TYPE_PASS?"refuse":"pass"; } logger.debug("会签投票结果:"+ passRefuse); varsMap.put("decisionType",passRefuse); taskService.setVariables(parentTask.getId(),varsMap); //完成父任务 taskService.completeTask(parentTask.getId(),signalName); } }else{//没有设置对应的会签配置,则认为会签是全部完成后才能往下执行 logger.error("Task "+parentTask.getActivityName()+" is not config right sign config in process admin console."); if(((TaskImpl)parentTask).getSubTasks().size()==1){//若只有当前子任务,则表示可以结束目前这个任务 taskService.setVariables(subTask.getId(),variables); //完成子任务 taskService.completeTask(subTask.getId()); //完成父任务 taskService.completeTask(parentTask.getId(),signalName); }else{ taskService.setVariables(subTask.getId(), variables); //完成子任务后,直接返回则可 taskService.completeTask(subTask.getId()); return ; } } }else{ //TODO logger.error("Task "+parentTask.getActivityName()+"is not config the setting in process admin console."); } }
产生会签的任务代码如下:
- /**
- * 创建新的任务
- * @param parentTaskId 父任务 ID
- * @param assignIds 任务执行人IDs
- */
- public void newSubTask(String parentTaskId,Long[]userIds){
- TaskServiceImpl taskServiceImpl=(TaskServiceImpl) taskService;
- Task parentTask=taskServiceImpl.getTask(parentTaskId);
- //为该父任务加上会签的人员数,方便后面对会签的投票进行统计
- Map vars=new HashMap();
- vars.put("taskSignCounts", new Integer(userIds.length));
- taskServiceImpl.setVariables(parentTaskId, vars);
- for(int i=0;i<userIds.length;i++){
- String userId=userIds[i].toString();
- TaskImpl task=(TaskImpl)taskServiceImpl.newTask(parentTaskId);
- task.setAssignee(userId);
- task.setName(parentTask.getName() + "-" + (i+1));
- task.setActivityName(parentTask.getName() );
- task.setDescription(parentTask.getDescription());
- //保存
- taskServiceImpl.saveTask(task);
- }
- }
/** * 创建新的任务 * @param parentTaskId 父任务 ID * @param assignIds 任务执行人IDs */ public void newSubTask(String parentTaskId,Long[]userIds){ TaskServiceImpl taskServiceImpl=(TaskServiceImpl) taskService; Task parentTask=taskServiceImpl.getTask(parentTaskId); //为该父任务加上会签的人员数,方便后面对会签的投票进行统计 Map vars=new HashMap(); vars.put("taskSignCounts", new Integer(userIds.length)); taskServiceImpl.setVariables(parentTaskId, vars); for(int i=0;i<userIds.length;i++){ String userId=userIds[i].toString(); TaskImpl task=(TaskImpl)taskServiceImpl.newTask(parentTaskId); task.setAssignee(userId); task.setName(parentTask.getName() + "-" + (i+1)); task.setActivityName(parentTask.getName() ); task.setDescription(parentTask.getDescription()); //保存 taskServiceImpl.saveTask(task); } }
其最终的实现效果如下flash演示。
http://bbs.jee-soft.cn/swf/signTask.html
或
http://bbs.jee-soft.cn/posts/list/288.page
发表评论
-
基于开源流程引擎Activiti5的工作流开发平台 BPMX3
2012-07-26 14:35 4182BPMX3平台是宏天软件在ESTBPM2的基础上,追随开源工作 ... -
Activiti 工作流会签开发设计思路
2012-07-26 14:32 3306Activiti 工作流会签开发设计思路 在流程业务管 ... -
J.Office中的公文签名及签章
2011-08-12 13:58 1718政府的很多系统都有涉及到电子签名及签章的管理功能,在jof ... -
JOffice2中WebService的使用(CXF)
2011-08-12 13:54 15651. WebService基本概念 WSDL: ... -
JOffice2 发布了开源的开发者体验版本
2011-08-12 13:48 1118JOffice的爱好者有福音了,经公司决定,现在 ... -
JBPM4的子流程与父流程的设计及开发
2011-07-14 12:02 1430【JBPM4的子流程与父流 ... -
Jbpm4中的会签设计及实现
2011-05-12 14:44 1763jbpm4.4提供了三种比较方便的分支跳转方式,如下所示: ...
相关推荐
工作流基础之JBPM 工作流(Workflow)是企业中业务流程自动化的一种方式,它将复杂的业务流程转化为计算机可执行的逻辑,以便更好地管理和协调各参与者的任务和信息交互。工作流管理系统(WfMS)是实现这一目标的...
### 基于JBPM工作流的CRM系统的设计与实现 #### 一、引言 在当前快速发展的信息化社会中,客户关系管理(CRM)系统已成为企业提高竞争力、提升服务质量的重要工具之一。随着业务流程日益复杂,传统的CRM系统难以...
### 基于jbpm与activiti的工作流平台技术架构介绍 #### 一、宏天BPM X3软件平台概述 宏天BPM X3软件平台是一款基于J2EE技术的开源、轻量级的企业业务开发平台。该平台旨在帮助用户以最快的速度梳理、设计、执行、...
3. **灵活的工作流引擎**:内嵌的JBPM4.4工作流引擎,支持所有业务流程的开发与二次定制,实现动态修改和创建复杂流程,无需编码即可可视化设置流程参数,自动生成自定义流程。 4. **跨平台部署与易用性**:EST-BPM...
本设计文档旨在详细介绍OA办公系统中的工作流模块设计思路及实现方法。该系统利用JBPM4引擎支持流程设计、表单创建及其与流程间的关联等功能,从而实现企业内部办公自动化的需求。本文档将重点介绍流程设计的目标、...
工作流引擎平台选型基本功能 北京慧正 广州宏天 广州天翎 方正飞鸿 炎黄盈动
宏天BPMX3.3业务流程管理平台是一款强大的企业级解决方案,通过其丰富的功能模块和灵活的配置选项,可以帮助企业实现高效的业务流程管理和日常办公自动化。无论是对于IT管理员还是普通业务用户来说,熟练掌握本平台...
本文档为开发者提供了快速入门指南,帮助他们在广州宏天软件有限公司开发的OA系统中实现工作流的简单开发。文档涵盖了基本的操作步骤和技术细节,以便开发者能够快速上手并实现所需功能。 #### 四、流程设计 #####...
- 进一步推出了BPMX 5,对原有产品进行了多项优化,如轻量级工作流平台的构建、组织架构的简化、流程服务化的简化等。 - **新产品研发**:近年来,宏天软件还研发了SaaS+BPM、BPM+SAP组件产品以及集成BPM、ESB、...
工作流设计的主要目标是利用OA系统内置的JBPM4引擎,构建灵活的流程,实现流程的动态跳转、自定义表单设计,并确保表单与流程的紧密关联。这一设计适用于广州宏天软件有限公司开发的OA办公系统,旨在简化流程开发,...
4.1、根据条码及后台配置,实现扫描、本地加载过程中的自动分单。 4.2、提供自动分单后的手工调整:手工分单、调整单证类型、鼠标拖拽、修改单证印刷号、拷贝剪切粘贴等多种方式。 5、支持采集过程中自动获取签名...
概要设计说明书是软件开发过程中的一个关键文档,它在项目的需求分析之后,详细设计之前编写,旨在概述系统的结构、组件、接口以及与其他系统的交互等。 从给出的部分内容中,我们可以提炼出以下知识点: 1. 系统...
4. 业务板块分析:针对不同业务部门,报告会分别阐述它们的业绩、市场份额、新项目进展及未来发展规划,帮助读者理解各业务单元的表现。 5. 市场环境与竞争态势:报告可能会分析所在行业的市场环境,包括市场规模、...
宏天是一家国内领先的政府协同办公OA应用平台解决方案供应商,同时也是知名的JBPM、Activiti工作流引擎应用开发服务商。公司致力于为政府机构、电力、通信、软件等行业提供高质量的信息化解决方案。宏天的服务范围...
本文档将深入探讨宏天 BPMX3 业务流程平台中基于开源 Activiti 工作流引擎的相关知识。 1.1 流程术语 1.1.1 流程定义 流程定义是描述业务过程的规范性文档,它由一系列活动和转移构成,遵循特定的语法规范。...
综上所述,宏天J.Office协同办公系统V1.3提供了全面的办公功能,覆盖了日常工作中的各个层面,从个人任务管理到团队协作,再到公司级别的公文处理和信息管理,构建了一个高效、有序的办公环境。
宏天信业:2021年半年度报告.PDF