jxTMS--web界面定義

web界面定義

jxTMS原生是動態web界面模式,即只有一個tms.html頁面,除右上角的四個系統菜單外,其它所有用戶交互都是動態從後臺獲取界面描述,然後根據這個界面描述來動態的生成所需的web控件。

動態web界面的工作流程是:

  • 開發者用文本一行一個的定義web界面的各個控件

  • jxTMS在啓動或熱機刷新時,解析開發者的定義生成對應的webObject保存到組織緩存中

  • 開發者定義disp類型的界面顯示入口【在op.py文件中】

  • jxTMS在用戶登錄時,通過該用戶的角色列表和各入口的role的定義是否匹配,來爲其準備初始界面

  • jxTMS將所有模塊中該用戶有權限的入口全部打包發送到前端,瀏覽器用這些入口信息爲該用戶生成左上角的功能菜單、左側的快捷功能樹

  • 用戶從菜單、快捷欄、工具條等點擊顯示型入口

  • 後臺在確認該用戶有訪問該入口的權限後【動態生成的界面無權限則不顯示該入口,但如果用戶知道了該入口的調用參數,可自行編寫或用我們的自動化腳本測試工具發起攻擊,所以後臺還是會進行權限覈驗的】,加載相應的capa,並將相應的界面描述發送到前端

  • 前端根據入口中的配置和這個界面描述來確定該如何顯示【如顯示到主界面、輔助界面還是彈出對話框等】,並創建相應的控件

  • 後臺等待一下,以確保後臺有足夠的時間生成界面所描述的各控件,然後觸發prepareDisp事件以對該界面進行初始化,並裝定數據

  • 前端用接收到的數據對控件進行裝定,並確定狀態,如是否遮擋、使能、不顯示、自動計算的初始化等等

  • 如果是主界面顯示,後臺還會發送該界面所對應的工具條,前端將其顯示到該界面上方的工具欄處

數據交互

對於輸入型控件,前端會監聽其change事件,實時將數據更新收集後以上一節中的pollData機制發送到後臺,也就是說,用戶的輸入和後臺之間是準同步的,所有的更新都會被實時採集,然後看pollData的間隔發送到後臺。

如果定義了自動計算,則當作爲數據源的某輸入控件發生變化時,其會觸發其所有參與的自動計算公式,而這些自動計算公式的產出方,如果是其它公式的數據源,其也會觸發相應的公式進行計算。也就是說,自動計算是一個自動化的鏈式反應,會將所有受影響的數據全部計算後更新。

注:自動計算就類似於excel中的公式計算,只不過是開發者預先定義好的,然後發送到前端在用戶輸入時自動執行,大家請先在demo組織中,以銷售角色登錄後點擊創建訂單增加幾個產品,輸入數量、列表價、報價來看一下。然後再閱讀關於自動計算的講解會比較容易理解

用戶如果點擊了某按鈕,前端會在向後臺請求相應的cmd入口前執行兩個動作:

  • 執行數據校驗,如果該按鈕定義了需校驗的數據名,則前端會調用綁定了這些數據名的控件的校驗函數,對用戶輸入到該控件中的值用開發者所定義的數據合法性檢查規則進行校驗,如果校驗不通過,則彈窗發出警告

  • 校驗通過後,爲避免pollData週期過長,有數據未提交,所以會先觸發一次pollData

界面打開後,後臺執行prepareDisp或cmd型事件之後,後臺是以異步的方式通過pollData將相應的輸出數據捎回前端的。這些數據包括:全局變量、上下文變量、控件數據、控件屬性值【如對違反業務規則的數據標紅,即控件加紅框以做警示】、提示信息等等,前端會將相應的數據自動分發。

注:由於是異步模式,所以用戶完全可以打開多個界面進行協作,如在主界面打開訂單審批界面,然後再在輔助界面打開發起這個訂單的銷售的業績表、回款等來做出是否批准的判斷。所以一次pollData會捎帶回多個capa的數據,前端會根據不同的capa分發到相應的控件,而不會混亂。而這個最普通的場景也是筆者一定要採取異步模式的根本原因,因爲在這個場景下,同步模式需要開發者來自行管理多個界面的數據交互,直接導致對開發者的要求高上很多

