七巧低代码表单JS脚本教学

七巧低代码前端表单JS脚本教学(原理详解版)

📘 基于官方文档核对,重点讲清"为什么这样写、能拿到什么、方法之间有什么差异"


一、先搞懂几个核心概念(不看会一直懵)

1.1 ⚠️ 这里的 this 和 Vue 里的 this 不是一回事

这是新手最容易踩的第一个坑。你如果写过 Vue,会习惯性地以为 this 能访问组件里的响应式变量。在七巧页面JS里不行。

官方文档原话:页面JS事件扩展的 this 区别于 Vue 中 this 的概念,不能访问到任何应用组件中的响应式变量,与系统 Vue 组件是解耦的。

那要访问/修改应用数据怎么办? 必须通过七巧暴露的 API(this.contextthis.businessthis.utils)来访问,不能直接 this.某变量

javascript 复制代码
// ❌ 错误:Vue习惯,这里访问不到
export function mounted() {
    this.表单数据 = '123';  // 没用,访问不到
}

// ✅ 正确:通过API访问
export function mounted() {
    this.context.form.setFormData({ '单行文本1': '123' });
}

1.2 为什么函数前面必须有 export

官方文档明确:若希望编辑器中的脚本能被动作面板引用到,必须要保证函数前使用了 export 标识,否则配置时会看不到对应的函数出现在动作面板中,实际运行时也会报错。

简单说:不写 export,你在动作面板里就选不到这个函数,配了也不执行。这是固定要求

javascript 复制代码
// ❌ 没加export,动作面板里看不到,配了也不执行
function mounted() { ... }

// ✅ 加了export,动作面板里能选到
export function mounted() { ... }

1.3 三个核心API模块的分工

七巧把前端API分成三块,各管各的,不要混用:

模块 能做什么 例子
this.utils 工具类 + UI交互(和业务无关) dayjs处理日期、axios发请求、Message弹提示
this.business 业务接口(深度交互七巧应用) 调后端自定义函数、打开弹窗
this.context 访问当前页面的系统数据 读表单数据、改表单数据、拿流程信息

记忆方法:utils是"工具箱"(通用工具),business是"业务通道"(和后端打交道),context是"当前环境"(拿系统数据)。

1.4 ⚠️ 表单类API不能在所有地方用(第二个大坑)

官方文档明确:表单类的上下文都必须要在表单相关的场景 中使用,不能在页面的 mounted 中使用该API,否则会返回空

什么意思?

  • 在"表单新增/编辑/详情页"里 → 可以用 this.context.form.getFormData() 拿到表单数据。
  • 在"普通列表页/自定义页面"的 mounted 里 → 用 getFormData() 会返回空,因为此时根本没有打开表单。

所以在写脚本前,先想清楚:这个脚本运行在什么场景?这个场景下能不能拿到表单数据?


二、脚本入口和事件函数

2.1 几个核心事件:什么时候触发、能拿到什么参数

七巧前端JS就是写一堆 export function 事件名(参数) 的函数,由系统在对应时机调用。每个事件的参数不同,下面逐个讲清。

mounted() ------ 页面/表单加载完成时触发
  • 参数:无
  • 能做什么:初始化数据、设置默认值、调用后端接口
  • 注意:如果是在普通页面(非表单)的mounted里,不能调表单API,会返回空
javascript 复制代码
export function mounted() {
    // 表单加载完成,设置默认值
    this.context.form.setFormData({ '创建日期': this.utils.dayjs().format('YYYY-MM-DD') });
}
onChange({field, value}) ------ 表单字段值变化时触发
  • 参数为什么这样写 :用解构 {field, value} 是因为系统传入的是一个对象,里面有两个属性。field 是变化字段的名字,value 是新值。
  • 能做什么:监听某字段变化,触发联动计算、调用后端
javascript 复制代码
export function onChange({field, value}) {
    // field = 变化的字段名,value = 新值
    if (field === '单价') {
        // 单价变了,重新计算小计
    }
}
onClick({button, selectedIds}) vs onClick({button, row}) ------ 列表按钮点击

