此文档是织信低代码平台的自动化文档。

## 概述
织信的自动化是一个**步骤列表的集合**。每个步骤要么是**交互步骤**（type 以 `Output` 开头，需要用户参与界面操作，例如弹出表单、确认框、上传、扫码、发起工作流等），要么是**非交互步骤**（控制流程、调脚本等）。一个完整的自动化通常由多种步骤交织而成。
如果自动化涉及数据表操作，则需要查询数据表文档

---

### 🖥️ 执行环境 · 客户端执行 vs 服务器执行（决定能否使用 `Output*` 步骤）

自动化在两种环境下运行，**这决定了它能用哪些步骤**。在编排前必须先判断当前自动化属于哪一类：

| 环境 | 触发方式（典型）| 能否使用 `Output*` 交互步骤 |
|------|---------------|----------------------------|
| **客户端执行** | 绑定在控件按钮上的自动化（按钮点击触发）| ✅ 可以使用 |
| **服务器执行** | 定时任务、监听器（如 `record.insert.after`）、工作流任务完成后调用、HTTP 回调等**非按钮触发**的自动化 | ❌ **禁止使用任何 `Output*` 步骤**——服务器没有用户界面 |

> **判定规则**：自动化是否绑定在控件按钮上？是 → 客户端执行；否 → 服务器执行。

#### 服务器执行的影响（关键约束）

服务器执行的自动化里**只能使用非交互步骤**：`If` / `If.true` / `If.false` / `ForEach` / `While` / `CallScript` / `SetReturnValue`。所有 `Output*` 步骤都不能用，因为服务器端没有"用户界面"可供交互。

如果一个服务器执行的需求看起来"需要交互"（例如"创建记录后给当事人发通知"），那它实际上不是交互——通知/写库等都要走 `CallScript` 里的脚本能力（在脚本中调用 `notify`、`model.insert` 等服务端 API）。

> **再进一步**：如果一个服务器执行的自动化里**全是 `CallScript`**、完全没有控制流分支需求，那应该考虑直接写成脚本模块而不是自动化。

---

### ⛔ 关键决策 · 三层判断（环境 → 意图 → 模糊时询问）

#### 第 1 层 · 先看执行环境

| 环境 | 可用步骤范围 |
|------|------------|
| 客户端执行（按钮触发）| 全部交互步骤 + 全部非交互步骤 |
| 服务器执行（定时/监听/工作流回调等）| **仅** 非交互步骤（控制流程 + `CallScript` + `SetReturnValue`）|

**如果是服务器执行，跳过第 2 层的"路径 A"，直接走"路径 B"。**

#### 第 2 层 · 按意图选步骤（仅当客户端执行时才需要选 A 还是 B）

收到一个需求时，**不要看名词联想 type**（"创建记录" ≠ `InsertRecord`、"工作流" ≠ `CreateBpmnProcess`）。先回答：

> **这一步是否需要用户参与界面操作？**（点击、填写、确认、选择文件、扫码等）

##### 路径 A · 需要用户交互 → 从交互步骤白名单中找最匹配的 `Output*` 步骤

许多看起来像"数据写入/工作流操作"的需求，**本身就有对应的交互步骤**，应当首选：

| 需求场景 | 选用的交互步骤（不要走 CallScript）|
|---------|-----------------------------------------|
| 让用户填表创建一条记录 | `OutputRecordCreate`（打开创建记录表单弹窗，平台直接帮你保存）|
| 让用户填一个轻量表单（不一定对应数据表）| `OutputDynamicForm`（自定义字段的表单弹窗）|
| 让用户上传文件 / Excel | `OutputUpload` / `OutputUploadExcel` |
| 让用户从列表中挑选记录 | `OutputRecordSelect` |
| 让用户发起一个工作流 | `OutputBpmnProcess`（打开工作流发起表单弹窗）|
| 让用户查看工作流任务 / 实例详情 | `OutputBpmnTaskInfo` / `OutputBpmnInstanceInfo` |
| 让用户确认 / 看到 Toast 或通知 | `OutputConfirm` / `OutputToast` / `OutputNotification` |

完整的交互步骤白名单见后文「自动化步骤」一节。

##### 路径 B · 不需要交互（纯后台逻辑）→ `CallScript`

数据 CRUD、HTTP、SSH、变量计算、调 AI 等**没有用户参与**的逻辑，使用 `CallScript` 调用脚本模块中的函数完成。

> ⚠️ **`CallScript` 的 `scriptId` 是 .js 文件的 ID，不是目录/分组的 ID**。新建脚本后必须用 `_query_informat_script_list` 重新查询拿到对应 .js 文件的 ID，再填入 `scriptId`——`_save_informat_script` 调用时传入的 `parentId` 是承载它的目录 ID，**不能当 `scriptId` 用**。

#### 第 3 层 · 意图模糊时必须先询问用户，不要擅自选择

在客户端执行的自动化里，有些动词同时有"前端交互"和"后台静默"两种实现，**意图不明确时不要猜，先问用户**。

##### 明确的需求（直接选，不必问）

需求里出现下面这类**前端交互专用动词**，意图明确指向交互步骤：

| 明确动词 | 直接选用 |
|---------|---------|
| "**打开**创建记录弹窗" / "**弹出**创建表单" | `OutputRecordCreate` |
| "**让用户填表**创建/编辑记录" | `OutputRecordCreate` / `OutputRecordInfo` / `OutputDynamicForm` |
| "**弹出**确认对话框" | `OutputConfirm` |
| "**让用户上传**文件" | `OutputUpload` |
| "**显示** Toast / 通知" | `OutputToast` / `OutputNotification` |
| "**打开**工作流发起表单" / "**让用户发起**工作流" | `OutputBpmnProcess` |

需求里出现下面这类**后台动词**，意图明确指向 `CallScript`：

| 明确动词 | 直接选用 |
|---------|---------|
| "**静默**创建一条记录" / "**直接**写一条数据" | `CallScript` |
| "**自动**更新字段" / "**后台**同步" | `CallScript` |
| "**调用** HTTP 接口" / "**调用** AI" | `CallScript` |

##### 模糊的需求（必须先询问用户）

需求里只有"创建/更新/删除/查询/发起工作流"等**中性动词**、没有明确指出"是否需要弹窗 / 用户填表"时，**必须停下来问用户**，不要擅自选择。

| 模糊需求 | 应该问用户 | 两种可能的实现 |
|---------|----------|--------------|
| "创建一条记录" | "需要弹出表单让用户填写后保存（A），还是直接用预设字段静默创建（B）？" | A → `OutputRecordCreate`；B → `CallScript` |
| "更新这条记录" | "需要弹出编辑表单（A），还是按规则后台直接更新（B）？" | A → `OutputRecordInfo`；B → `CallScript` |
| "发起一个工作流" | "需要弹出发起表单让用户填写（A），还是用预设变量后台发起（B）？" | A → `OutputBpmnProcess`；B → `CallScript` |
| "上传文件" | "需要让用户选文件上传（A），还是从已有数据/URL 拉取后存入（B）？" | A → `OutputUpload`；B → `CallScript` |
| "选择记录" | "需要弹窗让用户挑选（A），还是按筛选条件后台拿到（B）？" | A → `OutputRecordSelect`；B → `CallScript` |

