- 一、概述
 - 二、操作及示例
 - 2.1、通过表单属性编写表单脚本
 - 2.2、编写脚本示例
 - 三、表单脚本接口API
 - 3.1、加载事件
 - 3.2、按钮加载事件【v.3.2.4+】
 - 3.3、 表单提交校验
 - 3.4、按钮的前置事件
 - 3.5、按钮的后置事件
 - 3.6、子表按钮的前置事件【v3.1.9+支持】
 - 3.7、子表按钮的后置事件 【v3.1.9+支持】
 - 3.8、子表合计方法 【v3.1.10+支持】
 - 3.9、子表合并行或列方法 【v3.5.8+支持】
 - 四、常用脚本示例
 - 4.1、获取表单所有数据
 - 4.2、获取表单某个字段数据(值)
 - 4.3、修改表单某个字段数据(值)或者给字段赋值
 - 4.4、子表操作
 - 4.5、设置字段隐藏,只读,必填
 - 4.6、字段事件
 - 4.7、设置表单背景,字体,字体颜色
 - 4.8、form DOM操作
 - 4.9、子表合计自定义方法
 - 4.10 监听表单的值变化
 - 4.11 动态改变下拉选项的值
 - 4.12 常用工具类
 - 4.12.1. this.$request :可以通过this.$request 来ajax请求数据
 - 4.12.2. this._ (注意是下划线): Lodash是一个一致性、模块化、高性能的 JavaScript 实用工具库。
 - 4.12.3. this.$dialog 【v3.3.0支持】: 简单封装element-ui的弹窗
 - 4.12.4、this.$import 导入组件
 - 4.13 自定义提示弹窗
 - 1、默认的提示弹窗可以用element-ui的弹窗方式
 - 2、个性化实现示例
 - 3、平台样式实现【v3.5.0+支持】
 - 4.14、设置子表某行单个表格的读写权限【v3.3.7+】
 - 4.15、【推荐】增加快捷找到表单组件实例方法【v3.3.9+】
 - 4.16、【详情表单】-[数据模版]选择的向表单赋值
 - 4.17、【详情表单】-[数据模板]双击事件脚本并编辑表单
 - 4.18、自定义组件引入
 - 4.19、自定义按钮实现前置和后置的脚本示例
 - 4.20、自定义按钮实现打开[数据模版] 案例
 - 4.21、自定义按钮实现打开[在线表单] 案例
 - 五、 FAQ
 - 5.1、修改数据但界面还是旧的数据
 - 1) 处理对象(Object)的4种方式:
 - 1. 将本来要新增的属性提前在data中定义好
 - 2. 直接替换掉userInfo
 - 3. 使用Vue.set 【推荐该方式】
 - 4. 使用$forceUpdate【不推荐使用】
 - 2)针对数组(Array)的特定方式
 - 1) 处理数组(Array)的方式:
 - 1、使用Vue.set**
 - 2、使用数组的包装变异方式** 【推荐该方式】
 - 5.2、如何在表单脚本获取token
 - 5.3、获取当前用户信息
 - 5.4、获取当前流程相关信息
 - 5.5、判断表单是新建还是编辑有判断标识
 - 5.6、表单怎么刷新数据模版的页面
 - 5.7、移动端和PC脚本的区别
 - 5.8、一些常用脚本例子
 - 5.9、怎么关闭表单的弹窗
 - 5.10、怎么过滤子表附件不重复了
 - 5.11、怎么判断数据进行修改了
 - 5.11.1、方案1、你在表单 
onLoad方法定义一个全局变量 - 5.11.2、方案2、用vue 的$wactch处理
 - 5.12、使用this.$request进行数据请求,但是报this.$request is not a function是什么情况?
 - 5.13、【自定义对话框】根据子表选择的数据,过滤掉对话框列表内容
 - 5.14 、怎么触发事件在新tab显示数据模版,而不是弹出页面。
 - 5.15 、自定义按钮如何下载系统的附件
 - 5.16 、怎么调用后端的groovry 方法
 - 5.17 、自定义按钮怎么调用自定义弹窗
 - 5.18 、 如何引用第三方 JS 资源
 - 5.18.1、第三方CDN地址:
 - 5.18.2、本地地址:该地址必须放在public的路径下
 - 5.19 子表通过某个条件禁用字段
 - 5.20 子表级联保存后回填的例子
 - 5.21 监听子表中输入框的input等事件
 - 5.22 表单数据不同条件按钮显示不同
 - 5.23 流程不同节点设置当前用户签名默认值脚本
 - 5.23 报表控件点击按钮请求接口更新数据(支持版本v3.5.7+)
 - 5.24 选项值不同隐藏或显示不同tabs
 - 5.25 日期控件增加禁用日期和快捷方式(3.6.0+)
 - 5.26 值来源的下拉联动数据
 
说明:
本示例中的代码和截图可能和您现在手中的版本不同,但操作思路一样。
一、概述
    对表单界面的字段实现设定其值,读取其值、修改其值,隐藏、显示,必填等操作如:给某个字段设置默认值,获取表单界面某个字段的值,修改表单界面某个字段显示的值。
    有时候我们需要操作按钮的前后置事件 或者添加自定义按钮,点击自定义按钮时需要将列表中选中行的数据导入打开的其他表单。
    有时候需要找到绑定字段,通过$on指定事件(click,blur等事件)进行操作。
二、操作及示例
2.1、通过表单属性编写表单脚本

2.2、编写脚本示例

三、表单脚本接口API
统一说明:以下不再说明
form:是表单的vue实例数据,可以通过这个操作数据、dom,事件等。可以类似this,可以操作$router,$store,$utils等全局方法
也可以调用Element ui的全局方法,比如:$message、$msgbox、$alert等callback:按钮事件回调,如果通过ajax异步提交需要回调,按钮等操作必须回调,不然操作没反应。返回true是回调成功,false表示回调失败,阻止继续操作【v3.1.8+支持】$request:可以通过this.$request 来ajax请求数据【v3.1.9+支持】
3.1、加载事件
 //表单加载事件
 onLoad:function(form){
  }3.2、按钮加载事件【v.3.2.4+】
 //表单加载按钮事件
  onLoadActions:function(form,action,button,type){
  }参数说明:
| 参数 | 说明 | 是否必须 | 可选值 | 
|---|---|---|---|
| action | 按钮别名,在使用页面传入的根据自己需求定义的值; | 是 | add、edit等 | 
| button | 按钮相关数据,包含位置(position)等信息 | - | |
| type | 处理方式,hidden 隐藏,disabled 禁用 | - | hidden,disabled | 
举例说明:
eg1:按钮(action为close) 隐藏
  onLoadActions:function(form,action,button,type){
    if(action === 'close' && type==='hidden'){
    return true
    }
  }eg2:按钮(action为close) 禁用
  onLoadActions:function(form,action,button,type){
    if(action === 'close' && type==='disabled'){
    return true
    }
  }3.3、 表单提交校验
 //表单提交校验
  onValidate:function(form,callback){
    callback(true);
  }3.4、按钮的前置事件
注意:自定义按钮必须设置按钮编码
 //表单按钮前置事件
  beforeSubmit:function(form,action,postValue,callback){
    callback(true);
  }表单按钮提交前触发,在具体的页面中调用.
特别说明:
如果采用if else 要保证每个if、else if、else 都有callback 如下:
if(xxxx){ callback(false) return } callback(true)
//==== 或者这样====
if(xxxx){ callback(false) }else if(xxxx){ callback(true) } else{ callback(true) }
参数说明:
| 参数 | 说明 | 是否必须 | 可选值 | 
|---|---|---|---|
| action | 按钮code,在使用页面传入的根据自己需求定义的值; | - | close,save等 | 
| postValue | 提交给后台的数据,表单数据,避免对象引用该数据只可以读取,如果修改采用form.setData修改值 | - | |
| callback | funtion【必须】,数据回调,一定要有回调方法,不然没反应 | 必须 | true,false | 
3.5、按钮的后置事件
注意: 自定义按钮没有后置事件
 //表单按钮后置事件
  afterSubmit:function(form,action,postValue,callback){
    callback(true); 
  }表单按钮提交后触发,在具体的页面中调用.
