例-常用普通的简单例子
概述
- 一般的最常用的简单例子,主要介绍整个工作流的一个步骤流程
示例
这里主要介绍大致的步骤:
首先,就是画流程图了,可从“系统管理”模块下的“工作流管理”-“业务流程定义”菜单进入:
新建工作流,选择“实体名称”,填写“流程描述”,其他无特殊需要时都可不用设置:
根据业务需求,开始画流程的每个任务步骤和连线:
画好后,就开始设置每个任务步骤,右键对应的任务步骤,在弹出的窗口中设置,
无特殊要求时,只要设置“任务类型”、“动态指定执行人”,选择添加权限用户或权限角色即可:
接着可设置连线的条件,同样是右键对应的连线来打开设置窗口:
当然了,设置条件前,需要先添加作条件的字段,从“数据集合管理”页面来添加:
如果需要用到一些JS处理事件时,就从工具栏打开各步骤的JS设置页面:
以上各步设置时,记得确定保存,最后再点击定义的主页面工具栏的“保存”按钮保存整个
流程图,至此,一个简单的流程图就画好了。
接着就是要启动引擎,准备跑下流程,看是否正确,
点击“启动”按钮启动引擎:
引擎启动后,进入具体业务的网格页面,选择要测试的记录,点“提交”按钮提交工作流,如果设置正确
的话,就会提示“提交成功”的信息,失败的话,就要找原因,比如引擎和WEB.CONFIG设置是否对应、正确,
流程图的提交前事件、同实体多流程区分标识的设置等等是否正确。
提交成功后,进入“我的工作台”下的“工作内容”,双击当前流程记录,开始接下去的审批操作:
这是审批页面,填写意见,点击相应的按钮进行操作,如“同意”、“不同意”、“终止”等:
审批过程中,要注意看下步步骤的审批用户是否和业务要求的一致、当中要修改的数据库相应
数据是否修改了、流程是否按实际的流向条件走、动态执行人是否按设置的体现等等。
经过多次跑流程测试(流程图画好后,一定要跑流程测试),一个简单的工作流就完成了。
如果需发给现场,就用工具栏的导出按钮来导出该工作流的整个对象,发给现场导入即OK。
相关链接
例-提交时自动指定或弹窗选择用户
概述
- 流程提交时,需自动指定相应的用户,或是弹窗选择对应的用户
示例
在这里设置是否要弹窗选择用户,或是自已写代码处理自动传指定用户。
<ToolBar UniqueNo="0"> <UserButtons> <Button Target="Grid" Name="cmd提交" Text="提交" ToolTip="提交" Type="Normal" Image="WebToolBar/16_Import.gif" DisplayMode="TextAndImage" Script="WFSubmit()"></Button> </UserButtons> <Scripts> <Script> <![CDATA[ function __WFGetSumbitUserList(){ //重载,返回提交用户ID集合,系统自动会调用执行此函数 //代码段,如调用Webservice //.... return "aaaid;bbbid;cccid"; //返回 } ]]> </Script> </Scripts> </ToolBar>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
例-动态指定下一步骤执行人
概述
- 和“提交”时的指定是不一样的,这里是指在审批过程中,动态指定下一步骤的审批用户
示例
例如:A—>B—>C—>D流程,D步骤要由当前记录对应的部门主管来审批,那么这就无法事先在画流程图时就设置好
权限用户、角色了,所以D步骤的“动态指定执行人”要设置为“是”,表示在C步审批时,动态指定D步的审批用户,
如下图,C步审批时,在审批页面上会出现“下步执行人”的选择控件,选择好后审批。
这里的选择窗口默认是列出全部的用户,但有些业务可能要求不列出全部的用户来供选择,这时就要在D步的
“用户(动态执行人)”、“角色(动态执行人)”上设置添加这部分供选择的用户,这样选择窗口中就会
只列出这部分的用户来供选择。
上面这种方式是需要弹窗手工选择,当然了,有时客户要求不要手工选择,要自动选好下步执行人,那要怎么做呢?
其实这里就可以变通一下了,我们只要把“下步执行人”的文本框中自动填好指定用户,然后再把“下步执行人”
整个控件隐藏了,是不是让人看起来就像是自动指定了?对,就是这个效果了。实现这个效果需要我们自己写JS代码,
设置在D步骤那里的“页面加载事件”,填个方法名。
这个JS代码需包括几个内容,如下例子: function JSFUN1(){ var userList=""; //代码段,JS+WebService,获取要指定的用户ID //userList=.... $("#DynamicUserValue").val(userList); //将用户ID字符串赋值给“下步执行人”文件框 $("#DynamicObj").hide(); //隐藏“下步执行人”整个控件 }
1
2
3
4
5
6
7
8
9
10
11
例-审批过程中显示不同的业务展现页面
概述
设置在流程审批过程,不同步骤的审批页面中,“业务展现”可设置成不同的业务FORM页面,
如果不设置,那所有步骤的审批页面的“业务展现”都是同一个FORM页面。
示例
如下图,在对应步骤的“页面加载事件”上设置,
可调用 wm.wf.setFormUniqueNo(FormUniqueNo) 或 wm.wf.setFormUrl(Url) 两个通用函数,一个是通过设置
UniqueNo,一个是直接设置具体的URL地址
如:
wm.wf.setFormUniqueNo('111')
wm.wf.setFormUrl('../Config/Edit.aspx?Mappingid=123456&UniqueNo=0')
例-审批过程需操作到数据库
概述
- 在流程审批过程中,如果需要操作到数据库时,下面举出几个例子
示例
有两种实现方式:
1.在对应步骤中的“任务步骤设置”页面的“事件”页签中添加记录,选择“存储过程”类型:
注:不管是点击同意、不同意或终止按钮,只要这个步骤审批过后都会去执行存储过程
所以如果设计上只要求同意后才操作数据库的话,则要在存储过程中加判断,判断是审批同意后
才去执行存储过程中所要处理的部分。
2.在“工作流前台JS应用”页面中,相应步骤的相关按钮上增加点击前或点击后的JS事件,
通过JS+WebService方式去操作数据库:
相关链接
例-批量审批
概述
- 批量审批
示例
1.在流程定义中,“工作流信息”设置页面中,设置该流程为可批量审批
2.在“工作内容”里的“未审核”页签中,勾选可进行批量审批的业务
(勾选的记录需为同一实体表),双击,弹出批量审批页面来进行批量审批操作
3.批量审批页面中的“业务展现”页面,是调用业务的GRID网格页面(需创建虚拟的业务菜单),故相应的业务
实体配置文件中需配置相关网格页面的UniqueNo,UniqueNo固定为250088(如果一个实体中有多个流程,那么这个UniqueNo
就要多加上流程的标识,比如流程1的区分标识为“省级”,流程2的区分标识为“市级”,那么UniqueNo应设置为
250088_省级和250088_市级,也就是说需要创建两个虚拟业务菜单),数据源用自定义数据源,
过滤条件可从Request取选中的记录ID集合,Reqeust参数为:RecordIds
<Grid Name="ThisTable" HasPurviewFilter="false" UniqueNo="250088" FreezedIndex="0" AllowEdit="false" HasRowHeader="True" HasChecked="True" OpenCheckedEdit="True" WinHeight="600px" WinWidth="800px" OpenType="showmodaldialog" EditURL="Config/Edit.aspx"> <Column Field="Column1" FieldType="VarChar" CaptionText="描述" Width="100"></Column> <Column Field="Column2" FieldType="VarChar" CaptionText="描述" Width="100"></Column> <DataSource Type="SqlServer"> <![CDATA[ select * from ThisTable where ThisTableId in ({@Request['RecordIds']}) ]]> </DataSource> <DataSource Type="Oracle"> <![CDATA[ select * from ThisTable where ThisTableId in ({@Request['RecordIds']}) ]]> </DataSource> </Grid>
1
2
3
4
5
6
7
8
9
10
11
12
13
14注:批量审批仅对于一些比较简单的审批流程的使用,如果有审批前后事件、需选择执行人等处理的话,最好不要使用批量审批,
因为这些处理无法调用执行到。
例-不填写审批意见可提交
概述
- 添加JS后代码后,不填写审批意见直接提交后,审批意见为点击按钮的显示文本。
示例
在项目根目录下的JavaScript\User\User_WFlow.js中添加代码。 function takeche() {//用来让审批意见可以不填 不填的时候 根据点击按钮的文本值填充进去 if($("#__OptionCheck").length) $("#__OptionCheck").val(true); } $(takeche);
1
2
3
4
5
6
7
例-审批中手动选择下个步骤
概述
- 有些业务可能要求在某个步骤审批时,可以手动选择下个审批步骤。
示例
有些业务可能要求在某个步骤审批时,可以手动选择下个审批步骤,此时可以在该步骤的“任务步骤设置里”基础设置中,
将“同意时选择下步骤”选项目设置为“是”即可实现该需求。
审批时,点“同意”按钮,会弹出一个选择窗口来选择下个步骤,如下图,当前步骤是“主管审批”,其直接的下几个步骤有两个,
选择其中的一个,点确定后,流程就往这个步骤走:
例-Visio流程图相关
概述
- Visio流程图相关例子,包括画图,展现
示例
1.Visio流程图定义页面
画Visio流程图的页面和工作流定义页面不太一样,地址为:WorkFlow/WorkFlowDesign/WFlowMain.aspx?flowType=Visio
比工作流定义页面多加了flowType参数,如果项目要用到,需要自己添加业务菜单。
画流程图和画工作流的是一样的操作。
2.Visio流程图展现
展现的地址为:WorkFlow/WorkFlowApply/WFlowVisio.aspx?WFObjectId=2fd308bf-c9a1-4956-9ccd-48731a862e44,
WFObjectId参数为:工作流文件名。
显示页面如下:
3.一些可能用到的JS:
因为流程图展现页面是通用页面,如果要添加一些JS事件,是不能直接在该页面上写JS事件,这时可以在流程图定义那里添加:
将加载事件写在User_WFlow.js文件里,然后在加载事件里写自己要处理的JS。
下面是例子(包括给步骤加各种事件,改变颜色等):
//流程跟踪图加载事件 function aab() { //给每个步骤加点击事件 for(var i = 0; i < flowObj.Activitys.length; i++){ var Act = flowObj.Activitys[i]; //01: 填充步骤 for(var k=0;k<jsonRun.count;k++){ if(jsonRun.data[k].RUNNINGSTEP == Act.id){ Act.fillColor = jsonRun.data[k].COLOURCODE; document.getElementById(Act.id).fillColor =jsonRun.data[k].COLOURCODE; //步骤颜色 } } //02:弹出页面事件 for(var j=0;j<jsonShow.count;j++){ if(jsonShow.data[j].STEPID == Act.id){ //绑小图片,可弹出窗口 flowObj.attachObjectEvent(Act.id,"activity","onclick","showClick","弹出窗口事件"); //先添加事件到数组中 } } } flowObj.addEvent(); //真正将事件添加到步骤上 //每个步骤的事件 for(var i = 0; i < flowObj.Activitys.length; i++){ var Act = flowObj.Activitys[i]; document.getElementById(Act.id).bind( "click", window["stepClick"]); //直接绑步骤单击事件 } //填充线条 for(var l=0; l<flowObj.Transitions.length; l++){ for(var k=0;k<jsonRun.count;k++) { if(jsonRun.data[k].RUNNINGSTEP == flowObj.Transitions[l].fromAct && jsonRun.data[k].NEXTSTEP == flowObj.Transitions[l].toAct) { $(flowObj.Transitions[l].id)[0].strokecolor= jsonRun.data[k].COLOURCODE; //线条颜色 } } } } function stepClick() { //步骤直接点击事件处理 //... } function showClick(curStep) { //步骤小图片点击事件处理 //... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
例-自定义权限用户
概述
- 在流程图相应的任务步骤上设置“自定义权限用户”,可真正实现动态设置审批用户
示例
经常有这样的需求,提交人提交的申请要提交给对应的上级经理审批,
原来的做法一般是通过JS调用WebService来取到对应的上级经理,
现在多了一种方式,直接在流程相应步骤上设置“自定义权限用户”即可,如下图所示,
可填写Select语句或是存储过程,伪变量只有包含记录ID('{@RecordId}'),
注:
第一列返回用户ID,
第二列返回用户权限(会签一人有特权类型时才用到,1=普通权限,2=否决权限,其他情况下可不传或传1)
第三列返回判定分值(会签N人有特权类型时才用到,填写分值,如60,其他情况下可不传或传任意大于0的整数)
SQLSERVER存储过程例子: ALTER procedure [dbo].[SP_Test] @RecordId varchar(50) as begin --第一列用户ID,第二列用户权限(1=普通权限,=否决权限),第三列判定分值 --第二列和第三列在会签类型(一人有特权、N人有特权)时才用到,其他情况下可只返回第一列 select '88888888-8888-8888-8888-888888888888',2,60 union select '49e2a44e-5370-4392-9b70-e7703c1baa13',1,40 end
1
2
3
4
5
6
7
8
9
10
11ORACLE存储过程例子: CREATE OR REPLACE procedure SP_Test( P_RecordId varchar2, myCursor out sys_refcursor ) is begin open myCursor for select '88888888-8888-8888-8888-888888888888',2,60 from dual union select 'a589da05-bba3-48a0-8d21-67767610a292',1,40 from dual; end SP_Test;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
例-自定义C#代码调用
概述
- 在自己的C#代码中启动或呼叫工作流引擎
示例
/// <summary> /// 启动新工作流 /// </summary> /// <param name="XMLCon">参数XML</param> /// <returns></returns> [LogicMethod] public string StartWorkFlow(string XMLCon) { XmlDocument doc = new XmlDocument(); doc.LoadXml(XMLCon); XmlNode root = doc.SelectSingleNode("XMLCon"); string TableName = root.Attributes["TableName"].Value; string RecordId = root.Attributes["RecordId"].Value; string WFObjectId = root.Attributes["WFObjectId"].Value; string CurrentUserId = root.Attributes["CurrentUserId"].Value; string NewUser = root.Attributes["NewUser"].Value; string SysMappingId = root.Attributes["SysMappingId"].Value; //取备注信息 string wfMemo = ""; string sqlMemo = root.SelectSingleNode("MemoSQL").InnerXml; if (!string.IsNullOrWhiteSpace(sqlMemo)) { sqlMemo = sqlMemo.UnCommentXml().Replace("{@RecordId}", RecordId); if (!string.IsNullOrWhiteSpace(sqlMemo)) { try { wfMemo = Wima.DAL.SysDba.Adapter.ExecuteScalarForString(sqlMemo); } catch { } } } string result = string.Empty; string xml = "<Item "; xml += "KeyValue=\"5\" "; xml += "Id=\"" + Guid.NewGuid().ToString() + "\" "; xml += "Type=\"\" "; xml += "WorkflowId=\"" + Guid.NewGuid().ToString() + "\" "; xml += "ActivityId=\"\" "; xml += "User=\"" + CurrentUserId + "\" "; xml += "ToUser=\"\" "; xml += "NewUser=\"" + NewUser + "\" "; xml += "ObjectId=\"" + WFObjectId + "\" "; xml += "RecordId=\"" + RecordId + "\" "; xml += "WFMemo=\"" + wfMemo + "\" "; xml += "SysMappingId=\"" + SysMappingId + "\" "; xml += "RollBackActivity=\"\" "; xml += "Command=\"start\" "; xml += ">"; xml += "</Item>"; bool enableEngine = AppSetting.GetBoolean("enableWorkflowEngine", true); if (enableEngine) { // 流程引擎独立运行或者服务方式运行调用方式 byte[] buf = new byte[1024]; int count = 0; try { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(EngineServer, Convert.ToInt32(EnginePost)); socket.Send(System.Text.Encoding.Default.GetBytes(xml)); count = socket.Receive(buf); socket.Shutdown(SocketShutdown.Both); socket.Close(); string ret = System.Text.Encoding.Default.GetString(buf, 0, count); return ret.EqualIgnoreCase("ok") ? "1" : "0"; } catch(Exception ex) { LogHelper.Write(ex); return "0"; } } else { // 流程引擎集成运行方式(单独的dll)调用方式 return EngineManager.Instance.Execute(xml) ? "1" : "0"; } } /// <summary> /// 呼叫工作流引擎 /// </summary> /// <param name="XMLCon">参数XML</param> /// <returns></returns> [LogicMethod] public string CallWorkFlow(string XMLCon) { //XmlDocument doc = new XmlDocument(); //doc.LoadXml(XMLCon); bool enableEngine = AppSetting.GetBoolean("enableWorkflowEngine", true); if (enableEngine) { // 流程引擎独立运行或者服务方式运行调用方式 string r = ""; byte[] buf = new byte[1024]; int count = 0; try { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Connect(EngineServer, Convert.ToInt32(EnginePost)); socket.Send(System.Text.Encoding.Default.GetBytes(XMLCon));//doc.InnerXml)); count = socket.Receive(buf); socket.Shutdown(SocketShutdown.Both); socket.Close(); string ret = System.Text.Encoding.Default.GetString(buf, 0, count); return ret.EqualIgnoreCase("ok") ? "1" : "0"; } catch (Exception ex) { LogHelper.Write(ex); return "0"; } } else { // 流程引擎集成运行方式(单独的dll)调用方式 return EngineManager.Instance.Execute(XMLCon) ? "1" : "0"; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128