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 = $data ?? [];
error_log("📝 提交申请 - 用户ID: {$userId}, 申请ID: {$id}");
error_log("📦 接收到的数据: " . json_encode($data, JSON_UNESCAPED_UNICODE));
$approvers = $data['approvers'] ?? [];
$ccUsers = $data['cc_users'] ?? [];
error_log("👥 审批人列表: " . json_encode($approvers, JSON_UNESCAPED_UNICODE));
error_log("📨 抄送人列表: " . json_encode($ccUsers, JSON_UNESCAPED_UNICODE));
if (empty($approvers)) {
return $this->error('请选择审批人');
}
+62 -66
View File
@@ -138,47 +138,21 @@ class BusinessTripService
]);
}
// 根据审批人创建审批节点
$approverIds = array_column($approvers, 'id');
// approval_node 是流程模板,不应在提交时修改
// 实际的审批人存储在 approval_order.form_data 中
// 获取或创建第一个审批节点(仅用于流程结构)
$node = ApprovalNode::where('flow_id', $flow->id)
->where('order', 0)
->first();
if (!$node) {
// 创建第一个审批节点
$node = ApprovalNode::create([
'flow_id' => $flow->id,
'type' => count($approverIds) > 1 ? 'and_approve' : 'approver',
'type' => 'approver',
'name' => '审批',
'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);
return $businessTrip->fresh(['itineraries', 'approvalOrder']);
@@ -282,6 +258,8 @@ class BusinessTripService
private function sendApprovalNotification(BusinessTrip $businessTrip, array $approverIds, array $ccUserIds): void
{
try {
error_log("🔔 准备发送审批通知: trip_id={$businessTrip->id}, approvers=" . json_encode($approverIds) . ", cc=" . json_encode($ccUserIds));
$notificationService = new \app\service\FeishuNotificationService();
// 构建详情链接
@@ -295,6 +273,7 @@ class BusinessTripService
// 通知审批人
foreach ($approverIds as $approverId) {
try {
error_log("📧 通知审批人: approver_id={$approverId}");
$notificationService->setAppByUser($approverId)
->sendApprovalNotification([
'user_id' => $approverId,
@@ -304,14 +283,16 @@ class BusinessTripService
'content' => $content,
'url' => $detailUrl,
]);
error_log("✅ 审批人通知成功: approver_id={$approverId}");
} catch (\Exception $e) {
error_log("发送审批通知失败: approver_id={$approverId}, error=" . $e->getMessage());
error_log("❌ 发送审批通知失败: approver_id={$approverId}, error=" . $e->getMessage());
}
}
// 通知抄送人
foreach ($ccUserIds as $ccUserId) {
try {
error_log("📧 通知抄送人: cc_user_id={$ccUserId}");
$notificationService->setAppByUser($ccUserId)
->sendSystemNotification([
'user_ids' => [$ccUserId],
@@ -319,12 +300,15 @@ class BusinessTripService
'content' => "**申请人**: {$businessTrip->user->name}\n" . $content,
'url' => $detailUrl,
]);
error_log("✅ 抄送人通知成功: cc_user_id={$ccUserId}");
} 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) {
error_log("发送飞书通知异常: " . $e->getMessage());
error_log("❌ 发送飞书通知异常: " . $e->getMessage());
}
}
@@ -380,10 +364,12 @@ class BusinessTripService
break;
case 'pending':
// 待我审批:需要查询当前用户是审批人且还未审批的申请
$pendingOrderIds = ApprovalOrder::where('status', ApprovalOrder::STATUS_PENDING)
$allPendingOrders = ApprovalOrder::where('status', ApprovalOrder::STATUS_PENDING)
->where('business_type', 'business_trip')
->pluck('id')
->toArray();
->get();
error_log("🔍 Pending query result: count=" . count($allPendingOrders));
$pendingOrderIds = $allPendingOrders->pluck('id')->toArray();
if (empty($pendingOrderIds)) {
$query->whereRaw('1 = 0'); // 返回空结果
@@ -393,18 +379,29 @@ class BusinessTripService
$validOrderIds = [];
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'] ?? [];
// 检查用户是否在当前节点的审批人列表中
$isApprover = false;
foreach ($currentNodes as $nodeId) {
$node = ApprovalNode::find($nodeId);
if ($node && in_array($userId, $node->approvers ?? [])) {
$isApprover = true;
break;
// 兼容两种格式:[1,2,3] 或 [{id:1},{id:2},{id:3}]
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;
}
} 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) {
$hasApproved = ApprovalRecord::where('order_id', $order->id)
@@ -674,27 +671,24 @@ class BusinessTripService
}
// 检查用户是否是当前审批人
$currentNodes = $approvalOrder->current_nodes ?? [];
$isApprover = false;
// 从 form_data 获取实际的审批人列表
$formData = $approvalOrder->form_data ?? [];
$approvers = $formData['approvers'] ?? [];
foreach ($currentNodes as $nodeId) {
$node = ApprovalNode::where('flow_id', $approvalOrder->flow_id)
->where('id', $nodeId)
->first();
if (!$node) {
continue;
}
// 检查用户是否在审批人列表中
$approvers = $node->approvers ?? [];
if (in_array($userId, $approvers)) {
$isApprover = true;
break;
// 兼容两种格式:[1,2,3] 或 [{id:1},{id:2},{id:3}]
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;
}
} else {
$approverIds = [];
}
if (!$isApprover) {
if (!in_array($userId, $approverIds)) {
throw new \Exception('您不是当前审批人');
}
@@ -708,10 +702,14 @@ class BusinessTripService
throw new \Exception('您已经审批过了');
}
// 获取当前节点ID
$currentNodes = $approvalOrder->current_nodes ?? [];
$currentNodeId = $currentNodes[0] ?? null;
// 记录审批操作
ApprovalRecord::create([
'order_id' => $approvalOrder->id,
'node_id' => $currentNodes[0] ?? 1,
'node_id' => $currentNodeId,
'node_type' => 'approver',
'approver_id' => $userId,
'action' => $action,
@@ -726,7 +724,6 @@ class BusinessTripService
$businessTrip->status = BusinessTrip::STATUS_REJECTED;
} else {
// 同意:检查当前节点是否完成,并处理流程流转
$currentNodeId = $currentNodes[0] ?? null;
$nodeCompleted = false;
if ($currentNodeId) {
@@ -745,8 +742,7 @@ class BusinessTripService
->where('node_id', $currentNodeId)
->where('action', 'approve')
->count();
$allApprovers = $node->approvers ?? [];
if ($approvedCount >= count($allApprovers)) {
if ($approvedCount >= count($approverIds)) {
$nodeCompleted = true;
}
}