BPM 客製教學(3) 表單 trigger 入門教學| 一等一科技 DLL UOF2 | EIP | Getting Start

by | 8 月 4, 2025 | 一等一UOF系統, 程式 | 0 comments

Views: 83

我們目標是寫一支DLL,在申請者送出後讀取表單資料,然後將資料存到資料表Z_TRIGGER_TEST

Trigger用途

在BPM模組中,我們如果需要這幾樣功能,透過Trigger比較容易,這功能其實是所謂的hook,但在UOF2稱為TRIGGER

  1. 申請者送出表單時取到電子表單的內容並寫到特定的資料表
  2. 申請者送出將表單內容送去外部系統
  3. 在流程中將欄位填入特定資料,例如將評比分數轉換為ABC

前置準備

  1. 先把UOF2安裝好,我安裝到C:\Web\UOFTEST\,這篇教學使用的是v28版,官方2025公班導入時提供的版本
  2. 創好一個帳號(不建議用admin),然後可以設定為系統管理員
  3. Visual Studio 2022,我使用的是社群版本

Getting Start

創立專案

VISUAL STUDIO 2022 > 新增 類別庫專案(.Net Framwork) 英文版是Class Library(.NET Framwork)

Image

這邊要注意要選有(.NET Framwork的),然後.Net Framework版本要選4.8

創好之後刪除Class1.cs

Image

加入必要的參考元件

Image

選擇 瀏覽Browse > Browse..瀏覽,接著找到網站的bin資料夾,我的是C:\WEB\UOFTEST\bin,然後直接貼底下列出的黨名

(印象中這是公班導入時老師建議的常用DLL)

  1. Quartz.dll 排程有關的
  2. Ede.Uof.EIP.Organization.dll 組織有關的
  3. Ede.Uof.EIP.Organization.Util.dll 組織有關的
  4. Ede.Uof.EIP.Plant.dll 設備借用有關的
  5. Ede.Uof.EIP.ResourceLibrary.dll
  6. Ede.Uof.EIP.Schedule.CalendarSync.dll 行事曆有關的
  7. Ede.Uof.EIP.Schedule.Common.dll 行事曆有關的
  8. Ede.Uof.EIP.Schedule.Corporation.dll 行事曆有關的
  9. Ede.Uof.EIP.Schedule.dll 行事曆有關的
  10. Ede.Uof.EIP.Schedule.Report.dll 行事曆有關的
  11. Ede.Uof.EIP.SystemInfo.dll
  12. Ede.Uof.Utility.Data.dll
  13. Ede.Uof.Utility.dll 大部分重要的函數都在這邊
  14. Ede.Uof.Utility.Log.dll
  15. Ede.Uof.Utility.Message.dll 寄信有關
  16. Ede.Uof.Utility.Page.Common.dll 頁面元件有關
  17. Ede.Uof.Utility.Page.dll
  18. Ede.Uof.Utility.Task.dll 排程有關
  19. Ede.Uof.WKF.Design.dll 電子表單有關
  20. Ede.Uof.WKF.dll 電子表單有關
  21. Newtonsoft.Json.dll 物件轉JSON有關

加完後按下OK

加入檔案後

加入後可以在參考(Reference看到)

表單簽核事件

一等一UOF2的表單總共有幾個事件

  1. 起單
  2. 簽核
  3. 結案
  4. 取回
  5. 作廢
  6. 變更狀態(表單管理員)

比較常用的是前三個狀態

Image

設計一個TRIGGER測試表單

表單名稱:測試TRIGGER

表單設定

通常我不勾「預設儲存副本」,跟不勾「下一站若為相同簽核者則跳過」

表單設定

Image

設計表單

我們一開始欄位不用多,只需幾個代表性欄位

  1. 表單編號(DOC_NBR)
  2. 申請者(APPLICICATE)
  3. 申請者部門(APPLICICATE_DEPT)
  4. 單行文字(SINGLE_TEXT)
  5. 申請日期(APPLY_DATE)

欄位

加入流程

設計完成後加入流程,這邊測試上就加入兩個申請者就好。

流程

發佈表單

發佈表單