> **特殊情况**：如果是服务器执行环境，则忽略 A 选项，直接走 B（`CallScript`），但仍建议告知用户"由于此自动化是服务器执行（如定时任务），无法弹窗，将直接后台创建"。

> **询问示例话术**：
> "你的需求中提到『创建一条记录』，请问是希望（A）打开一个表单弹窗让用户填写后保存，还是（B）由自动化按预设字段静默创建？两种实现方式不同，请确认。"

#### 决策示例

| 需求 | 错误选择 | 正确选择 | 原因 |
|------|---------|---------|------|
| "**打开**创建记录弹窗 → 创建后 Toast" | 用 `OutputDynamicForm` + `InsertRecord` | 用 `OutputRecordCreate` + `OutputToast` | "打开"明确表示前端交互；`OutputRecordCreate` 一站式完成 |
| "用户点按钮 → **创建一条**项目记录 → Toast" | 直接选一种实现 | 先问用户："是弹表单让用户填，还是按预设字段静默创建？" | 没说"打开/弹出"，是模糊需求，必须确认 |
| "用户填表 → **发起**一条请假工作流" | 用 `OutputDynamicForm` + `CreateBpmnProcess` | 直接用 `OutputBpmnProcess` | 平台已经为"用户发起工作流"提供了专门的交互步骤 |
| "每天定时同步外部 API 数据到记录" | 用 `Http` + `InsertRecord` 步骤 | 服务器执行 → `CallScript`（脚本里发请求 + 写库） | 定时任务是服务器执行，禁用 `Output*`；且 `Http`/`InsertRecord` 都不是合法步骤 |
| "弹窗提示用户『有 5 条新工单』，需要先查数据库" | 用 `QueryRecordList` + `OutputToast` | 用 `CallScript`（脚本里 `model.query` 返回数量）+ `OutputToast` | "弹窗"明确为客户端执行；`QueryRecordList` 不是合法步骤，查询逻辑放进 `CallScript` |
| "工作流任务完成后给申请人发通知" | 用 `OutputNotification` | 服务器执行 → 在 `CallScript` 调用的脚本中用服务端 `notify` API 发送 | 工作流任务回调是服务器执行，禁用所有 `Output*` |

---

### 🚫 严重错误清单 · 这些 type 不能作为自动化步骤

下列 type **不是合法的自动化步骤**，无法直接出现在 `funcSettingList` 中：

| 类别 | 错误的 type（不能作为步骤）| 在自动化里的正确替代 |
|------|------------------------|------------------|
| 数据 CRUD | `InsertRecord` `UpdateRecord` `DeleteRecord` `QueryRecord` `QueryRecordList` `QueryRecordRelList` `QueryRecordListCount` `QueryRecordRelListCount` `UpdateLookupRollup` | 若需用户填表创建/编辑：用 `OutputRecordCreate` / `OutputRecordInfo` / `OutputDynamicForm`；若是后台静默操作：用 `CallScript`（脚本里调 `model.insert/update/delete/query`）|
| 网络/系统 | `Http` `SshRequest` | `CallScript`（在脚本里发请求）|
| 变量与流程内务 | `SetVar` `UpdateVar` `Abort` `Log` `Sleep` `Notification` `SetAppBadge` `PublishAppEvent` `PushEvent` `SetModuleAlert` | `CallScript`；自动化内的变量传递通过步骤的 `retValues` + `${name}` 引用 |
| 工作流写操作 | `CreateBpmnProcess` `SetBpmnVar` `GetBpmnVar` `BpmnQueryInstance` `BpmnQueryTask` `SetBpmnAssignee` `SetBpmnChangeActivity` `SetBpmnRevoke` `SetBpmnDelete` `BpmnDeleteTask` `SetBpmnTaskComplete` `BpmnSendSignal` `BpmnSendMessage` `BpmnTrigger` | 若需用户发起 / 查看工作流：用 `OutputBpmnProcess` / `OutputBpmnTaskInfo` / `OutputBpmnInstanceInfo` / `OutputBpmnEvent`；若是后台静默操作：用 `CallScript` |
| AI 调用 | `CallAI` `OpenAIChatGpt` | `CallScript`（在脚本里调用 AI）|

> **判断顺序**：
> ①**当前自动化是客户端执行还是服务器执行？** 服务器执行 → 跳到 ③，所有 `Output*` 不可用。
> ②**这一步意图是否需要用户交互？** 模糊需求（如"创建一条记录"）必须先问用户，不要猜。
> ③**最终落点**：交互步骤白名单中的 `Output*`（仅客户端执行）/ `CallScript`。**绝不会是上表中的任何 type**。

---

### ✅ 错 vs 对 · 完整对照示例

**业务需求**：用户填写表单 → 创建一条项目记录 → 提示成功

#### ❌ 错误编排（把 InsertRecord 直接当成步骤）

```jsonc
{
  "funcSettingList": [
    { "type": "OutputDynamicForm",  "outputDynamicFormFuncSetting": { /* ... */ } },
    { "type": "InsertRecord",       "insertRecordFuncSetting": { /* ... */ } },  // ← 严重错误：InsertRecord 不是合法步骤 type
    { "type": "OutputToast",        "outputToastFuncSetting": { /* ... */ } }
  ]
}
```

错在哪：`InsertRecord` 不在合法 type 白名单里，无论 setting 字段叫 `insertRecordSetting` 还是 `insertRecordFuncSetting` 都同样无效。**而且这个需求根本不需要走 `CallScript`**——平台已经有专门的"打开创建记录表单"交互步骤。

#### ✅ 方案 0 · 最佳方案：直接用 `OutputRecordCreate`（一站式交互）

`OutputRecordCreate` 本身就是"打开记录创建表单弹窗 + 用户填写 + 平台保存"的完整交互。这是这类需求的最优解：

```jsonc
{
  "funcSettingList": [
    {
      "type": "OutputRecordCreate",
      "retValues": [{ "id": "result", "name": "新项目记录" }],
      "outputRecordCreateFuncSetting": {
        "tableId": "project",
        "recordCreateSubmitType": "Create"
        /* 平台会读取 project 表的字段定义自动生成表单 */
      }
    },
    {
      "type": "OutputToast",
      "outputToastFuncSetting": {
        "toastValueVar": "${String.concat('项目创建成功-', 新项目记录.name)}"
      }
    }
  ]
}
```

#### ✅ 方案 A · 退路：自定义表单 + `CallScript`

仅当 `OutputRecordCreate` 不满足需求时（例如表单字段和数据表字段不完全一致、需要先做复杂处理再写库），才走这条路。

第一步：在脚本模块中编写函数

```javascript
// scriptId = "projectScript" 中的 createProject 函数
const createProject = (formData) => {
    return model.insert("project", {
        name: formData.projectName,
        budgetCode: formData.budgetCode,
        pm: formData.projectManager,
        status: formData.projectStatus
    });
};
```

第二步：自动化里用 `OutputDynamicForm` 收集数据 + `CallScript` 调脚本写库

