个人微型工做流引擎-功能解析及API设计

1、前言

     上一篇我给你们介绍了个人工做流的模型和基本的设计,这篇我想详细说明下我这款工做流的功能及使用示例。这款工做流主要是面向开发者设计的,为了先让你们有个全局的认识,局部功能的设计实现就不细说了,后续有时间我会继续写文章向你们介绍。web

2、功能详解及使用示例代码

     一、配置流程引擎,通常在程序启动过程当中调用(Global.asax.cs中)数据库

//初始化流程引擎
BpmConfiguration
    .Instance()
    .Config(@"C:\Configration\BpmConfig.xml")
    .Start();

若是不指定配置文件,则默认从app.config或web.config中读取流程配置app

//初始化流程引擎
BpmConfiguration
    .Instance()
    .Start();

固然还支持同时启动多个流程引擎,以提供SAAS程序的支持。测试

//A租户引擎配置
BpmConfiguration
    .Instance("TenantA")
    .Config(@"C:\BpmConfigA.xml") 
    .Start();

//B租户引擎配置
BpmConfiguration
    .Instance("TenantB")
    .Config(@"C:\BpmConfigB.xml")
    .Start();

XML中的配置包括:数据库链接、日志配置文件、任务计划启动延时、任务计划执行周期、用户关系结构的映射、流程中变量类型的拓展等。 

    二、取得工做流上下文,即工做流的入口,全部的功能都集中在这个入口上。 spa

var bpm = new BpmContext()
    .UseTransaction(true)
    .SetActor("萧秦");

当前对于不一样的引擎实例,其上下文是不一样的设计

var bpm = new BpmContext("TenantA");
var bpm = new BpmContext("TenantB");

不传构造参数时,返回的是默认实例。
 
    三、事务支持,是否开启事务、提交、回滚。 日志

bpm.UseTransaction(true);
bpm.Commit();
bpm.Rollback();


    四、流程定义 code

//新增流程定义
bpm.NewProcessDefinition("请假流程")
    .SetXmlFile(@"C:\Definition\demo1.xml")
    .SetCategory("分类1")
    .SetEffectDate(DateTime.Now)
    .SetExpireDate(DateTime.Now.AddDays(180))
    .SetMemo("memo1")
    .Create()   //建立流程定义
    .Parse()    //解析xml

流程建立时,版本号是自动生成的,默认从1.0开始,当流程名称相同时,就会生成不一样版本。
在xml中可定义不一样的任务节点:开始节点、自动节点、人工节点、决策节点、发散节点、聚合节点、子流程节点、会签节点、等待节点、结束节点。
及链接任务节点的路由、人员分配状况、变量定义、事件动做等信息,可参照我上篇文章中的xml定义xml

//加载流程定义
var processDefinition = bpm.LoadProcessDefiniton("1");
processDefinition.Deploy();     //发布流程定义
processDefinition.Revoke();     //召回流程定义
processDefinition.Delete();     //删除流程定义


    五、流程实例 对象

//发起流程实例
var process = bpm.NewProcessIntance("请假流程","萧秦");
process.SetVariable("project_id", 1399); //保存流程变量
process.Start();   //启动 
process.Suspend(); //挂起
process.Resume();  //恢复
process.Cancel();  //撤销
process.End();     //结束

这里NewProcessInstance这个方法实例上有三个参数,第一个是流程定义ID,第二个是启动的业务ID,第三个是子流程的返回栈点ID,非子流程能够忽略。

//启动流程
var startTask = process.Start();
startTask.SetRecord("SO20150903001");       //保存表单数据(关联)
startTask.SetAttach("01", "02");            //保存附件信息(关联),可多个
startTask.SetVariable("var1", "value1");    //保存任务变量
startTask.Signal();                         //转交下一步

task.SetRecord用于保存当前表单数据id,数据自己保存在业务表中
task.SetAttach用于保存当前节点的附件id,附件信息则保存在附件管理表中
task.Signal流程流转的关键方法,根据流程定义触发token令牌离开动做

//审批任务
var task = bpm.LoadTaskInstance("00");
task.SetOpinion(SignResult.Passed, "我赞成");  //设置审批意见
task.SetReceiver("颜经理");                    //设置下一步的审批人
task.Signal();                                //转交下一步

这里提供了SetReceiver的方法设置下一步的审批人,正常状况下流程定义中已经定义好了,是不须要再进行设置的,可是考虑在实际应用中可能会有把任务给指定领导审批的状况,在通达OA中也是能够设置下一步审批人,故添加了此方法,须要时能够调用,注意应用此方法会覆盖定义中对工做项owner属性的设置。

//任务委派
var task1 = bpm.LoadTaskInstance("01");
task1.AssignCandidate("小郑,小胡");              //添加任务候选人
task1.AssignCandidate("saler", ActorType.Role); //添加任务候选人
task1.AssignTo("李四");                         //把任务分配给李四