参数说明:
| 参数 | 说明 | 是否必须 | 可选值 | 
|---|---|---|---|
| action | 按钮code,在使用页面传入的根据自己需求定义的值; | - | close,save等 | 
| postValue | 提交给后台的数据,表单数据 ,避免对象引用该数据只可以读取,如果修改采用form.setData修改值 | - | |
| callback | funtion【必须】,数据回调,一定要有回调方法,不然没反应,会阻止其他事件 | 必须 | true,false | 
特别说明1:
form.formParams可以获取到表单的回调参数,
可以获得表单提交后的数据,表单提交后的变量,包含业务主键
{
data,//表单提交后的数据
variables//表单提交后的变量,包含业务主键
}
特别说明2:
如果流程按钮,在postValue包含提交后的数据和参数
{
data,//表单提交后的数据
variables//表单提交后的变量,包含业务主键,流程实例id,任务id等
}
3.6、子表按钮的前置事件【v3.1.9+支持】
注意:
1、自定义按钮必须设置按钮编码
2、如果多个子表要需要判断是那个子表的按钮tableForm.code
 //表单子表按钮前置事件
  beforeSubButton:function(tableForm, action, position, params, callback){
    callback(true);
  }表单子表按钮提交前触发,在具体的页面中调用.
参数说明:
| 参数 | 说明 | 是否必须 | 可选值 | 
|---|---|---|---|
| tableForm | 是表单子表的vue实例数据,可以通过这个操作数据、dom,事件等 | - | |
| action | 按钮code,在使用页面传入的根据自己需求定义的值; | - | add、edit等 | 
| position | 按钮位置 | - | |
| params | 参数传递,比如按钮,button,index | - | |
| callback | funtion【必须】,数据回调,一定要有回调方法,不然没反应,会阻止其他事件,如果通过ajax异步提交需要回调 | 必须 | true,false | 
3.7、子表按钮的后置事件 【v3.1.9+支持】
注意:
1、自定义按钮没有后置事件
2、如果多个子表要需要判断是那个子表的按钮tableForm.code
 //表单按钮后置事件
  afterSubButton:function(tableForm, action, position, params, callback){
    callback(true);
  }表单子表按钮提交后触发,在具体的页面中调用.
参数说明:
| 参数 | 说明 | 是否必须 | 可选值 | 
|---|---|---|---|
| tableForm | 是表单子表的vue实例数据,可以通过这个操作数据、dom,事件等 | - | |
| action | 按钮code,在使用页面传入的根据自己需求定义的值; | - | add、edit等 | 
| position | 按钮位置 | - | |
| params | 参数传递,比如按钮,button,index | - | |
| callback | funtion【必须】,数据回调,一定要有回调方法,不然没反应,会阻止其他事件,如果通过ajax异步提交需要回调 | 必须 | true,false | 
3.8、子表合计方法 【v3.1.10+支持】
需要先开启子表合计的,该脚本才会生效
 //子表合计的方法
  summaryMethod:function(tableForm, tableName, params){
  }在具体的页面中调用.
参数说明:
| 参数 | 说明 | 是否必须 | 可选值 | 
|---|---|---|---|
| tableForm | 是表单子表的vue实例数据,可以通过这个操作数据、dom,事件等 | - | |
| tableName | 子表的表名区分多个子表 | - | |
| params | 字段的参数{ columns, data },其中 columns 是字段的属性,data 是数据 | - | 
3.9、子表合并行或列方法 【v3.5.8+支持】
 //子表合并行或列方法
  spanMethod:function(tableForm, tableName, params){
  }在具体的页面中调用.
参数说明:
| 参数 | 说明 | 是否必须 | 可选值 | 
|---|---|---|---|
| tableForm | 是表单子表的vue实例数据,可以通过这个操作数据、dom,事件等 | - | |
| tableName | 子表的表名区分多个子表 | - | |
| params | 里面包含当前行row、当前列column、当前行号rowIndex、当前列号columnIndex四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan,第二个元素代表colspan。 也可以返回一个键名为rowspan和colspan的对象。可以参考:https://element.eleme.cn/#/zh-CN/component/table | - | 
四、常用脚本示例
4.1、获取表单所有数据
// 获取表单所有数据
form.getFormData();4.2、获取表单某个字段数据(值)
// 获取主表值(key为字段名)
form.getData('zd1');
// 子表数据(key 为子表的name)
form.getData('zbzd');
// 子表第几行的数据,先获取子表字段数据,然后找到数组的第几行的字段的数据,下面[1] 表示第2行【索引开始是0】,xxx:表示字段名
form.getData('zbzd')[1].xxx;
4.3、修改表单某个字段数据(值)或者给字段赋值
// 设置主表字段【key为字段名(key),value:为字段数据】
form.setData('zd1','广州安可');
// 设置子表数据 如果是一对多是个`数组`。一对一是个`对象`
// 子表建议先获取子表数据,form.getData('bdjbzb') 再修改 数组(或对象)
const subData = form.getData('bdjbzb')
form.setData('bdjbzb',[{
"leiXing": "",
"mingCheng": "测试",
"shuLiang": "",
"danJia": "",
"zhuangTai": "",
"xiaoJi": ""}]);
4.4、子表操作
//子表默认添加一行
//子表默认添加一行
form.setData('bdjbzb',[{
"leiXing": "",
"mingCheng": "测试",
"shuLiang": "",
"danJia": "",
"zhuangTai": "",
"xiaoJi": ""}]);
//子表在原来基础上添加一行
// 子表建议先获取子表数据,form.getData('bdjbzb') 再修改 数组(或对象)
const subData = form.getData('bdjbzb')
subData.push({
"leiXing": "",
"mingCheng": "测试",
"shuLiang": "",
"danJia": "",
"zhuangTai": "",
"xiaoJi": ""})
form.setData('bdjbzb',subData)
//调用完成会出现样式问题,记得调用下doLayout
form.getRefs('bdjbzb')[0].$refs.elTable.doLayout()4.5、设置字段隐藏,只读,必填
快捷方式(推荐):
权限(隐藏【h】,编辑【e】,只读【r】,必填【b】,子表或只有只读字段权限的字段控件-显示【s】)
// ①设置字段隐藏,只读,必填
// 字段名 ,权限(隐藏【h】,编辑【e】,只读【r】,必填【b】)
 form.setFormRights('ziDuan2','h')
 //② 设置子表权限
 // 建议先获取表单该字段的权限,然后在赋值 v3.2.4+支持
 const rights =  form.getFormRights('zb1') ||{}
 //可能是如下格式:
 //   const rights= {
  //      rights:'r',//整个子表权限
  //    buttons:{//子表按钮权限
  //        'add':'s',
  //        'remove':'h'
  //    },
  //    columns:{//子表字段权限
  //         'id':'h',
  //         'name':'e'
  //    }
  // }
  // 如果没定义请先定义columns
  //    if(!rights.columns){
  //      rights.columns ={}
  //  }
  //
   //设置子表字段 权限 xxxx 是字段名
   rights.columns['xxxx'] = 'r'
   form.setFormRights('zb1',rights)如果必填可能需重新加载下验证规则,触发验证
 setTimeout(()=>{
           form.validate(()=>{})
      },10)
触发验证需要判断是否校验成功可以判断回调的值是否成功
 setTimeout(()=>{
         form.validate((r)=>{
             if(!r) form.$message.warning('请检查数据')
           callback(r)
         })
      },10)也可以操作dom方式处理://TODO:需要编写
4.6、字段事件
//字段事件 目前只支持 change blur focus 事件
// 其中 `formItemziDuan1` 由formItem+字段名组成
form.$refs.dynamicForm.$refs.formItemziDuan1[0].$on('change',(data)=>{
    if(data==='1'){
        form.setFormRights('ziDuan2','h')
    }else{
        form.setFormRights('ziDuan2','e')
    }
})如果是栅格布局、标签页、步骤条等嵌套布局需要知道布局key
//如下代码
//formItemgrid_19i6jxc 是先找到栅格布局字段,然后找到字段进行操作
form.$refs.dynamicForm.$refs.formItemgrid_19i6jxc[0].$refs.formItemlanguage[0]
//最新版本建议采用form.getRefsField(‘language’)方式获取,避免要层层查找
form.getRefsField("language") 例子1:选择器的事件监听回填
 //最新版本建议采用form.getRefsField(‘test1’)方式获取,避免要层层查找