这里有个容易混的点 :同样是 onClick,但参数不同,取决于按钮位置:

按钮位置 参数 能拿到什么
列表顶部操作栏按钮 {button, selectedIds} button是按钮配置,selectedIds是选中的行ID数组
列表行内按钮 {button, row} button是按钮配置,row是当前点击那行的完整数据

为什么不同? 顶部按钮是"先勾选多行再批量操作",所以给你的是ID数组;行内按钮是"点哪行操作哪行",所以直接给你那一行数据。

javascript 复制代码
// 顶部按钮:批量操作
export function onClick({button, selectedIds}) {
    // selectedIds = ['id1', 'id2', 'id3']  勾选的行ID
    if (selectedIds.length === 0) {
        this.utils.Message({ message: '请先选择数据' });
        return;
    }
}

// 行内按钮:单行操作
export function onClick({button, row}) {
    // row = { 字段1: '值1', 字段2: '值2' }  当前行的完整数据
    console.log('点了这行:', row);
}

三、this.context ------ 访问和修改系统数据

这是最常用、也最容易出错的模块。核心要分清:哪些是只读的、哪些能改、改了怎么生效。

3.1 表单数据的三件套:getFormData / getFormInfo / setFormData

这三个是配套的,关系如下:

方法 能做什么 可读写 返回什么
getFormData() 拿当前表单的所有字段值 只读 对象 {字段名: 值}
getFormInfo() 拿当前表单的配置信息 只读 对象 {id, formDefinitionId, ...}
setFormData(数据) 修改当前表单的字段值 可写 -
getFieldData() 拿到当前表单的字段值 只读 -值

⚠️ getFormData 拿到的是只读的,不能直接改! 官方文档明确:直接修改会抛 Error。要改必须用 setFormData。

javascript 复制代码
export function mounted() {
    let formData = this.context.form.getFormData();
    // formData = { 单行文本1: '1', 数字1: '1', 人员多选1: ['id1','id2'] }
    
    let valueText = this.context.form.getFieldData('单行文本1');
		// valueText = '1'

    // ❌ 错误:直接改会报错
    // formData['单行文本1'] = '2';  // throw Error
    
    // ✅ 正确:用setFormData改
    this.context.form.setFormData({ '单行文本1': '2' });
}

setFormData 的一个重要特性 :它会自动过滤表单里不存在的字段。你传了一个表单里没有的字段名,不会报错,但也不会生效。所以字段名必须和表单设计器里的完全一致。

setFormData 数据类型要匹配:字符串字段就传字符串,数组字段(如多选)就传数组,否则可能不生效。

javascript 复制代码
export function mounted() {
    // ✅ 正确:类型匹配
    this.context.form.setFormData({
        '单行文本1': '张三',        // 文本字段传字符串
        '数字1': 100,              // 数字字段传数字
        '人员多选1': ['id1','id2']  // 多选字段传数组
    });
}

3.2 getFormData vs getFormInfo:拿数据 vs 拿配置

新手经常分不清这两个:

方法 拿到的是 里面有啥 什么时候用
getFormData() 表单的业务数据 各字段的值(姓名、金额等) 要读字段值时
getFormInfo() 表单的配置/元信息 文档ID、表单建模ID、按钮类型等 要拿文档ID、判断新增/编辑状态时
javascript 复制代码
export function mounted() {
    // 拿业务数据(字段值)
    let formData = this.context.form.getFormData();
    let name = formData['姓名'];  // "张三"
    
    // 拿配置信息
    let formInfo = this.context.form.getFormInfo();
    let docId = formInfo.id;              // 当前数据ID
    let btnType = formInfo.btnType;       // 按钮类型(判断新增/编辑/详情)
}

3.3 context.inputs ------ 拿控件配置(只读)

  • 能拿到什么:表单里所有控件的配置信息数组,每个控件一项,包含字段id、字段名、权限等。
  • 什么时候用:需要根据字段权限做逻辑判断时。
javascript 复制代码
export function mounted() {
    let inputs = this.context.inputs;
    // [
    //   { id: 'xxx', filedName: '姓名', permission: 'w' },
    //   { id: 'yyy', filedName: '金额', permission: 'r' }
    // ]
}

