Files
x-server-mobile/docs/APPROVAL_FLOWCHARTS.md
T
root 7e88c28cc5 docs: 添加审批流程图汇总文档
包含:
1. 节点类型说明 (approver/and_approve/or_approve/notify)
2. 基础流程图 (完整审批流程)
3. 按节点类型的详细流程图
4. 特殊场景流程图 (拒绝/重复操作/撤销/多节点)
5. 状态流转图 (状态机)
6. 消息发送流程图
2026-03-01 09:24:57 +08:00

22 KiB

审批流程图汇总

文档版本: 1.0 更新时间: 2026-03-01 适用版本: feature/debug-feishu-message


📋 目录

  1. 节点类型说明
  2. 基础流程图
  3. 按节点类型的流程图
  4. 特殊场景流程图
  5. 状态流转图

节点类型说明

节点类型定义

类型 常量 说明 完成条件
单人审批 approver 配置1个审批人 1人通过即可完成
会签 and_approve 配置多个审批人 所有人通过才完成
或签 or_approve 配置多个审批人 任一人通过即可完成
通知 notify 无需审批 自动跳过

流程状态

状态 常量 说明
待审批 pending 流程进行中
已通过 approved 流程完成(通过)
已拒绝 rejected 流程结束(拒绝)
已撤销 cancelled 申请人撤销

基础流程图

完整审批流程

┌─────────────┐
│  用户提交申请  │
└──────┬──────┘
       │
       ▼
┌─────────────────────────────┐
│  创建 ApprovalOrder          │
│  - status = pending          │
│  - current_nodes = [节点1]   │
└──────┬──────────────────────┘
       │
       ▼
┌─────────────────────────────┐
│  发送飞书消息给审批人         │
│  - 保存 feishu_message 映射   │
│  - 记录 feishu_message_log   │
└──────┬──────────────────────┘
       │
       ▼
┌─────────────────────────────┐
│      等待审批操作            │
│  (通过/拒绝/撤销)            │
└──────┬──────────────────────┘
       │
       ├─────────────┬─────────────┐
       ▼             ▼             ▼
   [通过]         [拒绝]        [撤销]
       │             │             │
       ▼             ▼             ▼
   检查节点        订单结束      订单结束
   是否完成       (rejected)    (cancelled)
       │
   ├──── [是]    └──── [否]
   ▼                  ▼
移动下一节点      保持pending
       │
       ▼
   有下一节点?
   ├──── [是]    └──── [否]
   │                  ▼
   发送通知        订单结束
   给下一节点       (approved)
   审批人
       │
       ▼
   ┌─────────┐
   │ 继续等待 │
   │  审批   │
   └─────────┘

按节点类型的流程图

1. 单人审批 (approver)

配置: 配置1个审批人 完成条件: 1人通过即可

提交申请
    │
    ▼
┌───────────────────┐
│ 当前节点: 单人审批  │
│ 审批人: [张三]     │
│ status: pending    │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│  张三审批操作      │
└─────┬─────────────┘
      │
      ├─────────────┬─────────────┐
      ▼             ▼             ▼
   [通过]        [拒绝]        [撤销]
      │             │             │
      ▼             ▼             ▼
  1人通过       任一人拒绝     申请人撤销
  满足条件       流程终止       流程终止
      │             │             │
      ▼             ▼             ▼
┌─────────┐   ┌─────────┐  ┌─────────┐
│approved │  │rejected │  │cancelled│
│ 已通过   │  │已拒绝   │  │已撤销   │
└─────────┘   └─────────┘  └─────────┘

通知申请人     通知申请人     通知申请人

关键代码逻辑:

if ($node->type === 'approver') {
    // 单人审批:需要一人通过
    return count($records) >= 1;
}

2. 会签 (and_approve)

配置: 配置多个审批人 完成条件: 所有人通过

提交申请
    │
    ▼
