From 32d19d56eed88a69cf465d587fbf44ce02b9d36f Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Feb 2026 18:49:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题1:BusinessTripService 数据格式兼容性 - 后端期望对象数组 [{id:1, name:'...'}],前端传纯 ID 数组 [1,2,3] - 修复:兼容两种格式,自动提取 id 问题2:ApprovalService 没有消息推送 - 添加 FeishuNotificationService 集成 - approve() 方法:节点完成后通知下一节点审批人,流程完成后通知申请人 - reject() 方法:审批拒绝时通知申请人 问题3:修复重复类定义导致的语法错误 相关文件: - backend/app/service/BusinessTripService.php - backend/app/service/ApprovalService.php Co-Authored-By: Claude Opus 4.6 --- backend/app/service/ApprovalService.php | 147 ++++++++++++++++++++ backend/app/service/BusinessTripService.php | 14 +- 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/backend/app/service/ApprovalService.php b/backend/app/service/ApprovalService.php index e076b95..82d786f 100644 --- a/backend/app/service/ApprovalService.php +++ b/backend/app/service/ApprovalService.php @@ -13,6 +13,7 @@ use Illuminate\Database\Connection; class ApprovalService { private Connection $db; + private ?FeishuNotificationService $notificationService = null; public function __construct() { @@ -96,6 +97,9 @@ class ApprovalService // 没有下一节点,审批完成 $order->status = ApprovalOrder::STATUS_APPROVED; $order->current_nodes = []; + + // 通知申请人审批通过 + $this->notifyApplicant($order, 'approve'); } else { // 检查第一个下一节点 $firstNextNode = $nextNodes[0] ?? null; @@ -103,9 +107,15 @@ class ApprovalService // 下一个是抄送节点,跳过并完成流程 $order->status = ApprovalOrder::STATUS_APPROVED; $order->current_nodes = []; + + // 通知申请人审批通过 + $this->notifyApplicant($order, 'approve'); } else { // 下一个是审批节点,移动到该节点 $order->current_nodes = collect($nextNodes)->pluck('id')->toArray(); + + // 通知下一节点的审批人 + $this->notifyNextApprovers($order, $nextNodes); } } @@ -146,6 +156,9 @@ class ApprovalService $order->current_nodes = []; $order->save(); + // 通知申请人审批被拒绝 + $this->notifyApplicant($order, 'reject', $comment); + return $order->fresh(['flow', 'applicant', 'records']); }); } @@ -381,4 +394,138 @@ class ApprovalService return $result; } + + /** + * 通知申请人 + */ + private function notifyApplicant(ApprovalOrder $order, string $action, ?string $comment = null): void + { + try { + if (!$this->notificationService) { + $this->notificationService = new FeishuNotificationService(); + } + + $applicant = User::find($order->applicant_id); + if (!$applicant) { + error_log("❌ notifyApplicant: 申请人不存在, applicant_id={$order->applicant_id}"); + return; + } + + // 根据业务类型获取详情链接 + $detailUrl = $this->getDetailUrl($order); + + // 构建消息内容 + $title = $action === 'approve' ? '您的申请已通过' : '您的申请已被拒绝'; + $content = "**申请标题**: {$order->title}\n"; + $content .= "**申请类型**: {$this->getBusinessTypeName($order->business_type)}\n"; + + if ($comment) { + $content .= "**审批意见**: {$comment}\n"; + } + + error_log("🔔 通知申请人: applicant_id={$applicant->id}, action={$action}"); + + $this->notificationService->setAppByUser($applicant->id) + ->sendSystemNotification([ + 'user_ids' => [$applicant->id], + 'title' => $title, + 'content' => $content, + 'url' => $detailUrl, + ]); + } catch (\Exception $e) { + error_log('❌ notifyApplicant 失败: ' . $e->getMessage()); + } + } + + /** + * 通知下一节点的审批人 + */ + private function notifyNextApprovers(ApprovalOrder $order, array $nextNodes): void + { + try { + if (!$this->notificationService) { + $this->notificationService = new FeishuNotificationService(); + } + + // 从 form_data 获取审批人列表 + $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 (empty($approverIds)) { + error_log("⚠️ notifyNextApprovers: 没有找到审批人, order_id={$order->id}"); + return; + } + + // 获取详情链接 + $detailUrl = $this->getDetailUrl($order); + + // 业务类型名称 + $businessTypeName = $this->getBusinessTypeName($order->business_type); + + error_log("🔔 通知下一节点审批人: order_id={$order->id}, approverIds=" . json_encode($approverIds)); + + // 为每个审批人发送通知 + foreach ($approverIds as $approverId) { + try { + $this->notificationService->setAppByUser($approverId) + ->sendApprovalNotification([ + 'user_id' => $approverId, + 'title' => '新的审批待办', + 'applicant' => $order->applicant->name, + 'type' => $businessTypeName, + 'content' => "**申请标题**: {$order->title}\n**申请人**: {$order->applicant->name}", + 'url' => $detailUrl, + ]); + error_log("✅ 审批人通知成功: approver_id={$approverId}"); + } catch (\Exception $e) { + error_log("❌ 发送审批通知失败: approver_id={$approverId}, error=" . $e->getMessage()); + } + } + } catch (\Exception $e) { + error_log('❌ notifyNextApprovers 失败: ' . $e->getMessage()); + } + } + + /** + * 获取详情链接 + */ + private function getDetailUrl(ApprovalOrder $order): string + { + $baseUrl = 'https://xsm.dev.hnxinyouhe.com'; + + switch ($order->business_type) { + case 'business_trip': + return "{$baseUrl}/business-trip/detail/{$order->business_id}"; + case 'expense': + return "{$baseUrl}/expense/detail/{$order->business_id}"; + case 'leave': + return "{$baseUrl}/leave/detail/{$order->business_id}"; + case 'purchase': + return "{$baseUrl}/purchase/detail/{$order->business_id}"; + default: + return "{$baseUrl}/approval/detail/{$order->id}"; + } + } + + /** + * 获取业务类型名称 + */ + private function getBusinessTypeName(string $businessType): string + { + $typeNames = [ + 'business_trip' => '出差申请', + 'expense' => '费用报销', + 'leave' => '请假申请', + 'purchase' => '采购申请', + ]; + + return $typeNames[$businessType] ?? $businessType; + } } diff --git a/backend/app/service/BusinessTripService.php b/backend/app/service/BusinessTripService.php index 6cb13b5..2196f22 100644 --- a/backend/app/service/BusinessTripService.php +++ b/backend/app/service/BusinessTripService.php @@ -104,8 +104,18 @@ class BusinessTripService } // 验证审批人和抄送人不能重复 - $approverIds = array_column($approvers, 'id'); - $ccUserIds = array_column($ccUsers, 'id'); + // 兼容两种格式:对象数组 [{id:1, name:'xxx'}] 或纯ID数组 [1, 2, 3] + if (!empty($approvers) && isset($approvers[0]['id'])) { + $approverIds = array_column($approvers, 'id'); + } else { + $approverIds = $approvers; + } + + if (!empty($ccUsers) && isset($ccUsers[0]['id'])) { + $ccUserIds = array_column($ccUsers, 'id'); + } else { + $ccUserIds = $ccUsers; + } // 检查审批人列表中是否有重复 if (count($approverIds) !== count(array_unique($approverIds))) {