From b67e8f2c9f10805728ef3dcbacfab1ebcf9818b1 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Tue, 31 Mar 2026 08:39:49 +0900 Subject: [PATCH] =?UTF-8?q?feat(tkfb):=20=EC=97=B0=EA=B0=84=20=EC=97=B0?= =?UTF-8?q?=EC=B0=A8=20=ED=98=84=ED=99=A9=20=E2=80=94=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20=EC=9B=94=EB=B3=84?= =?UTF-8?q?=20=EC=84=B8=EB=B6=80=EB=82=B4=EC=97=AD=20=EB=AA=A8=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 이름 클릭 → 월별 요약 테이블 (연차/반차/반반차/합계) - 상세 내역: 일자별 사용 기록 - 기존 /attendance/records API 활용 (별도 백엔드 불필요) - 경조사 모달과 동일 패턴 (overlay, ESC, 배경 클릭 닫기) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../web/pages/attendance/annual-overview.html | 112 +++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) 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 = [];