天天看點

jxTMS使用示例--簡易流程

使用本示例需通過docker容器,請先下拉jxTMS的docker鏡像并按說明啟動tms容器,并從helloWorld開始嘗試。

jxTMS的簡易流程

這一節我們做個複雜點的:一個申請審批流程。

一件事如果需要多人協作完成,業務管理系統一般是将其組織為一個流程來把各作業環節串聯起來。但一般意義上的流程既較為複雜又門檻頗高,對于jxTMS的所期望的低成本開發來說,對開發者的要求有點高。是以jxTMS對一般意義上的流程進行了簡化,稱之為簡易流程。

簡易流程是面向企業中大量的常見流程,對一般性的流程做了些簡化:

  • 去掉了标準流程的與或節點的概念,每個節點就是或入或出,這樣一來,開發者也不需要過多學習流程應該如何設計、如何排查了。更關鍵的再不會因為經驗不足設計出一個走不通的流程了
  • 去掉了節點間的自由流轉,即将标準流程可并行的多線作業縮減為隻有一條逐個節點依次推進的作業線,該作業線就是從第一個業務節點依次執行到最後一個節點,如果某節點被拒絕則傳回到前面的某節點重新執行

注:如果大家對一般性的流程是什麼樣的不太了解,那就先搞清楚jxTMS的簡易流程,等熟悉了之後再針對性的添加上面所說的這兩個被簡化掉的内容,就容易了解一般的流程了

也就是說,簡易流程就是針對大多數的線性作業,将作業環節按序依次推進,每節點就隻有兩個動作:

  • 同意:則推進到下一個環節,如果是最後一個節點,則流程結束
  • 拒絕:預設傳回第一個環節,但也可選之前的某個環節

所有的申請審批都是此種模式的流程。

制作一個流程所需的工作内容

jxTMS已經為簡易流程做了大量的支援工作,是以在jxTMS中制作一個簡易流程的工作得到了大大的簡化。

首先,需要協助業務部門進行流程的基本設計,包括:

  • 流程圖
  • 各節點的業務操作邏輯
  • 各節點的執行人【角色】

然後需要做的隻有:

  • 制作整個流程共享的流程作業界面
  • 為每個節點的業務處理進行程式設計
  • 編寫整個流程

但是呢,一個流程建立了,其執行情況如何我們還要提供清單查詢的功能,是以我們還需要制作該流程清單查詢的相關内容。

下面我們以一個最簡單的三環節申請審批流程為例來示範如何制作該流程。該流程簡述如下:

  • 申請:任意的申請者填寫申請資料
  • 稽核:manager角色【目前隻映射給了manager使用者】對申請人所申請的事進行稽核
  • 審批:manager角色進行審批

注:由于是示範,所有作業過程全部由manager來完成。以後我們會講解如何将各作業環節配置設定給不同的崗位

制作流程頁面

在web檔案中添加:

web sfDemo type div;
web sfDemoApply parent sfDemo type div cover=true;
web sfDemoApplyt1 parent sfDemoApply type table title='申請人填寫',width=900,alone=true;
with sfDemoApplyt1 row 0 col c0 web n type text text='類型:',width=100,extra=[{'color':'red','text':'*'}];
with sfDemoApplyt1 row 0 col c1 web n bind demoType type input  verify=[len>0] width=200,logChangedDisp='類型';
with sfDemoApplyt1 row 0 col c2 web n type text text='名稱:',width=100,extra=[{'color':'red','text':'*'}];
with sfDemoApplyt1 row 0 col c3 web n bind demoName type input  verify=[len>0] width=200,logChangedDisp='名稱';

web sfDemoApplyt2 parent sfDemoApply type table title='申請人說明',width=900,forDisp=false,alone=true;
with sfDemoApplyt2 row 0 col c0 web n type text text='意見:',width=100;
with sfDemoApplyt2 row 0 col c1 web n bind applySuggestion type textarea width=800,logChangedDisp='意見';
with sfDemoApplyt2 row 1 col c0 web n type text text='簽發時間:',width=100;
with sfDemoApplyt2 row 1 col c1 web n bind applyDate type text width=200;
with sfDemoApplyt2 row 1 col c2 web n type text text='簽發人:',width=100;
with sfDemoApplyt2 row 1 col c3 web n bind applyBy type text width=200;
with sfDemoApplyt2 row 2 col c0 web n type button width=80,text='确認',needVerify=['demoType','demoName'],motion=cmd,
 	demand=simpleFlowDual,onlyOnce=false,delay=2000,
 	params={'flowName':'sfDemo','nodeName':'demoApply','active':'accept','signBy':'applyBy','signDate':'applyDate'};