//test1 为字段名
form.getRefsField('test1').$children[0].$on("input",data=>{
//TODO:处理你需要处理的事件
debugger
})4.7、设置表单背景,字体,字体颜色
//设置表单背景,字体,字体颜色
  const id =  'formStyle' //保证唯一建议时间戳
  let styleTag = document.getElementById(id)
      if (!styleTag) {
        styleTag = document.createElement('style')
        styleTag.setAttribute('type', 'text/css')
        styleTag.setAttribute('id', id)
        document.head.appendChild(styleTag)
      }
  //添加的样式
  const newStyle ='' //这里编写你要添加的样式
  styleTag.innerText = newStyle
4.8、form DOM操作
form可以操作表单vue的方法(methods)、属性、DOM元素和事件
 如果层级比较深。 先在脚本里面设置一个断点debugger
 例子1:找子表的按钮例子
  在console面板中
  ①、先找到子表
 ②、再观察,查找出你要找的按钮
 ③、最终form.$refs.dynamicForm.$refs.formItembtzb[0].$children[0].$children[1].$children[0].$el找到是子表按钮所在的元素
4.9、子表合计自定义方法
需要先开启子表合计的,该脚本才会生效
el原生的方法
 summaryMethod:function(tableForm,tableName,param) {
      const { columns, data } = param
      const sums = []
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = this.sumText
          return
        }
        const property = column.property
        const values = data.map(item => Number(item[property]))
        const precisions = []
        let notNumber = true
        values.forEach(value => {
          if (!isNaN(value)) {
            notNumber = false
            const decimal = ('' + value).split('.')[1]
            precisions.push(decimal ? decimal.length : 0)
          }
        })
        const precision = Math.max.apply(null, precisions)
        if (!notNumber) {
          sums[index] = values.reduce((prev, curr) => {
            const value = Number(curr)
            if (!isNaN(value)) {
              return parseFloat((prev + curr).toFixed(Math.min(precision, 20)))
            } else {
              return prev
            }
          }, 0)
        } else {
          sums[index] = ''
        }
      })
      return sums
        }官网的例子:
 summaryMethod:function(tableForm,tableName,param) {
    const { columns, data } = param;
    const sums = [];
    columns.forEach((column, index) => {
      if (index === 0) {
        sums[index] = '总价';
        return;
      }
      const values = data.map(item => Number(item[column.property]));
      if (!values.every(value => isNaN(value))) {
        sums[index] = values.reduce((prev, curr) => {
          const value = Number(curr);
          if (!isNaN(value)) {
            return prev + curr;
          } else {
            return prev;
          }
        }, 0);
        sums[index] += ' 元';
      } else {
        sums[index] = 'N/A';
      }
    });
    return sums;
  }4.10 监听表单的值变化
//表单所有字段,v3.4.4以后 对象需要 deep: true
form.$refs.dynamicForm.$watch('models',(data)=>{
          console.info(data)
        },{
  deep: true
})
//如果需要某个字段,采用键路径,比如字段名:abc
form.$refs.dynamicForm.$watch('models.abc',(data)=>{
          console.info(data)
        })
//监听子表的值改变,首先先找到子表的实例
form.$refs.dynamicForm.$refs.formItembmsyjemxb[0].$watch('dataModel',(data)=>{
          console.info(data)
        },{
  deep: true
})https://cn.vuejs.org/v2/api/#vm-watch
需求多对象(数组)内部值的变化,可以在选项参数中指定 deep: true。
在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调。
移动端不采用 键路径
4.11 动态改变下拉选项的值
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
      //获取该字段的字段默认定义,比如该字段为第二个字段
    const defField = JSON.parse(JSON.stringify(form.formDefData.fields[2]))
    form.$refs.dynamicForm.$watch('models.tenantId', function(data) {
      if (data == '1') {
        const field = JSON.parse(JSON.stringify(defField))
        field.field_options.options = [{
          val: '3',
          label: '测试'
        }]
        //设置只有“测试”这个选项
        form.formDefData.fields.splice(2, 1, field)
      } else {
        form.formDefData.fields.splice(2, 1, defField)
      }
    })
  }
})
动态修改数据字典的值
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
    // 获取该字段的字段默认定义,比如该字段为第二个字段
    const sjzd = form.getRefsField('xianShiZhi').$children[0]
    let treeData = []
    setTimeout(() => {
      // 保存已经加载的数据字典的数据
      treeData = JSON.parse(JSON.stringify(sjzd.treeData))
    }, 1000)
    form.$refs.dynamicForm.$watch('models.fuId', function(data) {
      if (data === '1') {
        sjzd.treeData.splice(2, 1)
      } else {
        // 还原默认
        sjzd.treeData = JSON.parse(JSON.stringify(treeData))
      }
    })
  }
})
4.12 常用工具类
4.12.1. this.$request :可以通过this.$request 来ajax请求数据
//例如  Grovery  可以采用该方案
 this.$request({
        url:'/business/v3/form/def/getScriptValue',
        method: 'post',
        data:  { 
         'script': `脚本代码`
         }
      }).then(response => {
         //TODO:处理数据返回的逻辑
        }).catch(error => {
            console.log(error)
        })//例如  平台的接口
 this.$request({
        url:'xxx',//平台接口地址
        method: 'post',//get或者post
        data:{},// data数据
        params:{},// params数据
      }).then(response => {
         //TODO:处理数据返回的逻辑
        }).catch(error => {
          //TODO:异常数据处理
            console.log(error)
        })如果你请求的不是IFORM平台地址:请加必须参数:baseURL :’xxxx’
具体的地址前缀,更多参数看:https://www.kancloud.cn/yunye/axios/234845
  baseURL 将自动加在 url 前面,除非 url 是一个绝对 URL。
  它可以通过设置一个 baseURL 便于为 axios 实例的方法传递相对 URL
  平台的
//例如
  const baseURL = window.location.origin
 this.$request({
  //这里一般情况是做跨域的处理,那么访问就是当前地址,不是真实地址,例如:'https://api.example.com' 
 // 如果已经做的CORS跨域,则写真实地址
        baseURL:baseURL ,
        url:'/business/v3/form/def/getScriptValue',
        method: 'post',
        data:  { 
         'script': `脚本代码`
         }
      }).then(response => {
        //TODO:处理数据返回的逻辑
        }).catch(error => {
            console.log(error)
        })更多个性化属性配置:【传送门】
跨域问题解决:【传送门】
4.12.2. this._ (注意是下划线): Lodash是一个一致性、模块化、高性能的 JavaScript 实用工具库。
一些常用的就不需要我们自己写了
具体API:https://www.lodashjs.com/
4.12.3. this.$dialog 【v3.3.0支持】: 简单封装element-ui的弹窗
//自己写vue的模版和窗口
this.$dialog({
    template:'<xxx>xx</xxx>'
},[options],[callback])
①、
这个是 组件或html元素
② 、[options] 是element-ui的 dialog的属性(attrs)
v3.5.8+新添加了一些抽屉属性
openType 打开方式,dialog:对话框,drawer:抽屉
direction 呼出方向’ltr’, ‘rtl’, ‘ttb’, ‘btt’
③、[callback] 是数据的回填,主要关闭窗口
具体用例:
this.$dialog({
          data(){
              return {
             readonly:form.readonly,
             data:data
          }
          },
           template:'<multi-table-supplier  :data="data" :readonly="readonly" />'
      },{
        dialog:{
          appendToBody:true,
          width: '90%',
          top: '5vh',
          center: true,
          title: '供应商明细',
          'custom-class':'iform-dialog-90',
          openType:'dialog'
       }
      },(tpl)=>{
        form.dialogTemplate =tpl 
      }).catch((_this)=>{ 
           _this.visible = false
        form.dialogTemplate = null 
      })注意:
  ①、在数据模版中使用‘template’ 不是‘form’。修改为template.dialogTemplate =tpl
  ②、
   具体看示例:4.18