TRIGGER命名

  • 單一Trigger:如果沒有要把起單、簽核、結案等表單不同階段分開為不同triiger,這邊直接用Trigger就好。
  • 多個Trigger:起單、簽核、結案等表單不同階段分開為不同Trigger
    • 起單:TriggerStart
    • 簽核:TriggerSign
    • 結案:TriggerFinish
    • 作廢:TriggerCancel
    • 退回:TriggerReturn

常用的是這五種

開始寫TRIGGER

我們目標是讀取表單資料,然後將資料存到資料表Z_TRIGGER_TEST

新增 Trigger.cs

add class

Trigger.cs

對專案按下Add之後選Class後,輸入Trigger.cs

Image

這邊要做幾件事

Image

  1. 可見度改為public
  2. 繼承兩個介面ICallbackTriggerPlugin
  3. 加入using Ede.Uof.WKF.ExternalUtility; ,這個通常會自動加入,如果沒加入的話自己加一下,如果Visual Studio顯示找不到的話,應該是沒將對應的dll加入參考,請補一下。

實做Trigger介面

Trigger

這邊Visual Studio有自動實做的功能,先將滑鼠移到1紅線處,接著點出來的2小圖,然後選3 implement interface

Image

實做後我們要先把 throw都刪除,然後在GetFormResult()加入一個Return "" ;

Image

改完之後如圖。

之後我們目標在GetFormResult(),其他兩個方法不用理會

取得表單XML內容

表單送出後會存入XML,要取得的話有兩個方法

  1. 從資料庫的TB_WKF_TASK資料表用表單編號查詢
  2. applyTask取得表單的內容

從資料庫取得

表單的最後狀態在UOF2系統中是儲存在資料表TB_WKF_TASK ,可以透過SQL查詢取得,不過我寫Trigger不太用這個方式。

SELECT TOP (1) [CURRENT_DOC] FROM [dbo].[TB_WKF_TASK] WHERE [DOC_NBR] = '表單編號'

從applyTask取得

寫法關鍵在於 透過applyTask.CurrentDocXML可以拿到XML的內容,然後通常我會存到硬碟中,整個寫起來作法如下。

using Ede.Uof.Utility.Data;
using Ede.Uof.WKF.ExternalUtility;
using System;
using System.Xml;

namespace UOF_DEV
{
    public class Trigger : ICallbackTriggerPlugin
    {
        public void Finally()
        {
            
        }

        public string GetFormResult(ApplyTask applyTask)
        {
            //取得表單編號
            string DOC_NBR = applyTask.FormNumber;

            //將目前表單內容讀到 doc物件當中
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(applyTask.CurrentDocXML);

            //儲存表單xml內容到硬碟中
            doc.Save($"C:\\UOF_DEBUG\\{DOC_NBR}{DateTime.Now:yyyy-MM-dd-hh-mm-ss}.xml");

            //故意失敗,用於重複測試使用
            throw new Exception("For TEST");
            return "";
        }

        public void OnError(Exception errorException)
        {
            
        }
    }
}

Trigger的部分我們先寫到這,先來讓系統可以自動呼叫Trigger,這邊我多加了一個故意讓方法失敗的Exception,這是個開發上的小技巧,有了這個就能透過重送功能直接測試Trigger。

建立UOF_DEBUG資料夾

我將XML將資料儲存到C:\UOF_DEBUG資料夾中,這個資料夾要先手動建立+賦予帳號iis apppool\應用程式集區名稱寫入權限

設定編譯路徑

我通常設定編譯後直接送至bin資料夾。

對專案按下右鍵,選擇屬性Properties

Image

Image

這邊直接從檔案總管複製路徑,貼到Output path就好,完成後儲存與關閉。

Image

測試編譯

Image

測試編譯UOF_DEV,對專案按下滑鼠右鍵,選擇Build(建置)

Image

編譯後應該可以在bin資料夾中看到跟專案同名的dll檔案

外部組件註冊-註冊DLL

外部組件註冊

Image
Image
  • 分類:我有先建立一個TEST的分類,這邊就看需求去規劃你的分類
  • 外部組件名稱:這個不是檔名,通常是取表單名稱+事件名稱,例如表單AA-起單表單AA-簽核中表單AA-結案等,這邊用於之後表單事件的選擇辨認DLL用途。
  • DLL:名稱,這邊要帶入DLL檔名,但不需要副檔名.dll
  • 組件路徑:namespace+class名稱,通常是專案名稱+類別名稱,所以在這邊我填入UOF_DEV.Trigger

