七巧低代码服务端脚本使用方法

七巧低代码服务端脚本语法教学(原理详解版)

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


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

写脚本之前,必须先分清这几个对象,否则后面所有代码都是"抄了不知道为什么"。

1.1 应用 / 表单 / 文档 的关系

  • 应用(application):七巧里一个独立的应用,每个应用有自己的ID(appId)。同一套表单名在不同应用里可能都存在,所以几乎所有的数据操作API都要求传 appId,用来定位"在哪个应用里操作"。
  • 表单(form):表单设计器里建的那个表单模型,比如"采购订单"、"采购明细"。它是一个"模板/结构定义"。
  • 文档(document):表单的一条实际数据记录。比如张三提交的那一张采购订单,就是一个 document。脚本里操作的大部分对象都是 document,不是 form。

一句话:表单是结构,文档是数据。你读字段、改字段,操作的都是某一条文档(document),不是表单模型本身。

1.2 主表文档 vs 子表单文档

  • 主表文档:一张主表里的某一条数据,比如一条采购订单。
  • 子表单文档:主表里"子表单控件"里的某一行数据,比如采购订单里的某一行采购明细。
  • 子表单文档也是 document,只是它附属于某个主表文档,通过外键字段关联。

1.3 ⚠️ "当前文档" vs "原始文档"(最容易搞混,必须看懂)

这是新手最容易踩坑的地方。七巧里有两个API都能拿到 document,但它们拿到的根本不是同一个东西

API 拿到的是什么 典型场景
$.context.getCurrentDocument() 当前正在编辑/操作的那张表单文档 表单事件里改自己表单的字段
$.context.getHttpRequest().getAttribute("document") 触发这次按钮点击的那条原始数据 列表按钮:从A表生成B表,A表那条就是原始文档

举个具体场景帮你看懂:

场景:在"采购订单"列表页,每条订单后面有个"生成入库单"按钮。点这个按钮后,七巧会打开"入库单"的新增表单。

  • 此时 $.context.getCurrentDocument() 拿到的是 "入库单"(你正在填的那张表)。
  • $.context.getHttpRequest().getAttribute("document") 拿到的是 "采购订单"(你刚才点按钮的那条数据)。

如果你要改入库单的字段,用 getCurrentDocument。如果你要读采购订单的数据复制过来,必须用 getHttpRequest().getAttribute("document")。用错了就拿到错误的数据。

记忆方法:getCurrentDocument = "我正在编辑的表";getHttpRequest().getAttribute("document") = "谁触发了我"。


二、脚本入口:为什么是 (function(){ ... })()

七巧服务端脚本必须包在这个立即执行函数里:

javascript 复制代码
(function(){
    // 你的代码
})()

为什么这样写? 这是平台要求的执行容器。七巧在服务端执行你的脚本时,是把这整段代码当作一个"任务"来跑的,IIFE 格式能保证你的变量不会污染全局作用域,也保证脚本一加载就立即执行。这是固定写法,所有服务端脚本都必须这样开头和结尾,不能改成别的形式。


三、$.context ------ 拿到当前环境信息

$.context 的作用是"拿到当前这次脚本执行的环境信息"。下面逐个讲清每个方法能拿到什么、什么时候用。

3.1 $.context.getCurrentApplicationId()

  • 能拿到什么:当前应用的ID(字符串)。
  • 为什么需要 :后面几乎所有 $.form 的操作都要传 appId,因为七巧是多应用架构,必须告诉系统在哪个应用里查/改数据。
  • 用法
javascript 复制代码
var appId = $.context.getCurrentApplicationId();

3.2 $.context.getCurrentDocument()

  • 能拿到什么:当前正在编辑/操作的那张表单的 document 对象。
  • 什么时候用:表单的按钮事件、字段校验、系统任务里,你要读/改当前表单的字段时。
  • 注意:在"列表按钮"场景里,这个拿到的是新打开的那张表单(比如入库单),不是你点的那条原始数据。原始数据要用下面的方法。
