:::
此文档是织信低代码平台的脚本SDK文档，基于织信平台的业务逻辑可以用如下sdk方法去实现。读取该文档，根据该文档中提供的方法解决我提出的问题，请直接给出实现的js方法代码。需要注意除了可以使用普通的js自带方法，其余方法只能使用文档中提供的方法，不能杜撰文档中没有的方法。
如果使用文档中的方法不能完全实现需求则给出不能实现的原因。
织信采用多租户架构，系统中用户分为系统账号 Account、 团队成员 CompanyMember、 应用成员 User 三种。每个Account可加入到多个团队中成为CompanyMember, 每个CompanyMember在团队中可以加入多个应用成为 User。每一个团队成员可以归属于一个或者多个部门 Dept，部门之间也有父子关系。每个部门可以有一个或者多个CompanyMember作为部门负责人。
脚本都运行在某一个应用下。
:::

## ⚠️ 脚本与表达式的语法边界（强制，编写脚本前必读）

**脚本（.js） ≠ 表达式（UEL）。** 两者运行在不同环境、有不同语法规则，**严禁把表达式语法直接搬到脚本中**。

### 一、脚本中使用平台表达式 SDK 函数：脚本中必须加 `informat.` 前缀

表达式文档中 `String.concat(...)` / `Array.of(...)` / `Date.sysdate()` / `Misc.jsonStringify(...)` 等写法，**只在 `${}` 表达式上下文中合法**。在脚本（.js）中调用相同函数时，**必须加 `informat.` 前缀**——脚本运行在 GraalVM JS 引擎里，裸写 `String`、`Array`、`Date`、`Math` 指向的是 JS 原生对象，不是平台工具对象，调用平台方法会直接抛 `TypeError: xxx is not a function`。

| 表达式中（合法） | 脚本中（合法） | 脚本中（错误，会运行时报错） |
|---|---|---|
| `${String.concat(a, b)}` | `informat.String.concat(a, b)` | ~~`String.concat(a, b)`~~ |
| `${String.length(s)}` | `informat.String.length(s)` | ~~`String.length(s)`~~ |
| `${Array.of(1, 2)}` | `informat.Array.of(1, 2)` | ~~`Array.of(1, 2)`~~（JS 原生 `Array.of` 行为类似但非平台函数，混用会引发歧义）|
| `${Array.length(list)}` | `informat.Array.length(list)` | ~~`Array.length(list)`~~ |
| `${Date.sysdate()}` | `informat.Date.sysdate()` | ~~`Date.sysdate()`~~ |
| `${Math.abs(-1)}` | `informat.Math.abs(-1)` | ~~`Math.abs(-1)`~~（JS 原生 Math.abs 可用，但 `Math.round(n, digits)` 这类双参写法在 JS 原生中不存在，必须走 informat）|
| `${Misc.jsonStringify(o)}` | `informat.Misc.jsonStringify(o)` | ~~`Misc.jsonStringify(o)`~~ |
| `${Misc.parseInt(s)}` | `informat.Misc.parseInt(s)` | ~~`Misc.parseInt(s)`~~ |
| `${Encode.md5(s)}` | `informat.Encode.md5(s)` | ~~`Encode.md5(s)`~~ |
| `${Record.getById(t, id)}` | `informat.table.queryById(t, id)`（脚本走 `informat.table.*`）| ~~`Record.getById(...)`~~ |
| `${User.user(id)}` | `informat.company.queryMember(id)` 等（脚本走 `informat.company.*` / `informat.dept.*`）| ~~`User.user(id)`~~ |

> 规则口诀：**表达式里裸写工具对象，脚本里一律加 `informat.` 前缀**。如果记不清是哪种环境，看文件后缀——`.js` 文件就是脚本，必须加前缀。

### 二、JS 原生写法：脚本中合法，无需加前缀

脚本是真 JS，**JS 原生功能完全可用**，不需要也不应该加 `informat.` 前缀。常见易混淆点：

| 写法 | 性质 | 脚本中是否合法 |
|---|---|---|
| `String(x)` | JS 原生强制类型转换函数 | ✅ 合法（注意：这不是 `String.concat` 那种平台调用）|
| `Number(x)` / `Boolean(x)` | JS 原生类型转换 | ✅ 合法 |
| `'a' + b + 'c'` | JS 原生字符串拼接 | ✅ 合法（脚本中 `+` 可拼字符串，与表达式 DSL 不同）|
| `` `a${b}c` `` | JS 原生模板字符串 | ✅ 合法 |
| `[1, 2, 3]` | JS 原生数组字面量 | ✅ 合法（脚本中允许，与表达式 DSL 不同）|
| `{ key: 'value' }` | JS 原生对象字面量 | ✅ 合法 |
| `arr.length` / `arr[0]` | JS 原生数组属性/下标 | ✅ 合法 |
| `arr.map(x => ...)` / `arr.filter(...)` | JS 原生数组方法 | ✅ 合法 |
| `if / else / for / while` | JS 原生控制流 | ✅ 合法（与表达式 DSL 不同）|
| `JSON.stringify(o)` / `JSON.parse(s)` | JS 原生 JSON | ✅ 合法（也可用 `informat.Misc.jsonStringify`，二者皆可，按需选用）|
| `parseInt(s)` / `parseFloat(s)` | JS 原生全局函数 | ✅ 合法（也可用 `informat.Misc.parseInt`）|
| `new Date()` | JS 原生 Date 类 | ✅ 合法（拿到的是 JS Date 对象；如需平台 Date 行为则用 `informat.Date.sysdate()`）|

### 三、自检清单（写完脚本提交前必查）