个人工做流中,对于工做任务只能有一个全部者(owner),一个实际操做者(actor),但能够拥有多个候选人(candidate)。
候选人是当前工做可分配的一范围限制或人员列表,owner是任务的拥有者,actor是owner考虑复杂委办关系后计算出的操做者。
task.AssignCandidate这个方法用于添加任务候选人,第二个参数是对象类型,能够直接添加一个角色、机构、用户组等。
task.AssignTo即分配任务,任务的分配状态包括如下几个状态

public enum AssignStatus
{
    //未决
    Pending,

    //认领, 用户认领任务并接收任务输入数据
    Claim,

    //委办, 委派给另外一我的(例如,经理)以代替他或她执行任务
    Depute,

    //到期, 没有在指定的时间段内处理批准任务
    Expire,

    //续订, 没有在给定的时间范围内处理此任务,则该任务将被续订,以便在另外一时间段内执行
    Renew
}

若是流程卡到某个节点好久,咱们能够发催办消息
若是一个流程节点的确须要好久才能完成,我设计了一个当前工做进度汇报接口

//工做催办
task.Urge("很急,请经理尽快处理,在线等!");

//汇报当前工做进度
task.Report(0.6, "预计这个星期就能完成");

task.Urge会向任务实际拥有者发送一条催办通知,并生成催办历史。
task.Report会向任务的订阅者(全部关注当前流程任务的人)发送一条进度报告。

//查询变量
var var0 = process.GetVariable("project_id");
var var1 = task1.GetVariable("var1");
var var2 = task1.GetVariable<DateTime>("var2");
var var3 = task1.GetVariableObject("var3");

变量分为三种:
流程变量 会持久化,存在于整个的流程周期内
任务变量 会持久化,存在在当前的任务中
临时变量 不会持久化到数据库中,只存在于当前执行上下文中(executionContext)。
设置变量SetVariable 获取变量GetVariable
支持任意数据类型

    六、中国特点审批方式,主要包括会签、加签(前加签、后加签、并加签)、减签、自由流
会签:一个任务由多我的参与共同作决策
加签:这个任务我本身以为没有把握,想加入一我的或多我的跟我共同决策(在前加签顺序在当前决策者以前,后加签顺序在当前决策者以后,并加签不分顺序并行处理)
减签:跟加签相反,取消某人参与决策的资格
自由流:流程定义中没有,临时添加的动态路由直接把当前工做发送到指定的节点审批。
转会签:由单人决策的普通审批节点转成多人共同决策的会签节点,支持递归会签,即会签子节点能够继续转会签节点 。
转审批:由多人共同决策的会签节点转成单人决策的普通审批节点

在我在工做流中,会签设计了如下几个参数:
a 运行模式,并行时如发散节点,进入会签节点时会同时激活全部参与人的工做任务,串行时则有前后顺序,因此才有了前加签和后加签

public enum RunMode
{
    //串行
    Serial,

    //并行
    Parallel
}

b 决策模式,根据子节点的结果如何去决策会签节点

public enum DecisionMode
{
    //主办人模式
    Sponsor, 
    
    //投票模式
    Vote, 
    
    //一票经过
    OnePass, 
    
    //一票否决
    OneVeto
}

主办人模式:须要设置一个主办人,结果以主办人的决策为准,其它人的决策只是提供参考
投票模式:即设置一个经过的比例,由你们投票决定。支持设置每一个人的投票权重。
一票经过:其实能够看做是投票模式经过率设置大于0%的一种。
一票否决:能够看做投票模式经过率设置100%的一种。
固然这里只是我把经常使用的几种模式列出来了,还能够本身拓展决策模式,只须要继承实现我定义的抽象类Decision便可。

c 是否等待,即还有人未表决,但目前已表决的状况已经能够肯定会签结果的状况下,需不须要等待其它人表决完成后才继续转交下一步。

会签分两种,一种是流程定义中定义好的会签,一种是普通审批节点临时转成会签的。实际上中国式审批其实就是要灵活,若是在流程定义中定义好的,其实能够不用会签节点,用多个普通节点也能够去实现。会签节点的设计主要是为了转会签这个场景:就是当前普通审批节点的审批人以为本身没有把握或者不想担责任,能够加入上级领导或其它更多的人一块儿来决策或提供参考意见。

示例:普通审批转会签 运行模式设置为并行,决策模式是权重投票,须要等待全部人都投票,经过线为65%

//转会签
var task2 = bpm.LoadTaskInstance("02"); 
task2.ToCountersign(RunMode.Parallel, DecisionMode.Vote, true, 0.65M);
task2.CountersignAdd(new Countersigner() { actor_id = "张三", vote_weight = 1 });
task2.CountersignAdd(new Countersigner() { actor_id = "李四", vote_weight = 0.5 });
task2.CountersignAdd(new Countersigner() { actor_id = "小五", vote_weight = 2 });

并行模式即为并加签,前加签、后加签的前提是串行模式,假设task2为串行、主办人模式、原审批人为萧秦

//前加签
task2.CountersignAddBefore("萧秦", new Countersigner() { actor_id = "张三"});

//后加签
task2.CountersignAddAfter("萧秦", new Countersigner() { actor_id = "李四", is_sponsor = true});

减签则相对比较简单了

//减签
task2.CountersignRemove("王");

会签节点转普通审批,直接让一我的决策

