Easyflow.net 常用作業訊息框對應的資料表在資料庫中的位置

Easyflow.net 常用作業的資料表位置:[EFNETSYS.dbo.UsedFunctionHistory],包成的欄位有「使用者ID,工作ID(程式代號),運行次數,修改日期」,但是似乎有些頁面運行後並不會被紀錄統計在此資料表之中,當然也包含自已手動加上的應用程式。資料表Easyflow常用作業的欄位

當然我們也可以自已修改這個資料表,讓我們自已開發的頁面落在常用作業的訊框上。

Easyflow ISO 直接開啟文件PDF發佈檔(自訂網頁程式)

在 Easyflow ISO 模組上,把開放給使用者能列印(直接開啟PDF)的表單,文件權限等級為標記「9」。

建立後端程式碼處理pdf,由資料庫讀取PDF字串並輸出到前端。

using System;
using System.Collections.Generic;
//using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Configuration;

public partial class functions_readStream : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Response.Write("功能尚未開放,請耐心等候。");
        //Response.End();
        try
        {
            string DocNO = Request.QueryString["DocNO"];
            string DocVer = Request.QueryString["DocVer"];

            using (SqlConnection myConnection = new SqlConnection("User ID=sa;Password = qwe19735;Data Source=192.168.128.219;DataBase=EFNETDB;"))
            {
                if (Session["IsFromLoginPage"] == null || Session["IsFromLoginPage"].ToString() != "Y")
                {
                    Response.Write("你尚未登入Easyflow或是Session已逾時。<br/>如有任何疑問請聯繫資訊課人員。");
                    Response.End();
                }

                const string SQL = @"select isoebb005,isoebb006,isoebb009,isoebb010,isoebf003,isoebf004
                from isoebb join isoebf on isoebb005=isoebf001 and isoebb006=isoebf002
                where isoebb005=@DocNO and isoebb006=@DocVer
                and (isoebf003='0' or (isoebf003='1' and isoebf004 in (select resan001 from resan where resan003=@UserId)))
                and isoebf005='9'
                and isoebb015='1'
                    ;";
                SqlCommand myCommand = new SqlCommand(SQL, myConnection);
                myCommand.Parameters.AddWithValue("@DocNO", DocNO);
                myCommand.Parameters.AddWithValue("@DocVer", DocVer);
                myCommand.Parameters.AddWithValue("@UserId", Session["strUserID"].ToString());

                myConnection.Open();
                SqlDataReader myReader = myCommand.ExecuteReader();

                if (myReader.Read())
                {
                    //Response.ContentType = myReader["MIME"].ToString();
                    Response.ContentType = "application/pdf";
                    Response.BinaryWrite((byte[])myReader["isoebb010"]);
                    Response.End();
                }
                else{
                    Response.Write("你沒有權限瀏覽與列印所選取的文件。<br/>如有任何疑問請聯繫資訊課人員。");
                }

                myReader.Close();
                myConnection.Close();
            }
        }
        catch (Exception ex)
        {
            Response.Write(ex.ToString());
        }
    }
}

修改一般第三階表單判斷文件權限等級是否為 “9″ ,來產生列印的文件的連結。

using System;
using System.Collections.Generic;
//using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;

public partial class MIS_ISO_Doc_Index : System.Web.UI.Page
{
    SqlConnection myConEFnet;
    SqlDataAdapter myISOAdapter;
    public string tmpstring, isoType, SessionValues;
    string sqlstring1 = @"
select
a.isoebe003,a.isoebe004,a.isoead003,a.isoeba003, a.isoebe001,a.isoeba002,
b.isoeba003 as isoeba003x,b.isoeba001 as isoeba001x,b.isoeba002 as isoeba002x ,b.isoebd003,isoebf005,in_groups
from
(select isoebe002,isoebe003, isoebe004,isoead003,isoebe001,isoeba002,isoeba003,isoeba012 from
(isoebe join isoead on isoebe003=isoead001 and isoebe004=isoead002 ) join isoeba on isoebe001=isoeba001
and isoebe002=isoeba002 where isoebe001 not like '%-%-%'  and isoeba099='2'
) as a left join
(select substring(isoeba001,0,LEN(isoeba001)-CHARINDEX('-',reverse(isoeba001))+1) as isoeba000,
isoeba001,isoeba002,isoeba003,isoebd003,isoebf005,
in_groups=(case when (isoebf003='0' or (isoebf003='1' and isoebf004 in (select resan001 from resan where resan003=@UserId))) then '1' else '0' end)
from isoeba left join isoebd on isoeba001=isoebd001 and isoeba002=isoebd002 left join isoebf on isoeba001=isoebf001 and isoeba002=isoebf002
where isoeba001 like '%-%-%' and isoeba099='2'
) as b on a.isoebe001=b.isoeba000
where a.isoebe003=@isoType
order by isoebe003,isoebe004,isoebe001,isoeba001x
";
    string sqlstring2 = @"
select
a.isoebe003,a.isoebe004,a.isoead003,a.isoeba003, a.isoebe001,a.isoeba002,
b.isoeba003 as isoeba003x,b.isoeba001 as isoeba001x,b.isoeba002 as isoeba002x ,b.isoebd003,isoebf005,in_groups
from
(select isoebe002,isoebe003, isoebe004,isoead003,isoebe001,isoeba002,isoeba003,isoeba012 from
(isoebe join isoead on isoebe003=isoead001 and isoebe004=isoead002 ) join isoeba on isoebe001=isoeba001
and isoebe002=isoeba002 where isoebe001 not like '%-%-%'  and isoeba099='2'
) as a left join
(select substring(isoeba001,0,LEN(isoeba001)-CHARINDEX('-',reverse(isoeba001))+1) as isoeba000,
isoeba001,isoeba002,isoeba003,isoebd003,isoebf005,
in_groups=(case when (isoebf003='0' or (isoebf003='1' and isoebf004 in (select resan001 from resan where resan003=@UserId))) then '1' else '0' end)
from isoeba left join isoebd on isoeba001=isoebd001 and isoeba002=isoebd002 left join isoebf on isoeba001=isoebf001 and isoeba002=isoebf002
where isoeba001 like '%-%-%' and isoeba099='2'
) as b on a.isoebe001=b.isoeba000
where a.isoebe003='ISO'
order by isoebe003,isoebe004,isoebe001,isoeba001x
";

