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

概述

下面的表格列举了DWF的前端脚本提供的基础调用,以及一些控件的用法要领:

  • 全局变量:DWF脚本引擎中可以直接访问到的变量数据
  • 查询条件:在查询条件配置界面和URL操作的链接中可以使用的全局变量
  • 应用配置:可以用来控制app端的一系列函数,例如:在应用打开的时候把那些模块展开
  • 数据交互:DWF脚本访问数据或者通过接口访问数据,与前端进行消息通讯等
  • 表单交互:DWF脚本实现表单直接的切换,表单本身数据的更新,表单间参数传递
  • 控件访问:DWF脚本直接访问表单的控件、获取控件上的方法等
  • 控件要领:对部分控件的脚本使用要领

评论区则是在实战中积累的经验,作为备忘尚未整理但是在解决实际问题时肯定会用到的脚本。

详情

序号功能分类脚本名称/关键字功能描述适用范围/场景脚本示例说明
1全局变量





this.obj

表单绑定的类的对象,如果没有条件限制默认获取的是绑定类的最新一条记录

是一个JSON对象

this.obj是当前表单绑定类的对象,可以通过类上的属性获取返回对象的某一项的值

调试查看this.obj的返回值:

console.log(this.obj);

1)操作动作为visit/edit时,this.obj有数据

2)操作的前处理脚本中写了return{obj:obj},表单的this.obj会有对应值

使用范围:

在表单上绑定的前端脚本均可用

实体类:

  • console.log(this.obj);
  • this.obj.[属性名]

关联类:

  • this.obj.left_[左类属性名]
  • this.obj.right_[右类属性名]
  • this.obj.relation_[关联属性名]
2this.selectedObjs

表单中含有唯一的多对象控件时,通过此数组获得用户选中的对象,如果是有多个多对象控件可以在表单设置中绑定多对象控件

是一个JSON对象数组

使用范围:

表单中有多对象控件(表格),并且在表单的基础配置中设置了默认多对象控件,该脚本有效,否则为null


console.log(this.selectedObjs);
3this.data

打开表单的初始化参数

在表单中的任何操作的前端脚本都可以直接使用this.data获取初始化参数

是一个JSON对象

可以使用的场景有两类:

1)操作的前处理脚本,通过return{ data:this.obj} 可以传递json对象到打开的表单

2)使用脚本打开表单传参,可用的有:this.openTab,this.openForm,this.openDrawer


console.log(this.selectedObjs);
4this.env

当前DWF前端的上下文信息,返回一个JSON对象,JSON对象属性包括:

  • this.env.serverIp:获取服务器ip,在浏览器地址栏输入的DWF服务器位置
  • this.env.serverPort:字符串,在浏览器地址栏输入访问DWF服务器的端口号
  • this.env.appConfig[]:键值对,包含了在DWF配置文件中记录的配置项
  • this.env.serverURL:获取服务器URL,服务器IP+端口
  • this.env.metaServicePort:DWF元数据接口访问端口
  • this.env.objServicePort:DWF对象数据接口访问端口
  • this.env.locale:当前DWF的语言环境,用于判断是否要执行特定国家的逻辑

可以用在所有的前端脚本中,不限位置



console.log(this.env);
console.log(this.env.serverIp);
console.log(this.env.serverPort);
console.log(this.env.serverURL);
console.log(this.env.metaServicePort);
console.log(this.env.objServicePort);
console.log(this.env.appConfig);
console.log(this.env.locale);
5this.user

当前登录用户的基本信息,返回一个JSON对象,包括属性如下:

  • this.user.oid:字符串,当前登录用户在内部的唯一代号
  • this.user.userName:字符串,用户登录DWF的账号
  • this.user.displayName:字符串,用户的中文显示名
  • this.user.token:字符串,用于访问其他网站的令牌
  • this.user.userGroups:数组,当前用户所属的直接用户组
需要获取到用户的基本信息的时候,可以使用this.user


console.log(this.user.userName);
console.log(this.user.userId);
console.log(this.user.oid);
console.log(this.user.token);
console.log(this.user.userGroups);
console.log(this.user.displayName);
6this.store

DWF内部变量,缓存了当前访问表单的基本信息

是一个JSON对象,可用的对象如下:

  • this.store.state.DWF_form :表单绑定的类和属性的信息
  • this.store.state.DWF_global:当前DWF的服务器配置信息包括:服务器地址、接口对应端口等
  • this.store.user:当前登录用户和用户组的信息及当前登录的token

需要获取到配置系统的配置信息的时候可以使用this.store



console.log(this.store.state.DWF_form);
console.log(this.store.state.DWF_global);
console.log(this.store.state.user);
console.log(this.store);
7this.confirmData弹窗表单新增对象/编辑对象成功后提交的表单数据,在后处理脚本中可用仅适用于操作的后处理脚本中


console.log(this.confirmData);
8this.className表单所属的实体类或者关联类的名称任何表单的脚本中都可以使用


console.log(this.className);

9

this.generateUUID()

生成uuid的函数
console.log("打印自动生成的uuid:"+this.generateUUID());
10查询条件关键字$env

仅在拼接过滤条件等场景下使用,获取当前环境的基本信息,返回一个JSON对象,包括属性如下:

  • $env.serverURL:获取服务器URL
  • $env.serverIp:获取服务器ip
  • $env.serverPort:服务器端口
  • $env.metaServicePort:DWF元数据服务端口
  • $env.objServicePort:DWF对象数据服务端口

1、操作动作为url的时候,在URL地址中可用$env

2、在过滤条件中可以使用$env

3、嵌入网页的连接地址中可以使用$env

4、功能模型->应用管理->编辑应用中的起始操作可以使用$env


11$user

仅在拼接过滤条件等场景下使用,当前登录用户的基本信息,返回一个JSON对象,包括属性如下:

  • $user.oid:字符串,当前登录用户在内部的唯一代号
  • $user.userName:字符串,用户登录DWF的账号
  • $user.displayName:字符串,用户的中文显示名
  • $user.token:字符串,用于访问其他网站的令牌
  • $user.userGroups:数组,当前用户所属的直接用户组

1、操作动作为url的时候,在URL地址中可用$user

2、在过滤条件中可以使用$user

3、嵌入网页的连接地址中可以使用$user

4、功能模型->应用管理->编辑应用中的起始操作可以使用$user


12$obj

仅在拼接过滤条件等场景下使用,表单绑定的类的对象,如果没有条件限制默认获取的是绑定类的最新一条记录

是一个JSON对象

1、在表单中的事件操作动作为url的时候,在URL地址中可用$obj

2、在过滤条件中可以使用$obj

3、嵌入网页控件的连接地址中可以使用$obj

注意:当表单以create状态打开,如果未初始化数据$obj的各项属性为空,慎用


obj.[attributeName类属性英文名]=$obj.[attributeName类属性英文名]

13$form

获取表单的单对象控件的取值

示例:$form["控件代号"]

该关键字可用到过滤条件中,并且仅对单对象控件有效(有getValue方法的有效)

注意:如果是单选框、复选框、选择框等设置了数据的回填和显示属性不一致,则此处返回的是该控件的回填属性的取值

在过滤obj.attributeName= '$form["id"]'
14应用配置this.env.setCollapsed();
  • 侧边栏默认为展开,默认为false
  • 参数为false时表示侧边栏展开
  • 参数为true时表示侧边栏关闭
PC应用菜单
//控制侧边栏收起
setTimeout(() => {
	this.env.setCollapsed(true);
},500)
15this.env.setOpenNames

指定某些菜单展开

  • 展开菜单列表为二维数组,示例中['外部模块','iotdb外部映射','A'],按照格式['第一级菜单','第二级菜单','第三级菜单'],写入分组菜单的中文名称,只展开匹配到的下一个层级,再深层级的嵌套子集的不需展开
PC应用菜单
//分组菜单默认折叠,如需展开:
setTimeout(() => {
	this.env.setOpenNames([['招聘管理','人事管理'],['招聘管理','个人信息'],['外部模块','iotdb外部映射','A']])
},500)

数据访问

this.handleQueryData()

获取DWF定制的实体类、关联类的数据对象的脚本,支持回调,入参的查询条件为JSON对象,分别是:(返回方式为异步请求,如果在前端脚本要等待返回成功做处理需要将处理内容写到回调函数中)

  • targetClass:要查询数据所在的类(实体类、关联类、外部实体类)
  • queryObjReq:查询条件,是一个json对象,包含如下的属性:
    • 单纯查询目标类对象
      • condition:字符串,可以不传,一个DWF的快速查询条件,即:以and开头的若干逻辑表达式的组合,例如:`and obj.creator = '${this.user.oid}'`。
      • startIndex:整数,可以不传,用于翻页,从哪一行开始
      • pageSize:整数,可以不传,用于限制每页的大小
      • returnAttrs:字符串数组,可以不传,表示在得到的结果里面需要哪些英文名的属性,如:["assetName", "assetType", "assetState", "workhours"]
    • 通过属性引用其他类对象,此时返回的结果将变为1个JSON对象,包含queryResult和refResult两个属性,具体引用设置如下:
      • refs:数组,用于在第一轮查询出的结果基础上从数据库通过关联Join查询引用多个其他实体类对象,并将结果一并返回
        • id:字符串,返回值唯一key值,可以不填,如果不填,则返回结果为sourceAttr的取值。
        • sourceAttr:字符串,targetClass所指的实体类(或关联类)上关联了对象的属性,如 consumer(订单创建人)
        • sourceAttrSplit:字符串,sourceAttr的参数分隔符,用于支持根据多选回填查询显示取值
        • targetClass:字符串,被关联的类的类名,如 Customer(客户信息类)
        • targetAttr:字符串,被关联的类上的关联字段(即 回填字段),如 name
        • returnAttrs:字符串数组,可以不传,表示在得到的结果里面需要哪些英文名的属性,如:["assetName", "assetType", "assetState", "workhours"]
    • 顺便查询其他类对象,如果希望通过查询得到的结果与目标类直接查询得到的结果无关,只是顺便查询,例如:一些字典的选项,那么就可以使用options,其返回的结果会在前面的refResult、queryResult的基础上,额外包含optionsResult,类型为一个数组。
      • options:数组,用于在第一轮查询的结果基础上,额外提取一些与查询结果无关的其他类数据,一方面方便前端处理,同时减少前后端来回的调用降低性能
        • id:字符串,返回值唯一key值,可以不填,如果不填,则返回结果为sourceAttr的取值作为key。
        • targetClass:字符串,被关联的类的类名,如 Customer(客户信息类)
        • condition:字符串,以 and 开头的 sql 查询语句,此字段可不传递或设为空串
        • pageSize:数字,被请求对象个数
        • returnAttrs:字符串数组,可以不传,表示在得到的结果里面需要哪些英文名的属性,如:["assetName", "assetType", "assetState", "workhours"]
表格后台数据强制刷新/查询
  • 单纯查询实体类对象,返回结果
//查询条件
let  queryConditon = {
   targetClass:"Part",
   queryObjReq:{condition:`and obj.id='${this.obj.name}'`}
};
//基于DB进行查询
this.handleQueryData(queryConditon).then(res => {
	//调用成功返回结果为一个Part对象组成的数组
	console.log(res)
});
  • 增加属性引用其他实体类,返回结果含有queryResult和refRestult两个属性。
let  queryConditon = {
	targetClass:"Asset", 
	queryObjReq:{
		pageSize:3, 
		returnAttrs:["oid", "id","assetName"], 
		refs:[{
			sourceAttr:"partOid", 
			targetClass:"Part",
			targetAttr:"oid", 
			returnAttrs:["partName", "oid"]
			}]
		}};
//基于DB进行查询
this.handleQueryData(queryConditon).then(res => {
   console.log(res)
});
//打印得到的对象数组如下:
{
    "queryResult": [
        {
            "assetName": "",
            "oid": "6ADCD23CDC7EBF45A2DEC0B42E5AEFD6",
            "id": "我自闭了"
        },
        {
            "assetName": "",
            "oid": "0909498BE13D644B80ACC643A27BF4EB",
            "id": "我想开了"
        },
        {
            "assetName": "搅拌车",
            "oid": "05C2B5311CBE1B42B60A3ED6FFCF6734",
            "id": "BC1010313113"
        }
    ],
    "refResult": {
        "partOid": []
    }
}
17this.handleQueryBySQL()

提供在DWF数据库中接入的数据源,执行原始SQL语句的能力,接受一个对象,包含下面的属性:

  • dataSourceName:字符串,配置的数据源,如果不传,则从DWF默认的数据中执行。
  • condition:字符串,SQL语句

返回结果:

  • res.data.data.head:字符串数组,表示结果集的表头
  • res.data.data.data:二维数组,是查询得到的内容
切记,不要一次查询上巨量数据,例如:上百万量级,导致OOM(Out Of Memory)
  • 用SQL查询DWF的数据库
//用SQL查询DWF的数据库
this.handleQueryBySQL({"condition": "select plt_name as 姓名 from plt_org_user "}).then(res => {
	let header = res.data.data.head;
	let data = res.data.data.data;
    console.log(header); //输出结果为:["姓名"]
	console.log(data); //输出结果为:["admin"...]
});
  • 查询配置到DWF中的IoTDB数据源,假设外部数据连接的名字是IoTDB
//查询配置到DWF中的IoTDB数据源,假设外部数据连接的名字是IoTDB
let query = {
	dataSourceName: 'IoTDB',
	condition: 'select v_in from root.test.round00 limit 100'
}
this.handleQueryBySQL(query).then(res => {
	let header = res.data.data.head;
	let data = res.data.data.data;
    console.log(header); //输出结果为:["Time, root.test.round00.v_in"]
	console.log(data); //输出结果为:带时间戳的100个值
});
18this.handleQueryByApi()要求先在DWF建模工具中的“数据集成”-“API接口管理”的功能下面将外部接入的API先配置好,给其设定一个名字,如:“新闻报道”,在脚本中,直接将这个名字传递给函数,获得返回结果。要先配置好API,并且为其命名才能起作用。
//假设已经在建模工具的“数据集成”-“API接口管理”配置好名为:“新闻头条”的API
this.handleQueryByApi("新闻头条").then((res) => {
  console.log(res);
});
//返回结果随API的不同而不同
19this.create()

支持实体类和关联类表单中执行新增操作

  • 实体类:this.create(obj,className,{showMessage:true/false})
  • 关联类this.create(obj,className,{isRelation:true,showMessage:true/false})
用于系统新增时控制是否弹出信息和关联类表单新增实体类并控制是否弹出信息

新增实体类对象

//系统新增并弹出信息提示
this.create(obj, "WorkOrder", {showMessage:true}).then(res => {
	//res即为被新增的对象
	console.log(res);
})

新增关联类对象

