From d99fdcc2ecb11db385c93d9cad8c0ed21f96b562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Fri, 27 Feb 2026 13:06:42 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20[leave]=20=EC=9E=94=EC=97=AC=EC=97=B0?= =?UTF-8?q?=EC=B0=A8=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=ED=97=A4=EB=8D=94=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=20=EC=A0=95=EB=A0=AC=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사원, 부서, 입사일, 부여, 사용, 잔여, 소진율 컬럼 정렬 지원 - 기본 정렬: 입사일 오름차순 (빠른 순) - 활성 정렬 컬럼 파란색 강조 + 방향 화살표 표시 --- .../Api/Admin/HR/LeaveController.php | 6 ++- app/Services/HR/LeaveService.php | 25 +++++++-- resources/views/hr/leaves/index.blade.php | 9 +++- .../hr/leaves/partials/balance.blade.php | 54 ++++++++++++++++--- 4 files changed, 77 insertions(+), 17 deletions(-) diff --git a/app/Http/Controllers/Api/Admin/HR/LeaveController.php b/app/Http/Controllers/Api/Admin/HR/LeaveController.php index 682cfb5e..45f09641 100644 --- a/app/Http/Controllers/Api/Admin/HR/LeaveController.php +++ b/app/Http/Controllers/Api/Admin/HR/LeaveController.php @@ -181,10 +181,12 @@ public function cancel(Request $request, int $id): JsonResponse public function balance(Request $request): JsonResponse|Response { $year = $request->integer('year', now()->year); - $balances = $this->leaveService->getBalanceSummary($year); + $sort = $request->input('sort', 'hire_date'); + $direction = $request->input('direction', 'asc'); + $balances = $this->leaveService->getBalanceSummary($year, $sort, $direction); if ($request->header('HX-Request')) { - return response(view('hr.leaves.partials.balance', compact('balances', 'year'))); + return response(view('hr.leaves.partials.balance', compact('balances', 'year', 'sort', 'direction'))); } return response()->json([ diff --git a/app/Services/HR/LeaveService.php b/app/Services/HR/LeaveService.php index 5c25b9e1..60e306fe 100644 --- a/app/Services/HR/LeaveService.php +++ b/app/Services/HR/LeaveService.php @@ -224,7 +224,7 @@ public function cancel(int $id): ?Leave * 사원관리의 모든 재직/휴직 직원을 표시하며, * balance 레코드가 없는 직원은 자동 생성한다. */ - public function getBalanceSummary(?int $year = null): Collection + public function getBalanceSummary(?int $year = null, ?string $sort = null, ?string $direction = null): Collection { $tenantId = session('selected_tenant_id'); $year = $year ?? now()->year; @@ -294,16 +294,31 @@ public function getBalanceSummary(?int $year = null): Collection } } - return $existingBalances + $result = $existingBalances ->filter(fn ($balance) => $employeesByUserId->has($balance->user_id)) ->map(function ($balance) use ($employeesByUserId) { $employee = $employeesByUserId->get($balance->user_id); $balance->employee = $employee; return $balance; - }) - ->sortBy(fn ($balance) => $balance->employee?->display_name ?? '') - ->values(); + }); + + // 정렬 (기본: 입사일 오름차순) + $sortField = $sort ?? 'hire_date'; + $isDesc = ($direction ?? 'asc') === 'desc'; + + $sortCallback = match ($sortField) { + 'name' => fn ($b) => $b->employee?->display_name ?? '', + 'department' => fn ($b) => $b->employee?->department?->name ?? '', + 'hire_date' => fn ($b) => $b->employee?->hire_date ?? '9999-12-31', + 'total_days' => fn ($b) => $b->total_days, + 'used_days' => fn ($b) => $b->used_days, + 'remaining' => fn ($b) => $b->total_days - $b->used_days, + 'rate' => fn ($b) => $b->total_days > 0 ? $b->used_days / $b->total_days : 0, + default => fn ($b) => $b->employee?->hire_date ?? '9999-12-31', + }; + + return ($isDesc ? $result->sortByDesc($sortCallback) : $result->sortBy($sortCallback))->values(); } /** diff --git a/resources/views/hr/leaves/index.blade.php b/resources/views/hr/leaves/index.blade.php index 98db5b93..5232cf1c 100644 --- a/resources/views/hr/leaves/index.blade.php +++ b/resources/views/hr/leaves/index.blade.php @@ -311,12 +311,17 @@ function switchTab(tab) { } } - function loadBalance() { + let balanceSort = 'hire_date'; + let balanceDirection = 'asc'; + + function loadBalance(sort, direction) { + if (sort) balanceSort = sort; + if (direction) balanceDirection = direction; const year = document.getElementById('balanceYear').value; htmx.ajax('GET', '{{ route("api.admin.hr.leaves.balance") }}', { target: '#balance-container', swap: 'innerHTML', - values: { year: year }, + values: { year: year, sort: balanceSort, direction: balanceDirection }, }); } diff --git a/resources/views/hr/leaves/partials/balance.blade.php b/resources/views/hr/leaves/partials/balance.blade.php index 2a380573..3e3742db 100644 --- a/resources/views/hr/leaves/partials/balance.blade.php +++ b/resources/views/hr/leaves/partials/balance.blade.php @@ -1,17 +1,55 @@ {{-- 잔여연차 현황 (HTMX로 로드) --}} +@php + $currentSort = $sort ?? 'hire_date'; + $currentDir = $direction ?? 'asc'; + $sortColumns = [ + 'name' => ['label' => '사원', 'align' => 'left'], + 'department' => ['label' => '부서', 'align' => 'left'], + 'hire_date' => ['label' => '입사일', 'align' => 'center'], + 'tenure' => ['label' => '근속', 'align' => 'center', 'sortable' => false], + 'total_days' => ['label' => '부여', 'align' => 'center'], + 'used_days' => ['label' => '사용', 'align' => 'center'], + 'remaining' => ['label' => '잔여', 'align' => 'center'], + 'rate' => ['label' => '소진율', 'align' => 'center'], + ]; +@endphp - - - - - - - - + @foreach($sortColumns as $col => $meta) + @php + $sortable = $meta['sortable'] ?? true; + $isActive = $sortable && $currentSort === $col; + $nextDir = $isActive && $currentDir === 'asc' ? 'desc' : 'asc'; + $align = $meta['align'] === 'left' ? 'text-left' : 'text-center'; + @endphp + + @endforeach
사원부서입사일근속부여사용잔여소진율 + @if($sortable) + + @else + {{ $meta['label'] }} + @endif +