    DataTable myDataTable1,myDataTable2;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Session["IsFromLoginPage"] == null || Session["IsFromLoginPage"].ToString() != "Y")
        {
            Response.Write("你尚未登入Easyflow或是Session已逾時。<br/>如有任何疑問請聯繫資訊課人員。");
            Response.End();
        }

        isoType="14001";
        if (Request.QueryString["isoType"] != null)
        {
            isoType = Request.QueryString["isoType"];
        }

        myConEFnet = new SqlConnection("User ID=sa;Password = password;Data Source=192.168.128.219;DataBase=EFNETDB;");
        SqlCommand myCommand1 = new SqlCommand(sqlstring1, myConEFnet);
        myCommand1.Parameters.AddWithValue("@isoType",isoType);
        myCommand1.Parameters.AddWithValue("@UserId", Session["strUserID"].ToString());
        SqlCommand myCommand2 = new SqlCommand(sqlstring2, myConEFnet);
        myCommand2.Parameters.AddWithValue("@UserId", Session["strUserID"].ToString());

        myConEFnet.Open();
        myISOAdapter = new SqlDataAdapter(myCommand1);
        myDataTable1 = new DataTable();
        myISOAdapter.Fill(myDataTable1);
        myISOAdapter = new SqlDataAdapter(myCommand2);
        myDataTable2 = new DataTable();
        myISOAdapter.Fill(myDataTable2);
        string[] strs;
        DataView tmpView1 = myDataTable1.DefaultView;
        DataTable tmpTable1 = tmpView1.ToTable("tmpTable1",true,strs= new string[]{"isoebe004","isoead003"});
        DataTable tmpTable2 = tmpView1.ToTable("tmpTable2", true, strs = new string[] { "isoebe004","isoeba003","isoebe001","isoeba002" });
        DataTable tmpTable3 = tmpView1.ToTable("tmpTable3", true, strs = new string[] { "isoebe001", "isoeba003x", "isoeba001x", "isoeba002x", "isoebd003", "isoebf005","in_groups" });
        DataView tmpView2 = myDataTable2.DefaultView;
        DataTable tmpTable4 = tmpView2.ToTable("tmpTable4",true,strs= new string[]{"isoebe004","isoead003"});
        DataTable tmpTable5 = tmpView2.ToTable("tmpTable5", true, strs = new string[] { "isoebe004","isoeba003","isoebe001","isoeba002" });
        DataTable tmpTable6 = tmpView2.ToTable("tmpTable6", true, strs = new string[] { "isoebe001", "isoeba003x", "isoeba001x", "isoeba002x", "isoebd003", "isoebf005","in_groups" });

        foreach (DataRow row in tmpTable1.Rows) {
            tmpstring += "<tr><td class='td1'><div>" + row["isoebe004"] + " " + row["isoead003"] + "</div></td><td><table>";
            foreach (DataRow row1 in tmpTable2.Select("isoebe004 = '"+ row["isoebe004"]+"'")) {
                tmpstring += "<tr><td class='td2'><div><a style='color:blue;' target='_blank' href='/efnet/src/ISO/ISOEM008/DocDetail.aspx?DocNO=" + row1["isoebe001"] + "&DocVer=" + row1["isoeba002"] + "'>" + row1["isoeba003"] + "</div></td><td class='td3'><div>" + row1["isoebe001"] + "</div></td><td  class='td4'><div>" + row1["isoeba002"] + "</div></td><td><table>";
                foreach(DataRow row2 in tmpTable3.Select("isoebe001 = '"+ row1["isoebe001"]+"'")){
                    if (row2["isoeba003x"].ToString() == "")
                    {
                        tmpstring += "<tr><td  class='td5'><div>&nbsp;</div></td><td  class='td6'><div>&nbsp;</div></td><td  class='td7'><div>&nbsp;</div></td></tr>";
                    }
                    else
                    {
                        tmpstring += "<tr><td  class='td5'><div><a style='color:blue;' target='_blank' href='/efnet/src/ISO/ISOEM008/DocDetail.aspx?DocNO=" + row2["isoeba001x"] + "&DocVer=" + row2["isoeba002x"] + "'>" + row2["isoeba003x"] + "</a>"+
						((row2["isoebd003"].ToString()!="")?"<a style='color:red;font-weight:bold;' target='_blank' href='../../frm/"+row2["isoebd003"].ToString()+"/"+row2["isoebd003"].ToString()+".aspx'>&nbsp;&nbsp;[申請]</a>":"")
                        + (row2["isoebf005"].ToString() == "9" && row2["in_groups"].ToString() == "1" ? "<a style='color:blue;' target='_blank' href='../functions/readStream.aspx?DocNO=" + row2["isoeba001x"] + "&DocVer=" + row2["isoeba002x"] + "''>&nbsp;&nbsp;[列印]</a>" : "")
                        +"</div></td><td  class='td6'><div>" + row2["isoeba001x"] + "</div></td><td  class='td7'><div>" + row2["isoeba002x"] + "</div></td></tr>";
                    }
                }
                tmpstring += "</table></td><td><table title='" + row1[1] + "'>";

				foreach (DataRow row3 in tmpTable5.Select("isoebe004 = '"+ row1[2].ToString().Replace("-","")+"'")) {
					tmpstring += "<tr><td class='td2'><div><a style='color:blue;' target='_blank' href='/efnet/src/ISO/ISOEM008/DocDetail.aspx?DocNO=" + row3["isoebe001"] + "&DocVer=" + row3["isoeba002"] + "'>" + row3["isoeba003"] + "</div></td><td class='td3'><div>" + row3["isoebe001"] + "</div></td><td  class='td4'><div>" + row3["isoeba002"] + "</div></td><td><table>";
					foreach(DataRow row4 in tmpTable6.Select("isoebe001 = '"+ row3["isoebe001"]+"'")){
						if (row4["isoeba003x"].ToString() == "")
						{
							tmpstring += "<tr><td  class='td5'><div>&nbsp;</div></td><td  class='td6'><div>&nbsp;</div></td><td  class='td7'><div>&nbsp;</div></td></tr>";
						}
						else
						{
							tmpstring += "<tr><td  class='td5'><div><a style='color:blue;' target='_blank' href='/efnet/src/ISO/ISOEM008/DocDetail.aspx?DocNO=" + row4["isoeba001x"] + "&DocVer=" + row4["isoeba002x"] + "'>" + row4["isoeba003x"] + "</a>"+
							((row4["isoebd003"].ToString()!="")?"<a style='color:red;font-weight:bold;' target='_blank' href='../../frm/"+row4["isoebd003"].ToString()+"/"+row4["isoebd003"].ToString()+".aspx'>&nbsp;&nbsp;[申請]</a>":"")
                            + (row4["isoebf005"].ToString() == "9" && row4["in_groups"].ToString() == "1" ? "<a style='color:blue;' target='_blank' href='../functions/readStream.aspx?DocNO=" + row4["isoeba001x"] + "&DocVer=" + row4["isoeba002x"] + "''>&nbsp;&nbsp;[列印]</a>" : "")
							+"</div></td><td  class='td6'><div>" + row4["isoeba001x"] + "</div></td><td  class='td7'><div>" + row4["isoeba002x"] + "</div></td></tr>";
						}
					}
                    tmpstring += "</table></td></tr>";
				}
				tmpstring += "</table></td></tr>";
            }
            tmpstring+="</table></td></tr>";
        }
        tmpstring="<table class='table1' style='display:none;'>"+tmpstring+"</table>";
        foreach (string SessionVar in Session.Keys)
        {
            SessionValues += "<br />" + SessionVar + ":" + Session[SessionVar].ToString();
        }
        SessionValues = "<div>" + SessionValues + "</div>";
    }
}

