// web-ui/js/modules/calendar/CalendarView.js /** * 캘린더 UI 렌더링 및 DOM 조작을 담당하는 전역 객체입니다. */ (function(window) { 'use strict'; const CalendarView = { elements: {}, initializeElements: function() { this.elements.monthYearTitle = document.getElementById('monthYearTitle'); this.elements.calendarDays = document.getElementById('calendarDays'); this.elements.prevMonthBtn = document.getElementById('prevMonthBtn'); this.elements.nextMonthBtn = document.getElementById('nextMonthBtn'); this.elements.todayBtn = document.getElementById('todayBtn'); this.elements.dailyWorkModal = document.getElementById('dailyWorkModal'); this.elements.modalTitle = document.getElementById('modalTitle'); this.elements.modalSummary = document.querySelector('.daily-summary'); this.elements.modalTotalWorkers = document.getElementById('modalTotalWorkers'); this.elements.modalTotalHours = document.getElementById('modalTotalHours'); this.elements.modalTotalTasks = document.getElementById('modalTotalTasks'); this.elements.modalErrorCount = document.getElementById('modalErrorCount'); this.elements.modalWorkersList = document.getElementById('modalWorkersList'); this.elements.modalNoData = document.getElementById('modalNoData'); this.elements.statusFilter = document.getElementById('statusFilter'); this.elements.loadingSpinner = document.getElementById('loadingSpinner'); }, showLoading: function(show) { if (this.elements.loadingSpinner) { this.elements.loadingSpinner.style.display = show ? 'flex' : 'none'; } }, showToast: function(message, type = 'info') { const existingToast = document.querySelector('.toast-message'); if (existingToast) existingToast.remove(); const toast = document.createElement('div'); toast.className = `toast-message toast-${type}`; toast.textContent = message; document.body.appendChild(toast); setTimeout(() => toast.remove(), 3000); }, renderCalendar: async function() { const year = CalendarState.currentDate.getFullYear(); const month = CalendarState.currentDate.getMonth(); const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']; this.elements.monthYearTitle.textContent = `${year}년 ${monthNames[month]}`; this.showLoading(true); try { const monthData = await CalendarAPI.getMonthlyCalendarData(year, month); const firstDay = new Date(year, month, 1); const lastDay = new Date(year, month + 1, 0); const startDate = new Date(firstDay); startDate.setDate(startDate.getDate() - firstDay.getDay()); const today = new Date(); const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`; let calendarHTML = ''; let currentDay = new Date(startDate); for (let i = 0; i < 42; i++) { const dateStr = `${currentDay.getFullYear()}-${String(currentDay.getMonth() + 1).padStart(2, '0')}-${String(currentDay.getDate()).padStart(2, '0')}`; const dayWorkData = monthData[dateStr] || { hasData: false, hasIssues: false, hasErrors: false, workerCount: 0 }; const dayStatus = this.analyzeDayStatus(dayWorkData); let dayClasses = ['calendar-day']; if (currentDay.getMonth() !== month) dayClasses.push('other-month'); if (dateStr === todayStr) dayClasses.push('today'); if (currentDay.getDay() === 0) dayClasses.push('sunday'); if (currentDay.getDay() === 6) dayClasses.push('saturday'); const hasAnyProblem = dayStatus.hasOvertimeWarning || dayStatus.hasIncomplete || dayStatus.hasIssues; if (dayStatus.hasData && !hasAnyProblem) dayClasses.push('has-normal'); let statusIcons = ''; if (hasAnyProblem) { if (dayStatus.hasOvertimeWarning) statusIcons += '
'; if (dayStatus.hasIncomplete) statusIcons += '
'; if (dayStatus.hasIssues) statusIcons += '
'; } calendarHTML += `
${currentDay.getDate()}
${statusIcons}
`; currentDay.setDate(currentDay.getDate() + 1); } this.elements.calendarDays.innerHTML = calendarHTML; } catch (error) { console.error('캘린더 렌더링 오류:', error); this.showToast('캘린더를 불러오는데 실패했습니다.', 'error'); } finally { this.showLoading(false); } }, analyzeDayStatus: function(dayData) { if (dayData && typeof dayData === 'object' && 'totalWorkers' in dayData) { const totalRegisteredWorkers = CalendarState.allWorkers ? CalendarState.allWorkers.length : 0; const actualIncompleteWorkers = Math.max(0, totalRegisteredWorkers - dayData.workingWorkers); return { hasData: dayData.totalWorkers > 0, hasIssues: dayData.partialWorkers > 0, hasIncomplete: actualIncompleteWorkers > 0 || dayData.incompleteWorkers > 0, hasOvertimeWarning: dayData.hasOvertimeWarning || dayData.overtimeWarningWorkers > 0, workerCount: dayData.totalWorkers || 0 }; } return { hasData: false, hasIssues: false, hasErrors: false, workerCount: 0 }; } }; window.CalendarView = CalendarView; })(window);