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 @@
-
+