接著在機密等級代號維護作業中,新增一條文件權限等級「9」自訂公開、可列印。 新增一條機密等級代號9允許列印

指定允許被開啟列印的ISO文件,將文件的機密等級設定為「9」。指定允許列印的表單文件權限為「9 」

最後就完成了,ISO文件一覽表中加載了列印連結。ISO文件一覽表增加表單列印

Easyflow.NET 表單預設 AjaxPro function 運用

在Easyflow使用表單精靈建立的新表單,都能在C#的檔案中找到類似下面這樣的程式碼片段。這些是用 AjaxPro 函式庫所寫的程式碼片段。

#region AjaxMethod()
#region GetEmployeeId
		///
<summary>
		/// 取得員工 ID
		/// </summary>
		/// 回傳員工 ID(string)
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetEmployeeId()
			{
				return this.UserInfo.EmployeeId.ToString().Trim();
			}
#endregion

#region GetLoginName
		///
<summary>
		/// 取得登入者員工姓名
		/// </summary>
		/// 回傳員工姓名(string)
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetLoginName()
			{
				return this.UserInfo.LoginName.ToString().Trim();
			}
#endregion

#region GetAgentID
		///
<summary>
		/// 取得代理人員工 ID
		/// </summary>
		/// 回傳代理人員工 ID(string)
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetAgentID()
			{
				return base.StrAgentID.ToString().Trim();
			}