web sfDemoConfirm parent sfDemo type div cover=true;
web sfDemoConfirmt1 parent sfDemoConfirm type table title='稽核',width=900,alone=true;
with sfDemoConfirmt1 row 0 col c0 web n type text text='意見:',width=100;
with sfDemoConfirmt1 row 0 col c1 web n bind confirmSuggestion type textarea width=800,logChangedDisp='意見';
with sfDemoConfirmt1 row 1 col c0 web n type text text='簽發時間:',width=100;
with sfDemoConfirmt1 row 1 col c1 web n bind confirmDate type text width=200;
with sfDemoConfirmt1 row 1 col c2 web n type text text='簽發人:',width=100;
with sfDemoConfirmt1 row 1 col c3 web n bind confirmBy type text width=200;
with sfDemoConfirmt1 row 2 col c0 web n type button width=80,text='同意',motion=cmd,
	demand=simpleFlowDual,params={'flowName':'sfDemo','nodeName':'demoConfirm','active':'accept','signBy':'confirmBy','signDate':'confirmDate'};
with sfDemoConfirmt1 row 2 col c2 web n type button width=80,text='拒絕',motion=cmd,
	demand=simpleFlowDual,params={'flowName':'sfDemo','nodeName':'demoConfirm','active':'reject','signBy':'confirmBy','signDate':'confirmDate'};

web sfDemoApprove parent sfDemo type div cover=true;
web sfDemoApprovet1 parent sfDemoApprove type table title='審批',width=900,alone=true;
with sfDemoApprovet1 row 0 col c0 web n type text text='意見:',width=100;
with sfDemoApprovet1 row 0 col c1 web n bind approveSuggestion type textarea width=800,logChangedDisp='意見';
with sfDemoApprovet1 row 1 col c0 web n type text text='簽發時間:',width=100;
with sfDemoApprovet1 row 1 col c1 web n bind approveDate type text width=200;
with sfDemoApprovet1 row 1 col c2 web n type text text='簽發人:',width=100;
with sfDemoApprovet1 row 1 col c3 web n bind approveBy type text width=200;
with sfDemoApprovet1 row 2 col c0 web n type button width=80,text='同意',motion=cmd,demand=simpleFlowDual,
	params={'flowName':'sfDemo','nodeName':'demoApprove','active':'accept','signBy':'approveBy','signDate':'approveDate'};
with sfDemoApprovet1 row 2 col c1 web n type button width=80,text='拒絕',motion=cmd,demand=simpleFlowDual,
	params={'flowName':'sfDemo','nodeName':'demoApprove','active':'reject','signBy':'approveBy','signDate':'approveDate'};
with sfDemoApprovet1 row 2 col c3 web n bind exportAdditional type combobox width=80,values=[{'value':'demoApply','text':'退回申請人'},{'value':'demoConfirm','text':'退回稽核'}],notExtant=true;
           

制作好的界面顯示出來是如下的模樣:

jxTMS使用示例--簡易流程

注:先不要管【日志、資料變動等】這三個工具條,以後我們會示範的

我們所定義的這個界面:sfDemo。其包括了三個子div【組容器】:

  • sfDemoApply:申請人界面,由申請人填寫的部分,又包括了申請人填寫、申請人說明兩個表
  • sfDemoConfirm:稽核界面,由負責稽核的人員進行操作
  • sfDemoApprove:審批界面,由負責審批的人員進行填寫

大家先不要管這個界面的細節,等完成了整個流程後,再對照着web界面的參考:web界面定義、web控件的一般定義、web界面中各控件的定義來搞明白界面的定義。

對各節點的邏輯處理分别程式設計

然後我們打開capa.py,在demo1類的定義中添加:

#申請節點的處理
#request在這裡的參數表是:流程名、節點名、dual【指定為相應節點的邏輯處理】
@myModule.request('sfDemo', 'demoApply', 'dual')
def sfDemoApply_dual(self, db, ctx,ca,active):
	#ca是記錄目前流程各種狀态與資料的對象事件,也是
	#active是目前使用者的操作,點選同意按鈕是accept,點選否決按鈕是reject
	ca.Type=self.getInput('demoType')
	ca.Name=self.getInput('demoName')
	ca.Purpose='demo'
	ca.State=0
	ca.CreatorID=ctx.getCaller().id()
	ca.Info.set('creator',ctx.getCaller().abbreviation())
	
	#提示并關閉界面
	return True

#流程結束後的處理
#虛拟節點end訓示是整個流程結束後的邏輯處理
@myModule.request('sfDemo', 'end', 'dual')
def sprjend_dual(self, db, ctx,ca,active):
	#結束
	ca.State=1
	db.update(ca,'State')

	#提示并關閉界面
	return True
           

注:jxTMS在每個節點都執行了大量的預設操作,而稽核與審批兩節點并沒有需要執行的額外處理,是以省略

編寫流程

jxTMS中的簡易流程是用文本進行定義的,大家在capa.py,在demo1類的定義中添加:

#指定本功能子產品的預設顯示界面【jxTMS在自動指派任務時需要此預設界面】
def viewWebInterface(self):
	return 'sfDemo'

#定義一個名為sfDemo的簡易流程
@myModule.simpleFlow('sfDemo')
def sfDemo():
	'''
	web sfDemo;
	node demoApply 申請 web sfDemoApply ;
	node demoConfirm 稽核 web sfDemoConfirm needRole manager notJump;
	node demoApprove 審批 web sfDemoApprove needRole manager notJump;
	'''
	pass
           

