- 입사일/퇴직일 컬럼 클릭 시 오름차순/내림차순 토글 - 현재 정렬 상태를 아이콘으로 표시 (↑ 오름차순, ↓ 내림차순, ↕ 미선택) - 기본 정렬: 입사일 빠른순(오름차순)
143 lines
7.5 KiB
PHP
143 lines
7.5 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', '사원관리')
|
|
|
|
@section('content')
|
|
<div class="px-4 py-6">
|
|
{{-- 페이지 헤더 --}}
|
|
<div class="flex flex-col lg:flex-row lg:justify-between lg:items-center gap-4 mb-6">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-800">사원관리</h1>
|
|
<p class="text-sm text-gray-500 mt-1">{{ now()->format('Y년 n월 j일') }} 현재</p>
|
|
</div>
|
|
<div class="flex flex-wrap items-center gap-2 sm:gap-3">
|
|
<a href="{{ route('hr.employees.create') }}"
|
|
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/>
|
|
</svg>
|
|
사원 등록
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 통계 카드 --}}
|
|
<div class="grid gap-4 mb-6" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
|
<div class="bg-white rounded-lg shadow-sm p-4">
|
|
<div class="text-sm text-gray-500">전체</div>
|
|
<div class="text-2xl font-bold text-gray-800">{{ $stats['total'] }}명</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4">
|
|
<div class="text-sm text-gray-500">재직</div>
|
|
<div class="text-2xl font-bold text-emerald-600">{{ $stats['active'] }}명</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4">
|
|
<div class="text-sm text-gray-500">휴직</div>
|
|
<div class="text-2xl font-bold text-amber-600">{{ $stats['leave'] }}명</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-sm p-4">
|
|
<div class="text-sm text-gray-500">퇴직</div>
|
|
<div class="text-2xl font-bold text-red-600">{{ $stats['resigned'] }}명</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- 테이블 컨테이너 --}}
|
|
<div class="bg-white rounded-lg shadow-sm overflow-hidden">
|
|
{{-- 필터 --}}
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<x-filter-collapsible id="employeeFilter">
|
|
<form id="employeeFilterForm" class="flex flex-wrap gap-3 items-end">
|
|
<div style="flex: 1 1 200px; max-width: 300px;">
|
|
<label class="block text-xs text-gray-500 mb-1">검색</label>
|
|
<input type="text" name="q" placeholder="이름, 사번, 이메일..."
|
|
value="{{ request('q') }}"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
<div style="flex: 0 1 160px;">
|
|
<label class="block text-xs text-gray-500 mb-1">부서</label>
|
|
<select name="department_id"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
<option value="">전체 부서</option>
|
|
@foreach($departments as $dept)
|
|
<option value="{{ $dept->id }}" {{ request('department_id') == $dept->id ? 'selected' : '' }}>
|
|
{{ $dept->name }}
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div style="flex: 0 1 130px;">
|
|
<label class="block text-xs text-gray-500 mb-1">상태</label>
|
|
<select name="status"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
<option value="">전체 상태</option>
|
|
<option value="active" {{ request('status') === 'active' ? 'selected' : '' }}>재직</option>
|
|
<option value="leave" {{ request('status') === 'leave' ? 'selected' : '' }}>휴직</option>
|
|
<option value="resigned" {{ request('status') === 'resigned' ? 'selected' : '' }}>퇴직</option>
|
|
</select>
|
|
</div>
|
|
<div style="flex: 0 1 160px;">
|
|
<label class="block text-xs text-gray-500 mb-1">정렬</label>
|
|
<select name="sort_by"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
<option value="hire_date_asc" {{ request('sort_by', 'hire_date_asc') === 'hire_date_asc' ? 'selected' : '' }}>입사일 빠른순</option>
|
|
<option value="hire_date_desc" {{ request('sort_by') === 'hire_date_desc' ? 'selected' : '' }}>입사일 최신순</option>
|
|
<option value="resign_date_desc" {{ request('sort_by') === 'resign_date_desc' ? 'selected' : '' }}>퇴직일 최신순</option>
|
|
<option value="resign_date_asc" {{ request('sort_by') === 'resign_date_asc' ? 'selected' : '' }}>퇴직일 빠른순</option>
|
|
<option value="default" {{ request('sort_by') === 'default' ? 'selected' : '' }}>상태순</option>
|
|
</select>
|
|
</div>
|
|
<div class="shrink-0">
|
|
<button type="submit"
|
|
hx-get="{{ route('api.admin.hr.employees.index') }}"
|
|
hx-target="#employees-table"
|
|
hx-include="#employeeFilterForm"
|
|
class="px-4 py-2 bg-gray-600 hover:bg-gray-700 text-white text-sm rounded-lg transition-colors">
|
|
검색
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</x-filter-collapsible>
|
|
</div>
|
|
|
|
{{-- HTMX 테이블 영역 --}}
|
|
<div id="employees-table"
|
|
hx-get="{{ route('api.admin.hr.employees.index') }}?sort_by=hire_date_asc"
|
|
hx-trigger="load"
|
|
hx-headers='{"X-CSRF-TOKEN": "{{ csrf_token() }}"}'
|
|
class="min-h-[200px]">
|
|
<div class="flex justify-center items-center p-12">
|
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@push('scripts')
|
|
<script>
|
|
document.getElementById('employeeFilterForm')?.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
htmx.trigger('#employees-table', 'htmx:trigger');
|
|
});
|
|
|
|
function toggleSort(field) {
|
|
const sortSelect = document.querySelector('select[name="sort_by"]');
|
|
const current = sortSelect.value;
|
|
|
|
if (current === field + '_asc') {
|
|
sortSelect.value = field + '_desc';
|
|
} else {
|
|
sortSelect.value = field + '_asc';
|
|
}
|
|
|
|
// HTMX로 테이블 새로고침
|
|
const table = document.getElementById('employees-table');
|
|
const form = document.getElementById('employeeFilterForm');
|
|
const params = new URLSearchParams(new FormData(form)).toString();
|
|
const url = '{{ route('api.admin.hr.employees.index') }}?' + params;
|
|
|
|
htmx.ajax('GET', url, { target: '#employees-table', swap: 'innerHTML' });
|
|
}
|
|
</script>
|
|
@endpush
|