/* ===== Tasks CRUD ===== */ let taskWorkTypes = [], allTasks = [], tasksLoaded = false; let selectedTaskWorkTypeFilter = null; async function loadTasksTab() { await loadWorkTypes(); await loadTasks(); tasksLoaded = true; } async function loadWorkTypes() { try { const r = await api('/tasks/work-types'); taskWorkTypes = r.data || []; renderWorkTypeSidebar(); populateTaskWorkTypeSelect(); } catch(e) { console.warn('공정 로드 실패:', e); } } function renderWorkTypeSidebar() { const c = document.getElementById('workTypeSidebar'); if (!c) return; let html = `
전체 ${allTasks.length}
`; // 카테고리별 그룹핑 const grouped = {}; taskWorkTypes.forEach(wt => { const cat = wt.category || '미분류'; if (!grouped[cat]) grouped[cat] = []; grouped[cat].push(wt); }); Object.keys(grouped).sort().forEach(cat => { html += `
${cat}
`; grouped[cat].forEach(wt => { const count = allTasks.filter(t => t.work_type_id === wt.id).length; const isActive = selectedTaskWorkTypeFilter === wt.id; html += `
${wt.name}
${count}
`; }); }); // 미지정 작업 수 const noType = allTasks.filter(t => !t.work_type_id).length; if (noType > 0) { html += `
미지정 ${noType}
`; } c.innerHTML = html; } function populateTaskWorkTypeSelect() { const sel = document.getElementById('taskWorkType'); if (!sel) return; const val = sel.value; sel.innerHTML = ''; taskWorkTypes.forEach(wt => { sel.innerHTML += ``; }); sel.value = val; } function filterTasksByWorkType(wtId) { selectedTaskWorkTypeFilter = wtId; renderWorkTypeSidebar(); displayTasks(); } async function loadTasks() { try { const r = await api('/tasks'); allTasks = r.data || []; renderWorkTypeSidebar(); displayTasks(); } catch(e) { document.getElementById('taskList').innerHTML = `

${e.message}

`; } } function displayTasks() { const c = document.getElementById('taskList'); let filtered = allTasks; let label = '전체'; if (selectedTaskWorkTypeFilter === 0) { filtered = allTasks.filter(t => !t.work_type_id); label = '미지정'; } else if (selectedTaskWorkTypeFilter) { filtered = allTasks.filter(t => t.work_type_id === selectedTaskWorkTypeFilter); const wt = taskWorkTypes.find(w => w.id === selectedTaskWorkTypeFilter); label = wt ? wt.name : ''; } document.getElementById('taskFilterLabel').textContent = `- ${label}`; const active = filtered.filter(t => t.is_active).length; const inactive = filtered.length - active; document.getElementById('taskStats').textContent = `활성 ${active} / 비활성 ${inactive}`; if (!filtered.length) { c.innerHTML = '

등록된 작업이 없습니다.

'; return; } c.innerHTML = filtered.map(t => `
${escHtml(t.task_name)}
${t.work_type_name ? `${escHtml(t.work_type_name)}` : '미지정'} ${t.description ? `${escHtml(t.description)}` : ''} ${t.is_active ? '활성' : '비활성'}
`).join(''); } // 공정 모달 function openWorkTypeModal(editId) { document.getElementById('wtEditId').value = ''; document.getElementById('workTypeForm').reset(); document.getElementById('workTypeModalTitle').textContent = '공정 추가'; if (editId) { const wt = taskWorkTypes.find(w => w.id === editId); if (!wt) return; document.getElementById('workTypeModalTitle').textContent = '공정 수정'; document.getElementById('wtEditId').value = wt.id; document.getElementById('wtName').value = wt.name || ''; document.getElementById('wtCategory').value = wt.category || ''; document.getElementById('wtDesc').value = wt.description || ''; } document.getElementById('workTypeModal').classList.remove('hidden'); } function closeWorkTypeModal() { document.getElementById('workTypeModal').classList.add('hidden'); } function editWorkType(id) { openWorkTypeModal(id); } document.getElementById('workTypeForm').addEventListener('submit', async e => { e.preventDefault(); const editId = document.getElementById('wtEditId').value; const body = { name: document.getElementById('wtName').value.trim(), category: document.getElementById('wtCategory').value.trim() || null, description: document.getElementById('wtDesc').value.trim() || null }; try { if (editId) { await api(`/tasks/work-types/${editId}`, { method: 'PUT', body: JSON.stringify(body) }); showToast('공정이 수정되었습니다.'); } else { await api('/tasks/work-types', { method: 'POST', body: JSON.stringify(body) }); showToast('공정이 추가되었습니다.'); } closeWorkTypeModal(); await loadWorkTypes(); await loadTasks(); } catch(e) { showToast(e.message, 'error'); } }); // 작업 모달 function openTaskModal(editId) { document.getElementById('taskEditId').value = ''; document.getElementById('taskForm').reset(); document.getElementById('taskActive').checked = true; document.getElementById('taskModalTitle').textContent = '작업 추가'; populateTaskWorkTypeSelect(); // 사이드바 필터 선택된 공정 자동 선택 if (!editId && selectedTaskWorkTypeFilter && selectedTaskWorkTypeFilter !== 0) { document.getElementById('taskWorkType').value = selectedTaskWorkTypeFilter; } if (editId) { const t = allTasks.find(x => x.task_id === editId); if (!t) return; document.getElementById('taskModalTitle').textContent = '작업 수정'; document.getElementById('taskEditId').value = t.task_id; document.getElementById('taskName').value = t.task_name || ''; document.getElementById('taskWorkType').value = t.work_type_id || ''; document.getElementById('taskDesc').value = t.description || ''; document.getElementById('taskActive').checked = !!t.is_active; } document.getElementById('taskModal').classList.remove('hidden'); } function closeTaskModal() { document.getElementById('taskModal').classList.add('hidden'); } function editTask(id) { openTaskModal(id); } document.getElementById('taskForm').addEventListener('submit', async e => { e.preventDefault(); const editId = document.getElementById('taskEditId').value; const body = { task_name: document.getElementById('taskName').value.trim(), work_type_id: document.getElementById('taskWorkType').value ? parseInt(document.getElementById('taskWorkType').value) : null, description: document.getElementById('taskDesc').value.trim() || null, is_active: document.getElementById('taskActive').checked ? 1 : 0 }; try { if (editId) { await api(`/tasks/${editId}`, { method: 'PUT', body: JSON.stringify(body) }); showToast('작업이 수정되었습니다.'); } else { await api('/tasks', { method: 'POST', body: JSON.stringify(body) }); showToast('작업이 추가되었습니다.'); } closeTaskModal(); await loadTasks(); } catch(e) { showToast(e.message, 'error'); } }); async function deleteTask(id, name) { if (!confirm(`"${name}" 작업을 삭제하시겠습니까?`)) return; try { await api(`/tasks/${id}`, { method: 'DELETE' }); showToast('작업이 삭제되었습니다.'); await loadTasks(); } catch(e) { showToast(e.message, 'error'); } }