3.4 context.processInfo ------ 拿流程信息(只读)

  • 能拿到什么:流程实例ID、流程定义ID等流程配置。
  • 什么时候用:在流程详情页做流程相关逻辑时。
  • 注意:只有在流程相关场景才有值,普通表单里拿不到。
javascript 复制代码
export function mounted() {
    let processInfo = this.context.processInfo;
    // { processInstanceId: '流程实例id', definitionId: '流程定义id' }
}

3.5 this.params ------ 动作面板传参

  • 能拿到什么:在动作面板里配置的参数。
  • 为什么需要:一个函数可以被多个按钮复用,用 params 区分是哪个按钮触发的。
javascript 复制代码
// 在动作面板里给不同按钮配不同的 params,比如 {type: 'top'} 和 {type: 'inline'}
export function onClick() {
    let params = this.params;
    if (params.type === 'top') {
        // 顶部按钮的逻辑
    } else if (params.type === 'inline') {
        // 行内按钮的逻辑
    }
}

四、this.business ------ 调后端接口(三个方法的区别)

这里有三个方法都能调后端,新手完全分不清。对比一下:

方法 调什么 推荐程度 区别
excuteCustomAPI 自定义页面的服务端接口 ❌ 不推荐 官方说很快会被替换
executeServiceAPI 应用级自定义函数 ✅ 推荐 最常用,调当前应用里的自定义函数
executeGlobalServiceAPI 全局自定义函数 ✅ 推荐 调基础设置里定义的全局函数
openDialog 打开弹窗 - PC端专用

excuteCustomAPI 和 executeServiceAPI 的区别

  • excuteCustomAPI 调的是"自定义页面"里定义的接口(旧方式,要被淘汰)
  • executeServiceAPI 调的是"自定义函数"里定义的接口(新方式,推荐)
  • 两者参数也不同:前者要传 businessId,后者要传 customJsId

4.1 executeServiceAPI(最常用,重点讲)

  • 能做什么:调用当前应用里"自定义函数"中定义的后端方法。
  • 参数为什么这样传
参数 类型 为什么需要
applicationId String 告诉系统在哪个应用里找自定义函数
customJsId String 告诉系统调哪个自定义函数脚本(一个应用可能有多个脚本)
methodName String 告诉系统调这个脚本里的哪个方法
params Array 传给后端方法的参数,按顺序对应后端函数的形参

customJsId 怎么拿? 官方文档说:需要通过F12控制台获取。在表单脚本里打印 this 查看。

javascript 复制代码
export async function mounted() {
    let result = await this.business.executeServiceAPI({
        applicationId: '当前应用id',        // 哪个应用
        customJsId: '自定义函数脚本id',      // 哪个脚本(F12获取)
        methodName: 'getData',              // 调哪个方法
        params: ['参数1', '参数2']           // 传什么参数(数组,按顺序对应)
    });
    console.log(result);  // 后端方法的返回值
}

后端自定义函数怎么写(这是配套的):

javascript 复制代码
// 在"自定义函数"里定义
var API = {
    // 方法名要和前端的 methodName 对应
    // 形参要和前端 params 数组里的顺序对应
    getData: function(param1, param2) {
        // 这里能用服务端API($.context、$.form等)
        var doc = $.context.getCurrentDocument();
        // ...
        return { success: true, data: '结果' };  // 返回值就是前端 result
    }
};

4.2 executeGlobalServiceAPI ------ 调全局函数

  • 和 executeServiceAPI 的区别 :全局函数定义在"基础设置"里,不属于某个应用,所以不需要传 applicationId 和 customJsId
  • 什么时候用:调跨应用通用的函数(如统一的用户查询、统一的审批逻辑)。
javascript 复制代码
export async function mounted() {
    let result = await this.business.executeGlobalServiceAPI({
        methodName: 'hello',              // 只需要方法名
        params: ['参数1', '参数2']         // 和参数
    });
}

4.3 openDialog ------ 打开弹窗(PC端专用)