javascript 复制代码
var doc = $.context.getCurrentDocument();
var name = doc.getElementByName("姓名").getValue();

3.3 $.context.getHttpRequest().getAttribute("document")

  • 能拿到什么:触发这次操作的那条原始数据(document 对象)。
  • 什么时候用:只在"数据管理列表的自定义按钮"场景里用。当你需要从A表复制数据到B表时,A表那条就是用这个拿。
  • 和 getCurrentDocument 的区别:见第一章 1.3,这是两份不同的数据。
javascript 复制代码
var originalDocument = $.context.getHttpRequest().getAttribute("document");
var originalId = originalDocument.getId();  // 原始数据的ID

3.4 $.context.getCurrentUser() / $.context.getCurrentUserId()

  • 能拿到什么:getCurrentUser 拿到用户对象(含姓名、电话等),getCurrentUserId 只拿到用户ID字符串。
  • 区别:只想要ID就用后者更轻量;想要姓名、电话等详细信息就用前者。
javascript 复制代码
var userId = $.context.getCurrentUserId();          // 只要ID
var user = $.context.getCurrentUser();              // 要完整对象
var userName = user.getName();                      // 从对象里取姓名

四、Document 对象 ------ 读字段和改字段

拿到 document 之后,最常用的操作就是读字段值和改字段值。这里讲清各种读取方法的差异和修改方法的差异。

4.1 读取字段值:getValue / getIntValue / getDoubleValue / getFloatValue

所有读取方法都是 doc.getElementByName("字段名").xxxValue(),区别在返回类型:

方法 返回类型 什么时候用
getValue() String 或 JSONArray 通用方法。文本、人员、部门等所有控件都能用。多选控件返回的是数组
getIntValue() int 数字控件,且你需要整数参与运算时
getDoubleValue() double 数字控件,且你需要小数(金额类)参与运算时
getFloatValue() float 数字控件,float 类型

为什么数字要分三种? 因为数字控件在表单设计时可以配置成不同精度类型,对应后端不同数据类型。用错类型可能导致精度丢失或类型转换异常。如果拿不准,金额、数量类一律用 getDoubleValue() 最安全。

getValue 返回什么?

  • 单行文本、人员单选、部门单选 → 返回 String
  • 人员多选、部门多选 → 返回 JSONArray(数组),里面是用户ID/部门ID
javascript 复制代码
var doc = $.context.getCurrentDocument();

// 文本字段
var name = doc.getElementByName("姓名").getValue();        // "张三"

// 数字字段(金额用double)
var amount = doc.getElementByName("金额").getDoubleValue(); // 100.50

// 人员单选 → 用户ID字符串
var leader = doc.getElementByName("队长").getValue();       // "abc123..."

// 人员多选 → 用户ID数组
var members = doc.getElementByName("成员").getValue();      // ["id1","id2"]

4.2 ⚠️ 判空:为什么必须先判空再取值

getElementByName("字段名") 如果字段不存在或没值,会返回 null。如果直接 .getValue() 就会报空指针异常,整个脚本中断。

javascript 复制代码
// ❌ 错误:字段可能为null,直接取值会崩
var value = doc.getElementByName("可能不存在的字段").getValue();

// ✅ 正确:先判空
var element = doc.getElementByName("可能不存在的字段");
var value = element != null ? element.getValue() : null;

4.3 读取子表单:getSubDocuments

  • 能拿到什么 :子表单控件里的所有行,返回 List<Document>,每一行又是一个 document。
  • 注意 :这里拿到的是"当前文档自己的子表单"。如果你要拿"别的文档"的子表单,要用 $.form.getSubFormDocumentsByName(见第五章)。
javascript 复制代码
var doc = $.context.getCurrentDocument();
var subDocs = doc.getElementByName("明细").getSubDocuments();  // List<Document>