這邊KEY好之後按下「確定」,存檔離開。

設定表單事件要呼叫的Trigger

電子簽核 表單設計

同樣轉到表單設計

選擇表單後 維護表單

選擇表單 > 維護表單

選擇剛剛設定好的組件

接著在這幾個項目選擇剛剛的組件,選好了之後按下確定。

測試送單

換個帳號(不要用admin)

Image

電子簽核 >>表單申請

Image

選擇表單>>填寫表單

填寫表單

將一般帳號加入系統管理員

通常在本機開發時測試表單我都會用一般帳號測試,但會將這個一般帳號設定為系統管理員,不熟一等一科技EIP的朋友也別擔心,步驟如下

先用admin帳號登入,預設密碼為123456

Image

系統管理>管理員設定

Image

選系統管理員 > 選取人員 之後選擇你的帳號就能新增

觀看DLL呼叫情形

這個功能需要系統管理員才看的到

Image

電子簽核 >> 呼叫DLL狀態查詢

Image

接著點表單 > 查詢,如果正常的話可以看見一個傳送失敗 or (傳送成功),如果都沒看到的話要到表單設計>維護表單>進階設定看DLL那邊設定有沒有選。

接著滑鼠點表單編號,可以看到傳送狀態

Image

Image

點進去後應該可以看見程式末端拋出來的Exception For TEST,這代表之前到這個步驟你應該都做成功了。

拆解XML

Image

XML我們已經透過trigger另存成一個檔案,可以在檔案總管找到它,我的是存在C:\UOF_DEBUG\,這邊的小技巧是可以讓檔案照時間排序。

接著使用notepad++開啟檔案內容

Image

這邊你可以發現資料大致上是這樣

  • fildId = 欄位名稱
  • feildValue = 欄位內容
  • realValue = 另一種欄位內容 ,人員組織多半這樣放

寫Model

我習慣靠 Dapper 這類 ORM 替代 ADO.NET (傳統的 .NET 資料庫讀寫套件),寫得比較快而且比較不會出錯。

我們先把對應的 Model 寫出來,用途是我們寫一個物件,物件的屬性就是對應資料庫欄位,這樣靠 Dapper 寫資料庫 CRUD 時候就能自動幫我們進行對應,減少要寫的程式碼。

整理一下欄位(這個案例中都是string)

  • DOC_NBR 表單編號
  • APPLICICATE 申請者
  • APPLICICATE_DEPT 申請者部門
  • APPLY_DATE 申請日期,這個用DateTime類型
  • SINGLE_TEXT 單行文字

另外還有兩個狀態欄位建議加上去(都是string)

  • TASK_STATUS 表單工作狀態: 1處理中, 2結案, 3異常, 4退回
  • TASK_RESULT 表單申請結果: 0核准, 1否決, 2作廢, NULL簽核中

資料表在這邊我取名為 Z_TEST_TRIGGER ,因此新增一個類別檔案 Z_TEST_TRIGGER.cs

Image

Z_TEST_TRIGGER.cs內容如下:

using System;

namespace UOF_DEV
{
    /// <summary>
    /// 測試用的表單 對應資料表 Z_TEST_TRIGGER
    /// </summary>
    public class Z_TEST_TRIGGER
    {
        /// <summary>
        /// 表單編號
        /// </summary>
        public string DOC_NBR { get; set; }

        /// <summary>
        /// 申請人
        /// </summary>

        public string APPLICICATE { get; set; }

        /// <summary>
        /// 申請者部門
        /// </summary>

        public string APPLICICATE_DEPT { get; set; }

        /// <summary>
        /// 申請日期
        /// </summary>
        public DateTime APPLY_DATE { get; set; }

        /// <summary>
        /// 單行文字測試
        /// </summary>
        public string SINGLE_TEXT { get; set; }

        /// <summary>
        /// 表單工作狀態: 1處理中, 2結案, 3異常, 4退回
        /// </summary>
        public string TASK_STATUS { get; set; }

