/** * proxy-input.js — 대리입력 리뉴얼 * Step 1: 날짜 선택 → 작업자 목록 (체크박스) * Step 2: 공통 입력 1개 → 선택된 전원 일괄 적용 */ let currentDate = ''; let allWorkers = []; let selectedIds = new Set(); let projects = []; let workTypes = []; let defectCategories = []; // { category_id, category_name, items: [{ item_id, item_name }] } // ===== Init ===== document.addEventListener('DOMContentLoaded', () => { currentDate = new Date().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 || []).map(w => ({ id: w.id || w.work_type_id, name: w.name || w.work_type_name, ...w })); // 부적합 대분류/소분류 로드 const cRes = await window.apiCall('/work-issues/categories/type/nonconformity'); const cats = cRes.data || cRes || []; for (const c of cats) { const iRes = await window.apiCall('/work-issues/items/category/' + c.category_id); defectCategories.push({ category_id: c.category_id, category_name: c.category_name, items: (iRes.data || iRes || []) }); } } 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 || allWorkers.length; 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; } // 부서별 그룹핑 const byDept = {}; allWorkers.forEach(w => { const dept = w.department_name || '미배정'; if (!byDept[dept]) byDept[dept] = []; byDept[dept].push(w); }); let html = ''; Object.keys(byDept).sort().forEach(dept => { html += `
${esc(dept)}
`; byDept[dept].forEach(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` : '미입력'; html += ` `; }); }); list.innerHTML = html; } 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: Bulk Edit (공통 입력 1개) ===== function openEditMode() { if (selectedIds.size === 0) return; const selected = allWorkers.filter(w => selectedIds.has(w.user_id)); document.getElementById('editTitle').textContent = `일괄 편집 (${selected.length}명)`; // 프로젝트/공종 드롭다운 채우기 const projSel = document.getElementById('bulkProject'); projSel.innerHTML = '' + projects.map(p => ``).join(''); const typeSel = document.getElementById('bulkWorkType'); typeSel.innerHTML = '' + workTypes.map(t => ``).join(''); // 적용 대상 목록 document.getElementById('targetWorkers').innerHTML = selected.map(w => `${esc(w.worker_name)}` ).join(''); // 기본값 document.getElementById('bulkHours').value = '8'; document.getElementById('bulkDefect').value = '0'; document.getElementById('bulkNote').value = ''; 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 projId = document.getElementById('bulkProject').value; const wtypeId = document.getElementById('bulkWorkType').value; const hours = parseFloat(document.getElementById('bulkHours').value) || 0; const defect = parseFloat(document.getElementById('bulkDefect').value) || 0; const note = document.getElementById('bulkNote').value.trim(); if (!projId || !wtypeId) { showToast('프로젝트와 공종을 선택하세요', 'error'); return; } if (hours <= 0) { showToast('근무시간을 입력하세요', 'error'); return; } if (defect > hours) { showToast('부적합 시간이 근무시간을 초과합니다', 'error'); return; } const defectCategoryId = defect > 0 ? (parseInt(document.getElementById('bulkDefectCategory').value) || null) : null; const defectItemId = defect > 0 ? (parseInt(document.getElementById('bulkDefectItem').value) || null) : null; if (defect > 0 && !defectCategoryId) { showToast('부적합 대분류를 선택하세요', 'error'); return; } const btn = document.getElementById('saveBtn'); btn.disabled = true; document.getElementById('saveBtnText').textContent = '저장 중...'; const entries = Array.from(selectedIds).map(uid => ({ user_id: uid, project_id: parseInt(projId), work_type_id: parseInt(wtypeId), work_hours: hours, defect_hours: defect, defect_category_id: defectCategoryId, defect_item_id: defectItemId, note: note, start_time: '08:00', end_time: '17:00', work_status_id: defect > 0 ? 2 : 1 })); 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 = '전체 저장'; } // ===== Defect Category/Item ===== function onDefectChange() { const val = parseFloat(document.getElementById('bulkDefect').value) || 0; const row = document.getElementById('defectCategoryRow'); if (val > 0) { row.classList.remove('hidden'); const catSel = document.getElementById('bulkDefectCategory'); if (catSel.options.length <= 1) { catSel.innerHTML = '' + defectCategories.map(c => ``).join(''); } } else { row.classList.add('hidden'); } } function onDefectCategoryChange() { const catId = parseInt(document.getElementById('bulkDefectCategory').value); const itemSel = document.getElementById('bulkDefectItem'); const cat = defectCategories.find(c => c.category_id === catId); itemSel.innerHTML = '' + (cat ? cat.items.map(i => ``).join('') : ''); } function esc(s) { return (s || '').replace(/&/g, '&').replace(//g, '>'); }