#endregion

#region GetAgentName
		///
<summary>
		/// 取得代理人姓名
		/// </summary>
		/// 回傳代理人姓名(string)
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetAgentName()
			{
				string tAgentName = "";
				UserInfoClass tClass = (UserInfoClass)Session["UserInfo"];
				string mCompany = tClass.Company;
				DBCommand dbCommand = DscDBData.GetDataDBCommand();
				DataTable tDt = new DataTable();
				StringBuilder tSql = new StringBuilder();
				tSql.AppendFormat("SELECT resak002 FROM {0}..resak AS resak ", mCompany);
				tSql.AppendFormat("WHERE resak001 = '{0}' ", base.StrAgentID.ToString().Trim());
				tDt = dbCommand.Query(tSql.ToString());
				if (tDt.Rows.Count > 0)
				{
					tAgentName = tDt.Rows[0]["resak002"].ToString().Trim();
				}
				return tAgentName;
			}
#endregion

#region GetDepartmentId
		///
<summary>
		/// 取得部門 ID
		/// </summary>
		/// 回傳部門 ID(string)
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetDepartmentId()
			{
				string tDeptID = "";
				UserInfoClass tClass = (UserInfoClass)Session["UserInfo"];
				tDeptID = m_objRE.FindEmplDeptID(tClass.EmployeeId.ToString().Trim(), m_strProcID);
				return tDeptID;
			}
#endregion

#region GetDepartmentName
		///
<summary>
		/// 取得部門名稱
		/// </summary>
		/// 回傳部門名稱(string)
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetDepartmentName()
			{
				string tDeptName = "";
				string tDeptID = "";
				UserInfoClass tClass = (UserInfoClass)Session["UserInfo"];
				tDeptID = m_objRE.FindEmplDeptID(tClass.EmployeeId.ToString().Trim(), m_strProcID);
				tDeptName = m_objRE.FindDeptName(tDeptID, m_strProcID);
				return tDeptName;
			}
#endregion

#region GetEFDBFieldValue
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetEFDBFieldValue(string pSql, string pFieldName)
			{
				string tResult = "";
				UserInfoClass tClass = (UserInfoClass)Session["UserInfo"];
				string mCompany = tClass.Company;
				DBCommand dbCommand = DscDBData.GetDataDBCommand();
				DataTable tDt = new DataTable();
				string tSql = pSql;
				tDt = dbCommand.Query(tSql);
				if (tDt.Rows.Count > 0)
				{
					tResult = tDt.Rows[0]["\""+pFieldName+"\""].ToString().Trim();
				}
				return tResult;
			}
#endregion

#region GetOtherDBFieldValue
		[AjaxPro.AjaxMethod(AjaxPro.HttpSessionStateRequirement.ReadWrite)]
			public string ajaxGetOtherDBFieldValue(string pDBType,string pSql,string pConn,string pFieldName)
			{
				string tResult = "";
				DataSet tDs = new DataSet();
				if (pDBType == "SqlServer")
				{
					SqlConnection tDbConnection = new SqlConnection(pConn);
					tDbConnection.Open();
					SqlDataAdapter tAdpt = new SqlDataAdapter(pSql, pConn);
					tAdpt.Fill(tDs, "Result");
				}
				else if (pDBType == "Oracle")
				{
					OracleConnection tDbConnection = new OracleConnection (pConn);
					tDbConnection.Open();
					OracleDataAdapter tAdpt = new OracleDataAdapter (pSql, pConn);
					tAdpt.Fill(tDs, "Result");
				}
				else if (pDBType == "OleDb")
				{
					OleDbConnection tDbConnection = new OleDbConnection (pConn);
					tDbConnection.Open();
					OleDbDataAdapter tAdpt = new OleDbDataAdapter (pSql, pConn);
					tAdpt.Fill(tDs, "Result");
				}
				else if (pDBType == "Odbc")
				{
					OdbcConnection tDbConnection = new OdbcConnection (pConn);
					tDbConnection.Open();
					OdbcDataAdapter tAdpt = new OdbcDataAdapter (pSql, pConn);
					tAdpt.Fill(tDs, "Result");
				}

				DataTable tDt = tDs.Tables["Result"];
				if (tDt != null)
				{
					if (tDt.Rows.Count > 0)
					{
						tResult = tDt.Rows[0]["\""+pFieldName+"\""].ToString().Trim();
					}
				}
				return tResult;
			}
#endregion

既然已經有現成的Ajax可以取得關於表單相關的資訊,為何不拿來好好利用呢?那該如何使用由 AjaxPro 函式庫,所提供出來的Ajax呢?可以像下面這樣來取得值..