數據名

webObject是xTMS所有動態web控件的根對象,有三個最重要的屬性:

  • 控件名【原生名】,控件的原生名只要在同一個空間中不重名即可。由於在前端,很多web控件都是由多個html元素組合而來,如數據表,包括表頭、分頁、增加新行按鈕等等,所以就需要一個不重複的名字對這些內部的html元素標記供需要時能準確引用

注:爲能在用戶同時打開多個相同的界面時仍能確保準確定位,控件名更進一步的分爲原生名和動態名,動態名是當前capaid+原生名而得來的,這樣就確保了動態生成的控件的唯一性,而不會出現引用錯誤

  • 控件類型,目前jxTMS支持:文本、單行輸入、多行輸入、按鈕、a【工具條】、tag【標記】、數據表、單選框、多選框、樹型菜單、日期拾取器、下拉框、文件上傳、圖表【目前只支持bar型數據顯示】、代碼編輯器、div【應該是組容器,即用來打包其它控件的group以作爲一個整體進行顯示控制的,但一開始因爲就是用div進行打包的,就一直沿用了下來】

注1:目前有兩種組容器,一個是div主要用來整體加載或卸載以及作爲一塊工作區域進行顯示控制的;一個是容器表【上面說的是數據表,用來分頁顯示數據的】,主要是爲了簡化控件行列對齊的。在早期,筆者用的是top、left等直接進行定位,但發現對齊實在是太浪費時間了,後來才採用了容器表以行列方式進行對齊,這就大大簡化了前端的位置定義
注2:請開發者不要用top、left進行自主定位。因爲筆者經過反覆嘗試後,認爲jxTMS所定位的個人開發者實在是無法在美學和極少的工作量方面達到折中,所以後期增加的控件已經放棄了top、left的定位支持,所以無法保證這兩個屬性在各種控件中都能正常工作。關於美學問題,只能等jxTMS逐漸進化,加強在前端的美學設計後來解決,筆者也堅信,這纔是根本的解決之道
注3:筆者也曾非常擔心過這種表格行列對齊的界面能否爲用戶所接受,但實踐後發現,對於目前的中小微企業來說,信息化管理是有無問題,是能否真正幫助其提高作業效率、降低運行成本的問題,就沒有任何用戶對界面提出過任何異議:)

  • 綁定的數據名,前端由於需要同時管理非常多的web控件,所以需要爲這些動態web控件起一個全局唯一的動態名進行管理,但這個動態名太複雜,對開發者非常不友好,會因起名與使用而浪費大量的時間與精力,而一旦輸錯排查起來都非常的困難。而我們的編程模型是:用戶點擊一下,就執行一小段代碼。所以必須爲這些控件起一個局部的、簡短的、最好有強烈業務特性的數據名。這個數據名只有需要和後臺交互的web控件需要綁定,而這個數據名沒有任何限制,只要在一個capa內沒有重複即可

注:jxTMS中變量名的命名爲java標準的變量命名方式,也並沒有限制不得使用中文。但由於jxTMS的正確運行是由底層java、前端jQuery、開發者的python【基於jython,支持到python2.7,只使用到非常少的python特性,所以已經足夠使用】三種代碼環境共同協作完成的,所以建議不要用中文,以儘量減少不必要的轉碼風險

綁定了數據名的web控件,可以直接在python代碼中用如下兩個函數進行訪問其值:

#讀用戶在控件中的輸入
self.getInput(數據名)
#寫到控件中
self.setOutput(數據名,值)

注1:文件上傳控件是直接將文件保存到一個臨時目錄中,然後開發者可在self.importFilepath得到該文件的訪問路徑,例如上傳一個excel文件來導入用戶,則可:

#上傳後,在類似【導入】按鈕點擊所對應的cmd事件中執行
with jxExcel(self.importFilepath,'people') as e:
	...已經打開了上傳文件中名爲people的sheet,可通過e來進行讀寫操作了

注2:上傳文件爲了避免重名等不必要的衝突,所以在上傳時都重起了一個動態名,而且該文件保存在某臨時目錄中,jxTMS會定期清理該目錄,所以上傳文件的使用規則是:即傳即用,用後失效