//关联类表单新增实体类并控制是否弹出信息
this.create(obj, "WorkOrderToPart", {
isRelation:true,
relationClass:'WorkOrderToPart',
leftClass:'WorkOrder',
rightClass:'Part',
showMessage:true}).then(res => {
	//res为被新增的关联类对象
	console.log(res);
})
20this.createObj()在前端创建内存对象,临时对象不保存到数据库。如果在异步调用的响应函数then中,使用this.returnSync({obj: res}),则会实现同步传递。
//创建前端内存对象
let obj = this.createObj(this.className).then((res) => {
	console.log("新增内存对象oid=" + res.oid);	
	this.returnSync({obj: res})
})
console.log("新增内存对象oid=" + obj.oid);
return {sync:true}
21this.edit()

支持实体类和关联类表单中执行编辑操作

  • 实体类:this.edit(obj,className,{showMessage:true/false})
  • 关联类this.edit(obj,className,{isRelation:false,showMessage:true/false})
用于系统编辑时控制是否弹出信息和关联类表单编辑实体类并控制是否弹出信息

 实体类编辑

//系统编辑时控制是否弹出信息
this.edit(obj, "WorkOrder", {showMessage:true}).then(res => {
	console.log(res);
})

关联类编辑

//关联类表单新增实体类并控制是否弹出信息
this.edit(obj, "WorkOrderToPart", {
	isRelation:true,
	relationClass:'WorkOrderToPart',
	leftClass:'WorkOrder',
	rightClass:'Part',
	showMessage:true});
22this.delete()

支持实体类和关联类表单中执行删除操作

  • 实体类:this.delete(obj,className,{showMessage:true/false})
  • 关联类this.delete(obj,className,{isRelation:false,showMessage:true/false}
用于系统编辑时控制是否弹出信息和关联类表单删除实体类并控制是否弹出信息
//系统删除时控制是否弹出信息 
this.delete(obj, "WorkOrder", { showMessage:true});
//关联类表单删除实体类并控制是否弹出信息 
this.delete(obj, "WorkOrder", {isRelation:false, showMessage:true});
23

this.deleteByCondition(condition, className)

根据条件删除类对象

参数:

condition:查询条件

className:要操作的目标类


//删除实体类对象
var oid = this.getAddinById('Grid1').getSelected()[0].oid;
this.deleteByCondition(`and obj.oid='${oid}'`, 'WorkOrder').then(() => {
    this.getAddinById('Grid1').freshData();
})
//删除关联类对象
var oid1 = this.getAddinById('Grid2').getSelected()[0].relation_oid;
this.deleteByCondition(`and obj.oid='${oid1}'`, 'WorkOrderToPart').then(() => {
    this.getAddinById('Grid2').freshData();
})
24this.axios在前端调用接口可能的第三方接口

需要在config中补充接口信息,如headers: {'Authorization': this.user.token}。

由于是前端调用,要密切注意不会出现跨域调用被拒绝的问题CORS,如果出现该问题,改用后端脚本实现调用。



//从iotdb中获取最新的时间序列数据
var token = btoa("root:root");
var headers = { headers: { Authorization: `Basic ${token}` } }
var url = `http://i-vi6spj.cloud.nelbds.cn:8180/iotdb/rest/v1/query`;
var params = { sql: `select last * from root.fleet.*` };
this.axios.post(url, params, headers).then(res => {
	console.log(res.data);
});



25this.dwf_axios

在前端调用APP端的restfull接口,主要是实体类、关联类等数据的增删改查的接口,同时该接口还支持调用第三方服务的接口

支持post、get

注意:

  • 如果当前dwf的app接口,可以直接使用swagger中的地址去掉/dwf/v1即可
  • 如果是另外一个dwf服务的app接口,可以直接写全地址
  • post方法支持param参数,该参数为json对象
由于是前端调用,要密切注意不会出现跨域调用被拒绝的问题CORS,如果出现该问题,改用后端脚本实现调用。
//调用app的restful API示例1
let param = {
};
this.dwf_axios.post(`/omf/entities/${this.className}/objects`,param).then(res => {
	//在回调中处理结果
	console.log(res.data.data);
});

26

this.dwf_modeler_axios

在前端调用modeler端的restful接口,主要是一些模型类的数据、用户、授权、应用等建模相关接口

注意:

  • 如果当前dwf的modeler接口,可以直接使用swagger中的地址去掉/dwf/v1即可
  • 如果是另外一个dwf服务的modeler接口,可以直接写全地址
  • post方法支持param参数,该参数为json对象
调用modeler端的restful API
//获取当前服务器端IP
var curServerIP = this.env.serverIp;
//获取当前登录用户
var curUserId = this.user.oid;
//调用modeler端的restful API
this.dwf_modeler_axios("/dwf/v1/org/users/${curUserId}/groups");
27this.QueryResultAll()根据查询条件获取Store中缓存的数据该接口已经不推荐使用!
//查询条件
let  queryConditon = {
   targetClass:"Part",
   query:{query:`and obj.id='${this.obj.name}'`},
   fresh: true     //是否从后台强制刷新查询(建议默认值为true)
};
//该接口主要在store中进行查询(不查询后台DB)
let queryResult = this.QueryResultAll(queryConditon);
//TODO:查询结果queryResult处理
28this.getOperation()

根据类、操作名称获取操作的定义,通过getOperation获取到已有的操作(需要存储到数据库中),再通过executeOperation进行调用,并且允许修改已有操作的操作样式和动作。

  • targetClass:已有操作绑定的目标类;
  • operName:已有操作的英文名

在前端脚本中需要调用定义的其他前后端脚本操作,可以利用getOperation得到对应的脚本,然后借助executeOperation实现交互

//调用已有的操作,假设实体类WorkOrder有createWO的操作
this.getOperation("WorkOrder", "createWO").then(res =>{
    //先取出原始操作
    var opr = res.data.data;
    // 替代前处理脚本,不用的话可以不写
    opr.beforeExecute = () => {
        //新的前处理脚本
        return {
        		obj:{...},//选填,对象 
        		query:"",//选填,查询条件
        		data:{...}}//选填,自定义属性
    		}
		};
    // 替代原来操作的后处理脚本,不用的话可以不写
    opr.afterExecute = () => {
        //新的后处理脚本,可根据需要编写
        ...
    };
    this.executeOperation(opr);
});
29this.queryEntity()获取实体类的元模型信息,传入字符串表示的实体类的类名


//获取实体类的元模型信息
this.queryEntity(targetClassName).then(resMetaObj => {
   //在回调中处理resMetaObj值…
});
30this.queryRelation()获取关联类的元模型信息,传入字符串表示的关联类的类名
//获取关联类的元模型信息
this.queryRelation(targetClassName).then(resMetaObj => {
   //在回调中处理resMetaObj值…
});
31this.cudBatchObjs()

传入一个代表增删改事件的数组,批量增删改对象,在包含多个不同类型的实体类的复杂结构表单中,利用数据容器控件的this.getObj()提取对象,然后一次性提交数据修改,非常方便。

this.cudBtachObjs接受的是一个代表批量操作的动作数组,数组中的每个元素是一个JSON对象,包含下面的属性:

  • action:字符串,有4种动作:
    • 'create':批量创建对象,在对象数组中只需要给出对象的业务属性取值即可。
    • 'update':单纯的批量更新对象,要求对象数组中的对象必须包含一个oid属性。
    • 'delete':给定一个oid的数组,可以批量删除。
    • 'createOrUpdate':如果存在则更新,如果不存在则创建,要求数组中的对象必须包含oid属性,如果存在需要跨类设置oid和外键引用的时候,用这个动作。
  • className:字符串,表示要处理的类名
  • objs:数组,如果动作是'create', 'update', 'createOrUpdate',表示需要增删改的对象数组。
  • oids:数组,如果动作是'delete',表示要删除对象的全局唯一标识oid。

返回值为,被传入的动作数组,照原样返回,其中objs是实际增删改的数据。


var wo = this.getAddinById('DataView1').getObj();
var rt = this.getAddinById('DataView2').getObj();
var cudEvents = [
    {
        action: 'update',
        className: 'ReqWorkorder',
        objs: [wo]
    },
    {
        action: 'update',
        className: 'WorkorderReport',
        objs: [rt]
    },

 { "action" :"delete", "className":"TyPartDelivery", "oids":   ["7F8802A65B643E4FA1058E16197A23A3", "B075591C7FE45E43BFA0978CC409DCAA"] } 
];
this.cudBatchObjs(cudEvents);



32表单间交互this.openForm()

脚本打开弹窗,参数如下:

  • targetClass:字符串,表示对应的类
  • viewName:字符串,表示需要打开的表单名称
  • args:JSON对象,如果打算不传要使用null作为占位符,包含弹框的大小和高度,标题,初始化脚本和后处理脚本,具体有:
    • curDialogWidth:字符串,含有单位的宽度,如:800px
    • curDialogHeight:字符串,含有单位的高度,如:800px
    • curDrawerWidth:字符串,抽屉宽度,仅对抽屉效果有效
    • needDialogDefaultOpr:布尔,是否显示默认操作的按钮
    • displayName:字符串,弹窗以后标题的名字
    • initialScript:字符串,可以不传,前处理脚本
    • afterScript:字符串,可以不传,后处理脚本
  • displayType:字符串,打开方式,包含'edit', 'create', 'visit'。
  • initParams:JSON对象,用于完成弹窗打开前的初始化,与操作中的前处理脚本中return { obj:{...}, query: {...}, data: {...}} 返回的格式一致,可以设置对象,查询条件和夹带的数据
    • obj:对象,用于初始化的对象
    • query:字符串,默认查询条件
    • data:对象,外部带入的数据

如果,initialScript中初始化了返回的对象与initParams的含义冲突,以initParam里面的为准。


// 表单类名
let targetClass = 'ClaimResult'		
// 表单名称
let viewName = 'ClaimResultSingle' 	
// 弹框的基本操作
let args = { 
		curDialogWidth: '1000px',		/*弹窗宽*/ 
		curDialogHeight: '800px',		/*弹窗高*/, 
		needDialogDefaultOpr:false,		/*是否显示右下角保存按钮*/
		displayName: "openDialog标题",	/*弹窗标题*/
};
// 弹框的类型:create,edit,visit
let displayType = 'edit';	
// 前端脚本中Dialog弹窗脚本示例:
let initParams = {
    obj:this.selectedObjs[0],
    data: { woDesc1: 'cheney' }
}  
// 前端脚本中Dialog弹窗脚本示例:
this.openForm(
	targetClass, viewName, args, displayType, initParams
); 
33this.getRootForm()在有多层弹窗的情况下可以使用该方法获取最底层表单的句柄

34

this.getParentForm()出现弹窗的时候想在弹窗中获取父表单的控件可以使用该方法获取父表单句柄

35

前处理脚本:return false

表单默认操作:return false

如果无异步调用,在操作的前处理脚本中可用,并且操作样式为弹框方式,使用return false表示不继续弹窗。

同样的,在操作控制以弹框的方式显示表单,在默认操作里面使用retrun false也会阻止弹框的关闭。



36this.returnSync()

当前端调用后端服务接口需要等待返回后在执行返回操作可以使用该方法

这样的话就能够保证在前处理中请求接口数据初始化弹框的内容

var _this = this;
setTimeout(() => {
    var params = {
        obj: {
            AnimateName: 'a1'
        }
    }
    _this.openDialog(params);
}, 2000)
//弹窗的前处理脚本返回false时阻止弹窗打开,通过新增加的openDialog()脚本打开,参数与前处理脚本返回obj,query是一样的
return false;

//创建前端内存对象
let obj = this.createObj(this.className).then((res) => {
	console.log("新增内存对象oid=" + res.oid);	
	this.returnSync({obj: res})
})
console.log("新增内存对象oid=" + obj.oid);
return {sync:true}
37this.closeDialog()表单以弹窗样式打开,该方法有效,关闭当前弹窗,可以传递一个confirmData,在操作回到后处理脚本的时候,利用this.confirmData得到这个对象。

在弹框的操作脚本中调用

this.closeData({key1:'hello'})

在弹框关闭后触发的后处理脚本中通过this.confirmData获得

console.log(this.confirmData) //前端控制台输出:{key1:'hello'}
38this.openTab()

以tab页签方式打开表单,传入两个参数,queryOpr和args:

queryOpr:object,中的参数

targetClass:表示对应的类

viewName:表示需要打开的表单名称

action:动作

authority:英文名

extSettings:是否打开默认操作

args中的参数

initScript:object,与操作中的前处理脚本中return { obj:{...}, query: {...}, data: {...}} 返回的格式一致,可以设置对象,查询条件和夹带的数据

displayType:create/edit/visit


var grid=this.getAddinById("D0050C68B42743D79C646E1F8FB7D397");
obj=grid.getSelected();
let queryOpr = {
	targetClass: this.className, 
	viewName:'SingleWO',
	action: 'edit',//动作
	authority: 'hihilalal',//英文名可随意给 
	displayName: '设置的显示名',//显示名
	extSettings: JSON.stringify({needDefaultOpr:true})
}
let args = {  
	initScript:`return{
	obj:this.selectedObjs[0]
	}`,
	displayType:'edit'
}
this.openTab(queryOpr, args);
39this.closeTab()

分为不带参数和带参数两种方式。他们的功能分别是关闭tab和关闭tab传值到后处理

不带参数:this.closeTab()

带参数:this.closeTab(data)

关闭tab和关闭tab传值到后处理
//不带参数:关闭tab
this.closeTab();
//带参数:关闭tab传值到后处理
this.closeTab(data);
40this.closeTabById()

分为不带参数和带参数两种方式。他们的功能分别是关闭指定tab和指定tab关闭传值。

不带参数:this.closeTabById(id)

带参数:this.closeTabById(id, data)

页签的ID获取方式:moduleName-authority

moduleName:新建操作的时候的模块名,即打开页签的操作所在的类名

authority:打开页签操作的操作名即打开页签操作的英文名

data为回传给后处理脚本的参数,可以在后处理脚本中利用this.confirmData获取


//关闭页签
this.closeTabById('moduleName-authority');
//关闭页签并触发打开页签的后处理脚本
this.closeTabById('moduleName-authority',data);
41this.openDrawer()

支持打开滑窗的功能,规则如下:

targetClass:字符串,表示对应的类

viewName:字符串,表示需要打开的表单名称

direction:字符串,表示右滑窗还是左滑窗分成'left','right','top','buttom'四种

args:JSON对象,如果打算不传要使用null作为占位符,包含弹框的大小和高度,标题,初始化脚本和后处理脚本,具体有:

curDrawerWidth:字符串,抽屉宽度,仅对左右抽屉效果有效,取值为数值和单位的字符串,例如:'800px'

curDrawerHight:字符串,抽屉高度,仅对上下抽屉效果有效,取值为数值和单位的字符串,例如:'800px'

needDialogDefaultOpr:布尔,是否显示默认操作的按钮