┌───────────────────┐
│ 当前节点: 会签     │
│ 审批人: [张三,李四] │
│ status: pending    │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│  张三审批操作      │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 已审批: 1/2        │
│ 状态: pending     │ ← 仍需其他人审批
│ ⚠️ 继续等待        │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│  李四审批操作      │
└─────┬─────────────┘
      │
      ├─────────────┬─────────────┐
      ▼             ▼             ▼
   [通过]        [拒绝]        [撤销]
      │             │             │
      ▼             ▼             ▼
  所有人通过      任一人拒绝     申请人撤销
  2/2 满足条件    流程终止       流程终止
      │             │             │
      ▼             ▼             ▼
┌─────────┐   ┌─────────┐  ┌─────────┐
│approved │  │rejected │  │cancelled│
│ 已通过   │  │已拒绝   │  │已撤销   │
└─────────┘   └─────────┘  └─────────┘

通知申请人     通知申请人     通知申请人

关键代码逻辑:

if ($node->type === 'and_approve') {
    // 会签:需要所有人通过
    return count($records) >= count($approverIds);
}

测试结果:

  • 第1人通过 → 状态: pending (1/2)
  • 第2人通过 → 状态: approved (2/2) ✅

3. 或签 (or_approve)

配置: 配置多个审批人 完成条件: 任一人通过

提交申请
    │
    ▼
┌───────────────────┐
│ 当前节点: 或签     │
│ 审批人: [张三,李四] │
│ status: pending    │
└─────┬─────────────┘
      │
      ├─────────────┐
      ▼             │
┌───────────────────┐  │
│  张三审批操作      │  │
└─────┬─────────────┘  │
      │                │
      ▼                │
   [通过]              │
      │                │
      ▼                │
┌───────────────────┐  │
│ 1人通过            │  │
│ 满足条件           │  │
│ status: approved  │  │
└─────────┬─────────┘  │
          │            │
          ▼            │
    ┌────────────┐     │
    │订单完成     │     │
    │更新其他人消息│     │ ← 或签/单人特有
    └────────────┘     │
                       │
                       ▼ (李四无需操作)
                  ┌─────────┐
                  │approved │
                  │ 已通过   │
                  └─────────┘

关键代码逻辑:

if ($node->type === 'or_approve') {
    // 或签:任一人通过即可
    return count($records) >= 1;
}

// 或签/单人完成后更新其他人的消息卡片
if ($node->type === 'or_approve' || $node->type === 'approver') {
    $this->notificationService->updateMessageCards(...);
}

测试结果:

  • 第1人通过 → 状态: approved (1/2) ✅

4. 通知节点 (notify)

配置: 配置通知接收人 完成条件: 无需审批,自动跳过

前置节点完成
    │
    ▼
┌───────────────────┐
│ 检查下一节点       │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 下一节点是通知?   │
└─────┬─────────────┘
      │
      ├──── [是]    └──── [否] (审批节点)
      │                  │
      ▼                  ▼
┌───────────────────┐  继续等待审批
│ 自动跳过           │
│ 发送通知给接收人   │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 检查还有后续节点?  │
└─────┬─────────────┘
      │
      ├──── [有]    └──── [无]
      │                  │
      ▼                  ▼
  继续处理           订单完成
  下一节点          (approved)

代码逻辑:

if ($nextNode && $nextNode->type === 'notify') {
    // 下一个是抄送节点,跳过并完成流程
    $approvalOrder->status = ApprovalOrder::STATUS_APPROVED;
    $approvalOrder->current_nodes = [];
}

特殊场景流程图

1. 拒绝流程 (所有节点类型通用)

审批进行中
    │
    ▼
┌───────────────────┐
│  任一审批人拒绝     │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 记录拒绝操作       │
│ action: reject    │
│ comment: 原因...   │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 订单状态 → rejected│
│ 流程立即终止       │
│ 后续节点不执行     │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 通知申请人         │
│ 「您的申请已被拒绝」│
└───────────────────┘

代码逻辑:

if ($action === 'reject') {
    // 拒绝:直接结束流程
    $approvalOrder->status = ApprovalOrder::STATUS_REJECTED;
    $approvalOrder->current_nodes = [];
}

2. 重复操作防护