4.12.4、this.$import 导入组件
新增了几个路径的引入
this.$import 是views路径下的
this.$import1 是components路径下的
this.$import2 是business路径下的this.$vue.component('multi-table-supplier', this.$import('/demo/multi-table/supplier'))
4.13 自定义提示弹窗
1、默认的提示弹窗可以用element-ui的弹窗方式
form.$message(message, options)
form.$message.success(message)
form.$message.warning(message)
form.$message.error(message)
//更多请看api
form.$msgbox(options)
form.$alert(message, title, options) 或 form.$alert(message, options)
form.$confirm(message, title, options) 或 form.$confirm(message, options)
form.prompt(message, title, options) 或 form.$prompt(message, options)
form.$notify(message, options)具体API看上面链接地址,数据模版脚本类似的,把
form换成template
2、个性化实现示例

该功能使用了$createElement的语法实现
  const h = form.$createElement
      let isPrint = true
      const  checkPrint =  h('el-checkbox', {
            props:{
              value: isPrint
            },
            domProps: {
              value: isPrint
            },
            on: {
              input: (val) => {
                checkPrint.componentInstance.value =isPrint= val
              }
            }}, '打印标签')
      form.$msgbox({
        title: '提示',
        message: h('div', null, [
          h('div', null, '确认所勾选数据都审核完毕,并且填写了正确的提取数据。点击【提交】将代表本次提取完成,后续将进入分装环节 '),
         checkPrint
        ]),
        showCancelButton: true,
        confirmButtonText: '提交',
        cancelButtonText: '取消'
      }).then(action => {
        if (isPrint) {
          this.toPrintData(form, pk)
        }else{
          form.callback()
        }
       }).catch(err1 => {
         form.callback()
        console.log(err1)
      })3、平台样式实现【v3.5.0+支持】

//删除选中的记录,更多参数具体看API
this.$actionUtils.removeRecord(selection)
//保存成功,更多参数具体看API
this.$actionUtils.saveSuccessMessage(msg)4.14、设置子表某行单个表格的读写权限【v3.3.7+】
Object.assign(JForm,{
  //加载事件
  onLoad:function(form){
  }, 
 //表单子表按钮后置事件
  afterSubButton:function(tableForm,action,position,params,callback){
    setTimeout(()=>{ // 防止调取实例报错
    // 取到列表某行的实例,调用对应方法控制 true为只读,不用则不需要设置
    // 其中  `formItemidentification` 由formItem+字段名组成
      tableForm.$refs.formItemidentification[0].setDisabled(true)
    },100)
    callback(true) 
  }
});4.15、【推荐】增加快捷找到表单组件实例方法【v3.3.9+】
// 找到表单字段,表单标签和表单字段,如果需要找的事件还是需要[0],才是实例
form.getRefs(fieldName)
//找到表单字段,找到具体控件组件实例,这个实例才有控件的change的事件
form.getRefsField(fieldName)fieldName 是表单字段名或者字段标识名,点击右侧【业务对象】的字段避免编写错误
说明:该方式为快捷查找只能找到主表或子表,如果要找到子表的某个字段,则先找到子表后在一层层向下查找
4.16、【详情表单】-[数据模版]选择的向表单赋值
注意:延迟个3-5秒钟等待详情表单加载完成,或者加个定时器监听是否加载完成
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
     //注意:延迟个3-5秒钟等待详情表单加载完成,或者加个定时器监听是否加载完成
      setTimeout(() => {
        // fwjbxxgl 是详情表单的字段标识
           const fwjbxxgl = form.getRefsField('fwjbxxgl').$children[0]
      // 监听数据模版的行点击事件(row-click)
      fwjbxxgl.getRefs().$refs['crud'].$on('row-click', (row) => {
          // syfwxxd 是详请表单的字段标识
        const syfwxxd = form.getRefsField('syfwxxd').$children[0]
        // 向表单赋值
        syfwxxd.setData('huZhu', row.hu_zhu_)
        syfwxxd.setData('huZhuDianHua', row.hu_zhu_dian_hua_)
      })
    }, 3000)
  }
})4.17、【详情表单】-[数据模板]双击事件脚本并编辑表单
注意:延迟个3-5秒钟等待数据模版加载完成,或者加个定时器监听是否加载完成
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
     //注意:延迟个3-5秒钟等待数据模版加载完成,或者加个定时器监听是否加载完成
    setTimeout(() => {
    // 找到【产品管理】模版 其中`cpgl` 是 产品管理的key
      const cpgl = form.getRefsField('cpgl').$children[0].getRefs()
      // 找到table,监听双击事件
      cpgl.$refs.crud.$on('row-dblclick', (row, column, cell, event) => {
         //调用编辑的方法
        cpgl.handleEdit(row.id_, 'edit', 'manage', null, row)
      })
    }, 3000)
  }
})4.18、自定义组件引入
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
   // 1、先注册组件(如果全局注册的就不需要引入)
    // 2、引入的组件必须在views路径下 比如下面路径文件: src\views\demo\multi-table\supplier.vue
  this.$vue.component('multi-table-supplier', this.$import('/demo/multi-table/supplier'))
  }
})4.19、自定义按钮实现前置和后置的脚本示例
①、同步请求 不需要请求后端
Object.assign(JForm,{
 //表单按钮前置事件
  beforeSubmit:function(form,action,postValue,callback){
    if(action ==='custom'){ // action 是按钮的code
      //同步请求 不需要请求后端
      // TODO:相关业务处理
       alert("后置事件")
      // 注意:一定要有回调
        callback(true) 
    }else{
          callback(true) 
    }
  }
});②、异步请求
Object.assign(JForm,{
 //表单按钮前置事件
  beforeSubmit:function(form,action,postValue,callback){
    if(action ==='custom'){ // action 是按钮的code
     this.$request({
     url:'/business/v3/form/def/getScriptValue',
     method: 'post',
     data:  { 
      'script': `脚本代码`
      }
   }).then(response => {
       // TODO:相关业务处理
       //TODO:处理后置事件,也可以调用后置的方法
             callback(true) 
     }).catch(error => {
         console.log(error)
     })
    }else{
          callback(true) 
    }
  }
});4.20、自定义按钮实现打开[数据模版] 案例
Object.assign(JForm, {
  //加载事件
  onLoad:function(form){
      // 先注入数据模版组件
     const templateList = this.$import('/platform/data/dataTemplate/template-list-key.vue')
      this.$vue.component('template-list', templateList)
  },
  //表单子表按钮前置事件
  beforeSubButton: function (tableForm, action, position, params, callback) {
    if ('test' === action) {
      this.$dialog({
        data() {
          return {
            templateKey: 'abc' //数据模版别名
              dynamicParams:{//动态参数
              'xxx':'xxxx'
            }
          }
        },
        template: '<template-list  :template-id="templateId" />'
      }, {
        dialog: {
          appendToBody: true,
          width: '70%',
          center: true,
          title: 'xxx列表',
        }
      }, (tpl) => {
        tableForm.dialogTemplate = tpl
      }).catch((_this) => {
        _this.visible = false
        tableForm.dialogTemplate = null
      })
    }
    callback(true)
  }
});4.21、自定义按钮实现打开[在线表单] 案例
Object.assign(JForm, {
 //加载事件
  onLoad:function(form){
        //先注入表单组件
        const formrender = this.$import('/platform/form/formrender/index')
      this.$vue.component('formrender', formrender)
  },
  //表单子表按钮前置事件
  beforeSubButton: function (tableForm, action, position, params, callback) {
    if ('test' === action) {
      this.$dialog({
        data() {
          return {
            formKey: 'qjd1',//表单key
            pkValue: '',//数据主键
            buttons: [], //表单按钮 v3.4.5+支持
            readonly: false, //是否只读
          }
        },
        template: '<formrender  :formKey="formKey" :pkValue="pkValue" :buttons="buttons" :readonly="readonly" />'
      }, {
        dialog: {
          appendToBody: true,
          fullscreen: true
        }
      }, (tpl) => {
        tableForm.dialogTemplate = tpl
      }).catch((_this) => {
        _this.visible = false
        tableForm.dialogTemplate = null
      })
    }
    callback(true)
  }
});五、 FAQ
5.1、修改数据但界面还是旧的数据
  前几天有朋友给我发了一段代码,然后说Vue有bug,他明明写的没问题,为啥数据就不响应呢,一定是Vue的bug?我感觉他比尤雨溪要牛逼,高攀不起,就没有理他了。但是确实有时候我们在开发时候会遇到数据不响应的情况,那怎么办呢?比如下面这段代码:
 错误例子写法