displayName:字符串,弹窗以后标题的名字

initialScript:字符串,可以不传,前处理脚本

afterScript:字符串,可以不传,后处理脚本

displayType:字符串,打开方式,包含'edit', 'create', 'visit'。

initParams:JSON对象,用于完成弹窗打开前的初始化,与操作中的前处理脚本中return { obj:{...}, query: {...}, data: {...}} 返回的格式一致,可以设置对象,查询条件和夹带的数据

obj:对象,用于初始化的对象

query:字符串,默认查询条件

data:对象,外部带入的数据

如果,initialScript中初始化了返回的对象与initParams的含义冲突,以initParam里面的为准。

脚本打开滑窗
//传入初始化脚本,可以传一个对象obj,也支持query,也支持自定义内容data
let initParams = {
  obj: this.selectedObjs[0],
  data: {
    woDesc1: "cheney",
  },
};
this.openDrawer(
  this.className,
  "SingleWOTest",
  "left",
  null,
  "edit",
  initParams
);

 

42this.msgbox()

消息提示,支持三种:

this.msgbox.success
this.msgbox.info
this.msgbox.error

早期版本只接受一个字符串,后来发现有时候要停留更长时间,所以增加了输入一个配置的JSON对象的方法,这个JSON对象的具体的属性为:

content:字符串,表示消息内容

duration:数字,表示停留时间,单位为秒







//目前如下几种消息提示都是在界面上方提示后自动关闭
this.msgbox.success("成功的提示");
this.msgbox.info("一般的提示");
this.msgbox.error("错误的提示");

//特殊需求,对于提示时间需要加长的,可以参考如下写法:10 单位为秒
this.msgbox.success({content: "成功的提示",duration: 10});
this.msgbox.info({content: "一般的提示",duration: 10});
this.msgbox.error({content: "错误的提示",duration: 10});


更多的参数设置如下:

43this.msgboxDialog()

模态弹窗提示后需手动关闭的msg提示框,支持确定和取消两种回调方式,示例脚本如下:
this.msgboxDialog.confirm (
“title标题”,
"请确认是否删除?",
<function>(点击确定之后的回调函数),
<function>(点击取消之后的回调函数));

注意:comfirm有点击确定和取消的回调函数,可以自行编辑,由于使用函数作为参数,使用回调里面需要对this进行重定义,否则无法使用相关方法。


//由于使用函数作为参数,使用回调里面需要对this进行重定义,否则无法使用相关方法。
var _this = this;
this.msgboxDialog.confirm("title标题","请确认是否关闭?",
function() {
	console.log("确认关闭function");
	_this.closeDialog();
	},
function() {
	console.log("取消关闭function")   
	}
);
44this.spinShow()

表单遮罩,该脚本执行会弹出一个遮罩层,防止表单此时再去编辑

弹出遮罩

防止重复提交,数据混淆,主要用在异步请求数据接口调用的时候


this.spinShow(); //打开遮罩
this.edit(editObj, className).then(rtnObj =>{
   //返回的rtnObj为后台修改保存后返回的对象
   this.spinHide(); //编辑完成,关闭遮罩
});
45this.spinHide()关闭遮罩

事件处理完成,关闭遮罩,在异步交口调用完成后可以关闭遮罩

this.spinShow(); //打开遮罩
this.edit(editObj, className).then(rtnObj =>{
   //返回的rtnObj为后台修改保存后返回的对象
   this.spinHide(); //编辑完成,关闭遮罩
});
46this.validateForm()表单单对象控件规则校验提交保存表单之前,可以使用该脚本校验单对象控件是否满足设定的规则
// 一般性前端校验
if(this.validateForm()){
	console.log('表单验证成功')
}else{
	console.log('表单验证失败')
}
// 为了满足验重配置项的接口校验,将校验方法调整为如下:
this.validateForm().then(res=>{
	if(res){
		console.log('表单验证成功')
	}else{
		console.log('表单验证失败')
	}
});
47this.freshData()

使用原有查询条件控制表单刷新,更新数据会触发原有页面初始化事件

当数据同步被修改,可以利用this.freshData()获取到最新数据
this.freshData();
this.msgbox.info("fresh success")
48使用控件

this.getAddinById()根据控件代号获取控件对象,以便能够操作控件在表单的前端脚本中都可以获取到当前表单的控件对象
var grdiAddin = this.getAddinById("控件代号");


49this.getTargetAddin()获取控件绑定的多对象控件,这种用法不必在脚本里面使用字符串常量去得到目标控件。仅在按钮上有效,获取的是按钮绑定的多对象控件


var grid = this.getTargetAddin();
50this.getSourceAddin()获取当前操作绑定的控件,无需控件代号,避免了复用操作对应的脚本时,使用this.getAddinById必须指定字符串常量的局限性。


let addin = this.getSourceAddin();
if (addin) {
	console.log(addin.args)
}

51

this.getSocketId();

获取当前客户端的socketId

52脚本互相调用this.executeOperation()

调用并执行已有的后端脚本,支持回调

自定义操作对象(在现在的脚本中定义操作对象,无需事先定义操作)通过executeOperation进行调用

opr:定义的操作对象,包含下面的属性:

targetClass:目标类的类名

viewName:目标类中的表单名称

oprName:操作英文名

displayName: 操作中文名

displayType:动作支持create、edit、visit、next_create、url

url: 如果displayType是url需要增加这个参数来传url地址

oprStyle:操作样式dialog、tab、drawerL、 drawerR

displayOperation:默认操作 true、false

beforeExecute:表示前处理函数,代表前处理脚本

afterExecute:表示后处理函数,代表后处理脚本


可以和getOperation配合使用
//定义新的create动作的dialog样式的操作
var opr = {
    targetClass: "WorkOrder",  //目标类的类名
    viewName:"SinlgeWO"  ,//目标类中的表单名称
    oprName: "openCreatedial"  ,  //操作英文名,生造操作时可以自定义
    displayName:"创建工单" , //操作中文名 
		displayType:"create"  ,//动作支持create、edit、visit、next_create、url
    oprStyle:"dialog",   //操作样式dialog、tab、drawer
    displayOperation:true,  //默认操作 true、false
    beforeExecute:() => { //前处理函数,代表前处理脚本
        //新的前处理脚本
        return { 
         obj:this.selectedObjs[0],//选填,当前表单多对象控件选中的对象 
         //query:"and obj.woTitle = '工单1'", //选填,非必填 
         data:{ "woDesc1":"自定义属性"//选填,woDesc1是自定义的属性,
         } 
       }
    },
    afterExecute:() => {         //表示后处理函数,代表后处理脚本
        //新的后处理脚本,可根据实际情况维护
         var data = this.confirmData;
         console.log(`自定义后处理`)
         console.log(data)
    }
}
this.executeOperation(opr);
53前端脚本调用后端脚本

this.callServer().then(res => {})

完成前后端脚本的配合,传入参数并获得返回结果。

参数说明

customData:对象,调用后端脚本准备传递过去的自定义参数,JSON格式,后端脚本通过this.customData获取传递过去的参数结果。

scriptName:字符串,默认为“default”,后端脚本的脚本名称,在配置操作的时候,可以一次性新建多个后端脚本,每个后端脚本有一个英文名,传递这个英文名就意味着指示激活哪个后端脚本,也可以不传。

返回结果

callServer的调用为异步调用,如果希望从后端脚本向前端返回数据,方法是给后端脚本的this.res赋值:

res:对象,通过this.res向前端脚本传参,一般是结果。

注意

在同一个操作内编写的后端接口获取前端脚本传参可以利用this.customData获取callServer的第一个参数

返回结果需要通过this.res={}来给前端赋值回调结果

该方法属于操作内方法,调用的后端脚本仅支持在同一个操作内新建的后端脚本操作,如图:

一个操作中的前端脚本:

this.callServer(customData,'default').then(res => {
    console.log("后端回调结果");
    console.log(res.result);
})

统一操作中的后端脚本(default):

this.logger.info("前端传递给后端脚本的参数:"+this.customData);
this.res = {
	"result":"后端脚本执行成功"
}

结果:

打开console控制台,可以看到控制台输出了两行记录:

后端回调结果

后端脚本执行成功

54布局控件

showTab()


控制指定页签的显示,属于控件自身的函数标签页
var tabAddin = this.getAddinById("Tab1");
tabAddin.showTab("tab页签名称");
tabAddin.hideTab("tab页签名称");
55hideTab()控制指定页签的隐藏标签页
var tabAddin = this.getAddinById("Tab1");
tabAddin.showTab("tab页签名称");
tabAddin.hideTab("tab页签名称");
56getSelectedTab()获取Tab控件当前选中的子页签标签页
var tabAddin = this.getAddinById("Tab1");
tabAddin.getSelectedTab();
57turnTo()跳转激活子页签标签页
var tabAddin = this.getAddinById("Tab1");
tabAddin.turnTo('tab1');
58dropName()获取点击次数标签页
var dropName = ''
tabAddin.args.tabs.forEach(item => {
	if(name == item.name){
		dropName = item.dropName
	}
})
dropName = tabAddin.args.tabs[i].dropName
tabAddin.clickObj[dropName]
59导入导出按钮控件responseData

responseData:

code: 200

data: Object

allNum: 导入的数据条数

failedNum: 导入数据的失败条数

msg: "succeed"/“failed”

succeedNum: 导入数据的成功条数

message: "OK"

success: true

数据导入控件绑定数据导入完成事件


console.log('导入完成事件');
// 获取到导入接口返回的数据
let responseData = this.getSourceAddin().responseData;
console.log(responseData);
// 导入成功
if(responseData.success){
    console.log('导入成功');
    console.log(responseData.data);
    // responseData.data = {
    //     "msg": "succeed",
    //     "failedNum": 0,
    //     "succeedNum": 5,
    //     "allNum": 5
    // };
}else{
    console.log('导入失败')
}
60this.exportData(['属性名'], '类名', `查询条件`)数据导出并下载文件数据导出控件绑定点击事件
// 脚本调用数据导出方法,不传参数,以控件上设置的条件导出;有参数,就根据输入的参数导出
this.exportData(['oid'], 'echo', `and obj.oid='9948A73560B48D44AF3894FC7DF98E7E'`)
61setDisable()设置控件禁用/可用按钮、数据导入按钮、数据导出按钮、标签页
//设置标签页的页签"页签1"禁用
var tabAddin = this.getAddinById("Tab1");
tabAddin.setDisable('tab1', true);
//设置按钮禁用
var tabAddin = this.getAddinById("Operation1");
tabAddin.setDisable(true);
62单对象表单控件脚本







this.getAddinById("控件代号").getValue()获取控件取值除按钮外的单对象控件,包括:数字框、文本框、标签、富文本、选择框、单选框、复选框、对象标签。
let mySelect = this.getAddinById('SelectInput1');//绑定选择框,这个绑定的控件id需要根据自己的表单内的控件调整
let result = mySelect.getValue();
63this.getAddinById("控件代号").getDisplayValue()

获取界面显示的值,该方法仅在单选框、选择框、复选框中有效

单选框、选择框、复选框控件有效
let mySelect = this.getAddinById('SelectInput1');//绑定选择框,这个绑定的控件id需要根据自己的表单内的控件调整
let myRadio = this.getAddinById('RadioButton1');//绑定单选框,这个绑定的控件id需要根据自己的表单内的控件调整
let myCheckBox = this.getAddinById('CheckBox2');//绑定复选框,这个绑定的控件id需要根据自己的表单内的控件调整
let displayResult = mySelect.getDisplayValue();//获取选择框的界面显示值key
let result = mySelect.getValue();//获取选择框的界面显示值value
let displayRadioResult = myRadio.getDisplayValue();//获取单选框的界面显示值key
let displayCheckResult = myCheckBox.getDisplayValue();//获取复选框的界面显示值key
let result1 = myRadio.getValue();//获取单选框的界面显示值value
let result2 = myCheckBox.getValue();//获取复选框的界面显示值value
console.log('select',displayResult, result);//打印
console.log('radio',displayRadioResult,result1);
console.log('checkBox',displayCheckResult,result2);
64this.getAddinById("控件代号").setValue()给控件设置取值,并在控件上展示单对象控件
var place = this.getAddinById("CheckBox1");//绑定复选框
place.setValue('nanjing');//设置地点的值
65this.getAddinById("控件代号").args

获取控件上的其他配置参数

示例:

args.hided //控件的显示隐藏

true 隐藏

false:显示

所有控件
let myAttach = this.getAddinById('Attachments1');//绑定附件,这个绑定的控件id需要根据自己的表单内的控件调整
myAttach.args.allowType = 'jpg';//设置附件上传文件类型

//可以通过console.log查看每个控件支持的args的参数

myAttach.args.hided = true;//隐藏控件


66this.getAddinById("控件代号").triggerEvent()需要被触发的事件名称,跟中文名一样,例如:在控件的选项区中发现有:“值变化事件”,那么事件的名称即为:“值变化”
var place = this.getAddinById("CheckBox1");//绑定复选框
place.setValue('nanjing');//设置地点的值
place.triggerEvent('值变化')//触发控件上绑定的值变化事件
67this.getAddinById("控件代号").setTooltip()设置控件的鼠标悬停事件
var grid = this.getAddinById('Grid1');
var index = Math.round(Math.random() * 10)
var cellData = grid.getCellData(); //获取当前单元格数据集
var cellValue = cellData.value
var toolTipContent = `<p>${cellValue}</p>`
grid.setTooltip(toolTipContent);
68this.getAddinById("控件代号").setError()设置控件的提示信息设置信息
//控件的id可在app端开发者工具中拾取,后期可在modeler中直接拷贝
var addinElement = this.getAddinById("指定控件的id");
//设置控件在界面中的错误信息提示
addinElement.setError("存在异常");
//$el为指定控件的dom元素,可以直接对dom元素修改其样式
addinElement.$el.style.display = "none";
69this.getAddinById("控件代号").getSelected()获取选中的对象信息仅支持多对象控件,如:表格、卡片、目录树、关联结构树
var grid = this.getAddinById('Grid3');//绑定表格,这个里面是控件id,需要修改成表单内需要绑定的表格控件id
var button = this.getAddinById("Operation10");//绑定刷新按钮,这个里面是按钮的控件id,需要修改成表单内需要绑定的按钮控件id
var selectedObjs = grid.getSelected();//获取选中的对象的信息,信息包括oid,属性值等
var targetClass = 'Recordsheet';//指定要删除关联关系的关联类,这个根据自己需要改
var infoid={
	relation_oid: selectedObjs[0].relation_oid
	//获取选中对象的oid
}
var params = {
isRelation:true,
}//关联关系,这个地方可以改,当关联类和实体类没有关联的时候改成false
this.delete(infoid,targetClass,null,params).then(res => {
	button.invokeEvent("单击");//删除后执行刷新
})//删除关联类的关联关系
70this.getAddinById("控件代号").getKVValue()获取动态参数看的KV键值数据仅支持动态参数控件
//动态参数控件对象
var addin = this.getAddinById('DynamicParameterFrame1');
//获取控件全部数据(包括原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的后续处理
console.log(formValue);
console.log(formOBJ);

