会签可能会有很多解释或定义,本文讲的会签是指在一个流程中的某一步操作有多个用户同时参与,这些用户的操作界面一般是一样的。
QuickFlow的会签是通过MultiTask实现的,MultiTask实现了多个任务同时分配的逻辑,它具有以下控制属性:
1)ExecutionType--指定任务的分配是串行还是并行,如果是串行,则上一个用户完成任务后才会给下一个用户分配任务,如果是并行,则所有任务同时分配。
2)CompletionMode--任务的完成模式,可以为RequireOne和RequireAll,如果RequireOne,则无论这一步分配了几个任务,只要一个用户完成,步骤即结束,未完成的任务会被自动取消,如果是RequireAll,并且没有指定CompleteRule,则要求所有用户都完成任务。
3)CompleteRule--CompleteRule是一个Condition类型的属性,可以为CodeConditon或DeclareRuleConditon。当CompletionMode为RequireAll时,可以利用CompleteRule进一步控制审批步骤何时结束。我们经常碰到的如下的业务场景:当多个人参与审批,所有人都同意则到下一步,如果只要有一个用户不同意,则流程退回或结束,即使其他用户还没有审批。这种情况即可利用CompleteRule。
下面看一个示例:
流程很简单,第一步多人会签审批,如果有一人不同意则结束流程,如果所有人都同意则到经理审批。
Step1)画出如下的流程图
其中“开始”节点对应Start活动,“会签审批”对应MultiTask活动,“经理审批”对应Task活动,“结束”对应End活动。
注意:如果你已经画好了流程图中的线,然后改了活动的名字,可能需要将画好的线删掉重新画线,不然会出现活动找不到错误。
Step2)处理“会签审批”
指定会签审批的CompletionMode为RequireAll,ExecutionType为Parallel。
将“会签审批”的TaskOutcomes属性绑定到工作流的字段:
处理“会签审批”的Initialized事件:
private void 会签审批_Initialized(object sender, EventArgs e)
{
this.会签审批.Users.Add("dc\\user1");
this.会签审批.Users.Add("dc\\user2");
this.会签审批.Users.Add("dc\\user3");
//如果是串行分配任务,这里的顺序就决定了任务分配的顺序
}
设置“会签审批”的CompleteRule:
说明:只要有一个人的审批结果是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
注意:此代码并没有经过测试,只能作为参考。