1. 文件中是否出现裸的 `String.xxx(`、`Array.of(`、`Date.sysdate(`、`Misc.xxx(`、`Encode.xxx(`、`Record.xxx(`、`User.xxx(`、`Context.xxx(`、`T.t(`？
    - 是 → 全部加 `informat.` 前缀，或改用等价的 JS 原生写法。
2. 是否出现 `${...}` 表达式包裹符？
    - 是 → 错误。`${}` 仅在表达式上下文中使用，脚本中没有 `${}` 求值边界，写了会被当作模板字符串里的占位符或语法错误。
3. 是否把 `'inProgress'` 这类选项值写成不带引号的裸标识符？
    - 是 → 错误。表达式里选项值不加引号是 DSL 规则；**脚本中必须按 JS 字符串规则带引号**。

### 四、典型错误对照

```js
// ❌ 错误：脚本中裸用 String.concat（表达式语法）
return { message: String.concat('共 ', count, ' 条') };

// ✅ 修复方式 1：加 informat. 前缀
return { message: informat.String.concat('共 ', count, ' 条') };

// ✅ 修复方式 2：直接用 JS 原生拼接（脚本是真 JS，+ 合法）
return { message: '共 ' + count + ' 条' };

// ✅ 修复方式 3：模板字符串
return { message: `共 ${count} 条` };
```

```js
// ❌ 错误：脚本中写 ${...} 表达式
const name = ${用户.name};

// ✅ 正确：脚本中直接访问变量
const name = user.name;
```

```js
// ❌ 错误：脚本中用表达式风格的选项裸标识符
if (record.status === inProgress) { ... }

// ✅ 正确：脚本中按 JS 字符串规则
if (record.status === 'inProgress') { ... }
```

---

## 📚 	
本文档为脚本开发总览，包含通用基础API和常见场景示例。更详细的各模块独立API请参考`./script/`目录下的对应文档：

| 文档文件名 | 模块说明 | 适用场景 |
|-----------|----------|----------|
| `aiagent.md` | AI助手模块API | 调用AI大模型、开发自定义智能助手、对话补全功能 |
| `app.md` | 应用全局API | 获取应用信息、环境变量、操作用户信息、终止脚本执行 |
| `bpmn.md` | 工作流模块API | 操作工作流实例、任务处理、流程跳转、变量管理 |
| `codec.md` | 编解码模块API | MD5/SHA哈希计算、Base64编解码、RSA加密解密、签名验签 |
| `company.md` | 团队管理API | 查询团队信息、成员管理、角色管理、部门管理 |
| `console.md` | 控制台API | 脚本日志输出、调试信息打印 |
| `csv.md` | CSV文件处理API | CSV文件读写、批量数据导入导出 |
| `datasource.md` | 数据源管理API | 多数据源连接、SQL查询、事务控制 |
| `date.md` | 日期处理API | 日期格式化、时间计算、时区转换 |
| `dept.md` | 部门架构API | 查询部门层级、成员管理、负责人设置 |
| `designer.md` | 应用设计器API | 操作应用配置、模块管理、元数据查询 |
| `email.md` | 邮件发送API | 发送普通邮件、富文本邮件、带附件邮件 |
| `excel-easyPoi.md` | EasyPoi Excel处理API | 复杂Excel模板导出、批量数据导入 |
| `excel.md` | 基础Excel处理API | 简单Excel读写、单元格操作、样式设置 |
| `expression.md` | 表达式引擎API | 执行表达式计算、公式解析、动态逻辑执行 |
| `file.md` | 沙盒文件操作API | 本地沙盒文件读写、目录操作、压缩解压缩 |
| `ftp.md` | FTP/SFTP操作API | FTP文件上传下载、远程文件操作 |
| `http.md` | HTTP请求API | 发送GET/POST请求、调用第三方接口、文件下载 |
| `jdbc.md` | 数据库操作API | 原生JDBC操作、数据表直连、SQL执行 |
| `notification.md` | 系统通知API | 发送系统通知、站内消息、待办提醒 |
| `storage.md` | 共享存储API | S3存储文件上传下载、远程文件管理 |
| `table.md` | 数据表操作API | 数据表CRUD、关联查询、附件操作、汇总字段计算 |
| `task.md` | 任务中心API | 任务创建、状态更新、任务查询、流程处理 |
| `website.md` | 网站设计器API | 操作网站模块、页面组件、资源管理 |

> 💡 开发时优先查阅对应模块的独立文档，获取最新最全的API定义和示例代码。

::: warning 注意
织信脚本运行在 GraalVM JavaScript 引擎中，  
SDK 提供的 `informat.*` 方法均为 **同步调用**，不返回 Promise。

❌ 不支持 `async / await` 写法  
❌ 不支持基于 Promise 的异步模型

请直接使用同步方式调用 SDK 方法，例如：

```js
const list = informat.table.queryList(tableId, query);
```

## 执行系统命令

通过 `informat.system.runProcess(args)` 可以在脚本中直接执行系统命令。

### 参数

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| cmds | String[] | 是 | 命令及参数数组 |
| timeout | long | 否 | 超时时间（毫秒），0 表示忽略超时 |

### 返回值

| 字段 | 类型 | 说明 |
|------|------|------|
| exitValue | int | 进程退出码，0 通常表示成功 |
| out | String | 标准输出内容 |
| err | String | 错误输出内容 |

### 示例

```js
// 执行 ls 命令
const result = informat.system.runProcess({
  cmds: ["ls", "-la", "/tmp"],
  timeout: 10000
});
console.log("exitValue:", result.exitValue);
console.log("stdout:", result.out);
console.log("stderr:", result.err);

// 执行带超时的命令
const result2 = informat.system.runProcess({
  cmds: ["python3", "script.py"],
  timeout: 30000
});
```