审批人尝试操作
    │
    ▼
┌───────────────────┐
│ 检查是否已审批     │
│ 查询 approval_record│
└─────┬─────────────┘
      │
      ├──── [已审批]  └──── [未审批]
      │                  │
      ▼                  ▼
┌───────────────────┐  继续处理
│ 抛出异常           │
│ 「您已经XX过此申请」│
└───────────────────┘

代码逻辑:

$existingRecord = ApprovalRecord::where('order_id', $order->id)
    ->where('approver_id', $approverId)
    ->whereIn('action', [ApprovalRecord::ACTION_APPROVE, ApprovalRecord::ACTION_REJECT])
    ->first();

if ($existingRecord) {
    throw new \Exception("您已经{$action}过此申请,无需重复操作");
}

3. 撤销流程

审批进行中
    │
    ▼
┌───────────────────┐
│  申请人撤销申请     │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 记录撤销操作       │
│ action: cancel    │
│ operato: 申请人    │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 订单状态 → cancelled│
│ 流程立即终止       │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 通知所有审批人     │
│ 「申请已被撤销」   │
└───────────────────┘

代码逻辑:

public function cancel(int $orderId, int $userId): ApprovalOrder
{
    $order = ApprovalOrder::findOrFail($orderId);

    if ($order->applicant_id !== $userId) {
        throw new \Exception('只有申请人可以撤销');
    }

    // 记录撤销操作
    ApprovalRecord::create([
        'order_id' => $order->id,
        'node_id' => $currentNodeId,
        'action' => 'cancel',
        'operator_id' => $userId,
    ]);

    $order->status = ApprovalOrder::STATUS_CANCELLED;
    $order->current_nodes = [];
    $order->save();
}

4. 多节点流转

提交申请
    │
    ▼
┌───────────────────┐
│ 节点1: 会签        │
│ [张三, 李四]       │
│ status: pending    │
└─────┬─────────────┘
      │
      ├─────────────┐
      ▼             │
   所有人通过         │
      │             │
      ▼             │
┌───────────────────┐  │
│ 节点1完成          │  │
│ current_nodes     │  │
│   → [节点2]        │  │
└─────┬─────────────┘  │
      │                │
      ▼                │
┌───────────────────┐  │
│ 节点2: 或签        │  │
│ [王五, 赵六]       │  │
│ status: pending    │  │
└─────┬─────────────┘  │
      │                │
      ├─────────────┐  │
      ▼             │  │
   任一人通过         │  │
      │             │  │
      ▼             │  │
┌───────────────────┐  │
│ 节点2完成          │  │
│ current_nodes     │  │
│   → [节点3]        │  │
└─────┬─────────────┘  │
      │                │
      ▼                │
┌───────────────────┐  │
│ 节点3: 通知        │  │
│ 自动跳过           │  │
└─────┬─────────────┘  │
      │                │
      ▼                │
┌───────────────────┐  │
│ 流程完成           │  │
│ status: approved   │  │
│ current_nodes: []  │  │
└───────────────────┘  │
                      │
                      ▼
                  通知申请人

关键代码逻辑:

// 获取当前节点的 order 值
$currentOrder = $node->order ?? 0;

// 查找 order 比当前节点大的下一个节点
$nextNode = ApprovalNode::where('flow_id', $approvalOrder->flow_id)
    ->where('order', '>', $currentOrder)
    ->orderBy('order')
    ->first();

if ($nextNode) {
    if ($nextNode->type === 'notify') {
        // 跳过通知节点,完成流程
        $approvalOrder->status = ApprovalOrder::STATUS_APPROVED;
    } else {
        // 移动到下一节点
        $approvalOrder->current_nodes = [$nextNode->id];
    }
} else {
    // 没有下一节点,流程完成
    $approvalOrder->status = ApprovalOrder::STATUS_APPROVED;
}

状态流转图