// 必须判空!子表单可能没数据
if (subDocs != null) {
    for (var i = 0; i < subDocs.size(); i++) {
        var row = subDocs.get(i);
        var productName = row.getElementByName("产品名称").getValue();
    }
}

4.4 修改字段值:addElement vs setValue

两种方式都能改字段值,区别:

方法 写法 区别
doc.addElement("字段名", 值) 直接在 document 上调用 官方文档里更常见的写法
doc.getElementByName("字段名").setValue(值) 先取字段元素再设值 适合"先读再改"的场景

两者效果一样,选哪个看习惯。但注意:在按钮执行前事件、系统任务里改了字段值,不需要自己调 saveFormDocument 保存,七巧会自动保存。手动再保存反而会报错(见下章)。

javascript 复制代码
var doc = $.context.getCurrentDocument();

// 方式一:addElement
doc.addElement("姓名", "张三");
doc.addElement("金额", 100);

// 方式二:setValue(效果一样)
doc.getElementByName("姓名").setValue("张三");

五、$.form ------ 表单数据的增删改查

这是最常用也最容易混乱的一组API。重点讲清四种查询方法的区别、保存时机的坑、子表单获取的参数含义。

5.1 创建空文档:createEmptyDocument

  • 能拿到什么:一张指定表单的空白文档对象,里面还没有任何数据。
  • 参数为什么这样传
    • 参数1 appId:在哪个应用里建。
    • 参数2 表单名:建哪种表单的数据。
  • 什么时候用:要往某张表单里新增一条数据时,先建空文档,再 addElement 填字段,最后 saveFormDocument 保存。
javascript 复制代码
var appId = $.context.getCurrentApplicationId();
var doc = $.form.createEmptyDocument(appId, "学生表");  // 建一张空白的学生表数据
doc.addElement("姓名", "张三");
doc.addElement("年龄", 24);
$.form.saveFormDocument(doc, appId);  // 必须保存才会真正入库

5.2 保存文档:saveFormDocument

  • 能做什么:把文档真正写入数据库。
  • 参数:doc(要保存的文档)、appId(在哪个应用里)。
  • ⚠️ 什么时候该调 / 什么时候不该调(这个坑很多人踩):
场景 要不要调 saveFormDocument 原因
自己 createEmptyDocument 新建的数据 要调 新建的文档不会自动入库
按钮执行前事件里改当前表单字段 不要调 七巧会自动保存,手动调会报错(表单有版本机制)
系统任务里改当前表单字段 不要调 同上,自动保存
javascript 复制代码
// ❌ 错误:按钮执行前事件里手动保存
var doc = $.context.getCurrentDocument();
doc.addElement("姓名", "张三");
$.form.saveFormDocument(doc, appId);  // 报错!系统已经会自动保存

// ✅ 正确:只改值,不保存
var doc = $.context.getCurrentDocument();
doc.addElement("姓名", "张三");
// 不调 saveFormDocument,系统自动保存

5.3 ⚠️ 四种查询方法的区别(重点看这个)

七巧有四个API都能查数据,新手完全分不清该用哪个。对比一下:

方法 怎么传条件 适用场景
getFormDocumentsByFieldNameAndValue(appId, 表单名, fieldMap) HashMap(字段名→值,等值匹配) 简单的"字段=值"查询
getDocumentsByCondition(appId, 表单名, conditionMap) HashMap(字段名→值) 和上面类似,等值查询
getDocumentsByFilterParam(appId, 表单名, filterParamList) FilterParam 列表(支持大于/小于/like等) 需要 ><likebetween 等复杂条件
getDocumentsByFormModelAndCondition(appId, formModel, fieldMap) 表单模型对象 + HashMap 先拿到表单模型再查,某些场景下更稳