//转审批
 task2.ToSinglesign("隔壁老王");

自由流模式,建立临时路直接跳转到指定节点进行审批

//自由流
var task3 = bpm.LoadTaskInstance("03");
task3.SetFreeRedirect("总经理审批");
task3.Signal();


    七、回退机制
流程回退到指定节点

//流程实例指定任意节点回退
var process2 = bpm.LoadProcessInstance("02");
process2.Rollback("填写请假单");

任务实例回退到上一步

//当前工做任务回退到上一个审批节点
var task4 = bpm.LoadTaskInstance("04");
task4.Rollback();


    八、工做委办
张三把某个任务直接委托给李四办理,支持递归委办关系,即张三委托给李四,李四再委托给王五,王五在委托给赵六…

bpm.NewDeputeService("张三", "李四")
   .ForTaskInstance("任务实例ID")
   .Depute();

把整个流程实例委托给李四,即此流程实例下全部的张三的任务都会委托给李四

bpm.NewDeputeService("张三", "李四")
   .ForProcessInstance("流程实例ID")
   .Depute();

把某个流程定义中的一个任务节点委托给李四,即全部的这个节点建立的全部任务实例若是是张三的任务都会委托给李四

bpm.NewDeputeService("张三", "李四")
   .ForTaskDefinition("任务定义ID")
   .Depute();

把某个流程定义委托给李四,即这个流程中建立的全部的任务实例,若是是张三的任务,在设置的生效期间中都会委托给李四

bpm.NewDeputeService("张三", "李四")
   .ForProcessDefinition("流程定义ID")
   .SetDateRange(DateTime.Now, DateTime.Now.AddDays(30)) //生效期间
   .SetMemo("这个月出差,这个流程都委托给李四代办")            //委托说明
   .Depute();

收回委托关系,只要将Revoke替换Depute动做便可

//收回委办工做
bpm.NewDeputeService("张三", "李四")
   .ForProcessInstance("流程实例ID")
   .Revoke();


    九、关注订阅
这个功能跟委托类似,订阅后会收到流程动态或任务动态消息提醒,如:流程已建立、启动、挂起…,任务已建立、分配给谁、进度汇报、任务完成等等

//关注订阅
bpm.NewSubscribeService("张三")
   .ForTaskInstance("任务实例ID")
   .Subscribe();

bpm.NewSubscribeService("张三")
   .ForProcessInstance("流程实例ID")
   .Subscribe();

bpm.NewSubscribeService("张三")
   .ForProcessDefinition("流程定义ID")
   .Subscribe();

bpm.NewSubscribeService("张三","李四","王五")
   .ForTaskDefinition("任务定义ID")
   .Subscribe();

取消订阅,同样只须要把Subscribe改成Unsubscribe便可

//取消订阅
bpm.NewSubscribeService("李四")
   .ForProcessDefinition("采购流程")
   .Unsubscribe();


    十、数据查询
查询我没有提供接口,直接开放数据库查询比我提供的接口会更加灵活,好比:
a 查询已发布的流程定义

select * from bpm_definition_process where state = 'Deploy'

流程定义状态包括

public enum ProcessDefinitionState
{
    //建立
    Create,

    //解析
    Parse,

    //发布
    Deploy,

    //回收
    Revoke,

    //删除
    Delete
}

b 个人流程

select * from bpm_instance_process where state = 'Run' and starter = '萧秦'

流程状态包括

public enum ProcessState
{
    //建立
    Create,

    //运行
    Run,

    //挂起
    Pending,

    //终止
    Termination,

    //完成
    Complete,

    //取消
    Cancel
}

c 个人待办任务

select * from bpm_instance_task where state = 'Run' and actor_id = '萧秦'

待办任务包括了别人委托给你的任务,若是只想看属于本身的任务则能够

select * from bpm_instance_task where state = 'Run' and owner_id = '萧秦'

任务状态包括

public enum TaskState
{
    //建立, 任务已被建立
    Create,

    //阻塞, 到达线中有阻塞任务还未完成
    Blocking,

    //启动
    Run,
   
    //完成, 用户已经完成任务并提供了任务的输出数据
    Complete,

    //失败, 用户已经完成任务, 而且提供了错误消息
    Failure,

    //回退
    Rollback
}

d 查询任务的候选人信息

select * from bpm_instance_assignment where task_instance_id = 'ID'

e 查询个人消息

select * from bpm_application_notify where state='Unread' and reciever_id = '萧秦'

其它查询就再也不举例了
 

3、总结

     以前我有说过我开发这个的引擎的目的是为了在作项目时,有一个体积轻巧,引入方便的单dll文件(发布后大小为1.1M)的工做流引擎,接口也简单易于二次开发,支持多数据库而且功能还算强大。从前年开始的简易版本设计开发到如今基本成形,测试也是花费了大量的时间,可能还有问题没有测到,不过如今基本稳定。接下来若是有时间我会慢慢跟你们介绍功能细节的设计和实现,还有什么功能我考虑不周全的或意见或有哪部分想详细了解的均可以给我留言。联系13606021792

相关文章
相关标签/搜索