```jsonc
{
  "funcSettingList": [
    {
      "type": "OutputDynamicForm",
      "retValues": [{ "id": "result", "name": "表单数据" }],
      "outputDynamicFormFuncSetting": { /* 必须按"最小可用骨架"传入：包含 dynamicFormStyle/dynamicFormFieldStyle/dynamicFormStyleWidth/dynamicFormStyleWidthUnit 等 UI 字段，详见后文「弹窗/表单类步骤的设置项必填提醒」 */ }
    },
    {
      "type": "CallScript",
      "retValues": [{ "id": "result", "name": "新项目记录" }],
      "callScriptFuncSetting": {
        "scriptId": "projectScript",
        "func": "createProject",
        "args": [{ "valueVar": "${表单数据}" }]
      }
    },
    {
      "type": "OutputToast",
      "outputToastFuncSetting": {
        "toastValueVar": "${String.concat('项目创建成功-', 表单数据.projectName)}"
      }
    }
  ]
}
```

> **方案选择小结**：先看交互步骤白名单里有没有现成的（方案 0），有就用；没有再走 `CallScript`（方案 A）。

---

自动化类似于一个函数，参数是一个对象数组。调用方通过传递参数给自动化程序，自动化程序在执行特定动作后将结果返回给调用方。**不管何种方式调用自动化（HTTP调用、工具栏按钮调用、监听器调用、调用自动化步骤等），传入的输入参数数量必须和自动化定义中的接收参数（varList）长度保持一致，否则参数无法正确映射。**

## 输入参数（varList）

调用自动化时按 `varList` 定义传递输入参数。每个参数由 `id` 和 `name` 组成：

- **`id`** 是平台预设的**参数类型标识符**（如 `String`、`Integer`、`Array<Record>`、`HttpRequest` 等），与 `retValues` 的 `id` 一样**不允许修改**。它决定参数能接收什么数据、能在表达式中调用哪些方法。
- **`name`** 是**用户自定义的参数名**，用于在表达式中引用。后续步骤通过 `${name}` 读取参数值。
- 同一自动化中所有 `name` 必须唯一；不同 `id`（即类型）但 `name` 重复会引用歧义，必须避免。
- 同一个 `id` 允许在 `varList` 中出现多次（用不同 `name` 区分语义），例如 `Record` 既可作为"数据表记录"又可作为"仪表盘筛选条件"。
- 输入参数按 `varList` 的位置顺序与调用方传入参数一一对应：第一个传入参数对应 `varList[0]`，依此类推。**传入参数数量必须等于 `varList` 长度**，否则映射失败。

### 引用示例

```jsonc
// varList 定义
[
  { "id": "Record",         "name": "当前记录",   "optional": false },
  { "id": "Array<Record>",  "name": "选中记录",   "optional": false },
  { "id": "BpmnEvent",      "name": "工作流事件", "optional": false }
]
```

后续步骤可通过 `${当前记录.title}`、`${选中记录.size()}`、`${工作流事件.id}` 读取这些参数。

### 支持的类型清单

按用途分组，全部可用作 `varList[].id`：

#### 基础类型

| id | 含义 | 表达式示例 |
|----|------|----------|
| `String` | 字符串 | `${名称}`、`${String.concat('前缀-', 名称)}` |
| `Integer` | 整数 | `${数量 + 1}`、`${数量 > 0}` |
| `Double` | 小数 | `${金额 * 1.13}` |
| `Boolean` | 布尔值 | `${是否启用 ? 'on' : 'off'}` |
| `Object` | 通用对象 | `${对象.fieldA}` |

#### 集合类型

| id | 含义 |
|----|------|
| `Array<String>` | 字符串数组 |
| `Array<Object>` | 对象数组 |
| `Array<Record>` | 数据表记录列表 |
| `Array<Task>` | 工作流任务列表 |
| `Array<Instance>` | 工作流实例列表 |

#### 业务对象类型

| id | 含义 |
|----|------|
| `Record` | 数据表记录（也用于"仪表盘筛选条件"等承载结构化记录的场景）|
| `UploadFile` | 上传文件 |
| `Task` | 工作流任务 |
| `Instance` | 工作流实例 |

#### 请求 / 调用上下文类型

| id | 含义 |
|----|------|
| `HttpRequest` | HTTP 请求（HTTP 触发自动化时的入参） |
| `DesignerRequest` | 打印模板的 HTTP 请求 |
| `MqMessage` | 消息队列消息 |
| `WebsiteDynamicInvokeContext` | 网站页面动态渲染上下文 |
| `PageDesignerPageData` | 自定义界面通过 URL 访问的地址参数 |
| `SurveyContext` | 问卷调查上下文 |

#### 事件类型（监听器 / 工作流 / 仪表盘 等触发场景）

| id | 含义 |
|----|------|
| `AppEvent` | 监听器事件（数据/工作流/通用事件的统一入口）|
| `NotificationEvent` | 通知事件 |
| `FormEvent` | 表单事件 |
| `RecordFormCloseEvent` | 数据表表单关闭事件 |
| `ViewEvent` | 数据表视图事件 |
| `BpmnEvent` | 工作流事件 |
| `BpmnTaskArgs` | 工作流任务参数 |
| `ChartClickEvent` | 图表点击事件 |
| `CardEvent` | 仪表盘卡片事件 |
| `RichtextClickEvent` | 富文本卡片点击事件 |
| `TextIndexEvent` | 搜索引擎点击事件 |
| `DeptClickEvent` | 部门节点点击事件 |

#### 查询条件 / 拦截上下文类型

| id | 含义 |
|----|------|
| `QueryCondition` | 关联查询条件 |
| `RelationQueryCondition` | 关联记录自动化返回数据条件 |
| `ViewCondition` | 数据表查询条件 |
| `TableRecordQueryBeforeContext` | 数据详情查询前调用上下文 |
| `TableRecordQueryAfterContext` | 数据详情查询后调用上下文 |
| `TableQueryBeforeContext` | 视图数据查询前调用上下文 |
| `TableQueryAfterContext` | 视图数据查询后调用上下文 |

> ⚠️ **id 必须从上述清单中精确选取**，不允许自行编造类型名（如不存在 `int`、`string`、`List<String>` 等写法）。

## 变量

变量有唯一的标识符和类型——这一标识符就是 `varList[].name`（输入参数）或步骤 `retValues[].name`（步骤返回值），它们共享同一个表达式作用域。在自动化的表达式中可以通过 `${name}` 引用所有变量。变量有作用域范围，超过作用域范围的变量不可见，在表达式中不可以引用未定义的变量。


## 流程控制

- 条件判断(If) 步骤通过一个表达式来控制自动化程序的流转，条件表达式需要返回 boolean 值。
- 列表循环(ForEach) 步骤接受一个表达式作为循环集合，对于每一个循环集合中的列表项会顺序的执行列表循环的子步骤。
- 循环(While) 步骤根据条件重复执行子步骤。
- 调用脚本(CallScript) 调用应用中已有脚本模块的函数，并返回结果。
- 设置自动化返回值(SetReturnValue) 步骤接受一个表达式作为自动化的返回值。该步骤可以多次调用，后一次调用会覆盖前一次调用的结果。

