/** * annual-vacation-overview.js * 연간 연차 현황 페이지 로직 (2-탭 구조) */ import { API_BASE_URL } from './api-config.js'; // 전역 변수 let annualUsageChart = null; let currentYear = new Date().getFullYear(); let vacationRequests = []; /** * 페이지 초기화 */ document.addEventListener('DOMContentLoaded', async () => { // 관리자 권한 체크 const user = JSON.parse(localStorage.getItem('user') || '{}'); const isAdmin = user.role === 'Admin' || [1, 2].includes(user.role_id); if (!isAdmin) { alert('관리자만 접근할 수 있습니다'); window.location.href = '/pages/dashboard.html'; return; } initializeYearSelector(); initializeMonthSelector(); initializeEventListeners(); await loadAnnualUsageData(); }); /** * 연도 선택 초기화 */ function initializeYearSelector() { const yearSelect = document.getElementById('yearSelect'); const currentYear = new Date().getFullYear(); // 최근 5년, 현재 연도, 다음 연도 for (let year = currentYear - 5; year <= currentYear + 1; year++) { const option = document.createElement('option'); option.value = year; option.textContent = `${year}년`; if (year === currentYear) { option.selected = true; } yearSelect.appendChild(option); } } /** * 월 선택 초기화 */ function initializeMonthSelector() { const monthSelect = document.getElementById('monthSelect'); const currentMonth = new Date().getMonth() + 1; // 현재 월을 기본 선택 monthSelect.value = currentMonth; } /** * 이벤트 리스너 초기화 */ function initializeEventListeners() { // 탭 전환 document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', (e) => { const tabName = e.target.dataset.tab; switchTab(tabName); }); }); // 조회 버튼 document.getElementById('refreshBtn').addEventListener('click', async () => { await loadAnnualUsageData(); const activeTab = document.querySelector('.tab-btn.active').dataset.tab; if (activeTab === 'monthlyDetails') { await loadMonthlyDetails(); } }); // 연도 변경 시 자동 조회 document.getElementById('yearSelect').addEventListener('change', async () => { await loadAnnualUsageData(); const activeTab = document.querySelector('.tab-btn.active').dataset.tab; if (activeTab === 'monthlyDetails') { await loadMonthlyDetails(); } }); // 월 선택 변경 시 document.getElementById('monthSelect').addEventListener('change', loadMonthlyDetails); // 엑셀 다운로드 document.getElementById('exportExcelBtn').addEventListener('click', exportToExcel); } /** * 탭 전환 */ function switchTab(tabName) { // 탭 버튼 활성화 document.querySelectorAll('.tab-btn').forEach(btn => { btn.classList.remove('active'); if (btn.dataset.tab === tabName) { btn.classList.add('active'); } }); // 탭 콘텐츠 활성화 document.querySelectorAll('.tab-content').forEach(content => { content.classList.remove('active'); }); if (tabName === 'annualUsage') { document.getElementById('annualUsageTab').classList.add('active'); } else if (tabName === 'monthlyDetails') { document.getElementById('monthlyDetailsTab').classList.add('active'); loadMonthlyDetails(); } } /** * 연간 사용 데이터 로드 (탭 1) */ async function loadAnnualUsageData() { const year = document.getElementById('yearSelect').value; try { const token = localStorage.getItem('token'); // 해당 연도의 모든 승인된 휴가 신청 조회 const response = await fetch( `${API_BASE_URL}/api/vacation-requests?start_date=${year}-01-01&end_date=${year}-12-31&status=approved`, { headers: { 'Authorization': `Bearer ${token}` } } ); if (!response.ok) { throw new Error('휴가 데이터를 불러오는데 실패했습니다'); } const result = await response.json(); vacationRequests = result.data || []; // 월별로 집계 const monthlyData = aggregateMonthlyUsage(vacationRequests); // 잔여 일수 계산 (올해 총 부여 - 사용) const remainingDays = await calculateRemainingDays(year); updateAnnualUsageChart(monthlyData, remainingDays); } catch (error) { console.error('연간 사용 데이터 로드 오류:', error); showToast('데이터를 불러오는데 실패했습니다', 'error'); } } /** * 월별 사용 일수 집계 */ function aggregateMonthlyUsage(requests) { const monthlyUsage = Array(12).fill(0); // 1월~12월 requests.forEach(req => { const startDate = new Date(req.start_date); const endDate = new Date(req.end_date); const daysUsed = req.days_used || 0; // 간단한 집계: 시작일의 월에 모든 일수를 할당 // (더 정교한 계산이 필요하면 일자별로 쪼개야 함) const month = startDate.getMonth(); // 0-11 monthlyUsage[month] += daysUsed; }); return monthlyUsage; } /** * 잔여 일수 계산 */ async function calculateRemainingDays(year) { try { const token = localStorage.getItem('token'); // 전체 작업자의 휴가 잔액 조회 const response = await fetch(`${API_BASE_URL}/api/vacation-balances/year/${year}`, { headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) { return 0; } const result = await response.json(); const balances = result.data || []; // 전체 잔여 일수 합계 const totalRemaining = balances.reduce((sum, item) => sum + (item.remaining_days || 0), 0); return totalRemaining; } catch (error) { console.error('잔여 일수 계산 오류:', error); return 0; } } /** * 연간 사용 차트 업데이트 */ function updateAnnualUsageChart(monthlyData, remainingDays) { const ctx = document.getElementById('annualUsageChart'); // 기존 차트 삭제 if (annualUsageChart) { annualUsageChart.destroy(); } const labels = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월', '잔여']; const data = [...monthlyData, remainingDays]; annualUsageChart = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: '일수', data: data, backgroundColor: data.map((_, idx) => idx === 12 ? 'rgba(16, 185, 129, 0.8)' : 'rgba(59, 130, 246, 0.8)' ), borderColor: data.map((_, idx) => idx === 12 ? 'rgba(16, 185, 129, 1)' : 'rgba(59, 130, 246, 1)' ), borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { callbacks: { label: function(context) { return `${context.parsed.y}일`; } } } }, scales: { y: { beginAtZero: true, ticks: { stepSize: 5 } } } } }); } /** * 월별 상세 기록 로드 (탭 2) */ async function loadMonthlyDetails() { const year = document.getElementById('yearSelect').value; const month = document.getElementById('monthSelect').value; try { const token = localStorage.getItem('token'); // 해당 월의 모든 휴가 신청 조회 (승인된 것만) const startDate = `${year}-${String(month).padStart(2, '0')}-01`; const lastDay = new Date(year, month, 0).getDate(); const endDate = `${year}-${String(month).padStart(2, '0')}-${lastDay}`; const response = await fetch( `${API_BASE_URL}/api/vacation-requests?start_date=${startDate}&end_date=${endDate}&status=approved`, { headers: { 'Authorization': `Bearer ${token}` } } ); if (!response.ok) { throw new Error('월별 데이터를 불러오는데 실패했습니다'); } const result = await response.json(); const monthlyRequests = result.data || []; updateMonthlyTable(monthlyRequests); } catch (error) { console.error('월별 상세 기록 로드 오류:', error); showToast('데이터를 불러오는데 실패했습니다', 'error'); } } /** * 월별 테이블 업데이트 */ function updateMonthlyTable(requests) { const tbody = document.getElementById('monthlyTableBody'); if (requests.length === 0) { tbody.innerHTML = `
데이터가 없습니다