页面树结构
转至元数据结尾
转至元数据起始

前两章节介绍了表单控件相关的脚本开发能力,通过脚本控制表单控件基本行为,设置与获取控件绑定的数据对象等;本章进一步介绍表单控件的事件机制,与事件绑定操作的脚本扩展能力。

同时本章还补充介绍前端调用restful API、文件下载、DWF表单打开、对象数据查询与动态参数控件等高级脚本能力。

1. 脚本基础

1.1 表单控件事件机制

事件(Event)是UI页面重要概念,负责响应用户与页面元素的交互,常见的UI事件如表格控件行单双击事件、文本框值修改事件、文本框鼠标失去焦点事件、鼠标悬停事件等;DWF的表单定制过程也支持这些事件的定义,只是不同的表单控件所支持事件类型不一样,如表格控件所支持单双击事件,在文本框控件中就没有,而文本框只有值改变、鼠标获取焦点与失去焦点等事件;DWF大部分控件都封装支持了事件,而且事件绑定的操作也能基于脚本进行二次开发扩展,DWF表单中控件事件定义示例如下图所示:

图-DWF表单控件事件支持

DWF中典型控件事件说明:

  • 表格控件支持事件类型(如上图所示)
    • 单击:表示表格所选行的单击事件,一般场景为切换选中表格行,通过事件操作,控制对象详情区域刷新显示。
    • 双击:表示表格所选行的双击事件,一般场景为双击表格行,通过事件操作,触发dialog弹窗显示详情。
  • 文本控件支持事件类型(如下图所示)
    • 值变化:表示文本框内容发生变化时触发,一般可处理属性间联动的场景处理。
    • 获取焦点:文本控件获取焦点一般可清空默认提示等。
    • 失去焦点:文本控件失去焦点一般可用于额外正确性脚本等场景。
    • 鼠标悬停:文本控件鼠标悬停一般可弹出气泡详细显示tooltip提示信息等。

图-表单文本类型控件支持事件类型

如上列举了DWF表单中常用的”文本控件“与”表格控件“的事件支持,其它表单控件的事件支持就不展开说明。

1.2 前端restful接口调用

DWF是前后端分离的体系结构,前端通过restful API调用后端。在登录DWF后,点击右上角的“API说明”可获得restful API的详细说明。

1.2.1 modeler模型服务 restful API,通过下面的函数调用模型服务,从而操控DWF模型数据:

this.dwf_modeler_axios()函数是DWF模型restful 服务脚本调用总入口,该脚本调用示例说明如下:

//获取当前登录用户
var curUserId = this.user.userId;
//调用的参数,参见API说明
let param = {
};
//调用modeler端的restful API
this.dwf_modeler_axios(`/dwf/v1/org/users/${curUserId}/groups`).then(rtnOBJ => {
   // 在回调中处理rtnOBJ值…
    this.msgbox.success("调用成功");
});

1.2.2 app对象服务 restful API,通过下面的函数调用对象服务,从而超控DWF所有的业务对象数据:

this.dwf_axios()函数是DWF对象restful 服务脚本调用总入口,该脚本调用示例说明如下:

let param = {
};
this.dwf_axios.post(`/dwf/v1/omf/entities/${this.className}/objects/count`,param).then(initRes => {
   //在回调中处理
    this.msgbox.success("调用成功");
});

1.2.3 通用restful API,需要调用DWF之外的其它restful API时,可使用以下函数:

this.axios()函数是DWF之外其它异构的restful 服务脚本调用总入口,调用其它通用的restful 服务器时要注意,即不要将ip地址和端口号写死,否则服务器迁移功能就会失效,可以使用“this.env.serverIp”和地址无关来实现动态调用,该脚本调用示例说明如下:

//调用其它服务器的restful API
var curServerIP = this.env.serverIp;
var param = {…};
this.axios.post(`${curServerIP}/[其他接入点路径]`,param).then(rtnOBJ => {
    //回调处理…
    this.msgbox.success("调用成功");
});

1.3 文件下载

文件下载是比较常见的功能需求,DWF单对象表单是已支持通过”附件“控件实现文件(包括图片)的上传、下载与在线浏览功能,但有时在多对象控件或其它页面中存在使用DWF”附件“控件之外的文件下载需求,此时就需要利用的文件下载的脚本能力,如下所示”下载“设备图片的脚本示例:

clientScript:
if (this.selectedObjs && this.selectedObjs.length > 0){
    console.log(this);
	fileURL=`http://${this.env.serverIp}:9090/dwf/v1/omf/classes/${this.className}/objects/${this.selectedObjs[0].oid}/attributes/assetImg/bytes?attachment=true&0`;
    console.log(fileURL)
    window.open(fileURL);
}