完整状态机

                    ┌─────────────┐
                    │   pending    │ ◄─── 初始状态
                    │  (待审批)    │
                    └──────┬──────┘
                           │
         ┌─────────────────┼─────────────────┐
         │                 │                 │
         ▼                 ▼                 ▼
    ┌─────────┐      ┌─────────┐      ┌─────────┐
    │ 节点完成  │      │ 任何人  │      │ 申请人  │
    │检查     │      │  拒绝   │      │  撤销   │
    └────┬────┘      └────┬────┘      └────┬────┘
         │                 │                 │
         │                 ▼                 ▼
         │            ┌─────────┐      ┌─────────┐
         │            │rejected │      │cancelled│
         │            └─────────┘      └─────────┘
         │
         ▼
    ┌─────────────┐
    │ 所有人通过?  │
    └────┬────────┘
         │
         ├──── [是]    └──── [否] (继续等待)
         │
         ▼
    ┌─────────────┐
    │  或签/单人   │
    │  任人通过?  │
    └────┬────────┘
         │
         ├──── [是]    └──── [否] (继续等待)
         │
         ▼
    ┌─────────────┐
    │  有下一节点? │
    └────┬────────┘
         │
         ├──── [是]    └──── [否]
         │                 │
         ▼                 ▼
    ┌─────────┐      ┌─────────┐
    │移动到   │      │approved │
    │下一节点 │      └─────────┘
    └─────────┘

状态转换条件表

当前状态 触发条件 下一状态 说明
pending 所有人通过(会签) pending 还有下一节点
pending 所有人通过(会签)+ 无下一节点 approved 流程完成
pending 任一人通过(或签/单人) pending 还有下一节点
pending 任一人通过(或签/单人)+ 无下一节点 approved 流程完成
pending 任一人拒绝 rejected 流程终止
pending 申请人撤销 cancelled 流程终止
pending 下一节点是notify approved 自动跳过通知节点

消息发送流程图

消息类型

申请提交
    │
    ▼
┌───────────────────┐
│ 检查审批人列表     │
│ form_data.approvers│
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 遍历每个审批人     │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 是否是申请人自己?  │
└─────┬─────────────┘
      │
      ├──── [是]    └──── [否]
      │                 │
      ▼                 ▼
┌─────────────┐   ┌─────────────┐
│发送文本消息   │   │发送卡片消息   │
│(自审批)      │   │(带审批按钮)   │
└─────────────┘   └────┬────────┘
                         │
                         ▼
                   ┌─────────────┐
                   │保存消息映射   │
                   │feishu_message│
                   │message_id    │
                   └─────────────┘

消息卡片更新流程 (或签/单人特有)

订单完成(或签/单人)
    │
    ▼
┌───────────────────┐
│ 获取该节点的所有  │
│ 消息映射           │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 遍历每个其他审批人 │
│ (排除已操作的人)   │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 更新消息卡片       │
│ 移除审批按钮       │
│ 显示「已被XX处理」 │
└─────┬─────────────┘
      │
      ▼
┌───────────────────┐
│ 记录更新日志       │
│ action: update_card│
└───────────────────┘

附录:数据模型关系

核心表关系

approval_flow (审批流程)
    │
    ├── approval_node (审批节点)
    │     ├── 1: approver (单人)
    │     ├── 2: and_approve (会签)
    │     ├── 3: or_approve (或签)
    │     └── 4: notify (通知)
    │
    └── approval_order (审批订单)
          │
          ├── form_data (表单数据)
          │     ├── approvers: [1, 2, 3]
          │     └── cc_users: [4, 5]
          │
          ├── approval_record (审批记录)
          │     ├── action: approve/reject/cancel/submit
          │     └── approver_id: 用户ID
          │
          └── feishu_message (消息映射)
                └── message_id: 飞书消息ID

feishu_message_log (消息日志)
    ├── action: send/update/update_card
    ├── status: success/failed
    └── error_message: 错误信息

文档维护: 开发团队 最后更新: 2026-03-01 相关文档:

  • docs/APPROVAL_NOTIFICATION_ARCHITECTURE.md - 审批通知架构文档
  • docs/TEST_REPORT_COMPLETE_20260301.md - 完整测试报告