        /// <summary>
        /// 表單申請結果: 0核准, 1否決, 2作廢, NULL簽核中
        /// </summary>
        public string TASK_RESULT { get; set; }
    }
}

接著在資料庫新增資料表,這邊我使用SSMS的介面操作

Image

Image

這邊依照需求寫資料,注意記得將DOC_NBR設定為PK(主鍵)

一些處理的函數

(這邊其實靠ChatGPT就好)

我在這裡提供幾個方便的函數,可以學我將這些寫成Trigger共用DLL,但先這樣用

  • GetFieldValue 取得XML中FieldValue的值
  • TryParseDateTime 字串轉DateTime
  • GetFormTaskStatus 將表單狀態轉為數字
  • GetFormTaskResult 將申請結果轉為數字
/// <summary>
/// 取出XML字串的值
/// </summary>
/// <param name="doc"></param>
// <param name="fieldId"></param>
/// <returns></returns>
private string GetFieldValue(XmlDocument doc, string fieldId)
{
  return doc.SelectSingleNode($"//FieldItem[@fieldId='{fieldId}']")?.Attributes["fieldValue"]?.Value;
}

/// <summary>
/// 字串轉DateTime
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private DateTime? TryParseDateTime(string value)
{
    if (DateTime.TryParse(value, out DateTime result))
        return result;
    return null;
}

/// <summary>
///表單狀態
/// </summary>
/// <param name="applyTask">
/// </param>
/// <returns>
/// 1 = 處理中
/// 2 = 結案
/// 3 = 異常
/// 4 = 退回
/// </returns>
public static string GetFormTaskStatus(ApplyTask applyTask)
{
    try
    {
        // 結案
        // 如果 TaskStatus 不是 Active,返回 "2結案"
        if (applyTask.Task.TaskStatus != ActiveStatus.Active)
        {
            return "2";
        }

        //退回申請者
        // 檢查 SignResult 為 ReturnToAppliant 退回申請者 且 TaskStatus 為 Active,返回 "4退回"
        if (applyTask.SignResult == SignResult.ReturnToAppliant &&
            applyTask.Task.TaskStatus == ActiveStatus.Active)
        {
            return "4";
        }

        // 退回某人
        // 檢查 SignResult 為 Return 且 TaskStatus 為 Active,返回 "1處理中"
        if (applyTask.SignResult == SignResult.Return && applyTask.Task.TaskStatus == ActiveStatus.Active)
        {
            return "1";
        }

        // 檢查 SignResult 為 GetBack 且 TaskStatus 為 Active,返回 "4退回"
        if (applyTask.SignResult == SignResult.GetBack && applyTask.Task.TaskStatus == ActiveStatus.Active)
        {
            return "4";
        }

        // 檢查 SignResult 為 Approve 且 TaskStatus 為 ReturnToApplicant,返回 "1處理中"
        if (applyTask.SignResult == SignResult.Approve &&
            applyTask.Task.TaskStatus == ActiveStatus.ReturnToApplicant)
        {
            return "1";
        }

        // 檢查 SignResult 為 Disapprove 且 TaskStatus 為 Active,返回 "2結案"
        if (applyTask.SignResult == SignResult.Disapprove && applyTask.Task.TaskStatus == ActiveStatus.Active)
        {
            return "2";
        }

        // 如果沒有匹配條件,返回 "1處理中"
        return "1";
    }
    catch
    {
        // 如果發生異常,返回 "3異常"
        return "3";
    }
}

/// <summary>
/// 取得表單的申請結果
/// </summary>
/// <param name="applyTask">The apply task.</param>
/// <returns>0核准, 1否決, 2作廢,3退回, NULL 簽核中</returns>
public static string GetFormTaskResult(ApplyTask applyTask)
{
    return applyTask.FormResult == ApplyResult.UnKnow ? null : ((int)applyTask.FormResult).ToString();
}

將XML轉為MODEL