javascript 复制代码
export function onClick() {
    this.business.openDialog({
        // 弹窗配置
    });
}

五、this.utils ------ 工具箱

这些是通用工具,和业务无关。重点讲清 Message 和 MessageBox 的区别。

5.1 Message vs MessageBox:提示 vs 模态框

这两个最容易混:

方法 是什么 交互方式 适用场景
this.utils.Message(配置) 顶部提示条 自动消失,不阻塞 简单提示"操作成功"
this.utils.MessageBox(配置) 模态对话框 需要用户点确认/取消 需要用户确认的操作
javascript 复制代码
// Message:简单提示,自动消失
this.utils.Message({ message: '保存成功' });

// MessageBox:需要用户确认(返回Promise)
this.utils.MessageBox({
    title: '确认操作',
    message: '确定要删除吗?'
}).then(() => {
    // 用户点了确认
}).catch(() => {
    // 用户点了取消
});

5.2 dayjs ------ 日期处理

完整的dayjs功能都有,参考 https://dayjs.fenxianglu.cn/

javascript 复制代码
let today = this.utils.dayjs().format('YYYY-MM-DD');
let tomorrow = this.utils.dayjs().add(1, 'day').format('YYYY-MM-DD');

5.3 axios ------ 发HTTP请求

  • 特性:请求七巧内部接口时会自动带 token,无需额外鉴权;请求外部接口要自己处理鉴权。
javascript 复制代码
export async function mounted() {
    // 内部接口(自动带token)
    let res1 = await this.utils.axios({
        method: 'get',
        url: 'bpms-runtime/form',
        params: { id: 123 }
    });
    
    // 外部接口(自己鉴权)
    let res2 = await this.utils.axios({
        method: 'get',
        url: 'https://外部接口地址'
    });
}

5.4 loadScript ------ 加载第三方JS库

用Promise封装,async/await 调用:

javascript 复制代码
export async function mounted() {
    await this.utils.loadScript('https://cdn地址/库.js');
    // 加载完成后可以用这个库
}

5.5 Vue ------ Vue引用

暴露Vue引用,用于高级定制(如用createElement渲染自定义内容):

javascript 复制代码
const createVueElement = new this.utils.Vue().$createElement;
this.utils.MessageBox({
    message: createVueElement('div', {}, '自定义内容')
});

六、实战案例(每个都讲清为什么这样写)

6.1 新增时设置默认值

为什么这样写:要先判断是不是新增状态(通过 formInfo.btnType),只有新增才设默认值,否则编辑时也会覆盖已有数据。

javascript 复制代码
export function mounted() {
    let formInfo = this.context.form.getFormInfo();
    
    // 判断新增状态(PC端是addbtn,移动端是add)
    if (formInfo.btnType === 'addbtn' || formInfo.btnType === 'add') {
        this.context.form.setFormData({
            '创建日期': this.utils.dayjs().format('YYYY-MM-DD'),
            '状态': '草稿'
        });
    }
}

6.2 字段联动计算

为什么这样写:onChange 触发时,value 是变化后的新值,但其他字段值要用 getFormData 拿。

javascript 复制代码
export function onChange({field, value}) {
    if (field === '单价' || field === '数量') {
        let formData = this.context.form.getFormData();
        let price = parseFloat(formData['单价']) || 0;
        let quantity = parseFloat(formData['数量']) || 0;
        
        this.context.form.setFormData({
            '小计': price * quantity
        });
    }
}

6.3 调后端并回填表单

为什么这样写:前端拿不到用户信息等系统数据,必须调后端获取。后端返回结果后用 setFormData 回填。

javascript 复制代码
export async function onChange({field, value}) {
    if (field === '客户选择') {
        // 调后端拿客户详情
        let result = await this.business.executeServiceAPI({
            applicationId: '应用ID',
            customJsId: '脚本ID',
            methodName: 'getCustomerInfo',
            params: [value]   // value是选中的客户ID
        });
        
        if (result && result.data) {
            // 回填到表单
            this.context.form.setFormData({
                '客户名称': result.data.name,
                '客户电话': result.data.phone
            });
        }
    }
}