## 表达式
织信使用 UEL 语法的表达式，关于表达式的更多内容，可参见表达式文档的描述

## 自动化步骤

在自动化中可以使用自动化步骤实现程序功能。自动化步骤分为**设置项**（`<type首字母小写>FuncSetting`）和**返回值**（`retValues`）两部分。

### funcSetting 字段命名规则（强约束）

每一步必须携带且仅携带与其 `type` 对应的 `FuncSetting` 字段，命名规则固定为：

> **`type` 首字母小写 + `FuncSetting`**

| type 示例 | 对应字段名 |
|----------|-----------|
| `OutputToast` | `outputToastFuncSetting` |
| `OutputDynamicForm` | `outputDynamicFormFuncSetting` |
| `CallScript` | `callScriptFuncSetting` |
| `If` | `ifFuncSetting` |
| `ForEach` | `forEachFuncSetting` |

> ⚠️ **禁止使用 schema 未声明的字段名。** 例如把 `InsertRecord` 的 setting 写成 `insertRecordSetting` 或 `insertRecordFuncSetting` 都不会被识别——更重要的是，`InsertRecord` 本身就不是合法的自动化 type（应改用 `CallScript` 调脚本函数）。

### 步骤白名单（仅以下 type 合法）

仅以下 type 可以出现在 `funcSettingList` 中。**选 type 时先按前文「关键决策」分析意图**：需要交互的优先在白名单里找现成的 `Output*` 步骤（许多"创建记录""发起工作流""上传文件"等场景都有专门的交互步骤）；纯后台逻辑则用 `CallScript`。**任何不在白名单里的 type 都是错误**，例如把 `InsertRecord/UpdateRecord/Http/SetVar/CreateBpmnProcess/CallAI` 等当作步骤都属于严重错误。

| 类别 | 合法 type |
|------|----------|
| 控制流程 | `If` `If.true` `If.false` `ForEach` `While` `CallScript` `SetReturnValue` |
| 弹窗 | `OutputConfirm` `OutputUpload` `OutputUploadExcel` `OutputDynamicForm` `OutputDynamicTable` `OutputRecordInfo` `OutputRecordCreate` `OutputRecordSelect` `OutputFormDesigner` `OutputOpenFile` `OutputRichtext` `OutputString` `OutputPageDesigner` `OutputOpenSplitDrawer` `OutputOpenWebsite` |
| 提示 | `OutputToast` `OutputNotification` |
| 表单操作 | `OutputSetFormValue` `OutputFormValidate` `OutputRecordFormRefresh` `OutputCloseRecordInfo` `OutputSetFormTableSelection` |
| 数据表操作 | `OutputTableRefresh` `OutputTableEvent` `OutputRefreshTableViewColumn` `OutputSetTableViewFilter` `OutputSetTableViewFilterCondition` `OutputSetTableViewOrderBy` `OutputSetTableViewExpand` `OutputSetTableViewSelection` `OutputSetTableViewActiveRecords` `OutputSetTableViewRootRecordId` `OutputSetTableViewData` |
| 仪表盘 | `OutputRefreshDashboardCard` `OutputSetDashboardFilter` |
| 页面/导航 | `OutputOpenUrl` `OutputExternal` `OutputSetExternalUrl` `OutputCloseModuleVisitHistory` |
| 打印/下载 | `OutputPrintRecord` `OutputPrintRecordList` `OutputPrintByPageDesigner` `OutputDownloadFile` `OutputDownloadExcel` |
| 脚本/剪贴板 | `OutputInjectScript` `OutputExecuteScript` `OutputCopyClipboard` `OutputGetAppClipboard` `OutputSetAppClipboard` |
| 多媒体/扫码 | `OutputPlayAudio` `OutputPlayImage` `OutputQRCodeScanner` |
| 搜索/消息 | `OutputTextindexSearch` `OutputWebsitePageFireEvent` |
| 工作流 | `OutputBpmnEvent` `OutputBpmnProcess` `OutputBpmnTaskInfo` `OutputBpmnInstanceInfo` |

### 返回值与引用规则

每个步骤可在其 `retValues` 中声明 0 个、1 个或多个返回值。每个返回值由 `id` 和 `name` 组成：

- **`id`** 是平台预设的、与步骤类型绑定的**固定标识**，**不允许修改**。它取决于步骤的 type，不同 type 对应的 id 不同（例如 `QueryRecordList` 的 id 是 `list`，`UpdateRecord` 的 id 包含 `count` 和 `recordIdList`，并非所有步骤都叫 `result`）。
- **`name`** 是用户**自定义**的别名，作为该返回值在表达式中的引用名。后续步骤通过 `${name}` 引用该值。
- 同一自动化中，所有 `name` 必须唯一，重名会导致引用歧义。

#### 引用示例

```jsonc
// 步骤 A（OutputDynamicForm）
retValues = [{ "id": "result", "name": "表单数据" }]

// 步骤 B（CallScript）
retValues = [{ "id": "result", "name": "新项目记录" }]
```

后续步骤可通过 `${表单数据}`、`${新项目记录}` 引用上述值。

#### 自动化中合法步骤的返回值结构速查

| 步骤 type | 返回值结构（id → 默认 name） |
|----------|---------------------------|
| `If` / `If.true` / `If.false` / `While` / `SetReturnValue` | 无返回值 |
| `ForEach` | `object` → 列表项；`idx` → 索引 |
| `CallScript` | `result` → 返回值 |
| `OutputConfirm` | `result` → 是否确认 |
| `OutputDynamicForm` / `OutputFormDesigner` / `OutputRecordCreate` | `result` → 表单数据 |
| `OutputDynamicTable` | `result` → 记录列表 |
| `OutputRecordSelect` / `OutputUploadExcel` | `result` → 数据列表 |
| `OutputUpload` / `OutputOpenFile` | `result` → 文件列表 |
| `OutputOpenUrl` / `OutputOpenWebsite` | `result` → 返回值 |
| `OutputQRCodeScanner` | `result` → 扫码结果 |
| `OutputBpmnProcess` | `result` → 工作流实例ID |
| `OutputFormValidate` | `result` → 校验通过 |
| `OutputGetAppClipboard` | `result` → 应用剪切板数据 |
| `OutputExecuteScript` | `result` → 脚本返回数据 |

> 表中"默认 name"是平台预置的中文名，可在编辑步骤时改为任意符合表达式上下文命名规范的别名；改名后引用使用新的 name。其他 Output 类步骤（如各种 `Set*`、`Refresh*`、`Print*`、`Download*` 等）均无返回值。

> ⚠️ **`OutputUploadExcel` 返回值结构**：最外层是 sheet **数组**（即使只有 1 个 sheet 也是数组），整体形如 `[{ id, name, isHidden, data: { header, headerName, list } }, ...]`。访问数据前必须先取下标（如 `excelData[0]` 或按 `id`/`name` 找对应 sheet），**不能把 `excelData` 当单个 sheet 对象用**。`data.list` 是行数组，`list[0]` 是表头行（与 `data.header` 重复），真正的数据从 `list[1]` 开始。

