有权限的用户,如业务负责人、系统管理员等可以浏览、冻结、取消业务流程。图9.1是以管理员为登录用户的监控超期限流程的程序界面。在监控流程列表中点击“浏览业务信息”会弹出与当前流程关联的业务数据信息页;点击“业务内容”会弹出业务审批过程记录(包括任务名称、完成任务的工作人员及其审批意见等);点击重新指派任务按钮可以把未完成的任务重新指派给新的员工,以推动业务的继续进行。

图9.1 超期限业务流程监控
9.1 超期限业务流程监控
9.1.1 查询超期限业务流程的复杂SQL语句
从图9.1可以看出,超期限流程监控程序首先要实现的就是列表显示超期限的业务流程信息,包括业务名称、业务内容(过程实例描述)、业务开始时间、业务超过承诺期限的天数、未完成的任务名称与责任人等信息。特别是要找到有哪些流程的那些任务还没有完成,以便通过重新指派任务责任人等措施推动业务的继续进行。
考虑到业务过程可能存在并行分支,那样,一个流程实例就有可能存在多个尚未完成的任务实例,因此Sql语句要以查询任务实例数据表为主,找出超期限业务的所有未完成的任务实例。具体来说,Sql查询要满足以下条件:
1、鉴于列表显示的项以及Sql查询条件都与过程实例相关,最好对任务实例与过程实例进行连接查询。
2、过程实例要满足的条件是:(1)尚未完成:EndTime为空;(2)流程未被冻结或取消。
3、任务实例要满足的条件是:未完成,即TaskState=”Running” or TaskState=”JustCreated”
4、未完成的任务要区分是回退的任务还是正在进行(用户在处理任务时点击了暂时保存任务按钮),或刚创建的任务实例。回退任务的特点是TaskState=”Running” and NextTaskInstance is not null;正在进行的任务实例特点是TaskState=”Running” and NextTaskInstance is null;刚创建的任务实例特点是TaskState=”JustCreated” and TaskUserID isnull,即任务刚创建,还没有用户选择处理该任务。
5、对于回退和正在进行的任务要求显示任务名称和承担任务的员工姓名;刚创建的任务实例要求显示任务名称和可以处理任务的部门角色名称。以便对任务进行重新指派。
满足以上条件的Sql语句如下:
select TIns.TaskInstanceID,PIns.ProcessInstanceID,
(select ProcessName from ProcessDefinition where ProcessID=PIns.ProcessDefinitionID)
as process_name,PIns.Description,
CONVERT(varchar(10), PIns.StartTime, 120) as startdate,
datediff(day,PIns.StartTime,getdate()) as overtime,
(case when NextTaskInstance is not null and TaskState=’Running’
then (select TaskName from TaskDefinition where TaskID=TIns.TaskDefinitionID)
+’:’+(select EmployeeName from Employees where EmployeeID=
(select EmployeeID from Users where UserID=TIns.TaskUserID))
else ” end) as postbackedtask_user,
(case when NextTaskInstance is null and TaskState=’Running’
then (select TaskName from TaskDefinition where TaskID=TIns.TaskDefinitionID)
+’:’+(select EmployeeName from Employees where EmployeeID=
(select EmployeeID from Users where UserID=TIns.TaskUserID))
when TaskState=’Just Created’
then (select TaskName from TaskDefinition where TaskID=TIns.TaskDefinitionID)
+’:’+(select RoleName from RolesManagement where RoleID=
(select AssignedRole from TaskDefinition where TaskID=TIns.TaskDefinitionID))
else ” end) as notendedtask_user
from TaskInstance TIns,ProcessInstance PIns
where TIns.ProcessInstanceID=PIns.ProcessInstanceID and PIns.EndTime is null
and datediff(day,PIns.StartTime,getdate())
>(select DueDate from ProcessDefinition where ProcessID=ProcessDefinitionID)
and (PIns.IsSuspended is null or PIns.IsSuspended=”)
and PIns.IsCanceled is null
and (TaskState=’Just Created’ or TaskState=’Running’)”;
9.1.2 超期限业务流程监控程序代码
1、OverTimeProcess.aspx文件代码(代码中用到的日历控件脚本省略):
……
<form id=”Form1″ method=”post” runat=”server”>
<TABLE id=”Table6″ height=”18″ cellSpacing=”0″ cellPadding=”0″ width=”100%” border=”0″>
<TR><TD>超期限业务流程列表</TD></TR>
</TABLE>
<TABLE>
<TR>
<TD><asp:datagrid id=”DataGrid1″ runat=”server” AllowPaging=”True” Width=”100%”
DataKeyField=”ProcessInstanceID” >
<ItemStyle Font-Size=”13px” HorizontalAlign=”Center” Height=”28px”
VerticalAlign=”Bottom”></ItemStyle>
<HeaderStyle Font-Size=”16px” Font-Bold=”True” HorizontalAlign=”Center”
Height=”30px” VerticalAlign=”Middle”></HeaderStyle>
<Columns>
<asp:BoundColumn DataField=”process_name” HeaderText=”业务名称”>
</asp:BoundColumn>
<asp:HyperLinkColumn Target=”_blank” DataNavigateUrlField=”ProcessInstanceID”
DataNavigateUrlFormatString=”../Process/DisplayMessage.aspx?id={0}”
DataTextField=”Description” HeaderText=”业务内容”>
</asp:HyperLinkColumn>
<asp:BoundColumn DataField=”startdate” HeaderText=”业务开始时间”>
</asp:BoundColumn>
<asp:BoundColumn DataField=”overtime” HeaderText=”超期(天)”>
</asp:BoundColumn>
<asp:BoundColumn DataField=”postbackedtask_user”
HeaderText=”正在处理的退件任务”></asp:BoundColumn>
<asp:BoundColumn DataField=”notendedtask_user”
HeaderText=”未完成(或无人承办)的任务”></asp:BoundColumn>
<asp:HyperLinkColumn Text=”浏览业务信息” Target=”_blank”
DataNavigateUrlField=”ProcessInstanceID”
DataNavigateUrlFormatString=”DisplayProcessInfo.aspx?id={0}”>
</asp:HyperLinkColumn>
<asp:TemplateColumn>
<ItemTemplate>
<asp:LinkButton id=”LinkButton1″ runat=”server” CommandName=”assigntask”>
重新指派任务</asp:LinkButton>
<asp:Label id=”Label2″ runat=”server” ForeColor=”Red”></asp:Label>
</ItemTemplate>
</asp:TemplateColumn>
<asp:BoundColumn Visible=”False” DataField=”TaskInstanceID” ReadOnly=”True”>
</asp:BoundColumn>
</Columns>
<PagerStyle Font-Size=”9pt” HorizontalAlign=”Right” ForeColor=”#3366FF”
Mode=”NumericPages”></PagerStyle>
</asp:datagrid>
</TD>
</TR>
</TABLE>
……
<table width=”100%” border=”0″ cellspacing=”2″ cellpadding=”2″>
<tr><td width=”15%” align=”right”>业务名称:</td>
<td width=”30%”><asp:DropDownList id=”DropDownList1″ runat=”server”>
</asp:DropDownList></td>
<td width=”15%” align=”right”>业务内容:</td>
<td width=”40%”><asp:TextBox id=”TextBox1″ runat=”server” Columns=”50″>
</asp:TextBox></td>
</tr>
<tr><td align=”right”>参与员工:</td>
<td><asp:TextBox id=”TextBox2″ runat=”server”></asp:TextBox></td>
<td align=”right”>业务开始时间在</td>
<td><asp:TextBox id=”TextBox3″ runat=”server” Columns=”10″
οnclick=”calendar();”></asp:TextBox><FONT face=”宋体”>到</FONT>
<asp:TextBox id=”TextBox4″ runat=”server” Columns=”10″
οnclick=”calendar();”></asp:TextBox><FONT face=”宋体”>之间</FONT>
</td>
</tr>
<tr>
<td> </td><td> </td><td> </td>
<td>
<asp:Button id=”Button1″ runat=”server” Text=”查询”></asp:Button>
<asp:Button id=”Button2″ runat=”server” Text=”重置”></asp:Button>
<asp:Label id=”Label1″ runat=”server” ForeColor=”Red”></asp:Label>
</td>
</tr>
</table>
</form>
……
2、OverTimeProcess.aspx.cs文件代码
……
using DataAccess;
using UserResourceManagement;
namespace workflow.Controls
{
public class OverTimeProcess : System.Web.UI.Page
{
protected System.Web.UI.WebControls.DropDownList DropDownList1;
protected System.Web.UI.WebControls.TextBox TextBox1;
protected System.Web.UI.WebControls.TextBox TextBox2;
protected System.Web.UI.WebControls.TextBox TextBox3;
protected System.Web.UI.WebControls.TextBox TextBox4;
protected System.Web.UI.WebControls.Button Button1;
protected System.Web.UI.WebControls.Button Button2;
protected System.Web.UI.WebControls.Label Label1;
protected System.Web.UI.WebControls.DataGrid DataGrid1;
private void Page_Load(object sender, System.EventArgs e)
{
if(! IsPostBack)
{
//验证用户是否登录
if(Session[“userid”] == null)
Response.Redirect(“../Message.aspx”);
BindGrid();
BindList();
}
}
void BindGrid()
{
string strSql=”参考前面的sql语句”;
DataSet ds=new Base().SQLExeDataSet(strSql);
DataGrid1.DataSource=ds;
DataGrid1.DataBind();
}
void BindList()
{
//绑定业务流程名称列表
string strSql=”select ProcessID,ProcessName from ProcessDefinition where
DefineCompleted=’Y'”;
DataSet ds=new Base().SQLExeDataSet(strSql);
DataRow dr=ds.Tables[0].NewRow();
ds.Tables[0].Rows.InsertAt(dr,0);
DropDownList1.DataSource=ds;
DropDownList1.DataTextField=”ProcessName”;
DropDownList1.DataValueField=”ProcessID”;
DropDownList1.DataBind();
}
//重置按钮
private void Button2_Click(object sender, System.EventArgs e)
{
TextBox1.Text=””;
TextBox2.Text=””;
TextBox3.Text=””;
TextBox4.Text=””;
return;
}
//查询按钮
private void Button1_Click(object sender, System.EventArgs e)
{
string strSql=”参考前面的sql语句”;
if(DropDownList1.SelectedValue != “”)
strSql=strSql+” and ProcessDefinitionID=”+DropDownList1.SelectedValue;
if(TextBox1.Text.Trim() != “”)
strSql=strSql+” and Description like @Description”;
if(TextBox2.Text.Trim() != “”)
strSql=strSql+” and Message like @AboutTaskUsers”;
if(TextBox3.Text.Trim() != “”)
strSql=strSql+” and StartTime>='”+TextBox3.Text.Trim()+”‘”;
if(TextBox4.Text.Trim() != “”)
strSql=strSql+” and StartTime<='”+TextBox4.Text.Trim()+”‘”;
//按照超期时间排序
strSql=strSql+” order by overtime desc”;
SqlCommand cmd=new SqlCommand(strSql);
if(TextBox1.Text.Trim() != “”)
{
cmd.Parameters.Add(“@Description”,SqlDbType.VarChar);
cmd.Parameters[“@Description”].Value=”%”+TextBox1.Text.Trim()+”%”;
}
if(TextBox2.Text.Trim() != “”)
{
cmd.Parameters.Add(“@AboutTaskUsers”,SqlDbType.VarChar);
cmd.Parameters[“@AboutTaskUsers”].Value=”%”+TextBox2.Text.Trim()+”%”;
}
Base basecode=new Base();
DataSet ds=basecode.SQLExeDataSet(cmd);
if(ds == null)
{
Label1.Text=basecode.BaseSqlErrDes;
return;
}
DataGrid1.DataSource=ds;
DataGrid1.DataBind();
}
private void DataGrid1_PageIndexChanged(object source,
System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
DataGrid1.CurrentPageIndex = e.NewPageIndex;
BindGrid();
}
private void DataGrid1_ItemCommand(object source,
System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
//重新指派任务按钮
if(e.CommandName == “assigntask”)
{
//考虑到一个流程实例可能存在多个未完成任务,而重新指派是针对选定任务的,因此需
//要向指派任务页面传递任务实例编号参数tid(pid是过程实例编号)。
//判断用户是否具有重新指派任务的权限
UserManagement umanage=new UserManagement();
if(umanage.HaveReassignTaskPrivilege(Session[“userid”].ToString()))
Response.Redirect(“ReassignTaskUser.aspx?pid=”
+DataGrid1.DataKeys[e.Item.ItemIndex].ToString()
+”&tid=”+e.Item.Cells[8].Text.ToString());
else
((Label)e.Item.FindControl(“Label2″)).Text=”无权执行该操作!”;
}
}
}
}
3、显示业务办理过程与业务数据信息
(1)在流程监控列表中点击业务内容将弹出显示业务办理过程的页面,包括各任务环节名称、任务完成人、审核或审批意见等内容。程序比较简单,只是取出对应过程实例的Message字段内容进行显示。
(2)点击浏览业务信息按钮将弹出显示与业务过程关联的业务数据记录的详细内容,包括上传的申请书等附件资料。由于在过程实例表中保存了RelatedTable,IdentityFieldValue字段(关联的业务表名称及其标识字段的值),因此要获取业务数据记录的信息也非常方便,实现代码可以参考第七章中有关显示详细业务数据的程序。