var model = new Z_TEST_TRIGGER
{
    DOC_NBR = GetFieldValue(doc, "DOC_NBR"),
    APPLICICATE = GetFieldValue(doc, "APPLICICATE"),
    APPLICICATE_DEPT = GetFieldValue(doc, "APPLICICATE_DEPT"),
    APPLY_DATE = TryParseDateTime(GetFieldValue(doc, "APPLY_DATE")) ?? DateTime.Now,
    SINGLE_TEXT = GetFieldValue(doc, "SINGLE_TEXT"),
    TASK_STATUS = GetFormTaskStatus(applyTask),
    TASK_RESULT = GetFormTaskResult(applyTask)
};

安裝dapper

對專案案右鍵 然後選Manage NuGet Packages (管理Nuget套件)

Image

Browse 瀏覽 > 搜尋 dapper > install

Image

Apply (套用)

⚠️ System.Runtime.CompilerServices.Unsafe 4.5.3 這邊有個坑

Image

⚠️⚠️⚠️安裝時候會裝上舊版的System.Runtime.CompilerServices.Unsafe 4.5.3 編譯時候會蓋掉eip自帶的,導致eip變成錯誤500

Image

裝完之後要再去Nuget的Update將System.Runtime.CompilerService.Unsafe 4.5.3 升級到 System.Runtime.CompilerService.Unsafe 5.0之後的版本,eip才能正常運作

簡單的做法就是直接全部更新就好

這樣就安裝起來了,佈署的時候要記得將 dapper.dll 一起拷貝上去,其他dapper需要的dll在eip上都新版的,所以可以不用複製

寫新增與更新

取得EIP的連線字串

_connectionString = new DatabaseHelper().Command.Connection.ConnectionString;

using Ede.Uof.Utility.Data;
using Ede.Uof.WKF.Engine;
using Ede.Uof.WKF.ExternalUtility;
using System;
using System.Data.SqlClient;
using System.Xml;
using Dapper;

namespace UOF_DEV
{
    public class Trigger : ICallbackTriggerPlugin
    {
        /// <summary>
        /// 連線字串
        /// </summary>
        private string _connectionString;

        /// <summary>
        /// 建構子
        /// </summary>
        public Trigger()
        {
            //EIP內建抓取得連線字串
            _connectionString = new DatabaseHelper().Command.Connection.ConnectionString; 
        }
       /*其他程式碼 ....*/
     }
}

這邊偷懶一下,我只寫刪除+新增

/// <summary>
/// 新增或更新資料到 Z_TEST_TRIGGER 資料表
/// </summary>
/// <param name="model"></param>
public void Insert(Z_TEST_TRIGGER model)
{
    string sql = @"
        DELETE FROM Z_TEST_TRIGGER WHERE DOC_NBR = @DOC_NBR;
        INSERT INTO Z_TEST_TRIGGER (DOC_NBR, APPLICICATE, APPLICICATE_DEPT, APPLY_DATE, SINGLE_TEXT, TASK_STATUS, TASK_RESULT)
                    VALUES (@DOC_NBR, @APPLICICATE, @APPLICICATE_DEPT, @APPLY_DATE, @SINGLE_TEXT, @TASK_STATUS, @TASK_RESULT)";
    //將資料寫入資料庫
    using (var conn = new SqlConnection(_connectionString))
    {
        conn.Open();
        var transaction = conn.BeginTransaction();
        try
        {
            conn.Execute(sql, model , transaction);
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
            throw;
        }
        
    }
}

完整的Trigger程式如下

using Ede.Uof.Utility.Data;
using Ede.Uof.WKF.Engine;
using Ede.Uof.WKF.ExternalUtility;
using System;
using System.Data.SqlClient;
using System.Xml;
using Dapper;

namespace UOF_DEV
{
    public class Trigger : ICallbackTriggerPlugin
    {
        /// <summary>
        /// 連線字串
        /// </summary>
        private string _connectionString;

        /// <summary>
        /// 建構子
        /// </summary>
        public Trigger()
        {
            //EIP內建抓取得連線字串
            _connectionString = new DatabaseHelper().Command.Connection.ConnectionString; 
        }
        public void Finally()
        {
            
        }

