zoukankan      html  css  js  c++  java
  • SharePoint工作流解决方案QuickFlow系列(5)—会签(MultiTask and GroupTask)

    会签可能会有很多解释或定义,本文讲的会签是指在一个流程中的某一步操作有多个用户同时参与,这些用户的操作界面一般是一样的。

    QuickFlow的会签是通过MultiTask实现的,MultiTask实现了多个任务同时分配的逻辑,它具有以下控制属性:

    image

    1)ExecutionType--指定任务的分配是串行还是并行,如果是串行,则上一个用户完成任务后才会给下一个用户分配任务,如果是并行,则所有任务同时分配。

    2)CompletionMode--任务的完成模式,可以为RequireOne和RequireAll,如果RequireOne,则无论这一步分配了几个任务,只要一个用户完成,步骤即结束,未完成的任务会被自动取消,如果是RequireAll,并且没有指定CompleteRule,则要求所有用户都完成任务。

    3)CompleteRule--CompleteRule是一个Condition类型的属性,可以为CodeConditon或DeclareRuleConditon。当CompletionMode为RequireAll时,可以利用CompleteRule进一步控制审批步骤何时结束。我们经常碰到的如下的业务场景:当多个人参与审批,所有人都同意则到下一步,如果只要有一个用户不同意,则流程退回或结束,即使其他用户还没有审批。这种情况即可利用CompleteRule。

    下面看一个示例:

    流程很简单,第一步多人会签审批,如果有一人不同意则结束流程,如果所有人都同意则到经理审批。

    Step1)画出如下的流程图

    其中“开始”节点对应Start活动,“会签审批”对应MultiTask活动,“经理审批”对应Task活动,“结束”对应End活动。

    image

    注意:如果你已经画好了流程图中的线,然后改了活动的名字,可能需要将画好的线删掉重新画线,不然会出现活动找不到错误。

    Step2)处理“会签审批”

    指定会签审批的CompletionMode为RequireAll,ExecutionType为Parallel。

    将“会签审批”的TaskOutcomes属性绑定到工作流的字段:

    image

    处理“会签审批”的Initialized事件:

    private void 会签审批_Initialized(object sender, EventArgs e)
           {
               this.会签审批.Users.Add("dc\\user1");
               this.会签审批.Users.Add("dc\\user2");
               this.会签审批.Users.Add("dc\\user3");
               //如果是串行分配任务,这里的顺序就决定了任务分配的顺序
           }

    设置“会签审批”的CompleteRule:

    image 

    说明:只要有一个人的审批结果是Reject,则此条件为true。

    Step3)设置“会签审批”后的路由判断

    设置decision的Conditon为code conditon:

    private void allAgree(object sender, ConditionalEventArgs e)
           {
               e.Result = this.会签审批.TaskOutcomes.Filter("Reject") == 0; //没有reject的
           }

    Step4) 处理“经理审批”,设置其TaskCreating事件:

    private void managerTaskCreating(object sender, QuickFlow.TaskEventArgs e)
           {
               e.TaskProperties.AssignedTo = "dc\\manager";
           }

    完成!

     

    关于GroupTask

    每次使用MulitiTask时都要写代码指定审批人,这是一个不好的习惯,通常,审批人可以按照某些规则来获取,比如来自SharePoint组,来自AD组,来自第三方的角色管理系统,很显然我们应该将这些常用的用户获取逻辑做个封装。

    GroupTask继承于MultiTask,它的代码很简单,只是在MultiTask的Initialized事件中将用户从某个组中取出来添加到Users集合中,这样,如果我们要将任务分配给SharePoint用户组中的用户,直接用GroupTask,设置一下它的Group属性即可:

    //GroupTask获取用户的代码

    void GroupTask_Initialized(object sender, EventArgs e)
            {

                if (this.WorkflowProperties == null)
                    throw new Exception("WorkflowProperties is null , please bind it to correct field");

                SPRoleUserProvider up = new SPRoleUserProvider();

                IList<User> users = null;
                try
                {
                    if (this.DeptInherits)
                    {
                        User user = up.GetUser( this.WorkflowProperties.Web , this.WorkflowProperties.Originator);
                        users = up.GetRoleUsers( this.WorkflowProperties.Web, this.Group,user.Department );
                    }
                    else
                    {
                        users = up.GetRoleUsers(this.WorkflowProperties.Web, this.Group);
                    }
                }
                catch (Exception ex)
                {
                    ActivityUtil.Log(this, SPWorkflowHistoryEventType.WorkflowError, null, "获取组用户出错[" + this.Group + "]", ex.Message);
                    throw ex;
                }

                foreach (User u in users)
                {
                    this.Users.Add(u.LoginName);
                }
            }

    GroupTask有个DeptInherit属性,这个是来做什么的呢?

    假设有一步审批是“部门经理审批”,而这个公司是一个有多个部门的大公司,每个提交人发起的审批,都需要“他所在的部门的经理”进行审批,如何实现?
    一种方式是将部门经理作为用户的AD属性,在AD中进行维护,那么只要用Task活动,写代码从用户的AD属性中获取即可,这种方式的一个缺点是维护工作量太大了。

    还有个简单的方式:在网站建个部门经理的组,SharePoing中每个用户都有个“部门”属性,提交人和“本部门经理”的部门属性一定是一样的,那么用提交人的部门属性从部门经理组中进行一下过滤,即可取到“本部门经理”,当DeptInerit设置为true时,GroupTask即会进行这个操作。当然这个方法要求AD中用户的“部门”属性一定要维护正确,然后正确同步到UserProfile中(AD中维护后1小时)。

    这两种方法是不开发专门的“用户角色管理系统”的前提下的,如果您有完善的角色管理系统,可能实现的就更“优美”了。

     

    用过K2的朋友可以比较下,这个MultiTask和GroupTask跟K2的ClientEvent是很类似的。

     

    示例代码下载:

    https://files.cnblogs.com/jianyi0115/QuickFlowExample_%E4%BC%9A%E7%AD%BE.zip

    注意:此代码并没有经过测试,只能作为参考。

  • 相关阅读:
    STM32 硬件I2C 到底是不是个坑?
    memory cache 和 disk cache
    希尔排序为什么不稳定
    17-18专业课
    fread和fseek的用法
    浅析alsa声卡驱动snd_interval结构体openmin,openmax和integer含义
    动态存储区、静态存储区、堆和栈的区别
    【专家坐堂Q&A】在 petalinux-config 中选择外部来源时,可将符号链路添加内核来源目录树
    模型文件后缀介绍
    @RestController注解
  • 原文地址:https://www.cnblogs.com/jianyi0115/p/1562132.html
Copyright © 2011-2022 走看看