OneCode 表單引擎設計(表單引擎實現(xiàn)思路)
前言
“萬事俱備,就差一個程序員了”,這是一個互聯(lián)網(wǎng)圈里很著名的一個梗。很好的詮釋了“全民互聯(lián)網(wǎng) ” 時代的瘋狂。在當今“企業(yè)數(shù)智化轉型“的大背景下,也有一個一個關于表單系統(tǒng)的梗,“所有系統(tǒng)都逐步低代碼零代碼化,這一切就差一個“表單系統(tǒng)”。確實是如此,在多數(shù)的數(shù)智化應用軟件中,表單系統(tǒng)都是必不可少的基礎功能,更是低代碼零代碼的支撐性應用。本文是根據(jù)開源低代碼平臺,《OneCode低代碼引擎》 1.0.6版本整理的功能來闡述表單系統(tǒng)的設計。 參考閱讀:《OneCode開源低代碼引擎白皮書》
一,表單系統(tǒng)簡介
表單系統(tǒng)是一個比較寬泛的定義,沒有特定的業(yè)務背景,但在大多數(shù)數(shù)智化業(yè)務系統(tǒng)中又有著比較高的應用頻率,如日常辦公中各種行政類單據(jù)如請假單、設備申請單、用車申請單等;統(tǒng)計調(diào)查類單據(jù),如人員信息統(tǒng)計表、團建活動報名表、調(diào)查問卷等,在財務系統(tǒng)中,各類報銷單、涉稅報表等。但在數(shù)智化系統(tǒng)逐步精細化復雜化的今天,表單系統(tǒng)也不在是簡單的針對數(shù)據(jù)的單存的電子記錄功能,而是更多的增強其“可控可管”的能力。比如:“請假單”則需要從“HR人力資源系統(tǒng)”中讀取員工假期使用情況,以及根據(jù)請假天數(shù)在“OA系統(tǒng)”中選擇合適的審批流程。而且表單的組件類型也不在局限于,單一輸入展現(xiàn),而是集成更多的統(tǒng)計、計算以及與業(yè)務結合的組態(tài)控件等等。
二,OneCode 表單設計組成
onecode表單系統(tǒng)是建立在OneCode低代碼引擎的一個重要組成部分,由設計器,表單引擎、以及領域設計工具組成。
(1)可視化設計器
設計器是表單系統(tǒng)統(tǒng)一入口,onecode 設計器本身是一套開放的設計,用戶可以通過,OneCode語言指定擴展。設計器,采用的是拖拽引擎 插件的構造模型,用戶可以通過開放的低代碼協(xié)議編寫插件。支持JS和Java兩種擴展語言。樣式構建提供了標準CSS3編輯器,支持事件動作以及函數(shù)動態(tài)擴展。支持自定義函數(shù)庫擴展,支持阿里字體圖片等資源庫。
可視化設計器
(2)表單引擎
表單引擎由三塊自成體系的可獨立部署運行的部分組成。前端引擎負責界面建模并按低代碼協(xié)議協(xié)議生成標準JSON,中后臺OneCode通過讀取標準JSON協(xié)議,完成后端的視圖建模,合并DSM后端服務建模系統(tǒng),完成完整的后端服務建模應用,通過代碼工程完成前后端一體的出碼應用。JDSCloud是OneCode的協(xié)同支撐系統(tǒng),除了常規(guī)的資源代碼空間管理外,提供了獨立的沙箱運行環(huán)境。為OneCode 提供工程化的仿真版本Ops等服務。
表單組成
?
(3)DDD領域設計工具
OneCode-DSM(以下簡稱DSM)工具集是建立是以OneCode低代碼引擎為基礎專注于低代碼建模應用的高階建模工具。在OneCode引擎中,出了為普通用戶提供無代碼的拖動設計器,低代碼的業(yè)務邏輯編排器,之外還提供了供專業(yè)業(yè)務領域?qū)<业氖褂玫腄SM建模工具。
領域工具
?
?
三,運行原理
(1) 拖拽自定義頁面
用戶通過,拖拽完成頁面建模序列化為按標準協(xié)議序列化JSON文件,后端OneCode服務支撐系統(tǒng)解析JSON文件并混合DSM建模信息以及后端服務邏輯后,通過混合編譯,通過代碼工廠指定出碼模板,完成前后端一體的編譯文件。
運行原理
?
原型原理
?
?
(2) 從數(shù)據(jù)數(shù)據(jù)庫構建
?
?
(3) 手工撰寫OneCode代碼
OneCode 本身基于JAVA語言體系,是在Java Spring 注解基礎上的一套擴展子集,混合編譯引擎器通過擴展注解構建完整的Domain模型,通過讀取標準Spring 注解完成普通Web數(shù)據(jù)交付及調(diào)度過程,通過Domin域模型動態(tài)渲染JS文件輸出為JSON交付給前端引擎構建頁面。
?
四,設計器功能介紹
(1)功能介紹
(2)物料庫
?
"物料":低代碼引擎的核心目的之一是建設跨行業(yè)的低代碼框架,而每個行業(yè)由于其應用的領域不同,使用的人員以及方法方式不同,在一些底層組件方面會有會有加大差距。比如:政府業(yè)務中會大量使用的非規(guī)則表單元素,企業(yè)應用中各個行業(yè)自有的圖標體系,物聯(lián)網(wǎng)行業(yè)大量的設備圖標圖片以及實時聯(lián)網(wǎng)圖。
(3)組件庫
組件定義:可以用于低代碼平臺的組件,包含了搭建體驗增強配置,可以在設計器中 進行拖拽、配置等操作。有兩種分類方式:按照場景可以分為基礎組件、業(yè)務組件、圖 表組件、布局組件和復合組件等。通常用戶可以自主完成相關設定,并根據(jù)業(yè)務特點在視圖引擎中進行自行擴展(后續(xù)章節(jié)中會演示實際注冊示例)
?
(4)樣式體系
DOM樹透視樣式盒
DOM樹透視
?
?
配圖示例代碼
{ "alias":"BuildTreeTreeView", "key":"xui.UI.TreeView", "host":this, "properties":{ "name":"BuildTreeTreeGrid", "items":[ { "borderType":"none", "caption":"JAVA樹", "dynDestory":false, "hidden":false, "id":"getBuildTree", "imageClass":"bpmfont bpmgongzuoliuxitongpeizhi", "tagVar":{ } } ], "iniFold":false, "dynDestory":true }, "CS":{ "KEY":{ "color":"#000000", "font-weight":"lighter", "border-radius":"0px 2px 0px 0px" }, "BAR":{ "font-family":"tahoma,geneva,sans-serif" } } }
動態(tài)樣式盒
代碼配置示例
{ "alias":"xui_ui_cssbox1", "key":"xui.UI.CSSBox", "host":this, "properties":{ "className":"xui-css-ame", "normalStatus":{ "color":"#eeeeee", "border-radius":"6px", "box-shadow":"inset 0px 1px 0px #87C1DD", "text-shadow":"0 1px 0 #297192", "$gradient":{ "stops":[ { "pos":"0%", "clr":"#4BA3CC" }, { "pos":"70%", "clr":"#3289B2" } ], "type":"linear", "orient":"T" }, "cursor":"pointer", "border-top":"solid #3899C6 1px", "border-right":"solid #3899C6 1px", "border-bottom":"solid #3899C6 1px", "border-left":"solid #3899C6 1px" }, "hoverStatus":{ "border-radius":"0px 3px 0px 0px" } } }
(5)事件框架
?
?
配置代碼示例:
{ "alias":"BuildTreeTreeView", "key":"xui.UI.TreeView", "host":this, "properties":{ "name":"BuildTreeTreeGrid", "items":[ { "borderType":"none", "caption":"JAVA樹", "dynDestory":false, "hidden":false, "id":"getBuildTree", "imageClass":"bpmfont bpmgongzuoliuxitongpeizhi", "tagVar":{ } } ], "iniFold":false, "dynDestory":true }, "events":{ //獲取數(shù)據(jù) "onGetContent":{ "actions":[ { "args":[ "{page.ReloadChild.setQueryData()}", null, null, "{args[1].tagVar}", "" ], "desc":"設置擴展參數(shù)", "method":"setQueryData", "redirection":"other:callback:call", "target":"ReloadChild", "type":"control" } ] },//數(shù)據(jù)項選擇 "onItemSelected":{ "actions":[ { "args":[ "{args[1].id}" ], "conditions":[ { "symbol":"non-empty", "right":"", "conditionId":"_nonempty_{args[1].className}", "left":"{args[1].className}" } ], "desc":"刪除存在頁", "method":"removeItems", "target":"BuildTreeTab", "type":"control" } ] } } }
(6)動作編排框架
? 在OneCode白皮書中參數(shù)了OneCode工作原理,其中有一個章節(jié)就是允許用戶將邏輯片段以及動作函數(shù)序列化為特定的JSON字符串。動作(邏輯)概覽則是針對邏輯片段可視化的入口工具。打開任意頁面便可以直觀的將該頁面的代碼片段以直觀的方式展現(xiàn)出來。并且可以直接插入,編輯事件,修改動作。同時也可以在調(diào)試期動態(tài)的中斷、跳出終止等功能。
?
?
五,表單設計
(1)頁面布局
表單系統(tǒng),依然采用的是,OneCode低代碼引擎的布局結構。使用工程結構來完成項目代碼的管理及復用。
?在主體布局上默認采用的表格布局,支持行列的自由拖動,以及行列合并操作。
?
允許以,整行、整列、獨立單元格獨立設置樣式。
?
OneCode也提供了,常用的嵌套布局容器組件。方便進行復雜頁面組合。
?
(2)表單輸入
基于OneCode的通用輸入控件,是經(jīng)過OneCode封裝后統(tǒng)一輸出的,包括前端用戶展現(xiàn)控制以及OneCode后端定義語法及DSM工具。
?
?
?
?
?
?
?
?
?
輸入域事件
?
?
(3)表單數(shù)據(jù)交互
表單交互AJAX設定
?
?后端聚合配置
?
?
?
(六)數(shù)據(jù)列表
在表單系統(tǒng)中,列表是用戶交互一個基礎入口。除了承擔數(shù)據(jù)查詢及展現(xiàn)的功能外,還是多表多行數(shù)據(jù)批量提交的一個入口。
(1)列表設計器
設計器概覽圖
?
?
屬性集合
?
(2) OneCode列表領域模型
列表OneCode 轉換對比
?
?
領域模型分析
?
?
?
?
常用菜單注解
注解 | 位置 | 示例 |
@ToolBarMenu | 容器頂部工具欄 | @ToolBarMenu(hAlign = HAlignType.left, handler = false, menuClass = JavaRepositoryEditorTools.class) |
@MenuBarMenu | 頂部菜單欄 | @MenuBarMenu(menuType = CustomMenuType.sub, caption = "新建", imageClass = "xuicon xui-uicmd-add", index = 5) |
@BottomBarMenu | 容器底部按鈕欄 | @BottomBarMenu(menuClass = CustomBuildAction.class) |
@PageBar | 分頁欄 | @PageBar(pageCount = 100) |
@GridRowCmd | 列表行操作按鈕欄 | @GridRowCmd(tagCmdsAlign = TagCmdsAlign.left, menuClass = {AttachMentService.class}) |
@RightContextMenu | 右鍵菜單欄 | @RightContextMenu(menuClass = JavaViewPackageMenu.class) |
@Controller@RequestMapping(value = {"/java/agg/context/"})@MenuBarMenu(menuType = CustomMenuType.component, caption = "菜單")@Aggregation(type = AggregationType.menu)public class JavaAggPackageMenu { @RequestMapping(method = RequestMethod.POST, value = "paste") @CustomAnnotation(imageClass = "spafont spa-icon-paste", index = 1, caption = "粘貼") @APIEventAnnotation(customRequestData = {RequestPathEnum.treeview, RequestPathEnum.sTagVar}, callback = CustomCallBack.TreeReloadNode) public @ResponseBody TreeListResultModel<List<JavaAggTree>> paste(String sFilePath, String packageName, String domainId, String projectName) { TreeListResultModel<List<JavaAggTree>> result = new TreeListResultModel<List<JavaAggTree>>(); try { DSMFactory dsmFactory = DSMFactory.getInstance(); File desFile = new File(sfilePath); DomainInst domainInst = dsmFactory.getAggregationManager().getDomainInstById(domainId); JavaSrcBean srcBean = dsmFactory.getTempManager().genJavaSrc(desFile, domainInst, null); DSMFactory.getInstance().getBuildFactory().copy(srcBean, packageName); result.setIds(Arrays.asList(new String[]{domainId "|" packageName})); } catch (Exception e) { e.printStackTrace(); } return result; } @RequestMapping(method = RequestMethod.POST, value = "reLoad") @CustomAnnotation(imageClass = "xuicon xui-refresh", index = 1, caption = "刷新") @APIEventAnnotation(customRequestData = RequestPathEnum.treeview, callback = CustomCallBack.TreeReloadNode) public @ResponseBody TreeListResultModel<List<JavaAggTree>> reLoad(String packageName, String domainId, String filePath) { TreeListResultModel<List<JavaAggTree>> result = new TreeListResultModel<List<JavaAggTree>>(); String id = domainId "|" packageName; result.setIds(Arrays.asList(new String[]{id})); return result; } }
?
行子域
?
?
?
注解名稱 | 用途 | 實例 |
@GridRowCmd | 表格行按鈕 | @GridRowCmd(tagCmdsAlign = TagCmdsAlign.left, menuClass = {DBColAction.class}) |
@RowHead | 行頭配置 | @RowHead(selMode = SelModeType.none, gridHandlerCaption = "刪除|排序", rowHandlerWidth = "10em", rowNumbered = false) |
@PageBar(pageCount = 100)@RowHead(selMode = SelModeType.none, gridHandlerCaption = "刪除|排序", rowHandlerWidth = "10em", rowNumbered = false)@GridRowCmd(tagCmdsAlign = TagCmdsAlign.left, menuClass = {DBColAction.class})@GridAnnotation(customService = {ColService.class}, customMenu = {GridMenu.Reload, GridMenu.Add}, event = CustomGridEvent.editor)public class DbColGridView { @CustomAnnotation(caption = "字段名", uid = true, required = true) private String name; @CustomAnnotation(caption = "類型", required = true) private ColType type = ColType.VARCHAR; @CustomAnnotation(caption = "長度", required = true) private Integer length = 20; @CustomAnnotation(caption = "數(shù)字精度") private Integer fractions = 0; @CustomAnnotation(caption = "是否主鍵") private Boolean pk; @CustomAnnotation(caption = "是否可為空") private Boolean canNull = true; @CustomAnnotation(colSpan = -1, caption = "注解", rowHeight = "100", required = true) private String cnname; }
(3)配置運行實例:
?
配置項示例:
?
OneCode配置
?
按鈕綁定服務OneCode代碼
?
(七)圖表設計
(1)圖表設計器
?
(2)圖表配置器
?
?
(3)動作交互
?
(4)公式編輯器查詢綁定
?
(5)動畫綁定
?
(6)FusionChartsXT
?
?
?
(7) ECharts
?
?
(8) SVGPaper
?
)
?
(八)流程
表單應用,最常見的一種形式是與工作搭配獨立完成交互。onecode 流程系統(tǒng)是一個獨立的微服務系統(tǒng),表單引擎通過webapi完成流程的調(diào)度功能。
(1)流程設計器
?
(2)流程配置
?
?
?
1, 單人、多人、會簽等常見需求
2, 辦理方式支持,搶占、順序、并行等多種方式
3, 辦理方式支持、辦理人、傳閱人、代簽等常見方式。
(3)表單流轉
?
?
(4)表單按鈕權限
?
?
?
?
(九)數(shù)據(jù)源處理
oneCode數(shù)據(jù)源采用的是DDD模型的倉儲模型設計。并通過代碼工廠配置模版完成出碼設計。
(1) 倉儲概覽
?
(2) 數(shù)據(jù)庫配置
?
?
(3) 實體關系
?
倉儲建模的一個核心目的是將結構化的數(shù)據(jù)轉變?yōu)槊嫦驅(qū)ο蟮哪J?,而這其中非常重要的一點則是實體關系的處理,DSM設計中針對數(shù)據(jù)庫表允許用戶在導入數(shù)據(jù)庫后再次進行實體關系建模,將數(shù)據(jù)庫表按 1:1 ,1:N, N:N模型建立關系。完成建模后在出碼的過程中會根據(jù)業(yè)務模板設定,進行實體模型的轉變,在實體代碼中以 @Ref 關系標簽完成建模應用。
數(shù)據(jù)庫模型關系 | 實體關系 | 實體注解配置 |
1:N | 一對多 | @Ref(ref = RefType.o2m) |
N:N | 多對多 | @Ref(ref = RefType.m2m) |
1:1 | 一對一 | @Ref(ref = RefType.o2o) |
引用 | @Ref(ref = RefType.ref) | |
查找 | @Ref(ref = RefType.) |
(4) 倉儲建模模板
?
?
(5)倉儲模型常用注解
注解名稱 | 用途 | 實例 |
@DBTable | 數(shù)據(jù)庫表映射配置主要包含了,數(shù)據(jù)源標識,表名稱以及主鍵信息 | @DBTable(configKey="fdt",tableName="FDT_LINGDAO",primaryKey="uuid") |
@DBField | 數(shù)據(jù)庫字段配置 | @DBField(cnName="創(chuàng)建時間",length=0,dbType=ColType.DATETIME,dbFieldName="createtime") |
@Uid | 實體字段,在數(shù)據(jù)庫實體中一般標識為主鍵,在DDD模型中作為唯一值 | @Uid |
@Pid | 父級組件字段,通常在關系實體中用于標識父級對象的主鍵 | @Pid |
@CustomAnnotation | 常用實體注解,注解屬性中會包括,字段的展示類型,可讀屬性,展示注解等。 | @CustomAnnotation(caption="職務") |
@Caption | 標題注解一般作用在表格行數(shù)據(jù)的展示中作為默認顯示字段,如Person (人員對象中)會將name作為默認展示選項 | @Caption |
@Ref | 實體關系屬性 | @Ref(ref = RefType.m2m, view = ViewType.grid) |
@APIEventAnnotation | API服務注解,是對外服務的標識。添加該注解后,在后續(xù)的模型建模中會對應轉換為Web API服務 | @APIEventAnnotation(bindMenu = {CustomMenuItem.search}) |
(十)工程發(fā)布總覽
(1)發(fā)布服務組成
?
工程發(fā)布,需要三方面的資源做支撐,分別是用戶通過設計完成的頁面及功能交互,通過特定的特定的出碼模板完成相應的技術棧前端轉換形成的前端頁面目錄。而后端應用則根據(jù)則是用戶通過基礎數(shù)據(jù)建模形成的領域模型文件,這些領域模型文件通常會按照,資源庫、支撐域工程域等模型方式來獨立打包方便后期版本管理及個體更新。另外第三塊則是方便工程啟動運行以及訪問控制,對外暴露監(jiān)控等相關的工程配置信息。
(2)發(fā)布配置
發(fā)布本地
?
發(fā)布遠程
?
工程配置
?
(3)前端庫
?
?