### 控制流程步骤

| type | 说明 |
|------|------|
| If | 条件判断，通过表达式控制流程分支，必须包含If.true和If.false两个子节点 |
| If.true | If的true分支，作为If的子节点存在 |
| If.false | If的false分支，作为If的子节点存在 |
| ForEach | 循环列表，对集合中的每一项顺序执行子步骤 |
| While | 条件循环，当表达式为true时重复执行子步骤 |
| CallScript | 调用应用中的脚本函数，并返回结果 |
| SetReturnValue | 设置自动化返回值，调用方可获取该值 |

### 交互步骤 - 弹窗/表单

| type | 说明 |
|------|------|
| OutputConfirm | 打开确认对话框，等待用户点击确认或取消 |
| OutputUpload | 上传文件，支持Base64或共享存储模式 |
| OutputUploadExcel | 上传并解析Excel文件，返回解析后的数据 |
| OutputDynamicForm | 打开自定义表单页面，等待用户填写并提交 |
| OutputDynamicTable | 打开自定义表格弹窗，供用户操作数据 |
| OutputRecordInfo | 打开记录详情弹窗，显示指定记录的表单 |
| OutputRecordCreate | 打开创建记录表单弹窗，返回新建的记录 |
| OutputRecordSelect | 打开记录选择弹窗，让用户选择记录 |
| OutputFormDesigner | 打开表单设计器表单弹窗 |
| OutputOpenFile | 预览共享存储文件，支持Excel、Word、Ppt等 |
| OutputRichtext | 在弹窗中显示富文本内容 |
| OutputString | 在弹窗中显示文本、markdown、html等内容 |
| OutputOpenSplitDrawer | 打开侧边栏或对话框，可展示模块、网站、打印模板等 |
| OutputOpenWebsite | 弹窗打开平台内网站模块的页面 |
| OutputPageDesigner | 打开打印模板弹窗，支持打印和导出图片 |

### 交互步骤 - 提示/通知

| type | 说明 |
|------|------|
| OutputToast | 显示短暂的Toast提示消息 |
| OutputNotification | 显示带标题的通知提示框 |

### 交互步骤 - 表单操作

| type | 说明 |
|------|------|
| OutputSetFormValue | 设置当前打开表单的字段值 |
| OutputFormValidate | 校验当前表单，返回校验状态 |
| OutputRecordFormRefresh | 刷新记录表单，重新加载表单数据 |
| OutputCloseRecordInfo | 关闭当前记录详情或创建弹窗 |
| OutputSetFormTableSelection | 设置表单内子表格的选中行 |

### 交互步骤 - 数据表操作

| type | 说明 |
|------|------|
| OutputTableRefresh | 刷新数据表视图数据 |
| OutputTableEvent | 向前端发送数据表变更事件 |
| OutputRefreshTableViewColumn | 刷新数据表视图列配置 |
| OutputSetTableViewFilter | 设置数据表筛选条件 |
| OutputSetTableViewFilterCondition | 设置数据表筛选条件（条件列表模式） |
| OutputSetTableViewOrderBy | 设置数据表排序规则 |
| OutputSetTableViewExpand | 设置数据表展开/折叠状态（树形结构） |
| OutputSetTableViewSelection | 设置数据表选中行 |
| OutputSetTableViewActiveRecords | 设置数据表激活记录（高亮显示） |
| OutputSetTableViewRootRecordId | 设置树形数据表的根节点 |
| OutputSetTableViewData | 直接向前端数据表注入或更新数据 |

### 交互步骤 - 仪表盘

| type | 说明 |
|------|------|
| OutputRefreshDashboardCard | 刷新仪表盘卡片数据 |
| OutputSetDashboardFilter | 设置仪表盘筛选条件 |

### 交互步骤 - 页面/导航

| type | 说明 |
|------|------|
| OutputOpenUrl | 打开URL地址（新窗口/当前窗口/iframe） |
| OutputExternalUrl | 在模块区域内嵌显示外部URL |
| OutputSetExternalUrl | 动态修改已显示的外部页面地址 |
| OutputCloseModuleVisitHistory | 关闭模块访问历史记录 |

### 交互步骤 - 打印/下载

| type | 说明 |
|------|------|
| OutputPrintRecord | 以表单形式打印单条记录 |
| OutputPrintRecordList | 以表格形式打印多条记录 |
| OutputPrintByPageDesigner | 使用打印模板打印记录 |
| OutputDownloadFile | 下载文件到本地 |
| OutputDownloadExcel | 将数据导出为Excel并下载 |

### 交互步骤 - 客户端脚本/剪贴板

| type | 说明 |
|------|------|
| OutputInjectScript | 向页面注入并执行JavaScript代码 |
| OutputExecuteScript | 在前端执行JavaScript代码，可传入变量并获取返回值 |
| OutputCopyClipboard | 复制文本到系统剪贴板 |
| OutputGetAppClipboard | 获取应用内部剪贴板数据 |
| OutputSetAppClipboard | 将数据写入应用内部剪贴板 |

### 交互步骤 - 多媒体/扫码

| type | 说明 |
|------|------|
| OutputPlayAudio | 播放音频文件 |
| OutputPlayImage | 打开图片预览窗口 |
| OutputQRCodeScanner | 打开二维码扫描（移动端） |

### 交互步骤 - 全文检索/消息

| type | 说明 |
|------|------|
| OutputTextindexSearch | 打开全文检索搜索界面 |
| OutputWebsitePageFireEvent | 向网站页面发送自定义事件 |

### 交互步骤 - 工作流(BPMN)

| type | 说明 |
|------|------|
| OutputBpmnEvent | 向前端发送工作流变更事件 |
| OutputBpmnProcess | 打开工作流发起表单弹窗 |
| OutputBpmnTaskInfo | 打开工作流任务详情弹窗 |
| OutputBpmnInstanceInfo | 打开工作流实例详情弹窗 |

> `OutputBpmnProcess` 发起工作流时，**会在启动表中新插入一条记录**（不是复用调用方传入的源记录）。如果后续步骤要操作这条启动记录（更新状态、读字段等），**必须**通过 `informat.bpmn.getInstanceVar(moduleId, instanceId, 'form_recordId')` 拿到新记录的 ID，而不是用源记录 ID。

## 交互式执行

自动化程序中可以插入需要用户交互的步骤，这一类步骤我们称之为交互式步骤。

交互式执行机制
自动化流程中可以包含需要用户参与的步骤，这类步骤称为 交互式步骤。
当自动化执行到交互式步骤时，系统会：
自动保存当前执行上下文与变量状态
暂停流程执行
通知用户进行界面交互（如填写表单、确认操作等）
用户提交后恢复执行上下文
从该步骤继续向下执行
交互式执行可以让自动化流程自然地融入业务人工处理环节，适用于审批、输入、确认等场景。
交互式执行的自动化程序可以更方便的让开发人员编写业务过程。执行中所有界面交互类的自动化步骤都是交互式的。

交互式步骤判定规则（重要）
所有自动化步骤中，type 以 Output 开头的步骤，均属于交互式步骤。
即：
type.startsWith("Output")