71

this.getAddinById("控件代号").getSelectedFileList()

点击预览事件,获得被点击的文件列表多文件上传控件
this.getAddinById("控件代号").getSelectedFileList();

72

this.getAddinById("控件代号").getDeleteFileList()

针对删除文件事件,获取已经删除的文件列表多文件上传控件


this.getAddinById("控件代号").getDeleteFileList();

73

this.getAddinById("控件代号").getFileList(withUrl:false);


获得上传成功的所有文件列表,默认不获取全部URL,withUrl为真表示获取全部Url,自动拼接好多文件上传控件
this.getAddinById("控件代号").getFileList(withUrl:false);
74多对象表单控件脚本(卡片还有特殊包含的关键字)


























setExternalOprConfig(config)

表格操作列样式设置,其中用到uniLabel、type、shape、disabled、color
show脚本设置表格样式,用来根据数据的取值来动态修改操作按钮。

表格控件
var grid = this.getAddinById('Grid2');
var operationParams = [{
    uniLabel: '修改过的编辑',//按钮文字
    type: 'warning',//按钮样式
    shape: true,//是否圆角
    disabled: true, //是否禁用
    color: 'red',//文字颜色
    show: false//按钮是否显示
},{
    uniLabel: '修改过的新增',
    type: (rowData) => {
        if(rowData.product === '草莓'){
            return 'warning'
        }else{
            return 'success'
        }
    },
    shape: (rowData) => {
        if(rowData.product === '草莓'){
            return 'circle'//圆角
        }else{
            return 'true' //直角
        }
    },//是否圆角
    disabled: (rowData) => {
        if(rowData.product === '草莓'){
            return true
        }else{
            return false
        }
    }, //是否禁用
    color: (rowData) => {
        if(rowData.product === '草莓'){
            return 'red'
        }else{
            return 'blue'
        }
    },//文字颜色
    show: (rowData) => {
        if(rowData.product === '草莓'){
            return true
        }else{
            return false
        }
    } //是否显示
}]
grid.setExternalOprConfig(operationParams);
75setRowClass

设置行样式,是一个函数,表格会遍历每行,传入名为params的参数,其中params包含:

node:表示每行的信息,如rowIndex表示行号

data:表示每行显示的JSON对象。

可设置的配置项如下:

.grid-font-color-red
.grid-font-color-yellow
.grid-font-color-green
.grid-font-color-black
.grid-font-color-white
.grid-font-color-grey
.grid-font-color-blue
.grid-background-color-red
.grid-background-color-yellow
.grid-background-color-green
.grid-background-color-black
.grid-background-color-white
.grid-background-color-grey
.grid-background-color-blue
.grid-font-size-12
.grid-font-size-14
.grid-text-decoration-underline
.grid-text-decoration-line-through
.grid-font-weight-bold
.grid-font-weight-normal

表格控件
//行样式设置
var grid = this.getAddinById('Grid3');
grid.setRowClass((params) => {
	// 间隔行效果
	if (params.node.rowIndex % 2 === 0) {
		return 'grid-font-color-red';
	}
	if (params.node.rowIndex % 2 !== 0) {
		return 'grid-font-color-green';
	}
	// 特殊数据标绿
	if (params.data.companyd === '哈哈哈1') {
		return 'grid-font-color-green';
	}
});
76setColumnDefs设置列定义表格控件
//列样式设置
var grid = this.getAddinById('Grid3');
var def = [{
	// hide: true,
	cellClass: (params) => {
		return params.value==='哈哈哈1'?'grid-text-decoration-underline grid-font-color-blue grid-font-size-14':'';
		}
}]
grid.setColumnDefs(def);
77setColumnVisible设置列可见表格控件
var grdiAddin = this.getAddinById("id");
grdiAddin.setColumnVisible(0, false)
78setRowData设置表格数据表格控件
//表格头部生成与数据结构数据操作(增删改,浏览器内存实现,不涉及数据库)
var grdiAddin = this.getAddinById("表格控件的id");
var rowData = [
        {field: 'field1', oid: 'oid1'},
        {field: 'field2', oid: 'oid2'},
...
]
//设置表格数据
grdiAddin.setRowData(rowData);
//添加表格数据
grdiAddin.setRowData(rowData, 'add');
//删除表格数据(参数对应行)
grdiAddin.deleteRowData('oid1');
grdiAddin.deleteRowData(['oid2','oid3']);
//修改表格数据(参数对应行)
grdiAddin.updateRowData('oid4', {field: 'updatefield'});


79getRowData获取表格数据表格控件
80deleteRowData删除表格数据(参数对应行)表格控件
81updateRowData修改表格数据表格控件
82getAll获取表格的所有数据表格控件


//获取表格中所有的的行数据对象集合
let workItemTable = this.getAddinById("Grid1");
var Table = workItemTable.getAll();
console.log(Table);
this.msgbox.info('Table');
83getDefaultColumnDef获取一列的默认列定义表格控件
var grid = this.getAddinById("Grid3");
var pageInfo = grid.getPageInfo(); //获取当前表格页码信息
var defaultColumnDefs1 = grid.getDefaultColumnDef({
  alignCode: 1,
  attrName: "companyd",
  editable: false,
  colId: "companyd_id",
  enableFilter: true,
  enableSorting: true,
  field: "companyd",
  headerName: "单位",
});
var defaultColumnDefs2 = grid.getDefaultColumnDef({
  alignCode: 1,
  attrName: "number",
  editable: false,
  colId: "number_id",
  enableFilter: true,
  enableSorting: true,
  field: "number",
  headerName: "数量",
});
grid.setColumnDefs([defaultColumnDefs1, defaultColumnDefs2]);
var modReq = {
  condition: "",
};
if (!pageInfo.totalPage) {
  this.dwf_axios
    .post(
      "http://192.168.31.82:9090/dwf/v1/omf/entities/recruit/objects/count",
      modReq
    )
    .then((res) => {
      if (res.data.code != 200) {
      } else {
        pageInfo.totalPage = res.data.data; //数据总数
        pageInfo.pageSize = 2; //每页条数
        pageInfo.pageIndex = 1; //当前页码
        pageInfo.pageSizeOpts = [2]; //每页条数切换的配置
        modReq = {
          condition: "",
          startIndex: pageInfo.pageIndex,
          pageSize: pageInfo.pageSize,
        };
        grid.setPageInfo(pageInfo); //设置当前表格页码信息
        this.dwf_axios
          .post(
            "http://192.168.31.82:9090/dwf/v1/omf/entities/recruit/objects",
            modReq
          )
          .then((rsp) => {
            if (rsp.data.code != 200) {
            } else {
              grid.setRowData(rsp.data.data);
            }
          });
      }
    });
} else {
  modReq = {
    condition: "",
    startIndex: pageInfo.pageIndex,
    pageSize: pageInfo.pageSize,
  };
  this.dwf_axios
    .post(
      "http://192.168.31.82:9090/dwf/v1/omf/entities/recruit/objects",
      modReq
    )
    .then((rsp) => {
      if (rsp.data.code != 200) {
        {
          var pageIndex = pageInfo.pageIndex;
          var pageSize = pageInfo.pageSize;
          grid.setRowData(rsp.data.data);
        }
      }
    });
}
84setPageInfo设置当前页码表格控件
85getPageInfo获取表格页码信息表格控件
var grid = this.getAddinById("Grid3");
var query = "";
var modReq = {
  condition: query,
};
this.dwf_axios
  .post("http://192.168.31.82:9090/dwf/v1/omf/entities/recruit/objects", modReq)
  .then((rsp) => {
    if (rsp.data.code != 200) {
    } else {
      var rowData = rsp.data.data;
      var pageInfo = grid.getPageInfo();
      grid.setRowData(
        rowData.slice(
          (pageInfo.pageIndex - 1) * pageInfo.pageSize,
          pageInfo.pageIndex * pageInfo.pageSize
        )
      );
    }
  });
86setTooltip表格单元格的鼠标悬停事件表格控件
var grid = this.getAddinById('Grid1');
var index = Math.round(Math.random() * 10)
var cellData = grid.getCellData(); //获取当前单元格数据集
var cellValue = cellData.value
var toolTipContent = `<p>${cellValue}</p>`
grid.setTooltip(toolTipContent);
87setDisplayType()

设置卡片的展示类型,支持

craete、visit、edit

卡片控件
88getSelected获取选中行数据,支持多选对象表格控件、卡片控件
var grid = this.getAddinById('Grid2');
var button = this.getAddinById("Operation3");
var selectedObjs = grid.getSelected();
console.log('getSelected',selectedObjs);
89getParentAddin获取卡片控件所在的表单卡片控件
//卡片之间值传递
var FormEngine1 = this.getAddinById("FormEngine1"); //获取卡片1控件id
var FormEngine2 = this.getAddinById("FormEngine3"); //获取卡片2控件id
var Text1InFormEngine = FormEngine1.getAddinById("TextInput1"); //获取卡片1控件中的文本框1
Text1InFormEngine.setValue(1); //为文本框1赋值为1
var FE1 = Text1InFormEngine.getParentAddin(); //获取文本框1的父控件,也就是卡片1
if (FE1) {
  var Form = FE1.getParentAddin(); //卡片1的父控件,也就是当前表单
  debugger;
  if (Form) {
    var FE2 = Form.getAddinById("FormEngine3"); //获取当前表单的卡片2
    if (FE2) {
      var TextInput1FormEngine2 = FE2.getAddinById("TextInput1"); //卡片2的文本框
      if (TextInput1FormEngine2) TextInput1FormEngine2.setValue(3); //给卡片2的文本框赋值
    }
  }
}
90updateShow刷新子表单的数据显示卡片控件
//为子表单设置对象
var FormEngine1 = this.getAddinById("FormEngine1");
let query = {condition: ` and obj.dataname = '数据111' `}; //查询条件
//开始后台数据的查询
this.handleQueryData({ queryObjReq: query, targetClass: "Asset"}).then(
  (res) => {
    //updateShow('子表单类名','子表单名',{obj:res[0]});
    FormEngine1.updateShow("Asset", "biaoqian", { obj: res[0] });
  }
);

91getRootAddin获取控件卡片控件,子表单中使用var subFormAddin = this.getRootAddin();
92freshObj(res)修改信息后刷新卡片,只是前端刷新卡片控件
this.edit(
  { product: "上海米老头", oid: "04D0D88571046C4C9EA6546FE6245784" },
  "salevalue"
).then((res) => {
  this.getSourceAddin().getParentAddin().freshObj(res);
});

93freshObj(res)关联类修改信息后刷新卡片卡片控件
var newObj = {
  relation_leftOid: "34AC734FBFB2294E852EE50B54C00831",
  relation_number: 77,
  right_partName: "螺丝",
  left_partName: "头盔",
  relation_oid: "A7EEDE6CA7AE0748BEE6B195041EB877",
  relation_rightOid: "DAFB73D0B5202941A46AC896965682BE",
};
// 假设点击的编辑按钮,在卡片的表单内部
this.edit(newObj, "PartToPart", { isRelation: true }).then((res) => {
  this.getSourceAddin().getParentAddin().freshObj(res);
});
94editNodeObj()编辑树树控件
var tree = this.getAddInByID('TreeID');
let fixObj = {
	right_uintname: "value",
}
tree.editNodeObj(fixObj, true)
95start(args)启动消息订阅订阅控件
var addin = this.getAddinById("TextInput1");
var wm = this.getAddinById('WatchMessage2');
var params = {
	data: addin.getValue()
}
wm.start(params);
96pause()暂停消息订阅订阅控件
var wm = this.getAddinById('WatchMessage2');
wm.pause();
97resume()恢复消息订阅订阅控件
var wm = this.getAddinById('WatchMessage2');
wm.resume();
98stop()停止消息订阅订阅控件
var wm = this.getAddinById('WatchMessage2');
wm.stop();
99this.param获取后端返回值,当调用后端脚本完成后,后端脚本返回的数据会存储在this.param变量中,需要的时候可以取到调用后端脚本或restful接口返回的结果存储在this.param中,当调用后该对象有值
console.log(this.param);
var label = this.getAddinById("Label1");
label.setValue(this.param.data.operationResult);
100getValue();获取查询框中控件的取值查询框


//获取查询框中的控件的2种方式:var value = this.getSourceAddin().getAddinById('parentOidEcho&2').getValue();
this.getAddinById("控件代号").getAddinById("查询框内控件的控件代号").getValue()
101freshData

获取查询框中的查询条件和

重新执行查询条件

查询框
this.getSourceAddin().getSelected('Grid1').then(res => {
	var query = res
	console.log('getselected');
	console.log(query);
	//重新执行查询事件
	this.getSourceAddin().freshData(query)
})
102freshObj支持返回结果,如改用API查询或者自定义sql查询查询框
var rowData = [
        {field: 'field1', oid: 'oid1'},
        {field: 'field2', oid: 'oid2'},
]
//更新列表数据
this.getSourceAddin().freshObj(rowData)
103可视化表单控件脚本









this.getAddinById('可视化控件代号').clickData

获取选中系列

可视化控件
let chart = this.getAddinById('EChart1');
console.log(chart.clickData)
104freshData(query)根据过滤条件更新数据多对象控件、可视化控件
//获取可视化控件
var grid = this.getAddinById("控件id");
//设置过滤条件
let query = `and obj.number = '${this.obj.number}'`;
//根据query过滤显示可视化控件
grid.freshData(query);
105freshData(extendArr, extendGrid, extendSTime, extendETime) @param extendArr 外部选择的序列集合
@param extendGrid 外部指定图表排列方式
@param extendSTime 外部指定查询起始时间
@param extendETime 外部指定查询结束时间,
时序看板
106getToolsSeries()返回当前工具栏所选全部序列时序看板
107getToolsGridType()返回当前工具栏所选图标排列方式时序看板
108getToolsStartTime()返回当前工具栏日期起始时间时序看板
109getToolsEndTime()返回当前工具栏日期结束时间时序看板
110option.legend设置图例位置可视化控件
let myChart = this.getAddinById('EchartBar1');
myChart.args.option.legend.right = 60;//可以写left ,right,top,bottom
myChart.args.option.legend.bottom = 'auto';
111编码扩展表单控件脚本HTML

超级控件扩展,支持Html和Vue两种格式

在控件内可以通过dwf_ctx调用dwf脚本引擎中的方法

获取dwf_ctx句柄的方法:

var _this = window.parent.dwf_ctx;  //获取dwf的脚本句柄

1)自定义复杂的交互逻辑,如根据设置数据自动增加可控件等