        public string GetFormResult(ApplyTask applyTask)
        {
            //取得表單編號
            string DOC_NBR = applyTask.FormNumber;

            //將目前表單內容讀到 doc物件當中
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(applyTask.CurrentDocXML);

            //建立儲存表單的目錄
            System.IO.Directory.CreateDirectory("C:\\UOF_DEBUG\\");
            //儲存表單xml內容到硬碟中
            doc.Save($"C:\\UOF_DEBUG\\{DOC_NBR}{DateTime.Now:yyyy-MM-dd-hh-mm-ss}.xml");

            /*XML SAMPLE
             <Form formVersionId="09a27207-17b7-4ff5-be49-3b8d2d1552a7">
                 <FormFieldValue>
                   <FieldItem fieldId="DOC_NBR" fieldValue="BPM250800001" realValue="" enableSearch="True" />
                   <FieldItem fieldId="APPLICICATE" fieldValue="WISH(wish)" realValue="&lt;UserSet&gt;&lt;Element type='user'&gt; &lt;userId&gt;084ecfd9-b65a-4b99-b649-d4abcf03112c&lt;/userId&gt;&lt;/Element&gt;&lt;/UserSet&gt;&#xD;&#xA;" enableSearch="True" />
                   <FieldItem fieldId="APPLICICATE_DEPT" fieldValue="RD-T1" realValue="2c3feec0-c47e-b3d2-9b62-053be7cac613,RD-T1,False" enableSearch="True" />
                   <FieldItem fieldId="APPLY_DATE" fieldValue="2025/08/05" realValue="" enableSearch="True" fillerName="WISH" fillerUserGuid="084ecfd9-b65a-4b99-b649-d4abcf03112c" fillerAccount="wish" fillSiteId="" />
                   <FieldItem fieldId="SINGLE_TEXT" fieldValue="123456" realValue="" enableSearch="True" fillerName="WISH" fillerUserGuid="084ecfd9-b65a-4b99-b649-d4abcf03112c" fillerAccount="wish" fillSiteId="" />
                 </FormFieldValue>
               </Form>
             */
            var model = new Z_TEST_TRIGGER
            {
                DOC_NBR = GetFieldValue(doc, "DOC_NBR"),
                APPLICICATE = GetFieldValue(doc, "APPLICICATE"),
                APPLICICATE_DEPT = GetFieldValue(doc, "APPLICICATE_DEPT"),
                APPLY_DATE = TryParseDateTime(GetFieldValue(doc, "APPLY_DATE")) ?? DateTime.Now,
                SINGLE_TEXT = GetFieldValue(doc, "SINGLE_TEXT"),
                TASK_STATUS = GetFormTaskStatus(applyTask),
                TASK_RESULT = GetFormTaskResult(applyTask)
            };
            Insert(model);
            //故意失敗,用於重複測試使用
            throw new Exception("For TEST");

            return "";
        }

        /// <summary>
        /// 新增或更新資料到 Z_TEST_TRIGGER 資料表
        /// </summary>
        /// <param name="model"></param>
        public void Insert(Z_TEST_TRIGGER model)
        {
            string sql = @"
                DELETE FROM Z_TEST_TRIGGER WHERE DOC_NBR = @DOC_NBR;
                INSERT INTO Z_TEST_TRIGGER (DOC_NBR, APPLICICATE, APPLICICATE_DEPT, APPLY_DATE, SINGLE_TEXT, TASK_STATUS, TASK_RESULT)
                            VALUES (@DOC_NBR, @APPLICICATE, @APPLICICATE_DEPT, @APPLY_DATE, @SINGLE_TEXT, @TASK_STATUS, @TASK_RESULT)";
            //將資料寫入資料庫
            using (var conn = new SqlConnection(_connectionString))
            {
                conn.Open();
                var transaction = conn.BeginTransaction();
                try
                {
                    conn.Execute(sql, model , transaction);
                    transaction.Commit();
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    throw;
                }
                
            }
        }

        public void OnError(Exception errorException)
        {
            
        }

        /// <summary>
        /// 取得BPM表單中 FieldValue 的內容
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="fieldId"></param>
        /// <returns></returns>
        private string GetFieldValue(XmlDocument doc, string fieldId)
        {
            return doc.SelectSingleNode($"//FieldItem[@fieldId='{fieldId}']")?.Attributes["fieldValue"]?.Value;
        }

