/** * proxy-input.js — 대리입력 리뉴얼 * Step 1: 날짜 선택 → 작업자 목록 (체크박스) * Step 2: 선택 작업자 일괄 편집 → 저장 (TBM 자동 생성) */ let currentDate = ''; let allWorkers = []; let selectedIds = new Set(); let projects = []; let workTypes = []; let editData = {}; // { userId: { project_id, work_type_id, work_hours, defect_hours, note } } // ===== Init ===== document.addEventListener('DOMContentLoaded', () => { const now = new Date(); currentDate = now.toISOString().substring(0, 10); document.getElementById('dateInput').value = currentDate; setTimeout(async () => { await loadDropdownData(); await loadWorkers(); }, 500); }); async function loadDropdownData() { try { const [pRes, wRes] = await Promise.all([ window.apiCall('/projects'), window.apiCall('/daily-work-reports/work-types') ]); projects = (pRes.data || pRes || []).filter(p => p.is_active !== 0); workTypes = (wRes.data || wRes || []).filter(w => w.is_active !== 0); } catch (e) { console.warn('드롭다운 로드 실패:', e); } } // ===== Step 1: Worker List ===== async function loadWorkers() { currentDate = document.getElementById('dateInput').value; if (!currentDate) return; const list = document.getElementById('workerList'); list.innerHTML = '
'; selectedIds.clear(); updateEditButton(); try { const res = await window.apiCall('/proxy-input/daily-status?date=' + currentDate); if (!res.success) throw new Error(res.message); allWorkers = res.data.workers || []; const s = res.data.summary || {}; document.getElementById('totalNum').textContent = s.total_active_workers || 0; document.getElementById('doneNum').textContent = s.report_completed || 0; document.getElementById('missingNum').textContent = s.report_missing || 0; document.getElementById('vacNum').textContent = allWorkers.filter(w => w.vacation_type_code === 'ANNUAL_FULL').length; renderWorkerList(); } catch (e) { list.innerHTML = '

데이터 로드 실패

'; } } function renderWorkerList() { const list = document.getElementById('workerList'); if (!allWorkers.length) { list.innerHTML = '

작업자가 없습니다

'; return; } list.innerHTML = allWorkers.map(w => { const isFullVac = w.vacation_type_code === 'ANNUAL_FULL'; const hasVac = !!w.vacation_type_code; const vacBadge = isFullVac ? '연차' : hasVac ? `${esc(w.vacation_type_name)}` : ''; const doneBadge = w.has_report ? `${w.total_report_hours}h` : '미입력'; return ` `; }).join(''); } function onWorkerCheck(userId, checked) { if (checked) selectedIds.add(userId); else selectedIds.delete(userId); updateEditButton(); } function toggleSelectAll(checked) { allWorkers.forEach(w => { if (w.vacation_type_code === 'ANNUAL_FULL') return; const cb = document.querySelector(`.pi-check[value="${w.user_id}"]`); if (cb) { cb.checked = checked; onWorkerCheck(w.user_id, checked); } }); } function updateEditButton() { const btn = document.getElementById('editBtn'); const n = selectedIds.size; btn.disabled = n === 0; document.getElementById('editBtnText').textContent = n > 0 ? `선택 작업자 편집 (${n}명)` : '작업자를 선택하세요'; } // ===== Step 2: Edit Mode ===== function openEditMode() { if (selectedIds.size === 0) return; const selected = allWorkers.filter(w => selectedIds.has(w.user_id)); editData = {}; // 기본값 설정 selected.forEach(w => { const isHalfVac = w.vacation_type_code === 'ANNUAL_HALF'; const isQuarterVac = w.vacation_type_code === 'ANNUAL_QUARTER'; editData[w.user_id] = { project_id: '', work_type_id: '', work_hours: isHalfVac ? 4 : isQuarterVac ? 6 : 8, defect_hours: 0, note: '', start_time: '08:00', end_time: isHalfVac ? '12:00' : isQuarterVac ? '14:00' : '17:00', work_status_id: 1 }; }); document.getElementById('editTitle').textContent = `일괄 편집 (${selected.length}명)`; const projOpts = projects.map(p => ``).join(''); const typeOpts = workTypes.map(t => ``).join(''); document.getElementById('editList').innerHTML = selected.map(w => { const d = editData[w.user_id]; const vacLabel = w.vacation_type_name ? ` ${esc(w.vacation_type_name)}` : ''; return `
${esc(w.worker_name)} ${esc(w.job_type || '')} ${vacLabel}
`; }).join(''); document.getElementById('step1').classList.add('hidden'); document.getElementById('step2').classList.remove('hidden'); } function closeEditMode() { document.getElementById('step2').classList.add('hidden'); document.getElementById('step1').classList.remove('hidden'); } // ===== Save ===== async function saveAll() { const btn = document.getElementById('saveBtn'); btn.disabled = true; document.getElementById('saveBtnText').textContent = '저장 중...'; const entries = []; let hasError = false; for (const uid of selectedIds) { const projEl = document.getElementById('proj_' + uid); const wtypeEl = document.getElementById('wtype_' + uid); const hoursEl = document.getElementById('hours_' + uid); const defectEl = document.getElementById('defect_' + uid); const noteEl = document.getElementById('note_' + uid); if (!projEl?.value || !wtypeEl?.value) { showToast(`프로젝트/공종을 선택하세요`, 'error'); projEl?.focus(); hasError = true; break; } const workHours = parseFloat(hoursEl?.value) || 0; const defectHours = parseFloat(defectEl?.value) || 0; if (defectHours > workHours) { showToast('부적합 시간이 근무시간을 초과합니다', 'error'); hasError = true; break; } entries.push({ user_id: uid, project_id: parseInt(projEl.value), work_type_id: parseInt(wtypeEl.value), work_hours: workHours, defect_hours: defectHours, note: noteEl?.value || '', start_time: '08:00', end_time: '17:00', work_status_id: defectHours > 0 ? 2 : 1 }); } if (hasError) { btn.disabled = false; document.getElementById('saveBtnText').textContent = '전체 저장'; return; } try { const res = await window.apiCall('/proxy-input', 'POST', { session_date: currentDate, entries }); if (res.success) { showToast(res.message || `${entries.length}명 저장 완료`, 'success'); closeEditMode(); selectedIds.clear(); updateEditButton(); await loadWorkers(); } else { showToast(res.message || '저장 실패', 'error'); } } catch (e) { showToast('저장 실패: ' + (e.message || e), 'error'); } btn.disabled = false; document.getElementById('saveBtnText').textContent = '전체 저장'; } function esc(s) { return (s || '').replace(/&/g, '&').replace(//g, '>'); }