一講到工作流,很多人第一反應就是這個東西很深奧,有時候又覺得離我們較為遙遠,確實完善的工 作流設計很多方面,而正是由於需要兼顧很多方面,一般通用的工作流都難做到盡善盡美。微軟也提供 了幾個版本的WF框架支持,也有一些廠家是基於這個框架基礎上開發的工作流應用。
以前由於項目的需要,參與過一些工作流的項目開發,其中有些是基於我簡易工作流的原理上進行拓 展的,包括一個廣州市各區縣使用的行業審批業務平台,由於基於自己的流程處理,界面設計、流程流 轉等方面可以很好符合客戶需求,定制的彈性較好,缺點是不夠通用,也需要編寫表單部分代碼。
後面由於業務的需要,工作流方面的業務逐漸顯得迫切,公司是想采用一個較為通用工作流框架來組 織目前的業務,因此找了廣州一家做工作流的公司,購買了他們的產品,雖然號稱完全通過後台配置, 零代碼實現工作流業務表單的處理,但是由於客戶對表單的設計要求比較多,有時候需要結合一些外部 的數據接口,流程處理方面也有著進一步的需要,這樣可能就打破了他們原來的格局,導致無論在表單 設計、流程配置等方面,都需要購買他們工程師的現場服務,來進一步完善整個項目的內容,導致整個 項目進展緩慢,遭遇水土不服的處境。
因此感覺,一個工作流模塊,號稱再強大,如果不能很好結合項目應用,即使零代碼的功能配置,也 可能使你處於尴尬的境況之中,因為通過配置,可能在代碼裡面平常很容易實現的表單功能,要通過零 代碼配置,花費的時間更多更難掌握,因為零代碼是有代價的,需要您很好利用他們的API,他們的業務 對象,有時候還需要很曲折的摸索參數,而這一切可能就是非常致命的弱點。
1、簡易工作流的設計模型
在沒有第三方工作流模塊的情況下,簡易工作流就是利用數據庫和業務對象之間的協作關系,構建的 一個半模塊化的流程引擎,它能通過整合到項目代碼中進行更好的融合以便實現工作流的相關功能。
首先我們知道,我們在Office裡面創建任何文檔,都有一個模板的概念,這樣我們方便利用一些現成 的數據和布局,工作流也一樣,有一個流程模板的概念,如下所示。
然後每個流程模板,本身會預定義了一系列的處理流程,以便在流程實例裡面進行不同的處理,因此 流程模板還包含了多個流程步驟對象,他們的關系構成如下。
每個流程實例,除了他們自己的流程數據和字段信息外,它本身還有一個表單設計的問題,如費用審 批,可能包含填寫的費用清單數據等,所以流程實例還應該包含了流程的業務表單對象。
這樣他們構成了一個完整的流程業務對象關系,如下所示。
2、流程審批的操作
對於一個流程處理操作,我們知道一般有審批通過、拒絕、退回到某步驟、轉發到內部閱讀、閱讀, 以及包括起草者能撤銷表單呢等操作,當然如果還有一些具體的業務,可能還會有一些流程的處理才操 作,不過基本上也可以歸結為上面幾種,只是他們每步處理的數據內容不同而已。因此審批的操作步驟 分類如下所示。
這些操作我們都可以通過一些界面操作的封裝實現,因為他們基本上都是通用的,我們傳入一些流程 ID等相關標識後,就能交給這些標准的操作界面完成了。
如審批界面如下所示,裡面包含了通過、拒絕,跳回到某步驟,增加步驟等功能集合。
上面的界面是審批過程中,對於某一個流程處理人員實現的操作,而有時候,我們可能需要針對多個 人進行某個步驟的處理,如傳遞給內部人員進行分閱操作,那麼就應該選定多個人員進行處理,大概的 處理界面效果如下所示。
當然,若申請人的申請單填寫錯誤,需要撤銷的話,那麼也應該有這個操作,撤銷表單後,就可以重 新填寫表單,然後再次提交進行流程。
3、流程審批的表單處理
在表單的動態設計和顯示方面,一直沒有好的思路,因此我覺得把流程模塊作為半模塊化即可,把部 分界面通過代碼編寫方式進行整合,因此把表單的填寫,表單查看做到用戶控件裡面,然後在界面裡面 引用即可。
如下面的表單填寫操作界面如下所示,對不同的流程表單,在項目中增加一個表單的填寫界面和保存 操作即可。
查看本欄目
查看並處理的表單操作,我們可以先做一個查看表單信息的界面,然後整合流程的處理工具欄,組合 成一個查看、處理操作一體化的流程操作。
當然,如果是能夠有動態設計表單,然後進行無縫整合當然更加完美,不過這樣的操作,界面設計上 也不會很麻煩,一般普通的開發人員都能勝任,因此,對於其他流程表單,依葫蘆畫瓢就可以完成不同 的表單了。
而且裡面的工具欄代碼都是可以操作的,雖然可能集成了不同業務的處理方式,但是我們還是動態進 行處理,處理代碼如下所示。
private void InitToolBar() { //如果流程是可以撤銷,且表單狀態為處理中,那麼可以“撤銷”操作可用 bool mayCancel = BLLFactory<AppApply>.Instance.IsApplyMayCancel(ApplyId, base.LoginUserInfo.ID); this.btnCancel.ToVisibility(mayCancel); //可退回重新編輯 bool mayBackToEdit = BLLFactory<AppApply>.Instance.IsApplyMayBackEdit(ApplyId, base.LoginUserInfo.ID); this.btnEdit.ToVisibility(mayBackToEdit); //判斷是否需要顯示閱辦狀態 bool isReadStatus = BLLFactory<ApplyRead>.Instance.IsReadSatus(ApplyId, base.LoginUserInfo.ID); this.btnRead.ToVisibility(isReadStatus); //如果不是當前審批人隱藏審批按鈕 bool canDeal = BLLFactory<BLL.ApplyUser>.Instance.IsCheckPermission(ApplyId, base.LoginUserInfo.ID); if (canDeal) { ApplyFlowInfo flowInfo = BLLFactory<ApplyFlow>.Instance.GetFirstUnHandledFlow(ApplyId); if (flowInfo != null) { string procTypeName = BLLFactory<AppProc>.Instance.GetProcType(flowInfo.ProcType); BarButtonItem button = new BarButtonItem(); button.Caption = procTypeName; button.Name = procTypeName; button.Tag = flowInfo;//綁定流程內容 button.ImageIndex = 3; button.LargeImageIndex = 3; button.PaintStyle = BarItemPaintStyle.CaptionGlyph; button.ItemClick += new ItemClickEventHandler(button_ItemClick); this.bar1.AddItem(button); } } }
上面對於流程步驟的處理,就交給一個獨立的按鈕事件進行判斷處理即可,根據不同的業務步驟名稱 進行不同的處理,這樣就能夠進行很好的控制處理。
伍華聰 http://www.iqidi.com