<template>
  <div>
    <div>
      <span>用户名: {{ userInfo.name }}</span>
      <span>用户性别: {{ userInfo.sex }}</span>
      <span v-if="userInfo.officialAccount">
        公众号: {{ userInfo.officialAccount }}
      </span>
    </div>
    <button @click="handleAddOfficialAccount">添加公众号</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      userInfo: {
        name: 'hugh',
        sex: '男'
      }
    }
  },
  methods: {
    // 在这里添加用户的公众号
    handleAddOfficialAccount() {
      this.userInfo.officialAccount = '广州安可'
    }
  }
}
</script>在上面的代码中,我们希望给用户信息里面添加公众号属性,但是通过this.userInfo.officialAccount = '广州安可' 添加之后,并没有生效,这是为什么呢?
这是因为在Vue内部,数据响应是通过使用Object.definePrototype监听对象的每一个键的getter,setter方法来实现的,但通过这种方法只能监听到已有属性,新增的属性是无法监听到的,但我就是想监听,下面提供了四种方式
1) 处理对象(Object)的4种方式:
1. 将本来要新增的属性提前在data中定义好
比如上面的公众号,我可以提前在userInfo里面定义好,这样就不是新增属性了,就像下面这样
data() {
    return {
      userInfo: {
        name: 'hugh',
        sex: '男',
        // 我先提前定义好
        officialAccount: ''
      }
    }
  }2. 直接替换掉userInfo
虽然无法给userInfo里面添加新的属性,但是因为userInfo已经定义好了,所以我直接修改userInfo的值不就可以了么,所以也可以像下面这样写
this.userInfo = {
  // 将原来的userInfo 通过扩展运算法复制到新的对象里面
  ...this.userInfo,
  // 添加新属性
  officialAccount: '广州安可'
}3. 使用Vue.set 【推荐该方式】
其实上面两种方法都有点取巧的嫌疑,其实对于新增属性,Vue官方专门提供了一个新的方法Vue.set用来解决新增属性无法触发数据响应。Vue.set 方法定义
/**
* target 要修改的对象
* prpertyName 要添加的属性名称
* value 要添加的属性值
*/
Vue.set( target, propertyName, value )上面的代码使用Vue.set可以修改为
import Vue from 'vue'
// 在这里添加用户的公众号
handleAddOfficialAccount() {
  Vue.set(this.userInfo,'officialAccount', '广州安可')
}但是每次要用到set方法的时候,还要把Vue引入进来,好麻烦,所以为了简便起见,Vue又将set方法挂载到了Vue的原型链上了,即Vue.prototype.$set = Vue.set,所以在Vue组件内部可以直接使用this.$set代替Vue.set
this.$set(this.userInfo,'officialAccount', '广州安可')在IFORM表单脚本可以这样写
form.$set(this.userInfo,'officialAccount', '广州安可')发现有许多同学不知道什么时候应该用Vue.set,其实只有当你要赋值的属性还没有定义的时候需要使用Vue.set,其他时候一般不会需要使用。
4. 使用$forceUpdate【不推荐使用】
我觉得$forceUpdate的存在,让许多前端开发者不会再去注意数据双向绑定的原理,因为不论什么时候,反正我修改了data之后,调用一下$forceUpdate就会让Vue组件重新渲染,bug是不会存在的。但是实际上这个方法并不建议使用,因为它会引起许多不必要的性能消耗。
2)针对数组(Array)的特定方式
其实不仅仅是对象,数组也存在数据修改之后不响应的情况,比如下面这段代码
<template>
  <div>
    <ul>
      <li v-for="item in list" :key="item">
        {{ item }}
      </li>
    </ul>
    <button @click="handleChangeName">修改名称</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      list: ['张三', '李四']
    }
  },
  methods: {
    // 修改用户名称
    handleChangeName() {
      this.list[0] = '王五'
    }
  }
}
</script>上面的代码希望将张三的名字修改为王五,实际上这个修改并不能生效,这是因为Vue不能检测到以下变动的数组:
当你利用索引直接设置一个项时,例如: this.list[index] = newValue修改数组的length属性,例如: this.list.length = 0
所以在上例中通过this.list[0] = '王五'是无法触发数据响应的,那应该怎么办呢?
像上面提到的Vue.set和$forceUpdate都可以解决这个问题,
1) 处理数组(Array)的方式:
1、使用Vue.set**
比如Vue.set可以这样写
Vue.set(this.list,0,'王五')
//或者
this.$set(this.list,0,'王五')在表单中
form.$set(this.list,0,'王五')除了那些方法之外,Vue还针对数组提供了变异方法
2、使用数组的包装变异方式** 【推荐该方式】
在操作数组的时候,我们一般会用到数据提供的许多方法,比如push,pop,splice等等,在Vue中调用数组上面提供的这些方法修改数组的值是可以触发数据响应的,比如上面的代码改为以下代码即可触发数据响应
this.list.splice(0,1,'王五')实际上,如果Vue仅仅依赖getter与setter,是无法做到在数组调用push,pop等方法时候触发数据响应的,因此Vue实际上是通过劫持这些方法,对这些方法进行包装变异来实现的。
Vue对数组的以下方法进行的包装变异:
push
pop
shift
unshift
splice
sort
reverse========扩展阅读=============
所以在操作数组的时候,调用上面这些方法是可以保证数据可以正常响应,下面是Vue源码中包装数组方法的代码:
var original = arrayProto[method];
  def(arrayMethods, method, function mutator () {
    // 将 arguments 转换为数组
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];
    var result = original.apply(this, args);
    // 这儿的用法同dependArray(value),就是为了取得dep
    var ob = this.__ob__;
    var inserted;
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args;
        break
      case 'splice':
        inserted = args.slice(2);
        break
    }
    // 如果有新的数据插入,则插入的数据也要进行一个响应式
    if (inserted) { ob.observeArray(inserted); }
   // 通知依赖进行更新
    ob.dep.notify();
    return result
  });如果在对象的数组响应式里面
 computed: {
    // ...其他计算属性...
    resetFields: {
        get() {
            return this.editData.resetFields || []
        },
        set(val) {
            // 使用Vue.set确保响应式更新
            this.$set(this.editData, 'resetFields', val || [])
        }
    },
    // ...其他计算属性...
}
//=====================================================
// 添加元素
this.resetFields = [...this.resetFields, newItem]
// 删除元素 
this.resetFields = this.resetFields.filter(item => item !== id)
// 修改元素
this.resetFields.splice(index, 1, newValue)5.2、如何在表单脚本获取token
form.$utils.cookies.get('token')由于移动端在微信不支持cookies 移动端存储在localStorage
旧版本v3.5.0-采用
JSON.parse(localStorage.getItem('iform-app-'+form.$env.VUE_APP_VERSION+'-token')).value以下方法v3.5.0+支持 建议采用该脚本
form.$utils.storages.get('token')5.3、获取当前用户信息
form.$store.getters.userInfo获取更多的用户相关信息,用户,zhu
比如获取当前用户id
form.$store.getters.userInfo.user.id比如获取当前组织id
form.$store.getters.userInfo.org.id5.4、获取当前流程相关信息
获取当前流程定义defId(只有启动和草稿有该参数)
form.$parent.formParams.defId获取当前流程草稿实例ID(只有草稿有该参数)
form.$parent.formParams.bpmnProInstId获取当前流程节点ID
form.$parent.formParams.nodeId获取当前流程任务ID(只有审批时候有参数)
form.$parent.formParams.taskId获取当前流程实例ID(只有实例或流程结束后时候有参数)
form.$parent.formParams.instanceId5.5、判断表单是新建还是编辑有判断标识
是否编辑,是编辑还是新增,编辑是true,新增是false
form.params.isEdit也可以通过判断主键id来判断是否为空,来判断新增还是编辑
//例如主键是‘id’,如果是其他业务属性字段请替换成其他属性
form.getData('id')判断是否是明细(或详请)表单
通过判断上述是否编辑+readonly 属性
form.params.isEdit && form.readonly5.6、表单怎么刷新数据模版的页面
form.callback()5.7、移动端和PC脚本的区别
大部分脚本编写基本一样,区别如下:
1)调用的控件、控件属性和控件的事件不一样,
例如:pc的控件是element-ui的控件,移动端是vant的控件
比如监听事件改变
移动端用“input”,没有“change”
pc端
2)查找元素层级和元素,pc和移动端可能层级不同,移动端不支持嵌套布局,不支持子表编辑模式等。
例如:$children查找节点
5.8、一些常用脚本例子
下面为部分脚本整合的例子,可根据下面例子代入自己所需功能重新进行补充编辑
Object.assign(JForm,{
    //加载事件
    onLoad:function(form){
        // 默认将子表赋值为只有一行的数据
        // xjsykjzbn为子表name值,下同
        // _subDataSaveSign为逻辑删除所需的标识
        form.setData('xjsykjzbn',[{
            "_subDataSaveSign": "add", // 逻辑删除判断所需的标志字段,add表示新增
            "danXing": "单行",
            "duoXing": "多行",
            "shuZi": 1,
            "danXuan": "1",
            "duoXuan": "2"}]);
        // 权限
        const rights =  form.getFormRights('xjsykjzbn') ||{}
        console.info(rights)
        // 其中 `formItemziDuan1` 由formItem+字段名组成
        console.info(form.getRefs('kaiGuan'))
        form.getRefs('kaiGuan')[0].$on('change',(data)=>{
            if(data==='Y'){
                form.setFormRights('shuoMing','h')
            }else{
                form.setFormRights('shuoMing','e')
            }
        })
        // 监听
        //表单所有字段,如果需要细节,采用键路径
        form.$refs.dynamicForm.$watch('models',(data)=>{
            console.info(data)
        })
        //子表的值改变
        form.getRefs('xjsykjzbn')[0].$watch('dataModel',(data)=>{
                console.info(data)
            },
            {deep:true,immediate:true} // 深度监听
        )
    },
    //表单子表按钮前置事件
    beforeSubButton:function(tableForm,action,position,params,callback){
        console.info(this,tableForm)
        // action为按钮编码
        if(action === 'tjh'){ // 添加一行
            tableForm.dataModel.push({
                "_subDataSaveSign": "add", // 逻辑删除判断所需的标志字段,add表示新增
                "danXing": "单行2",
                "duoXing": "多行2",
                "shuZi": 11,
                "danXuan": "11",
                "duoXuan": "22"})
        }else if(action === 'dyg'){
            let data = tableForm.dataModel
            console.info(data)
            if(tableForm.$utils.isNotEmpty(data)){ // 修改子表数据内第一个数据的dangXing字段的值
                tableForm.dataModel[0]
                tableForm.$set(tableForm.dataModel[0],'danXing','修改')
            }
        }else if(action === 'qx'){
            const rights =  this.$form.getFormRights('xjsykjzbn') ||{}
            console.info(rights)
            //设置子表字段 权限
            if(tableForm.$utils.isNotEmpty(rights)){
                if(rights.columns['danXing'] === 'r'){
                    rights.columns['danXing'] = 'e'
                }else{
                    rights.columns['danXing'] = 'r'
                }
                this.$form.setFormRights('xjsykjzbn',rights)
            }
        }
        callback(true) 
    }
});5.9、怎么关闭表单的弹窗
// 关闭窗口
form.closeDialog()// 如果是父类弹窗,通过.$parent一直 找到这个弹窗的对象  通过观察$el对象
form..$parent.$parent 。。。 .closeDialog()//在数据模版或者待办事宜 进入的表单,关闭窗口并刷新列表
form.callback(true)5.10、怎么过滤子表附件不重复了
注意:一定要延迟下赋值,组件渲染有延迟
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
    const data = JSON.parse(JSON.stringify(form.getData('zddezdx')))
    console.error(data)
    // 清空子表数据
    form.setData('zddezdx', null)
    // 注意:一定要延迟下赋值
    setTimeout(() => {
      // 过滤子表数据
      data.splice(1, 1)
      form.setData('zddezdx', data)
    }, 20)
  }
})5.11、怎么判断数据进行修改了
有以下2个方案参考:
5.11.1、方案1、你在表单 onLoad 方法定义一个全局变量
    // 这个是初始的表单数据
    form.tempFomData =  JSON.parse(JSON.stringify(form.getFormData()))   你想获取地方在获取就行  form.tempFomData 然后需要时候在2个对象进行比较了
   比较逻辑需要自己写
