Files
x-server-mobile/backend/app/service/ApprovalService.php
T
root 78a1921f06 fix: 修复审批详情显示问题
- 修复用户不存在时仍然显示审批人ID的问题
- 即使部分用户不存在,也保留其ID信息显示
- 优化审批人和抄送人的查询逻辑

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:21:15 +08:00

807 lines
31 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\service;
use app\model\ApprovalFlow;
use app\model\ApprovalNode;
use app\model\ApprovalOrder;
use app\model\ApprovalRecord;
use app\model\User;
use support\Db;
use Illuminate\Database\Connection;
class ApprovalService
{
private Connection $db;
private ?FeishuNotificationService $notificationService = null;
public function __construct()
{
$this->db = Db::connection();
}
/**
* 提交审批
*/
public function submit(array $data): ApprovalOrder
{
return $this->db->transaction(function () use ($data) {
// 1. 获取审批流程
$flow = ApprovalFlow::active()
->byBusinessType($data['business_type'])
->with('nodes')
->findOrFail($data['flow_id']);
// 2. 创建审批单
$order = ApprovalOrder::create([
'business_type' => $data['business_type'],
'business_id' => $data['business_id'],
'title' => $data['title'],
'applicant_id' => $data['applicant_id'],
'status' => ApprovalOrder::STATUS_PENDING,
'current_nodes' => $this->getFirstNodeIds($flow),
'flow_id' => $flow->id,
'form_data' => $data['form_data'] ?? [],
'attachments' => $data['attachments'] ?? [],
]);
// 3. 记录提交操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => $flow->nodes->first()->id ?? 0,
'node_type' => 'submit',
'approver_id' => $data['applicant_id'],
'action' => ApprovalRecord::ACTION_SUBMIT,
'comment' => $data['comment'] ?? null,
]);
return $order->load(['flow', 'applicant']);
});
}
/**
* 审批通过
*/
public function approve(int $orderId, int $approverId, ?string $comment = null): ApprovalOrder
{
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
$order = ApprovalOrder::with(['flow.nodes'])->findOrFail($orderId);
// 检查是否为自己审批自己的申请 - 自动通过
if ($order->applicant_id === $approverId) {
error_log('🔄 检测到自审批,自动通过');
return $this->autoApproveSelfNode($order, $approverId);
}
if (!$order->canApprove()) {
throw new \Exception('当前状态无法审批');
}
$currentNodeIds = $order->current_nodes ?? [];
error_log("🔍 当前节点 IDs: " . json_encode($currentNodeIds));
$currentNode = ApprovalNode::whereIn('id', $currentNodeIds)->first();
if (!$currentNode) {
error_log("❌ 未找到节点,IDs: " . json_encode($currentNodeIds));
throw new \Exception('当前节点不存在');
}
// 检查当前用户是否已经在当前节点审批过
$existingRecord = ApprovalRecord::where('order_id', $order->id)
->where('node_id', $currentNode->id)
->where('approver_id', $approverId)
->whereIn('action', [ApprovalRecord::ACTION_APPROVE, ApprovalRecord::ACTION_REJECT])
->first();
if ($existingRecord) {
$actionText = $existingRecord->action === ApprovalRecord::ACTION_APPROVE ? '通过' : '拒绝';
throw new \Exception("您已经{$actionText}过此申请,无需重复操作");
}
// 记录审批操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => $currentNode->id,
'node_type' => $currentNode->type,
'approver_id' => $approverId,
'action' => ApprovalRecord::ACTION_APPROVE,
'comment' => $comment,
]);
// 判断节点是否完成
if ($this->isNodeCompleted($order->id, $currentNode->id)) {
// 对于或签和单人审批,更新其他审批人的消息卡片
if ($currentNode->type === ApprovalNode::TYPE_OR_APPROVE || $currentNode->type === 'approver') {
$approver = User::find($approverId);
$approverName = $approver ? $approver->name : '未知';
if ($this->notificationService) {
$this->notificationService->updateMessageCards(
$order->id,
$currentNode->id,
$approverId,
'approved',
$approverName
);
}
}
// 移动到下一节点
$nextNodes = $this->getNextNodes($order->flow, $currentNode->order);
if (empty($nextNodes)) {
// 没有下一节点,审批完成
$order->status = ApprovalOrder::STATUS_APPROVED;
$order->current_nodes = [];
// 通知申请人审批通过
$this->notifyApplicant($order, 'approve');
} else {
// 检查第一个下一节点
$firstNextNode = $nextNodes[0] ?? null;
if ($firstNextNode && $firstNextNode['type'] === 'notify') {
// 下一个是抄送节点,跳过并完成流程
$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);
}
}
$order->save();
}
return $order->fresh(['flow', 'applicant', 'records']);
});
}
/**
* 审批拒绝
*/
public function reject(int $orderId, int $approverId, ?string $comment = null): ApprovalOrder
{
return $this->db->transaction(function () use ($orderId, $approverId, $comment) {
$order = ApprovalOrder::findOrFail($orderId);
// 检查是否为自己审批自己的申请 - 自动取消
if ($order->applicant_id === $approverId) {
error_log('🔄 检测到自审批拒绝,自动取消申请');
return $this->cancel($orderId, $approverId);
}
if (!$order->canApprove()) {
throw new \Exception('当前状态无法审批');
}
$currentNodeIds = $order->current_nodes ?? [];
$currentNode = ApprovalNode::whereIn('id', $currentNodeIds)->first();
// 记录拒绝操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => $currentNode->id ?? 0,
'node_type' => $currentNode->type ?? 'unknown',
'approver_id' => $approverId,
'action' => ApprovalRecord::ACTION_REJECT,
'comment' => $comment,
]);
// 更新其他审批人的消息卡片(拒绝时所有人都需要更新)
$approver = User::find($approverId);
$approverName = $approver ? $approver->name : '未知';
if ($this->notificationService && $currentNode) {
$this->notificationService->updateMessageCards(
$order->id,
$currentNode->id,
$approverId,
'rejected',
$approverName
);
}
// 更新状态为已拒绝
$order->status = ApprovalOrder::STATUS_REJECTED;
$order->current_nodes = [];
$order->save();
// 通知申请人审批被拒绝
$this->notifyApplicant($order, 'reject', $comment);
return $order->fresh(['flow', 'applicant', 'records']);
});
}
/**
* 撤销申请
*/
public function cancel(int $orderId, int $userId): ApprovalOrder
{
$order = ApprovalOrder::findOrFail($orderId);
if ($order->applicant_id !== $userId) {
throw new \Exception('只有申请人可以撤销');
}
if (!$order->canEdit() && !$order->canApprove()) {
throw new \Exception('当前状态无法撤销');
}
// 记录撤销操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => 0,
'node_type' => 'cancel',
'approver_id' => $userId,
'action' => ApprovalRecord::ACTION_CANCEL,
'comment' => '申请人撤销',
]);
$order->status = ApprovalOrder::STATUS_CANCELLED;
$order->current_nodes = [];
$order->save();
return $order->fresh(['flow', 'applicant', 'records']);
}
/**
* 获取审批详情(包含实际审批人信息)
*/
public function getDetail(int $orderId): array
{
$order = ApprovalOrder::with(['flow.nodes', 'applicant', 'records.approver'])
->findOrFail($orderId);
// 获取 form_data 中的实际审批人和抄送人
$formData = $order->form_data ?? [];
$actualApprovers = $formData['approvers'] ?? [];
$actualCcUsers = $formData['cc_users'] ?? [];
// 兼容两种格式:对象数组 [{id:1, name:'xxx'}] 或纯ID数组 [1, 2, 3]
if (!empty($actualApprovers) && isset($actualApprovers[0]['id'])) {
$actualApproverIds = array_column($actualApprovers, 'id');
} else {
$actualApproverIds = $actualApprovers;
}
if (!empty($actualCcUsers) && isset($actualCcUsers[0]['id'])) {
$actualCcUserIds = array_column($actualCcUsers, 'id');
} else {
$actualCcUserIds = $actualCcUsers;
}
// 获取实际审批人的完整用户信息
$actualApproverUsers = [];
$actualApproverIdsArray = [];
if (!empty($actualApproverIds)) {
$users = User::whereIn('id', $actualApproverIds)->get()->keyBy('id');
foreach ($actualApproverIds as $approverId) {
if ($users->has($approverId)) {
$actualApproverUsers[$approverId] = $users->get($approverId)->toArray();
} else {
// 用户不存在,至少保留ID信息
$actualApproverUsers[$approverId] = [
'id' => $approverId,
'name' => '用户' . $approverId . '(不存在)',
'status' => 0,
];
}
$actualApproverIdsArray[] = (int)$approverId;
}
}
// 获取实际抄送人的完整用户信息
$actualCcUserObjects = [];
$actualCcUserIdsArray = [];
if (!empty($actualCcUserIds)) {
$users = User::whereIn('id', $actualCcUserIds)->get()->keyBy('id');
foreach ($actualCcUserIds as $ccUserId) {
if ($users->has($ccUserId)) {
$actualCcUserObjects[$ccUserId] = $users->get($ccUserId)->toArray();
} else {
// 用户不存在,至少保留ID信息
$actualCcUserObjects[$ccUserId] = [
'id' => $ccUserId,
'name' => '用户' . $ccUserId . '(不存在)',
'status' => 0,
];
}
$actualCcUserIdsArray[] = (int)$ccUserId;
}
}
// 处理节点信息,添加实际审批人
$nodes = [];
if ($order->flow && $order->flow->nodes) {
foreach ($order->flow->nodes as $node) {
$nodeArray = $node->toArray();
// 为审批节点添加实际审批人信息
if (in_array($node->type, ['approver', 'and_approve', 'or_approve'])) {
$nodeArray['actual_approvers'] = [];
foreach ($actualApproverIdsArray as $approverId) {
if (isset($actualApproverUsers[$approverId])) {
$nodeArray['actual_approvers'][] = $actualApproverUsers[$approverId];
}
}
// 获取每个实际审批人的审批状态
$nodeArray['approver_statuses'] = [];
foreach ($actualApproverIdsArray as $approverId) {
$record = ApprovalRecord::where('order_id', $orderId)
->where('node_id', $node->id)
->where('approver_id', $approverId)
->whereIn('action', ['approve', 'reject'])
->first();
$nodeArray['approver_statuses'][] = [
'user_id' => $approverId,
'user' => $actualApproverUsers[$approverId] ?? null,
'action' => $record->action ?? null,
'action_name' => $record ? ($record->action === 'approve' ? '已通过' : '已拒绝') : '待审批',
'comment' => $record->comment ?? null,
'created_at' => $record->created_at ?? null,
];
}
}
// 为通知节点添加实际抄送人
if ($node->type === 'notify') {
$nodeArray['actual_cc_users'] = [];
foreach ($actualCcUserIdsArray as $ccUserId) {
if (isset($actualCcUserObjects[$ccUserId])) {
$nodeArray['actual_cc_users'][] = $actualCcUserObjects[$ccUserId];
}
}
}
$nodes[] = $nodeArray;
}
}
// 构建返回数据
$result = $order->toArray();
$result['flow']['nodes'] = $nodes;
$result['actual_approvers'] = array_values($actualApproverUsers);
$result['actual_cc_users'] = array_values($actualCcUserObjects);
return $result;
}
/**
* 获取审批列表
*/
public function getList(int $userId, string $type = 'my', int $page = 1, int $pageSize = 20): array
{
$query = ApprovalOrder::with(['flow', 'applicant']);
switch ($type) {
case 'my':
$query->where('applicant_id', $userId);
error_log("🔍 Debug 'my' query: userId={$userId}");
break;
case 'pending':
// 获取用户待审批的订单
$pendingOrderIds = $this->getPendingOrderIds($userId);
error_log("🔍 Debug 'pending' query: userId={$userId}, pendingOrderIds=" . json_encode($pendingOrderIds));
$query->whereIn('id', $pendingOrderIds);
break;
case 'approved':
// 获取用户已审批的订单(只显示已完成的:approved、rejected、cancelled)
$approvedOrderIds = ApprovalRecord::where('approver_id', $userId)
->where('action', '!=', ApprovalRecord::ACTION_SUBMIT)
->whereIn('action', [ApprovalRecord::ACTION_APPROVE, ApprovalRecord::ACTION_REJECT])
->pluck('order_id')
->unique()
->toArray();
error_log("🔍 Debug 'approved' query: userId={$userId}, approvedOrderIds=" . json_encode($approvedOrderIds));
$query->whereIn('id', $approvedOrderIds)
->whereIn('status', [ApprovalOrder::STATUS_APPROVED, ApprovalOrder::STATUS_REJECTED, ApprovalOrder::STATUS_CANCELLED]);
break;
case 'cc':
// 获取抄送给我的订单
$allOrders = ApprovalOrder::where('status', '!=', ApprovalOrder::STATUS_DRAFT)->get();
$ccOrderIds = [];
foreach ($allOrders as $order) {
$formData = $order->form_data ?? [];
$ccUsers = $formData['cc_users'] ?? [];
// 兼容两种格式:[{id:29, name:'...'}] 或 [29] 或 [{id:29}]
if (!empty($ccUsers)) {
if (is_array($ccUsers[0] ?? null) && isset($ccUsers[0]['id'])) {
// 对象数组格式: [{id:29, name:'...'}]
$ccUserIds = array_column($ccUsers, 'id');
} else if (is_numeric($ccUsers[0] ?? null)) {
// ID数组格式: [29, 30]
$ccUserIds = $ccUsers;
} else {
$ccUserIds = [];
}
if (in_array($userId, $ccUserIds)) {
$ccOrderIds[] = $order->id;
}
}
}
error_log("🔍 Debug 'cc' query: userId={$userId}, ccOrderIds=" . json_encode($ccOrderIds));
$query->whereIn('id', $ccOrderIds);
break;
}
$total = $query->count();
error_log("🔍 Debug total count: type={$type}, total={$total}");
$list = $query->orderBy('created_at', 'desc')
->offset(($page - 1) * $pageSize)
->limit($pageSize)
->get();
error_log("🔍 Debug list count: type={$type}, page={$page}, count=" . $list->count());
// 转换为数组避免序列化问题
$listArray = $list->map(function ($item) {
return [
'id' => $item->id,
'title' => $item->title,
'business_type' => $item->business_type,
'status' => $item->status,
'created_at' => $item->created_at ? $item->created_at->toDateTimeString() : null,
'applicant' => $item->applicant ? [
'id' => $item->applicant->id,
'name' => $item->applicant->name,
] : null,
'flow' => $item->flow ? [
'id' => $item->flow->id,
'name' => $item->flow->name,
] : null,
];
})->toArray();
return [
'list' => $listArray,
'total' => $total,
'page' => $page,
'page_size' => $pageSize,
];
}
/**
* 获取第一个节点ID列表
*/
private function getFirstNodeIds(ApprovalFlow $flow): array
{
return $flow->nodes
->where('order', 0)
->pluck('id')
->toArray();
}
/**
* 判断节点是否完成
*/
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'] ?? [];
// 兼容两种格式:[{id:1, name:'...'}] 或 [1]
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;
}
}
/**
* 获取下一节点
*/
private function getNextNodes(ApprovalFlow $flow, int $currentOrder): array
{
return $flow->nodes
->where('order', '>', $currentOrder)
->sortBy('order')
->values()
->toArray();
}
/**
* 获取用户待审批的订单ID列表
*/
private function getPendingOrderIds(int $userId): array
{
// 获取用户参与的待审批订单
$pendingOrders = ApprovalOrder::where('status', ApprovalOrder::STATUS_PENDING)
->whereNotNull('current_nodes')
->get();
$result = [];
foreach ($pendingOrders as $order) {
// 从 form_data 获取审批人列表
$formData = $order->form_data ?? [];
$approvers = $formData['approvers'] ?? [];
// 兼容两种格式:[{id:1, name:'...'}] 或 [1]
if (!empty($approvers)) {
if (is_array($approvers[0] ?? null) && isset($approvers[0]['id'])) {
// 对象数组格式: [{id:1, name:'...'}]
$approverIds = array_column($approvers, 'id');
} else {
// ID数组格式: [1, 2, 3]
$approverIds = $approvers;
}
if (in_array($userId, $approverIds)) {
// 检查是否已审批
$hasApproved = ApprovalRecord::where('order_id', $order->id)
->where('approver_id', $userId)
->whereIn('action', [ApprovalRecord::ACTION_APPROVE, ApprovalRecord::ACTION_REJECT])
->exists();
if (!$hasApproved) {
$result[] = $order->id;
}
}
}
}
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));
// 获取第一个下一节点的 ID(用于消息映射)
$nextNodeId = $nextNodes[0]['id'] ?? null;
// 为每个审批人发送通知
foreach ($approverIds as $approverId) {
try {
$this->notificationService->setAppByUser($approverId)
->sendApprovalNotification([
'user_id' => $approverId,
'applicant_id' => $order->applicant_id,
'title' => '新的审批待办',
'applicant' => $order->applicant->name,
'type' => $businessTypeName,
'content' => "**申请标题**: {$order->title}\n**申请人**: {$order->applicant->name}",
'url' => $detailUrl,
'order_id' => $order->id,
'node_id' => $nextNodeId, // 添加节点ID用于保存消息映射
]);
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 = config('feishu_notification.base_url');
// 如果没有配置,使用当前请求构建
if (!$baseUrl) {
// 检查是否在 CLI 环境
if (PHP_SAPI === 'cli' || !request()) {
// CLI 环境:使用默认域名
$baseUrl = 'https://uniservice-mobile.hnxinyouhe.com';
} else {
// Web 环境:检查反向代理的协议头
$scheme = request()->header('x-forwarded-proto') ?? request()->header('x-scheme') ?? 'https';
$host = request()->host();
$baseUrl = $scheme . '://' . $host;
}
}
// 统一使用审批详情页,不再跳转到具体业务模块的详情页
return "{$baseUrl}/approval/detail/{$order->id}";
}
/**
* 获取业务类型名称
*/
private function getBusinessTypeName(string $businessType): string
{
$typeNames = [
'business_trip' => '出差申请',
'expense' => '费用报销',
'leave' => '请假申请',
'purchase' => '采购申请',
];
return $typeNames[$businessType] ?? $businessType;
}
/**
* 自动通过申请人自己的审批节点
* 当审批人是申请人自己时,自动通过当前节点
*/
private function autoApproveSelfNode(ApprovalOrder $order, int $approverId): ApprovalOrder
{
$currentNodeIds = $order->current_nodes ?? [];
error_log("🔄 自审批自动通过 - 当前节点: " . json_encode($currentNodeIds));
// 检查订单是否已经结束
if (empty($currentNodeIds)) {
error_log("❌ 自审批:订单已完成,current_nodes为空");
if ($order->status === ApprovalOrder::STATUS_APPROVED) {
throw new \Exception('该申请已通过,无需重复操作');
} else if ($order->status === ApprovalOrder::STATUS_REJECTED) {
throw new \Exception('该申请已被拒绝');
} else if ($order->status === ApprovalOrder::STATUS_CANCELLED) {
throw new \Exception('该申请已被撤销');
}
throw new \Exception('该申请已完成,无法重复操作');
}
$currentNode = ApprovalNode::whereIn('id', $currentNodeIds)->first();
if (!$currentNode) {
error_log("❌ 自审批:当前节点不存在,IDs: " . json_encode($currentNodeIds));
throw new \Exception('当前节点不存在');
}
// 记录自动审批操作
ApprovalRecord::create([
'order_id' => $order->id,
'node_id' => $currentNode->id,
'node_type' => $currentNode->type,
'approver_id' => $approverId,
'action' => ApprovalRecord::ACTION_APPROVE,
'comment' => '系统自动通过(申请人自审批)',
]);
// 检查节点是否完成(单人审批节点会完成,会签节点需要所有人审批)
if ($this->isNodeCompleted($order->id, $currentNode->id)) {
error_log("✅ 自审批节点完成,移动到下一节点");
// 移动到下一节点
$nextNodes = $this->getNextNodes($order->flow, $currentNode->order);
if (empty($nextNodes)) {
// 流程结束
$order->status = ApprovalOrder::STATUS_APPROVED;
$order->current_nodes = [];
error_log("✅ 自审批完成整个流程");
// 通知申请人审批通过
$this->notifyApplicant($order, 'approve');
} else {
// 下一个是通知节点或审批节点
$isNotify = collect($nextNodes)->every(fn($n) => $n->type === 'notify');
if ($isNotify) {
// 下一个是通知节点,流程结束
$order->status = ApprovalOrder::STATUS_APPROVED;
$order->current_nodes = [];
error_log("✅ 自审批后到达通知节点,流程完成");
// 通知申请人审批通过
$this->notifyApplicant($order, 'approve');
} else {
// 下一个是审批节点,移动到该节点
$order->current_nodes = collect($nextNodes)->pluck('id')->toArray();
error_log("➡️ 自审批后移动到下一节点: " . json_encode($order->current_nodes));
// 通知下一节点的审批人
$this->notifyNextApprovers($order, $nextNodes);
}
}
} else {
error_log("⏳ 自审批节点未完成(会签节点),等待其他审批人");
}
$order->save();
return $order->fresh(['flow', 'applicant', 'records']);
}
}