From 512f01bea6a3bcdc173fbc7bbc7bb5bbfdc961f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Tue, 10 Mar 2026 00:09:09 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20[hr]=20=ED=9C=B4=EA=B0=80=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=B0=B8=EC=A1=B0=EC=9E=90=20=EC=84=A0=ED=83=9D=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 휴가 신청 모달에 참조자 검색/선택 UI 추가 (Alpine.js) - 부서별 사용자 목록에서 참조자 검색 및 녹색 칩 표시 - LeaveController 참조 배열 유효성 검증 추가 - LeaveService에서 결재선 steps에 참조자 자동 병합 --- .../Api/Admin/HR/LeaveController.php | 2 + app/Services/HR/LeaveService.php | 19 ++- resources/views/hr/leaves/index.blade.php | 122 ++++++++++++++++++ 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/Admin/HR/LeaveController.php b/app/Http/Controllers/Api/Admin/HR/LeaveController.php index 58742888..6151a450 100644 --- a/app/Http/Controllers/Api/Admin/HR/LeaveController.php +++ b/app/Http/Controllers/Api/Admin/HR/LeaveController.php @@ -53,6 +53,8 @@ public function store(Request $request): JsonResponse 'end_date' => 'required|date|after_or_equal:start_date', 'reason' => 'nullable|string|max:1000', 'approval_line_id' => 'nullable|integer|exists:approval_lines,id', + 'references' => 'nullable|array', + 'references.*.user_id' => 'required|integer|exists:users,id', ]); try { diff --git a/app/Services/HR/LeaveService.php b/app/Services/HR/LeaveService.php index 8e0b4fe4..76387094 100644 --- a/app/Services/HR/LeaveService.php +++ b/app/Services/HR/LeaveService.php @@ -118,7 +118,7 @@ public function storeLeave(array $data): Leave ]); // 결재 자동 생성 + 상신 (유형에 맞는 결재양식 자동 선택) - $approval = $this->createLeaveApproval($leave, $tenantId, $data['approval_line_id'] ?? null); + $approval = $this->createLeaveApproval($leave, $tenantId, $data['approval_line_id'] ?? null, $data['references'] ?? []); $leave->update(['approval_id' => $approval->id]); return $leave; @@ -992,7 +992,7 @@ public function sendPromotionNotices(array $employeeIds, string $noticeType, int /** * 휴가/근태신청/사유서 결재 자동 생성 + 상신 */ - private function createLeaveApproval(Leave $leave, int $tenantId, ?int $approvalLineId = null): Approval + private function createLeaveApproval(Leave $leave, int $tenantId, ?int $approvalLineId = null, array $references = []): Approval { $approvalService = app(ApprovalService::class); @@ -1033,6 +1033,21 @@ private function createLeaveApproval(Leave $leave, int $tenantId, ?int $approval 'step_type' => $s['step_type'] ?? $s['type'] ?? 'approval', ])->toArray(); + // 4-1. 개별 참조자 추가 (결재선에 없는 사용자만) + if (! empty($references)) { + $existingUserIds = collect($steps)->pluck('user_id')->toArray(); + foreach ($references as $ref) { + $refUserId = (int) ($ref['user_id'] ?? 0); + if ($refUserId && ! in_array($refUserId, $existingUserIds)) { + $steps[] = [ + 'user_id' => $refUserId, + 'step_type' => 'reference', + ]; + $existingUserIds[] = $refUserId; + } + } + } + // 5. 결재 제목 생성 (유형별 차별화) $typeName = Leave::TYPE_MAP[$leave->leave_type] ?? $leave->leave_type; $userName = $leave->user->name ?? ''; diff --git a/resources/views/hr/leaves/index.blade.php b/resources/views/hr/leaves/index.blade.php index 683fdca6..165d4b30 100644 --- a/resources/views/hr/leaves/index.blade.php +++ b/resources/views/hr/leaves/index.blade.php @@ -272,6 +272,56 @@ class="text-xs text-blue-600 hover:underline mt-1"> @endif + {{-- 참조 선택 --}} +
+ +
+ +
+
+ +
+ + +
+
+
+