1.4 脚本中动态执行其他操作

存在这种情况,希望在脚本中动态执行一些其他操作,例如:在前端脚本中根据对象所处的状态,打开不同类型的其他表单,此时可以通过下面的调用完成目标:

this.getOperation(className, oprName):返回一个操作的对象,作为输入可以动态激活操作。

this.executeOperation(opr):输入一个操作对象,在脚本中激活该操作。

以打开设备类的oprAI操作为例,典型的调用方式如下:

this.getOperation('Asset', 'oprAi').then(res => {
    var operation = res.data.data;
    this.executeOperation(operation).then((opr) => {
        this.freshData()
    });
})

1.5 对象数据查询

DWF前端提供灵活的业务数据查询脚本API,这里对常见的实体类对象查询API进行说明,如下脚本示例,其中说明了”ES6字符串转换机制“与”this.handleQueryData()“函数调用:

//查询条件
let  queryConditon = {
   targetClass:"Part",
   query:{query:`and obj.id='${this.obj.name}'`}, //ES6字符串转换机制,即在``中间变量可通过${}引入;
   fresh: true     //是否从后台强制刷新查询
};
//进行后端数据查询,在回调函数中处理查询结果
this.handleQueryData(queryConditon).then(res => {
   //针对res值(查询返回值)直接处理…
});

1.6 动态参数控件

动态参数控件作用是运行时通过动态传入Form表单的UI元素(属性字段)构成,即时根据传入渲染出表单页面,然后手动录入值后再通过脚本获取录入的数据对象,最后脚本再灵活处理这些数据,如新增或修改保存到系统中;该控件在脚本中有比较灵活的应用场景,支持在modeler中少定制很多表单,而是通过脚本逻辑动态构造表单UI元素Schema构成,具体动态参数控件使用与脚本处理如下示例:

图-表单中定义动态参数控件

1.6.1动态参数控件基础

  • 控件页面显示字段元数据设置
    • 字段必选属性
      • name:字段名称
      • value:字段取值
    • 字段扩展属性
      • type:数据类型,具体支持常用的”int/整形"、”datetime/日期“与”string/字符串“等
      • default:缺省值,需要和数据类型匹配
      • label:页面中字段显示名
      • required:布尔值,表示对应参数是否必须填写
      • tips:字符串,给用户的提示文本
  • 控件布局方式:
    • 表格(多列)布局:即多字段按照水平从左至右(支持2列/3列/4列设置)垂直从上至下顺序布局,
    • 垂直浮动布局:即多字段按照垂直从上至下水平固定一列浮动布局。
  • 控件脚本函数:
    • addin.setValue():作用是设置控件的页面显示字段元数据,脚本示例:[{"name": "name","label":"商品名称" ,"type": "string", "tips":"请输入","default":"","required": true},{...}]
    • addin.getValue():作用是获取控件的页面显示字段所有数据,包括元素据与具体value值,脚本返回示例如:[{"name": "name","label":"商品名称" ,"type": "string", "tips":"请输入","default":"","required": true,"value": "桌子"},{...}]
    • addin.getKVValue():作用是获取控件的页面字段对应的Key/Value键值对json集合对象,即不包括元素据,脚本返回示例如:{"number": 1,"date":"2020-03-01 10:30:00" ,"name": "桌子", "price":100,"type":"家具","description": "测试数据..."}

1.6.2 动态参数控件脚本示例

上图中”设置动态参数Schema“按钮操作,通过如下脚本执行,即时渲染出的表单控件显示页面如下所示:

clientScript:
//定位获取”动态参数表单“控件对象
var addin = this.getAddinById('C70A786EDBB04E3B99CC2F8AF26F67E0');
debugger;
var schemaJson = `[
{"name": "number","label":"数量" ,"type": "double", "tips":"请输入","default":"","required": true},
{"name": "date","label":"生产日期" ,"type": "date", "tips":"请输入","default":"","required": true},
{"name": "name","label":"商品名称" ,"type": "string", "tips":"请输入","default":"","required": true},
{"name": "price","label":"价格" ,"type": "double", "tips":"请输入","default":"","required": true},
{"name": "type","label":"商品类型" ,"type": "string", "tips":"请输入","default":"","required": true},
{"name": "description","label":"商品说明" ,"type": "string", "tips":"请输入","default":"","required": true}
]`
addin.setValue(schemaJson); 

图-表单动态参数控件运行时即时页面渲染

上图中”获取动态表单对象“按钮操作,具体脚本如下所示:

clientScript:
//动态参数控件对象
var addin = this.getAddinById('C70A786EDBB04E3B99CC2F8AF26F67E0');
//获取控件全部数据(包括原schema与新输入值)
var formValue = addin.getValue();
/*获取控件KV键值对数据,即不包括原schema元数据,返回数据如下:
{"number": 1,"date":"2020-03-01 10:30:00" ,"name": "桌子", "price":100,"type":"家具","description": "测试数据..."} */
var formOBJ = addin.getKVValue();
//TODO:针对formOBJ的后续处理

2. 脚本案例

在设备管理案例中,设备详情页中针对产品结构部位选择联动设备的工单列表,在教学案例设备管理模块中有个”设备详情页“,如下图所示,该页面上侧为设备基础属性区,左下为设备的产品结构显示区,右下为设备的工单列表区。本案例主要介绍左树右表控制工单自动刷新的场景。

图-设备详情页及树节点单击事件定义

2.1 设备管理中工单与设备及零部件的模型关系

图-设备管理数据模型

通过上面树模型类图,可了解到工单(WorkOrder)有”故障设备(assetOid)“与”故障部位(partOid)"两个属性,其中“故障部位”允许为空,但“故障设备”不能为空;

一个“设备(Asset)”存在多个“工单(WorkOrder)”,如果同时故障部位不为空,那么表示相同“设备(Asset)”与“部位(Part)”也可存在多个“工单(WorkOrder)”。

2.2 右下侧工单列表刷新显示逻辑

通过上面的“设备管理数据模型”截图与“设备详情页”截图,可理解如果不选择产品结构中的“部位”,那么右(下)侧工单列表的过滤逻辑仅与当前设备相关,如果选择产品结构中部位后,会多增加基于“部位”的二次工单过滤,如下图所示:

图-工单列表默认基于当前设备的过滤条件

上图中表格过滤条件(“and obj.assetOid = '$obj.oid'” )通过表单自带的“过滤条件生成器”交互产生,其中“ obj.”表示对应的数据库中的工单表,其中“$obj.oid”表示当前设备对象变量。

2.3 左侧设备部位结构树节点选择事件脚本

上图中如果不选择左侧设备部位树节点,那么右侧的工单列表会显示所有故障设备为与当前设备的所有工单,但如果选择了左侧“故障部位”导航树的部位,那么右侧工单列表会过滤刷新,即仅显示工单故障部位为当前左侧导航树所选部位的工单;左侧设备部位树提供了树节点单击选择事件机制,且树节点单击选择事件的脚本可绑定开发脚本,通过脚本可灵活处理表单特定逻辑,如下面脚本示意了通过树节点单击选择事件刷新右侧工单列表;

clientScript:
//左下侧的产品结构表示(工单涉及)部位的树
tree = this.getAddinById("5E181498CEC545B1B6FA571B5DB68532");
//右下侧的工单列表
list = this.getAddinById("847A1B03A10642BE9C8740E942751D6B");
console.log("tree:",tree); //前端调试输出
nodes = tree.getSelected();  //导航树所选部位节点
if (nodes.length > 0){
    console.log("nodes:", nodes)
    if ('relation_rightOid' in nodes[0]){//判断选择的是非根节点
		/*两个过滤条件,除了所属设备(obj.assettOid),还需所属部位(obj.partOid)
		其中${nodes[0].right_id},表示当前所选产品结构树的零部件节点,且取其中一个节点,
		节点对象实际绑定的关系对象,因此right_id是具体子件的id;*/
        list.freshData(`and obj.assettOid = '${this.obj.oid}' and obj.partOid like '${nodes[0].right_id}%'`); 
    } else {//判断选择的是根节点
		//表示工单不体现(零部件)部位,只与整体设备相关
        list.freshData(`and obj.assettOid = '${this.obj.oid}'`);   
    }
}

3. 小结

本章主要介绍了表单控件事件机制与相关的高级脚本能力,重点需掌握如下相关的脚本基础:

  • DWF表单控件事件机制,以及典型的单击、双击、值变化、鼠标焦点获取、失去鼠标焦点与鼠标悬停等常用事件;
  • 前端对restful API服务几种调用函数:this.axios, this.dwf_axios, this.axios_app 与 this.axios_moderler;
  • 文件下载脚本处理;
  • 直接打开主页签页面表单;
  • 动态参数控件使用与脚本封装。

本章是前端脚本介绍最后一章,下一章开始介绍后端脚本能力与典型案例场景说明。

4. 附件

第六章 表单中的事件脚本.zip

  • 无标签