示例（属于交互式步骤）
OutputDynamicForm
OutputDynamicTable
OutputConfirm
OutputToast
OutputPageDesigner
OutputRecordSelect
OutputUpload

> **执行环境约束**：交互式步骤**只能在客户端执行的自动化中使用**。绑定在控件按钮上的自动化是客户端执行；定时任务、监听器（除客户端触发的外）、工作流任务完成后调用等是服务器执行，**所有 `Output*` 步骤都不可用**。详见文档顶部「执行环境」小节。

## 监听器调用自动化

监听器是一种触发机制，通过捕捉系统中的特定事件（如数据变更、用户操作等），自动执行相应的自动化程序。

### 事务特性

所有事件监听器（发送通知和客户端触发除外）在触发点的同一事务中执行。若自动化抛出异常，包括原操作在内的所有事务将回滚。

**重要限制**：非客户端运行的监听器属于**服务器执行**环境，必须不包含交互式步骤（type 以 Output 开头的步骤）。监听器中如需"创建记录""发通知"等操作，使用 `CallScript` 调用脚本完成。详见文档顶部「执行环境」小节。

### 监听器参数结构

自动化接收单一参数 `AppEvent`：
```json
{
  "id": "事件类型ID",
  "content": { /* 事件内容，格式因事件类型而异 */ }
}
```

### 事件类型列表

#### 数据表记录事件

| 事件ID | 说明 | 触发时机 |
|--------|------|----------|
| `record.create.before` | 创建记录前 | 用户通过表单创建记录（自动化/脚本创建不触发） |
| `record.create.after` | 创建记录后 | 同上 |
| `record.update.before` | 更新记录前 | 用户通过表单更新记录 |
| `record.update.after` | 更新记录后 | 同上 |
| `record.delete.before` | 删除记录前 | 用户通过表单删除记录 |
| `record.delete.after` | 删除记录后 | 同上 |

**record.create.before** content参数：
```json
{
  "record": {"name": "值", "age": 0},
  "source": "form",
  "tableId": "listenerData"
}
```

**record.create.after** content参数：
```json
{
  "afterRecord": {"id": "d6dhvhodo62nl", "name": "值", "age": 0, "seq": 2},
  "record": {"name": "值", "age": 0},
  "source": "form",
  "tableId": "listenerData"
}
```

**record.update.before** content参数：
```json
{
  "beforeRecord": {"id": "xg2d0hi83cwym", "name": "旧值", "age": 100, "seq": 1},
  "record": {"id": "xg2d0hi83cwym", "name": "新值"},
  "source": "form",
  "tableId": "listenerData",
  "updateFieldList": ["name"]
}
```

**record.update.after** content参数：
```json
{
  "afterRecord": {"id": "xg2d0hi83cwym", "name": "新值", "age": 100, "seq": 1},
  "beforeRecord": {"id": "xg2d0hi83cwym", "name": "旧值", "age": 100, "seq": 1},
  "record": {"id": "xg2d0hi83cwym", "name": "新值"},
  "source": "form",
  "tableId": "listenerData",
  "updateFieldList": ["name"],
  "updateRowCount": 1
}
```

**record.delete.before / record.delete.after** content参数：
```json
{
  "record": {"id": "d6dhvhodo62nl", "name": "值", "age": 0, "seq": 2},
  "source": "form",
  "tableId": "listenerData"
}
```

> 事件顺序：主表创建前 → 子表创建前后 → 主表创建后。关联列表删除仅删除关联关系，不触发子表事件。

#### 评论事件

| 事件ID | 说明 |
|--------|------|
| `record.comment.create.after` | 用户发表评论后 |
| `record.comment.delete.after` | 用户删除评论后 |

content参数：
```json
{
  "comment": {
    "id": 0,
    "parentId": 0,
    "content": "{richtext_json}",
    "recordId": "xg2d0hi83cwym",
    "tableId": "listenerData"
  }
}
```

#### 排序事件

| 事件ID | 说明 |
|--------|------|
| `record.rownumber.update.before` | 拖拽修改记录顺序前 |
| `record.rownumber.update.after` | 拖拽修改记录顺序后 |

**record.rownumber.update.before** content参数：
```json
{
  "beforeRowNumber": 4,
  "recordId": "gf13shmq3njqf",
  "source": "form",
  "tableId": "listenerData"
}
```

**record.rownumber.update.after** content参数：
```json
{
  "afterRowNumber": 3,
  "beforeRowNumber": 4,
  "recordId": "gf13shmq3njqf",
  "source": "form",
  "tableId": "listenerData"
}
```

#### 自动化执行事件

| 事件ID | 说明 |
|--------|------|
| `app.automatic.before` | 自动化执行开始 |
| `app.automatic.success` | 自动化执行成功 |

content参数：
```json
{
  "args": ["param1"],
  "id": "trang7ixclbtg",
  "uuid": "trang7ixclbtg:sesgv3tgz0el",
  "draft": false,
  "isDraft": false
}
```

#### 定时任务事件

| 事件ID | 说明 |
|--------|------|
| `app.schedule.before` | 定时任务开始执行 |
| `app.schedule.success` | 定时任务执行成功 |

content参数：
```json
{
  "id": "tlijinwmbtnet",
  "name": "任务名称",
  "requestId": "arqwu3bsirbh8",
  "serverId": "informat-biz2-prd",
  "startTime": 1718157714369,
  "endTime": 1718092915132
}
```

#### 应用级事件

| 事件ID | 说明 | 触发方式 |
|--------|------|----------|
| `app.enter` | 用户进入应用 | 客户端触发，可包含交互式步骤 |
| `app.module.enter` | 用户进入模块 | 客户端触发，可包含交互式步骤 |
| `app.publish` | 应用发布后 | 服务端触发 |

**app.enter** content参数：包含完整的应用信息、用户信息、平台信息、URL参数等。

**app.module.enter** content参数：在app.enter基础上增加 `moduleId`、`moduleKey` 等模块信息。

**app.publish** content参数：
```json
{
  "appId": "i1mwqy35y88hl",
  "appDefineId": "demoApp",
  "companyId": "icxt9rsd1f0ai",
  "build": 1906,
  "publishUser": "username"
}
```

#### 成员事件

| 事件ID | 说明 |
|--------|------|
| `app.member.add.after` | 成员加入应用后 |
| `app.member.remove.after` | 成员移除应用后 |
| `app.member.role.update.after` | 成员角色更新后 |

**app.member.add.after** content参数：
```json
{
  "appId": "i1mwqy35y88hl",
  "appDefineId": "demoApp",
  "companyId": "icxt9rsd1f0ai",
  "userId": "bt4tdzx8vtjoe",
  "roleList": ["admin"]
}
```

**app.member.role.update.after** content参数：
```json
{
  "appId": "i1mwqy35y88hl",
  "appDefineId": "demoApp",
  "companyId": "icxt9rsd1f0ai",
  "userId": "yvkc2kwpy3xzr",
  "beforeRoleList": ["admin", "ceo"],
  "afterRoleList": ["admin", "ceo", "manager"]
}
```


## 数据表工具栏按钮调用自动化