對於web控件,除了顯示給用戶看的值,有時開發者也需要動態修改控件的屬性,如demo中所演示的:銷售所給折扣低於其權限,則業務規則會將其標紅以提示後繼的審批人員這裏不合規。針對這種情況:

#以原生名來獲取本capa中的控件
wo=self.getWO(控件的原生名)
#設置該控件的屬性,如set('boder','3px solid red')即將該控件標紅--用一個3像素的紅框框起來
wo.set(屬性,值)

注1:大家在看demo所演示的源碼的時候,會發現絕大多數的控件的原生名都是n。這是由於筆者在使用過程中,發現由於有同一個空間原生名不得重複的限制,導致筆者在給控件起名時太過痛苦,尤其是在修改web界面的定義時,一不注意就會導致系統報錯。所以最後筆者利用容器表的表名+行列信息給所有容器表中名爲n的控件自動生成一個原生名,這就大大降低了開發時的工作量和風險
注2:由於名爲n的控件會自動生成一個原生名,所以開發者必須記得如果要修改控件屬性,必須爲其指定一個本空間內不重複的原生名

數據校驗

數據校驗的實現分爲兩步,首先在定義一個需要用戶輸入的web控件時,開發者可以指定用戶輸入的數據需要符合什麼樣的要求:

  • 值比較,如銷售輸入折扣率時應有一個最低限額

  • 長度限制,主要針對字符串,其長度應滿足什麼樣的條件,如密碼長度大於6

  • 日期比較,主要針對字符串轉成的日期,應滿足什麼樣的條件

  • 類型判斷,應是數字、整數、日期格式等

  • 正則表達式,對於更復雜的規則,如判斷是mail、手機號等,可以用javascript的正則表達式定義一個規則,必須滿足該規則才接受

注:具體的校驗規則請參考編程手冊中的相關定義

其次,開發者還需要在用戶輸入完,所要點擊的按鈕的定義中,設置needVerify屬性:

needVerify=['customName','customFax','customType','payType']

則當用戶點擊該按鈕後,前端即檢查這幾個數據名的控件值是否符合其各自的數據准入規則。

注1:由於javascript屬於弱類型語言,一般的控件在輸入時都是作爲字符串類型的,所以需要注意校驗條件的比較是否成立。jxTMS在進行比較時是做了類型轉換的,但開發者仍然需要反覆測試用戶各種奇怪輸入情況下的校驗條件是否成立

