where('instance_id', $instanceId) ->orderBy('id', 'asc') ->get() ->toArray(); return array_map(function($r){ return [ 'id' => (int)$r->id, 'instance_id' => (int)$r->instance_id, 'step_index' => (int)$r->step_index, 'record_id' => (int)$r->record_id, 'from_user_id' => (int)$r->from_user_id, 'to_user_id' => (int)$r->to_user_id, 'reason' => $r->reason, 'created_at' => $r->created_at, ]; }, $rows); } /** 转交当前待办给他人 */ public function transferApproval( int $instanceId, int $stepIndex, int $fromUserId, int $toUserId, string $reason = '', ?string $userNameColumn = null ): array { if ($fromUserId === $toUserId) { return ['status' => 'noop', 'msg' => '目标与来源相同,无需转交']; } return \support\Db::transaction(function () use ($instanceId, $stepIndex, $fromUserId, $toUserId, $reason, $userNameColumn) { // 锁实例,避免并发推进 $instance = Db::table('approval_instances')->where('id', $instanceId)->lockForUpdate()->first(); if (!$instance) throw new BusinessException('审批实例未找到'); if ($instance->status !== 'processing') throw new BusinessException('流程非进行中,无法转交'); // 锁定来源人的 pending 记录 $record = Db::table('approval_records') ->where('instance_id', $instanceId) ->where('round', (int)$instance->round) ->where('step_index', $stepIndex) ->where('approver_id', $fromUserId) ->where('status', 'pending') ->lockForUpdate() ->first(); if (!$record) throw new BusinessException('未找到可转交的待办或已处理'); $now = date('Y-m-d H:i:s'); // 若目标已有 pending:合并(本记录置为 skipped) $target = Db::table('approval_records') ->where('instance_id', $instanceId) ->where('round', (int)$instance->round) ->where('step_index', $stepIndex) ->where('approver_id', $toUserId) ->where('status', 'pending') ->lockForUpdate() ->first(); if ($target) { Db::table('approval_records')->where('id', $record->id)->update([ 'status' => 'skipped', 'approved_at' => $now, 'updated_at' => $now, 'comment' => trim(($record->comment ?? '')."\n[转交给 {$toUserId},目标已有待办,已合并]"), ]); $effectiveRecordId = (int)$target->id; } else { // 原地替换 approver_id Db::table('approval_records')->where('id', $record->id)->update([ 'approver_id' => $toUserId, 'updated_at' => $now, 'comment' => trim(($record->comment ?? '')."\n[自 {$fromUserId} 转交]"), ]); $effectiveRecordId = (int)$record->id; } // 组织“转交来源/原因”文案(优先姓名) $fromLabel = (string)$fromUserId; $toLabel = (string)$toUserId; if ($userNameColumn) { $fromName = Db::table('user')->where('id', $fromUserId)->value($userNameColumn); $toName = Db::table('user')->where('id', $toUserId)->value($userNameColumn); if ($fromName) $fromLabel = $fromName; if ($toName) $toLabel = $toName; } $note = "【转交】{$fromLabel} → {$toLabel}"; $r = trim($reason); if ($r !== '') $note .= ",原因:{$r}"; // 通知被转交人(在内容里追加 note) $this->sendNotification([$toUserId], (object)[ 'id' => (int)$instance->id, 'flow_type' => (string)$instance->flow_type, 'biz_type' => (string)$instance->biz_type, 'biz_id' => (string)$instance->biz_id, 'initiator_id' => (int)$instance->initiator_id, 'form_data' => $instance->form_data, ], 'pending', false, ['note' => $note]); // 记转交流水 Db::table('approval_transfers')->insert([ 'instance_id' => (int)$instanceId, 'step_index' => (int)$stepIndex, 'record_id' => $effectiveRecordId, 'from_user_id' => (int)$fromUserId, 'to_user_id' => (int)$toUserId, 'reason' => $reason, 'created_at' => $now, ]); $this->pushTodoChanged([$fromUserId, $toUserId]); return ['status' => 'ok', 'record_id' => $effectiveRecordId]; }); } }