import { API, getAuthHeaders } from '/js/api-config.js'; const yearSel = document.getElementById('year'); const monthSel = document.getElementById('month'); const container = document.getElementById('attendanceTableContainer'); const holidays = [ '2025-01-01','2025-01-27','2025-01-28','2025-01-29','2025-01-30','2025-01-31', '2025-03-01','2025-03-03','2025-05-01','2025-05-05','2025-05-06', '2025-06-03','2025-06-06','2025-08-15','2025-10-03','2025-10-09','2025-12-25' ]; const leaveDefaults = { '김두수':16,'임영규':16,'반치원':16,'황인용':16,'표영진':15, '김윤섭':16,'이창호':16,'최광욱':16,'박현수':14,'조윤호':0 }; let workers = []; // ✅ 셀렉트 박스 옵션 + 기본 선택 추가 function fillSelectOptions() { const currentY = new Date().getFullYear(); const currentM = String(new Date().getMonth() + 1).padStart(2, '0'); for (let y = currentY; y <= currentY + 5; y++) { const selected = y === currentY ? 'selected' : ''; yearSel.insertAdjacentHTML('beforeend', ``); } for (let m = 1; m <= 12; m++) { const mm = String(m).padStart(2, '0'); const selected = mm === currentM ? 'selected' : ''; monthSel.insertAdjacentHTML('beforeend', ``); } } // ✅ 작업자 목록 불러오기 async function fetchWorkers() { try { const res = await fetch(`${API}/workers`, { headers: getAuthHeaders() }); const allWorkers = await res.json(); // 활성화된 작업자만 필터링 workers = allWorkers.filter(worker => { return worker.status === 'active' || worker.is_active === 1 || worker.is_active === true; }); workers.sort((a, b) => a.user_id - b.user_id); } catch (err) { alert('작업자 불러오기 실패'); } } // ✅ 출근부 불러오기 (해당 연도 전체) async function loadAttendance() { const year = yearSel.value; const month = monthSel.value; if (!year || !month) return alert('연도와 월을 선택하세요'); const lastDay = new Date(+year, +month, 0).getDate(); const start = `${year}-01-01`; const end = `${year}-12-31`; try { const res = await fetch(`${API}/workreports?start=${start}&end=${end}`, { headers: getAuthHeaders() }); const data = await res.json(); renderTable(data, year, month, lastDay); } catch (err) { alert('출근부 로딩 실패'); } } // ✅ 테이블 렌더링 function renderTable(data, year, month, lastDay) { container.innerHTML = ''; const weekdays = ['일','월','화','수','목','금','토']; const tbl = document.createElement('table'); // ⬆️ 헤더 구성 let thead = `작업자`; for (let d = 1; d <= lastDay; d++) thead += `${d}`; thead += `잔업합계사용연차잔여연차`; for (let d = 1; d <= lastDay; d++) { const dow = new Date(+year, +month - 1, d).getDay(); thead += `${weekdays[dow]}`; } thead += ''; tbl.innerHTML = thead; // ⬇️ 본문 workers.forEach(w => { // ✅ 월간 데이터 (표에 표시용) const recsThisMonth = data.filter(r => r.user_id === w.user_id && new Date(r.date).getFullYear() === +year && new Date(r.date).getMonth() + 1 === +month ); // ✅ 연간 데이터 (연차 계산용) const recsThisYear = data.filter(r => r.user_id === w.user_id && new Date(r.date).getFullYear() === +year ); let otSum = 0; let row = `${w.worker_name}`; for (let d = 1; d <= lastDay; d++) { const dd = String(d).padStart(2, '0'); const date = `${year}-${month}-${dd}`; const rec = recsThisMonth.find(r => { const rDate = new Date(r.date); const yyyy = rDate.getFullYear(); const mm = String(rDate.getMonth() + 1).padStart(2, '0'); const dd = String(rDate.getDate()).padStart(2, '0'); return `${yyyy}-${mm}-${dd}` === date; }); const dow = new Date(+year, +month - 1, d).getDay(); const isWe = dow === 0 || dow === 6; const isHo = holidays.includes(date); let txt = '', cls = ''; if (rec) { const ot = +rec.overtime_hours || 0; if (ot > 0) { txt = ot; cls = 'overtime-cell'; otSum += ot; } else if (rec.work_details) { const d = rec.work_details; if (['연차','반차','반반차','조퇴'].includes(d)) { txt = d; cls = 'leave'; } else if (d === '유급') { txt = d; cls = 'paid-leave'; } else if (d === '휴무') { txt = d; cls = 'holiday'; } else { txt = d; } } } else { txt = (isWe || isHo) ? '휴무' : ''; cls = (isWe || isHo) ? 'holiday' : 'no-data'; } row += `${txt}`; } const usedTot = recsThisYear .filter(r => ['연차','반차','반반차','조퇴'].includes(r.work_details)) .reduce((s, r) => s + ( r.work_details === '연차' ? 1 : r.work_details === '반차' ? 0.5 : r.work_details === '반반차' ? 0.25 : 0.75 ), 0); const remain = (leaveDefaults[w.worker_name] || 0) - usedTot; row += `${otSum.toFixed(1)}`; row += `${usedTot.toFixed(2)}${remain.toFixed(2)}`; row += ``; tbl.insertAdjacentHTML('beforeend', row); }); container.appendChild(tbl); } // ✅ 초기 로딩 fillSelectOptions(); fetchWorkers().then(() => { loadAttendance(); // 자동 조회 }); document.getElementById('loadAttendance').addEventListener('click', loadAttendance);