怎么选?

  • 只需要"某字段等于某值"→ 用前两个,简单。
  • 需要"日期在某范围"、"金额大于某值"、"姓名模糊匹配" → 必须用 getDocumentsByFilterParam,因为它支持操作符。
  • getFormDocumentsByFieldNameAndValuegetDocumentsByCondition 功能基本一样,任选一个即可。

四种查询的代码对比:

javascript 复制代码
var appId = $.context.getCurrentApplicationId();

// 方法1:getFormDocumentsByFieldNameAndValue(等值查询)
var fieldMap = new Packages.java.util.HashMap();
fieldMap.put("状态", "已审批");  // 状态=已审批
var docs = $.form.getFormDocumentsByFieldNameAndValue(appId, "报销单", fieldMap);

// 方法2:getDocumentsByCondition(等值查询,和上面效果一样)
var conditionMap = new Packages.java.util.HashMap();
conditionMap.put("请假人", "张三");
var docs = $.form.getDocumentsByCondition(appId, "请假表", conditionMap);

// 方法3:getDocumentsByFilterParam(支持大于/小于/like等复杂条件)
var filterParamList = new Packages.java.util.ArrayList();
filterParamList.add(new Packages.cn.com.do1.do1cloud.runtime.dto.FilterParam("金额", "gt", 1000));  // 金额>1000
filterParamList.add(new Packages.cn.com.do1.do1cloud.runtime.dto.FilterParam("姓名", "like", "张%")); // 姓名以张开头
var docs = $.form.getDocumentsByFilterParam(appId, "报销单", filterParamList);

// 方法4:getDocumentsByFormModelAndCondition(先拿表单模型再查)
var formModel = $.form.getFormModel(appId, "报销单");
var fieldMap = new Packages.java.util.HashMap();
fieldMap.put("状态", "已审批");
var docs = $.form.getDocumentsByFormModelAndCondition(appId, formModel, fieldMap);

FilterParam 操作符一览(只有方法3支持这些):

操作符 含义 值的格式
gt / ge 大于 / 大于等于 直接传值
lt / le 小于 / 小于等于 直接传值
eq / ne 等于 / 不等于 直接传值
like 模糊匹配 字符串,可用%
between 在区间内 字符串,逗号隔开:"(开始,结束)"
isNull / isNotNull 为空 / 非空 -
in / notIn 包含 / 不包含 数组

⚠️ 所有查询方法返回的都可能为 null,遍历前必须判空:

javascript 复制代码
var docs = $.form.getFormDocumentsByFieldNameAndValue(appId, "报销单", fieldMap);
if (docs != null) {                          // 必须判空
    for (var i = 0; i < docs.size(); i++) {
        var doc = docs.get(i);
        // 处理每条数据
    }
}

5.4 获取子表单:getSubFormDocumentsByName(参数详解)

这个就是你在问题里举的那个API,重点讲清楚每个参数为什么必须传。

javascript 复制代码
$.form.getSubFormDocumentsByName(docId, 外键字段名, 子表单名, appId)
  • 获取谁的子表单? 获取 docId 对应的那条主表数据的子表单。
  • 参数1 docId:主表文档的ID。告诉系统查哪条主表数据的子表单。不传这个,系统不知道查谁的子表单。
  • 参数2 外键字段名:主表里"关联子表单"的那个字段名。子表单是通过主表的某个字段关联的,必须告诉系统通过哪个字段去找。
  • 参数3 子表单名:子表单的表单名称。一张主表可能有多个子表单控件,要指定是哪一个。
  • 参数4 appId:在哪个应用里查。

完整示例 + 业务场景:

场景:在采购订单列表点"生成入库单"按钮,要拿到这条采购订单的采购明细。