        /// <summary>
        /// 取得BPM表單中 RealValue 的內容
        /// </summary>
        /// <param name="doc">表單XML</param>
        /// <param name="fieldId">欄位名稱</param>
        /// <returns></returns>
        private string GerRealValue(XmlDocument doc, string fieldId)
        {
            return doc.SelectSingleNode($"//FieldItem[@fieldId='{fieldId}']")?.Attributes["realValue"]?.Value;
        }

        /// <summary>
        /// 字串轉DateTime
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private DateTime? TryParseDateTime(string value)
        {
            if (DateTime.TryParse(value, out DateTime result))
                return result;
            return null;
        }

        /// <summary>
        ///表單狀態
        /// </summary>
        /// <param name="applyTask">
        /// </param>
        /// <returns>
        /// 1 = 處理中
        /// 2 = 結案
        /// 3 = 異常
        /// 4 = 退回
        /// </returns>
        public static string GetFormTaskStatus(ApplyTask applyTask)
        {
            try
            {
                // 結案
                // 如果 TaskStatus 不是 Active,返回 "2結案"
                if (applyTask.Task.TaskStatus != ActiveStatus.Active)
                {
                    return "2";
                }

                //退回申請者
                // 檢查 SignResult 為 ReturnToAppliant 退回申請者 且 TaskStatus 為 Active,返回 "4退回"
                if (applyTask.SignResult == SignResult.ReturnToAppliant &&
                    applyTask.Task.TaskStatus == ActiveStatus.Active)
                {
                    return "4";
                }

                // 退回某人
                // 檢查 SignResult 為 Return 且 TaskStatus 為 Active,返回 "1處理中"
                if (applyTask.SignResult == SignResult.Return && applyTask.Task.TaskStatus == ActiveStatus.Active)
                {
                    return "1";
                }

                // 檢查 SignResult 為 GetBack 且 TaskStatus 為 Active,返回 "4退回"
                if (applyTask.SignResult == SignResult.GetBack && applyTask.Task.TaskStatus == ActiveStatus.Active)
                {
                    return "4";
                }

                // 檢查 SignResult 為 Approve 且 TaskStatus 為 ReturnToApplicant,返回 "1處理中"
                if (applyTask.SignResult == SignResult.Approve &&
                    applyTask.Task.TaskStatus == ActiveStatus.ReturnToApplicant)
                {
                    return "1";
                }

                // 檢查 SignResult 為 Disapprove 且 TaskStatus 為 Active,返回 "2結案"
                if (applyTask.SignResult == SignResult.Disapprove && applyTask.Task.TaskStatus == ActiveStatus.Active)
                {
                    return "2";
                }

                // 如果沒有匹配條件,返回 "1處理中"
                return "1";
            }
            catch
            {
                // 如果發生異常,返回 "3異常"
                return "3";
            }
        }

        /// <summary>
        /// 取得表單的申請結果
        /// </summary>
        /// <param name="applyTask">The apply task.</param>
        /// <returns>0核准, 1否決, 2作廢,3退回, NULL 簽核中</returns>
        public static string GetFormTaskResult(ApplyTask applyTask)
        {
            return applyTask.FormResult == ApplyResult.UnKnow ? null : ((int)applyTask.FormResult).ToString();
        }
    }
}

好了就可以編譯+進行重送表單到Trigger

重送表單到Trigger測試

因為之前有拋出Exception,所以可以一直重新執行,這個上線前記得拿掉。

Image

編譯新版的後,重新回到EIP內的電子簽核>>管理>>呼叫DLL狀態查詢

選擇表單>>勾選>>重新執行>>點表單編號進去看結果

從資料庫驗證結果

Image

寫程式的一個很重要的點 ,一定要驗證

上測試環境前的準備

  1. 多測試幾次,使用不同帳號跟職位進行測試
  2. 將儲存xml等臨時性的程式碼刪除或註解
  3. 進行重構:補齊註解+重新命名變數讓程式更好維護

官方文件參考

這部分如果想參考可以看 U-OfficeForce26.0系統開發手冊(電子簽核).docx.pdf ,看肆、表單事件處理,不過我覺得寫的很少,多數技巧是我自己摸出來的。

0 Comments

Submit a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *