OneCode 表单引擎设计(表单引擎实现思路)
前言
“万事俱备,就差一个程序员了”,这是一个互联网圈里很著名的一个梗。很好的诠释了“全民互联网 ” 时代的疯狂。在当今“企业数智化转型“的大背景下,也有一个一个关于表单系统的梗,“所有系统都逐步低代码零代码化,这一切就差一个“表单系统”。确实是如此,在多数的数智化应用软件中,表单系统都是必不可少的基础功能,更是低代码零代码的支撑性应用。本文是根据开源低代码平台,《OneCode低代码引擎》 1.0.6版本整理的功能来阐述表单系统的设计。 参考阅读:《OneCode开源低代码引擎白皮书》
一,表单系统简介
表单系统是一个比较宽泛的定义,没有特定的业务背景,但在大多数数智化业务系统中又有着比较高的应用频率,如日常办公中各种行政类单据如请假单、设备申请单、用车申请单等;统计调查类单据,如人员信息统计表、团建活动报名表、调查问卷等,在财务系统中,各类报销单、涉税报表等。但在数智化系统逐步精细化复杂化的今天,表单系统也不在是简单的针对数据的单存的电子记录功能,而是更多的增强其“可控可管”的能力。比如:“请假单”则需要从“HR人力资源系统”中读取员工假期使用情况,以及根据请假天数在“OA系统”中选择合适的审批流程。而且表单的组件类型也不在局限于,单一输入展现,而是集成更多的统计、计算以及与业务结合的组态控件等等。
二,OneCode 表单设计组成
onecode表单系统是建立在OneCode低代码引擎的一个重要组成部分,由设计器,表单引擎、以及领域设计工具组成。
(1)可视化设计器
设计器是表单系统统一入口,onecode 设计器本身是一套开放的设计,用户可以通过,OneCode语言指定扩展。设计器,采用的是拖拽引擎 插件的构造模型,用户可以通过开放的低代码协议编写插件。支持JS和Java两种扩展语言。样式构建提供了标准CSS3编辑器,支持事件动作以及函数动态扩展。支持自定义函数库扩展,支持阿里字体图片等资源库。
可视化设计器
(2)表单引擎
表单引擎由三块自成体系的可独立部署运行的部分组成。前端引擎负责界面建模并按低代码协议协议生成标准JSON,中后台OneCode通过读取标准JSON协议,完成后端的视图建模,合并DSM后端服务建模系统,完成完整的后端服务建模应用,通过代码工程完成前后端一体的出码应用。JDSCloud是OneCode的协同支撑系统,除了常规的资源代码空间管理外,提供了独立的沙箱运行环境。为OneCode 提供工程化的仿真版本Ops等服务。
表单组成
(3)DDD领域设计工具
OneCode-DSM(以下简称DSM)工具集是建立是以OneCode低代码引擎为基础专注于低代码建模应用的高阶建模工具。在OneCode引擎中,出了为普通用户提供无代码的拖动设计器,低代码的业务逻辑编排器,之外还提供了供专业业务领域专家的使用的DSM建模工具。
领域工具
三,运行原理
(1) 拖拽自定义页面
用户通过,拖拽完成页面建模序列化为按标准协议序列化JSON文件,后端OneCode服务支撑系统解析JSON文件并混合DSM建模信息以及后端服务逻辑后,通过混合编译,通过代码工厂指定出码模板,完成前后端一体的编译文件。
运行原理
原型原理
(2) 从数据数据库构建
(3) 手工撰写OneCode代码
OneCode 本身基于JAVA语言体系,是在Java Spring 注解基础上的一套扩展子集,混合编译引擎器通过扩展注解构建完整的Domain模型,通过读取标准Spring 注解完成普通Web数据交付及调度过程,通过Domin域模型动态渲染JS文件输出为JSON交付给前端引擎构建页面。
四,设计器功能介绍
(1)功能介绍
(2)物料库
"物料":低代码引擎的核心目的之一是建设跨行业的低代码框架,而每个行业由于其应用的领域不同,使用的人员以及方法方式不同,在一些底层组件方面会有会有加大差距。比如:政府业务中会大量使用的非规则表单元素,企业应用中各个行业自有的图标体系,物联网行业大量的设备图标图片以及实时联网图。
(3)组件库
组件定义:可以用于低代码平台的组件,包含了搭建体验增强配置,可以在设计器中 进行拖拽、配置等操作。有两种分类方式:按照场景可以分为基础组件、业务组件、图 表组件、布局组件和复合组件等。通常用户可以自主完成相关设定,并根据业务特点在视图引擎中进行自行扩展(后续章节中会演示实际注册示例)
(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" } } }
动态样式盒
代码配置示例
{ "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":{ //获取数据 "onGetContent":{ "actions":[ { "args":[ "{page.ReloadChild.setQueryData()}", null, null, "{args[1].tagVar}", "" ], "desc":"设置扩展参数", "method":"setQueryData", "redirection":"other:callback:call", "target":"ReloadChild", "type":"control" } ] },//数据项选择 "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白皮书中参数了OneCode工作原理,其中有一个章节就是允许用户将逻辑片段以及动作函数序列化为特定的JSON字符串。动作(逻辑)概览则是针对逻辑片段可视化的入口工具。打开任意页面便可以直观的将该页面的代码片段以直观的方式展现出来。并且可以直接插入,编辑事件,修改动作。同时也可以在调试期动态的中断、跳出终止等功能。
五,表单设计
(1)页面布局
表单系统,依然采用的是,OneCode低代码引擎的布局结构。使用工程结构来完成项目代码的管理及复用。
在主体布局上默认采用的表格布局,支持行列的自由拖动,以及行列合并操作。
允许以,整行、整列、独立单元格独立设置样式。
OneCode也提供了,常用的嵌套布局容器组件。方便进行复杂页面组合。
(2)表单输入
基于OneCode的通用输入控件,是经过OneCode封装后统一输出的,包括前端用户展现控制以及OneCode后端定义语法及DSM工具。
输入域事件
(3)表单数据交互
表单交互AJAX设定
后端聚合配置
(六)数据列表
在表单系统中,列表是用户交互一个基础入口。除了承担数据查询及展现的功能外,还是多表多行数据批量提交的一个入口。
(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 = "数字精度") 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 流程系统是一个独立的微服务系统,表单引擎通过webapi完成流程的调度功能。
(1)流程设计器
(2)流程配置
1, 单人、多人、会签等常见需求
2, 办理方式支持,抢占、顺序、并行等多种方式
3, 办理方式支持、办理人、传阅人、代签等常见方式。
(3)表单流转
(4)表单按钮权限
(九)数据源处理
oneCode数据源采用的是DDD模型的仓储模型设计。并通过代码工厂配置模版完成出码设计。
(1) 仓储概览
(2) 数据库配置
(3) 实体关系
仓储建模的一个核心目的是将结构化的数据转变为面向对象的模式,而这其中非常重要的一点则是实体关系的处理,DSM设计中针对数据库表允许用户在导入数据库后再次进行实体关系建模,将数据库表按 1:1 ,1:N, N:N模型建立关系。完成建模后在出码的过程中会根据业务模板设定,进行实体模型的转变,在实体代码中以 @Ref 关系标签完成建模应用。
数据库模型关系 | 实体关系 | 实体注解配置 |
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 | 数据库表映射配置主要包含了,数据源标识,表名称以及主键信息 | @DBTable(configKey="fdt",tableName="FDT_LINGDAO",primaryKey="uuid") |
@DBField | 数据库字段配置 | @DBField(cnName="创建时间",length=0,dbType=ColType.DATETIME,dbFieldName="createtime") |
@Uid | 实体字段,在数据库实体中一般标识为主键,在DDD模型中作为唯一值 | @Uid |
@Pid | 父级组件字段,通常在关系实体中用于标识父级对象的主键 | @Pid |
@CustomAnnotation | 常用实体注解,注解属性中会包括,字段的展示类型,可读属性,展示注解等。 | @CustomAnnotation(caption="职务") |
@Caption | 标题注解一般作用在表格行数据的展示中作为默认显示字段,如Person (人员对象中)会将name作为默认展示选项 | @Caption |
@Ref | 实体关系属性 | @Ref(ref = RefType.m2m, view = ViewType.grid) |
@APIEventAnnotation | API服务注解,是对外服务的标识。添加该注解后,在后续的模型建模中会对应转换为Web API服务 | @APIEventAnnotation(bindMenu = {CustomMenuItem.search}) |
(十)工程发布总览
(1)发布服务组成
工程发布,需要三方面的资源做支撑,分别是用户通过设计完成的页面及功能交互,通过特定的特定的出码模板完成相应的技术栈前端转换形成的前端页面目录。而后端应用则根据则是用户通过基础数据建模形成的领域模型文件,这些领域模型文件通常会按照,资源库、支撑域工程域等模型方式来独立打包方便后期版本管理及个体更新。另外第三块则是方便工程启动运行以及访问控制,对外暴露监控等相关的工程配置信息。
(2)发布配置
发布本地
发布远程
工程配置
(3)前端库