2)酷炫的可视化看板功能

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <style type="text/css">
    body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;font-family:"微软雅黑";}
    </style>
    <script type="text/javascript" src="//api.map.baidu.com/api?type=webgl&v=1.0&ak=??????"></script>
    <title>地球模式</title>
</head>
<body>
    <div id="allmap"></div>
</body>
</html>
<script type="text/javascript">
    // GL版命名空间为BMapGL
    var map = new BMapGL.Map("allmap");    // 创建Map实例
    map.centerAndZoom(new BMapGL.Point(118.5, 27.5), 5);  // 初始化地图,设置中心点坐标和地图级别
    map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放
    map.setMapType(BMAP_EARTH_MAP);      // 设置地图类型为地球模式
     
    var ctx = window.parent.dwf_ctx;
    let param = {};
    ctx.dwf_axios.post(`/omf/entities/Asset/objects`,param).then(initRes => {
      //在回调中处理
      console.log(initRes.data.data);
      let assets = initRes.data.data;
      assets.forEach(a => {
          var marker = new BMapGL.Marker(new BMapGL.Point(a.locationX, a.locationY));
          marker.asset = a; //先将标记点对应的数据绑定起来
          marker.addEventListener('click', function () {
                console.log(marker.asset);
                // 单击的时候打开对话框
                let initParams={ obj:marker.asset };
                ctx.openForm('Asset','AssetComposition',null,'visit',initParams);             
            });
          map.addOverlay(marker);
        });
    });
</script>
112VUEvue-超级控件支持Iview的组件,如需其他组件需要在服务器安装后才可以被引用,如要使用elementUI的组件库,可以预先在dwf服务器下载安装,然后才能再此处加入引用
<template>
<div>
<Button>Hello World</Button>
</div>
</template>
<script>
import { Button } from 'iview';
export default {
components: { Button },
data() {
return {
}
},
}
</script>
<style>
@import "../../node_modules/iview/dist/styles/iview.css";
</style>