<script type="text/javascript">
            $(function () {                                alert(tw.com.dsc.easyflowDotNet.forms.TEST2.ajaxGetEmployeeId().value);                
            });

</script>

上面有些地方需要說明:

  • 1. tw.com.dsc.easyflowDotNet 是命名空間,需加在類別之前。
  • 2. TEST2 是表單的類別名稱,需要加在命名空間及Ajax後端函式的中間。
  • 綜合上述兩點在前端叫用Ajax函式時像是這樣 「命名空間.表單類別.Ajax後端函式([參數值…])」。

為什麼使用方法很簡單呢?因為Easyflow已經將Ajaxpro函式庫的DLL檔引用進入網頁應用程式,並也已經設定Web.config設定檔註冊HttpHandler,並在表單後端Page_Load時註冊包含Ajax函式的類別。如果想了解 AjaxPro 從安裝到使用的詳細說明,可以造訪 http://www.ajaxpro.info/ 網站。

Easyflow.NET 程式更新流程說明 開單加流程、流程中增減修改流程

對於 Easyflow 執行流程增減修改等動作中,比較有關聯的資料表有三個:

  • 表單流程異動子檔(RESDB):紀錄表單所有的流程關卡,新增刪除或更新都由此表來操作。
  • 表單流程異動明細檔(RESDC):紀錄表單流程已確定完成簽核的關卡簽核狀態。
  • 表單流程異動明細簽核檔(RESDD):紀錄表單流程簽核中的所有詳細的歷程,例如: 對同流程關卡經歷多次上呈、退件的動作,每一次的簽核結果都會被詳盡紀錄。

無意間在網路上找到「程式碼控制流程說明文件」。雖然這是ASP版本的說明文件,但是文章中講到對流程控制時所使用的物件架構,在Dot.NET版本中它有被延用下來且物件名稱都一樣。

  • rstTRFlow:「resdb」資料表物件,使用時機 流程簽核中。
  • rstTRFlowDetail:「resdc」資料表物件,使用時機 流程簽核中。
  • rstTRFlowApprove:「resdd」資料表物件,使用時機 流程簽核中。

在開單時可利用覆寫「BeforeSendNewFormAddFlow」函式,在送出來表單時手動加入新的流程關卡。※「TRFlowRESDB」類別所建立的物件,可以在開單時新增流程資訊。

		protected override void BeforeSendNewFormAddFlow(TRFlowRESDB[] xFlowData, ref bool xBlnFlowChanged)
		{
			xBlnFlowChanged = false; //不要重新解析流程
			int rows_count = MasterObj.DetailObjs[0].NewRows.Count;//取得grid有幾列資料
			xFlowData = new TRFlowRESDB[rows_count];//宣告流程物件陣列及其大小
			int resdb003=9901,index=0;//迴圈用的變數,流程關號、流程物件索引
			//送出表單時插入自訂流程使用 MasterObj.DetailObjs[0].NewRows 物件
			//DetailObjs[0]代表第一個Grid物件
			//NewRows代表尚未存入資料庫的資料
			foreach (DscRow dscRow in MasterObj.DetailObjs[0].NewRows)
			{
				if (!dscRow.IsDeleted)
				{
					xFlowData[index].resdb001 = formID; //表單代號
					xFlowData[index].resdb002 = SheetNo; //表單單號
					xFlowData[index].resdb003 = resdb003.ToString(); //關號
					xFlowData[index].resdb004 = "0010"; //支號
					xFlowData[index].resdb005 = 1; //流程角色
					xFlowData[index].resdb006 = 4; //簽核種類
					xFlowData[index].resdb007 = dscRow["empl1"].Value.ToString(); //流程角色參數1 (Grid物件中取得的員工編號值,中括號中填入"欄位名稱")
					xFlowData[index].resdb008 = ""; //流程角色參數2
					xFlowData[index].resdb009 = ""; //流程角色參數3
					xFlowData[index].resdb010 = ""; //流程角色參數4
					xFlowData[index].resdb011 = 0;  //容許簽核時間
					xFlowData[index].resdb012 = "N"; //自動ByPass?
					xFlowData[index].resdb013 = "0"; //ByPass方式
					xFlowData[index].resdb014 = "Y"; //是否強制簽核?
					xFlowData[index].resdb015 = "Y"; //是否單一簽核
					xFlowData[index].resdb016 = "N"; //可否列印?
					xFlowData[index].resdb017 = "Y"; //可否撤簽?
					xFlowData[index].resdb018 = "Y"; //可否加簽?
					xFlowData[index].resdb019 = "N"; //可否轉會?
					xFlowData[index].resdb020 = "N"; //可否轉寄?
					xFlowData[index].resdb021 = "N"; //可否新增附加檔?
					xFlowData[index].resdb022 = "N"; //可否修改附加檔?
					xFlowData[index].resdb023 = "N"; //可否刪除附加檔?
					xFlowData[index].resdb024 = "Y"; //可否閱讀附加檔?
					xFlowData[index].resdb025 = "N"; //簽核時密碼驗證?
					xFlowData[index].resdb026 = "N"; //流程是否已經解析?
					xFlowData[index].resdb027 = ""; //流程提示訊息
					xFlowData[index].resdb028 = ""; //
					xFlowData[index].resdb029 = ""; //
					resdb003++;
					index++;
				}
			}
			base.BeforeSendNewFormAddFlow(xFlowData, ref xBlnFlowChanged);
		}

