diff --git a/docs/TEST_REPORT_APPROVAL_20260301.md b/docs/TEST_REPORT_APPROVAL_20260301.md
new file mode 100644
index 0000000..e3d67e1
--- /dev/null
+++ b/docs/TEST_REPORT_APPROVAL_20260301.md
@@ -0,0 +1,371 @@
+# 审批流程测试报告
+
+**测试日期**: 2026-03-01
+**测试版本**: feature/debug-feishu-message (commit: 1e2d337)
+**测试环境**: 生产环境 (45.153.130.80)
+**测试人员**: Claude
+
+---
+
+## 📋 测试环境配置
+
+### 服务器信息
+```
+IP: 45.153.130.80
+域名: uniservice-mobile.hnxinyouhe.com
+后端: x-server-backend-prod (PHP 8.5.3)
+数据库: 1Panel-mysql-XyxS (MySQL)
+```
+
+### 节点配置
+```
+节点ID: 7
+节点名称: 李佳博
+节点类型: and_approve (会签)
+所属流程: 2 (出差审批)
+节点顺序: 0
+```
+
+### 测试用户
+```
+申请人: 李佳博 (ID: 1)
+审批人:
+ - 陈兰 (ID: 2)
+ - 陈标 (ID: 3)
+```
+
+---
+
+## 🧪 测试场景
+
+### 场景1: 会签流程 - 所有人通过
+
+#### 流程图
+```
+提交申请 → 审批人1通过 → 审批人2通过 → 订单完成
+ ↓ ↓(pending) ↓(approved)
+ pending 1/2 已通过 2/2 已通过
+```
+
+#### 测试步骤
+
+| 步骤 | 操作 | 参数 | 预期结果 | 实际结果 | 状态 |
+|------|------|------|----------|----------|------|
+| 1 | 创建审批订单 | `form_data.approvers = [2, 3]`
`current_nodes = [7]`
`status = "pending"` | 订单ID创建成功 | 订单ID=14 | ✅ |
+| 2 | 审批人1通过 | `order_id = 14`
`approver_id = 2`
`action = "approve"` | 状态=pending
已审批=1/2 | 状态=pending
已审批=1/2 | ✅ |
+| 3 | 审批人2通过 | `order_id = 14`
`approver_id = 3`
`action = "approve"` | 状态=approved
已审批=2/2 | 状态=approved
已审批=2/2 | ✅ |
+| 4 | 验证审批记录 | `order_id = 14`
`action = "approve"` | 2条记录 | 2条记录 | ✅ |
+
+#### 审批记录
+```
+ID 1: 陈兰 (ID:2) 在节点 7 审批通过
+ID 2: 陈标 (ID:3) 在节点 7 审批通过
+```
+
+#### 测试代码
+```php
+// 创建订单
+$order = ApprovalOrder::create([
+ 'business_type' => 'business_trip',
+ 'business_id' => 100,
+ 'title' => '会签测试',
+ 'applicant_id' => 1,
+ 'status' => 'pending',
+ 'current_nodes' => [7],
+ 'flow_id' => 2,
+ 'form_data' => ['approvers' => [2, 3]],
+]);
+
+// 审批人1通过
+$service->approve(14, 2);
+
+// 审批人2通过
+$service->approve(14, 3);
+```
+
+---
+
+### 场景2: 拒绝流程 - 任一人拒绝
+
+#### 流程图
+```
+提交申请 → 审批人1拒绝 → 订单结束
+ ↓ ↓(rejected)
+ pending 流程终止
+```
+
+#### 测试步骤
+
+| 步骤 | 操作 | 参数 | 预期结果 | 实际结果 | 状态 |
+|------|------|------|----------|----------|------|
+| 1 | 创建审批订单 | `form_data.approvers = [2, 3]`
`status = "pending"` | 订单ID创建成功 | 订单ID=15 | ✅ |
+| 2 | 审批人1拒绝 | `order_id = 15`
`approver_id = 2`
`action = "reject"`
`comment = "测试拒绝"` | 状态=rejected | 状态=rejected | ✅ |
+| 3 | 验证审批记录 | `order_id = 15`
`action = "reject"` | 1条拒绝记录 | 1条拒绝记录 | ✅ |
+
+#### 审批记录
+```
+ID 1: 陈兰 (ID:2) 在节点 7 审批拒绝 - 原因: "测试拒绝"
+```
+
+#### 测试代码
+```php
+$order = ApprovalOrder::create([
+ 'business_type' => 'business_trip',
+ 'business_id' => 101,
+ 'title' => '拒绝测试',
+ 'applicant_id' => 1,
+ 'status' => 'pending',
+ 'current_nodes' => [7],
+ 'flow_id' => 2,
+ 'form_data' => ['approvers' => [2, 3]],
+]);
+
+// 审批人1拒绝
+$service->reject(15, 2, '测试拒绝');
+```
+
+---
+
+### 场景3: 重复操作防护 - 同一人不能重复审批
+
+#### 流程图
+```
+提交申请 → 审批人1通过 → 审批人1再次通过
+ ↓ ↓(success) ↓(异常)
+ pending 记录已创建 抛出异常
+```
+
+#### 测试步骤
+
+| 步骤 | 操作 | 参数 | 预期结果 | 实际结果 | 状态 |
+|------|------|------|----------|----------|------|
+| 1 | 创建审批订单 | `form_data.approvers = [2, 3]`
`status = "pending"` | 订单ID创建成功 | 订单ID=16 | ✅ |
+| 2 | 审批人1第一次通过 | `order_id = 16`
`approver_id = 2` | 操作成功 | 操作成功 | ✅ |
+| 3 | 审批人1第二次通过 | `order_id = 16`
`approver_id = 2` | 抛出异常 | "您已经通过过此申请" | ✅ |
+
+#### 异常信息
+```
+Exception: 您已经通过过此申请,无需重复操作
+```
+
+#### 测试代码
+```php
+$order = ApprovalOrder::create([
+ 'business_type' => 'business_trip',
+ 'business_id' => 102,
+ 'title' => '重复操作测试',
+ 'applicant_id' => 1,
+ 'status' => 'pending',
+ 'current_nodes' => [7],
+ 'flow_id' => 2,
+ 'form_data' => ['approvers' => [2, 3]],
+]);
+
+try {
+ $service->approve(16, 2); // 第一次 - 成功
+ $service->approve(16, 2); // 第二次 - 异常
+} catch (Exception $e) {
+ // 捕获重复操作异常
+}
+```
+
+---
+
+### 场景4: 撤销流程 - 申请人可撤销
+
+#### 流程图
+```
+提交申请 → 申请人撤销 → 订单结束
+ ↓ ↓(cancelled)
+ pending 流程终止
+```
+
+#### 测试步骤
+
+| 步骤 | 操作 | 参数 | 预期结果 | 实际结果 | 状态 |
+|------|------|------|----------|----------|------|
+| 1 | 创建审批订单 | `applicant_id = 1`
`status = "pending"` | 订单ID创建成功 | 订单ID=17 | ✅ |
+| 2 | 申请人撤销 | `order_id = 17`
`user_id = 1` | 状态=cancelled | 状态=cancelled | ✅ |
+| 3 | 验证撤销记录 | `order_id = 17`
`action = "cancel"` | 1条撤销记录 | 1条撤销记录 | ✅ |
+
+#### 审批记录
+```
+ID 1: 李佳博 (ID:1) 撤销了申请
+```
+
+#### 测试代码
+```php
+$order = ApprovalOrder::create([
+ 'business_type' => 'business_trip',
+ 'business_id' => 103,
+ 'title' => '撤销测试',
+ 'applicant_id' => 1,
+ 'status' => 'pending',
+ 'current_nodes' => [7],
+ 'flow_id' => 2,
+ 'form_data' => ['approvers' => [2, 3]],
+]);
+
+// 申请人撤销
+$service->cancel(17, 1);
+```
+
+---
+
+## 📊 核心逻辑验证
+
+### 节点完成判断逻辑
+
+**代码位置**: `ApprovalService::isNodeCompleted()`
+
+```php
+private function isNodeCompleted(int $orderId, int $nodeId): bool
+{
+ $node = ApprovalNode::findOrFail($nodeId);
+ $records = ApprovalRecord::where('order_id', $orderId)
+ ->where('node_id', $nodeId)
+ ->where('action', 'approve')
+ ->get();
+
+ // 从 form_data 获取实际审批人列表
+ $order = ApprovalOrder::find($orderId);
+ $formData = $order->form_data ?? [];
+ $approvers = $formData['approvers'] ?? [];
+
+ if (!empty($approvers) && is_array($approvers[0] ?? null) && isset($approvers[0]['id'])) {
+ $approverIds = array_column($approvers, 'id');
+ } else {
+ $approverIds = $approvers;
+ }
+
+ if ($node->type === ApprovalNode::TYPE_AND_APPROVE) {
+ // 会签:需要所有人通过
+ return count($records) >= count($approverIds);
+ } elseif ($node->type === ApprovalNode::TYPE_OR_APPROVE) {
+ // 或签:任一人通过即可
+ return count($records) >= 1;
+ } else {
+ // 单人审批:需要一人通过
+ return count($records) >= 1;
+ }
+}
+```
+
+**验证结果**: ✅ 通过
+
+| 节点类型 | 完成条件 | 测试结果 |
+|----------|----------|----------|
+| and_approve (会签) | 已审批人数 >= 总审批人数 | ✅ |
+| or_approve (或签) | 已审批人数 >= 1 | ⏳ 未测试 |
+| approver (单人) | 已审批人数 >= 1 | ⏳ 未测试 |
+
+---
+
+## 🔔 消息发送功能
+
+### 当前状态
+- ⚠️ **飞书消息发送失败** (emoji 编码问题)
+
+### 错误信息
+```
+ErrCode: 200621;
+ErrMsg: parse card json err, please check whether the card json is correct
+```
+
+### 原因分析
+PHP 的 `json_encode()` 默认将 emoji 编码成 Unicode 转义序列:
+- `🔔` → `\ud83d\udd14`
+- `📋` → `\ud83d\udccb`
+
+飞书 API 不接受这种编码格式。
+
+### 待修复项
+1. 修改 `FeishuNotificationService` 的 JSON 编码选项
+2. 使用 `JSON_UNESCAPED_UNICODE` 标志
+
+---
+
+## 🗄️ 数据库表状态
+
+### feishu_message_log
+```sql
+CREATE TABLE IF NOT EXISTS feishu_message_log (
+ id bigint unsigned NOT NULL AUTO_INCREMENT,
+ action varchar(20) NOT NULL COMMENT '操作类型:send=发送, update=更新, update_card=更新卡片',
+ order_id bigint unsigned NOT NULL COMMENT '审批订单ID',
+ node_id bigint unsigned DEFAULT NULL COMMENT '审批节点ID',
+ user_id bigint unsigned DEFAULT NULL COMMENT '用户ID',
+ message_id varchar(64) DEFAULT NULL COMMENT '飞书消息ID',
+ status varchar(10) NOT NULL COMMENT '状态:success=成功, failed=失败',
+ request_data text DEFAULT NULL COMMENT '请求数据(JSON)',
+ response_data text DEFAULT NULL COMMENT '响应数据(JSON)',
+ error_message text DEFAULT NULL COMMENT '错误信息',
+ created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
+ updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (id),
+ KEY idx_order_id (order_id),
+ KEY idx_action (action),
+ KEY idx_status (status),
+ KEY idx_created_at (created_at)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='飞书消息日志表';
+```
+
+**状态**: ✅ 已创建并包含 `updated_at` 字段
+
+---
+
+## ✅ 测试结论
+
+### 通过的测试
+1. ✅ 会签流程 - 所有人通过后订单完成
+2. ✅ 拒绝流程 - 任一人拒绝后订单结束
+3. ✅ 重复操作防护 - 同一人不能重复审批
+4. ✅ 撤销流程 - 申请人可撤销申请
+5. ✅ 审批记录正确保存
+6. ✅ 节点完成判断逻辑正确
+
+### 待解决的问题
+1. ⚠️ 飞书消息发送失败 (emoji 编码问题)
+2. ⏳ 或签 (or_approve) 场景未测试
+3. ⏳ 单人审批 (approver) 场景未测试
+4. ⏳ 多节点流转未测试
+
+### 建议
+1. 优先修复飞书消息 emoji 编码问题
+2. 补充或签和单人审批场景测试
+3. 测试多节点流转场景
+4. 测试消息卡片更新功能(或签/单人审批完成后)
+
+---
+
+## 📝 附录
+
+### 测试文件位置
+```
+/www/x-server-mobile/docs/TEST_REPORT_APPROVAL_20260301.md
+```
+
+### 相关代码文件
+```
+backend/app/service/ApprovalService.php # 审批服务
+backend/app/service/FeishuNotificationService.php # 飞书通知服务
+backend/app/model/ApprovalOrder.php # 审批订单模型
+backend/app/model/ApprovalRecord.php # 审批记录模型
+backend/app/model/ApprovalNode.php # 审批节点模型
+backend/app/model/FeishuMessageLog.php # 消息日志模型
+```
+
+### 测试执行命令
+```bash
+# 会签流程测试
+docker exec x-server-backend-prod php /app/test_approval_logic.php
+
+# 全场景测试
+docker exec x-server-backend-prod php /app/test_approval_all.php
+```
+
+---
+
+**报告生成时间**: 2026-03-01 09:18:00
+**测试执行者**: Claude Code
+**审核状态**: 待审核