6.4 列表批量操作(顶部按钮)

为什么这样写:顶部按钮给的是 selectedIds(ID数组),要先判断有没有勾选数据,确认后调后端批量处理。

javascript 复制代码
export async function onClick({button, selectedIds}) {
    if (selectedIds.length === 0) {
        this.utils.Message({ message: '请先选择数据' });
        return;
    }
    
    // 确认对话框
    this.utils.MessageBox({
        title: '确认',
        message: `处理选中的${selectedIds.length}条数据?`
    }).then(async () => {
        let result = await this.business.executeServiceAPI({
            applicationId: '应用ID',
            customJsId: '脚本ID',
            methodName: 'batchProcess',
            params: [selectedIds]   // 把ID数组传给后端
        });
        
        if (result && result.success) {
            this.utils.Message({ message: '处理成功' });
        }
    });
}

6.5 调试:不知道表单数据长什么样

javascript 复制代码
export function mounted() {
    let formData = this.context.form.getFormData();
    console.log('表单数据:', formData);
    
    let formInfo = this.context.form.getFormInfo();
    console.log('表单配置:', formInfo);
    console.log('按钮类型:', formInfo.btnType);
}

附录:完整 API 速查表

事件

事件 参数 触发时机
mounted() 页面/表单加载完成
onChange({field, value}) field:字段名, value:新值 表单字段变化
onClick({button, selectedIds}) button:按钮配置, selectedIds:ID数组 列表顶部按钮
onClick({button, row}) button:按钮配置, row:行数据 列表行内按钮

this.context

API 能拿到什么 可读写
form.getFormData() 表单字段值 只读(直接改会报错)
form.getFormInfo() 表单配置(ID、按钮类型等) 只读
form.setFormData(数据) 修改表单字段值 可写
inputs 控件配置列表 只读
processInfo 流程信息 只读
this.params 动作面板配置的参数 只读

this.business

API 能做什么 和谁区别
excuteCustomAPI 调自定义页面接口 ❌不推荐,要被替换
executeServiceAPI 调应用级自定义函数 ✅推荐,要传applicationId+customJsId
executeGlobalServiceAPI 调全局自定义函数 不需要传applicationId
openDialog 打开弹窗 PC端专用

this.utils

API 能做什么 和谁区别
Message(配置) 顶部提示,自动消失 简单提示用这个
MessageBox(配置) 模态框,需确认 需要确认用这个
dayjs() 日期处理 -
axios(配置) HTTP请求 内部接口自动带token
loadScript(url) 加载第三方库 Promise封装
Vue Vue引用 高级定制用

官方文档参考


📘 文档版本 :v4.0(原理详解版)

📅 更新日期 :2026-08-06

🎯 改进重点:每个API都讲清"为什么这样写、能拿到什么、和相似方法的区别"

相关推荐
似璟如你1 小时前
Java 开发者的 Go 语法基础:从 0 开始快速上手 Go
java·开发语言·后端·golang·go·编程语言
LccKyI1 小时前
C#学习day05(开发福彩双色球系统附思维导图)
开发语言·学习·c#
zzz_23681 小时前
TencentDB-Agent-Memory 深度解析:让多个 Agent 共享项目经验的记忆中枢
java·开发语言·jvm·人工智能·agent·memory·tencent db
vx-程序开发2 小时前
django医院预约挂号系统---附源码23353
java·javascript·spring boot·python·eclipse·django·php
charlie1145141912 小时前
IMX6ULL WM8960 的移植——前置介绍
开发语言·c++·开源项目·嵌入式linux
宿6742 小时前
tsconfig.node.json
前端·javascript·vue.js
迷迭香yy2 小时前
Python实战:涨停板“假封板”识别系统的工程实现
开发语言·人工智能·python
charlie1145141912 小时前
Cinux是如何管理进程的 —— 上下文与调度
开发语言·c++·操作系统·开源项目
lilian2333 小时前
Harmony os 技术实战|拼豆制图10:把取消、解析失败和保存失败写成可恢复状态机
java·javascript·华为·harmonyos