fix: 使用 form_data 存储运行时审批人,不修改 approval_node 模板

主要修改:
1. submit() 方法不再修改 approval_node 表,节点仅作为流程模板
2. getList() 的 pending 查询从 form_data.approvers 获取审批人列表
3. approve() 方法从 form_data.approvers 检查用户是否有权限
4. 兼容两种数据格式:[1,2,3] 或 [{id:1},{id:2},{id:3}]

修复问题:
- 之前每次提交申请都会修改 approval_node 表的 approvers 字段
- 这导致流程模板被污染,不同的申请共享同一个节点配置

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-02-26 18:01:40 +08:00
parent 5095f556c8
commit cc3c599c90
2 changed files with 68 additions and 66 deletions
@@ -129,9 +129,15 @@ class BusinessTripController extends BaseController
$data = $request->post(); $data = $request->post();
$data = $data ?? []; $data = $data ?? [];
error_log("📝 提交申请 - 用户ID: {$userId}, 申请ID: {$id}");
error_log("📦 接收到的数据: " . json_encode($data, JSON_UNESCAPED_UNICODE));
$approvers = $data['approvers'] ?? []; $approvers = $data['approvers'] ?? [];
$ccUsers = $data['cc_users'] ?? []; $ccUsers = $data['cc_users'] ?? [];
error_log("👥 审批人列表: " . json_encode($approvers, JSON_UNESCAPED_UNICODE));
error_log("📨 抄送人列表: " . json_encode($ccUsers, JSON_UNESCAPED_UNICODE));
if (empty($approvers)) { if (empty($approvers)) {
return $this->error('请选择审批人'); return $this->error('请选择审批人');
} }
+63 -67
View File
@@ -138,47 +138,21 @@ class BusinessTripService
]); ]);
} }
// 根据审批人创建审批节点 // approval_node 是流程模板,不应在提交时修改
$approverIds = array_column($approvers, 'id'); // 实际的审批人存储在 approval_order.form_data 中
// 获取或创建第一个审批节点(仅用于流程结构)
$node = ApprovalNode::where('flow_id', $flow->id) $node = ApprovalNode::where('flow_id', $flow->id)
->where('order', 0) ->where('order', 0)
->first(); ->first();
if (!$node) { if (!$node) {
// 创建第一个审批节点
$node = ApprovalNode::create([ $node = ApprovalNode::create([
'flow_id' => $flow->id, 'flow_id' => $flow->id,
'type' => count($approverIds) > 1 ? 'and_approve' : 'approver', 'type' => 'approver',
'name' => '审批', 'name' => '审批',
'order' => 0, 'order' => 0,
'approvers' => $approverIds, 'approvers' => [], // 模板节点不存储具体审批人
]); ]);
} else {
// 更新现有节点的审批人
$node->approvers = $approverIds;
$node->save();
}
// 创建抄送节点(如果有抄送人)
$ccUserIds = array_column($ccUsers, 'id');
if (!empty($ccUserIds)) {
$ccNode = ApprovalNode::where('flow_id', $flow->id)
->where('type', 'notify')
->where('order', 1)
->first();
if (!$ccNode) {
ApprovalNode::create([
'flow_id' => $flow->id,
'type' => 'notify',
'name' => '抄送',
'order' => 1,
'approvers' => $ccUserIds,
]);
} else {
$ccNode->approvers = $ccUserIds;
$ccNode->save();
}
} }
// 创建审批单 // 创建审批单
@@ -270,6 +244,8 @@ class BusinessTripService
} }
// 发送飞书通知给审批人 // 发送飞书通知给审批人
error_log("🔔 准备发送审批通知,调用 sendApprovalNotification 方法");
error_log("📋 传递的参数 - approverIds: " . json_encode($approverIds) . ", ccUserIds: " . json_encode($ccUserIds));
$this->sendApprovalNotification($businessTrip, $approverIds, $ccUserIds); $this->sendApprovalNotification($businessTrip, $approverIds, $ccUserIds);
return $businessTrip->fresh(['itineraries', 'approvalOrder']); return $businessTrip->fresh(['itineraries', 'approvalOrder']);
@@ -282,6 +258,8 @@ class BusinessTripService
private function sendApprovalNotification(BusinessTrip $businessTrip, array $approverIds, array $ccUserIds): void private function sendApprovalNotification(BusinessTrip $businessTrip, array $approverIds, array $ccUserIds): void
{ {
try { try {
error_log("🔔 准备发送审批通知: trip_id={$businessTrip->id}, approvers=" . json_encode($approverIds) . ", cc=" . json_encode($ccUserIds));
$notificationService = new \app\service\FeishuNotificationService(); $notificationService = new \app\service\FeishuNotificationService();
// 构建详情链接 // 构建详情链接
@@ -295,6 +273,7 @@ class BusinessTripService
// 通知审批人 // 通知审批人
foreach ($approverIds as $approverId) { foreach ($approverIds as $approverId) {
try { try {
error_log("📧 通知审批人: approver_id={$approverId}");
$notificationService->setAppByUser($approverId) $notificationService->setAppByUser($approverId)
->sendApprovalNotification([ ->sendApprovalNotification([
'user_id' => $approverId, 'user_id' => $approverId,
@@ -304,14 +283,16 @@ class BusinessTripService
'content' => $content, 'content' => $content,
'url' => $detailUrl, 'url' => $detailUrl,
]); ]);
error_log("✅ 审批人通知成功: approver_id={$approverId}");
} catch (\Exception $e) { } catch (\Exception $e) {
error_log("发送审批通知失败: approver_id={$approverId}, error=" . $e->getMessage()); error_log("❌ 发送审批通知失败: approver_id={$approverId}, error=" . $e->getMessage());
} }
} }
// 通知抄送人 // 通知抄送人
foreach ($ccUserIds as $ccUserId) { foreach ($ccUserIds as $ccUserId) {
try { try {
error_log("📧 通知抄送人: cc_user_id={$ccUserId}");
$notificationService->setAppByUser($ccUserId) $notificationService->setAppByUser($ccUserId)
->sendSystemNotification([ ->sendSystemNotification([
'user_ids' => [$ccUserId], 'user_ids' => [$ccUserId],
@@ -319,12 +300,15 @@ class BusinessTripService
'content' => "**申请人**: {$businessTrip->user->name}\n" . $content, 'content' => "**申请人**: {$businessTrip->user->name}\n" . $content,
'url' => $detailUrl, 'url' => $detailUrl,
]); ]);
error_log("✅ 抄送人通知成功: cc_user_id={$ccUserId}");
} catch (\Exception $e) { } catch (\Exception $e) {
error_log("发送抄送通知失败: cc_user_id={$ccUserId}, error=" . $e->getMessage()); error_log("❌ 发送抄送通知失败: cc_user_id={$ccUserId}, error=" . $e->getMessage());
} }
} }
error_log("✅ 审批通知发送完成");
} catch (\Exception $e) { } catch (\Exception $e) {
error_log("发送飞书通知异常: " . $e->getMessage()); error_log("❌ 发送飞书通知异常: " . $e->getMessage());
} }
} }
@@ -380,10 +364,12 @@ class BusinessTripService
break; break;
case 'pending': case 'pending':
// 待我审批:需要查询当前用户是审批人且还未审批的申请 // 待我审批:需要查询当前用户是审批人且还未审批的申请
$pendingOrderIds = ApprovalOrder::where('status', ApprovalOrder::STATUS_PENDING) $allPendingOrders = ApprovalOrder::where('status', ApprovalOrder::STATUS_PENDING)
->where('business_type', 'business_trip') ->where('business_type', 'business_trip')
->pluck('id') ->get();
->toArray(); error_log("🔍 Pending query result: count=" . count($allPendingOrders));
$pendingOrderIds = $allPendingOrders->pluck('id')->toArray();
if (empty($pendingOrderIds)) { if (empty($pendingOrderIds)) {
$query->whereRaw('1 = 0'); // 返回空结果 $query->whereRaw('1 = 0'); // 返回空结果
@@ -393,18 +379,29 @@ class BusinessTripService
$validOrderIds = []; $validOrderIds = [];
foreach ($pendingOrders as $order) { foreach ($pendingOrders as $order) {
$currentNodes = $order->current_nodes ?? []; error_log("🔍 Checking order {$order->id}: form_data=" . json_encode($order->form_data));
// 从 form_data 获取实际的审批人列表
$formData = $order->form_data ?? [];
$approvers = $formData['approvers'] ?? [];
// 检查用户是否在当前节点的审批人列表中 // 兼容两种格式:[1,2,3] 或 [{id:1},{id:2},{id:3}]
$isApprover = false; if (!empty($approvers)) {
foreach ($currentNodes as $nodeId) { if (is_array($approvers[0] ?? null) && isset($approvers[0]['id'])) {
$node = ApprovalNode::find($nodeId); // 对象数组格式: [{id:1, name:'...'}]
if ($node && in_array($userId, $node->approvers ?? [])) { $approverIds = array_column($approvers, 'id');
$isApprover = true; } else {
break; // ID数组格式: [1, 2, 3]
$approverIds = $approvers;
} }
} else {
$approverIds = [];
} }
error_log("🔍 Order {$order->id}: approverIds=" . json_encode($approverIds) . ", userId={$userId}");
// 检查用户是否在审批人列表中
$isApprover = in_array($userId, $approverIds);
error_log("🔍 Order {$order->id}: isApprover=" . ($isApprover ? 'true' : 'false'));
// 如果用户是当前节点审批人,且未审批过,则加入列表 // 如果用户是当前节点审批人,且未审批过,则加入列表
if ($isApprover) { if ($isApprover) {
$hasApproved = ApprovalRecord::where('order_id', $order->id) $hasApproved = ApprovalRecord::where('order_id', $order->id)
@@ -674,27 +671,24 @@ class BusinessTripService
} }
// 检查用户是否是当前审批人 // 检查用户是否是当前审批人
$currentNodes = $approvalOrder->current_nodes ?? []; // 从 form_data 获取实际的审批人列表
$isApprover = false; $formData = $approvalOrder->form_data ?? [];
$approvers = $formData['approvers'] ?? [];
foreach ($currentNodes as $nodeId) { // 兼容两种格式:[1,2,3] 或 [{id:1},{id:2},{id:3}]
$node = ApprovalNode::where('flow_id', $approvalOrder->flow_id) if (!empty($approvers)) {
->where('id', $nodeId) if (is_array($approvers[0] ?? null) && isset($approvers[0]['id'])) {
->first(); // 对象数组格式: [{id:1, name:'...'}]
$approverIds = array_column($approvers, 'id');
if (!$node) { } else {
continue; // ID数组格式: [1, 2, 3]
$approverIds = $approvers;
}
} else {
$approverIds = [];
} }
// 检查用户是否在审批人列表中 if (!in_array($userId, $approverIds)) {
$approvers = $node->approvers ?? [];
if (in_array($userId, $approvers)) {
$isApprover = true;
break;
}
}
if (!$isApprover) {
throw new \Exception('您不是当前审批人'); throw new \Exception('您不是当前审批人');
} }
@@ -708,10 +702,14 @@ class BusinessTripService
throw new \Exception('您已经审批过了'); throw new \Exception('您已经审批过了');
} }
// 获取当前节点ID
$currentNodes = $approvalOrder->current_nodes ?? [];
$currentNodeId = $currentNodes[0] ?? null;
// 记录审批操作 // 记录审批操作
ApprovalRecord::create([ ApprovalRecord::create([
'order_id' => $approvalOrder->id, 'order_id' => $approvalOrder->id,
'node_id' => $currentNodes[0] ?? 1, 'node_id' => $currentNodeId,
'node_type' => 'approver', 'node_type' => 'approver',
'approver_id' => $userId, 'approver_id' => $userId,
'action' => $action, 'action' => $action,
@@ -726,7 +724,6 @@ class BusinessTripService
$businessTrip->status = BusinessTrip::STATUS_REJECTED; $businessTrip->status = BusinessTrip::STATUS_REJECTED;
} else { } else {
// 同意:检查当前节点是否完成,并处理流程流转 // 同意:检查当前节点是否完成,并处理流程流转
$currentNodeId = $currentNodes[0] ?? null;
$nodeCompleted = false; $nodeCompleted = false;
if ($currentNodeId) { if ($currentNodeId) {
@@ -745,8 +742,7 @@ class BusinessTripService
->where('node_id', $currentNodeId) ->where('node_id', $currentNodeId)
->where('action', 'approve') ->where('action', 'approve')
->count(); ->count();
$allApprovers = $node->approvers ?? []; if ($approvedCount >= count($approverIds)) {
if ($approvedCount >= count($allApprovers)) {
$nodeCompleted = true; $nodeCompleted = true;
} }
} }