65 评论

  1. 于亚杰 发表:

    使用脚本操作用户新增用户设置密码和修改密码的示例

    登录密码生成工具:

    第一步将下面代码放到全局脚本中,脚本类型为前端脚本

    function passwords(pasLen) {
    var pasArr = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9','$','%','&','@','+','!'];
    var password = '';
    var pasArrLen = pasArr.length;
    for (var i=0; i<pasLen; i++){
    var x = Math.floor(Math.random()*pasArrLen);
    password += pasArr[x];
    }
    console.log(password);
    return password;
    }
    function BASE64() {
     
        // private property
        _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
     
        // public method for encoding
        this.encode = function (input) {
            var output = "";
            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
            var i = 0;
            input = _utf8_encode(input);
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output = output +
                    _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
                    _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
            }
            return output;
        }
     
        // public method for decoding
        this.decode = function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
            while (i < input.length) {
                enc1 = _keyStr.indexOf(input.charAt(i++));
                enc2 = _keyStr.indexOf(input.charAt(i++));
                enc3 = _keyStr.indexOf(input.charAt(i++));
                enc4 = _keyStr.indexOf(input.charAt(i++));
                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;
                output = output + String.fromCharCode(chr1);
                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }
            }
            output = _utf8_decode(output);
            return output;
        }
     
        // private method for UTF-8 encoding
        _utf8_encode = function (string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";
            for (var n = 0; n < string.length; n++) {
                var c = string.charCodeAt(n);
                if (c < 128) {
                    utftext += String.fromCharCode(c);
                } else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                } else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
     
            }
            return utftext;
        }
     
        // private method for UTF-8 decoding
        _utf8_decode = function (utftext) {
            var string = "";
            var i = 0;
            var c = c1 = c2 = 0;
            while (i < utftext.length) {
                c = utftext.charCodeAt(i);
                if (c < 128) {
                    string += String.fromCharCode(c);
                    i++;
                } else if ((c > 191) && (c < 224)) {
                    c2 = utftext.charCodeAt(i + 1);
                    string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                    i += 2;
                } else {
                    c2 = utftext.charCodeAt(i + 1);
                    c3 = utftext.charCodeAt(i + 2);
                    string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                    i += 3;
                }
            }
            return string;
        }
    }

    第二步:生成密码并调用接口创建用户或者修改密码

    var base = new BASE64();
    var password = passwords(3) + base.encode("11111111") + passwords(5)
    
    //调用新增用户接口
    var param = [{
      "comment": "string",
      "displayName": "张三002",
      "email": "aa@11.com",
      "name": "zhangsan002",
      "groupIds": [
        "941BBC3A90ADB44D943E8E7018C77DDD"
      ],
      "oid": "94F50B9435DE4E4686597AC39541493B",
      "password": password
    }];
    var url = Config.baseUrl;
    if(url == undefined){
        url = `${Config.modelerApiBase}/dwf/v1`;
    }
    this.dwf_axios.post(`${url}/org/users-create`,param).then(function (res) {
     //TODO 请求成功,res为返回结果 
     console.log(res); 
     alert("新增用户成功!");
    }).catch(function (error) {
     //TODO 请求失败,失败信息 error
     console.log(error);
    });
     
    //调用修改密码接口
    var param1 = {
      "comment": "string",
      "displayName": "张三001",
      "email": "aa@11.com",
      "groupIds": [
        "941BBC3A90ADB44D943E8E7018C77DDD"
      ],
      "name": "zhangsan001",
      "oid": "94F50B9435DE4E4686597AC39541493B",
      "password": password
    }
    var url = Config.baseUrl;
    if(url == undefined){
        url = `${Config.modelerApiBase}/dwf/v1`;
    } 
    this.dwf_axios.post(`${url}/org/users-update`,param1).then(function (res) {
     //TODO 请求成功,res为返回结果 
     console.log(res); 
     alert("密码修改成功");
    }).catch(function (error) {
     //TODO 请求失败,失败信息 error
     console.log(error);
    });
  2. 于亚杰 发表:

    表格控件功能扩展(脚本放到表格的初始化事件中【前端脚本】)

    (一)在单元格中根据多个属性的对比计算展示不同颜色

    var grid = this.getSourceAddin();
    console.log(grid.gridApi.getRowNode(0));
    grid.args.columnDefs[2].hide = true;
    grid.args.columnDefs[2].cellClass = (params) => { 
    //params.node.data可以获取到当前行的所有数据
    if( params.value > params.node.data.dierzhou2 && params.value < params.node.data.disizhou){
        console.log(params.node.data.dierzhou2);
        console.log(params.node.data.disizhou);
        return ' grid-background-color-yellow';
    }
    else
    {
        return '';
    }
    }
    

    (二)在单元格中根据属性取值显示图片或超链接

    var grid = this.getSourceAddin();
    grid.args.columnDefs[2].cellRenderer = (params) => {
      let array = params.value;
        if( params.value > params.node.data.dierzhou2 && params.value < params.node.data.disizhou){
            console.log(params.node.data.dierzhou2);
        console.log(params.node.data.disizhou);
              var cellView = "<span><img src='http://www.xinhuanet.com/photo/2018-07/18/1123141280_15318734471611n.jpg' width='30px' height = '30px'></span><span align='center' valign='middle'>" + params.value +"</span>";
      return cellView;
        }
        else
        {
              var cellView = "<span><img src='http://www.xinhuanet.com/photo/2018-07/18/1123141280_15318734471521n.jpg' width='30px' height = '30px'></span><span align='center' valign='middle'>" + params.value +"</span>";
      return cellView;
        }
    }


    (三)设置多级表头


    var grid = this.getSourceAddin();
         //定义表格列
            var columnDefs = [
                {
                    headerName: '分组A',
                    children: [
                        grid.args.columnDefs[0],
                       grid.args.columnDefs[1],
                    ]
                },
                {
                    headerName: '分组B',
                    children: [grid.args.columnDefs[2],
                    grid.args.columnDefs[3],
                    grid.args.columnDefs[4],
                    grid.args.columnDefs[5]
                    ]
                }
            ];
    grid.setColumnDefs(columnDefs);

    (四)设置表头行高和表头文字换行显示

    grid.gridOptions.api.setGroupHeaderHeight(50);
    grid.gridOptions.api.setHeaderHeight(50);
    setTimeout(function() { 
        let columnsHeader = document.querySelectorAll('.customHeaderLabel');
        for(let i = 0; i<columnsHeader.length;i++){
            columnsHeader[i].style.whiteSpace = 'normal';
        } 
    }, 1500);

    (五)通过接口后去数据给表格赋值并展示

    var grid = this.getAddinById("Grid1");
    console.log(grid);
    var pageInfo = grid.getPageInfo();
    console.log(pageInfo);
    var defaultColumnDefs1 = grid.getDefaultColumnDef({
        alignCode: 1,
        attrName: "companyd",
        editable: false,
        colId: "companyd_id",
        enableFilter: true,
        enableSorting: true,
        field: "companyd",
        headerName: "单位"
    });
    var defaultColumnDefs2 = grid.getDefaultColumnDef({
        alignCode: 1,
        attrName: "number",
        editable: false,
        colId: "number_id",
        enableFilter: true,
        enableSorting: true,
        field: "number",
        headerName: "数量"
    });
    grid.setColumnDefs([defaultColumnDefs1, defaultColumnDefs2]);
    pageInfo.totalPage =2;//数据总数
    pageInfo.pageSize = 1;//每页条数
    pageInfo.pageIndex = 1;//当前页码
    pageInfo.pageSizeOpts = [1,2,3]//每页条数切换的配置
    grid.setPageInfo(pageInfo);
    var data = [];
    var obj1 = {companyd:"第一行第一列",number:"第一行第二列"};
    var obj2 = {companyd:"第二行第一列",number:"第二行第二列"};
    data.push(obj1);
    // data.push(obj2);
    grid.setRowData(data)

    (六)表格动态修改翻页配置,并且设置翻页页码

     

    (七)根据数据设置操作列的禁用启用,放到表格的初始化脚本里面

    var grid = this.getAddinById("Grid1");
    var columnDefs = grid.args.columnDefs;
    var operationParams = [];
    for(let j = 0; j < columnDefs.length;j++){
        let colDef = columnDefs[j];
        if(colDef.colId == "_oprColumn"){
            operationParams = colDef.operationParams;
            break;
        }
    }
    
    operationParams = grid.args.columnDefs[2].operationParams; //获取到操作列 
    for(let i = 0; i < operationParams.length; i++){
        let oprParam = operationParams[i];
        oprParam.disabled = (rowData) => {   //注意这里面的rowData就是当前渲染的时候的行数据
            if(rowData.name === '新增' && oprParam.text == "新增" ){
                return true
            }else{
                return false
            }
        };
    }
    grid.setExternalOprConfig(columnDefs);

    操作列支持的更多的配置项如下:

    //以下注释是操作列支持的配置项
    //  var operationParams = [{
    //     uniLabel: '修改过的编辑',//按钮文字
    //     type: 'warning',//按钮样式
    //     shape: true,//是否圆角
    //     disabled: true, //是否禁用
    //     color: 'red',//文字颜色
    //     show: false//按钮是否显示
    // },{
    //     uniLabel: '修改过的新增',
    //     type: (rowData) => {
    //         if(rowData.product === '草莓'){
    //             return 'warning'
    //         }else{
    //             return 'success'
    //         }
    //     },
    //     shape: (rowData) => {
    //         if(rowData.product === '草莓'){
    //             return 'circle'//圆角
    //         }else{
    //             return 'true' //直角
    //         }
    //     },//是否圆角
    //     disabled: (rowData) => {
    //         if(rowData.product === '草莓'){
    //             return true
    //         }else{
    //             return false
    //         }
    //     }, //是否禁用
    //     color: (rowData) => {
    //         if(rowData.product === '草莓'){
    //             return 'red'
    //         }else{
    //             return 'blue'
    //         }
    //     },//文字颜色
    //     show: (rowData) => {
    //         if(rowData.product === '草莓'){
    //             return true
    //         }else{
    //             return false
    //         }
    //     } //是否显示
    // }]
     
    1. 于亚杰 发表:

      已有操作列+自定义列组合

      var grid = this.getAddinById("Grid1");
      var colOpr = grid.args.columnDefs[0];
      console.log(grid.args.columnDefs);
      var defaultColumnDefs1 = grid.getDefaultColumnDef({
      alignCode: 1,
      attrName: "companyd",
      editable: false,
      colId: "companyd_id",
      enableFilter: true,
      enableSorting: true,
      field: "companyd",
      headerName: "单位"
      });
      var defaultColumnDefs2 = grid.getDefaultColumnDef({
      alignCode: 1,
      attrName: "number",
      editable: false,
      colId: "number_id",
      enableFilter: true,
      enableSorting: true,
      field: "number",
      headerName: "数量"
      });
      var columnDefs = [];
      columnDefs.push(defaultColumnDefs1);
      columnDefs.push(defaultColumnDefs2);
      columnDefs.push(colOpr);
        
      columnDefs.push(colOpr);
      console.log("columnDefs");
      console.log(columnDefs);
      grid.setColumnDefs(columnDefs);


    2. 于亚杰 发表:

      给指定行的某一列属性更改取值,该列如果设置有引用类的情况下,需要将显示值也设置上即可:


      Grid1.updateRowData('2774F71556137C45B1CD5C02839629E5', {String: "44","label%ref%String": "√√"});

  3. 于亚杰 发表:

    可视化控件单击系列获取选中系列取值

    var pie = this.getAddinById("PieChart1");
    console.log(pie.clickData); //注意这个clickData就是选中的系列的数据
    var clickData = pie.clickData;
    if(clickData.carID == '京R3179'){
        console.log(clickData.carID);
        var targetClass = 'TyWork';
        var viewName = 'test';
        var args = {};  //args是{ conditionExpre: 查询条件, params: 初始化脚本 },如果没有args可以传空
        this.openForm(targetClass, viewName, args);
    }
    if(clickData.carID == '津QE984'){
        console.log(clickData.carID);
        var targetClass = 'TyWork';
        var viewName = 't12';
        var args = {};  //args是{ conditionExpre: 查询条件, params: 初始化脚本 },如果没有args可以传空
        this.openForm(targetClass, viewName, args);
    }



  4. 于亚杰 发表:

    通过接口动态给复选框、单选框、下拉框的选项赋值,同时这是默认选中值,示例代码如下:

    let check = this.getAddinById('CheckBox1');
    check.args.list=[
    	{
    		value: '1',
    		label: '男'
    	}, 
    	{
    		value: '2',
    		label: '女'
    	}, 
    	{
    		value: '3',
    		label: '不男不女'
    	}
    ]
    setTimeout(function() { //加上一个100毫秒的延迟是为了能够让下拉选项生效后赋值可以正常显示数据
    	check.setValue('1');
    },100)
  5. 于亚杰 发表:

    目录点选控件,通过脚本给目录点选控件赋值并触发目录点选控件根据赋值显示对应数据

    var tree = this.getAddinById("JoinCascaderTree1");
    console.log(tree.getValue());
    // tree.setValue('1FD1E0270EAC0A44AC1EE9BE30A23E57');// 18BDFEF4A55B444C9702EC3D675134ED
    tree.temCasData = ['1FD1E0270EAC0A44AC1EE9BE30A23E57'];
    tree.updateTree();
    console.log(tree.getValue());
  6. 于亚杰 发表:

    弹窗的前处理脚本中,通过接口请求数据,返回数据后再跳转弹窗表单

    异步调用数据处理后返回:
    
    var data ;
    
    //TODO: 加工处理要传递的data
    
    this.aixos.get/put/post().success( ()=> {   //后端restful API异步调用
    
     this.returnSync(data);
    
    });
    
    return {"sync":true}   //表示手动弹出新窗口
    
    
    
    1. 钟广友 发表:

      如果无异步调用,使用return false表示不继续弹窗;

  7. 于亚杰 发表:

    属性规则授权配合对象授权规则,让用户拥有查看本组以及查看本组及下级组的规则,示例属性规则如下:

    1)查看本组用户创建的数据:SELECT l.plt_leftoid as userId ,r.plt_leftoid as objId FROM plt_org_r_user2group l FULL OUTER JOIN plt_org_r_user2group r ON l.plt_rightoid = r.plt_rightoid
    
    2)查看自己创建的数据:select plt_oid as userId ,plt_oid as objId from plt_org_user
    
    
    
    
    
  8. 于亚杰 发表:

    编码扩展HTML (超级控件)中与页面进行交互的两种方式

    var _this = window.parent.dwf_ctx;  //获取到超级控件所在表单句柄
    //第一种操作方式,通过按钮点击事件触发,触发执行表单中的前端脚本操作
    var btn = _this.getAddinById("Operation1");
    btn.invokeEvent("单击");
    //第二种操作方式,通过executeOperation调用后端脚本
     
    _this.getOperation('SuperHtmlCallOpr''serverScriptOpr').then(res => {
        var opr = res.data.data;   
        console.log("通过getOperation获取到已有的操作");
        console.log(opr);
        debugger
        var param1 = new Object();
        _this.executeOperation(opr, param1).then(end => {
            console.log(end);
        });
    });

  9. 于亚杰 发表:

    在使用树控件的时候,会碰到由于数据量很大导致树加载特别慢,树的配置增加了懒加载的功能可以有效解决这个问题,但又带来了另外一个问题就是在弹窗编辑树节点的时候需要再次刷新树控件,这个时候由于编辑的节点层级比较深,所以刷新的时候懒加载就已经失去了意义会刷新到当前展开的节点的层次导致树非常慢,为了解决这个问题可以利用树的局部刷新的方式只刷新当前节点,该方法是根据当前选中节点所在的父节点重新加载父节点以下一层的数据,使用方法如下:

    tree.freshData(''truetrue, newRtnObj, 'edit');//前三个参数保持不变,第四个参数newRtnObj是要新增的节点对象,第五个参数为当前操作状态可选的为create或edit

    1. 于亚杰 发表:

      //根据选中节点加载下级节点数据

      let myTree = this.getAddinById('RelationTree1');
      console.log(myTree.clickData);
      myTree.loadSelfData(myTree.clickData)

  10. 于亚杰 发表:

    前端引入第三方依赖库或者自定义的全局方法在脚本或者页面中使用到

    在DWF中如何扩展引用第三方依赖库并能在前端脚本中访问。与全局脚本的区别在于可以在任何脚本中都可以访问到,可以实现参数的传递,相当于定义真正的全局变量或者方法,有了这个方法可以有更多的方式加持DWF的能力
    使用方法:
    1)功能模型-->应用管理-->选中要添加第三方库依赖的应用
    2)找到自定义脚本文件,输入如下脚本,注意XXXXX部分换成自己希望的依赖库


    function appendJQCDN(src) {
        var head = document.head || document.getElementsByTagName('head')[0];
        if(src.indexOf("js")== -1){ //css
            var style = document.createElement('style');
            style.setAttribute("rel", "stylesheet"); 
            style.setAttribute("href",src);
            head.appendChild(style);
        }else{
            var script = document.createElement('script');
            script.type = "text/javascript";
            script.setAttribute("src",src);
            head.appendChild(script);
        }
    }
    //appendJQCDN("http://192.168.31.82:8180/code/test.js");
    appendJQCDN("XXXXX");  //此处的XXXXX 替换为用户自己的库或者公共库如JQuery等
    
    
    //test.js中的代码如下:
    var CCCC = "123456";
    function test()
    {
      alert(3333)
    }


    3)在操作事件中使用

    //直接使用test方法
    test();
    //输出全局变量CCCC,并更改CCCC的取值
    alert(CCCC);
    CCCC = "4t4t4t4t4";
    //更改全局变量CCCC取值后验证结果
    alert(CCCC);
  11. 于亚杰 发表:

    选择框属性联动功能

    拖入三个选择框,第一个为省份(控件ID:SelectInput1)、第二个为城市(控件ID:SelectInput2)、第三个为区县(控件ID:SelectInput3)
    这三个选择框都配置引用类为行政区划、浏览自动为城市名称、回填字段为全局唯一标识,
    省份字段配置过滤条件为:and obj.parentOid is null or  obj.parentOid = '' order by  obj.paixu
    城市控件配置过滤条件为:and obj.parentOid = '$form["SelectInput1"]'
    区县控件配置过滤条件为:and obj.parentOid = '$form["SelectInput2"]'

    控件联动脚本如下:


    1)省份选择框增加值变化事件
    var SelectInput2 = this.getAddinById("SelectInput2");
    SelectInput2.combineObjData();
    2)城市变化增加值变化事件
    var SelectInput3 = this.getAddinById("SelectInput3");
    SelectInput3.combineObjData();



  12. 于亚杰 发表:

    URL配置技巧:

    如果操作配置选择的是外部连接URL方式,脚本内容中可以修改打开的URL的地址。

    如:url地址配置的为:http://www.baidu.com

    可以再脚本中写一个脚本替换需要打开的url地址,这块主要是解决动态配置打开地址传参

    写法如下:

    return {

         "url":"http://www.baidu.com"

    }

  13. 于亚杰 发表:

    给动态地图控件设置中心点位置


    var DynamicMap4this.getAddinById("DynamicMap4")
        var objs = DynamicMap4.getAll();
        if(objs.length > 0){
            var obj = objs[0];
            var map = DynamicMap4.map;
            console.log(map);
            var point = new BMap.Point(obj.longitude,obj.latitude);  // 创建点坐标  
            map.centerAndZoom(point, 8);              
        }



  14. 于亚杰 发表:

    表格的鼠标悬停事件给指定列设置示例脚本如下:

    var grid = this.getAddinById('Grid1');
    var cellData = grid.getCellData(); //获取当前单元格数据集
    var cellValue = cellData.value
    var toolTipContent = `<p>${cellValue}</p>`
    if(cellData.colDef.attrName == "typeofapplication"){  //此处可以判断是哪一列,对需要显示tooltip的列可以设置其他列不设置
        grid.setTooltip(toolTipContent);
    }
  15. 于亚杰 发表:

    已有的图片利用上传文件控件进行展示

    var fujian1 = this.getAddinById("Attachments1");
    console.log(fujian1);
    var fujian2 = this.getAddinById("Attachments2");
    console.log(fujian2);
    var fileUrl = fujian1.fileUrl;
    var stash_id = fujian1.stash_id;
    var uploadUrl = fujian1.uploadUrl;
    console.log(fileUrl);
    console.log(stash_id);
    fujian2.fileUrl = fileUrl;  //这个是是设置显示图片的路径
    fujian2.stash_id = stash_id; //这个是设置stash_id的
    fujian2.uploadUrl = uploadUrl; //这个是设置上传图片接口的
    fujian2.file_exists = true; //设置文件已存在以展示形式存在
    console.log("========");
    console.log(fujian2);
  16. 于亚杰 发表:

    创建态上传附件在后端脚本中对上传附件进行处理,实现方式:

    1. 编写前端脚本,通过调用this.executeOperation的方式将附件的临时ID传递到后端脚本
    2. 编写后端脚本,通过this.customData获取前端传递的参数,然后根据stashId获取文件信息

    示例

    前端脚本:
    
    this.getOperation('recruit', 'test11111').then(res => {
        var opr = res.data.data;
        var Attachments1 = this.getSourceAddin();
        var stash_id = Attachments1.stash_id;
        var param1 = new Object();
        param1.stashid=stash_id;
        this.executeOperation(opr, param1).then(end => {
            console.log(end);
        });
    });
    
    后端脚本:
    
    this.logger.info("========" + this.customData);
    var stashId = this.customData.stashid;
    if(stashId){
        var imgString = this.omf.getString(stashId,this.className,"text");
        this.logger.info("imgString");
        this.logger.info(imgString);
    }


    后端脚本中还可以使用的获取文件的方法:

    this.omf.getFilePath(oid, className, attrName); //返回文件在服务存储的绝对路径

    this.omf.getByteArray(oid, className, attrName);//返回二进制流

  17. 于亚杰 发表:

    超级控件使用技巧:

    目标:利用超级控件封装一个在DWF中可以直接使用的控件,即超级控件中实现的功能逻辑可以被表单上的其他控件事件调用

    实现方法:

    第一步:

    在超级控件中通过JS封装一个方法赋值给表单引擎,示例语法如下:

    window.parent.function1 = function(){
      var h = editor.txt.html();
      return h;
    }

    完整示例代码:




    <html>
    <head>
    	<meta charset="utf-8">	
      <script src="https://cdn.jsdelivr.net/npm/wangeditor@latest/dist/wangEditor.min.js"></script>
    </head>
    <body>
    
    <div id="toolbar-container" class="toolbar" ></div>
    
    <div id="text-container" class="text"></div>
    <script>
    
      const E = window.wangEditor
      const editor = new E('#toolbar-container', '#text-container') // 传入两个元素
      editor.create()
    window.parent.getHtml = function(){
      var h = editor.txt.html();
      return h;
    }
    </script>
    
    </body>
    </html>




    第二步:

    在表单中通过按钮执行超级控件中的方法获取到返回值

    var html = window.getHtml();
    console.log(html);



  18. 于亚杰 发表:

    应用端增加水印的能力,添加方法放到应用端的自定义脚本中

    function watermark(settings) {
        //默认设置
        var defaultSettings = {
            watermark_txt: "text",
            watermark_x: 20, //水印起始位置x轴坐标
            watermark_y: 20, //水印起始位置Y轴坐标
            watermark_rows: 20, //水印行数
            watermark_cols: 20, //水印列数
            watermark_x_space: 100, //水印x轴间隔
            watermark_y_space: 50, //水印y轴间隔
            watermark_color: '#aaa', //水印字体颜色
            watermark_alpha: 0.4, //水印透明度
            watermark_fontsize: '15px', //水印字体大小
            watermark_font: '微软雅黑', //水印字体
            watermark_width: 210, //水印宽度
            watermark_height: 80, //水印长度
            watermark_angle: 20 //水印倾斜度数
        };
        if (arguments.length === 1 && typeof arguments[0] === "object") {
            var src = arguments[0] || {};
            for (key in src) {
                if (src[key] && defaultSettings[key] && src[key] === defaultSettings[key]) continue;
                else if (src[key]) defaultSettings[key] = src[key];
            }
        }
        var oTemp = document.createDocumentFragment();
        //获取页面最大宽度
        var page_width = Math.max(document.body.scrollWidth, document.body.clientWidth);
        var cutWidth = page_width * 0.0150;
        var page_width = page_width - cutWidth;
        //获取页面最大高度
        var page_height = Math.max(document.body.scrollHeight, document.body.clientHeight) + 450;
        page_height = Math.max(page_height, window.innerHeight - 30);
        //如果将水印列数设置为0,或水印列数设置过大,超过页面最大宽度,则重新计算水印列数和水印x轴间隔
        if (defaultSettings.watermark_cols == 0 || (parseInt(defaultSettings.watermark_x + defaultSettings.watermark_width * defaultSettings.watermark_cols + defaultSettings.watermark_x_space * (defaultSettings.watermark_cols - 1)) > page_width)) {
            defaultSettings.watermark_cols = parseInt((page_width - defaultSettings.watermark_x + defaultSettings.watermark_x_space) / (defaultSettings.watermark_width + defaultSettings.watermark_x_space));
            defaultSettings.watermark_x_space = parseInt((page_width - defaultSettings.watermark_x - defaultSettings.watermark_width * defaultSettings.watermark_cols) / (defaultSettings.watermark_cols - 1));
        }
        //如果将水印行数设置为0,或水印行数设置过大,超过页面最大长度,则重新计算水印行数和水印y轴间隔
        if (defaultSettings.watermark_rows == 0 || (parseInt(defaultSettings.watermark_y + defaultSettings.watermark_height * defaultSettings.watermark_rows + defaultSettings.watermark_y_space * (defaultSettings.watermark_rows - 1)) > page_height)) {
            defaultSettings.watermark_rows = parseInt((defaultSettings.watermark_y_space + page_height - defaultSettings.watermark_y) / (defaultSettings.watermark_height + defaultSettings.watermark_y_space));
            defaultSettings.watermark_y_space = parseInt(((page_height - defaultSettings.watermark_y) - defaultSettings.watermark_height * defaultSettings.watermark_rows) / (defaultSettings.watermark_rows - 1));
        }
        var x;
        var y;
        for (var i = 0; i < defaultSettings.watermark_rows; i++) {
            y = defaultSettings.watermark_y + (defaultSettings.watermark_y_space + defaultSettings.watermark_height) * i;
            for (var j = 0; j < defaultSettings.watermark_cols; j++) {
                x = defaultSettings.watermark_x + (defaultSettings.watermark_width + defaultSettings.watermark_x_space) * j;
                var mask_div = document.createElement('div');
                mask_div.id = 'mask_div' + i + j;
                mask_div.className = 'mask_div';
                mask_div.appendChild(document.createTextNode(defaultSettings.watermark_txt));
                //设置水印div倾斜显示
                mask_div.style.webkitTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                mask_div.style.MozTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                mask_div.style.msTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                mask_div.style.OTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                mask_div.style.transform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
                mask_div.style.visibility = "";
                mask_div.style.position = "absolute";
                mask_div.style.left = x + 'px';
                mask_div.style.top = y + 'px';
                mask_div.style.overflow = "hidden";
                mask_div.style.zIndex = "9999";
                //让水印不遮挡页面的点击事件
                mask_div.style.pointerEvents = 'none';
                mask_div.style.opacity = defaultSettings.watermark_alpha;
                mask_div.style.fontSize = defaultSettings.watermark_fontsize;
                mask_div.style.fontFamily = defaultSettings.watermark_font;
                mask_div.style.color = defaultSettings.watermark_color;
                mask_div.style.textAlign = "center";
                mask_div.style.width = defaultSettings.watermark_width + 'px';
                mask_div.style.height = defaultSettings.watermark_height + 'px';
                mask_div.style.display = "block";
                oTemp.appendChild(mask_div);
            };
        };
        document.body.appendChild(oTemp);
    }
    
    function getNow() {
        var d = new Date();
        var year = d.getFullYear();
        var month = change(d.getMonth() + 1);
        var day = change(d.getDate());
        var hour = change(d.getHours());
        var minute = change(d.getMinutes());
        var second = change(d.getSeconds());
    
        function change(t) {
            if (t < 10) {
                return "0" + t;
            } else {
                return t;
            }
        }
        var time = year + '年' + month + '月' + day + '日 ' + hour + '时' + minute + '分' + second + '秒';
        return time;
    }
    
    var now = getNow();
    watermark({"watermark_txt":"A B C X Y Z "+now});
  19. 于亚杰 发表:

    对于控件不支持修改的样式,可以通过如下方式对某个控件进行修改

    var multiFilesList1 = this.getAddinById('MultiFilesList1');
    setTimeout(() => {
        multiFilesList1.$el.querySelector('.ivu-table-wrapper').style.height = '500px';
        multiFilesList1.$el.querySelector('.ivu-table-body').style.height = '500px';
    }, 200)
  20. 于亚杰 发表:

    前端脚本,通过点击事件跳转到对应控件位置

    var CompoundLabel10 = this.getAddinById("CompoundLabel10"); //第一步 获取到控件
    CompoundLabel10.$el.scrollIntoView(); //通过$el获取到控件的dom元素,然后利用scrollIntoView()的方法跳转到对应控件
  21. 于亚杰 发表:

    导出表格展示的数据(通过接口导出)

    var grid1 = this.getAddinById("Grid1");
    var objs = grid1.getAll();
    //var condition = grid1.lastQuery.replace("and obj.key is null","");   //此处的lastQuery无效了
    
    var condition = grid1.queryData.query.query.replace("and obj.key is null","");
    if(objs.length > 0){
        var url = Config.modelerApiBase+ "/exportData/exportData?classname=DataDict&attributes=type,key,label,desc,order&joinToOneSheet=false&condition=" + encodeURIComponent(condition);
        window.open(url);
    }
    else{
        alert("没有需要导出的数据字典内容!")
    }
    
    
    
    
    
    


    对于2022年10月份之后版本对导出接口做了限制,增加了权限校验导出方法可以参考如下:

    var grid1 = this.getAddinById("Grid1");
    var objs = grid1.getAll();
    //var condition = grid1.lastQuery.replace("and obj.key is null","");   //此处的lastQuery无效了
    
    var condition = grid1.queryData.query.query.replace("and obj.key is null","");
    if(objs.length > 0){
        var url = Config.modelerApiBase+ "/exportData/exportData?classname=DataDict&attributes=type,key,label,desc,order&joinToOneSheet=false&condition=" + encodeURIComponent(condition);
        var xhr = new XMLHttpRequest();
    	xhr.open('get', url);
    	xhr.responseType="blob";
    	var token = this.user.token;
    	xhr.setRequestHeader('authorization', token);
    	xhr.onload = function (e) {    
            var contentType = xhr.getResponseHeader("content-type");  
            var blob = new Blob([this.response], { type: contentType });
            if (this.status == 200) {       
                var filename = "TaskInstance.xlsx"; //要导出的文件名,允许用户自定义
                var a = document.createElement('a');
                var urlTemp = URL.createObjectURL(blob);
                a.href = urlTemp;
                a.download = filename;
                document.body.appendChild(a);
                a.click();
                window.URL.revokeObjectURL(urlTemp);
            }
        };
        xhr.send();
    }
    else{
        alert("没有需要导出的数据字典内容!")
    }





    1. 钟广友 发表:

      树控件树节点默认选中样式处理:

      let selfTree = this.getAddinById('SelfJoinsTree1'); selfTree.clickData = selfTree.args.treeList[2];

    2. 钟广友 发表:

      多对象卡片控件能力增强
      • addRowData(param,index):param可以是一个对象,也可以是一个对象数组,给卡片增加一个或多个元素 ,index为非必填项,默认不填写只有param参数,则追加的元素都在卡片的最后面,如果设置了index会以卡片中元素顺序插入,比如index设置为0则在最前面插入元素,此处的插入仅仅是界面上插入,不会插入到数据,该方法仅对卡片多对象展示的模式下有效
      • updateRowData(param):param可以是一个对象,也可以是一个对象数组,根据param中的数据查找oid相同的数据进行更新,未匹配上的数据则不处理,此处的更新仅仅是更新当前显示,不涉及数据库中的修改
      • deleteRowData(param):param可以是一个字符串,也可以是一个字符串数组,这个删除是按照oid进行删除,这里的删除,只是显示界面上的移除元素,不涉及数据库层面的删除,该方法仅对卡片多对象展示的模式下有效
      • setRowData(param):param可以是一个对象,也可以是一个对象数组,清空当前卡片的内容,以param为准,加载内容
      • getRowData(param):根据oid获取对象数组,param为oid,可以是一个oid字符串,也可以是oid数组,返回是对象数组
      • getAll():获取卡片当前显示的所有对象数组
      1. 钟广友 发表:

        //生成32位UUID方法

        function uuid() {
        var s = [];
        var hexDigits = "0123456789abcdef";
        for (var i = 0; i < 32; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23];
        var uuid = s.join("");
        return uuid;
        }

    3. 钟广友 发表:

      “任务执行”控件样式处理脚本:

      this.getAddinById(`userTaskExecutionControlMobile1`).vDom.args.disabled = true;  //是否禁用;

      this.getAddinById(`userTaskExecutionControlMobile1`).vDom.args.hided = true;      //是否隐藏;

    4. 钟广友 发表:

      //弹窗(创建内存对象)关闭后,插入主对象表单中“从对象的(内存)多对象卡片”中;

      this.closeDialog(rtnOBJ);//弹窗关闭脚本中回传数据rtnOBJ;

      var newOBJ = this.confirmData; //在“新建弹窗”操作的后处理事件中,获取弹窗关闭回传的数据(即rtnOBJ);

      newOBJ.oid = getUUID(); //需补充oid属性,方便后续的内存对象定位后的编辑与删除操作!

      var formEngine1 = this.getAddinById('FormEngine1'); //内存多对象卡片

      formEngine1,addRowData(newOBJ); //插入新增内存对象;


      //主对象表单中“从对象的(内存)多对象卡片”中删除内存对象【在卡片子表单的“删除”按钮操作脚本】

      var formEngine1 = this.getRootAddin().getAddinById('FormEngine1'); //卡片子表单脚本中获取卡片对象;

      formEngine1.deleteRowData(this.obj.oid); //删除内存卡片中的对象行;

    5. 钟广友 发表:

      前端Excel数据导出
      debugger
      let grid = this.getAddinById("Grid1");
      let objs = grid.getAll(); //这里的所有数据通过后端脚本获取
      let company = this.getAddinById("SelectInput1").getDisplayValue();
      const fields = {
        plt_oid: '用户Id',
        plt_displayname: '姓名',
        plt_name: '手机号',
        plt_email: '登录数',
        plt_password: '阅读数',
        plt_comment: '企业'
      }
      // 拼接标题行
      const head = Object.values(fields).map(item => {
        return `<td>${item}</td>`
      }).join('')
      // 拼接数据行
      const body = objs.map(item => {
        /* eslint-disable-next-line */
        let res = `<tr style="mso-number-format:'\@';">` // 为了不让表格显示科学计数法
        for (const key in fields) {
          res += `<td>${item[key] != undefined ? item[key] : ''}</td>`
        }
        return res + '</tr>'
      }).join('')
      
      // Worksheet名
      const worksheet = 'Sheet1'
      const uri = 'data:application/vnd.ms-excel;base64,'
      
      // 下载的表格模板数据
      const template = `<html xmlns:o="urn:schemas-microsoft-com:office:office"
        xmlns:x="urn:schemas-microsoft-com:office:excel"
        xmlns="http://www.w3.org/TR/REC-html40">
        <head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
        <x:Name>${worksheet}</x:Name>
        <x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>
        </x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
        </head><body><table><tr>${head}</tr>${body}</table></body></html>`
      // 下载模板
      let link = document.createElement('a')
      link.setAttribute('href', uri + window.btoa(unescape(encodeURIComponent(template))))
      link.setAttribute('download', company+'.xls');
      link.click();
      link = null;
      
      
  22. 钟广友 发表:

    样式模板补充说明(待完善)

  23. 于亚杰 发表:

    表格控件设置某列背景的关键字支持$row和$cell两个

    $row 表示某一行的对象 

    $cell 表示某一个单元格 也就是当前列配置对应的某一行的某一列单元格 

    列背景设置表达式如下:

    '$row.company' === '美术'      这个表示company这一个属性取值为美术的设置某种颜色

    '$cell' === '美术'   这个表示当前列取值为美术的设置某种颜色

    1. 钟广友 发表:

      也可通过$row变量设置grid表格的操作列是否可见与可用:

      如:'$row.status' != '1' && '$row.status' != '2'  //操作列某操作可见或可用

  24. 刘英博 发表:

    this.handleQueryBySQL({"condition": "select plt_name as 姓名 from plt_org_user "}).then(res => {
        console.log(res);
    });
    res.data.data.head是表头,res.data.data.data是内容

  25. 于亚杰 发表:

    按照表格的配置导出数据

    1)表格展示的属性

    2)表格的过滤条件

    3)表格绑定的类

    示例代码如下:

    var Grid1 = this.getAddinById("Grid1");
    console.log(Grid1);
    var attrs = Grid1.args.columnDefs;
    var result = [];
    attrs.forEach( (item , index ) => {
        if(item.hide == undefined || item.hide == false){
            if(item.attrName != null && item.attrName !=""){
                result.push(item.attrName);
            }
        }    
    });
    var exportAttrs = result.join(",");  //需要导出的属性
    console.log(exportAttrs);
    var condition = encodeURIComponent(Grid1.queryData.query.query) ; // 需要导出的条件
    console.log(condition);
    var classname = Grid1.targetClass ;//需要导出的类名
    console.log(classname);
    var preapi = Config.modelerApiBase +"/dwf/v1/";//请求前缀 
    var exporturl = `exportData/exportData?classname=${classname}&attributes=${exportAttrs}&joinToOneSheet=false&condition=${condition}`;
    if(Grid1.getAll().length > 0){
        window.open(preapi + exporturl);
    }
    else{
        alert("没有需要导出的内容!")
    }
  26. 钟广友 发表:

    //在表单中模拟音视频播放,by zgy 21226

    var audio = "http://10.20.134.36:8180/multi-file/multifile_default/2022-12-26/1672068953087.mp3"//音频资源url

    audio = new Audio(audio);                 //实例化音频播放对象

    var curRootAddin = this.getAddinById('col18');  //add by zgy,签发主页亮显样式  

    curRootAddin.cacheAudio = audio;    //音频播放对象缓存在UI控件中;

    curRootAddin.cacheAudio.play();        //音频播放(可在特定事件中触发音频播放)

  27. 钟广友 发表:

    //前端脚本中Dialog弹窗脚本示例:
    var initParams = {
        // obj:this.selectedObjs[0],
        // query:`and obj.woTitle != '工单标题11'`
        data: { woDesc1: 'cheney' }
    }  
    this.openForm("ClaimResult"/*表单类名*/'ClaimResultSingle'/*表单名称*/, { curDialogWidth: '1000px'/*弹窗宽*/, curDialogHeight: '800px'/*弹窗高*/, needDefaultOpr: false/*是否显示右下角保存按钮*/,needDialogDefaultOpr:false/*是否显示右下角保存按钮*/,displayName: "openDialog标题"/*弹窗标题*/ ,authority: 'OPRE4949DDCA76D7344BD9AAF052E300'/*操纵授权标识*/}, 'visit'/*弹窗CUD状态*/, initParams/*传入数据*/); 

  28. 钟广友 发表:

    //String类型文件下载脚本示例:

    /**
     * 文件下载示例(不改变文件名称)1,by zgy,23-01-10

     * fileURL 如 “/multi-file/multifile_default/2023-02-22/1677059677086.docx”
     */
    function downloadFile(fileURL, fileName) {
        window.location.href = fileURL;//"http://www.域名/template.xlsx(文件名)"
    }


    /**
     * 文件下载示例(可传入下载文件名称)2,by zgy,23-01-10

     * fileURL 如 “/multi-file/multifile_default/2023-02-22/1677059677086.docx”
     */
    function download2(fileURL, fileName) {
        debugger
        if (fileName == null || fileName.trim() == '') {
            var fileUrlStrs = fileURL;
            if (fileUrlStrs && fileUrlStrs.trim()) {
                fileUrlStrs = fileUrlStrs.split(`/`);
                fileUrlStrs = fileUrlStrs[fileUrlStrs.length - 1];
            }
            if (fileUrlStrs) {
                fileName = fileUrlStrs;
            } else {
                fileName = '未知文件名';
            }
        }
        var index = fileURL.lastIndexOf('.'); 
        var suffix = fileURL.substring(index);
        fileName = fileName+suffix;
        const a = document.createElement('a');
        a.style.display = 'none';
        a.setAttribute('target', '_blank');
        /*
         * download的属性是HTML5新增的属性
         * href属性的地址必须是非跨域的地址,如果引用的是第三方的网站或者说是前后端分离的项目(调用后台的接口),这时download就会不起作用。
         * 此时,如果是下载浏览器无法解析的文件,例如.exe,.xlsx..那么浏览器会自动下载,但是如果使用浏览器可以解析的文件,比如.txt,.png,.pdf....浏览器就会采取预览模式
         * 所以,对于.txt,.png,.pdf等的预览功能我们就可以直接不设置download属性(前提是后端响应头的Content-Type: application/octet-stream,如果为application/pdf浏览器则会判断文件为 pdf ,自动执行预览的策略)
         */
        a.setAttribute('download', fileName);
        a.href = fileURL;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }

  29. 刘英博 发表:

    在前端脚本里设置localStorage或者sessionStorage以便实免登陆跳转?

    let userAndPwd = {
        "username": 'admin',
        "password": 'public'
    }
    window.sessionStorage.setItem('user12', JSON.stringify(userAndPwd));

    这里需要注意下面的前提条件:

    第一、第三方被集成的页面必须支持这种通过sessionStorage实现免登陆的能力

    第二、DWF侧要能够通过反向代理,将第三方页面并入相同的sessionStorage之中

  30. 于亚杰 发表:

    表格设置使用自定义sql展示数据,如果要通过脚本来给表格更新查询条件可以参考如下用法:

    image2023-6-4_0-31-2.png

  31. 钟广友 发表:

    this.getAddinById('FormEngine1').setDisplayType('visit')   //卡片设置为创建态(create)/编辑态(edit)/浏览态(visit)

    1. 钟广友 发表:

      /*
      * 内存表格分页与内存数据赋值示例
      * ---初始化部分---
      */
      debugger
      var grid = this.getAddinById('Grid2');
      //设置表头与分页
      var pageInfo = grid.getPageInfo();//获取当前表格页码信息
      try{
          grid.setColumnDefs(grid.getColumnDefs());
      }catch(e){}
      debugger
      pageInfo.totalPage = 99;//数据总数
      pageInfo.pageSize = 5;//每页条数
      pageInfo.pageIndex = 1;//当前页码
      pageInfo.pageSizeOpts = [5,10,15,20]//每页条数切换的配置
      grid.setPageInfo(pageInfo)//设置当前表格页码信息
      var rowDatas = [];
      var curIndex = 0;
      for (i = 0; i < pageInfo.pageSize; i++) {
          curIndex++;
          var rowData = { test: `测试${curIndex}`, strFile: `文件${curIndex}` };  //strFile
          rowDatas.push(rowData);
      }
      //赋值内存数据
      this.getAddinById('Grid2').setRowData(rowDatas);

    2. 钟广友 发表:

      /*
      * 内存表格分页与内存数据赋值示例
      * ---翻页部分---
      */
      debugger
      var curIndex = 0;
      curIndex = this.getAddinById('Grid2').currentPage; //当前页
      var pageSize = this.getAddinById('Grid2').getPageInfo().pageSize;//每页条数
      curIndex = (curIndex - 1) * pageSize;
      var rowDatas = [];
      for (i = 0; i < pageSize; i++) {
          curIndex++;
          var rowData = { test: `测试${curIndex}`, strFile: `文件${curIndex}` };  //strFile
          rowDatas.push(rowData);
      }
      this.getAddinById('Grid2').setRowData(rowDatas);

    3. 钟广友 发表:

      /*
      * 牵制设置表单页面tab加载后不能回刷
      */

      var form = this.getRootAddin();
      form.sourceFormFreshStatus = false;
      form.openSourceFormFreshControl = true;

    4. 钟广友 发表:

      /*
      * PC端查询框去掉新加开发引起的加载过程中显示滚动条闪烁(by 王昆)
      */

      .ivu-icon-ios-loading{display: none;}

    5. 钟广友 发表:

      /*
      * 模型包释放时提示“操作xxx:yyy没能释放(尝试更新...尝试新增...尝试覆盖...等都PlatformException)”
      */

      方法一:/dwf/v1/auth/items-delete/{authName} 删除授权项

      方法二:select * from PLT_MDL_AuthorityItem where PLT_authorityId in ('cronbds', 'disable', 'trigger')

    6. 钟广友 发表:

      隐藏指定页签 this.getAddinByld(Tab2').hideTab(页签01')

      显示指定页签: this.getAddinByld(Tab2')showTab(页签01')

    7. 钟广友 发表:

      this.getAddinById("FormEngine1").freshData(query);  //卡片对象刷新

      this.getAddinById('FormEngine1').freshObj(res,true); //赋值内存对象,并刷新子表单初始化

    8. 钟广友 发表:

      var grid = this.getAddinById('Grid1');
      var allRows = grid.getAll();
      if (allRows && allRows.length > 0) {
        grid.setSelected(0); //默认选择grid表格第一行
      }

    9. 钟广友 发表:

      //获取表格手动表格列筛选过滤后的表格行;

      this.getAddinById('Grid1').gridApi.forEachNodeAfterFilter(x => console.log(x.data.oid)); 

    10. 钟广友 发表:

      this.edit(this.obj, "ClassName", { showMessage: false/*是否修改保存后前端提示*/,freshForm:false/*禁止this.freshData()刷新当前表单,by zgy,230613 */})

    11. 钟广友 发表:

      PC端tab页窗口是否保持缓存的脚本调用示例说明

      this.openTab({targetClass:"xx",viewName: "xx",action:"visit',authority:"xx",displayName:"xx"},{displayType:"visit",targetFormFreshStatus:true/*目标打开窗口默认刷新,如设置false表示可打开缓存的窗口*/, sourceFormFreshStatus:false/*当前窗口默认不刷新,如设置true表示回到当前窗口时刷新*/})

      移动端tab页窗口是否保持缓存的脚本调用示例说明

      this.openTab({targetClass:"xx",viewName: "xx",action:"visit',authority:"xx",displayName:"xx"},{displayType:"visit",backRefresh:true/*当前打开窗口被回退时默认缓存不刷新,如设置false则表示回到当前打开窗口时会被刷新*/})

      1. 钟广友 发表:

        移动端this.openTab选项补充说明:

    12. 钟广友 发表:

      cudBatchObjs示例
      var cudEvents = [
          {
              action: 'update',
              className: 'DocumentsApplication',
              objs: [docApp]
          }, {
              action: 'update',
              className: 'FileUploadInfo',
              objs: [fileUploadInfo]
          }, {
              action: 'createOrUpdate',
              className: 'FileBasicInfo',//流程文件的FileBasicInfo
              objs: [docFileBasicInfos]
          }, {
              action: 'createOrUpdate',
              className: 'ProcSysFileLinkInfo',//流程文件的FileBasicInfo
              objs: procSysFileLinkInfos
          }
      ]
      var threeCachekey = "DWF_ThreePage_threeCachekey";
      dwfthis.cudBatchObjs(cudEvents).then(res => {
          dwfthis.spinHide(); //编辑完成,关闭遮罩
          localStorage.setItem(threeCachekey, JSON.stringify({ docApp, fileUploadInfo: fileUploadInfo, fileBasicInfo: docFileBasicInfos }));
          var doccc = dwfthis.obj;
          openSecondPage(dwfthis, doccc);
      })
    13. 钟广友 发表:

      当前浏览器是否允许PDFjs(第三方PDF在线浏览器)的可视化浏览
      /**
       * 当前浏览器是否允许PDFJS的可视化浏览
       * by zgy 2024-07-01
       */
      function canPDFjsViewer() {
          var version = getChromeVersion();
          if (version && version > 86) {
              return true;
          } else {
              return false;
          }
      }
      
      /**
       * 获取浏览器的chrome内部版本号
       * by zgy 2024-07-01
       */
      function getChromeVersion() {
          // Chrome, Edge (Chromium-based), 和其他基于Chromium的浏览器都会在userAgent中包含类似"Chrome/版本号"的字符串  
          var userAgent = navigator.userAgent;
          var match = userAgent.match(/Chrome\/(\d+)/);
      
          if (match && match[1]) {
              // 如果找到匹配项,match[1]将包含版本号  
              return parseInt(match[1], 10); // 将版本号转换为整数  
          }
          // 如果没有找到匹配项,返回null或0表示未检测到Chrome版本  
          return null; // 或者你可以选择返回0或其他默认值  
          /**
           * chrome
          chrome/126.0.0.0 
          360极速浏览器64位新版本
          chrome/122.0.6261.95 
          360极速浏览器32位13版本
          chrome/86.0.4240.198 
          360极速浏览器32位11版本
          chrome/69.0.3497.100 
          */
      }
  32. 刘英博 发表:

    如何在后端生成空白文件empty.txt并在前端脚本中下载,技术路线是在后端脚本中将文件放到web服务器multi-file,然后下载:

    后端脚本:

    const JavaFile = Java.type('java.io.File');
    const JavaFileWriter = Java.type('java.io.FileWriter');
    const JavaIOException = Java.type('java.io.IOException');
    
    const folderPath = '/opt/apache-tomcat/webapps/multi-file/tmp';
    const fileName = this.generateUUID();
    const content = 'Hello World!';
    
    const file = new JavaFile(folderPath);
    try {
      if (!file.exists()) {
        file.mkdirs();
      }
    
      const filePath = new JavaFile(folderPath, fileName);
      const isNewFile = filePath.createNewFile();
    
      const writer = new JavaFileWriter(filePath, false); // 设置为 false,覆盖已有内容
      writer.write(content);
      writer.close();
    
      this.res = fileName;
    
    } catch (e) {
      this.logger.info('An error occurred while creating/writing the file: ' + e.getMessage());
      // 可以在此处添加适当的异常处理逻辑
    }

    前端脚本,添加1个临时a标签,然后下载:

    function downloadFile(url, fileName) {
      const link = document.createElement('a');
      link.href = url;
      link.setAttribute('download', fileName);
      link.click();
    }
    
    this.callServer().then(res => {
        debugger;
        console.log(res.data.data);
        // 如果不采用二级域名反向代理,直接安装,则:`http://${this.env.serverIp}:${this.env.serverPort}/multi-file/tmp/${res.data.data}`,去掉/dwf/
        url = `http://${this.env.serverIp}:${this.env.serverPort}/dwf/multi-file/tmp/${res.data.data}`;
        downloadFile(url, 'empty.txt');
    });



  33. 钟广友 发表:

    sysLog汇总说明
    public enum LogType {
    // 登陆登出
    LOGIN,
    LOGOUT,
    //对象增删改
    OBJECT_CREATE,
    0BJECT_UPDATE,
    0BJECT_DELETE,
    // 操作
    OPERATION,
    // 组织用户
    USER_CREATE,
    USER_UPDATE,
    USER_DELETE,
    GROUP_CREATE,
    GROUP_UPDATE,
    GROUP_DELETE,
    // 表单
    VIEW_CREATE,
    VIEW_UPDATE,
    VIEW_DELETE,
    // 授权
    ACCESSRULE_CREATE,
    ACCESSRULE_UPDATE,
    ACCESSRULE_DELETE,
    ATTR_ACCESSRULE_CREATE,
    ATTR_ACCESSRULE_UPDATE,
    ATTR_ACCESSRULE_DELETE,
    OBJ_ACCESSRULE_CREATE,
    OBJ_ACCESSRULE_UPDATE,
    OBJ_ACCESSRULE_DELETE,
    //代码装配
    ASSEMBLE,
    //插件
    ADDIN
    }
    /* syslog表字段:
    logtype:日志类型(登录日志、操作日志、装配日志、权限日志)
    logcontent:日志内容(如果是装配,记录下本次需要装配的插件)
    username:登录账号
    displayname:登录账号显示名
    ip:登录IP
    operationName:操作名
    action:动作
    targetClass:目标类
    formName:表单名称
    url:URL地址(action为url的时候有效)
    implementType:实现方式(插件调用、后端脚本、前端脚本、存储过程、插件别名)
    costTime:耗时(单位为秒s)
    creator:创建人
    createTime:创建时间
    lastModifier:最近更新人
    lastModifyTime:最近更新时间
    describtion: 描述(json)
    */
  34. 刘英博 发表:

    文件下载任务的总结

    DWF中包含3类可以上传文件的方法,分别对应localfile类型,string类型,其中:
    localfile:

    • 文件存放目录:/opt/dwf3.0-deploy/file-repository/${类名}/${属性名}/${对象的oid}
    • 数据库字段内容:文件的名称,例如:“微信图片_20221112104507.jpg”
    • 下载链接拼接方式:http://${this.env.serverURL}/v1/omf/classes/${className}/objects/${oid}/attributes/${attributeName}/bytes
    • 辅助函数,详见上面的说明
      • this.omf.setLocalFile()
      • this.omf.getFilePath()
      • this.omf.getFileString()
      • this.omf.getFileByte()

    string:

    • 文件存放目录 /opt/apache-tomcat/webapps/multi-file/multifile_default/${日期}/${文件名}
    • 数据库字段内容:JSON数组,每个元素都含有: name, size, file_id, url,其中url为对外的相对路径,如下所示:

      [{
          "name": "录音文件 2023-07-26 19:18:26.mp3",
          "size": "59.5908203125KB",
          "file_id": "96847415A35DB742B6466C9617A9CB50",
          "url": "/multi-file/multifile_default/2023-07-26/1690370313575.mp3"
      },
      {...}
      ]
    • 下载链接拼接方式:http://${this.env.serverURL}/value[0].url
    • 脚本辅助函数,无

    此外,还有下面的静态资源文件,分别是:
    图片库上传的静态图片,存放目录/opt/dwf3.0-deploy/file-repository/picture_management
    html扩展控件生成的JS文件,存放目录 /opt/apache-tomcat/webapps/code
    大屏中上传的文件,存放目录 /opt/apache-tomcat/webapps/bv-file

    1. 钟广友 发表:

      String类型文件PC端单个上传后,目前应该还拿不到上面的json数据【但多文件上传控件与移动端单文件上传目前均能拿到原始文件信息】

  35. 刘英博 发表:

    在表格已经存在的提交基础上合并查询框用户输入的条件

    this.getSourceAddin().getSelected('Grid1').then(res => {
      // query 查询框的查询拼接字符串
      var query = res
      console.log('getselected', query);
      // 获取表格过滤条件
      var gridQuery = this.getAddinById('Grid1').lastQuery;
      console.log('gridQuery', gridQuery)
      query = `${gridQuery}${query}`
      console.log('拼接后的query', query);
      //重新执行查询事件
      this.getSourceAddin().freshData(query)
    })
  36. 于亚杰 发表:

    表格自定义样式功能示例:(其他控件用法雷同)

    .ag-theme-balham .ag-header{
    	background:red !important;
    }
    
  37. 于亚杰 发表:

    树表格控件通过脚本来设置表格的cell样式,示例效果如下:

    //一个实现表格cell中根据data不同显示不同颜色的脚本
    var tree= this.getAddinById('TreeGrid7');
    var cellStyleCallback = (data) => {
        //让‘数量’列中,数据大于100的显示绿色,小于100的显示红色
        //data数据结构为Object,
        //data.column列信息
        //data.row行数据信息
        if(data.column.property === 'number'){
            if(data.row[data.column.property] > 100){
                return {
                    color: 'green'
                }
            }else{
                return {
                    color: 'red'
                }
            }
        }
    }
    tree.setCellStyle(cellStyleCallback)
  38. 于亚杰 发表:

    目录树控件中根据选中节点获取父级节点的clickData数据,并利用loadSelfData方法来执行重新加载父节点下级数据

    let selfTree = this.getAddinById('SelfJoinsTree1');
    let indexArr = selfTree.clickData.index.split('-');
    let parentNode = null; //父节点的对象 相当于选中了父节点与clickData数据一致
    
    if(indexArr.length  > 1) { //有父节点
        for(let i = 0; i < indexArr.length -1; i++) {
            if(!parentNode) {
                parentNode = selfTree.args.treeList[indexArr[i]];
            } else {
                parentNode = parentNode.children[indexArr[i]];
            }
        }
        selfTree.loadSelfData(parentNode); 
    }