5.11.2、方案2、用vue 的$wactch处理
//表单所有字段
const tempFomData = {}
form.$refs.dynamicForm.$watch('models',(data)=>{
//这里记录改变
          console.info(data)
        })值改变了就保存到全局变量里面
5.12、使用this.$request进行数据请求,但是报this.$request is not a function是什么情况?
这个是基础知识this的作用域不对,这个this 不等于 这个this,  function的作用域不对了
1、一种写法,function(){} 写成()=>{}
2、另外一种写法在function外面定义
   var _this = this
   用的地方_this.$request
以上2种方法最常用,其他的apply,call有点难理解,如果你比较熟悉可以自行尝试
5.13、【自定义对话框】根据子表选择的数据,过滤掉对话框列表内容
  在自定义对话框设置动态条件,设置不在。。。之内
子表的配置
在表单脚本中编写
Object.assign(JForm, {
  // 表单子表按钮前置事件
  beforeSubButton: function(tableForm, action, position, params, callback) {
    if (action === 'selectWl') {
      const ids = []
      tableForm.dataModel.forEach((data, i) => {
      //wuLiaoId:这个是物料的id
        ids.push(data.wuLiaoId)
      })
      // 设置自定义对话框
      tableForm.customDialogKey = 'xzwlxx'
      tableForm.customDialogMultiple = true
      //设置动态参数  1c1v5me这个是动态参数的key,注意为空设置随机字符串
      tableForm.customDialogDynamicParams = {
        '1c1v5me_1': tableForm.$utils.isNotEmpty(ids) ? ids.join(',') : tableForm.$utils.guid()
      }
      tableForm.customDialogCustom = params.button.custom
      tableForm.customDialogVisible = true
      // 注意一定要阻止事件,否则调用默认联动数据
      callback(false)
      return
    }
    callback(true)
  }
})
5.14 、怎么触发事件在新tab显示数据模版,而不是弹出页面。
先判断是的tab的页面是否在菜单存在还是不存在
1、系统菜单有配置【推荐该方案】
  1.1)添加个菜单,请记住资源别名(下面用到)
