EasyUIYbSoftwareFactory 代码生成插件【十六】:Web 下灵活、强大的审查批准流程达成(含流程序控制制组件、流程设计器和表单设计器)

   
程序=数据结构+算法,而商户级的软件=数据+流程,流程往往千差万别,客户自身有时都搞不清楚,随时变动的情景越发家常便饭,抛开效能等不谈,供给变化相当的大程度上就是流程的生成,流程的生成会给开发工作造成十分的大麻烦。而本审查批准流程具有较强的通用性,同时也有十分大的八面驶风,就算不可能百分之百的化解各样分外性情化的审批流程,但起码也能缓解之中五分四以上的较为通用的流水线了。本文将就享受部分心得!

   
本审查批准流程从贯彻上的话由流程设计器、流程控制组件和表单设计器三大学一年级些构成。上面将分头举行描述:

    1. 流程设计器 

    流程设计器基于 Web,使用了JQuery
UI、EasyUI、Bootstrape、Knockout.js等等前端框架,可随便设计符合本人的流水生产线,首先看望效果图:

EasyUI 1 

   
近年来的流程库支持5种档次的活动,个中并行活动表示其后面包车型大巴位移需举办交互审查批准,其输入事件都实施通过后才同意实施当前移动;分支活动重要用于判断后续到底怎么活动供给越来越实施,分支活动由系统自动依照所设条件自动执行,条件的宣示采纳C#
的专业语法;各种运动均存在抵达入口和说话的外部方法接口,可在后台编写好代码后再在界面上开始展览布局绑定,目标是提供诸如发送邮件通告等相近的接口效率;同时还是能随随便便自定义任何活动上的审查批准事件,例如保存、上报、回退、驳回、通过、截至等等,如下是事件的参数设置界面: 

EasyUI 2 

   
在此不得不提一下knockout.js,举行质量的绑定和界面包车型地铁换代实在是太方便了,但就是宣称
ViewModel
的概念太辛苦。因而笔者此处还用到了其 knockout.mapping 插件,通过 ko.mapping.fromJS(data,
mapping, this) 一句代码就可径直把 Json 数据转换为
ViewModel,也能一句代码就能把 ViewModel 转换回要保存的 Json
数据,假使您利用knockout.js
的话,简直没有不利用该插件的道理,可让你从评释 ViewModel
的繁杂体力活中抽身出来。如下是工作流定义从 WebApi 加载后绑定至界面所需的
ViewModel 的制造代码:

var ViewModel = function(data) {
    var self = this;
    ko.mapping.fromJS(data, mapping, this);
    self.StartCount = ko.computed(function() {
        var total = 0;
        $.each(self.ActivityDefinitions(), function() {
            if (this.ActivityType() == 0) total++;
        });
        return total;
    });
    self.FinishCount = ko.computed(function() {
        var total = 0;
        $.each(self.ActivityDefinitions(), function() {
            if (this.ActivityType() == 4) total++;
        });
        return total;
    });
    self.refresh = function(item) {
        ko.mapping.fromJS(item, self);
    };}

    2. 流程序控制制组件

   
流程控制组件首要成就流程的跳转控制,数据的加载和封存等。流程序控制制组件和前边小说中关系过的最底层组件一样,使用了
Provider
格局。因为急需在界面上一向配备自定义跳转执行规则,而在C#中近年来还没有接近于
Javascript 的 eval
方法。为落到实处该意义,供给对字符串脚本进行动态编写翻译,方今.NET 下支持C#
脚本的工具如故广大的,在此先后用过CS-SCHavalIPT,Javascript.NET和Roslyn,但都没成功。

     CS-SCLX570IPT 很好用,但.NET 4.0 下的版本不不奇怪,即便是 .NET 4.0
的,但实质上还得安装.NET
4.5,当时在本机测试没别的难题,一旦布置至服务器上就会报错,提醒无法加载
System.Runtime.CompilerServices 类型之类的一无所能,最后发现是其借助的
Mono.CSharp.dll 的标题;最后的来由也搞掌握了个大体,是.NET 4.0 下安装了
.NET 4.5 后会修改暗中同意的 .NET 4.0 底层框架,也正是说,那是晋升至 .NET 4.5
带来的包容性难题,导致在设置了 .NET 4.5 的环境下所生成的针对.NET 4.0 的
Mono.CSharp.dll 组件不能在没安装.NET 4.5
的条件下运作。因为眼前游人如织的服务器环境还是 Windows Server
二零零三,还没办法安装.NET 4.5,非常蛋疼,唯有屏弃。

    Javascript.NET
