企業級自定義表單引擎解決方案(十一)–表單規則引擎1
.net core研發的自定義表單引擎,採用強大的規則引擎將所有的業務串聯起來的,和其他低程式碼平台是有本質的區別的,目標是完全解放繁瑣的CRUD工作。
規則引擎是自定義表單最為核心的內容,也是與其他低程式碼工具最為本質的區別,非常重要的內容,對於讀者來說也是最難理解內容。
沒有規則引擎的低程式碼工具,即使前端做得再花哨,也僅僅是解決了一些複製粘貼的問題
視圖和表單都可以定義規則,規則將所有業務串聯起來,至關重要。
內容比較多,分兩篇文章介紹。
對象樹
進行自定義表單頁面,都會定義唯一一個最外層的表單,表單裡面可以定義子表單、子視圖(視圖裡面也可以定義子表單和子視圖),視圖或者表單裡面會定義各種對象(可以是控制項、彈框、行列資訊等),整體構造一棵樹,每一個節點都有唯一的編碼,編碼是根據樹的每一個節點的Id組成,通過編碼就可以找到唯一的對象。比如介面上的新增按鈕的編碼為「表單Id.列表視圖Id.新增按鈕控制項Id」。
視圖和表單Wrap、表單的表單列、ItemView的列,這幾個地方可以定義子表單和子視圖。
規則管理
表單、視圖、控制項都會觸發各種事件,表單或視圖對父表單或父視圖一無所知,且只能控制操作直接子表單或子視圖的對象,事件規則查找邏輯為:
- 如果是表單觸發的事件,系統會查找本表單觸發的規則(子表單Id、子視圖Id、對象Id都為空)和父級(父表單或者父視圖)定義的規則(子表單Id為觸發事件的表單Id,子視圖Id為空,對象Id為空)
- 如果是視圖觸發的事件,系統會查找本視圖觸發的規則(子表單Id、子視圖Id、對象Id都為空)和父級(父表單或者父視圖)定義的規則(子表單Id為空,子視圖Id為觸發事件的視圖Id,對象Id為空)以及當父級為表單時,查找父級的父級定義的規則(子表單Id為父級表單Id,子視圖為觸發事件的視圖Id,對象Id為空)
- 如果是對象觸發的事件,系統直接查找父級規則(子表單Id為空、子視圖Id為空、對象Id為對象Id)和父級的父級規則(子表單Id為空或者子視圖Id為空(取決於父級的類型)、子表單Id為空或者子視圖Id為父級Id(取決於父級的類型)、對象Id為對象Id)和父級的父級的父級(觸發事件的對象的父級為視圖,父級的父級為表單,且還會繼續網上查找一級的規則,查找邏輯與其他情況類似)
上述描述不好理解,可以結合到體驗網站各種配置好的表單查看,多看一些規則就能理解清楚。
- 業務分類
只能是View或Form,系統自動選擇 - 子表單Id
子表單Id - 子視圖Id
子視圖Id - 對象Id
表單或者視圖內不同控制項的Id,注意:Wrap對象的Id為:Wrap包裹的表單或視圖Id_Wrap配置id - 事件名稱
基礎控制項的使用參見不同控制項的ant的事件,自定義表單會將所有ant控制項的事件拋出,可以定義規則進行攔截,其他自定義事件參考如下
viewloaded:視圖載入時觸發的事件
selectedrows:ListView的選中行
advancequery:ListView的高級查詢按鈕點擊事件
pagechange:ListView分頁觸發事件
refresh:ListView頁面刷新事件
selected:樹視圖節點選擇事件
Workflow_FormValidate:工作流介面觸發表單驗證事件(流程管理介面點擊提交按鈕等地方)
Workflow_GetMethods:工作流管理獲取表單資訊事件(工作流管理介面裝載自定義表單時,需要獲取自定義表單資訊)
Workflow_FormOpen:打開工作流管理介面事件
Workflow_TrySend:工作流預提交完成
Workflow_Save:工作流保存執行完成
Workflow_Send:工作流提交完成
另外,還可以自己定義一些事件,並配置執行規則,這些事件不是由系統自動觸發,而是在需要的時候,可以在其他規則執行中選擇執行其他規則,事件名稱選擇自定義的事件名稱即可,這樣就可以觸發執行自定義的事件規則。比如在列表視圖中,多個地方都會觸發查詢列表數據並綁定到表格中,此時就可以定義一個自定義的事件及規則,其他地方直接使用即可。
規則執行管理
一個事件會觸發一系列的規則執行,每個規則執行都會有一個規則執行所在的宿主對象,宿主對象為事件所屬的視圖或者表單,規則執行都在相對宿主對象來定義執行的。
子表單、子視圖、對象Id:這幾個欄位都是相對宿主對象來說有,某些規則執行需要指定規則執行的目標對象,比如綁定數據,需要知道將數據綁定到哪個目標對象上,比如可以綁定到本視圖的某個按鈕或者子表單的子視圖的某個對象上。
- 子表單Id
子表單Id - 子視圖Id
子視圖Id - 對象Id
- 排序
定義規則執行的先後順序 - 執行類型和執行配置
不同的執行類型定義不同的配置支援,具體規則如下:
- 設置屬性(actionType=1)
設置目標對象的自定義屬性,比如點擊新增按鈕彈出對話框,參考前端組件的屬性,則設置對象為對話框Id(參見【Wrap對象定義】):66e68bf9-8e05-4691-bf99-ed95c820260d_modal1,執行設置為:{“visible”:true}
特殊屬性設置
彈出導入Excel對話框,{“type”:”importexcel”,”objectName”:”TemplateTests”,”applicationCode”:”Default”}
設置頁碼為1,{“skipCount”:0}
彈出模態對話框,{“visible”:true,”bodyStyle”:{“padding”:”10px”}},對象Id為af1756bb-da48-4b5f-821d-78aeeaddbd2e_modal1
- 執行方法(actionType=2)
執行後端伺服器方法,自定義表單默認了一系列默認方法執行,默認情況下滿足絕大多數業務場景,默認方法不滿足的情況下,可以定義Object對象方法,自定義執行邏輯,自定義方法的執行參考【方法管理】
方法執行配置結構:
applicationCode:應用編碼,默認即可
isTransaction:是否封裝到事務中執行,多數情況填寫true
methods:執行的一系列後端方法集合,具體參數如下:
- ruleId:方法執行Id,任意定義的值,用於存儲方法執行的結果
- objectName:方法所屬的對象
- methodId:如果是執行自定義的Object對象方法,則填寫Object對象方法的Id,否則填寫系統默認的方法名稱,具體名稱見下文
- paramModel:server或者local,默認為local,定義方法參數是從前端綁定還是後端其他方法執行結果獲取
- serverParams:如果paramModel為server時使用,
- userFields:定義查詢結果哪些欄位是需要構造用戶名稱的欄位(資料庫只存儲用戶id,介面顯示的時候,需要顯示用戶名,系統自動為查詢結果添加”原始欄位_UserName”欄位)
- remoteFieldInfos:遠程關聯欄位特殊處理(常常用在外鍵關聯的地方,資料庫只存儲遠程對象的Id,介面需要顯示外鍵綁定的值),具體參考【外鍵關聯處理】
- instanceIdField:如果表單掛接到流程引擎,系統自動帶出流程相關數據欄位,這裡定義關聯的流程定義欄位名稱,系統查詢流程管理,獲取流程審批狀態等資訊
- execType:workflow_formId或者workflow_fact,只在流程引擎處使用,標識方法是獲取表單Id值還是事實庫Fact值
- baseConfig: 基礎配置,可空,配置之後,會先應用基礎配置,再執行後續的傳遞替換參數值
- transfors:執行方法所需的參數的綁定規則,真正請求的時候,參數封裝到datas對象(如果是數組,請採用「欄位名稱:數組索引」,具體設置某個數組對象的值),datas具體屬性內容參見不同方法執行配置舉例。傳遞數據配置:
- paramName:需要賦值的參數名
- transType:參數傳遞類型,query、exportexcel、eventData等,具體值參考後續規則執行示例,eventData表示從事件觸發處獲取參數值,比如點擊列表刪除按鈕,會將當前刪除按鈕所在行的數據加入到觸發事件的事件綁定值上,可以在規則執行時獲取
- transTypeParam:給具體參數哪個屬性賦值,如Get方法需要給id賦值,參數層級比較深時,可以用冒號:隔開等。
- transfors:遞歸給參數賦值,當參數層級比較深時,需要遞歸到參數所在的層級再進行賦值,比如datas.paramValues.id欄位賦值,則需要遞歸到paramValues對象,給paramValues對象的id屬性賦值
方法返回結果:[{ruleId:"XX1",result:object1},{ruleId:"XX2",result:object2}]
- Get、Fact方法:
Get方法可以傳遞paramValues和sqlFields參數,paramValues只需定義主鍵資訊,sqlFields可以定義查詢的哪些列,Fact方法同Get完全一致,流程引擎執行Fact方法獲取表單實體對象
例:
配置:
{"aplicationCode":"Default","isTransaction":true,"methods":[{"ruleId":1,"objectName":"TemplateTests","methodId":"Get","transfors":[{"paramName":"paramValues","transfors":[{"parentParamName":"paramValues","paramName":"id","transType":"eventData","transTypeParam":"id"}]}]}]}
實際請求:{"routeName":"SingleTemplateTest","applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"Get","ruleId":1,"objectName":"TemplateTests","paramModel":"local","datas":{"paramValues":{"id":"0b3cb8d7-6cb4-44bf-a480-2003bf4733b4"}}}]}
說明:將觸發事件綁定的對象的id欄位賦值給datas.paramValues.id參數,執行默認的Get方法
- CreateOrUpdate、Create、Update方法
三個方法參數相同,一般情況調用CreateOrUpdate方法即可,新增或者修改資料庫表數據,當id欄位為空時,執行新增Create方法,當id欄位不為空時,執行修改Update方法
例:
配置:
{"aplicationCode":"Default","isTransaction":true,"methods":[{"ruleId":1,"objectName":"TemplateTests","methodId":"CreateOrUpdate","transfors":[{"subFormId":"66e68bf9-8e05-4691-bf99-ed95c820260d","subViewId":"ecd0c03d-a67a-45a0-a64c-9c53e3522fb1","paramName":"paramValues","transType":""}]}]}}
實際請求:{"applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"CreateOrUpdate","ruleId":1,"objectName":"TemplateTests","paramModel":"local","datas":{"paramValues":{"id":"0b3cb8d7-6cb4-44bf-a480-2003bf4733b4","field1":"12","field2":"12",......}}}]}
說明:在ListView視圖對話框保存按鈕執行時,將子表單的子視圖(ItemView)的數據傳遞到方法參數,執行CreateOrUpdate方法
- Delete方法
刪除資料庫一條數據
例:
配置:
{"ruleId":1,"objectName":"TemplateTests","methodId":"Delete","transfors":[{"paramName":"paramValues","transfors":[{"parentParamName":"paramValues","paramName":"id","transType":"eventData","transTypeParam":"id"}]}]}
實際請求:{"routeName":"SingleTemplateTest","applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"Delete","ruleId":1,"objectName":"TemplateTests","paramModel":"local","datas":{"paramValues":{"id":"499e1b14-5bd4-4d8d-bb72-46558996fbbd"}}}]}
說明:在ListView的表格某一行點擊刪除按鈕,執行刪除方法,將點擊事件綁定的對象的id欄位賦值給參數datas.paramValues.id,執行刪除方法
- DeleteWhere方法
按照自定義條件批量刪除數據,比如ListView的批量選擇刪除功能,自定義條件參見附錄【自定義查詢條件】
例:
配置:
{"aplicationCode":"Default","isTransaction":true,"methods":[{"ruleId":1,"objectName":"TemplateTests","methodId":"DeleteWhere","transfors":[{"transType":"batchdelete"}]}]}
實際請求:{"applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"DeleteWhere","ruleId":1,"objectName":"TemplateTests","paramModel":"local","datas":{"sqlWheres":{"sqlExpressType":1,"children":[{"sqlExpressType":3,"field":"Id","conditionType":4,"value":["147632d6-7b12-411b-a7f0-c83744fb46c1","411c9856-07aa-4427-830c-35d6bfa29220"]}]}}}]}
說明:transType為batchdelete,系統自動將用戶批量勾選的數據id構造為數組賦值給參數,調用批量刪除功能
- GetWhere方法
同Get方法,只是查詢條件不是以id查詢,是自定義的sqlWhere查詢條件 - UpdateWhere方法
同Update方法,只是查詢條件是自定義的sqlWhere查詢條件 - PageList方法
ListView視圖列表數據分頁查詢,將查詢數據構造為查詢條件參數,執行後端分頁查詢獲取資料庫數據,參見附錄【自定義查詢條件】
例:
配置:
{"ruleId":1,"objectName":"TemplateTests","methodId":"PageList","userFields":"creatorId;lastModifierId;userField;userFields","remoteFieldInfos":[{"objectName":"OTN1","field":"singleField","script":"
${obj.string1}(${obj.sex})"},{"objectName":"OTN1","field":"singleFields","script":"
${obj.string1}(${obj.sex})"},{"objectName":"Student","field":"studentId","script":"
${obj.name}(${obj.userName})"}],"transfors":[{"transType":"query"}]}
實際請求:{"routeName":"SingleTemplateTest","applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"PageList","ruleId":1,"objectName":"TemplateTests","userFields":"creatorId;lastModifierId;userField;userFields","remoteFieldInfos":[{"objectName":"OTN1","field":"singleField","script":"
${obj.string1}(${obj.sex})"},{"objectName":"OTN1","field":"singleFields","script":"
${obj.string1}(${obj.sex})"},{"objectName":"Student","field":"studentId","script":"
${obj.name}(${obj.userName})"}],"paramModel":"local","datas":{"sqlSkipCount":0,"sqlMaxResultCount":15,"sqlWheres":{"sqlExpressType":1,"children":[{"sqlExpressType":3,"field":"Education","conditionType":5,"value":"master"},{"sqlExpressType":3,"field":"studentId","conditionType":1,"value":"05781136-4fef-4961-b5d7-d5b6073ddd37"},{"sqlExpressType":3,"field":"userFields","conditionType":5,"value":"39f9719b-0a41-6364-133c-e9c39c92d01a"}]}}}]}
說明:將ListView查詢區域用戶輸入的值構造為參數參數,執行分頁查詢功能,userFields參數定義哪些欄位是用戶欄位,需要顯示用戶名,remoteFieldInfos標識哪些欄位是外鍵關聯欄位,需要關聯顯示外鍵資訊,參見【外鍵關聯處理】
- ListWhere方法
與PageList方法類似,只是去掉了分頁功能,可以用在導出Excel等不需要分頁獲取數據集合的地方
例:
配置:
{"aplicationCode":"Default","isTransaction":true,"methods":[{"ruleId":1,"objectName":"TemplateTests","methodId":"ListWhere","userFields":"creatorId;lastModifierId;userField;userFields","remoteFieldInfos":[{"objectName":"OTN1","field":"singleField","script":"
${obj.string1}(${obj.sex})"},{"objectName":"OTN1","field":"singleFields","script":"
${obj.string1}(${obj.sex})"},{"objectName":"Student","field":"studentId","script":"
${obj.name}(${obj.userName})","transfors":[{"transType":"exportexcel"}]}]}
實際請求:{"routeName":"SingleTemplateTest","applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"ListWhere","ruleId":1,"objectName":"TemplateTests","userFields":"creatorId;lastModifierId;userField;userFields","remoteFieldInfos":[{"objectName":"OTN1","field":"singleField","script":"
${obj.string1}(${obj.sex})"},{"objectName":"OTN1","field":"singleFields","script":"
${obj.string1}(${obj.sex})"},{"objectName":"Student","field":"studentId","script":"
${obj.name}(${obj.userName})"}],"paramModel":"local","datas":{"sqlWheres":{"sqlExpressType":1,"children":[]},"excelDicts":[{"dict":"edu","field":"education"},{"dict":"sex","field":"sex"},{"dict":"post","field":"post"}],"excelName":"單表測試Excel數據","excelTemplate":[{"name":"string欄位","field":"field1","fieldType":5,"isRequred":true,"validateType":0},{"name":"string2欄位","field":"field2","fieldType":5,"validateType":0},{"name":"Int欄位1","field":"fieldInt1","fieldType":1,"validateType":1},{"name":"int2欄位","field":"fieldInt2","fieldType":1,"validateType":1},{"name":"datetime欄位1","field":"fieldDatetime1","fieldType":7,"validateType":10},{"name":"datetime欄位2","field":"fieldDatetime2","fieldType":7,"validateType":10},{"name":"bool欄位","field":"fieldBool1","fieldType":4,"validateType":1},{"name":"學歷","field":"education","fieldType":5,"validateType":11},{"name":"性別","field":"sex","fieldType":5,"validateType":11}]}}]}
說明:這個例子為導出Excel的配置,transType為exportexcel,excelName定義導出的Excel名稱,excelDicts定義哪些欄位是數據字典,excelTemplate定義導出Excel的模板資訊,參見附錄【導入導出Excel模版】其他參數同PageList方法說明
- MultiPageList方法
與PageList方法類似,PageList只能處理單表數據,對於多表關聯處理無能為力(最多只顯示關聯表一個欄位顯示),此方法專門用於多表關聯處理
例:
配置:
{"aplicationCode":"Default","isTransaction":true,"methods":[{"ruleId":1,"objectName":"OTO1","methodId":"MultiPageList","transfors":[{"transType":"query","aliasInfos":"OTO1:a;OTO2:b","joinInfos":"OTO1 a LEFT JOIN OTO2 b ON a.Id=b.Id"}]}]}
實際請求:{"applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"MultiPageList","ruleId":1,"objectName":"OTO1","paramModel":"local","datas":{"sqlSkipCount":0,"sqlMaxResultCount":15,"sqlWheres":{"sqlExpressType":1,"children":[]},"joinInfos":"OTO1 a LEFT JOIN OTO2 b ON a.Id=b.Id","aliasInfos":"OTO1:a;OTO2:b"}}]}
說明:特殊使用參見【外鍵關聯處理】,其他同PageList方法
- MultiListWhere
與ListWhere方法類似,ListWhere只能處理單表數據,對於多表關聯處理無能為力(只多隻顯示關聯表一個欄位顯示),此方法專門用於多表關聯處理
說明:特殊使用參見【外鍵關聯處理】,其他同ListWhere方法 - TreeListWhere
與ListWhere方法類似,此方法主要是針對樹結構的資料庫表進行查詢,查詢邏輯: 先根據查詢條件查詢出滿足條件的數據,再把所有節點的祖先節點查詢出來,構造為一樹完整的樹。
例:
配置:
{"aplicationCode":"Default","isTransaction":true,"methods":[{"ruleId":1,"objectName":"Depts","methodId":"TreeListWhere","transfors":[{"transType":"querytree"}]}]}
實際請求:{"applicationCode":"Default","isTransaction":true,"methods":[{"methodId":"TreeListWhere","ruleId":1,"objectName":"Depts","paramModel":"local","datas":{"sqlWheres":{"sqlExpressType":1,"children":[{"sqlExpressType":3,"field":"title","conditionType":5,"value":"後端"}]}}}]}
說明:獲取樹不會涉及到分頁,整棵樹完整數據顯示,另外注意,樹結構資料庫對象自動添加維護PId、TreeCode、Path、Icon、Title欄位
- BatchCreate方法
批量新增數據,比如導入Excel,獲取一對多關係,批量添加子表數據等場景。
例:
配置:
{"aplicationCode":"Default","isTransaction":true,"methods":[{"ruleId":1,"objectName":"OTN1","methodId":"CreateOrUpdate","transfors":[{"subFormId":"e928438e-645f-45fb-9fe7-88c74dafaa00","subViewId":"8c78e079-c23d-4d27-907e-76eadfc30b05","paramName":"paramValues","transType":""}]},{"ruleId":2,"objectName":"OTN2","methodId":"BatchCreate","paramModel":"server","serverParams":[{"ruleId":"1","targetFields":"datas#oTN1_Id"}],"transfors":[{"subFormId":"e928438e-645f-45fb-9fe7-88c74dafaa00","subViewId":"852c8f20-c4f2-4e7f-bccb-1573d7a3af5c","transType":""}]}]}
說明:此配置執行一對多數據保存邏輯,執行兩個方法,先執行主表的CreateOrUpdate方法,再執行BatchCreate批量新增子表數據方法,BatchCreate的執行邏輯為:子表的數據是從子表單XX子視圖XX獲取(ListView表格數據),主表執行完CreateOrUpdate方法後,將結果(主鍵)值賦值給子表的oTN1_Id欄位,再執行子表的BatchCreate批量新增子表數據方
wike文檔地址://gitee.com/kuangqifu/sprite/wikis/pages
開源地址://gitee.com/kuangqifu/sprite
體驗地址://47.108.141.193:8031 (首次載入可能有點慢,用的阿里雲最差的伺服器)
自定義表單文章地址://www.cnblogs.com/spritekuang/
流程引擎文章地址://www.cnblogs.com/spritekuang/category/834975.html (採用WWF開發,已過時,已改用Elsa實現,//www.cnblogs.com/spritekuang/p/14970992.html )