javascript 复制代码
(function(){
    var appId = $.context.getCurrentApplicationId();
    
    // 拿到触发按钮的那条采购订单(不是当前正在编辑的入库单!)
    var purchaseOrder = $.context.getHttpRequest().getAttribute("document");
    
    // 拿这条采购订单的子表单"采购明细"
    // 参数1:采购订单的文档ID
    // 参数2:"采购编号"是采购订单表里关联子表单的字段名
    // 参数3:"采购明细"是子表单的表单名
    // 参数4:应用ID
    var subDocuments = $.form.getSubFormDocumentsByName(
        purchaseOrder.getId(),
        "采购编号",
        "采购明细",
        appId
    );
    
    // 判空后遍历每一行明细
    if (subDocuments != null) {
        for (var i = 0; i < subDocuments.size(); i++) {
            var row = subDocuments.get(i);
            var productName = row.getElementByName("产品名称").getValue();
        }
    }
    
    return subDocuments;
})()

doc.getElementByName("子表单").getSubDocuments() 的区别:

方法 拿谁的子表单 什么时候用
doc.getElementByName("明细").getSubDocuments() 拿当前文档自己的子表单 当前表单有子表单,直接读
$.form.getSubFormDocumentsByName(...) 拿任意指定文档的子表单 要读别的文档(如原始数据)的子表单

5.5 删除数据:两种方法

方法 能做什么 区别
deleteAllDocumentsByFormName(appId, 表单名) 删整张表的所有数据 不加任何条件,全删
deleteFormDocumentsByFieldNameAndValue(appId, 表单名, fieldMap) 按条件删 只删满足条件的
javascript 复制代码
var appId = $.context.getCurrentApplicationId();

// 全删(慎用!)
$.form.deleteAllDocumentsByFormName(appId, "临时数据表");

// 条件删:只删"数量=100"的
var fieldMap = new Packages.java.util.HashMap();
fieldMap.put("数量", 100);
$.form.deleteFormDocumentsByFieldNameAndValue(appId, "采购明细", fieldMap);

六、$.validate ------ 校验:四种消息的区别

校验脚本返回的是一个 message 对象,用 $.validate.create() 创建。四种添加消息的方法,区别在"会不会阻止提交":

方法 效果 什么时候用
addSuccess("信息") 显示成功提示 校验通过时给个正面反馈
addInfo("信息") 显示普通提示 给提示但不影响提交
addWarn("信息") 显示警告 警告但仍可提交
addError("信息") 阻止提交 校验不通过,拦住

关键点 :只有 addError 会阻止用户提交,其他三个只是提示。所以拦截场景必须用 addError。

javascript 复制代码
(function(){
    var doc = $.context.getCurrentDocument();
    var amount = doc.getElementByName("金额").getDoubleValue();
    
    if (amount > 10000) {
        var message = $.validate.create();
        message.addError("金额超过10000,不允许提交");  // 阻止提交
        return message;  // 必须 return 才生效
    }
})()

七、$.message ------ 发消息:站内信 vs 邮件

方法 能做什么 参数
sendGeneralStationMessage(subject, context, userId) 发七巧站内信 标题、内容、接收人用户ID
sendEmail(subject, context, email) 发邮件 标题、内容、接收人邮箱
javascript 复制代码
// 发站内信给指定用户
var userId = doc.getElementByName("队长").getValue();
$.message.sendGeneralStationMessage("通知标题", "通知内容", userId);

// 发邮件
var email = doc.getElementByName("客户邮箱").getValue();
$.message.sendEmail("报价通知", "您的报价已处理", email);

八、$.log / $.json / $.date ------ 辅助工具

8.1 $.log ------ 日志(调试用)

四种级别,都支持 {} 占位符:

javascript 复制代码
$.log.info("处理文档:{}", docId);     // 提示日志
$.log.error("出错了:{}", errorMsg);   // 异常日志
$.log.warn("警告:{}", warnMsg);       // 警告日志
$.log.debug("调试:{}", detail);       // 调试日志

8.2 $.json ------ 对象转JSON字符串(调试神器)

拿到一个对象不知道里面有什么?转成JSON打印出来看:

javascript 复制代码
var doc = $.context.getCurrentDocument();
var jsonStr = $.json.objectToJsonString(doc);
$.log.info("文档完整内容:{}", jsonStr);  // 看看里面到底有什么

8.3 $.date ------ 日期处理

方法 能做什么 返回值
getCurrentDate() 拿当前时间 Date对象
dateToString(date, format) Date转字符串 String
stringToDate(str, format) 字符串转Date Date
timestampToDate(ts) 时间戳转Date Date
javascript 复制代码
var now = $.date.getCurrentDate();
var dateStr = $.date.dateToString(now, "yyyy-MM-dd");  // "2024-01-15"
var date = $.date.stringToDate("2024-01-15", "yyyy-MM-dd");

九、$.contact ------ 通讯录(常用方法)

通讯录有33个方法,这里只讲最常用的几个,讲清参数和返回值。完整列表见附录。

9.1 拿用户

javascript 复制代码
// 按ID拿单个用户
var user = $.contact.getUserById("用户ID");  // 返回 UserDTO
var name = user.getName();                   // 取姓名
var phone = user.getTelephone();             // 取电话

// 按姓名关键字模糊查
var users = $.contact.listUserByKeyword("张");  // 返回 List,所有姓张的

9.2 拿部门下的人

javascript 复制代码
// 只拿本部门的人
var users = $.contact.listUsersByDepartmentId("部门ID");

// 拿本部门+所有子部门的人
var allUsers = $.contact.listAllUsersByDepartmentId("部门ID");

9.3 拿用户的领导

javascript 复制代码
// includeAllLeader: true=所有上级领导, false=只拿直接领导
var userConfig = $.contact.getUserLeadersByUserId("用户ID", true);
var directLeader = userConfig.getLeaderUser();    // 直接领导
var allLeaders = userConfig.getLeaderUsers();     // 所有领导

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

10.1 从采购订单生成入库单(数据复制)

业务场景:采购订单列表有"生成入库单"按钮,点击后把采购订单的主表+子表数据复制到入库单。

为什么这样写:这是列表按钮场景,要拿原始数据(采购订单)必须用 getHttpRequest,要改当前表单(入库单)用 getCurrentDocument。

javascript 复制代码
(function(){
    var appId = $.context.getCurrentApplicationId();
    
    // 拿触发按钮的那条采购订单(不是入库单!)
    var purchaseOrder = $.context.getHttpRequest().getAttribute("document");
    
    // 拿当前正在编辑的入库单
    var storageDoc = $.context.getCurrentDocument();
    
    // 把采购订单的主表字段复制到入库单
    storageDoc.addElement("采购编号", purchaseOrder.getId());
    storageDoc.addElement("供应商", purchaseOrder.getElementByName("供应商名称").getValue());
    
    // 拿采购订单的子表单(采购明细)
    var purchaseDetails = $.form.getSubFormDocumentsByName(
        purchaseOrder.getId(),    // 哪条采购订单
        "采购编号",                // 主表外键字段名
        "采购明细",                // 子表单名
        appId                     // 哪个应用
    );
    
    // 把每行明细复制成入库明细
    var storageDetails = new Packages.java.util.ArrayList();
    if (purchaseDetails != null) {
        for (var i = 0; i < purchaseDetails.size(); i++) {
            var row = purchaseDetails.get(i);
            var detailDoc = $.form.createEmptyDocument(appId, "入库明细");
            detailDoc.addElement("产品名称", row.getElementByName("产品名称").getValue());
            detailDoc.addElement("数量", row.getElementByName("待入库数量").getValue());
            storageDetails.add(detailDoc);
        }
    }
    
    // 把明细列表塞到入库单的子表单字段
    storageDoc.addElement("入库明细", storageDetails);
    
    // 注意:不调 saveFormDocument!按钮执行前事件里系统自动保存
})()

10.2 金额校验(拦截提交)

业务场景:报销金额超过10000不让提交。