的最大的特点是应用格外不难,使用JS兼容的语法,但无能为力传递Dynamic类型的参数。

    最后又利用了Roslyn,和Javascript.NET一样,.NET 4.0 版本的形似不扶助dynamic 类型参数,反正小编是没测试成功,推断.NET 4.5
的版本倒是支持,但因很多安插环境依然Windows Server
贰零零壹,由此最后照旧抛弃了。最终没折,唯有和睦实现了,通过 CSharpCodeProvider
动态编写翻译技术达成了1个伊娃l方法,一番煎熬后发觉实际是很简短的,效果也还不易,该
伊娃l 的代码如下,在此粘出代码共享下劳动成果:

 1 /// <summary>
 2         /// 动态编写翻译,获取条件表明式的履行结果
 3         /// </summary>
 4         /// <param name=”expression”>度量圭臬表达式</param>
 5         /// <param name=”objectInstance”>对象实例,种种属性和Form表单对应</param>
 6         /// <param name=”activityInstance”>当前推行的活动实例对象</param>
 7         /// <returns>编译并进行基准表明式后归来的结果</returns>
 8         private object Eval(string expression, dynamic objectInstance, ActivityInstance activityInstance)
 9         {
10             var codeProvider = new CSharpCodeProvider();
11             var cpt = new CompilerParameters();
12 
13             //引用程序集
14             cpt.ReferencedAssemblies.Add(“system.core.dll”);
15             cpt.ReferencedAssemblies.Add(“system.dll”);
16             cpt.ReferencedAssemblies.Add(“Microsoft.CSharp.dll”);
17             //获取对象实例的类别
18             var type = (Type)objectInstance.GetType();
19             //获取活动实例对应的先后集路径
20             var path = activityInstance.GetType().Assembly.Location;
21             cpt.ReferencedAssemblies.Add(path);
22             if (type.Assembly.Location != path)
23             {
24                 cpt.ReferencedAssemblies.Add(type.Assembly.Location);
25             }
26             cpt.CompilerOptions = “/t:library”;
27             cpt.GenerateInMemory = true;
28 
29             var builder = new StringBuilder(“”);
30             builder.Append(“using System;\n”);
31             builder.Append(“using System.Dynamic;\n”);
32             builder.Append(“using Yb.Workflow.Provider;\n”);
33 
34             var ns = type.Namespace;
35             if (ns != “Yb.Workflow.Provider”)
36             {
37                 builder.Append(string.Format(“using {0};\n”, ns));
38                 cpt.ReferencedAssemblies.Add(activityInstance.GetType().Assembly.Location);
39             }
40 
41             builder.Append(“namespace CSCodeEvaler{ \n”);
42             builder.Append(“public class CSCodeEvaler{ \n”);
43             builder.Append(“public bool EvalCode(dynamic objectInstance,ActivityInstance activityInstance){\n”);
44             builder.Append(“return ” + expression + “; \n”);
45             builder.Append(“} \n”);
46             builder.Append(“} \n”);
47             builder.Append(“}\n”);
48             //在内部存款和储蓄器中编译
49             var cr = codeProvider.CompileAssemblyFromSource(cpt, builder.ToString());
50             if (cr.Errors.Count > 0)
51             {
52                 throw new InvalidExpressionException(
53                     string.Format(“Error ({0}) evaluating: {1}”,
54                     cr.Errors[0].ErrorText, expression));
55             }
56 
57             var a = cr.CompiledAssembly;
58             object instance = a.CreateInstance(“CSCodeEvaler.CSCodeEvaler”);
59 
60             Type t = instance.GetType();
61             var mi = t.GetMethod(“EvalCode”);
62             //反射调用方法的实施结果
63             object result = mi.Invoke(instance, new object[] { objectInstance, activityInstance });
64             return result;
65         }

    3. 表单设计器

   
表单设计器将在下个本子中合拢,当前还只可以在流水线定义中手动敲入已编纂好的表单内容。表单内容的持久化和加载使用了前头提到过的
ExtensionDataApi,因为援助 .NET 4.0 下的 dynamic
属性,同时提供了四个名为 Properties 的字典来管理全数的属性名和属性值,和
MVC 下的 Request.Form.AllKeys
简直便是绝配,由此可不行便于地和表单界面举办合并。换句话说,你只管安顿好表单界面即可,具身体表面单数据的保留和加载完全能够交由 ExtensionDataApi
来形成。

    如需特别询问,可点击:http://pjdemo.yellbuy.com/