使用本示例需通過docker容器,請先下拉jxTMS的docker鏡像并按說明啟動tms容器,并從helloWorld開始嘗試。
jxTMS簡易流程的查詢
任何一種業務管理,起碼都需要兩點:
- 業務的辦理
- 業務辦理情況的查詢
簡易流程也同樣如此。我們前面已經實作sfDemo流程,是以現在我們還需要為其添加查詢功能。和之前的資料表一樣,實作業務查詢功能需要做如下工作:
- 定義資料源
- 定義清單顯示與查詢界面
- 設定查詢條件
- 對查詢出來的資料進行加工
- 添加查詢入口
大家可以先回想一下前面我們在條件查詢以及資料表等節所示範的内容,先自己做一下,這樣再來看我們的示範會比較容易了解。
定義資料源
在sql檔案中添加:
sql listDemoSF
from affair as ta
select ta.all
where ta.Purpose=='demo'
orderBy ta.CreateTime DESC;
由于我們沒有在data檔案定義自己的流程資料類,那麼jxTMS會自動使用預設的affair類作為sfDemo流程的流程資料類。由于affair是提供預設流程資料類的,是以我們在sfDemo流程啟動時【使用者點選了發起申請中申請人填寫部分的确認按鈕,對應的處理函數是@myModule.request(‘sfDemo’, ‘demoApply’, ‘dual’)标記的sfDemoApply_dual函數】,将sfDemo的流程資料對象的Purpose設定為demo。是以資料源listDemoSF就是查詢Purpose為demo的affair。
注:如果想定義自己的流程資料類,則除通常的ID、CreateDate之外,必須聲明如下的三個屬性:
field Info json
field Extant json
field FlowExec json
同時,還需要在capa.py檔案中增加一個joType的成員函數:
def joType(self):
return '自己在data檔案定義的流程資料類名'
重載了joType函數傳回一個資料類名,jxTMS就不會再使用affair來記錄流程資訊,而是用joType所指定的類名建立一個流程資料對象,然後将流程資訊記錄到該對象的Info、Extant、FlowExec中。
定義清單顯示與查詢界面
在web檔案中添加:
web listDemoSF type div;
web listDemoSFt0 parent listDemoSF type table title="查詢條件",width=900;
with listDemoSFt0 row 0 col c0 web n type text text="類型:",width=120;
with listDemoSFt0 row 0 col c1 web n bind demoType type input width=120;
with listDemoSFt0 row 0 col c2 web n type text text="名字:",width=120;
with listDemoSFt0 row 0 col c3 web n bind demoName type input width=120;
with listDemoSFt0 row 1 col c0 web n type text text="查詢時間段起點:",width=120;
with listDemoSFt0 row 1 col c1 web n bind startDate type dtpicker width=120,minuteStep=5,initDisp=false;
with listDemoSFt0 row 1 col c2 web n type text text="查詢時間段終點:",width=120;
with listDemoSFt0 row 1 col c3 web n bind endDate type dtpicker width=120,time=false,initDisp=false;
with listDemoSFt0 row 2 col c0 web n type button width=80,motion=cmd,demand=reSearch,text='搜尋',onlyOnce=false;
web listDemoSFt1 bind tableTotalCount parent listDemoSF type table title="簡易流程demo清單",width=900,pagination=true,query=search,queryParam={'listTable':'listDemoSFt1'};
with listDemoSFt1 col demoID head demoID hide=true;
with listDemoSFt1 col demoCreateTime head 建立時間 width=80;
with listDemoSFt1 col demoType head 類型 width=80;
with listDemoSFt1 col demoName head 名字 width=80;
with listDemoSFt1 col creator head 建立人 width=80;
with listDemoSFt1 col demoState head 狀态 width=80;
with listDemoSFt1 col op1 head 檢視 width=60;
其中startDate、endDate是新出現的控件:日期時間選擇器。出于示範的目的,startDate設定為帶時間選擇、5分鐘為最小機關;endDate設定為不帶時間。
類似的可查詢的資料表,在前面講解過,大家可回看一下,然後對照着最後顯示出來的界面一一過一下就好了。
設定查詢條件
在capa.py檔案中修改setSearchCondition函數:
def setSearchCondition(self, db, ctx):
if self.dataSource == 'demo.listDemoData':
cn = self.getInputBoolean('demoNoUsed')
if cn:
self.sql.addContion('demoData', 'NoUsed', jxCompare.Equal,cn)
cn = self.getInputString('demoName')
if utils.valid(cn):
self.sql.addContion('demoData', 'Name', jxCompare.Match,cn)
elif self.dataSource == 'demo.listDemoSF':
cn = self.getInputString('demoType')
if utils.valid(cn):
self.sql.addContion('affair', 'Type', jxCompare.Like,cn)
cn = self.getInputString('demoName')
if utils.valid(cn):
self.sql.addContion('affair', 'Name', jxCompare.Like,cn)
ds = self.getInputDate('startDate')
if not utils.isNone(ds):
self.sql.addContion('affair', 'CreateTime',jxCompare.GreatEqual, ds)
de = self.getInputDate('endDate')
if not utils.isNone(de):
self.sql.addContion('affair', 'CreateTime', jxCompare.LessEqual, utils.getDateEndBefore(de))
startDate和endDate是日期,是以應用getInputDate讀取,如果用getInput則讀到的是一個字元串。日期時間選擇器控件所選擇的時間,是我們所選擇的時間點,而由于endDate不帶時間【即便帶了也一樣】,是以endDate其實是我們所選時間的0點0分0秒,而我們一般的概念中,選擇的結束時間都是包括在内的,這就會導緻使用者了解的是所選日期一天都算在内,而日期時間選擇器所給出的卻是當天的開始,就會造成一天的誤差。是以我們這裡用utils.getDateEndBefore函數,來擷取所給日期【不管什麼時間】的最後一個毫秒所對應的時間點。這就保證了使用者了解的準确執行。
我們之前在示例資料表的查詢的時候,增加過listDemoData,現在又增加了listDemoSF,可setSearchCondition函數、dispAffairInfo函數等系統函數都隻有一個,怎麼辦呢?如同上面的示例一樣,通過對目前所加載的資料源來區分使用者打開的到底是listDemoData還是listDemoSF,這個目前加載的資料源的全名就放到了對象變量中的self.dataSource中。
我們的流程資料對象的類名是affair,是以大家查詢的就是affair的Type和Name,這裡使用的Like算子。
對查詢出來的資料進行加工
在capa.py檔案中,修改dispAffairInfo函數:
def dispAffairInfo(self,db,ctx,json, jo):
if self.dataSource == 'demo.listDemoData':
json.set("demoID", jo.ID)
json.set("demoCreateTime", jo.CreateTime)
json.set("demoType", utils.getMsg('{}-type',jo.Type))
json.set("demoName", utils.getMsg('{}-name',jo.Name))
json.set("demoTypeName", utils.getMsg('{}-{}',jo.Type,jo.Name))
json.set("demoNoUsed", jo.NoUsed)
elif self.dataSource == 'demo.listDemoSF':
json.set("demoID", jo.ID)
json.set("demoCreateTime", jo.CreateTime)
json.set("demoType", utils.getMsg('{}-type',jo.Type))
json.set("demoName", utils.getMsg('{}-name',jo.Name))
json.set("creator", jo.Info.get('creator'))
state = '審批中'.decode('utf-8')
if jo.State == 1:
state = '審批結束'.decode('utf-8')
json.set("demoState",state)
json.set('op1',self.getViewA(self.getFullName(),'sfDemo',jo.Name,jo.ID))
dispAffairInfo函數同樣用self.dataSource區分了使用者打開的到底是那個界面。其中比較特殊的是對op1的設定。大家回看一下web檔案中listDemoSF的定義,會看到op1的列頭是檢視,應該可以猜測出來,這裡應該就是點選後檢視相應的流程的入口。請大家到時點選看看。
注:getViewA就是擷取依據本功能子產品的相關設定來擷取檢視某資料對象的入口。其函數簽名為:
public static infoBlock getViewA(String capaname,String viewWeb,String joname,Long joid);
其中的參數說明如下:
- capaname:功能子產品的名字,即:module().name()
- viewWeb:顯示界面,對于sfDemo流程來說,就是sfDemo
- joname:要顯示的資料對象名,jxTMS用來動态設定界面的title
- joid:要顯示的資料對象id
然後getViewA就會利用這些參數動态生成一個針對本資料對象的檢視入口,供使用者點選後檢視。
添加查詢入口
在op.py中添加:
@biz.Motion('demo.demo1','disp','listDemoSF')
@biz.OPDescr
def op1(json):
json.setShortcut('示範'.decode('utf-8'),'demo簡易流程查詢'.decode('utf-8'))
json.setParam('dispType','list').setParam('dataSource','demo.listDemoSF')
我們将sql、web、op.py、capa.py等檔案按用sftp管理jxTMS的代碼所述更新到/home/tms/codeDefine/demo/demo/demo1目錄中。
然後執行一次熱機重新整理後,由于快捷欄中的入口有變化,是以先要登出,再次登入後點選快捷欄中的【示範->demo簡易流程查詢】,然後看看顯示出來的界面是什麼樣的并執行下查詢。
結語
大家看到現在的setSearchCondition函數和dispAffairInfo函數,是否覺得太不kiss了?!簡單的很,拆成兩個子產品啊。大家可以自己嘗試一下。
不拆成兩個子產品可以嗎?!當然可以,筆者在開始就說一個功能子產品是由data、sql、web、op.py、capa.py五個檔案組成,其中data、sql、op.py這三個檔案的内容都不會太多,如果太多那真的是應該拆分為其它子產品了。而web、capa.py之外,jxTMS還會從.web字尾名的檔案加載界面定義,從.py字尾名的檔案加載功能代碼,是以大家也可以将listDemoData和listDemoSF做一下拆解。