/* ===== Checklist Management (체크리스트 관리 - 관리자) ===== */ let checklistItems = []; let weatherConditions = []; let workTypes = []; let editingItemId = null; let currentTab = 'basic'; /* ===== Tab switching ===== */ function switchTab(tab) { currentTab = tab; ['basic', 'weather', 'worktype'].forEach(t => { document.getElementById('panel' + t.charAt(0).toUpperCase() + t.slice(1)).classList.toggle('hidden', t !== tab); const tabBtn = document.getElementById('tab' + t.charAt(0).toUpperCase() + t.slice(1)); if (t === tab) { tabBtn.classList.add('active'); } else { tabBtn.classList.remove('active'); } }); } /* ===== Load checklist items ===== */ async function loadChecklistItems() { try { const res = await api('/checklist'); checklistItems = res.data || []; renderBasicItems(); renderWeatherItems(); renderWorktypeItems(); } catch (e) { showToast('체크리스트 로드 실패: ' + e.message, 'error'); } } /* ===== Load lookup data ===== */ async function loadLookupData() { try { const [wcRes, wtRes] = await Promise.all([ api('/checklist/weather-conditions'), api('/checklist/work-types') ]); weatherConditions = wcRes.data || []; workTypes = wtRes.data || []; // Populate selects document.getElementById('itemWeatherCondition').innerHTML = '' + weatherConditions.map(w => ``).join(''); document.getElementById('itemWorkType').innerHTML = '' + workTypes.map(w => ``).join(''); } catch (e) { console.error('Lookup data load error:', e); } } /* ===== Load tasks by work type ===== */ async function loadTasksByWorkType(workTypeId) { const taskSelect = document.getElementById('itemTask'); if (!workTypeId) { taskSelect.innerHTML = ''; document.getElementById('taskField').classList.add('hidden'); return; } try { const res = await api('/checklist/tasks/' + workTypeId); const tasks = res.data || []; taskSelect.innerHTML = '' + tasks.map(t => ``).join(''); document.getElementById('taskField').classList.remove('hidden'); } catch (e) { console.error('Task load error:', e); taskSelect.innerHTML = ''; } } /* ===== Work type change handler ===== */ function onWorkTypeChange() { const workTypeId = document.getElementById('itemWorkType').value; loadTasksByWorkType(workTypeId); } /* ===== Render basic items ===== */ function renderBasicItems() { const items = checklistItems.filter(i => i.item_type === 'basic'); const container = document.getElementById('basicItemsList'); if (!items.length) { container.innerHTML = '
기본 항목이 없습니다
'; return; } // Group by category const groups = {}; items.forEach(i => { const cat = i.category || '미분류'; if (!groups[cat]) groups[cat] = []; groups[cat].push(i); }); container.innerHTML = Object.entries(groups).map(([cat, items]) => `
${escapeHtml(cat)}
${items.map(i => renderItemRow(i)).join('')}
`).join(''); } /* ===== Render weather items ===== */ function renderWeatherItems() { const items = checklistItems.filter(i => i.item_type === 'weather'); const container = document.getElementById('weatherItemsList'); if (!items.length) { container.innerHTML = '
날씨별 항목이 없습니다
'; return; } // Group by weather condition const groups = {}; items.forEach(i => { const cond = i.weather_condition_name || '미지정'; if (!groups[cond]) groups[cond] = []; groups[cond].push(i); }); container.innerHTML = Object.entries(groups).map(([cond, items]) => `
${escapeHtml(cond)}
${items.map(i => renderItemRow(i)).join('')}
`).join(''); } /* ===== Render worktype items (2-level: work_type → task) ===== */ function renderWorktypeItems() { const items = checklistItems.filter(i => i.item_type === 'task'); const container = document.getElementById('worktypeItemsList'); if (!items.length) { container.innerHTML = '
작업별 항목이 없습니다
'; return; } // 2-level grouping: work_type → task const wtGroups = {}; items.forEach(i => { const wt = i.work_type_name || '미지정'; if (!wtGroups[wt]) wtGroups[wt] = {}; const task = i.task_name || '미지정'; if (!wtGroups[wt][task]) wtGroups[wt][task] = []; wtGroups[wt][task].push(i); }); container.innerHTML = Object.entries(wtGroups).map(([wt, taskGroups]) => `
${escapeHtml(wt)}
${Object.entries(taskGroups).map(([task, items]) => `
${escapeHtml(task)}
${items.map(i => renderItemRow(i)).join('')}
`).join('')}
`).join(''); } /* ===== Render single item row ===== */ function renderItemRow(item) { const activeClass = item.is_active ? '' : 'opacity-50'; const activeIcon = item.is_active ? '' : ''; return `
${activeIcon} ${escapeHtml(item.item_content)} ${item.category ? `${escapeHtml(item.category)}` : ''}
#${item.display_order}
`; } /* ===== Add/Edit Modal ===== */ function openAddItem(tab) { editingItemId = null; document.getElementById('itemModalTitle').textContent = '체크리스트 항목 추가'; document.getElementById('itemForm').reset(); document.getElementById('itemIsActive').checked = true; document.getElementById('itemDisplayOrder').value = '0'; // Set type based on tab const typeMap = { basic: 'basic', weather: 'weather', worktype: 'task' }; document.getElementById('itemType').value = typeMap[tab] || 'basic'; toggleTypeFields(); document.getElementById('itemModal').classList.remove('hidden'); } async function openEditItem(id) { const item = checklistItems.find(i => i.item_id === id); if (!item) return; editingItemId = id; document.getElementById('itemModalTitle').textContent = '체크리스트 항목 수정'; document.getElementById('itemType').value = item.item_type; document.getElementById('itemCategory').value = item.category || ''; document.getElementById('itemContent').value = item.item_content || ''; document.getElementById('itemDisplayOrder').value = item.display_order || 0; document.getElementById('itemIsActive').checked = item.is_active !== false && item.is_active !== 0; if (item.weather_condition_id) { document.getElementById('itemWeatherCondition').value = item.weather_condition_id; } if (item.work_type_id) { document.getElementById('itemWorkType').value = item.work_type_id; // Load tasks first, then set value after load completes await loadTasksByWorkType(item.work_type_id); if (item.task_id) { document.getElementById('itemTask').value = item.task_id; } } toggleTypeFields(); document.getElementById('itemModal').classList.remove('hidden'); } function closeItemModal() { document.getElementById('itemModal').classList.add('hidden'); document.getElementById('taskField').classList.add('hidden'); editingItemId = null; } function toggleTypeFields() { const type = document.getElementById('itemType').value; document.getElementById('weatherConditionField').classList.toggle('hidden', type !== 'weather'); document.getElementById('workTypeField').classList.toggle('hidden', type !== 'task'); // Hide task field when type changes away from task if (type !== 'task') { document.getElementById('taskField').classList.add('hidden'); } else { // Show task field if work type is already selected const workTypeId = document.getElementById('itemWorkType').value; if (workTypeId) { document.getElementById('taskField').classList.remove('hidden'); } } } /* ===== Submit item ===== */ async function submitItem(e) { e.preventDefault(); const data = { item_type: document.getElementById('itemType').value, category: document.getElementById('itemCategory').value.trim() || null, item_content: document.getElementById('itemContent').value.trim(), display_order: parseInt(document.getElementById('itemDisplayOrder').value) || 0, is_active: document.getElementById('itemIsActive').checked }; if (!data.item_content) { showToast('점검 항목을 입력해주세요', 'error'); return; } if (data.item_type === 'weather') { data.weather_condition_id = parseInt(document.getElementById('itemWeatherCondition').value) || null; if (!data.weather_condition_id) { showToast('날씨 조건을 선택해주세요', 'error'); return; } } if (data.item_type === 'task') { const taskId = parseInt(document.getElementById('itemTask').value) || null; if (!taskId) { showToast('작업을 선택해주세요', 'error'); return; } data.task_id = taskId; } try { if (editingItemId) { await api('/checklist/' + editingItemId, { method: 'PUT', body: JSON.stringify(data) }); showToast('수정되었습니다'); } else { await api('/checklist', { method: 'POST', body: JSON.stringify(data) }); showToast('추가되었습니다'); } closeItemModal(); await loadChecklistItems(); } catch (e) { showToast(e.message, 'error'); } } /* ===== Delete item ===== */ async function doDeleteItem(id) { if (!confirm('이 항목을 삭제하시겠습니까?')) return; try { await api('/checklist/' + id, { method: 'DELETE' }); showToast('삭제되었습니다'); await loadChecklistItems(); } catch (e) { showToast(e.message, 'error'); } } /* ===== Init ===== */ function initChecklistPage() { if (!initAuth()) return; // Check admin const isAdmin = currentUser && ['admin', 'system'].includes(currentUser.role); if (!isAdmin) { document.querySelector('.flex-1.min-w-0').innerHTML = `

관리자 권한이 필요합니다

`; return; } // Type change handler document.getElementById('itemType').addEventListener('change', toggleTypeFields); document.getElementById('itemWorkType').addEventListener('change', onWorkTypeChange); document.getElementById('itemForm').addEventListener('submit', submitItem); loadLookupData(); loadChecklistItems(); }