可以在数据表顶部工具栏创建按钮，点击按钮时调用自动化流程。

### 创建步骤

1. 先创建自动化流程（使用 `_automatic_save_define`）
2. 使用 `_table_create_tool_bar_button` 创建工具栏按钮，`action` 设为 `CallAutomatic`
3. 在 `actionSetting` 中配置 `automaticId`（自动化ID）和可选的 `varList`（变量列表）

### 参数示例

```json
{
  "tableId": "myTable",
  "name": "执行自动化",
  "action": "CallAutomatic",
  "actionSetting": {
    "automaticId": "vc3xpthwbf8ne",
    "varList": [
      { "value": "${tableSelectedRecordList}" },
      { "value": "${user.id}" }
    ]
  },
  "buttonSetting": {
    "type": "primary"
  }
}
```

### 支持的变量

- `${user}` — 当前用户对象，包含 id、name、roleList、departmentList 属性，可使用 `${user.id}` 获取用户ID
- `${tableSelectedRecordList}` — 用户在数据表中选中的记录列表
- `${moduleKey}` — 当前模块标识符

## 数据表表单工具栏按钮调用自动化

可以在数据表表单工具栏创建按钮，点击按钮时调用自动化流程。

### 创建步骤

1. 先创建自动化流程（使用 `_automatic_save_define`）
2. 使用 `_table_create_form_tool_bar_btn` 创建表单工具栏按钮，`action` 设为 `CallAutomatic`
3. 在 `actionSetting` 中配置 `automaticId`（自动化ID）和可选的 `varList`（变量列表）

### 参数示例

```json
{
  "tableId": "myTable",
  "name": "提交审批",
  "action": "CallAutomatic",
  "actionSetting": {
    "automaticId": "vc3xpthwbf8ne",
    "varList": [
      { "value": "${formRecord}" }
    ]
  },
  "buttonSetting": {
    "type": "primary"
  }
}
```

### 支持的变量

- `${user}` — 当前用户对象，包含 id、name、roleList、departmentList 属性，可使用 `${user.id}` 获取用户ID
- `${formRecord}` — 当前表单记录数据
- `${formModuleKey}` — 表单模块标识符

## 通过HTTP的方式调用

开启通过HTTP的方式调用后，自动化程序允许使用HTTP请求的方式调用，调用地址如下

```
https://{host}/web${cluster}/automatic/${appId}/${automaticId}?args=${args}
```

- ${host} 为服务的部署地址
- ${cluster} 为部署的集群ID，单节点部署时为0
- ${appId} 为应用的ID(不是标识符)
- ${automaticId} 为自动化的标识符
- ${args} 为请求参数。传递给自动化的参数是一个数组，格式为JSON后的数据

当调用成功后返回内容为自动化执行的返回值，返回值将会按照自动化配置的格式返回。
注意：通过HTTP请求的自动化内部不能包含交互输出相关的步骤

## 工作流调用自动化

工作流（BPMN）可以通过监听器配置，在特定事件发生时自动调用自动化程序。工作流在流程定义上配置 `BpmnListenerSetting`，每个监听器可以绑定多个事件类型和多个自动化程序。当事件触发时，系统会将 `BpmnEvent` 对象作为自动化的第一个输入参数传入。

### 监听器配置

每个工作流流程定义可以配置多个监听器（`BpmnListener`），每个监听器包含：

| 字段 | 类型 | 说明 |
|------|------|------|
| id | String | 监听器标识 |
| name | String | 监听器名称 |
| eventList | List\<String\> | 监听的事件类型列表 |
| automaticList | List\<String\> | 触发的自动化ID列表 |
| isEnable | boolean | 是否启用 |

### 事件类型

工作流支持以下事件类型，按场景分为三大类：

#### 一、用户任务事件

| 事件类型 | 说明 |
|---------|------|
| TASK_CREATED | 用户任务创建完成 |
| TASK_COMPLETED | 用户任务完成（审批通过等） |
| TASK_ASSIGNED | 用户任务被分配处理人 |
| TASK_OWNER_CHANGED | 任务所有者变更 |
| TASK_DUEDATE_CHANGED | 任务截止日期变更 |

#### 二、流程实例事件

| 事件类型 | 说明 |
|---------|------|
| PROCESS_CREATED | 流程实例创建 |
| PROCESS_STARTED | 流程实例启动 |
| PROCESS_COMPLETED | 流程实例正常结束 |
| PROCESS_CANCELLED | 流程实例被取消 |

#### 三、活动节点事件

| 事件类型 | 说明 |
|---------|------|
| ACTIVITY_STARTED | 活动节点开始执行 |
| ACTIVITY_COMPLETED | 活动节点执行完成 |
| ACTIVITY_CANCELLED | 活动节点被取消 |
| MULTI_INSTANCE_ACTIVITY_STARTED | 多实例活动开始 |
| MULTI_INSTANCE_ACTIVITY_COMPLETED | 多实例活动完成 |
| MULTI_INSTANCE_ACTIVITY_COMPLETED_WITH_CONDITION | 多实例活动按条件完成 |
| MULTI_INSTANCE_ACTIVITY_CANCELLED | 多实例活动被取消 |

### BpmnEvent 对象结构

自动化接收到的第一个参数为 `BpmnEvent` 对象，包含以下字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| appId | String | 应用ID |
| moduleUuid | String | 模块UUID |
| moduleId | String | 模块Key |
| type | String | 事件类型名称 |
| processDefinitionId | String | 流程定义ID |
| tenantId | String | 租户ID |
| instance | BpmnInstance | 流程实例信息（见下表） |
| task | BpmnTask | 任务信息，仅用户任务事件时有值 |
| activityEvent | BpmnActivityEvent | 活动事件信息，仅活动节点事件时有值 |
| processEvent | BpmnProcessEvent | 流程事件信息，仅流程实例事件时有值 |
| numberOfInstances | Integer | 多实例总数，仅多实例事件时有值 |
| numberOfActiveInstances | Integer | 多实例活跃数，仅多实例事件时有值 |
| numberOfCompletedInstances | Integer | 多实例已完成数，仅多实例事件时有值 |
| sequential | Boolean | 是否串行多实例，仅多实例事件时有值 |

#### BpmnInstance（流程实例信息）

所有事件都包含 `instance` 字段：

| 字段 | 类型 | 说明 |
|------|------|------|
| id | String | 流程实例ID |
| name | String | 流程实例名称 |
| businessKey | String | 业务键（关联的数据记录ID） |
| procDefId | String | 流程定义ID |
| startTime | Date | 启动时间 |
| endTime | Date | 结束时间 |
| startUserId | String | 发起人用户ID |
| tenantId | String | 租户ID |
| procDefName | String | 流程定义名称 |
| deleteReason | String | 删除原因 |

#### BpmnTask（任务信息）

仅在用户任务事件（TASK_CREATED、TASK_COMPLETED、TASK_ASSIGNED、TASK_OWNER_CHANGED、TASK_DUEDATE_CHANGED）时有值：