1.2)在脚本中编写
//比如监听某个事件或按钮触发。其他代码略,请根据实际逻辑编写
const alias = 'dataTemplate_ywsjtb'
form.$router.push('/router-alias/'+alias)注意:数据模版类似的,把
form换成template
2、系统菜单没有配置【不推荐使用,刷新页面没有加载回来】
2.1) 、表单脚本编写
Object.assign(JForm, {
  // 表单按钮前置事件
  beforeSubmit: async function(form, action, postValue, callback) {
    // 添加到菜单路由中
    const alias = 'xsxxb' // 在菜单资源唯一的别名
    await form.$store.dispatch('iform/menu/addLinkRouter', {
      title: 'tab标题',
      name: alias
    })
    const config = {
      id: 'xxx', // 随机id
      openType: 'tab',
      type: 'dataTemplate',
      bind_template_key: 'xsxxb'// 数据模版别名
    }
    const itemId = '_' + config.id
    const data = JSON.stringify({
      config: config
    })
    localStorage.setItem(itemId, data)
    // 跳转
    form.$router.push({
      path: '/form/linkPage/index',
      query: {
        _itemId: itemId
      }
    })
    callback(true)
  }
})
数据模版类似的,把
form换成template
5.15 、自定义按钮如何下载系统的附件
方案一:采用直接请求下载【推荐该方案】
v3.5.0 +版本支持,this.$actionUtils
      const baseUrl = form.$store.getters.baseApi
      const token = form.$utils.cookies.get('token')
      const fileId = '920375097598935040'
       //方案一:
      const url = baseUrl +'/platform/v3/file/download?attachmentId='+fileId+'&access_token='+token
     this.$actionUtils.open(url)v3.5.0- 的 旧版本 采用以下脚本
      const baseUrl = form.$store.getters.baseApi
      const token = form.$utils.cookies.get('token')
      const fileId = '920375097598935040'
       //方案一:
      const url = baseUrl +'/platform/v3/file/download?attachmentId='+fileId+'&access_token='+token
     const a = document.createElement('a')
        a.setAttribute('href', url)
        a.setAttribute('target', '_blank')
        a.setAttribute('id', 'iform-open-link')
        document.body.appendChild(a)
        a.click()
        document.body.removeChild(a)数据模版类似的,把
form换成template
方案二:采用$request请求下载
该方案缺点:要自己写文件输出文件的名字
v3.5.0 +版本支持,this.$actionUtils
  const fileName = '学生模版.xml'
  const fileId = '920375097598935040'
this.$request({
          url:'/platform/v3/file/download?attachmentId='+fileId,
          method: 'get',
          responseType: 'arraybuffer'
      }).then(response => {
          const data = response.data
          this.$actionUtils.download(data,fileName)
      }).catch(error => {
        console.log(error)
      })
v3.5.0- 的 旧版本 采用以下脚本
  const fileName = '学生模版.xml'
  const fileId = '920375097598935040'
this.$request({
          url:'/platform/v3/file/download?attachmentId='+fileId,
          method: 'get',
          responseType: 'arraybuffer'
      }).then(response => {
      const data = response.data
         const blob = data instanceof Blob ? data : new Blob([data], { type: 'application/octet-stream' })
      const url = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.style.display = 'none'
      link.href = url
      link.setAttribute('download', fileName)
      document.body.appendChild(link)
      link.click()
      window.URL.revokeObjectURL(link.href)
      document.body.removeChild(link)
      }).catch(error => {
        console.log(error)
      })5.16 、怎么调用后端的groovry 方法
var vars ={} //传的参数,选填
this.$request({
      //此url请求地址是在后端单体部署,微服务需改成/business/v3/form/def/getScriptValue
         url:'/form/def/getScriptValue',
          method: 'post',
          data:  {
            'script': `写的后端的脚本`,
            'vars': vars
          }
      }).then(response => {
           //TODO:你处理的回调的逻辑
      }).catch(error => {
      })参数传递说明:
例如后端的脚本
cscript.testScript(gender)
5.17 、自定义按钮怎么调用自定义弹窗
1、【最新版本】有这个代码组件,可以直接引用
2、如果【v3.5.1-】以下的版本没有该代码,需要把src\business\platform\data\templaterender\custom-dialog\dialog.vue代码复制到src\views\platform\data\custom-dialog\dialog.vue路径下
注意:
①、templateKey请根据实际的自定义对话框的key修改
②、点击确定按钮请根据数据处理data数据
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
    //注册自定义对话框
    this.$vue.component('iform-customdialog-dialog', this.$import('/platform/data/custom-dialog/dialog.vue'))
  },
  customDialogTemplate: function(form) {
    return this.$vue.extend({
      data() {
        return {
          visible: true,
          templateKey:'dhklb06'//请根据实际的自定义对话框的key
        }
      },
      methods: {
        handleActionEvent(buttonKey, data) {
          debugger
          switch (buttonKey) {
            case 'ok':// 确定
              // TODO:根据实际处理data数据
              alert(data)
              this.closeDialog()
              break
            case 'cancel':// 取消
              this.closeDialog()
              break
          }
        },
        closeDialog() {
          this.visible = false
        }
      },
      render() {
        var h = arguments[0]
        return h('iform-customdialog-dialog', {
          'attrs': {
            visible: this.visible,
            templateKey: this.templateKey
          },
          on: {
            close: this.closeDialog,
            'action-event': this.handleActionEvent
          }
        })
      }
    })
  },
  // 表单按钮前置事件
  beforeSubmit: function(form, action, postValue, callback) {
    if (action === 'test1') {
      form.dialogTemplate = this.customDialogTemplate(form)
    }
    callback(true)
  }
})
扩展应用,可以弹窗其他弹窗
eg:流程表单窗口:弹窗组件:/platform/bpmn/form/template-form.vue
5.18 、 如何引用第三方 JS 资源
请特别注意,要保证安全后调用。可参考以下代码:
5.18.1、第三方CDN地址:
   loadAssets() {
    this.loadScript('https://www.goat1000.com/tagcanvas.min.js', () => {
      // your code  具体的业务代码
    });
  },
      loadScript(src, callback) {
    if (!src) {
      return;
    }
    const node = document.createElement('script');
    node.crossOrigin = 'crossOrigin';
    node.src = src;
    node.addEventListener('load', callback, false);
    document.head.appendChild(node);
  }5.18.2、本地地址:该地址必须放在public的路径下
   loadAssets(form) {
     const baseUrl = form.$baseUrl
    this.loadScript(baseUrl+'/lib/UEditor/ueditor.all.min.js', () => {
      // your code  具体的业务代码
    });
  },
      loadScript(src, callback) {
    if (!src) {
      return;
    }
    const node = document.createElement('script');
    node.crossOrigin = 'crossOrigin';
    node.src = src;
    node.addEventListener('load', callback, false);
    document.head.appendChild(node);
  },5.19 子表通过某个条件禁用字段
