// 작업장 관리 페이지 JavaScript // 전역 변수 let categories = []; let workplaces = []; let currentCategoryId = ''; let currentEditingCategory = null; let currentEditingWorkplace = null; // 페이지 초기화 document.addEventListener('DOMContentLoaded', function() { console.log('🏗️ 작업장 관리 페이지 초기화 시작'); loadAllData(); }); // 모든 데이터 로드 async function loadAllData() { try { await Promise.all([ loadCategories(), loadWorkplaces() ]); renderCategoryTabs(); renderWorkplaces(); updateStatistics(); } catch (error) { console.error('데이터 로딩 오류:', error); showToast('데이터를 불러오는데 실패했습니다.', 'error'); } } // ==================== 카테고리(공장) 관련 ==================== // 카테고리 목록 로드 async function loadCategories() { try { const response = await apiCall('/workplaces/categories', 'GET'); let categoryData = []; if (response && response.success && Array.isArray(response.data)) { categoryData = response.data; } else if (Array.isArray(response)) { categoryData = response; } categories = categoryData; console.log(`✅ 카테고리 ${categories.length}개 로드 완료`); } catch (error) { console.error('카테고리 로딩 오류:', error); categories = []; } } // 카테고리 탭 렌더링 function renderCategoryTabs() { const tabsContainer = document.getElementById('categoryTabs'); if (!tabsContainer) return; // 전체 탭은 항상 표시 let tabsHtml = ` `; // 각 카테고리 탭 추가 categories.forEach(category => { const count = workplaces.filter(w => w.category_id === category.category_id).length; const isActive = currentCategoryId === category.category_id; tabsHtml += ` `; }); tabsContainer.innerHTML = tabsHtml; } // 카테고리 전환 function switchCategory(categoryId) { currentCategoryId = categoryId === '' ? '' : categoryId; renderCategoryTabs(); renderWorkplaces(); } // 카테고리 모달 열기 function openCategoryModal(categoryData = null) { const modal = document.getElementById('categoryModal'); const modalTitle = document.getElementById('categoryModalTitle'); const deleteBtn = document.getElementById('deleteCategoryBtn'); if (!modal) return; currentEditingCategory = categoryData; if (categoryData) { // 수정 모드 modalTitle.textContent = '공장 수정'; deleteBtn.style.display = 'inline-flex'; document.getElementById('categoryId').value = categoryData.category_id; document.getElementById('categoryName').value = categoryData.category_name || ''; document.getElementById('categoryDescription').value = categoryData.description || ''; document.getElementById('categoryOrder').value = categoryData.display_order || 0; } else { // 신규 등록 모드 modalTitle.textContent = '공장 추가'; deleteBtn.style.display = 'none'; document.getElementById('categoryForm').reset(); document.getElementById('categoryId').value = ''; } modal.style.display = 'flex'; document.body.style.overflow = 'hidden'; setTimeout(() => { document.getElementById('categoryName').focus(); }, 100); } // 카테고리 모달 닫기 function closeCategoryModal() { const modal = document.getElementById('categoryModal'); if (modal) { modal.style.display = 'none'; document.body.style.overflow = ''; currentEditingCategory = null; } } // 카테고리 저장 async function saveCategory() { try { const categoryId = document.getElementById('categoryId').value; const categoryData = { category_name: document.getElementById('categoryName').value.trim(), description: document.getElementById('categoryDescription').value.trim() || null, display_order: parseInt(document.getElementById('categoryOrder').value) || 0, is_active: true }; if (!categoryData.category_name) { showToast('공장명은 필수 입력 항목입니다.', 'error'); return; } console.log('💾 저장할 카테고리 데이터:', categoryData); let response; if (categoryId) { // 수정 response = await apiCall(`/workplaces/categories/${categoryId}`, 'PUT', categoryData); } else { // 신규 등록 response = await apiCall('/workplaces/categories', 'POST', categoryData); } if (response && (response.success || response.category_id)) { const action = categoryId ? '수정' : '등록'; showToast(`공장이 성공적으로 ${action}되었습니다.`, 'success'); closeCategoryModal(); await loadAllData(); } else { throw new Error(response?.message || '저장에 실패했습니다.'); } } catch (error) { console.error('카테고리 저장 오류:', error); showToast(error.message || '카테고리 저장 중 오류가 발생했습니다.', 'error'); } } // 카테고리 삭제 async function deleteCategory() { if (!currentEditingCategory) return; if (!confirm(`"${currentEditingCategory.category_name}" 공장을 정말 삭제하시겠습니까?\n\n⚠️ 이 공장에 속한 모든 작업장의 공장 정보가 제거됩니다.`)) { return; } try { const response = await apiCall(`/workplaces/categories/${currentEditingCategory.category_id}`, 'DELETE'); if (response && response.success) { showToast('공장이 성공적으로 삭제되었습니다.', 'success'); closeCategoryModal(); await loadAllData(); } else { throw new Error(response?.message || '삭제에 실패했습니다.'); } } catch (error) { console.error('카테고리 삭제 오류:', error); showToast(error.message || '카테고리 삭제 중 오류가 발생했습니다.', 'error'); } } // ==================== 작업장 관련 ==================== // 작업장 목록 로드 async function loadWorkplaces() { try { const response = await apiCall('/workplaces', 'GET'); let workplaceData = []; if (response && response.success && Array.isArray(response.data)) { workplaceData = response.data; } else if (Array.isArray(response)) { workplaceData = response; } workplaces = workplaceData; console.log(`✅ 작업장 ${workplaces.length}개 로드 완료`); } catch (error) { console.error('작업장 로딩 오류:', error); workplaces = []; } } // 작업장 렌더링 function renderWorkplaces() { const grid = document.getElementById('workplaceGrid'); if (!grid) return; // 현재 카테고리별 필터링 const filtered = currentCategoryId === '' ? workplaces : workplaces.filter(w => w.category_id == currentCategoryId); if (filtered.length === 0) { grid.innerHTML = `
🏗️

