(關(guān)鍵字:前端栓辜、Web界面锹锰、SDK模式忘衍、QueryObject位他、ORM映射)
目錄
- 本攻略的好處 = 5萬(wàn)元+
- 緣起
- 起步
- 外包
- 目標(biāo)(A)已辦、歸檔部服、申請(qǐng)唆姐,三個(gè)一覽型畫(huà)面
- (A-1)參考模塊——概念集——關(guān)鍵機(jī)制
- 【參考模塊】“待辦”計(jì)數(shù)器
- 【參考模塊】“待辦”UC第一部分:獲得流程記錄集(調(diào)用SDK接口)
- 【參考模塊】“待辦”UC第二部分:渲染記錄一覽表(單一Table,帶GroupBy)
- (A-2)新模塊——定制解決
- 【定制模塊】“已辦”計(jì)數(shù)器廓八、“歸檔”計(jì)數(shù)器
- 【定制模塊】“歸檔”UC第一部分:獲得流程記錄集(調(diào)用SDK接口)
- 【定制模塊】“歸檔”UC第二部分:渲染記錄一覽表(單一Table奉芦,帶GroupBy)
本攻略的好處 = 5萬(wàn)元+
5萬(wàn)元,是基于.Net國(guó)產(chǎn)開(kāi)源工作流引擎ccFlow定制Web界面外殼**的官方報(bào)價(jià)(5萬(wàn)/人月剧蹂,或12萬(wàn)/次培訓(xùn))声功。
與筆者之前調(diào)研的jBPMN4涅槃之作Activiti引擎相比的話,ccFlow勝在是中文文檔国夜、自帶符合國(guó)內(nèi)用戶習(xí)慣的Web界面(AppDemo包)减噪、并在國(guó)內(nèi)擁有了一定的用戶群;但就這次UI定制開(kāi)發(fā)經(jīng)歷而言车吹、也存在一些問(wèn)題:
- 代碼易維護(hù)性易讀性略低(如采購(gòu)官方服務(wù)則不構(gòu)成問(wèn)題)
如一些關(guān)鍵字的英文拼寫(xiě)錯(cuò)誤,C#的非主流用法(字符串拼接/空判斷醋闭、三元表達(dá)式合理運(yùn)用等)降低了代碼易維護(hù)性窄驹;無(wú)注釋卻又無(wú)實(shí)際作用的代碼段提高了代碼解讀成本- 對(duì)BPMN2.0國(guó)際標(biāo)準(zhǔn)的支持是在2015年9月新近追加
- ccFlow6起取消了對(duì)多國(guó)語(yǔ)言的支持
- 參考資料尚未基于常見(jiàn)開(kāi)發(fā)用例做系統(tǒng)編排
- 值得注意的是,ccFlow的開(kāi)源遵循的是GPL協(xié)議证逻,商用則無(wú)法閉源
本文僅供已經(jīng)選型ccFlow并需定制界面部分的技術(shù)者參考乐埠,并不代表作者選型偏好。
將比《黑客帝國(guó)》早了10年的神作《攻殼機(jī)動(dòng)隊(duì)》(不過(guò)比《機(jī)械戰(zhàn)警》要晚出2年)用于“渲染”純技術(shù)向的ccFlow攻略囚企,未免有點(diǎn)小眾了丈咐,不過(guò)興致所至、就順著這個(gè)腦洞筆法來(lái)寫(xiě)也無(wú)妨龙宏。
緣起
巴特面前擺放著一本《開(kāi)源工作流引擎ccFlow——從入門(mén)到迷路》棵逊,早已義體化的雙眼則泛著微光直視前方,空無(wú)而深邃银酗。
距離草薙少佐離開(kāi)公安9課已經(jīng)3年多了辆影,八幡宮研究所外也再次隨風(fēng)吹起山桂花的幽香,“人生一世黍特,草木一秋”蛙讥,雖說(shuō)義體比普通人的肢體強(qiáng)健得多,可是——靈魂呢灭衷?
賽博(Cyber)驅(qū)動(dòng)的仿生人(Android)“審核者”是采用公元2003年就發(fā)布的ccFlow引擎作為其“靈魂”(Ghost)的次慢,最初每家采購(gòu)“審核者”的企業(yè)還需要各自維護(hù)其靈魂的升級(jí)(注:當(dāng)對(duì)靈魂做過(guò)定制時(shí)、這種升級(jí)并不總是簡(jiǎn)單),后來(lái)隨著云時(shí)代到來(lái)迫像、以及基于對(duì)定制影響拓?fù)浞治龅膮^(qū)隔熱更新技術(shù)成熟拭抬,靈魂主體部分已經(jīng)上升到了云端∏置桑“審核者”的靈魂的安全強(qiáng)度造虎,也隨之晉級(jí)到了聯(lián)盟區(qū)塊鏈的級(jí)別。
可是纷闺,人的靈魂呢算凿?
在能真正探明人的靈魂“生從何處來(lái),死至何處去”之前犁功,從邏輯上說(shuō)氓轰,恐怕無(wú)法真正回答得了這個(gè)問(wèn)題。除了草薙素子之外浸卦,畢竟還沒(méi)有原生人(包括由人生育后天經(jīng)過(guò)改造的義體人)署鸡、其靈魂能進(jìn)出于賽博世界;而即使是與(傀儡師的)“賽博自主意識(shí)”融合而變強(qiáng)的草薙的靈魂限嫌,她真正人類的部分是否真地已依附電子媒介活得好好的靴庆,還是已只是被賽博讀取了記憶后的克隆體,都并無(wú)法斷言…
【任務(wù)】審核者UI外殼定制(級(jí)別:E怒医,極安全)
荒卷課長(zhǎng)對(duì)仿生人“審核者”的UI外殼不甚滿意炉抒,提出了新的需求
若是以前,巴特一定不會(huì)對(duì)此種內(nèi)部維護(hù)任務(wù)感興趣稚叹,包管找個(gè)理由丟給戶草了事焰薄。可是這次扒袖,“審核者”……
起步
深吸了一口山桂林間的怡人空氣塞茅,巴特飛速輸入“\\Kusanagi:”(注:草薙的日文讀音)
對(duì)“審核者”代碼做了全文檢索〖韭剩“只修改過(guò)這點(diǎn)么…”巴特自語(yǔ)到野瘦,“主要都聚集在界面相關(guān)的頁(yè)面.aspx
、控件.ascx
…恩蚀同,這里有一個(gè)BP.En
包中的QueryObject
…”
思考戰(zhàn)車塔奇克馬(Tachikoma)上堆放著其他資料缅刽,它一邊烘焙著已泛金黃的桂花曲奇酥煮著玄米茶、一邊為老友切上了一首遠(yuǎn)野魂音版的《那些花兒》蠢络。
依照慣例衰猛,首先列出我(玩巴特這個(gè)人物通關(guān)后)覺(jué)得有用的資料、便于推斷本攻略的參考價(jià)值刹孔,第三方資料幾近于無(wú):
- 官方文檔(中文原版):http://ccbpm.mydoc.io/
- 官方社區(qū):QQ=383352596(ccFlow 19號(hào))啡省,論壇=http://bbs.ccflow.org/
- 馳騁dotNet與java工作流引擎-表結(jié)構(gòu).xlsx(QQ群共享文件)
- 開(kāi)源碼庫(kù):http://git.oschina.net/opencc/ccflow/tree/master/
- 開(kāi)發(fā)環(huán)境構(gòu)筑:http://git.oschina.net/opencc/ccflow/wikis/使用svn下載
- 必須:VStudio2010娜睛、.Net 4.0+、數(shù)據(jù)庫(kù)(推薦MSSQL)
- 可選:SilverLight 4+(用于流程設(shè)計(jì)器卦睹,官方另有HTML5版本)
- 可選:IIS(VStudio內(nèi)置ASP.Net開(kāi)發(fā)服務(wù)器就夠用)
選用巴特視角進(jìn)入游戲時(shí)畦戒、“審核者”的開(kāi)發(fā)環(huán)境已經(jīng)構(gòu)筑于一臺(tái)虛擬機(jī)之中,只需登錄后打開(kāi)IDE就能進(jìn)行修改-調(diào)試-發(fā)布的整個(gè)過(guò)程(否則需自行構(gòu)筑)结序。草薙作為前任開(kāi)發(fā)者留有一段作業(yè)交接視頻障斋,不過(guò)不知是否時(shí)間匆忙、錄制得并不算完整徐鹤。
“幫我加載一個(gè)版本2的AppDemo包做對(duì)照垃环,另外,給這首歌掛個(gè)單曲循環(huán)吧”巴特關(guān)照塔奇克馬返敬。
【道具】AppDemo包(品質(zhì):Rare)
官方的UI外殼范例遂庄,定制的關(guān)鍵。原始版本原本位于開(kāi)源碼庫(kù)的CCFlow\AppDemo劲赠,因?yàn)椴豢芍脑蛞驯还俜健芭R時(shí)下架”涛目,但9課保留了歷史版本
“嘿,連Demo包目錄名都沒(méi)改就用了…那個(gè)人可真夠敷衍了事啊”巴特隨手復(fù)制出一個(gè)AppNew目錄凛澎,用來(lái)存放這次修改的代碼霹肝,“類重名錯(cuò)誤,給每個(gè).aspx.cs
都補(bǔ)上namespace
就行预厌“⒙酰”
紅圈自動(dòng)差分提示修改范圍,這次的UI外殼定制就從這里出發(fā)轧叽。
外包
“……單單看這一小段交接視頻和這堆混亂的代碼、資料刊棕,不知道要看到猴年馬月…”
“猴年馬月炭晒,按照中國(guó)太陰歷,這個(gè)月正是申猴年午馬月甥角⊥希”塔奇克馬呆萌的聲音解釋到。
“……”悻悻地嚼了一口曲奇酥嗤无,巴特首先接駁上公眾終端QQ模塊震束,白色義眼掃入了383-352-596
,QQ外殼上立刻顯示出“ccFlow 19號(hào)”当犯,“申請(qǐng)加入” 巴特語(yǔ)音確認(rèn)道垢村。
很快一個(gè)清脆干練的女聲傳來(lái):“您好,客服編號(hào)‘敏’為您服務(wù)嚎卫,請(qǐng)問(wèn)您是需要使用ccflow嗎嘉栓?”
【人物】CCFlow客服‘敏’(原生人,女性)
CCFlow美女工程師兼首席客服,接通QQ群即可收到聯(lián)系侵佃。
NPC麻昼,保留真人玩家以該角色視角在線的可能。
性格開(kāi)朗馋辈,敬業(yè)認(rèn)真抚芦,專業(yè)嫻熟,不過(guò)也曾有過(guò)因客戶頻繁需求變更迈螟、不得不超期駐扎外包現(xiàn)場(chǎng)的經(jīng)歷叉抡。
經(jīng)過(guò)一番簡(jiǎn)短的詢問(wèn),
“50,000RMB/人月…9課近期不會(huì)有這樣一筆預(yù)算給內(nèi)部項(xiàng)目吧井联〔泛荆”巴特心里盤(pán)算著,已經(jīng)有了結(jié)論烙常。
目標(biāo)(A)已辦轴捎、歸檔、申請(qǐng)蚕脏,三個(gè)一覽型畫(huà)面
荒卷老爹的新需求可以簡(jiǎn)化成這張圖來(lái)滿足:
相當(dāng)于新增兩個(gè)位于不同處理狀態(tài)(已辦侦副、歸檔)、和一個(gè)發(fā)起人是自己的流程的一覽畫(huà)面驼鞭,避免都使用查詢畫(huà)面做入口不夠清晰秦驯;這看起來(lái)也是個(gè)很簡(jiǎn)單的需求么,先理清幾個(gè)概念:
【概念 & 相關(guān)代號(hào)】
- 發(fā)起人:一個(gè)申請(qǐng)流程實(shí)例的發(fā)起者挣棕。
變量名/縮寫(xiě)=Starter
- 處理人:一個(gè)申請(qǐng)流程實(shí)例的審批者译隘,可以有多人。
變量名/縮寫(xiě)=Emp洛心、Worker
- 我的待辦:流程處于“運(yùn)行中”生命周期狀態(tài)固耘、且當(dāng)前處理人是自己。
變量名/縮寫(xiě)=EmpWorks
- 我的已辦:流程處于“運(yùn)行中”生命周期狀態(tài)词身、且自己已處理過(guò)厅目。別名:在途。
變量名/縮寫(xiě)=Runing(注:[SIC]原拼寫(xiě)就這樣…)
- 我的歸檔:流程處于“已完成”生命周期狀態(tài)法严,且自己已處理過(guò)损敷。
變量名/縮寫(xiě)=Completed
- 我的申請(qǐng):流程處于任意生命周期狀態(tài),且發(fā)起人是自己深啤。
變量名/縮寫(xiě)=Apply
*提示:部分常量定義位于
Components\BP.WF\PubLib\Enumlib.cs
拗馒,如WFState.Complete(狀態(tài)=已完成)
(A-1)參考模塊——概念集——關(guān)鍵機(jī)制
編程是一個(gè)需要"實(shí)踐記憶"的活動(dòng),單單看“攻略記錄”可是學(xué)不來(lái)的墓塌。建議玩家讀取CCFlow5.sln項(xiàng)目存檔一起操作瘟忱。
“從啟動(dòng)頁(yè)AppNew\Default.aspx
看奥额,這個(gè)AppDemo包原來(lái)采用的還是一種古老的UI外殼技術(shù)——Frame,不知是何用意…”巴特審慎地解讀到访诱。
打開(kāi)左側(cè)導(dǎo)航欄所對(duì)應(yīng)的AppNew\Left.aspx
垫挨,掃視當(dāng)前版本從“發(fā)起”到“設(shè)置”的5個(gè)鏈接,很容易便能順藤排摸出這個(gè)UI外殼的線路紋理(如下圖):
- 導(dǎo)航欄鏈接會(huì)指向位于
WF\\
目錄的某個(gè).aspx
UI頁(yè)面触菜,要做一覽型UI需參照“待辦”九榔、也就是~WF\EmpWorksSmall.aspx
(如前述EmpWorks
是“待辦”的代號(hào),Small
則標(biāo)識(shí)了頁(yè)面布局風(fēng)格) -
WF\\
目錄下的UI頁(yè)面其實(shí)都是空殼涡相,注冊(cè)重用了UC控件哲泊,如~WF\UC\EmpWorks.ascx
-
WF\\UC\\
目錄下的UC控件類,才包含了真正的流程實(shí)例獲取&渲染的代碼
【道具】第一塊參考模塊:我的待辦UC控件 Get!(一覽型UC)
位于~WF\UC\EmpWorks.ascx.cs
催蝗。
主要功能是查詢?nèi)〉?/strong>符合特定條件的流程實(shí)例切威,然后渲染為一覽列表。
雖說(shuō)繼承自BP.Web.UC.UCBase3
類丙号,追根溯源也是一個(gè)ASP.Net的System.Web.UI.UserControl
先朦,從Page_Load()
方法開(kāi)始解讀即可。
*提示:UCBase3
封裝了共3層UC共通功能犬缨,不過(guò)完成此次UI定制#無(wú)需#去費(fèi)時(shí)解讀它們喳魏。
【參考模塊】“待辦”計(jì)數(shù)器
在解構(gòu)EmpWorks.ascx.cs
前先解決掉一個(gè)“小目標(biāo)”練手:可以注意到Left.aspx
的“待辦”與“抄送”的右邊各有一個(gè)計(jì)數(shù)器、每過(guò)100秒會(huì)自動(dòng)刷新(0表示無(wú)記錄)怀薛。這也是需要模擬的對(duì)象刺彩。
巴特很容易地從Left.aspx.cs
中找到了計(jì)數(shù)器的實(shí)現(xiàn),代碼只有寥寥幾行枝恋,通過(guò)直接SQL文查詢視圖WF_EmpWorks
實(shí)現(xiàn)创倔,
//Left.aspx頁(yè)面屬性:“待辦”流程的COUNT計(jì)數(shù)值,只讀焚碌。
public int EmpWorks
{
get
{
string sql = @"SELECT COUNT(*) AS Num FROM WF_EmpWorks
WHERE FK_Emp='" + BP.Web.WebUser.No + "' ";
return BP.DA.DBAccess.RunSQLReturnValInt(sql); //返回Int型計(jì)數(shù)結(jié)果
}
}
所涉及的“最小概念集”正好值得梳理一下作為入門(mén)三幻。當(dāng)然如果是大腦電子腦化過(guò)的角色(如荒卷課長(zhǎng))、閱讀時(shí)的短期記憶能更快轉(zhuǎn)化為長(zhǎng)期記憶呐能、這一學(xué)習(xí)環(huán)節(jié)就會(huì)更為簡(jiǎn)單,
【概念】流程相關(guān)編碼
掌握數(shù)據(jù)表/視圖/實(shí)體類解讀技能的前置知識(shí)點(diǎn)抑堡。與倉(cāng)庫(kù)計(jì)件一樣摆出,對(duì)運(yùn)行中/運(yùn)行完成的流程、以及流程中的每個(gè)(環(huán)節(jié))節(jié)點(diǎn)首妖,都會(huì)用“編碼”作標(biāo)識(shí)偎漫。
- WorkID:動(dòng)態(tài)自增序列號(hào),Int64型有缆、全局唯一象踊。一個(gè)流程啟動(dòng)后(運(yùn)行時(shí))生成温亲,標(biāo)識(shí)該流程實(shí)例,所有流程表單杯矩、節(jié)點(diǎn)表單的主鍵都使用該值栈虚。別名:OID。
- 流程編碼:靜態(tài)概念史隆。三位數(shù)String型編號(hào)(最大999)魂务,標(biāo)識(shí)某種流程(如“072:預(yù)算外攻殼更換申請(qǐng)”)。
常用于字段FK_Flow(FK=外鍵)
- 節(jié)點(diǎn)編碼:靜態(tài)概念泌射。流程編碼(e.g.001)+節(jié)點(diǎn)ID(兩位數(shù)Int粘姜,最大99),表示某種流程中的某個(gè)節(jié)點(diǎn)(如“07201:發(fā)起”(預(yù)算外攻殼更換申請(qǐng))熔酷,不同流程中的節(jié)點(diǎn)允許重名)孤紧。
常用于字段FK_Node(FK=外鍵)
【道具】第一張數(shù)據(jù)表/視圖:WF_EmpWorks
開(kāi)發(fā)環(huán)境中已有名為ccport
的數(shù)據(jù)庫(kù),保管著開(kāi)發(fā)用的數(shù)據(jù)表/視圖拒秘。
WF_EmpWorks
是其中專門(mén)為“待辦”流程配置的視圖(用到WF_GenerWorkFlow
和WF_GenerWorkerlist
兩張核心數(shù)據(jù)表号显,篩選條件為IsEnable = 1 AND IsPass = 0(表示未辦理)
)
數(shù)據(jù)庫(kù)配置:項(xiàng)目的
Web.config
的AppSettings
下有AppCenterDSN
和AppCenterDBType
數(shù)據(jù)庫(kù)命名規(guī)范【重要】
- Sys前綴=系統(tǒng)表,將用到的是
Sys_MapData
和Sys_MapAttr
映射表(任務(wù)后半段分析)- Port前綴=組織結(jié)構(gòu)翼抠,如
Port_Emp
(人員表咙轩,Emp
代表Employee
)、Port_Dept
(部門(mén)表)- WF前綴=流程規(guī)則描述阴颖,尤其是WF_GenerXxx系列是流程運(yùn)行控制表活喊,如
WF_EmpWorks
所用到的WF_GenerWorkFlow
和WF_GenerWorkerlist
,分別維護(hù)著所有運(yùn)行中流程實(shí)例的細(xì)節(jié)量愧、和每個(gè)流程節(jié)點(diǎn)的處理者信息(如IsPass
表示是否已被處理者審核通過(guò))钾菊。- V前綴=國(guó)際慣例視圖的前綴應(yīng)為
V_
,卻也有多個(gè)原因不明的例外(如WF_EmpWorks
視圖的命名就是)- ND前綴=節(jié)點(diǎn)表單(
NDxxxxx
)偎肃、流程報(bào)表(NDxxxRpt
)煞烫、或流程軌跡表(NDxxxTrack
)。本次UI外殼任務(wù)不涉及累颂,但屬于基礎(chǔ)知識(shí)滞详。
當(dāng)CCFlow處于“軌跡模式”時(shí),編輯創(chuàng)建一個(gè)節(jié)點(diǎn)時(shí)就會(huì)創(chuàng)建一個(gè)表與此節(jié)點(diǎn)相對(duì)應(yīng)紊馏,便于記錄節(jié)點(diǎn)級(jí)別的數(shù)據(jù)變化(例如“ND07201
:預(yù)算外攻殼更換申請(qǐng)發(fā)起節(jié)點(diǎn)表”包含了該環(huán)節(jié)的表單數(shù)據(jù))料饥。另一個(gè)“合并模式”不常用,不創(chuàng)建節(jié)點(diǎn)表朱监、更快岸啡、但不記錄細(xì)節(jié)。常見(jiàn)字段含義
- 每個(gè)節(jié)點(diǎn)表都會(huì)有的字段:OID:工作ID赫编,RDT:記錄日期巡蘸,Rec:記錄人奋隶,CDT:完成時(shí)間,NodeState:節(jié)點(diǎn)狀態(tài)
- 開(kāi)始節(jié)點(diǎn)(才)有的字段: WFState:流程狀態(tài)
*提示:字段列的命名有些頗為費(fèi)解悦荒,可通過(guò)列屬性確認(rèn)其含義(如圖)
“計(jì)數(shù)器居然是后臺(tái)代碼直接SQL文讀的唯欣,沒(méi)至少弄個(gè)REST方式的封裝感覺(jué)對(duì)前后端分離不很友好啊” 巴特吐槽到,“算了我也沒(méi)功夫自己弄一個(gè)逾冬∈蚰簦”
接著就開(kāi)始解剖第一個(gè)大的參考模塊EmpWork.ascx.cs
控件,如前所述從Page_Load()
方法開(kāi)始身腻,
//Step1.調(diào)用SDK接口獲得“待辦”流程的記錄集(DataTable型)賦值給成員變量
dt = BP.WF.Dev2Interface.DB_GenerEmpWorksOfDataTable();
//Step2.基于成員變量dt進(jìn)行一覽表渲染
this.BindList();
【參考模塊】“待辦”UC第一部分:獲得流程記錄集(調(diào)用SDK接口)
首先F12切換到DB_GenerEmpWorksOfDataTable()
方法的定義产还,可以看到針對(duì)是否授權(quán)(IsAuthorize)
及何種授權(quán)有若干分支,這里#無(wú)需#對(duì)此多糾結(jié)嘀趟、只需參考到其本質(zhì)其實(shí)也是在對(duì)WF_EmpWorks
做SQL查詢即可(吐槽:與計(jì)數(shù)器那邊用的同一視圖脐区,一覽這邊卻有著多重條件分歧,兩邊竟然還能匹配得上…不深究)
【武器】
BP.WF.Dev2Interface
下的
DB_GenerEmpWorksOfDataTable()
她按、DB_GenerRuning()
等接口
SDK模式開(kāi)發(fā)接口層牛隅。其中DB_GenerXxx
系列與完成本次定制任務(wù)有關(guān),其特點(diǎn)是簡(jiǎn)單粗暴易于上手且輸出夠猛烈酌泰,接近于半自動(dòng)型AK-b48媒佣。
輸入:當(dāng)前用戶的編碼BP.Web.WebUser.No (全局變量,string型)
輸出:當(dāng)前用戶的待辦陵刹、已辦等不同特征流程的記錄集(DataTable型)
*注意:用了SELECT *
所以相關(guān)表中所有字段均可在結(jié)果記錄中用到
【道具】BP包
ccFlow官方的核心工具箱默伍,多格。BP標(biāo)志代表"Brain Power"(見(jiàn)官方文檔)衰琐,宣稱著電子腦陣營(yíng)的強(qiáng)大[*需注明出處]
也糊。
- BP.En
30
:基層實(shí)體類庫(kù),用處多多
1.數(shù)據(jù)庫(kù)交互
2.實(shí)體類:實(shí)體的工作基于Map映射(即ORM)
3.其他數(shù)據(jù)源交互:XML文件等
4.組織結(jié)構(gòu)類庫(kù):人員羡宙、部門(mén)狸剃、崗位,并提供登錄控制- BP.WF
v4
:W/F(WorkFlow)相關(guān)
* **`BP.WF.Dev2Interface`:SDK模式開(kāi)發(fā)接口層**狗热,僅`DB_GenerXxx`系列有用钞馁。完整列表則可參見(jiàn)[CCFlow5接口說(shuō)明文檔](http://pan.baidu.com/s/1c29QF08)`(官方文檔似乎經(jīng)過(guò)了…削減(?),鏈接到9課緩存吧)`
- BP.Web.Control:公共Web組件庫(kù)
*相比之下匿刮,CCFlow包下的 WF指攒、WF.UC、WF.Rpt.UC
(Rpt代表報(bào)表)
更偏應(yīng)用層
【參考模塊】“待辦”UC第二部分:渲染記錄一覽表(單一Table僻焚,帶GroupBy)
得到DataTable
記錄集之后轉(zhuǎn)到this.BindList()
方法做渲染,迎面猝不及防便是一大段冗余代碼——當(dāng)按照PRI
做GroupBy時(shí)將跳轉(zhuǎn)到另一個(gè)BindList_PRI()
膝擂,而這兩套BindList
卻是猶如雙生子般類似虑啤。
“古老的冗余型防壁么…迫使意圖定制修改者必須肉眼多解讀一倍以上內(nèi)容隙弛,并增加后續(xù)維護(hù)所需耗費(fèi)的精力∧剑” 這里其實(shí)#無(wú)需#閱讀BindList_PRI()
全闷,只需參照BindList()
就能仿制出自己的UI外殼。
【概念】GroupBy分組
一覽型UC的唯一特色萍启。如下圖总珠,當(dāng)前是按照流程名稱(FlowName)
分組的(例如“多次簽證申請(qǐng)”)
,如果點(diǎn)擊表頭中的狀態(tài)
勘纯,會(huì)切換到按狀態(tài)(WFState)
分組局服,而狀態(tài)
列則會(huì)被當(dāng)前的分組字段流程名稱
所替代。
*伏筆劇透:這里所能參考到的GroupBy實(shí)現(xiàn)驳遵、其實(shí)只是偽實(shí)現(xiàn)…淫奔。玩家可檢查代碼看能否發(fā)現(xiàn)疑點(diǎn)所在。
巴特點(diǎn)起了一支煙又被塔奇克馬迅速撲滅堤结,只能抿了口玄米茶嘆道:“這BindList()
中搞了半天無(wú)非是遍歷dt
集合唆迁,把每條dr
記錄渲染成行,唯一特色無(wú)非就是得兼顧到GroupBy的因素竞穷,卻又冗余地做成了(GroupBy列數(shù)+1)x記錄數(shù)
的遍歷復(fù)雜度唐责,而且對(duì)一次讀入的記錄數(shù)并沒(méi)有限制…”
“嘛,算了瘾带,數(shù)據(jù)庫(kù)里如果真積壓著幾千條“待辦流程”影響到顯示鼠哥、卡死的也就不只是一個(gè)UI外殼而是N個(gè)人腦了。實(shí)際環(huán)境中還是可以用月弛,在新UI外殼里面改掉也就是了肴盏。”
(A-2)新模塊——定制解決
解讀現(xiàn)有模塊完成帽衙,開(kāi)始定制新模塊菜皂。
先從“我的已辦”(=在途)的UI外殼入手。這里有一個(gè)捷徑厉萝,
【道具】AppDemoLigerUI包(品質(zhì):Rare)
同樣是官方的UI外殼范例恍飘,同樣因?yàn)椴豢芍脑虮还俜健芭R時(shí)下架”了,但9課保留了歷史版本谴垫。
除了使用LigerUI技術(shù)風(fēng)格更接近主流外章母,其中還包括了一些AppDemo包中被省略了的內(nèi)容。
*LigerUI技術(shù)本身并不推薦使用翩剪,優(yōu)缺點(diǎn)可參考這篇乳怎。技術(shù)選型真少不了甄別比較、無(wú)論面向靈魂的還是外殼前弯。
導(dǎo)航鏈接指向\WF\RuningSmall.aspx
頁(yè)面蚪缀,“在途的英文…是Runing
么秫逝?”巴特也不禁疑惑道,電子眼識(shí)別出是拼寫(xiě)混淆術(shù)询枚。
【概念】英語(yǔ)拼寫(xiě)混淆術(shù)(Spelling Obfuscation)
相比傳統(tǒng)的代碼混淆技術(shù)(Code Obfuscation)违帆,英語(yǔ)拼寫(xiě)混淆術(shù)在非英語(yǔ)母語(yǔ)尤其東亞地區(qū)運(yùn)用較多。相比前者金蜀,拼寫(xiě)混淆更容易打擊解讀者信心刷后,令其懷疑究竟是誤解了單詞含義還是用眼過(guò)度。眩暈對(duì)象0.5秒渊抄,并有小概率引發(fā)爆笑尝胆。
- 這次任務(wù)會(huì)遇見(jiàn)的混淆/非常規(guī)代號(hào)、及其真實(shí)含義:
IsExitsContral
(=IsExistsControl..)抒线,Runing
(=Running)班巩,Sta
(=Status),Cash
(=Cache!)嘶炭,LGType
(=LoGicType)
【定制模塊】“已辦”計(jì)數(shù)器抱慌、“歸檔”計(jì)數(shù)器
“我的已辦”的左側(cè)欄計(jì)數(shù)器,如法炮制的話眨猎,是否也需自己編制一個(gè)WF_Runing
視圖呢抑进?答案是不需要。
可以參考到~WF\UC\\
下面其實(shí)已經(jīng)有一個(gè)“我的已辦”一覽型UC控件睡陪,它所用到的記錄查詢SDK接口是BP.WF.Dev2Interface.DB_GenerRuning()
寺渗,參考就能鐫刻出計(jì)數(shù)器所需的SQL銘文了:
public int Runing
{
get
{
string sql = String.Format(@"SELECT * FROM WF_GenerWorkerList
WHERE FK_Emp='{1}' and IsPass=1 AND IsEnable=1", BP.Web.WebUser.No)
return BP.DA.DBAccess.RunSQLReturnValInt(sql);
}
}
編譯運(yùn)行即可看到第一個(gè)UI定制成果——導(dǎo)航欄中“我的已辦”計(jì)數(shù)值已正確顯示。
而“我的已辦”一覽UC控件(~\WF\UC\Runing.ascx.cs
)經(jīng)驗(yàn)證風(fēng)格與“我的待辦”相同兰迫,可直接鏈接上使用信殊。
快速進(jìn)入下一個(gè)一覽畫(huà)面的打造——“我的歸檔”(Completed)。
首先仍是計(jì)數(shù)器部分汁果。這次發(fā)現(xiàn)~WF\UC\\
目錄下也沒(méi)有現(xiàn)成的UC控件可用了涡拘,沒(méi)有現(xiàn)成的DB_GenerXxx
接口參考,得自己分析SQL銘文据德。
“還是用WF_GenerWorkFlow
和WF_GenerWorkerList
定制出一張‘我的歸檔’視圖鳄乏?”這是巴特的第一反應(yīng)。玩家只需記住一條線索棘利,“我的歸檔”的特征橱野、是WFState=3(3:Complete)
,然而你在WF_GenerWorkFlow
和WF_GenerWorkerList
中卻找不到一條WFState=3
的記錄善玫。
巴特這時(shí)會(huì)切入CCFlow官方社區(qū)查詢水援,再次獲得客服‘敏’的回答,可這次卻是包含著錯(cuò)誤信息的(“History也在WF_GenerWorkFlow
中”)。
正確的解答在這邊——當(dāng)然深度玩家可嘗試自行在資料堆中查找裹唆,
節(jié)點(diǎn)數(shù)據(jù)表(NDxxx)
的話就意味著有多少種流程就有多少個(gè)誓斥、包括“審核者”上線后新建的,該怎么組成視圖呢许帐?
其實(shí)數(shù)據(jù)庫(kù)中一共也沒(méi)多少視圖,很快就能發(fā)現(xiàn)一張名為V_FlowData
的視圖毕谴,包含著WFState
字段成畦、并且已經(jīng)是所有NDxxRpt
數(shù)據(jù)表的拼接;在“審核者”中新建流程時(shí)涝开,流程編輯器也會(huì)維護(hù)修改該視圖循帐。
【道具】核心視圖:V_FlowData(可改裝為:V_FlowDataPlus)
V_FlowData
是數(shù)據(jù)庫(kù)中唯一無(wú)差別維護(hù)著所有種類所有狀態(tài)的流程實(shí)例的視圖(包括“已完成”狀態(tài)的流程實(shí)例),但只維護(hù)被所有種類流程共有的基本字段信息舀武、不包含表單字段業(yè)務(wù)信息拄养。
V_FlowDataPlus
是通過(guò)對(duì)V_FlowData
增設(shè)一覽型UI所需的三個(gè)名稱字段構(gòu)成:FlowName(流程名稱)
,FlowStarterName(發(fā)起人名稱)
,FlowEndNodeName(結(jié)束節(jié)點(diǎn)名稱)
- 重要字段
OID
:即WorkID
,唯一標(biāo)識(shí)一個(gè)流程實(shí)例FK_Flow
:外鍵银舱,流程ID瘪匿,關(guān)聯(lián)到WF_Flow
表FK_Dept
:外鍵,部門(mén)ID寻馏,關(guān)聯(lián)到Port_Dept
表FlowStarter
:流程的發(fā)起者的IDFlowEmps
:流程的處理者的ID組棋弥,多人,以特定格式分隔FlowEndNode
:流程的結(jié)束節(jié)點(diǎn)ID诚欠,關(guān)聯(lián)到WF_Node
表
獲得了V_FlowData
之后顽染,“我的歸檔”的計(jì)數(shù)器也就輕松完成了。官方文檔會(huì)告訴你“流程狀態(tài)=1轰绵、表示已完成”粉寞,你可以選擇相信它、然后用實(shí)際查詢結(jié)果教育自己左腔。
public int Completed
{
get
{
string sql = @"SELECT COUNT(*) AS Num FROM V_FlowData
WHERE WFState=3 AND FlowEmps LIKE '%@" + BP.Web.WebUser.No + ",%' ";
return BP.DA.DBAccess.RunSQLReturnValInt(sql);
}
}
“我的歸檔”從UI畫(huà)面~WF\Completed.aspx
到UC控件~WF\UC\Completed.ascx
都需要自己創(chuàng)建(參照“UI外殼結(jié)構(gòu)規(guī)則”)唧垦,遵照風(fēng)格,真正的代碼也藏到UC控件中翔悠。
【定制模塊】“歸檔”UC第一部分:獲得流程記錄集(調(diào)用SDK接口)
需創(chuàng)建一個(gè)BP.WF.Dev2Interface.DB_GenerCompleted()
方法业崖,參考“我的已辦”中用到的DB_GenerRuning()
更為方便。
“少佐對(duì)BP.WF.Dev2Interface.DB_GenerRuning()
已做過(guò)了精簡(jiǎn)蓄愁,”巴特發(fā)現(xiàn)双炕,
//Kusanagi: 1.コーディングスタイル改善 2.ソーティング
WF.Port.WFEmp emp = (WebUser.IsAuthorize) ? new Port.WFEmp(WebUser.No) : null;
sql = "SELECT a.WorkID FROM WF_GenerWorkFlow A, WF_GenerWorkerlist B WHERE "
+ (string.IsNullOrEmpty(fk_flowNo) ? "" : ("A.FK_Flow='" + fk_flowNo + "' AND "))
+ "A.WorkID=B.WorkID AND B.IsEnable=1 AND B.IsPass=1"
+ " AND B.FK_Emp='" + WebUser.No + "'"
+ (emp == null ? "" : (" AND A.FK_Flow IN " + emp.AuthorFlows));
GenerWorkFlows gwfs = new GenerWorkFlows();
gwfs.RetrieveInSQL(GenerWorkFlowAttr.WorkID, "(" + sql + ")", "RDT", true);
return gwfs.ToDataTableField();
“懶如伊人都忍不住要對(duì)這Coding Style出手改了吧~還有補(bǔ)了Sorting排序〈樽ィ”巴特從注釋中讀到妇斤。
值得注意的是,這里首次出現(xiàn)了ORM映射,就是GenerWorkFlows.RetrieveInSQL()
這段(排序也是改在這里)站超。
【概念】ORM映射(Object-Relational Mapping)
實(shí)體類與關(guān)系型數(shù)據(jù)表之間的映射荸恕。以GenerWorkFlow
實(shí)體類為例,
- 實(shí)體類都繼承自
BP.En.Entitiy
基類(或其輔助用子類)- 實(shí)體類都有一個(gè)集合類(如
GenerWorkFlows
)死相,并繼承自集合型的BP.En.Entities
類(或其輔助用子類)- 實(shí)體基類的集合型
BP.En.Entities
中融求,已實(shí)現(xiàn)了從相應(yīng)關(guān)系數(shù)據(jù)表讀取實(shí)體實(shí)例集合的公開(kāi)方法(如RetrieveInSQL()
)- 實(shí)體基類
BP.En.Entity
中,已實(shí)現(xiàn)了對(duì)應(yīng)到單條關(guān)系數(shù)據(jù)表記錄的CRUD(增刪改查)操作- 實(shí)體類中必須重載的算撮,就是只讀屬性
EnMap(實(shí)體映射)
生宛,需在這里聲明所關(guān)聯(lián)的關(guān)系數(shù)據(jù)表的名稱(如Map map = new Map("WF_GenerWorkFlow")
)、追加需映射到實(shí)體類屬性集的數(shù)據(jù)表字段(如map.AddTBIntPK(GenerWorkFlowAttr.WorkID, 0, "WorkID", true, true)
添加了從WorkID
字段到同名屬性的映射肮柜,并且從方法名可以看出陷舅,該字段可用輸入框渲染(TB
)是數(shù)值型(Int
)且是主鍵(PK
))- 實(shí)體類的集合類中必須實(shí)現(xiàn)的,只有只讀屬性
GetNewEntity
审洞,通常只需象工廠類一樣new
一個(gè)實(shí)體類的實(shí)例即可- 基本屬性(如
GenerWorkFlowAttr
中所列出)什么的莱睁、只屬于具體實(shí)體類的個(gè)性/表相,它們會(huì)在EnMap
的get
實(shí)現(xiàn)中被一一映射到關(guān)系數(shù)據(jù)表的字段上*提示:映射思想是CCFlow的核心靈魂之一(官方語(yǔ))芒澜,貫穿于方方面面:類映射仰剿、UI展現(xiàn)映射、字段關(guān)系映射撰糠、查詢條件映射酥馍、方法映射等等。
“我們用到的是V_FlowData
視圖阅酪,需要自己配一個(gè)FlowData
實(shí)體類咯旨袒?”巴特繼續(xù)自言自語(yǔ)著…至少有塔奇克馬做伴、做定制開(kāi)發(fā)類任務(wù)時(shí)也都并不孤單吧术辐。
“匹配顯示已有一個(gè)實(shí)體類的代碼中包含了V_FlowData
”塔奇克馬提供了一條有價(jià)值的智能助言(IntelliHint)砚尽。
“哦?打開(kāi)看看——果然辉词!實(shí)體類BP.WF.FlowData
”巴特為這個(gè)小確幸不由輕揚(yáng)了下嘴角——“你裝的這付義眼有些忒大必孤,大到都無(wú)法再透你的心靈”草薙在時(shí)會(huì)這樣調(diào)侃他。
“我的心靈…守護(hù)天使瑞躺,如果你仍舊在線敷搪,就請(qǐng)繼續(xù)給我些幸運(yùn)吧〈鄙冢”
//BP.WF.FlowData - revision 2
public override Map EnMap
{
get
{
if (this._enMap != null)
return this._enMap;
//關(guān)系數(shù)據(jù)表映射
Map map = new Map("V_FlowDataPlus"); //為獲得名稱使用V_FlowData的改裝體
......
//字段-屬性映射
map.AddTBIntPKOID(FlowDataAttr.OID, "WorkID");
map.AddTBInt(FlowDataAttr.FID, 0, "FID", false, false);
map.AddDDLEntities(FlowDataAttr.FK_Dept, null, "部門(mén)", new Port.Depts(), false);
map.AddTBString(FlowDataAttr.Title, null, "標(biāo)題", true, true, 0, 100, 100);
map.AddTBString(FlowDataAttr.FlowStarter, null, "發(fā)起人", true, true, 0, 100, 100);
......
map.AddSearchAttr(FlowDataAttr.FK_NY);
map.AddSearchAttr(FlowDataAttr.WFState);
map.AddSearchAttr(FlowDataAttr.FK_Flow);
map.AddHidden(FlowDataAttr.FlowEmps, " LIKE ", "'%@@WebUser.No%'");
//方法映射
RefMethod rm = new RefMethod();
rm.Title = "工作報(bào)告";
rm.ClassMethodName = this.ToString() + ".DoOpen";
this._enMap = map;
return this._enMap;
}
}
ORM問(wèn)題解決赡勘,于是BP.WF.Dev2Interface.DB_GenerCompleted()
就可以寫(xiě)成,
WF.Port.WFEmp emp = (WebUser.IsAuthorize) ? new Port.WFEmp(WebUser.No) : null;
sql = "SELECT OID FROM V_FlowData WHERE "
+ (string.IsNullOrEmpty(fk_flowNo) ? "" : ("FK_Flow='" + fk_flowNo + "' AND "))
+ "WFState = " + WFState.Complete
+ " AND FlowEmps LIKE '%@" + WebUser.No + ",%'"
+ (emp == null ? "" : (" AND FK_Flow IN " + emp.AuthorFlows));
FlowDatas fds = new FlowDatas();
fds.RetrieveInSQL(FlowDataAttr.OID, "(" + sql + ")", "FlowStartRDT", true);
return fds.ToDataTableField();
當(dāng)山桂花飄香時(shí)捞镰,那段混合著斑駁陽(yáng)光颯颯白衣與那個(gè)人盈盈笑聲的影像就會(huì)再次被加載到記憶里闸与。
“這是真實(shí)的存在毙替,不是幻覺(jué)迷宮〖#”
(未完待續(xù)厂画,繼半自動(dòng)單兵武器站BP.WF.Dev2Interface
之后,可組裝中型武器BP.En.QueryObject
將登場(chǎng))