注2:前端輸入的數據,在傳遞到後臺後,因爲java是強類型語言,所以底層java代碼會將其轉換爲合適的類型,以確保java對象以及數據對象、數據庫中的列這些數據的數據類型正確而一致。但,開發者用的是python,依然是一種弱類型語言,所以開發者不要使用過於奇怪或會造成歧義的數據格式,最佳的辦法就是隻使用:字符串、整數、浮點數、日期、布爾量這幾種數據類型,其它數據類型,在這麼複雜的javascript【弱類型】、java【強類型】、python【弱類型】、mysql數據庫【已經準確的和java中的類型進行了匹配】集成環境中反覆進行數據類型的準確轉換,jxTMS已經很難了哦:(

注3:jxTMS在前後臺傳送數據使用的是json,而如果文本中混合有回車、tab、單引號、雙引號等各種稀奇古怪的字符,javascript是無法正確轉換的,所以在涉及到多行輸入的控件,jxTMS使用base64編碼後傳送,但java和javascript的base64編碼格式還不一致,需要前後臺協作進行復雜的變換。所以,建議這種涉及多行輸入的控件只用於人-人交互的用戶意見等文本信息,其它需要計算機處理的數據用各種選擇框、下拉框進行採集,萬不得已也要使用單行輸入框【單行輸入框已經限制了一些奇怪字符的輸入】,而將用戶意見之類不加處理的直接保存到數據庫中,在需要時也直接顯示給用戶看,不要讓計算機來處理這些多行文本

多人協作場景下的數據隔離

業務系統中常用的流程就是一個多人協作的典型場景。這樣的協作場景有幾個要求:

  • 數據的共享與隔離,某環節的工作人員,只能操作指定的數據,但可能需要查看前面環節其它人員的處理情況,如demo所演示的訂單審批,銷售經理總得查看一下銷售所輸入的訂單信息吧?但銷售卻不允許在總經理意見那輸入任何文字,更不用說其能點擊總經理的同意按鈕了

  • 數據隱藏,如某訂單非常獨特,可能在通常的訂單成本覈算之外,進行單獨的成本覈算,但成本一般來說都不希望銷售能看到,但總經理進行審批的時候又希望在一個界面中就能看到所有的信息,而不要看到了訂單再打開另外的成本覈算表之類的,這樣的工作效率就太低了,尤其還是時間精力都是最值錢的核心員工

  • 一般情況下,因爲有不同人員的輸入,爲了減少差錯、容易控制,一般都是把輸入和顯示單獨做成不同的界面,在需要錄入的時候使用錄入的界面,其它時候則使用顯示的界面。但如果一個流程有七個處理環節【這還是一般的簡易流程啊】,那麼如果每個環節顯示做一個、錄入做一個,這就需要做十四個獨立的控件組,然後根據不同情況動態決定到底顯示哪些控件組,還需要平衡分別對應同一個數據的輸入控件和顯示控件的名字衝突問題,這就到底開發者的工作量加大了一倍,而作爲通用系統的jxTMS如何協調、控制這個過程的複雜度更是上升了n倍

針對這些問題,jxTMS最終採取了一個最簡單的辦法來解決:遮罩。即不區分某環節你是隻看還是需要錄入,開發者每個環節只需要製作一個錄入的控件組【開發量少了一半】,然後將所有控件組用半透明的遮罩進行遮擋,就實現了用戶可看而無法錄入,然後檢查當前查看的用戶是否需要錄入,如果需要則打開其需要錄入的那個控件組的遮罩即可。

perfect!完美,但有個問題,雖然你用遮罩擋住了讓我點擊然後輸入的可能,但銷售完全可以不停的按tab鍵,移動到總經理的意見那輸入【同意,另給一萬作爲獎勵】,然後再按tab移動到總經理的同意按鈕那,回車!

所以,jxTMS關閉了tab鍵,通過犧牲用戶鍵盤錄入的平均效率來大幅度降低開發者的開發工作量和系統的複雜度,而這兩者筆者經過權衡,認爲是值得的:開發者工作量的下降會直接降低開發成本,系統複雜度的下降會大大提高系統的可靠性、堅固性、也極大的降低了開發者的潛在bug率,這兩者都直接提升了整個系統的性價比。

而性價比的大幅度提升,將鼓勵用戶在更多業務環節、業務處理中使用jxTMS,而使用的越多,則需要用戶錄入的就越少、作業環節就越少、需要審批的環節也越少【因爲業務越來越規範】,用戶在單點損失的效率最終將從整個業務作業效率的巨大提升中得到超額的回報。

注:筆者在用jxTMS開發一個銷售合同審批流程時,原本的折扣率計算等都需要審覈人員在拿到審批單後重新手工計算一遍,而利用jxTMS的自動計算、業務規則審查,該環節只要看看折扣率那裏系統有沒有顯示紅框,沒有直接點擊確定按鈕放行就好了

但是,遮罩引出了一個問題,jxTMS的web控件是先創建控件,然後後臺刷數據過來進行裝定的。對於其它控件都沒問題,但數據表就不成了,因爲數據表在創建的時候,接收到的只是列信息,具體的每行數據是後續刷過來的,而每有一行數據,數據表就會自動伸長一行,整個頁面也會跟着伸長一行。所以如果遮罩一開始就設置,那麼隨着數據表的不斷伸長,其數據行以及數據表下面的控件都可能會逃出遮罩區,而如果其中有輸入控件和按鈕,那這個遮罩有和沒有沒多大的區別。

因此,遮罩就必須在數據裝定完成後才能進行遮擋,但jxTMS的數據又是異步的,雖然一般情況下,用戶操作完畢,在下一個pollData中就會把所有數據全部捎帶回來,但如果網絡延遲比較大呢?!所以呢,遮罩是在顯示完畢5秒後才進行遮擋的。

但是,又來但是了,我當時真的是都快瘋了的啦:( 對於常用的操作界面,哪個按鈕在哪,用戶一定是非常熟悉的,在這5秒內,銷售直接下拉點擊總經理同意按鈕,咋辦?!

所以呢,jxTMS默認所有的操作按鈕都是失能的,只有遮罩遮擋完畢纔會使能。而且這個使能操作是和遮罩去除動作關聯的,如果沒有去除遮罩,其不會使能。

終於有好消息了,這個默認失能竟然帶來了一個巨大的好處,web操作,因爲要從本機到互聯網服務器一來一回,所以系統的反應是比較遲鈍的,用戶如果性子急,看着還沒反應,再點一下肯定會出問題的,所以這個默認失能就順理成章的引出了一個附帶功能:點擊後失能。

但,令我崩潰的是:如果用戶錄入錯誤、數據校驗未通過,那用戶改好了卻發現:失能後就無法再點擊了啊!難道就因爲一個數沒輸對,就讓用戶重新打開再次錄入一遍?!所以,配套的就有一個延時n毫秒後重新使能的功能:

#按鈕默認是先失能以避免在數據未裝定完用戶就有操作,然後再使能,並設置爲點擊後失能
#onlyOnce則是用來控制是否允許再次使能的,如果爲false則先失能delay一段時間,然後再使能,以避免用戶雙擊
#delay則是給出了失能後到再次使能的毫秒計數的間隔
#
#爲什麼會這麼設計呢?!
#說起來都是淚:某個用戶手太快,竟然在瞬間完成了雙擊,導致系統執行了兩次,自然觸發了稀奇古怪的故障:(
#
onlyOnce=false,delay=2000;

上述說明,雖然不需要開發者介入,但還是請開發者務必仔細閱讀,然後根據用戶業務的具體操作來選擇功能按鈕的參數配置,如無特殊情況,強烈建議默認使用上面所給的配置:onlyOnce=false,delay=2000

界面生命週期

所有的capa界面都是顯式生存的:即在需要時後臺檢查需要加載新的界面,會從系統獲取相應的capa,然後執行:

  • 根據這個capa創建一個新的capa

  • 爲這個新的capa準備上下文,並將前端ui的代理和其進行綁定

  • 執行相應的disp函數,從系統中讀取相應的控件組描述

  • 對讀到的控件組將前述的從控件的原生名結合新創建的capa爲其生成動態名

  • 將控件組中的所有數據名綁定到上下文中,爲後繼的輸入輸出關聯做好準備

  • 對控件組所涉及到的按鈕、工具條等和調用人就其調用權限進行預處理

所有這些處理工作做完,才能將這個綁定後的界面描述發送到前端。然後等待一小段時間,確保前端已經正確創建界面了:

  • 創建數據庫連接和數據庫事務,然後調用該界面所對應的prepareDisp事件

  • 查看該界面是否關聯了工具條,如果有則爲其調用權限進行預處理,然後將工具條發送到前端

最後,如果該界面用戶用完了,點擊關閉的×符號,前端將發出註銷請求,後臺將其卸載。

此外,前端有自己的界面管理策略,主界面是tab式樣的,最大允許5個tab同時存在,輔助界面是平行彈窗式樣的,最大允許10個界面同時存在,當超過各自限值後,兩者都是按最近使用的策略來淘汰最久沒有使用的那個界面的。

而當界面被淘汰掉的時候,前端也會向後臺進行註銷,如果同一個capa同時在主界面和輔助界面都有打開的界面,則只有當所有界面都被淘汰或關閉後纔會註銷。這一過程,開發者不需關注。

注:由於前述的原生名和capaid進行關聯生成動態名原則,前端不支持在主界面同時打開同一個capa中的兩個界面,如果在某個主界面中的界面點擊後又打開了一個主界面中的界面,這個新的界面其實是在一個新的capa中加載的。開發者請務必瞭解這一點,以避免後者未能正確初始化【新的capa自然沒有老capa中已經有的數據】

目前,jxTMS已經打包爲雲服務器鏡像,開發者開箱即用:
jxTMS-騰訊雲市場​

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章