diff --git a/system1-factory/web/css/my-monthly-confirm.css b/system1-factory/web/css/my-monthly-confirm.css index 20037c2..f607829 100644 --- a/system1-factory/web/css/my-monthly-confirm.css +++ b/system1-factory/web/css/my-monthly-confirm.css @@ -76,8 +76,14 @@ body { max-width: 480px; margin: 0 auto; } .cal-cell.special .cal-val { color: #b45309; } .cal-cell.partial .cal-val { color: #6b7280; } .cal-cell.none .cal-val { color: #d1d5db; } +.cal-cell.changed { outline: 2px solid #f59e0b; outline-offset: -2px; } +.cal-cell.changed::after { content: '수정'; position: absolute; top: 1px; right: 2px; font-size: 0.5rem; color: #f59e0b; font-weight: 700; } +.cal-cell { position: relative; } -/* 상세 표시 */ +/* 상세 표시 + 수정 */ +.cal-edit-row { margin-top: 6px; display: flex; align-items: center; gap: 6px; } +.cal-edit-select { padding: 4px 8px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 0.8rem; flex: 1; } +.cal-changed-badge { font-size: 0.65rem; font-weight: 700; color: #f59e0b; background: #fefce8; padding: 1px 6px; border-radius: 4px; } .cal-detail { display: none; margin-bottom: 10px; } .cal-detail-inner { background: white; border-radius: 10px; padding: 10px 14px; diff --git a/system1-factory/web/js/my-monthly-confirm.js b/system1-factory/web/js/my-monthly-confirm.js index 0261b9b..0c1c8dc 100644 --- a/system1-factory/web/js/my-monthly-confirm.js +++ b/system1-factory/web/js/my-monthly-confirm.js @@ -6,6 +6,9 @@ var DAYS_KR = ['일', '월', '화', '수', '목', '금', '토']; var currentYear, currentMonth; var isProcessing = false; var selectedCell = null; +var currentConfStatus = null; // 현재 confirmation 상태 +var pendingChanges = {}; // 수정 내역 { 'YYYY-MM-DD': { from: '반차', to: '정시', hours: 8 } } +var loadedRecords = []; // 로드된 daily_records // ===== Init ===== document.addEventListener('DOMContentLoaded', function() { @@ -61,6 +64,9 @@ async function loadData() { renderUserInfo(data.user); renderCalendar(data.daily_records || []); renderSummaryCards(data.daily_records || []); + loadedRecords = data.daily_records || []; + currentConfStatus = data.confirmation ? data.confirmation.status : 'pending'; + pendingChanges = {}; renderVacationBalance(balanceRes.data || []); renderConfirmStatus(data.confirmation); } catch (e) { @@ -146,24 +152,75 @@ function selectDay(day) { var cells = document.querySelectorAll('.cal-cell'); cells.forEach(function(c) { c.classList.remove('selected'); }); - // 해당 셀 찾기 var allCells = document.querySelectorAll('.cal-cell:not(.empty)'); if (allCells[day - 1]) allCells[day - 1].classList.add('selected'); var dateStr = currentYear + '-' + String(currentMonth).padStart(2, '0') + '-' + String(day).padStart(2, '0'); var d = new Date(currentYear, currentMonth - 1, day); var dow = DAYS_KR[d.getDay()]; + var record = loadedRecords.find(function(r) { return parseInt(r.date.substring(8)) === day; }); + var currentVal = record ? getCellInfo(record).text : '-'; - // 현재 로드된 데이터에서 찾기 - var calWrap = document.getElementById('tableWrap'); - var cellEl = allCells[day - 1]; - if (!cellEl) return; + var html = '
'; + html += '' + currentMonth + '/' + day + ' (' + dow + ') — ' + escHtml(currentVal); - var info = cellEl.querySelector('.cal-val').textContent; - el.innerHTML = '
' + - '' + currentMonth + '/' + day + ' (' + dow + ') — ' + info + - '
'; + // review_sent 상태에서만 수정 드롭다운 표시 + if (currentConfStatus === 'review_sent') { + var changed = pendingChanges[dateStr]; + html += '
'; + html += ''; + if (changed) html += ' 수정'; + html += '
'; + } + + html += '
'; + el.innerHTML = html; el.style.display = 'block'; + updateChangeRequestBtn(); +} + +function onCellChange(day) { + var dateStr = currentYear + '-' + String(currentMonth).padStart(2, '0') + '-' + String(day).padStart(2, '0'); + var sel = document.getElementById('editType-' + day); + var newType = sel ? sel.value : ''; + var record = loadedRecords.find(function(r) { return parseInt(r.date.substring(8)) === day; }); + var currentType = record ? getCellInfo(record).text : '-'; + + if (newType && newType !== currentType) { + var hoursMap = { '정시': 8, '연차': 0, '반차': 4, '반반차': 6, '조퇴': 2, '휴무': 0 }; + pendingChanges[dateStr] = { from: currentType, to: newType, hours: hoursMap[newType] || 0 }; + // 셀에 수정 뱃지 + var allCells = document.querySelectorAll('.cal-cell:not(.empty)'); + if (allCells[day - 1]) allCells[day - 1].classList.add('changed'); + } else { + delete pendingChanges[dateStr]; + var allCells2 = document.querySelectorAll('.cal-cell:not(.empty)'); + if (allCells2[day - 1]) allCells2[day - 1].classList.remove('changed'); + } + updateChangeRequestBtn(); + // 상세 영역 재렌더 + selectDay(day); +} + +function updateChangeRequestBtn() { + var rejectBtn = document.getElementById('rejectBtn'); + if (!rejectBtn) return; + var changeCount = Object.keys(pendingChanges).length; + if (currentConfStatus === 'review_sent' && changeCount > 0) { + rejectBtn.disabled = false; + rejectBtn.innerHTML = '수정요청 (' + changeCount + '건)'; + } else if (currentConfStatus === 'review_sent') { + rejectBtn.disabled = true; + rejectBtn.innerHTML = '수정요청'; + } } function renderSummaryCards(records) { @@ -239,7 +296,8 @@ function renderConfirmStatus(conf) { actions.classList.remove('hidden'); confirmBtn.innerHTML = '확인 완료'; rejectBtn.innerHTML = '수정요청'; - rejectBtn.onclick = function() { openChangeRequestModal(); }; + rejectBtn.disabled = true; // 수정 내역 없으면 비활성화 + rejectBtn.onclick = function() { submitChangeRequest(); }; } else if (status === 'confirmed') { badge.textContent = '확인완료'; badge.className = 'mmc-status-badge confirmed'; @@ -291,6 +349,26 @@ async function confirmMonth() { finally { isProcessing = false; } } +async function submitChangeRequest() { + if (isProcessing) return; + var changeCount = Object.keys(pendingChanges).length; + if (changeCount === 0) { showToast('수정 내역이 없습니다', 'error'); return; } + if (!confirm(changeCount + '건의 수정요청을 제출하시겠습니까?')) return; + isProcessing = true; + try { + var changes = Object.keys(pendingChanges).map(function(date) { + return { date: date, from: pendingChanges[date].from, to: pendingChanges[date].to }; + }); + var res = await window.apiCall('/monthly-comparison/confirm', 'POST', { + year: currentYear, month: currentMonth, status: 'change_request', + change_details: { changes: changes } + }); + if (res && res.success) { showToast(res.message || '수정요청 완료', 'success'); loadData(); } + else { showToast(res && res.message || '처리 실패', 'error'); } + } catch (e) { showToast('네트워크 오류', 'error'); } + finally { isProcessing = false; } +} + function openRejectModal() { document.getElementById('rejectReason').value = ''; document.getElementById('rejectModal').classList.remove('hidden'); diff --git a/system1-factory/web/pages/attendance/my-monthly-confirm.html b/system1-factory/web/pages/attendance/my-monthly-confirm.html index 3f2ab71..a65a9ab 100644 --- a/system1-factory/web/pages/attendance/my-monthly-confirm.html +++ b/system1-factory/web/pages/attendance/my-monthly-confirm.html @@ -8,7 +8,7 @@ - +
@@ -106,7 +106,7 @@ - +