# 事件
事件,是指每种控件在某种特定情况下而触发的动作,Meper通过在事件中定义不同的响应类型,而形成与最终用户的互动,从而赋予程序以灵魂。
当用户选中一个组件的时候,会自动列出该控件所支持的事件类型。如上图所示,按钮支持click事件。
目前系统支持以下几种事件类型:
Button Click 按钮的点击事件
Timer Click 定时器的点击事件
MenuBar Click 菜单栏的点击事件
Search Field Click 搜索框的点击事件
Item Click 表格等组件的点击事件
Item Double Click 表格等组件的双击事件
Item Select 表格数据的选中事件
Value Change Input类型组件的值发生变化时触发
Post Initialize 页面初始化完成事件,每个页面初始化完成时触发,且只触发一次
Tab Selected Change TabSheet组件的值发生变化时触发
Calendar Timeslot Click LumosResourceCalendar组件的时间槽被点击时触发
Calendar Entry Click LumosResourceCalendar组件中入口被点击时触发
Parameter Value Set 为页面传值所用,当ViewModel调用页面的setParmater方法时,会默认发布一个此事件
# Actions
在某种事件发生后,需要在事件中定义各种事件发生后的响应类型,来进行一系列的动作。
这些Action会随着平台的升级而逐渐丰富起来。如上图所示,当前所支持的响应类型主要为以下几种
# 弹出框
定义一个弹出框事件,比如点击添加按钮时,需要弹出一个窗体,就可以在添加按钮的actionflow流程下添加一个弹出框
- 图 1:在Entry下双击“弹出框”,Entry与弹出框直接会自动加上连接线;或直接拖拽一个弹出框到actionflow下,再用连接线将Entry与弹出框连接起来。
- 图 2:选中弹出框,点击下拉框选择弹出框页面,下拉框中展示的是系统所有弹出框类型的页面。
- 图 3:弹出框页面选完之后,需要在弹出框后的连接线上选择弹出框定义的事件(这个事件在设计弹出框页面时,在弹出框GlobalEvent定义的事件),也就是点击按钮弹出对应页面后需要执行什么事件。
# 侧边弹出框
和弹出框类似,可以用于诸如点击表格某个数据,自动从侧边弹出详情信息等场景,和弹出框的区别是,弹出位置固定在页面的右边
# API
对于复杂的逻辑,不属于页面逻辑可以解决的部分,需要借助于调用后台的API进行处理。 一般用于调用后台API的场景主要有:
- 核心逻辑在于后台处理,如产品在站位开始处理(startAtRouteStep)、产品在站位结束处理(completeAtRouteStep)等
- 对于对象之间的关系绑定。如用户与角色的绑定、用于与权限的绑定
上图即为API Action的定义界面:
系统服务 罗列出系统中的所有服务,选择系统服务后再选择服务中可以调用的方法,如调用UserService服务下的assignUserWithroles方法,绑定用户与角色。
组件 列出当前页面所有组件(当前在设计页面中添加的各种组件),选择组件后再选择组件下可以调用的方法,如调用grid组件下的clear方法,清除grid下的数据。
ViewModel 列出当前页面所定义的Controller方法(调用后台ViewModel代码),选择ViewModel服务后再选择ViewModel下可以调用的方法,如生产定义页面调用 ProductConfigurationViewModel下的refreshTreeGrid方法,刷新生产定义树形表格。
参数定义 一旦选中Method后,该方法所需要的参数将会全部现在下面的表格中,用户需要定义各个参数需要从哪里获取值,一共有三种取值方法
- USER DEFINED 如果参数是一个常量,需要用户直接输入,可以使用该方法
- COMPONENT 如果参数需要从页面元素中取值,一旦用户确定使用该方法取值,在 “值” 这一列将会列出当前页面中的所有的ID,对于取值组件,请参考Component
- ACTION_CONTEXT 如果参数不能通过以上方法获取,最后一种策略可以从Action执行的上下文中获取。 往往一个事件中,会有多个Action的定义。对于一个按钮事件,既有LoadData这样的Action,又有API这样的Action。每一种Action的执行,系统都会 将Action中使用到的值放到Action执行的上下文中。这些值对于后续的Action可见。
在各种API调用中,定义参数的时候,常常有ENUM作为参数的情况,此种情况,需要定义参数获取为USER_DEFINED。
ENUM本身作为常量,其值有可能固定不变,针对固定不变的情况,为了对这种情况提供支持,用户可以直接选择参数获取为User_Defined,然后直接输入ENUM的名称即可。
比如,User 对象中,
public void setStatus(UserStatusType status) {
getInternalObject().setStatus(status.getName());
}
对于以上方法,用于可以直接输入:ACTIVE
那么在后台API调用的时候,对于ENUM类型的参数,需要直接从用户输入中解析为ENUM,进行API调用
ApiAction添加一个表单校验的选项
# 导航
该Action用于添加导航,将页面重定向到新地址,填写的URL可以是系统内部的网页也可以是系统外部的。
上图即为该事件的定义界面:
系统页面 导航到系统设计页面,下拉框会展示系统内所有设计页面,不包含弹出框页面 。
URL 导航到一个指定URL地址。
在新标签页中打开 是指在预览点击事件触发时,重开打开一个浏览器页面还是在当前预览页面中打开新页面。
# 确认框
该action用于触发某些事件时给予信息提醒,是否继续执行。如删除用户会弹出一个确认框确认是否删除,确定则用户删除,取消则取消删除用户操作。
# 提示框
用于向用户弹出操作成功提示、错误提示或警告信息。
# 删除对象
该action用于删除系统对象,一般用于删除grid数据。
# 提交保存数据
用于新增、修改弹出框页面提交数据保存到数据库表。
# SQL脚本
# Script
groovy是动态执行脚本,可以jvm中动态执行groovy代码,用于简单的逻辑处理。
# 关闭弹出框
用于弹出框在做提交数据的同时、或者点击弹出框关闭按钮,执行关闭弹出框事件。
# 关闭浏览器
用于关闭导航界面
# 刷新组件
对页面数据的一个刷新,如添加某个对象显示在表格下,对表格需要进行一个刷新操作。
# 获取组件值
获取当前页面某个组件的值,赋予变量名称,便于其他事件的调用。
# 设置组件值
给页面某个组件赋予值
# 启用/置灰组件
用于触发某个事件时,一些组件的启用或者置灰设定。如点击表格的数据,编辑、删除等按钮会启用,不选中数据时编辑、删除按钮置灰。
# 过滤器
用于使用特定条件过滤表格数据,如:用户在查询条件输入框中输入特定用户名,点击查询按钮后,根据输入的用户名过滤用户表格。 ❶ 从输入框获取输入的用户名,将获取到的值赋予变量名称userName ❷ 添加过滤器 ❸ 设置过滤目标、过滤属性、表达式 ❹ 在表达式框中输入上面获取到的userName
# 发布事件
主要有以下两个用途:
简单的通知事件 当用户点击某个按钮时,发布一个事件,其他Action接收到这个事件后再执行后续操作。 比如:用户进行添加数据操作时,希望只有成功添加数据后,才会刷新Grid,可以在添加弹出框的确定按钮中添加OK事件,主页面弹出添加界面后,只有接收到OK事件,才会执行后续的刷新功能。
通过给事件添加额外参数来实现跨页面传值。 比如:用户通过输入框+查询按钮的组合方式,来查找特定的物料编号。
具体设置过程:
# 简单的通知事件
弹出框❶ 定义事件❷ 添加发布事件Action❸ 选择要发布的事件
主界面❶ 弹出添加框❷ 在连接线上选择事件❸ 刷新组件
# 通过事件传值
如图所示为发布事件的一个简单应用,输入框+按钮查询物料
❶ 点击查询按钮❷ 弹出物料查询界面,选中一条物料后点击确定按钮❸ 物料编码被设置为选中物料的编码
弹出框 ❶ 定义事件,并点击事件后面的“+”号,为事件添加参数❷ 添加获取组件值Action,获取Grid中被选中值❸ 发布事件,将获取到的值赋值给事件参数
主界面 ❶ 弹出物料查询界面 ❷ 在连接线上选择事件 ❸ 添加设置组件值Action,在表达式一栏输入弹出框事件的附加参数,设置组件值
# 显示/隐藏组件
用于触发某个事件时,组件的显示和隐藏,true代表显示组件,false代表隐藏组件。
# 上传文件
需要组件库中的“上传”组件和ActionFlow库中的“提交上传文件”Action配合使用, 上传组件只是给用户选择本地文件用的,真正上传到数据库中的动作是由提交上传文件这个Action执行的,文件会上传到SYS_MEDIA表中。 提交上传文件还可以有返回值,需要给返回值起一个变量名,可以通过设置组件值Action将返回的变量赋值给文件预览Action,这样会弹出一个新窗口对上传的文件进行预览,也可以赋值给页面中的Image组件,直接在当前页面中预览,赋值给Image组件时只能赋值文件的Id,可通过getId()方法获取文件Id。
- 上传组件可以配置后台流程,如果将提交上传文件Action配置在上传组件的流程中,程序在执行的时候,会在用户选择完文件的同时将文件上传到数据库中;
- 也可以在其他按钮的流程中添加提交上传文件Action,比如:在弹出框的保存按钮中配置,当用户通过上传组件选择要上传的文件后,点击保存按钮之后,才会将所选文件上传到数据库中。
具体配置步骤: ❶ 在界面中添加上传组件; ❷ 在上传组件或其他按钮的流程中添加提交上传文件Action; ❸ 可以根据需要给返回值定义名称,赋值给预览文件或者Image组件;
Upload组件“上传结束”的事件配置三种用法:详见以下具体实现方法。
用法1:上传前预览。首先【API】获取文件流(此步骤不会生成Media对象,即不会保存进数据库),然后【设置组件值】将文件流赋值给Image组件。
用法2:上传后预览。首先【提交保存数据】(保存到数据库media表),然后【文件预览】。
用法3:上传后显示。首先【提交保存数据】(保存到数据库media表),然后【设置组件值】赋值给MediaFrame组件。
另外:是否要上传多个文件,在Upload组件的【基本属性】-【组件】-【File Max Files】中设置,1为单个文件,大于1为多个文件。
# 导出
导出当前页面数据。 ❶ 设计页面添加导出按钮,进入导出按钮事件页面 ❷ 事件页面添加导出控件,设置导出过滤条件(比如根据名称来查询的结果,导出对应名称过滤后的数据)
# 设置BPMN业务数据
bpmn工作流专用控件,用于表单提交事件,主要是把表单业务数据id传给工作流。
# 打印机打印
打印组件,用于生产过程中的一些常规打印需求。添加打印组件后,选中打印机组件进入属性设置(Action Properties)。 打印机ID可以不填,点击打印机模板下拉框展示系统中所有打印机模板文件,选择一个打印机模板后页面下方会直接带出打印机模板里的参数,输入对应的参数值。
ActionFlow页面一改以往下拉框形式,而是修改成了平铺展示(多个TAB),并且如果某个事件有内容的话,默认选中这个TAB,并且有内容的跟无内容的需要显示颜色标注。同时actionflow页面增加了一键format功能,当actionflow页面的控件排列比较杂乱时,可以通过一键format功能解决。
# Action 扩展
Action除了内置的实现, 平台也提供了扩展。 如需扩展,需要实现以下步骤:
- 扩展Action:需继承ExtendAction类,并重写getActionFlowItemType()方法及getLabel()方法。
- 扩展Action类型:需实现IWidgetActionFlowItemType接口
- 扩展Action对应的属性面板:需实现IActionPropertiesPanel接口
- 扩展Action对应的执行程序:需实现IActor接口
# 扩展Action
继承ExtendAction类
新扩展的Action类型,会在页面“Action Flow Library”面板看到,设计时可以选择扩展的类型。
ExtendAction定义
public class ExtendAction extends NodeData {
private static final long serialVersionUID = 567285355342148548L;
public ExtendAction() {
super("extend-action");
}
@Override
public String getLabel() {
return "Extend";
}
@Override
public void validate(IDisplay display) {
}
@Override
public ExtendAction clone() {
ExtendAction clone = (ExtendAction) super.clone();
return clone;
}
}
例.扩展的TextAction
public class TextAction extends ExtendAction {
@Override
public IWidgetActionFlowItemType getActionFlowItemType() {
return MesWidgetActionFlowItemType.TEST;
}
@Override
public String getLabel() {
return "Text";
}
}
# 扩展Action类型
创建一个enum并继承IWidgetActionFlowItemType接口。
IWidgetActionFlowItemType接口定义
public interface IWidgetActionFlowItemType {
IWidgetActionFlowItemType getValue(String name);
String getName();
String getNameKey();
String getDisplayName();
String getIcon();
Class<? extends IActionPropertiesPanel> getPanelClazz();
Class<? extends CellData> getActionClazz();
}
例.MesWidgetActionFlowItemType
public enum MesWidgetActionFlowItemType implements IWidgetActionFlowItemType {
/**
*
*/
TEST("Test", "lumos.design.event.test", "platform/icons/actionflow/Entry.png", TextAction.class, TestWidgetActionPanel.class);
private String name;
private String nameKey;
private Class<? extends IActionPropertiesPanel> panelClass;
private Class<? extends CellData> actionClass;
private String iconPath;
MesWidgetActionFlowItemType(String name, String nameKey, String iconPath, Class<? extends CellData> actionClass, Class<? extends IActionPropertiesPanel> panelClass) {
this.name = name;
this.nameKey = nameKey;
this.iconPath = iconPath;
this.actionClass = actionClass;
this.panelClass = panelClass;
}
@Override
public IWidgetActionFlowItemType getValue(String name) {
if (name != null) {
for (MesWidgetActionFlowItemType c : MesWidgetActionFlowItemType.values()) {
if (c.getName().equals(name)) {
return c;
}
}
}
return null;
}
@Override
public String getName() {
return name;
}
@Override
public String getNameKey() {
return nameKey;
}
@Override
public String getDisplayName() {
return I18NUtility.getValue(getNameKey(), getName());
}
@Override
public String getIcon() {
return iconPath;
}
@Override
public Class<? extends IActionPropertiesPanel> getPanelClazz() {
return panelClass;
}
@Override
public Class<? extends CellData> getActionClazz() {
return actionClass;
}
}
# 扩展Action属性面板
创建一个enum并继承 IActionPropertiesPanel
接口。
IActionPropertiesPanel接口定义
public interface IActionPropertiesPanel<T extends CellData> {
IWidgetActionFlowItemType getActionType();
void init(IDisplay display, T callData, WidgetActionFlowDiagram actionFlowDiagram, ActionFlowData actionFlowData);
default void setDisplay(IDisplay display) {
}
default void setCellData(T callData) {
}
default void setActionFlowData(ActionFlowData actionFlowData) {
}
default void setDiagram(WidgetActionFlowDiagram actionFlowDiagram) {
}
}
# 扩展Action执行
实现IActor接口。
IActor定义
public interface IActor {
void execute(ActionFlowContext actionFlowContext);
}
TextActor
public class TextActor extends BaseActor<TextAction> {
public TextActor(TextAction action) {
super(action);
}
@Override
protected boolean doExecute(ActionFlowContext actionFlowContext) {
//自定义自己的执行逻辑
return true;
}
}
# Action一键检查功能
# Console展示错误信息
一键检查功能是指针对Action进行遍历检查,对可能出现的错误进行打印提示。
一键检查有两个入口,分别在页面头部位置和Action Flow画布的右上角位置
当点击一键check按钮时,系统会自动打开Console面板展示错误信息。
用户也可以按下 Ctrl+F12
键手动打开/关闭Console面板。
# validate扩展
重写 IAction
中的 validate
方法
以OpenDialogAction为例
public class OpenDialogAction extends CommonAction {
@Override
public void validate(IDisplay display) {
if (type.equals(APIActionType.COMPONENT.getName())) {
if (Strings.isNullOrEmpty(componentId) || display.getWidgetById(componentId) == null) {
Designer.getConsole()
.error(this.getClass().getSimpleName() + " --- Component: '" + componentId + "' is not existed");
}
} else if (type.equals(APIActionType.SERVICE.getName())) {
if (serviceClassName == null) {
Designer.getConsole().error(this.getClass().getSimpleName() + " --- Service class name is null");
}
if (Strings.isNullOrEmpty(methodName)) {
Designer.getConsole().error(this.getClass().getSimpleName() + " --- Method name is null");
}
}
}
}
# 事务处理
对于众多的Action执行中,系统支持对于事务的基本处理。其原则为:
系统会在一次事件调用中,遍历所有的Action,找到第一个为 ITransactionalAction 类型的action,然后将后续的所有Action放入到事务中来处理。
public interface ITransactionalAction {}
目前实现以上的接口有以下几个Action:
- ApiAction
- SubmitDataAction
public class ApiAction extends BaseAction implements ITransactionalAction {
private static final long serialVersionUID = -8906250438743395484L;
private static Logger log = LoggerFactory.getLogger(LoadDataAction.class);
private Class serviceName;
public class SubmitDataAction extends HasAction implements ITransactionalAction {
private static final long serialVersionUID = -8030805740324876028L;
private static final Logger log = LoggerFactory.getLogger(SubmitDataAction.class);
public static final String SUMBMIT_DATA = "submitdata";