数据的自动流转之一


一般用户可以忽略本节内容。
本节的内容可以参考CaseStudy目录下的文件:自动流转一.Table
打开此文件的时候,请以张三、李四或王五登录。

我们用一个简单的例子来介绍如何在Foxtable实现数据的自动流转,所谓自动流转,就是本流程能自动接收上一流程处理完毕的数据,同时本流程处理完毕的数据,也能自动提交给下一流程,无需人工干预。
流程是无定式的,Foxtable可以随心所欲地定义工作流程,本节只是介绍一些基本的方法和原理。

假定表A有九列,分三个流程处理,要求:

1、流程一由张三负责,输入第一列、第二列的数据。
2、流程二由李四负责,输入第三列、第四列的数据。
3、流程三由王五负责,输入第五列、第六列的数据。
4、上级流程处理完毕,才能处理本级流程,例如流程一处理完毕,才能处理流程二。
5、禁止李四和王五增加行,因为他们不是流程的初始发起者,只是后续流程的处理者。
6、只加载登录用户负责处理的行,例如李四负责流程二,所以李四登录后,只加载流程一处理完毕,但流程二未处理的行。
7、保存后移除(注意不是删除)处理完毕的行,并从后台追载新的待处理行。
8、如果所有行均处理完毕,那么定期从后台追载新的待处理行。

设计步骤:

1、给表增加一个名为“进度”的字符型列,用于记录流程的处理进度,此列的值和流程进度的对应关系为:

进度
1A 流程一开始
1B 流程一完毕
2A 流程二开始
2B 流程二完毕
3A 流程三开始
3B 流程三完毕

每个流程都有开始和结束标记,是行自动流转的需要。
例如新增行的初始流程状态为"1A",张三处理完毕后,状态变为"1B"(表示流程一处理完毕),李四检测到后台有状态为"1B"的行,将其追载到表中处理,并将其状态设置为"2A"(表示流程二已经开始)并保存。
假定没有开始标记,只有结束标记,当李四再次追载后台数据时,由于此行的状态还是"1B",将无法判断此行是否已经追载,会影响行的自动流转效率。

2、为了只加载登录用户负责处理的行,首先必须确保默认不加载任何数据:

如果是内部表,设置项目事件BeforeLoadInnerTable的代码为:

If e.DataTableName = "表A" Then
   
e.Filter = "[_Identify] Is Null"
End If

如果是外部表,可以在定义外部表的时候,直接定义加载条件:

3、然后在项目事件LoadUserSetting中设置代码,加载由登录用户负责处理的行,并设置本流程开始标记:

'加载登录用户负责处理的行
Dim
Filter As String
Dim
bj As String
Select
Case User.Name
    Case
"张三"
        Filter =
"进度 = '1A'" '进度一开始
   
Case "李四"
        Filter =
"进度 = '1B' Or 进度 = '2A'" '进度一结束或进度二开始
        bj =
"2A"
   
Case "王五"
        Filter =
"进度 = '2B' Or 进度 = '3A'" '进度二结束或进度三开始
        bj =
"3A"
   
Case Else
        Filter = ""
'其他用户加载全部记录
End
Select
DataTables
("表A").LoadFilter = Filter
DataTables(
"表A").Load()
'设置本流程开始标记

If
bj >"" Then
    For
Each dr As DataRow In DataTables("表A").DataRows
        dr
("进度") = bj
   
Next
End
If
DataTables(
"表A").Save() '一定要保存,以更新后台的流程开始标记

4、每个用户只能编辑本流程范围内的列,且进度列是不允许任何人编辑的,为此将表的PrepareEdit事件代码设置为:

Select Case e.Col.Name
    Case
"进度"
        e.Cancel =
True
   
Case "第一列","第二列"
        e.Cancel = (User.Name <>
"张三")
    Case
"第三列",
"第四列"
        e.Cancel = (User.Name <>
"李四")
    Case
"第五列",
"第六列"
        e.Cancel = (User.Name <>
"王五")
End
Select

5、为了禁止除张三之外的人增加行,将表的BeforeAddDataRow事件代码设置为:

If User.Name <> "张三" Then
    e.Cancel=
True
End
If

6、将表的DataRowAdding事件代码设置为:

e.DataRow("进度") = "1A"

这样新增行的时候,进度列的值默认为"1A"。

7、进度列的值需要根据其他列的输入进度来计算得出,为此将表的DataColChanged事件代码设置为:

Select Case e.DataCol.Name
    Case
"第一列","第二列","第三列","第四列","第五列","第六列"
       
Dim dr As DataRow = e.DataRow
       
Dim jd As String = "1A"
       