而在流程簽核中則以覆寫「BeforeApprove」、「AfterApprove」這兩個函式來處理流程關卡的新增、刪除、修改。在這兩個函式中就可以使用 RstTRFlow、RstTRFlowApprove、RstTRFlowDetail 這三個物件來操作他們所對應的表單資料。

#region 簽核前處理
		protected override void BeforeApprove(PublicUTIL.DBProcessor processor)
		{
			base.BeforeApprove(processor);
			//取得單身欄位資料
			string sql_command = @"select empl1 from [EFNETDB].[dbo].[test2_2] where test2_2001='{0}' and test2_2002='{1}' ";
			sql_command = String.Format(sql_command, this.formID, this.SheetNo);
			SqlDataAdapter my_adapter = processor.getDataAdapter(sql_command);
			DataTable my_table= new DataTable();
			my_adapter.Fill(my_table);

			if (AryFlowProperty.SerialSignResult == "2") //同意
			{
				//如果關號是0010,則手動塞流程
				if (this.FlowNo == "0010")
				{
					foreach (DataRow my_resdd_row in RstTRFlowApprove.Tables[0].Select("resdd003 like '2%'"))
					{
						my_resdd_row.Delete();
					}
					foreach (DataRow my_resdc_row in RstTRFlowDetail.Tables[0].Select("resdc003 like '2%'"))
					{
						my_resdc_row.Delete();
					}
					foreach (DataRow my_resdb_row in RstTRFlow.Tables[0].Select("resdb003 like '2%'"))
					{
						my_resdb_row.Delete();
					}

					int resdb003=20;
					foreach( DataRow my_row in my_table.Rows )
					{
						DataRow my_datarow = RstTRFlow.Tables[0].NewRow();//流程資料表建立一新的資料列
						//開始設定資料列相關資資料
						my_datarow["resdb001"] = formID;
						my_datarow["resdb002"] = SheetNo;
						my_datarow["resdb003"] = resdb003.ToString()+DateTime.Now.Second.ToString("00");
						my_datarow["resdb004"] = "0010"; //支號
						my_datarow["resdb005"] = 1; //流程角色
						my_datarow["resdb006"] = 4; //簽核種類
						my_datarow["resdb007"] = my_row["empl1"].ToString(); //流程角色參數1 (Grid物件中取得的員工編號值,中括號中填入"欄位名稱")
						my_datarow["resdb008"] = ""; //流程角色參數2
						my_datarow["resdb009"] = ""; //流程角色參數3
						my_datarow["resdb010"] = ""; //流程角色參數4
						my_datarow["resdb011"] = 0;  //容許簽核時間
						my_datarow["resdb012"] = "N"; //自動ByPass?
						my_datarow["resdb013"] = "0"; //ByPass方式
						my_datarow["resdb014"] = "Y"; //是否強制簽核?
						my_datarow["resdb015"] = "Y"; //是否單一簽核
						my_datarow["resdb016"] = "N"; //可否列印?
						my_datarow["resdb017"] = "Y"; //可否撤簽?
						my_datarow["resdb018"] = "Y"; //可否加簽?
						my_datarow["resdb019"] = "N"; //可否轉會?
						my_datarow["resdb020"] = "N"; //可否轉寄?
						my_datarow["resdb021"] = "N"; //可否新增附加檔?
						my_datarow["resdb022"] = "N"; //可否修改附加檔?
						my_datarow["resdb023"] = "N"; //可否刪除附加檔?
						my_datarow["resdb024"] = "Y"; //可否閱讀附加檔?
						my_datarow["resdb025"] = "N"; //簽核時密碼驗證?
						my_datarow["resdb026"] = "N"; //流程是否已經解析?
						my_datarow["resdb027"] = ""; //流程提示訊息
						my_datarow["resdb028"] = ""; //
						my_datarow["resdb029"] = ""; //
						RstTRFlow.Tables[0].Rows.Add(my_datarow);//將資料列插入流程資料表中
						resdb003++;
					}
				}
			}
		}
#endregion

		protected override void AfterApprove()
		{
			base.AfterApprove();
		}

p.s:以上的程式碼片段僅為測試說明用,實際上可能未能符合流程關卡新增刪除相關資料表依存邏輯。

MSSQL 使用 OPENROWSET 插入或更新檔案到資料型態是「varbinary(max)」的欄位

由於Easyflow的ISO文管人員在沒有注意文件內容是否正確的情況下就將新版文件發佈,隔天才發現發佈檔案有問題。但依照Easyflow ISO文管運作流程,當文件發佈後如果需要進行修正就要做一次文件版本更新。這樣的作法費時又費工,如果可以直接置換存放於資料庫中的檔案內容或許是一個比較簡的作法。

