diff --git a/system1-factory/web/pages/attendance/annual-overview.html b/system1-factory/web/pages/attendance/annual-overview.html index 10cca91..f11e006 100644 --- a/system1-factory/web/pages/attendance/annual-overview.html +++ b/system1-factory/web/pages/attendance/annual-overview.html @@ -339,6 +339,22 @@ + + + @@ -497,7 +513,7 @@ return ` ${idx + 1} - ${w.worker_name} + ${w.worker_name} { - if (e.key === 'Escape') closeSpecialModal(); + if (e.key === 'Escape') { closeSpecialModal(); closeMonthlyDetail(); } }); document.getElementById('specialModal').addEventListener('click', e => { if (e.target.id === 'specialModal') closeSpecialModal(); }); + // ===== 월별 사용 내역 모달 ===== + async function openMonthlyDetail(userId, workerName) { + const year = parseInt(document.getElementById('yearSelect').value); + document.getElementById('monthlyDetailTitle').textContent = `${workerName} — ${year}년 연차 사용 내역`; + document.getElementById('monthlyDetailBody').innerHTML = '

로딩 중...

'; + document.getElementById('monthlyDetailModal').classList.add('active'); + + try { + const res = await axios.get(`/attendance/records?start_date=${year}-01-01&end_date=${year}-12-31&user_id=${userId}`); + const records = (res.data.data || []).filter(r => r.vacation_type_id); + + if (records.length === 0) { + document.getElementById('monthlyDetailBody').innerHTML = '

연차 사용 내역이 없습니다

'; + return; + } + + // 월별 그룹핑 + const DAYS_KR = ['일', '월', '화', '수', '목', '금', '토']; + const monthly = {}; + const totals = { ANNUAL_FULL: 0, ANNUAL_HALF: 0, ANNUAL_QUARTER: 0, other: 0 }; + + records.forEach(r => { + const d = new Date(r.record_date); + const m = d.getMonth() + 1; + if (!monthly[m]) monthly[m] = { ANNUAL_FULL: 0, ANNUAL_HALF: 0, ANNUAL_QUARTER: 0, other: 0, total: 0 }; + const days = parseFloat(r.vacation_days) || 1; + const code = r.vacation_type_code || 'other'; + if (['ANNUAL_FULL', 'ANNUAL_HALF', 'ANNUAL_QUARTER'].includes(code)) { + monthly[m][code] += days; + totals[code] += days; + } else { + monthly[m].other += days; + totals.other += days; + } + monthly[m].total += days; + }); + + const grandTotal = totals.ANNUAL_FULL + totals.ANNUAL_HALF + totals.ANNUAL_QUARTER + totals.other; + + // 월별 요약 테이블 + let html = '

월별 요약

'; + html += ''; + html += ''; + html += ''; + for (let m = 1; m <= 12; m++) { + if (!monthly[m]) continue; + const d = monthly[m]; + html += ` + + + + + + `; + } + html += ` + + + + + + `; + html += '
연차반차반반차합계
${m}월${d.ANNUAL_FULL > 0 ? fmtNum(d.ANNUAL_FULL) : '-'}${d.ANNUAL_HALF > 0 ? fmtNum(d.ANNUAL_HALF) : '-'}${d.ANNUAL_QUARTER > 0 ? fmtNum(d.ANNUAL_QUARTER) : '-'}${fmtNum(d.total)}
합계${fmtNum(totals.ANNUAL_FULL)}${fmtNum(totals.ANNUAL_HALF)}${fmtNum(totals.ANNUAL_QUARTER)}${fmtNum(grandTotal)}
'; + + // 상세 내역 + html += '

상세 내역

'; + html += '
'; + records.sort((a, b) => a.record_date.localeCompare(b.record_date)).forEach(r => { + const d = new Date(r.record_date); + const dateStr = `${d.getMonth()+1}/${String(d.getDate()).padStart(2,'0')}(${DAYS_KR[d.getDay()]})`; + const days = parseFloat(r.vacation_days) || 1; + html += `
+ ${dateStr} ${r.vacation_type_name || ''} + ${fmtNum(days)}일 +
`; + }); + html += '
'; + + document.getElementById('monthlyDetailBody').innerHTML = html; + } catch (e) { + document.getElementById('monthlyDetailBody').innerHTML = '

데이터 로드 실패

'; + } + } + + function closeMonthlyDetail() { + document.getElementById('monthlyDetailModal').classList.remove('active'); + } + + document.getElementById('monthlyDetailModal').addEventListener('click', e => { + if (e.target.id === 'monthlyDetailModal') closeMonthlyDetail(); + }); + // ===== 저장 ===== async function saveAll() { const balancesToSave = [];