企業級自定義表單引擎解決方案(十一)--表單規則引擎1

2022-07-03 18:00:48

.net core研發的自定義表單引擎,採用強大的規則引擎將所有的業務串聯起來的,和其他低程式碼平臺是有本質的區別的,目標是完全解放繁瑣的CRUD工作。


規則引擎是自定義表單最為核心的內容,也是與其他低程式碼工具最為本質的區別,非常重要的內容,對於讀者來說也是最難理解內容。
沒有規則引擎的低程式碼工具,即使前端做得再花哨,也僅僅是解決了一些複製貼上的問題
檢視和表單都可以定義規則,規則將所有業務串聯起來,至關重要。
內容比較多,分兩篇文章介紹。

物件樹

進行自定義表單頁面,都會定義唯一一個最外層的表單,表單裡面可以定義子表單、子檢視(檢視裡面也可以定義子表單和子檢視),檢視或者表單裡面會定義各種物件(可以是控制元件、彈框、行列資訊等),整體構造一棵樹,每一個節點都有唯一的編碼,編碼是根據樹的每一個節點的Id組成,通過編碼就可以找到唯一的物件。比如介面上的新增按鈕的編碼為「表單Id.列表檢視Id.新增按鈕控制元件Id」。
檢視和表單Wrap、表單的表單列、ItemView的列,這幾個地方可以定義子表單和子檢視。

規則管理

表單、檢視、控制元件都會觸發各種事件,表單或檢視對父表單或父檢視一無所知,且只能控制操作直接子表單或子檢視的物件,事件規則查詢邏輯為:

  1. 如果是表單觸發的事件,系統會查詢本表單觸發的規則(子表單Id、子檢視Id、物件Id都為空)和父級(父表單或者父檢視)定義的規則(子表單Id為觸發事件的表單Id,子檢視Id為空,物件Id為空)
  2. 如果是檢視觸發的事件,系統會查詢本檢視觸發的規則(子表單Id、子檢視Id、物件Id都為空)和父級(父表單或者父檢視)定義的規則(子表單Id為空,子檢視Id為觸發事件的檢視Id,物件Id為空)以及當父級為表單時,查詢父級的父級定義的規則(子表單Id為父級表單Id,子檢視為觸發事件的檢視Id,物件Id為空)
  3. 如果是物件觸發的事件,系統直接查詢父級規則(子表單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
  • 排序
    定義規則執行的先後順序
  • 執行型別和執行設定
    不同的執行型別定義不同的設定支援,具體規則如下:
  1. 設定屬性(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

  1. 執行方法(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具體屬性內容參見不同方法執行設定舉例。傳遞資料設定:
  1. paramName:需要賦值的引數名
  2. transType:引數傳遞型別,query、exportexcel、eventData等,具體值參考後續規則執行範例,eventData表示從事件觸發處獲取引數值,比如點選列表刪除按鈕,會將當前刪除按鈕所在行的資料加入到觸發事件的事件繫結值上,可以在規則執行時獲取
  3. transTypeParam:給具體引數哪個屬性賦值,如Get方法需要給id賦值,引數層級比較深時,可以用冒號:隔開等。
  4. 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檔案地址:https://gitee.com/kuangqifu/sprite/wikis/pages
開源地址:https://gitee.com/kuangqifu/sprite
體驗地址:http://47.108.141.193:8031 (首次載入可能有點慢,用的阿里雲最差的伺服器)
自定義表單文章地址:https://www.cnblogs.com/spritekuang/
流程引擎文章地址:https://www.cnblogs.com/spritekuang/category/834975.html (採用WWF開發,已過時,已改用Elsa實現,https://www.cnblogs.com/spritekuang/p/14970992.html