| 字段 | 类型 | 说明 |
|------|------|------|
| id | String | 任务ID |
| name | String | 任务名称 |
| taskDefKey | String | 任务定义Key（节点标识） |
| assignee | String | 当前处理人用户ID |
| owner | String | 任务所有者用户ID |
| procInstId | String | 流程实例ID |
| procDefId | String | 流程定义ID |
| procDefName | String | 流程定义名称 |
| procInstName | String | 流程实例名称 |
| executionId | String | 执行ID |
| tenantId | String | 租户ID |
| dueDate | Date | 截止日期 |
| claimTime | Date | 认领时间 |
| startTime | Date | 任务创建时间 |
| delegation | String | 委派状态 |

#### BpmnActivityEvent（活动事件信息）

仅在活动节点事件（ACTIVITY_STARTED、ACTIVITY_COMPLETED、ACTIVITY_CANCELLED及多实例活动事件）时有值：

| 字段 | 类型 | 说明 |
|------|------|------|
| activityId | String | 活动节点ID |
| activityName | String | 活动节点名称 |
| activityType | String | 活动类型（如userTask、serviceTask等） |
| behaviorClass | String | 行为类全名 |
| executionId | String | 执行ID |
| type | String | 事件类型 |
| processInstanceId | String | 流程实例ID |
| processDefinitionId | String | 流程定义ID |

#### BpmnProcessEvent（流程事件信息）

仅在流程实例事件（PROCESS_CREATED、PROCESS_STARTED、PROCESS_COMPLETED、PROCESS_CANCELLED）时有值，包含 `entity` 字段（BpmnExecutionEntity）：

| 字段 | 类型 | 说明 |
|------|------|------|
| entity.id | String | 执行实体ID |
| entity.name | String | 名称 |
| entity.activityId | String | 当前活动ID |
| entity.businessKey | String | 业务键 |
| entity.businessStatus | String | 业务状态 |
| entity.currentActivityId | String | 当前活动节点ID |
| entity.deleteReason | String | 删除原因 |
| entity.deploymentId | String | 部署ID |
| entity.processDefinitionId | String | 流程定义ID |
| entity.processDefinitionKey | String | 流程定义Key |
| entity.processDefinitionName | String | 流程定义名称 |
| entity.processDefinitionVersion | Integer | 流程定义版本 |
| entity.processInstanceId | String | 流程实例ID |
| entity.processInstanceBusinessKey | String | 流程实例业务键 |
| entity.startTime | Date | 开始时间 |
| entity.startUserId | String | 发起人用户ID |
| entity.tenantId | String | 租户ID |

### 用户任务完成后调用自动化

工作流的用户任务节点可以配置 `completeAutomaticId`，当该任务被完成（审批通过等）后，系统会自动调用指定的自动化程序。此时传递给自动化的第一个输入参数为 `BpmnTaskArgs` 对象。

> **执行环境**：此场景属于**服务器执行**，自动化中**不能包含任何 `Output*` 交互步骤**。

#### BpmnTaskArgs 对象结构

| 字段 | 类型 | 说明 |
|------|------|------|
| procDefId | String | 流程定义ID |
| procInstId | String | 流程实例ID |
| activityId | String | 任务节点定义Key（活动ID） |
| taskId | String | 任务ID |

#### 自动化 varList 配置

自动化需要定义一个 `BpmnTaskArgs` 类型的输入参数来接收任务参数：

```jsonc
// varList 定义
[
  { "id": "BpmnTaskArgs", "name": "任务参数", "optional": false }
]
```

#### 自动化中获取参数

- `${任务参数.procDefId}` — 获取流程定义ID
- `${任务参数.procInstId}` — 获取流程实例ID
- `${任务参数.activityId}` — 获取任务节点定义Key
- `${任务参数.taskId}` — 获取任务ID

#### 使用示例

通过 `CallScript` 调用脚本函数处理任务完成后的业务逻辑：

```jsonc
{
  "funcSettingList": [
    {
      "type": "CallScript",
      "retValues": [{ "id": "result", "name": "处理结果" }],
      "callScriptFuncSetting": {
        "scriptId": "bpmnScript",
        "func": "onTaskComplete",
        "args": [{ "valueVar": "${任务参数}" }]
      }
    }
  ]
}
```

### 各场景事件对象内容对照

| 场景 | type | instance | task | activityEvent | processEvent | 多实例字段 |
|------|------|----------|------|---------------|--------------|-----------|
| 用户任务创建 | TASK_CREATED | ✓ | ✓ | ✗ | ✗ | ✗ |
| 用户任务完成 | TASK_COMPLETED | ✓ | ✓ | ✗ | ✗ | ✗ |
| 用户任务分配 | TASK_ASSIGNED | ✓ | ✓ | ✗ | ✗ | ✗ |
| 任务所有者变更 | TASK_OWNER_CHANGED | ✓ | ✓ | ✗ | ✗ | ✗ |
| 任务截止日期变更 | TASK_DUEDATE_CHANGED | ✓ | ✓ | ✗ | ✗ | ✗ |
| 流程创建 | PROCESS_CREATED | ✓ | ✗ | ✗ | ✓ | ✗ |
| 流程启动 | PROCESS_STARTED | ✓ | ✗ | ✗ | ✓ | ✗ |
| 流程完成 | PROCESS_COMPLETED | ✓ | ✗ | ✗ | ✓ | ✗ |
| 流程取消 | PROCESS_CANCELLED | ✓ | ✗ | ✗ | ✓ | ✗ |
| 活动开始 | ACTIVITY_STARTED | ✓ | ✗ | ✓ | ✗ | ✗ |
| 活动完成 | ACTIVITY_COMPLETED | ✓ | ✗ | ✓ | ✗ | ✗ |
| 活动取消 | ACTIVITY_CANCELLED | ✓ | ✗ | ✓ | ✗ | ✗ |
| 多实例活动开始 | MULTI_INSTANCE_ACTIVITY_STARTED | ✓ | ✗ | ✓ | ✗ | sequential |
| 多实例活动完成 | MULTI_INSTANCE_ACTIVITY_COMPLETED | ✓ | ✗ | ✓ | ✗ | ✓ 全部 |
| 多实例活动条件完成 | MULTI_INSTANCE_ACTIVITY_COMPLETED_WITH_CONDITION | ✓ | ✗ | ✓ | ✗ | ✓ 全部 |
| 多实例活动取消 | MULTI_INSTANCE_ACTIVITY_CANCELLED | ✓ | ✗ | ✓ | ✗ | sequential |

### 自动化中获取事件参数

在自动化中，`BpmnEvent` 作为第一个输入参数传入，可以通过输入参数引用事件数据。例如：

- `${参数1.type}` — 获取事件类型
- `${参数1.instance.id}` — 获取流程实例ID
- `${参数1.instance.businessKey}` — 获取关联的业务数据记录ID
- `${参数1.instance.startUserId}` — 获取流程发起人
- `${参数1.task.assignee}` — 获取当前任务处理人（仅任务事件）
- `${参数1.task.name}` — 获取当前任务名称（仅任务事件）
- `${参数1.activityEvent.activityName}` — 获取活动节点名称（仅活动事件）
- `${参数1.activityEvent.activityType}` — 获取活动节点类型（仅活动事件）