在MSSQL的資料庫中,可以利用內建函式「OPENROWSET」來將檔案塞入到欄位中。使用「OPENROWSET」可以當作是一個子查詢,而這個子查詢的來源資料表就是實體檔案的存放路徑(以SQLSERVER本機的路徑為基準、或是可以存取的網芳資料夾中的檔案路徑)。

注意!必須要給子查詢指定一個別名,否則在執行操作中會出現錯誤。

以下的範例是置換文件編號為「TQP-G001」發佈版本為「C」所對應到的發佈檔案,置換為網芳分享資料夾中的檔案。

update isoebb set isoebb010 =
(select * FROM OPENROWSET(bulk N'\\192.168.128.189\temp\廢棄物管理程序.pdf', SINGLE_BLOB ) as binary_file )
where isoebb005='TQP-G001' and isoebb006='C'

Easyflow.NET 如何在簽核中加入新的流程關卡

這次要在表單簽核流程中由程式判斷手動塞入新的流程關卡。所用的變數和先前開單塞流程中使用的是不一樣,至於為什麼不能用開單中所使用的變數我也不知道為何。相同的這次還是由雙檔表單的子單身中紀錄的人員作為塞入的流程關卡來作為操作範例。

一、取得紀錄 Grid 單身中人員的員工編號是使用 Easyflow 物件中內建的方法processor.getDataAdapter(sql_command) 直接由資料庫中抓取資料並填入 DataTable 物件的變數之中。在取得人員資料後就可以利用迴圈,將流程塞入表單流程異動子檔資料表中。

二、插入流程 於流程中使用表單流程資料表物件的方法「RstTRFlow.Tables[0].Add(my_datarow)」加入新的流程關卡。在這之前先必須藉由 「RstTRFlow.Tables[0].NewRow()」物件方法新增一個「DataRow」資料列件件(流程關卡資料列),再將這資料列物件的「key-value」資料補齊(設定方法如陣列元素給值那樣)。