簡易流程的定義,是用myModule.simpleFlow(流程名)修飾的一個空函數的__doc__中進行定義的,大家可參考簡易流程中的說明來了解。概要的說,就是定義了一個sfDemo的流程,該流程的web界面也叫sfDemo,其包括了三個節點:申請、稽核、審批,指定了每個節點可操作的子界面,後兩個節點都指派給manager角色的使用者來執行【而且不可跳過】。

增加流程建立的入口

在op.py中添加:

@biz.Motion('demo.demo1','disp','sfDemo')
@biz.OPDescr
def op1(json):
	json.setShortcut('示範'.decode('utf-8'),'發起申請'.decode('utf-8'))
	json.setParam('notCover','sfDemoApply')
           

就是一個顯示流程界面的sfDemo,唯一不同的是有一個notCover的參數被設定為了申請節點所對應的界面:sfDemoApply。意思就是不要遮擋sfDemoApply界面,什麼意思呢?!等流程建好,大家多執行幾次就會了解了的,是以現在先不管了。

我們将web、op.py、capa.py等檔案按用sftp管理jxTMS的代碼所述更新到/home/tms/codeDefine/demo/demo/demo1目錄中。

然後執行一次熱機重新整理,由于快捷欄中的入口有變化,是以先要登出,再次登入後點選快捷欄中的【示範->發起申請】,然後看看顯示出來的界面是什麼樣的。

遮罩

大家會看到【發起申請】這個界面,自上而下由四張表組成:申請人填寫、申請人說明、稽核、審批。在過了一小會之後,稽核、審批兩表會突然變灰了,而且裡面的控件也無法再被點選到。

大家請回過頭來,看一下sfDemo界面的定義,會發現sfDemoApply【參考simpleFlow(‘sfDemo’)的定義,可以觀察到其是demoApply即申請節點所對應的web操作界面】、sfDemoConfirm【參考simpleFlow(‘sfDemo’)的定義,可以觀察到其是demoConfirm即稽核節點所對應的web操作界面】、sfDemoApprove【參考simpleFlow(‘sfDemo’)的定義,可以觀察到其是demoApprove即審批節點所對應的web操作界面】都有一個之前從沒看到過的屬性:

cover=true
           

大家看一下組控件中對cover屬性的講解。當一個組容器設定了cover=true後,其在界面初始化與資料裝定之後,就會被用一個罩子遮擋起來,進而使得使用者能看到其内容但無法對其包含的控件進行操作。

大家再看一下op.py檔案中【發起申請】這個入口,我們設定了一個參數:

json.setParam('notCover','sfDemoApply')
           

意思也很明顯,就是在打開通過【發起申請】這個入口打開sfDemo界面後,取消sfDemoApply界面的遮擋,也就是将sfDemoApply的遮罩關閉掉,進而使得使用者可以填寫申請資訊以及進行說明,并點選【确認】按鈕。

注:大家有沒有想到一種攻擊方式:在某種情況下【如請款被退回重新填寫】,通過按【tab】鍵将焦點移動到總經理的意見那一欄後,輸入同意支付一百萬,然後再按【tab】鍵将焦點移動到總經理對應的同意按鈕上,敲擊【回車】,如果财務人員未注意簽發人或簽發人正好同名【這就是jxTMS為什麼要用簡稱的原因】,就完成了一次非法的申請審批。針對此種情況,jxTMS中禁用了【tab】鍵,使用者是無法通過按動【tab】鍵來切換焦點的

取消【tab】鍵、加遮罩、取消遮罩,這豈不是很麻煩啊,jxTMS為什麼要這麼做呢?!大家看一下sfDemo界面的web定義,是不是覺得的很麻煩,可sfDemo流程隻有簡單的三個步驟,而且每個步驟都非常簡單。那麼大家想一下,如果是一個複雜的流程,其界面是不是就會非常的麻煩?!

那麼,如果不使用遮罩的話,任何一個節點就必須同時設計一個寫界面、一個隻顯示的讀界面,然後在流轉到自己的那個節點的時候,其它節點的界面都是讀界面、自己的這個節點的界面是寫界面。而這樣一來,界面開發的工作量就大了一倍,管控隻會更複雜。因為,如果是其他人檢視呢?如果是自己已經做完了想再看看呢?

注:另一種實作方案是将該節點所對應的組容器中的所有子控件禁用掉,但jxTMS的控件都是動态生成的、界面管理本身就非常複雜,如果采用本方法,會導緻界面管理進一步複雜化,這對于隻有一個開發者的jxTMS來說,筆者實在不想出現該禁用又被錯誤的使能,或是該使能的時候卻沒有正确的使能

開發過程可能需要修改流程界面啊,那麼如果有修改,則還必須保持兩個界面的同步。是以呢,思來想去,筆者認為簡單才是硬道理,jxTMS的實作再複雜,隻要測試完備就不怕,換來的是開發者成本、風險的雙雙下降,還是一半以上的下降,最終還是采用了遮擋的方案。

結語

簡易流程比較複雜,而本節内容就已經較多了,是以就不再繼續,大家對照顯示出來的【發起申請】界面,仔細回顧一下本節内容,這樣可以加深對簡易流程的了解。我們下一節開始講解簡易流程的流轉。