为什么这样写:校验脚本必须 return message 对象,且必须用 addError 才能阻止提交。

javascript 复制代码
(function(){
    var doc = $.context.getCurrentDocument();
    var amount = doc.getElementByName("金额").getDoubleValue();
    
    if (amount > 10000) {
        var message = $.validate.create();
        message.addError("金额超过10000,不允许提交");  // 只有Error会拦截
        return message;  // 必须 return
    }
})()

10.3 重复录入校验(查历史数据)

业务场景:今天已经登记过体温,不能再登记。

为什么这样写:要先查今天有没有记录,用 getDocumentsByFilterParam 因为要按"日期=今天"且"用户=当前用户"两个条件查。查到有数据就用 addError 拦截。

javascript 复制代码
(function(){
    var appId = $.context.getCurrentApplicationId();
    var userId = $.context.getCurrentUserId();
    var today = $.date.dateToString($.date.getCurrentDate(), "yyyy-MM-dd");
    
    // 构建查询条件:日期=今天 且 人员=当前用户
    var filterList = new Packages.java.util.ArrayList();
    filterList.add(new Packages.cn.com.do1.do1cloud.runtime.dto.FilterParam("日期", "eq", today));
    filterList.add(new Packages.cn.com.do1.do1cloud.runtime.dto.FilterParam("登记人", "eq", userId));
    
    var docs = $.form.getDocumentsByFilterParam(appId, "体温登记表", filterList);
    
    // 查到了就拦截
    if (docs != null && docs.size() > 0) {
        var message = $.validate.create();
        message.addError("今天已登记过,不能重复登记");
        return message;
    }
})()

10.4 子表单关联必填校验

业务场景:出行方式选了"飞机",航班信息必填。

为什么这样写:要遍历子表单每一行,检查每行的"出行方式"和"航班信息"。

javascript 复制代码
(function(){
    var doc = $.context.getCurrentDocument();
    var subDocs = doc.getElementByName("出行明细").getSubDocuments();
    
    if (subDocs != null) {
        for (var i = 0; i < subDocs.size(); i++) {
            var row = subDocs.get(i);
            var way = row.getElementByName("出行方式").getValue();
            var flight = row.getElementByName("航班信息").getValue();
            
            // 出行方式=2表示飞机,且航班信息为空 → 拦截
            if (way == 2 && (flight == null || flight == "")) {
                var message = $.validate.create();
                message.addError("选择飞机出行时,航班信息不能为空");
                return message;
            }
        }
    }
})()

10.5 调试:不知道对象里有什么

为什么这样写:拿到一个对象不确定结构时,转成JSON打印或发站内信给自己看。

javascript 复制代码
(function(){
    var doc = $.context.getCurrentDocument();
    var jsonStr = $.json.objectToJsonString(doc);
    
    // 方式1:日志输出
    $.log.info("文档内容:{}", jsonStr);
    
    // 方式2:发站内信给自己看(日志看不到时用这招)
    var userId = $.context.getCurrentUserId();
    $.message.sendGeneralStationMessage("调试信息", jsonStr, userId);
})()

十一、Java 包使用

七巧脚本里能用 Java 的集合类,通过 Packages 访问。常用的是 HashMap(查询条件)、ArrayList(列表)、HashSet(去重)。

javascript 复制代码
// HashMap:用于查询条件(字段名→值)
var fieldMap = new Packages.java.util.HashMap();
fieldMap.put("字段名", "值");

// ArrayList:用于列表(如子表单列表、FilterParam列表)
var list = new Packages.java.util.ArrayList();
list.add("item");

// HashSet:用于去重
var set = new Packages.java.util.HashSet();
set.add("value1");
set.add("value1");  // 重复的不会加进去

// FilterParam:过滤查询参数
var filterParam = new Packages.cn.com.do1.do1cloud.runtime.dto.FilterParam("字段名", "eq", "值");

附录:完整 API 速查表

$.context

