脚本使用指南
表达式与脚本的运行位置、内置变量、多行脚本语句、import 与 log 模块、沙箱限制,以及数据集计算字段、SQL 模板、报表变量、自定义参数的规则。
概述
平台使用内置脚本引擎执行表达式和脚本,语法接近 JavaScript。「表达式」是只含一个值的写法,如 sum(B2);「脚本」是含多条语句的写法,可以声明变量、循环、判断。同一个引擎在多个位置使用,但各处提供的变量和允许的语法不同,本文逐项说明。基本语法见 报表基本语法,函数见 内置函数总览。
脚本在哪里运行
| 位置 | 写法形式 | 可用变量 | 语法范围 |
|---|---|---|---|
| 公式单元格「内容公式」 | 表达式 | 单元格引用、$参数、$$config、$$reportVars |
完整语法和全部函数 |
| 数据绑定单元格「计算表达式」 | 表达式 | $$record、$参数 |
完整语法 |
| 分组公式 | 表达式 | 同上 | 完整语法 |
| 条件渲染的公式条件与新值 | 表达式 | $$value、单元格引用、$参数 |
完整语法,见 条件渲染 |
| 报表参数默认值(表达式模式) | 表达式 | 请求传入的 $参数 |
完整语法,见 报表参数 |
| 报表变量(表达式模式) | 表达式 | 数据集、$参数、之前声明的 $$reportVars |
完整语法 |
| 数据集后处理脚本 | 多行脚本 | $$data、$参数 |
完整语法,含 import |
SQL 模板里的 ${} |
表达式 | $参数 |
完整语法 |
| 数据集计算字段 | 受限表达式 | $$record、$参数 |
受限语法,见下文 |
只含一个表达式的脚本,其值自动作为返回值;含多条语句时,要用 return 返回结果。
内置变量
| 变量 | 含义 | 类型 | 说明 |
|---|---|---|---|
$参数名 |
报表参数 | 按参数类型 | 未定义得 null |
$$value |
当前单元格的值 | 数值或原类型 | 数字文本转为数值,以 0 开头的编码保持文本;条件渲染中使用 |
$$record |
当前数据记录 | 对象 | 用 .字段 或 ['字段'] 访问 |
$$data |
数据集记录列表 | List | 后处理脚本中使用 |
$$config.名称 |
自定义参数 | 文本、布尔、数值或数组 | 在管理端「系统」>「自定义参数」维护 |
$$reportVars.名称 |
报表变量 | 任意 | 在报表设置「报表变量」里定义 |
$$line |
分行打印的当前行序号 | 整数 | 默认 0 |
$$lines |
分行打印的总行数 | 整数 | 默认 1 |
$$isFirstLine |
是否首行 | 布尔 | 默认 true |
$$isLastLine |
是否末行 | 布尔 | 默认 true |
$$group $$groupVars |
套打分组信息 | 对象 | 单据(套打)分组使用,见 单据模板概述 |
$$line 等变量的详细用法见 分行打印。
多行脚本
声明与赋值
var total = 0
let name = '内科'
const rate = 0.1
var、let、const 声明变量;语句之间可用分号或换行分隔。
判断与循环
if ($$value > 100) {
return '高'
} else if ($$value > 50) {
return '中'
} else {
return '低'
}
var sum = 0
for (item in $$data) { sum = sum + item.amount }
for (i, item in $$data) { ... } // 带下标
for (var i = 0; i < 3; i++) { ... } // C 风格
while (cond) { ... }
break、continue 可用于循环;try { } catch (e) { } finally { } 处理异常;throw 主动抛错;exit 结束脚本。
Lambda 与集合方法
$$data.filter(row => row.age >= 18).map(row => row.name)
集合上的 filter、map、sort、group 等方法见 聚合与集合函数。
import 与模块
import 引入模块或 Java 类:
| 写法 | 作用 |
|---|---|
import log |
引入日志对象,写到服务端日志,见 用户、工具与数组函数 |
import java.util.Date |
引入类,变量名取类的简单名称 Date |
import 'java.util.Date' as D |
引入并起别名 D |
import java.util.* |
引入整个包 |
示例:
import java.util.Date
return new Date().getTime()
沙箱限制
脚本运行在受限环境里,import 会检查目标类,下列内容被拒绝,引入时报错:
| 类别 | 被拒绝的目标 |
|---|---|
| 反射与动态调用 | java.lang.reflect、java.lang.invoke |
| 文件与网络 | java.io、java.nio.file、java.net |
| 脚本与命名服务 | javax.script、javax.naming |
| 平台内部 | jdk.、sun.、com.sun. 开头的包 |
| 其他脚本引擎与表达式库 | groovy、ognl、org.springframework.expression、org.springframework.context、org.springframework.beans.factory、javassist、bytebuddy、commons.collections.functors |
| 进程与系统类 | Runtime、ProcessBuilder、Process、System、Thread、ClassLoader、Class、Compiler、Shutdown、SecurityManager |
要点:
java.lang.Math、java.text.*、java.util.*等常规工具类允许使用。- 检查只针对
import;文件读写、网络请求、执行系统命令等都无法通过脚本完成,需要这类能力时在数据源或数据集层面实现。 - 该检查默认开启,可用 JVM 系统属性
-Dsightdata.script.class-guard.enabled=false或环境变量SIGHTDATA_SCRIPT_CLASS_GUARD=false关闭,不建议关闭。
执行时限
数据集后处理脚本有执行超时,默认 30 秒,由配置项 script.postScript.timeoutSeconds 调整,超时后取数失败。脚本里避免写无限循环和对大数据集的嵌套遍历。
数据集后处理脚本
在数据集编辑页的「后处理脚本」标签页填写,适用于 SQL 数据集和 API 数据集。脚本在取数后运行:
$$data是取回的记录列表,$参数名是数据集参数。- 脚本返回一个 List 时,用它替换原来的数据。
return $$data.filter(item => item.age >= 18).sort((a, b) => b.amount - a.amount);
完整说明和例子见 后处理脚本与计算字段。
数据集计算字段
在数据集编辑页的「计算字段」里追加派生列,界面最多添加 10 个。计算字段使用受限语法,逐行计算,字段之间不能互相引用。
允许的内容:数字、文本、null、true、false、$参数、$$record.字段 或 $$record['字段']、括号、加减乘除四则运算、负号,以及下面的函数。
不允许:% 取余、比较运算、三元条件、赋值和语句。
| 函数 | 参数个数 | 函数 | 参数个数 |
|---|---|---|---|
round |
1 到 2 | upper |
1 |
ceil |
1 | lower |
1 |
floor |
1 | trim |
1 |
abs |
1 | substring |
2 到 3 |
min |
2 个以上 | replace |
3 |
max |
2 个以上 | left |
2 |
ifNull |
2 | right |
2 |
ifEmpty |
2 | length |
1 |
coalesce |
2 个以上 | formatNumber |
2 |
concat |
1 个以上 | formatDate |
1 到 3 |
year |
1 | formatDateTime |
1 |
month |
1 | day |
1 |
注意:校验器允许
substring写 2 个参数,但运行时substring只有 3 个参数的写法(第三个可传null),2 个参数会因「找不到函数」而在该行得到错误标记,请写全三个参数。
示例:
$$record.数量 * $$record.单价
concat($$record.姓, $$record.名)
ifNull($$record.折扣, 0)
需要条件判断或复杂逻辑时,改用后处理脚本,或在报表单元格里写表达式。
SQL 模板
SQL 数据集的语句里可以嵌入表达式,规则:
| 写法 | 作用 |
|---|---|
${表达式} |
计算后作为绑定参数(?),值不会拼进 SQL 文本,可防注入 |
${$name}、$name |
引用参数 name 的值,两种写法等价 |
#{表达式} |
计算结果按文本直接拼进 SQL,用于表名、列名、排序方向等无法绑定的位置;必须确保内容可信 |
名字:cursor、名字:数字 |
存储过程的输出参数 |
规则补充:
- 集合参数展开为
?,?,...,与IN (...)配合使用;集合为空时展开为字面量NULL。 - 先去掉 SQL 注释再解析;引号内的内容按数据处理,不会被当作参数。
例:
select * from 门诊 where 日期 >= ${$startDate} and 科室 in (${$deptList})
详见 SQL 参数与动态语法 和 数据集参数。
报表变量
报表变量是报表级的、可重复引用的计算值,在报表设置的「报表变量」里定义,引用写法 $$reportVars.名称。
| 计算方式 | 说明 |
|---|---|
| 内置计算 | 对指定数据集的某个字段取 first(第一行,默认)、last、count、sum、avg、min、max;必须指定数据集 |
| 表达式 | 写一段表达式,可引用参数、数据集函数和之前声明的报表变量 |
规则:
- 按声明顺序逐个计算,表达式只能引用排在它前面的变量,引用后面的或未定义的变量报错。
- 变量名不能重复,重复定义时报错「报表变量【名称】重复定义」。
- 数据集为空时,
count得0,其他计算得null。
自定义参数
$$config.名称 读取管理端「系统」>「自定义参数」里配置的全局值,类型有文本、布尔、数值、数组。适合放各报表共用的固定内容,如单位名称、阈值。修改后所有引用它的报表下次运行时生效。
调试
- 在多行脚本里
import log,用log.info('信息 {}', x)写到服务端日志。 println(x)、print(x)、printf(fmt, args)输出到服务端控制台。- 表达式出错时,先把长表达式拆成几段分别在预览里看结果。
常见错误
| 现象 | 原因 | 处理 |
|---|---|---|
| 「找不到函数」 | 参数个数或类型不符 | 见 内置函数总览 的调用规则 |
| import 报错 | 目标被沙箱拒绝 | 见上文沙箱限制 |
| 计算字段保存失败 | 用了 %、比较、三元,或不在白名单的函数 |
改用后处理脚本 |
| 后处理脚本没有效果 | 没有 return 一个 List |
返回处理后的列表 |
| 数据集未取到数据 | 超时 | 缩小取数范围,优化脚本 |
| 多行脚本得不到值 | 缺少 return |
补上 return |
可直接套用的写法见 脚本与表达式示例。