> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alforse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 工作流

> 自动响应 Alforse 事件或排程：在画布上将一个触发器连接到条件和操作，发布后，逐步检查每次运行。

工作流让 Alforse 在事情发生时自动做出反应：销售订单一落到某位客户经理名下就通知他，工单一进入搁置就创建一个问题，或在发货单过账后通知另一个系统。拥有工作流权限的用户在**自动化 → 工作流**下设计这些自动化，并在**自动化 → 运行**下审查它们的执行情况。

## 概览

每个工作流都绘制在一块画布上。一张触发器卡片位于顶部；条件和操作卡片挂在它下面，一个触发器可以分出多条相互独立的路径。在您选择“**发布**”之前，什么都不会运行。此后，每次触发都会成为一条已记录的运行，您可以打开并检查它的每一步，参见[运行与历史](#runs-and-history)。

Alforse screenshot**自动化 → 工作流下的工作流构建器画布：一张触发器卡片连接到条件和操作步骤，以及面板和发布按钮**

一个触发器分成多个分支，每个分支都有自己的结局。

## 什么会启动工作流

工作流始终恰好有一个**触发器**步骤。在其上，“**触发器类型**”切换项提供“**事件**”或“**排程**”；选择其中一个会清除您为另一个配置的所有内容。

### 记录事件

事件指明某一种记录类型上的某一种变更。共有三种形式：

| 事件形式 | 示例 | 传递给工作流的数据 |
| - | - | - |
| 已创建 | `job.created` | 新创建的记录 |
| 已删除 | `purchaseOrder.deleted` | 记录被删除之前的快照 |
| 某一列已更改 | `customer.assignee.changed` | 该记录，以及该字段的 `before` 和 `after` 值 |

NOTE

**没有通用的“已更新”事件**

您需要指明所关心的字段，而不是“任何变化”。可监视的记录类型有十种：采购订单、销售订单、工单、物料、收据、发货单、报价、供应商、客户和问题。每种都公开一份简短的受监视字段列表，对任何其他字段的编辑都不会启动工作流。

### 业务时刻

在选择器的更下方，“**业务时刻**”标题下是 Alforse 内置流程中的九个里程碑：

| 领域 | 时刻 |
| - | - |
| 生产 | 工单已释放 · 工单已搁置 · 工单工序已完成 |
| 销售 | 报价已发送 · 报价已接受 |
| 物流 | 收据已过账 · 发货单已过账 |
| 开票 | 销售发票已过账 · 采购发票已过账 |

业务时刻告诉工作流涉及*哪些*记录（即它们的标识），但不复制它们的字段。当后续步骤需要该时刻未提供的值时，请在其前面放置一个**查找**（Find）步骤。

### 排程

选择“**排程**”可按时钟运行。您设置“**频率**”为每日、每周或每月，选择适用的日期，然后输入“**一天中的时间**”和“**时区**”。编辑时，“**下次触发时间**：”（Next fires at:）一行会预览即将到来的触发。

HEADS UP

**排程绝不会补跑**

由于 Alforse 把挂钟时间与时区分开保存，09:00 的排程在时钟调整之后仍会在 09:00 触发。固定在 31 日的每月排程会直接**跳过**较短的月份。如果在某次运行到期时 Alforse 不可用，它不会补跑：而是等待下一个到期时间，任何逾期超过一小时的运行都会记录为已跳过。每个排程还带有最多五分钟的固定抖动以分散负载，因此 09:00 实际上指的是 09:00 到 09:05 之间的某个时刻。

### 限制谁的更改算数

对于事件触发器，“**触发者**”决定由“**人员**”、“**工作流**”还是“**两者**”所做的编辑可以触发工作流。新触发器默认为“**人员**”，这是安全的设置，因为它会忽略由任何工作流（包括本工作流）所做的更改。仅在有意让一个自动化驱动另一个时，才切换为“**两者**”。

## 构建工作流

### 六种步骤类型

步骤在面板中按以下顺序列出：

| 步骤 | 在画布上的作用 |
| - | - |
| **触发器** | 唯一的入口。没有其他步骤可以连接到它。 |
| **条件**（Condition） | 选择运行要走的一条路径。路径是一组子句；“**否则**”路径是可选的。 |
| **操作** | 执行工作，即通知、创建、更新或调用外部，并公开各自独立的**成功**和**故障**连接点。 |
| **计算**（Compute） | 从记录中导出一个数字，例如订单总额或报废百分比，而不更改任何内容。 |
| **查找**（Find） | 获取一条记录供后续使用。 |
| **筛选** | 将列表缩小为满足您规则的条目。 |

### 操作能做什么

十六个操作分为三类：

1. **创建（4）**。工单、问题、采购订单或销售订单。它们调用的正是 Alforse 自身界面背后的服务，因此编号序列、默认值和必填字段的适用方式与对人完全相同。
2. **更新（10）**。每种可监视的记录类型一个，编辑现有记录。
3. **通知和调用外部（2）**。“**通知某人**”和“**调用外部 URL**”。

NOTE

**更新有意设得很窄**

每个更新操作只公开一组由 Alforse 定义的简短字段，例如负责人、到期日、参考号、优先级。您无法在工作流中更改状态，也没有任何操作会删除内容。工作流可以*监视*的字段与可以*写入*的字段是分别维护的两份列表。

### 向步骤提供值

字段可以包含您输入的字面值，也可以包含上游产生的值。在文本字段中输入 `{` 会打开变量菜单，列出较早的步骤、它们的输出，以及深达两层的属性。

只有*一定*在当前步骤之前已执行的步骤才会出现在那里。条件分支另一侧的值不会列出，对它们的任何引用在发布时都会被拒绝。

### 对列表中的每一项各运行一次步骤

把一个列表接入期望单个值的字段，该步骤就会循环，对每个条目运行一次，最多 100 次；表单会指出这一点。把两个不同的列表接入同一个步骤会在发布时被拒绝，因为循环将没有唯一的来源。

## 调用外部 URL

“**调用外部 URL**”会发出一个 HTTP 请求，即 webhook，让另一个系统响应 Alforse 中的事件。

FieldType

<details>
  <summary>**URL**required`text`</summary>

  `https` 端点。它可以包含变量，例如路径中的记录 id。
</details>

<details>
  <summary>**方法**required`choice`</summary>

  `GET`、`POST`、`PUT`、`PATCH` 或 `DELETE`；新步骤默认为 `GET`。
</details>

<details>
  <summary>**标头**`name/value rows`</summary>

  额外的请求标头，例如授权密钥。允许使用变量，运行历史会屏蔽每个标头的*值*。
</details>

<details>
  <summary>**正文**`text`</summary>

  填入变量后的负载。仅在 `POST`、`PUT` 和 `PATCH` 时可用并发送。
</details>

HEADS UP

**webhook 步骤的限制**

* 仅接受 `https`。解析到私有或链路本地范围的地址同样会被拒绝，其中包括 `localhost` 和云元数据端点。
* 绝不会跟随重定向；十秒后仍未应答的请求会被放弃。
* 成功范围之外的响应会将该步骤标记为失败。
* Alforse 拥有八个标头，您无法替换它们。
* 请求不带签名。如果接收方必须验证发送方身份，请在标头中包含共享密钥。

## 保存、发布与版本

### 自动保存

您找不到保存按钮：编辑内容会持续保存，标题旁的状态显示为“**保存中…**”、“**已保存**”或“**无法保存**”。不完整的草稿也能正常保存，因为验证要等到发布时才进行。

### 发布

“**发布**”要么完全成功，要么什么都不改变。在上线之前，Alforse 会确认存在触发器、没有步骤反馈到更早的步骤、必填字段已填写，并且每个变量都指向上游步骤。失败会汇总在一个面板中；选择其中一项会将画布滚动到相关步骤。

发布同时也是电源开关。已发布的版本就是会触发的版本；“**取消发布**”会停止工作流但不删除任何内容，再次发布即可使其恢复。没有已发布版本的工作流标记为**草稿**。

### 版本

版本一经发布即被锁定。要继续编辑，请从版本菜单创建新版本，它以已发布版本的副本为起点，版本号递增。正在进行的运行会在其开始时所用的版本上完成，即使期间发布了另一个版本。

### 测试运行

工作流的负责人可以在触发器卡片上选择“**测试运行**”。这是真实的执行，任何操作都会真的发生，但它不会在运行历史中留下条目。

## 权限

工作流由专用的权限模块管理，此外每条路由还要求员工账号。

| 权限 | 授予 |
| - | - |
| **查看** | 工作流列表、构建器和运行历史。 |
| **创建** | 新工作流和新版本。 |
| **更新** | 编辑、发布和测试运行。 |
| **删除** | 删除工作流及其版本和历史。 |

NOTE

**工作流以其负责人的身份运行，而不是以触发它的人的身份**

每一步都以负责人的权限执行，并在每一步重新检查。如果负责人失去对某个区域的访问权，运行会停止，并给出指明该区域的消息。工作流被限制在自己的公司内，运行历史在数据库层面受写保护，因此无论权限多高，都无人能篡改或伪造运行日志。

## 运行与历史

每次触发都会产生一条工作流运行：一条针对该运行的记录，外加每一步各一条，记录输入了什么、输出了什么，以及为何如此结束。

### 运行列表

在**自动化 → 运行**下，每行显示状态、工作流、触发器、时长、负责人和起源记录，后者按名称或编号显示并带链接以便快速访问。当另一次运行引发了本次运行时**，链**列显示“**Hop 2**”（第 2 跳）及以后。运行在排队或执行期间，列表会实时刷新。

<details>
  <summary>**排队中**</summary>

  已接受，等待工作进程。
</details>

<details>
  <summary>**运行中**</summary>

  已被工作进程认领，该进程正在执行各步骤。
</details>

<details open>
  <summary>**成功**</summary>

  所有已执行的步骤均无错误完成。
</details>

<details>
  <summary>**失败**</summary>

  某一步失败，或运行达到了 500 步的上限。
</details>

<details>
  <summary>**已阻止**</summary>

  在任何步骤执行之前被循环防护停止；运行会说明原因。
</details>

<details>
  <summary>**已跳过**</summary>

  从未开始，因为工作流已被取消发布、排程运行已逾期，或上一次运行尚未结束。
</details>

### 查看运行

打开一行会显示“**运行详情**”抽屉，顶部是一句简明的结论，例如 *"Failed at 'notify the buyer': The address answered 500."*（在“通知采购员”处失败：该地址返回 500。）

Alforse screenshot**自动化 → 运行中的运行详情抽屉：结果语句、按工作流顺序排列的步骤列表（已跳过的分支呈灰色），以及展开显示输入和输出的一个步骤**

先看结论语句；只有需要细节时才展开步骤。

步骤按其在工作流中的位置列出，而不是按执行顺序。因此未运行的步骤保持在原位，呈灰色并标为“**未到达**”，或标为已跳过并附原因。展开步骤会显示其**输入**和**输出**；对于条件**，原因**部分会逐个说明每个子句，并高亮所选路径。

循环步骤会记录每一项并附加一个汇总。*"Ran 100 of 150; 50 were not used"*（运行了 150 项中的 100 项；50 项未使用）表示触及了 100 项的限制，而不是错误。

NOTE

**运行可以什么都没做却成功**

如果条件的所有路径都不匹配且没有“**否则**”，该条件就是*成功*的，它做出了正确的决定：停止。此时运行为绿色，尽管大多数步骤从未到达，这正是结论语句用文字解释结果的原因。缺失数据同样会导致跳过而不是失败。而无法读取其输入的条件**不会**走“**否则**”路径：不知道不同于否。

### 失败如何扩散

当某一步失败时，只有它所在的分支停止；兄弟分支继续运行，已连接的**故障**连接点仍会被执行，但运行结束后会报告为失败。权限失败更为严格：即使接了失败路径，它们也会终止该分支。

### 工作流链

如果一个工作流的写入触发了另一个工作流，Alforse 会把这些运行联系起来并显示整条链。同一条链中同一工作流出现两次，或链长超过十跳，会产生一个**已阻止**的运行。要从源头防止链式触发，请调整[“**触发者**”](#what-starts-a-workflow)。

HEADS UP

**没有重试按钮**

已完成的运行无法从运行页面重放。请解决外部问题后让触发器再次触发，或在构建器中发起“**测试运行**”。中途崩溃的运行由队列自动重试；由于每一步在执行任何操作之前都会先被认领，重试绝不会重复已完成的步骤。

### 保留与脱敏

每晚，清理作业会分四个阶段处理运行历史的老化。仍在进行中的运行绝不会被动。

| 时间 | 效果 |
| - | - |
| 24 小时 | 卡在排队或运行中的运行被关闭并记为失败。 |
| 7 天 | 存储的值被浓缩为摘要。 |
| 30 天 | 步骤行被删除；运行表头保留。 |
| 90 天 | 整个运行被删除。 |

任何名称类似凭证的内容都保存为 `[REDACTED]`，webhook 标头值始终被屏蔽。只是听起来敏感的字段（例如物料键、授权某事的人）会被保留，因为遮蔽过多的日志与遮蔽过少的日志一样无助于调试。

## 故障排查

| 现象 | 可能原因 | 处理办法 |
| - | - | - |
| 您预期的某次运行不在**自动化 → 运行**下。 | 测试运行从不记录；逾期的排程运行显示为**已跳过**；超过 90 天的运行会被清除。 | 在到期时间查找**已跳过**行，或使用真实触发器代替测试运行。 |
| 工作流触发了两次，或对自己的编辑做出了响应。 | “**触发者**”为“**两者**”或“**工作流**”。 | 将其改为“**人员**”。 |
| 状态为**成功**，但什么都没有改变。 | 某个条件没有匹配任何路径，且没有“**否则**”。 | 结论语句会指出该条件；调整其子句或添加“**否则**”。 |
| 较旧的运行没有显示任何步骤。 | 步骤行在 30 天后被清除。 | 无需修复；抽屉中的横幅会作出解释。 |
| “**发布**”报告问题。 | 必填字段为空、步骤构成循环，或变量引用了并非总是先运行的步骤。 | 选择列出的每个问题以跳转到其步骤。 |

## 相关内容

**通知**

“通知某人”步骤的消息送达的位置，以及每个人如何静音某个主题。

[Open](https://docs.alforse.com/zh/docs/reference/notifications.md)

**审批**

自动化的另一半：对单据按规则驱动的签核关卡。

[Open](https://docs.alforse.com/zh/docs/reference/approvals.md)

**审计日志**

另一份按记录组织的历史，记录谁在何时更改了哪个字段。

[Open](https://docs.alforse.com/zh/docs/reference/audit-log.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.