API 能拿到什么 和谁容易混
getCurrentDocument() 当前正在编辑的表单文档 别和 getHttpRequest().getAttribute("document") 搞混
getHttpRequest().getAttribute("document") 触发按钮的那条原始数据 见上
getCurrentUser() 当前用户对象(含姓名电话) 和 getCurrentUserId 区别:一个拿对象一个拿ID
getCurrentUserId() 当前用户ID字符串 见上
getCurrentApplicationId() 当前应用ID -

Document 读取

API 返回类型 区别
getValue() String/JSONArray 通用,多选返回数组
getIntValue() int 整数
getDoubleValue() double 小数(金额推荐)
getFloatValue() float float类型
getSubDocuments() List<Document> 拿当前文档自己的子表单

Document 修改

API 区别
addElement("字段名", 值) 直接改
getElementByName("字段名").setValue(值) 先取再改,效果一样

$.form 查询(四种对比)

API 条件类型 适用场景
getFormDocumentsByFieldNameAndValue HashMap 等值 简单等值查询
getDocumentsByCondition HashMap 等值 和上面一样
getDocumentsByFilterParam FilterParam 支持操作符 复杂条件(大于/小于/like)
getDocumentsByFormModelAndCondition 表单模型+HashMap 先拿模型再查

$.form 其他

API 能做什么 注意
createEmptyDocument(appId, 表单名) 建空文档 建完要save才入库
saveFormDocument(doc, appId) 保存文档 按钮事件里不要调!
getSubFormDocumentsByName(docId, 外键, 子表单名, appId) 拿指定文档的子表单 和 getSubDocuments 区别见5.4
deleteAllDocumentsByFormName(appId, 表单名) 全删 慎用
deleteFormDocumentsByFieldNameAndValue(appId, 表单名, fieldMap) 条件删 -

$.validate

API 会阻止提交吗
addSuccess 不会
addInfo 不会
addWarn 不会
addError

$.message

API 能做什么
sendGeneralStationMessage(标题, 内容, userId) 发站内信
sendEmail(标题, 内容, email) 发邮件

$.date

API 能做什么
getCurrentDate() 拿当前时间
dateToString(date, format) Date转字符串
stringToDate(str, format) 字符串转Date
timestampToDate(ts) 时间戳转Date

$.contact(常用)

API 能拿到什么
getUserById(id) 单个用户对象
listUserByKeyword(关键字) 模糊查用户列表
listUsersByDepartmentId(deptId) 部门下的人(不含子部门)
listAllUsersByDepartmentId(deptId) 部门下的人(含子部门)
getUserLeadersByUserId(userId, includeAll) 用户的领导

官方文档参考


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

📅 更新日期 :2026-08-06

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

相关推荐
1 小时前
Android 自定义 View 实战:从零打造工业级全向摇杆控件(OmniJoystickView)
android·kotlin·自定义view·摇杆控件
雨白1 小时前
深入理解 Kotlin 协程 (十一):以逸待劳,探秘 select 多路复用与并发安全策略
android·kotlin
hunterandroid3 小时前
[Android 从零到一] Android 深度链接与 App Links:从 URI Scheme 到可验证的应用跳转
android
我命由我123456 小时前
Jetpack Compose - Material Design 断点范围、WindowSizeClass、针对不同屏幕尺寸创建预览、四类导航栏
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
执明wa6 小时前
Android 开发中的设计模式入门:六大设计原则
android·设计模式
松仔log20 小时前
Java中级——组合和继承
android·java·开发语言
我命由我123451 天前
Jetpack Compose - MaterialExpressiveTheme 与 MaterialTheme、ColorScheme
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
lilian2331 天前
Harmony os 技术实战|拼豆制图06:收藏 ID、生成记录与重启恢复怎么不打架
android·java·数据库·harmonyos
iori97king1 天前
织信开发日志 03:表单引擎从 0 到 1 的设计过程
低代码