등록된 작업장이 없습니다.

"작업장 추가" 버튼을 눌러 작업장을 등록해보세요.

`; return; } let gridHtml = ''; filtered.forEach(workplace => { const categoryName = workplace.category_name || '미분류'; const isActive = workplace.is_active === 1 || workplace.is_active === true; gridHtml += `
🏗️

${workplace.workplace_name}

${workplace.category_id ? `🏭 ${categoryName}` : ''}
${workplace.description ? `

${workplace.description}

` : ''}
등록: ${formatDate(workplace.created_at)} ${workplace.updated_at !== workplace.created_at ? `수정: ${formatDate(workplace.updated_at)}` : ''}
`; }); grid.innerHTML = gridHtml; } // 작업장 모달 열기 function openWorkplaceModal(workplaceData = null) { const modal = document.getElementById('workplaceModal'); const modalTitle = document.getElementById('workplaceModalTitle'); const deleteBtn = document.getElementById('deleteWorkplaceBtn'); const categorySelect = document.getElementById('workplaceCategoryId'); if (!modal) return; currentEditingWorkplace = workplaceData; // 카테고리 선택 옵션 업데이트 let categoryOptions = ''; categories.forEach(cat => { categoryOptions += ``; }); categorySelect.innerHTML = categoryOptions; if (workplaceData) { // 수정 모드 modalTitle.textContent = '작업장 수정'; deleteBtn.style.display = 'inline-flex'; document.getElementById('workplaceId').value = workplaceData.workplace_id; document.getElementById('workplaceCategoryId').value = workplaceData.category_id || ''; document.getElementById('workplaceName').value = workplaceData.workplace_name || ''; document.getElementById('workplaceDescription').value = workplaceData.description || ''; } else { // 신규 등록 모드 modalTitle.textContent = '작업장 추가'; deleteBtn.style.display = 'none'; document.getElementById('workplaceForm').reset(); document.getElementById('workplaceId').value = ''; // 현재 선택된 카테고리가 있으면 자동 선택 if (currentCategoryId) { document.getElementById('workplaceCategoryId').value = currentCategoryId; } } modal.style.display = 'flex'; document.body.style.overflow = 'hidden'; setTimeout(() => { document.getElementById('workplaceName').focus(); }, 100); } // 작업장 모달 닫기 function closeWorkplaceModal() { const modal = document.getElementById('workplaceModal'); if (modal) { modal.style.display = 'none'; document.body.style.overflow = ''; currentEditingWorkplace = null; } } // 작업장 편집 function editWorkplace(workplaceId) { const workplace = workplaces.find(w => w.workplace_id === workplaceId); if (workplace) { openWorkplaceModal(workplace); } else { showToast('작업장을 찾을 수 없습니다.', 'error'); } } // 작업장 저장 async function saveWorkplace() { try { const workplaceId = document.getElementById('workplaceId').value; const workplaceData = { category_id: document.getElementById('workplaceCategoryId').value || null, workplace_name: document.getElementById('workplaceName').value.trim(), description: document.getElementById('workplaceDescription').value.trim() || null, is_active: true }; if (!workplaceData.workplace_name) { showToast('작업장명은 필수 입력 항목입니다.', 'error'); return; } console.log('💾 저장할 작업장 데이터:', workplaceData); let response; if (workplaceId) { // 수정 response = await apiCall(`/workplaces/${workplaceId}`, 'PUT', workplaceData); } else { // 신규 등록 response = await apiCall('/workplaces', 'POST', workplaceData); } if (response && (response.success || response.workplace_id)) { const action = workplaceId ? '수정' : '등록'; showToast(`작업장이 성공적으로 ${action}되었습니다.`, 'success'); closeWorkplaceModal(); await loadAllData(); } else { throw new Error(response?.message || '저장에 실패했습니다.'); } } catch (error) { console.error('작업장 저장 오류:', error); showToast(error.message || '작업장 저장 중 오류가 발생했습니다.', 'error'); } } // 작업장 삭제 확인 function confirmDeleteWorkplace(workplaceId) { const workplace = workplaces.find(w => w.workplace_id === workplaceId); if (!workplace) { showToast('작업장을 찾을 수 없습니다.', 'error'); return; } if (confirm(`"${workplace.workplace_name}" 작업장을 정말 삭제하시겠습니까?\n\n⚠️ 삭제된 작업장은 복구할 수 없습니다.`)) { deleteWorkplaceById(workplaceId); } } // 작업장 삭제 (수정 모드에서) function deleteWorkplace() { if (currentEditingWorkplace) { confirmDeleteWorkplace(currentEditingWorkplace.workplace_id); } } // 작업장 삭제 실행 async function deleteWorkplaceById(workplaceId) { try { const response = await apiCall(`/workplaces/${workplaceId}`, 'DELETE'); if (response && response.success) { showToast('작업장이 성공적으로 삭제되었습니다.', 'success'); closeWorkplaceModal(); await loadAllData(); } else { throw new Error(response?.message || '삭제에 실패했습니다.'); } } catch (error) { console.error('작업장 삭제 오류:', error); showToast(error.message || '작업장 삭제 중 오류가 발생했습니다.', 'error'); } } // ==================== 유틸리티 ==================== // 전체 새로고침 async function refreshWorkplaces() { const refreshBtn = document.querySelector('.btn-secondary'); if (refreshBtn) { const originalText = refreshBtn.innerHTML; refreshBtn.innerHTML = '새로고침 중...'; refreshBtn.disabled = true; await loadAllData(); refreshBtn.innerHTML = originalText; refreshBtn.disabled = false; } else { await loadAllData(); } showToast('데이터가 새로고침되었습니다.', 'success'); } // 통계 업데이트 function updateStatistics() { const total = workplaces.length; const active = workplaces.filter(w => w.is_active === 1 || w.is_active === true).length; document.getElementById('totalCount').textContent = total; document.getElementById('activeCount').textContent = active; } // 날짜 포맷팅 function formatDate(dateString) { if (!dateString) return ''; const date = new Date(dateString); return date.toLocaleDateString('ko-KR', { year: 'numeric', month: '2-digit', day: '2-digit' }); } // 토스트 메시지 표시 function showToast(message, type = 'info') { // 기존 토스트 제거 const existingToast = document.querySelector('.toast'); if (existingToast) { existingToast.remove(); } // 새 토스트 생성 const toast = document.createElement('div'); toast.className = `toast toast-${type}`; toast.textContent = message; // 스타일 적용 Object.assign(toast.style, { position: 'fixed', top: '20px', right: '20px', padding: '12px 24px', borderRadius: '8px', color: 'white', fontWeight: '500', zIndex: '1000', transform: 'translateX(100%)', transition: 'transform 0.3s ease' }); // 타입별 배경색 const colors = { success: '#10b981', error: '#ef4444', warning: '#f59e0b', info: '#3b82f6' }; toast.style.backgroundColor = colors[type] || colors.info; document.body.appendChild(toast); // 애니메이션 setTimeout(() => { toast.style.transform = 'translateX(0)'; }, 100); // 자동 제거 setTimeout(() => { toast.style.transform = 'translateX(100%)'; setTimeout(() => { if (toast.parentNode) { toast.remove(); } }, 300); }, 3000); } // 전역 함수로 노출 window.switchCategory = switchCategory; window.openCategoryModal = openCategoryModal; window.closeCategoryModal = closeCategoryModal; window.saveCategory = saveCategory; window.deleteCategory = deleteCategory; window.openWorkplaceModal = openWorkplaceModal; window.closeWorkplaceModal = closeWorkplaceModal; window.editWorkplace = editWorkplace; window.saveWorkplace = saveWorkplace; window.deleteWorkplace = deleteWorkplace; window.confirmDeleteWorkplace = confirmDeleteWorkplace; window.refreshWorkplaces = refreshWorkplaces;