If dr.IsNull("第一列") = False AndAlso dr.IsNull("第二列") = False Then
            jd =
"1B"
           
If dr.IsNull("第三列") = False AndAlso dr.IsNull("第四列") = False Then
                jd =
"2B"
               
If dr.IsNull("第五列") = False AndAlso dr.IsNull("第六列") = False Then
                    jd =
"3B"
               
End If
            End
If
        End
If
        If
jd = "1B" AndAlso dr("进度") = "2A" Then '注意这里的处理技巧,意思是2A不能回到1B,3A不能回到2B
        ElseIf
jd = "2B" AndAlso dr("进度") = "3A" Then
        Else

            dr(
"进度") = jd
        End
If
End
Select

8、为了在保存后自动移除已经处理完毕的行,并加载新的待处理行,将项目事件AfterSaveProject事件代码设置为:

Dim Filter As String
Dim
bj As String
Dim
drs As List(Of DataRow)
'移除处理完毕的行

Select
Case User.Name
    Case
"张三"
        Filter =
"进度 = '1B'"
    Case
"李四"
        Filter =
"进度 = '2B'"
   
Case "王五"
        Filter =
"进度 = '3B'"
   
Case Else
        Return
'其他用户正常返回
End
Select
DataTables
("表A").RemoveFor(Filter)
'追载待处理的行

Select
Case User.Name
    Case
"李四"
        Filter =
"进度 = '1B'"
        bj=
"2A"
   
Case "王五"
        Filter =
"进度 = '2B'"
        bj =
"3A"
   
Case Else
        Return
'其他用户正常返回
End
Select
drs =
DataTables("表A").AppendLoad(Filter,False)
'为新追载的行设置流程开始标记

If
drs.Count > 0 Then
    For
Each dr As DataRow In drs
        dr(
"进度") = bj
        dr.Save()
'一定要保存,以更新后台的流程进度标记
    Next
End
If

提示:

1、没有数据要保存的时候,你也可以单击菜单中的保存按钮来追载新的待处理行,因为上面的代码使得保存按钮具备了保存和追载的双重功能。
2、如果需要的话,也可以在菜单或者窗口增加一个按钮,单单用于追载待处理行,按钮代码为:

Dim Filter As String
Dim
bj As String
Dim
drs As List(Of DataRow)
Select
Case User.Name
    Case
"李四"
        Filter =
"进度 = '1B'"
        bj=
"2A"
   
Case "王五"
        Filter =
"进度 = '2B'"
        bj =
"3A"
   
Case Else
Return
'其他用户不追载
End
Select
drs =
DataTables("表A").AppendLoad(Filter,False) '追载待处理行
'为新追载的行设置流程开始标记

If
drs.Count > 0 Then
    For Each dr As DataRow In drs
        dr(
"进度") = bj
        dr.Save()
'一定要保存,以更新后台的流程进度标记
    Next
End If

9、在计划管理中新增一个计划,计划的执行间隔为10秒(即10000毫秒),代码为:

Dim Filter As String
Dim
bj As String
Dim
drs As List(Of DataRow)
If
DataTables("表A").DataRows.Count > 0 Then
    Return
End
If
Select
Case User.Name
    Case
"李四"
        Filter =
"进度 = '1B'"
        bj=
"2A"
   
Case "王五"
        Filter =
"进度 = '2B'"
        bj =
"3A"
   
Case Else
Return
'其他用户不追载
End
Select
drs =
DataTables("表A").AppendLoad(Filter,False) '追载待处理行
If
drs.Count > 0 Then '设置新流程的开始标记
    For Each dr As DataRow In drs
        dr(
"进度") = bj
        dr.Save()
'一定要保存 ,以更新后台的流程进度标记
    Next
End If

上面的代码就会每隔10秒执行一次,如果当前表已经没有数据,就从后台追载新的待处理行,并为新追载行设置本流程开始标记。
具体间隔时间可以根据需要调整,但不宜过短,以免服务器的负载过重。

利用消息推送实现即时刷新

前述代码利用计划,每隔10秒追载一下待处理的数据,用户量大的时候,这种定时轮询的方式会导致服务器负载过重。
Foxtable 2016增加了消息推送工具OpenQQ
,可以通过代码进行信息的自动收发。
这样负责上一流程的用户处理完成之后,可以给负责下一流程的用户给发一个约定格式的信号,该用户收到信号后,立即自动追载新的数据。
这种主动追载数据的方式,不仅即时,而且高效,具体实现可以参考帮助文件《消息推送》这一章。
 


本页地址:http://www.foxtable.com/webhelp/topics/2264.htm