函式「BeforeApprove」程式碼範例(完整檔案範例 TEST2.aspx.cs

	#region 簽核前處理
    protected override void BeforeApprove(PublicUTIL.DBProcessor processor)
    {
        base.BeforeApprove(processor);
        //取得單身欄位資料
        string sql_command = @"select empl1 from [EFNETDB].[dbo].[test2_2] where test2_2001='{0}' and test2_2002='{1}' ";
        sql_command = String.Format(sql_command, this.formID, this.SheetNo);
        SqlDataAdapter my_adapter = processor.getDataAdapter(sql_command);
        DataTable my_table= new DataTable();
        my_adapter.Fill(my_table);

        if (AryFlowProperty.SerialSignResult == "2") //同意
        {
            //如果關號是0010,則手動塞流程
            if (this.FlowNo == "0010")
            {
                int resdb003=9901;
                foreach( DataRow my_row in my_table.Rows )
                {
                        DataRow my_datarow = RstTRFlow.Tables[0].NewRow();//流程資料表建立一新的資料列
                        //開始設定資料列相關資資料
                        my_datarow["resdb001"] = formID;
                        my_datarow["resdb002"] = SheetNo;
                        my_datarow["resdb003"] = resdb003;
                        my_datarow["resdb004"] = "0010"; //支號
                        my_datarow["resdb005"] = 1; //流程角色
                        my_datarow["resdb006"] = 4; //簽核種類
                        my_datarow["resdb007"] = my_row["empl1"].ToString(); //流程角色參數1 (Grid物件中取得的員工編號值,中括號中填入"欄位名稱")
                        my_datarow["resdb008"] = ""; //流程角色參數2
                        my_datarow["resdb009"] = ""; //流程角色參數3
                        my_datarow["resdb010"] = ""; //流程角色參數4
                        my_datarow["resdb011"] = 0;  //容許簽核時間
                        my_datarow["resdb012"] = "N"; //自動ByPass?
                        my_datarow["resdb013"] = "0"; //ByPass方式
                        my_datarow["resdb014"] = "Y"; //是否強制簽核?
                        my_datarow["resdb015"] = "Y"; //是否單一簽核
                        my_datarow["resdb016"] = "N"; //可否列印?
                        my_datarow["resdb017"] = "Y"; //可否撤簽?
                        my_datarow["resdb018"] = "Y"; //可否加簽?
                        my_datarow["resdb019"] = "N"; //可否轉會?
                        my_datarow["resdb020"] = "N"; //可否轉寄?
                        my_datarow["resdb021"] = "N"; //可否新增附加檔?
                        my_datarow["resdb022"] = "N"; //可否修改附加檔?
                        my_datarow["resdb023"] = "N"; //可否刪除附加檔?
                        my_datarow["resdb024"] = "Y"; //可否閱讀附加檔?
                        my_datarow["resdb025"] = "N"; //簽核時密碼驗證?
                        my_datarow["resdb026"] = "N"; //流程是否已經解析?
                        my_datarow["resdb027"] = ""; //流程提示訊息
                        my_datarow["resdb028"] = ""; //
                        my_datarow["resdb029"] = ""; //
                        RstTRFlow.Tables[0].Rows.Add(my_datarow);//將資料列插入流程資料表中
                        resdb003++;
                }
            }
        }
    }
 #endregion

執行步驟說明:

程式碼 BeforeApprove 範例片段,利用這個函式在指定的關卡完成審核動作前加入新的流程關卡。

建立一張測試表單,加入兩位員工於單身中。

表單送出後,流程解析為兩關。

在第二關流程畫面中,解析流程已有新的流程加入。

第三關流程解析畫面

最後表單完成簽核

Easyflow.NET 表單送出時,依Grid中的員工編號做為手動塞流程的關卡

由雙檔架構表單的單身(Grid)所儲存的員工編號欄位值,來當作程式手動塞流程的員工編號值(流程參數1的值)。此次的重點在於知道Grid的物件是什麼及如何從Grid物件中取得指定欄位的值。

表單後端程式碼完整範例「TEST2.aspx.cs」
範例程式碼片段:

protected override void BeforeSendNewFormAddFlow(TRFlowRESDB[] xFlowData, ref bool xBlnFlowChanged)
{
	xBlnFlowChanged = false; //不要重新解析流程
	int rows_count = MasterObj.DetailObjs[0].NewRows.Count;//取得grid有幾列資料
	xFlowData = new TRFlowRESDB[rows_count];//宣告流程物件陣列及其大小
	int resdb003=9901,index=0;//迴圈用的變數,流程關號、流程物件索引
	//送出表單時插入自訂流程使用 MasterObj.DetailObjs[0].NewRows 物件
	//DetailObjs[0]代表第一個Grid物件(第一個子單身)
	//NewRows代表尚未存入資料庫的資料
	foreach (DscRow dscRow in MasterObj.DetailObjs[0].NewRows)
	{
		if (!dscRow.IsDeleted)
		{
			xFlowData[index].resdb001 = formID; //表單代號
			xFlowData[index].resdb002 = SheetNo; //表單單號
			xFlowData[index].resdb003 = resdb003.ToString(); //關號
			xFlowData[index].resdb004 = "0010"; //支號
			xFlowData[index].resdb005 = 1; //流程角色
			xFlowData[index].resdb006 = 4; //簽核種類
			xFlowData[index].resdb007 = dscRow["empl1"].Value.ToString(); //流程角色參數1 (Grid物件中取得的員工編號值,中括號中填入"欄位名稱")
			xFlowData[index].resdb008 = ""; //流程角色參數2
			xFlowData[index].resdb009 = ""; //流程角色參數3
			xFlowData[index].resdb010 = ""; //流程角色參數4
			xFlowData[index].resdb011 = 0;  //容許簽核時間
			xFlowData[index].resdb012 = "N"; //自動ByPass?
			xFlowData[index].resdb013 = "0"; //ByPass方式
			xFlowData[index].resdb014 = "Y"; //是否強制簽核?
			xFlowData[index].resdb015 = "Y"; //是否單一簽核
			xFlowData[index].resdb016 = "N"; //可否列印?
			xFlowData[index].resdb017 = "Y"; //可否撤簽?
			xFlowData[index].resdb018 = "Y"; //可否加簽?
			xFlowData[index].resdb019 = "N"; //可否轉會?
			xFlowData[index].resdb020 = "N"; //可否轉寄?
			xFlowData[index].resdb021 = "N"; //可否新增附加檔?
			xFlowData[index].resdb022 = "N"; //可否修改附加檔?
			xFlowData[index].resdb023 = "N"; //可否刪除附加檔?
			xFlowData[index].resdb024 = "Y"; //可否閱讀附加檔?
			xFlowData[index].resdb025 = "N"; //簽核時密碼驗證?
			xFlowData[index].resdb026 = "N"; //流程是否已經解析?
			xFlowData[index].resdb027 = ""; //流程提示訊息
			xFlowData[index].resdb028 = ""; //
			xFlowData[index].resdb029 = ""; //
			resdb003++;
			index++;
		}
	}
	base.BeforeSendNewFormAddFlow(xFlowData, ref xBlnFlowChanged);
}

流程角色及流程角色參數設定參考

範例說明:
新增一個雙檔的表單,其中單頭只有一個 Textbox 輸入框,然後用 Grid 物件建立單身而單身也僅有放一個DSC內建的員工選單。(注意:被加入單身的人員會變成表單流程的關卡)

原始的流程設置,只有一個關卡(直屬主管)。

修改表單後端的程式碼,複寫函式「BeforeSendNewFormAddFlow」。這樣做可以在表單送出前經由程式修改的內容,將所選取的人員做為關卡插入於原始流程關卡之後。「BeforeSendNewFormAddFlow」函式預設是不會出現在後端程式碼的檔案中,我們需要手動將這段函式的程式碼區塊放到表單類別裏。

修改完成之後,重新開啟測試表單。將人員選擇加入單身之中,接著按下表單送出按鈕。此時表單流程顯示就會出現我們剛剛所加入人員的流程關卡。