V3.5.5+例子
Object.assign(JForm,{ //加载事件 onLoad:function(form){ form.getRefsField('cs1').$watch('dataModel',(data)=>{ setTimeout(() => { data.forEach((ele,i)=>{ const ziDuan1 = ele.ziDuan1 const index=i*3 if(ziDuan1==='1'){ form.$set(form.getRefsField('cs1').$refs.formItem1ziDuan2[index].$children[0].$children[1].$children[0]._props,'disabled',true) form.$set(form.getRefsField('cs1').$refs.formItem1ziDuan2[index].$children[0].$children[1].$children[0],'disabled',true) }else{ form.$set(form.getRefsField('cs1').$refs.formItem1ziDuan2[index].$children[0].$children[1].$children[0]._props,'disabled',false) form.$set(form.getRefsField('cs1').$refs.formItem1ziDuan2[index].$children[0].$children[1].$children[0],'disabled',false) } }) },300) },{ deep: true }) } })
—– 设置了禁用点击后还是无法禁用
 单选按钮要再禁用click属性组件
   form.$set(form.getRefsField('ziDuan02'),'disabled',true)
   form.$set(form.getRefsField('ziDuan02').$children[0],'disabled',true)5.20 子表级联保存后回填的例子
V3.5.4-例子
首先在对应的级联的表单的后置事件
Object.assign(JForm,{
 //表单按钮后置事件
  afterSubmit:function(form,action,postValue,callback){
      if(action === 'save'){
    //增加保存后的"保存回调"事件
    form.$emit('save-callback',postValue)
    }
    callback(true) 
  }
});Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
      //对应的子表
    const zb = form.getRefsField('z1byzsj1')
    zb.$watch('cascadeDialogVisible', (visible) => {
      if (visible) {
        setTimeout(() => {
         //监听对应的子表的级联的“保存回调”事件
         zb.$refs.cascadeDialog.$children[0].$children[0].$refs.formrender.$on('save-callback', (data) => {
              //TODO:级联回调,赋值给指定控件的值
                console.info(data)
          })
        }, 2000)
      }
    })
  }
})
V3.5.4+例子
Object.assign(JForm,{
  //加载事件
  onLoad:function(form){
    // z1byzsj1  是子表的字段
    form.getRefsField('z1byzsj1').$refs.cascadeDialog.$on('callback',(flag, params)=>{
        const data = params.formData
       //TODO:级联回调,赋值给指定控件的值
        console.info(data)
    })
  }
});5.21 监听子表中输入框的input等事件
v3.5.6-例子
首先在对应的级联的表单的后置事件
Object.assign(JForm,{
  //加载事件
  onLoad:function(form){
   //cs2为子表的key
   const tableKey = 'cs2'
   const tableForm=form.getRefsField(tableKey)
   //tableForm.mode为子表的类型
   const mode=tableForm.mode
   //createBy为控件的字段
   const key = 'createBy'
   const prefix='formItem'
   const refKey =`${prefix}${key}`
   //子表编辑模式为块模式
    if(mode==='block'){
         if(tableForm.getRefs&&tableForm.getRefs(key,prefix)){
           tableForm.getRefs(key,prefix).forEach((ele,index)=>{
                 const field = tableForm.getRefs(key,prefix)[index].$refs[refKey].$refs.formField
             field.$children[0].$on('input',(data)=>{
              console.log('block')
             })
           })
         }
     }
     //子表编辑模式为表内编辑模式
    if(mode==='inner'){
        tableForm.getRefs(key,prefix).forEach((ele,index)=>{
              const field = tableForm.getRefs(key,prefix)[index].$children[0].$children[1]
          field.$children[0].$on('input',(data)=>{
             console.log('inner')
          })
       })
    }
   //子表编辑模式为表内弹窗模式
   if(mode==='dialog'){
        form.getRefsField(tableKey).$children[0].$on('click',(data)=>{
        setTimeout(() => {
           const filed = tableForm.$children[4].$refs.formrender.$refs.dynamicForm.$refs[refKey][0].$refs.formField
           filed.$children[0].$on('input',(data)=>{
            console.log('dialog')
           })
         },300)
       })
   }
  },
 //表单子表按钮后置事件
  afterSubButton:function(tableForm,action,position,params,callback){
    //cs2为子表的key
      if(tableForm.code==='cs2'){
         const tableKey = 'cs2'
         const dataModel=tableForm.dataModel
         const mode=tableForm.mode
         const key = 'createBy'
         const prefix='formItem'
         dataModel.forEach((ele,item)=>{
           let itemKey =`${prefix}${item}`
           let refKey =`${prefix}${key}`
           //子表编辑模式为块模式
           if(mode==='block'){
                const filed = tableForm.getRefs(key,prefix)[item].$refs[refKey].$refs.formField
                filed.$children[0].$on('input',(data)=>{
                    console.log('block')
                })
            //子表编辑模式为表内编辑模式
           }else if(mode==='inner'){
                const field = tableForm.getRefs(key,prefix)[item].$children[0].$children[1]
                field.$children[0].$on('input',(data)=>{
                    console.log('inner')
                })
           }
         })
    }
   callback(true)
  }
})5.22 表单数据不同条件按钮显示不同
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
      //复制原有的按钮数据
      const buttons = this._.cloneDeep(form.$parent.buttons)
   //清空所有
   form.$parent.buttons.splice(0)
    form.$refs.dynamicForm.$watch('models.faWenZiHao', (data) => {
       //清空所有
     form.$parent.buttons.splice(0)
      form.$parent.buttons.push(buttons[0])
      form.$parent.buttons.push(buttons[1])
      if (data === '1') {
        form.$parent.buttons.push(buttons[2])
      } else if (data === '2') {
        form.$parent.buttons.push(buttons[3])
      } else if (data === '3') {
        form.$parent.buttons.push(buttons[4])
      }
    }, {
          immediate: true,
      deep: true
    })
  }
})
5.23 流程不同节点设置当前用户签名默认值脚本
Object.assign(JForm, {
  // 加载事件
  onLoad: function(form) {
    const nodeId = form.$parent.formParams.nodeId
    if (nodeId === 'Activity_0nms7ey' && form.$utils.isEmpty(form.getData('aQianMing'))) { // 节点A
          this.getSignature((id) => {
        // 设置节点A的签名A的值
        form.setData('aQianMing', id)
        })
    }
    if (nodeId === 'Activity_1pgfyix' && form.$utils.isEmpty(form.getData('bQianMing'))) { // 节点B
          this.getSignature((id) => {
        // 设置节点B签名B的值
        form.setData('bQianMing', id)
        })
    }
      if (nodeId === 'Activity_0rsi1aj' && form.$utils.isEmpty(form.getData('cQianMing'))) { // 节点C
          this.getSignature((id) => {
           // 设置节点C的签名C的值
        form.setData('cQianMing', id)
        })
    }
  },
  // 获取当前用户的签名
  getSignature(callback) {
    this.$request({
      url: '/platform/v3/party/signature/getDefault?type=picture&last=false',
      method: 'get'
    }).then(response => {
      // 处理数据返回的逻辑
      callback(response.data.attaId)
    }).catch(error => {
      console.log(error)
    })
  }
})
5.23 报表控件点击按钮请求接口更新数据(支持版本v3.5.7+)
Object.assign(JForm,{
 //表单按钮前置事件
  beforeSubmit:function(form,action,postValue,callback){
    //danXing10为控件对象
    const danXing10=form.getData('danXing10')
    const formData= {danXing10:danXing10}
    this.$request({
      url:'/platform/v3/desktop/facade/demo/pie/chart',
      method: 'get',
      params: formData
    }).then(response => {
      //TODO:处理数据返回的逻辑
      //histogram_1l5ig6j为报表控件字段标识,获取报表控件的实例
      const histogram = form.getRefsField('histogram_1l5ig6j')
      //处理返回数据
      const params = eval('(' + response.data + ')') 
      //更新报表控件的数据
      histogram.updataEchartsOption(params)
    }).catch(error => {
      console.log(error)
    })
   }
});
5.24 选项值不同隐藏或显示不同tabs
Object.assign(JForm,{
  //加载事件
  onLoad:function(form){
    //获取该字段的字段默认定义,比如该字段为第3(数组-1)字段
    const tabIndex = 2
    const defField = JSON.parse(JSON.stringify(form.formDefData.fields[tabIndex]))
        //  xxxx :表示字段名
    form.$refs.dynamicForm.$watch('models.xxxx',(data)=>{
       if(data === '1'){
        const field = JSON.parse(JSON.stringify(defField))
        //删除 Tabs选项
             field.field_options.columns.splice(1,1)
        form.formDefData.fields.splice(tabIndex, 1, field)
       }else{
         //还原 Tabs选项
        form.formDefData.fields.splice(tabIndex, 1, JSON.parse(JSON.stringify(defField)))
       }
        })
  }
});5.25 日期控件增加禁用日期和快捷方式(3.6.0+)
// 找到字段
  const zd1 = form.getRefsField('zd1')
    const _this = this
// 设置属性
    form.$set(zd1.fieldAttrs,'pickerOptions',{
      disabledDate(time){
       // 例子1:禁用表单另外个字段的只之前的日期
         const   zd2 =  form.getData('zd2')
      if(form.$utils.isEmpty(zd2)){ return false }
      const date=  _this.fecha.parse(sj,'yyyy-MM-dd')
      return time.getTime() < date.getTime();
      // 例子2:禁用今天之前的所有日期
      const today = new Date();
      today.setHours(0, 0, 0, 0); // 设置时间为当天的开始
      return time.getTime() < today - 86400000; // 减去一天的时间戳 (24 * 60 * 60 * 1000)
      }
        })5.26 值来源的下拉联动数据
  //加载事件
  onLoad:function(form){
   // 需要监听的字段 把a1 换成你具体的字段
   const field =  form.getRefsField('a1')
   field.$children[0].$on('change',(data)=>{
     // 获取选择的数据值来源 ajaxOptionMap
        const selectData = field.ajaxOptionMap[data]
     console.info(selectData)
     debugger
     //设置值
     form.setData('xxx',selectData.abc)
   })
  }最后编辑:hugh 更新时间:2025-10-24 18:04



