diff --git a/web-ui/css/modern-dashboard.css b/web-ui/css/modern-dashboard.css index f7e6724..ff148b9 100644 --- a/web-ui/css/modern-dashboard.css +++ b/web-ui/css/modern-dashboard.css @@ -2940,6 +2940,23 @@ color: #6b7280; } +/* 임시 이동된 설비 */ +.equipment-marker.moved { + border-color: #f59e0b; + border-style: dashed; + border-width: 3px; + background: rgba(245, 158, 11, 0.15); + animation: movedPulse 2s infinite; +} +.equipment-marker.moved .marker-label { + color: #d97706; +} + +@keyframes movedPulse { + 0%, 100% { border-color: #f59e0b; } + 50% { border-color: #fbbf24; } +} + @keyframes pulse-border { 0%, 100% { border-color: #dc2626; } 50% { border-color: #fca5a5; } @@ -3825,3 +3842,168 @@ font-size: 9px; } } + +/* ==================== 임시 이동 설비 목록 ==================== */ +.moved-equipment-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 16px; +} + +.moved-equipment-card { + background: white; + border: 1px solid #e5e7eb; + border-radius: 12px; + padding: 16px; + cursor: pointer; + transition: all 0.15s ease; + border-left: 4px solid #f59e0b; +} + +.moved-equipment-card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + transform: translateY(-2px); +} + +.moved-eq-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; +} + +.moved-eq-code { + font-weight: 700; + font-size: 0.9rem; + color: #374151; +} + +.moved-eq-badge { + background: #fef3c7; + color: #d97706; + font-size: 0.75rem; + font-weight: 600; + padding: 2px 8px; + border-radius: 12px; +} + +.moved-eq-name { + font-size: 1rem; + font-weight: 600; + color: #111827; + margin-bottom: 12px; +} + +.moved-eq-location { + background: #f9fafb; + border-radius: 8px; + padding: 12px; + margin-bottom: 12px; +} + +.location-row { + display: flex; + justify-content: space-between; + align-items: center; +} + +.location-label { + font-size: 0.8rem; + color: #6b7280; +} + +.location-value { + font-size: 0.85rem; + font-weight: 500; + color: #374151; +} + +.location-value.current { + color: #f59e0b; + font-weight: 600; +} + +.location-arrow { + text-align: center; + color: #9ca3af; + font-size: 1rem; + margin: 4px 0; +} + +.moved-eq-date { + font-size: 0.8rem; + color: #9ca3af; + margin-bottom: 12px; +} + +.moved-equipment-card .btn { + width: 100%; +} + +/* 모달 내 이동 설비 탭 스타일 */ +.moved-eq-tab-content { + padding: 16px 0; +} + +.moved-eq-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.moved-eq-item { + background: white; + border-radius: 8px; + padding: 12px; + border-left: 4px solid #9ca3af; +} + +.moved-eq-item.in { + border-left-color: #22c55e; + background: #f0fdf4; +} + +.moved-eq-item.out { + border-left-color: #f59e0b; + background: #fffbeb; +} + +.moved-eq-item-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 6px; +} + +.moved-eq-item-header .eq-code { + font-weight: 700; + font-size: 0.85rem; + color: #374151; +} + +.moved-eq-item-header .eq-name { + font-size: 0.9rem; + color: #111827; +} + +.moved-eq-item-info { + display: flex; + align-items: center; + gap: 8px; + font-size: 0.8rem; + color: #6b7280; +} + +.moved-eq-item-info .arrow { + color: #9ca3af; +} + +.moved-eq-item-info .to-location { + font-weight: 500; +} + +.moved-eq-item-date { + font-size: 0.75rem; + color: #9ca3af; + margin-top: 4px; +} diff --git a/web-ui/js/app-init.js b/web-ui/js/app-init.js index cdd9d70..b757e5d 100644 --- a/web-ui/js/app-init.js +++ b/web-ui/js/app-init.js @@ -201,8 +201,8 @@ } }); - // 저장된 상태 복원 - const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true'; + // 저장된 상태 복원 (기본값: 접힌 상태) + const isCollapsed = localStorage.getItem('sidebarCollapsed') !== 'false'; const sidebar = doc.querySelector('.sidebar-nav'); if (isCollapsed && sidebar) { sidebar.classList.add('collapsed'); diff --git a/web-ui/js/load-sidebar.js b/web-ui/js/load-sidebar.js index f8bbc12..037b7b8 100644 --- a/web-ui/js/load-sidebar.js +++ b/web-ui/js/load-sidebar.js @@ -116,10 +116,10 @@ function highlightCurrentPage(doc) { } /** - * 사이드바 상태 복원 + * 사이드바 상태 복원 (기본값: 접힌 상태) */ function restoreSidebarState(doc) { - const isCollapsed = localStorage.getItem('sidebarCollapsed') === 'true'; + const isCollapsed = localStorage.getItem('sidebarCollapsed') !== 'false'; const sidebar = doc.querySelector('.sidebar-nav'); if (isCollapsed && sidebar) { diff --git a/web-ui/js/workplace-status.js b/web-ui/js/workplace-status.js index 3061791..13a5eca 100644 --- a/web-ui/js/workplace-status.js +++ b/web-ui/js/workplace-status.js @@ -24,6 +24,9 @@ document.addEventListener('DOMContentLoaded', async () => { // 기본값으로 제1공장 선택 await selectFirstCategory(); + + // 임시 이동된 설비 로드 + await loadMovedEquipments(); }); // ==================== 카테고리 (공장) 로드 ==================== @@ -641,9 +644,15 @@ async function loadEquipmentMarkers(workplaceId) { equipments.forEach(eq => { // 위치 정보가 있는 설비만 마커 표시 if (eq.map_x_percent != null && eq.map_y_percent != null) { - const statusClass = eq.status === 'active' ? 'active' : - eq.status === 'maintenance' ? 'maintenance' : - eq.status === 'repair_needed' ? 'repair' : 'inactive'; + // 임시 이동된 설비는 별도 클래스 적용 + let statusClass = ''; + if (eq.is_temporarily_moved) { + statusClass = 'moved'; + } else { + statusClass = eq.status === 'active' ? 'active' : + eq.status === 'maintenance' ? 'maintenance' : + eq.status === 'repair_needed' ? 'repair' : 'inactive'; + } // 마커 크기 (기본값 또는 설정된 값) const width = eq.map_width_percent || 8; @@ -651,14 +660,15 @@ async function loadEquipmentMarkers(workplaceId) { // 표시 이름: [코드] 이름 const displayName = `[${eq.equipment_code}] ${eq.equipment_name}`; + const movedBadge = eq.is_temporarily_moved ? ' 🚚' : ''; markersHtml += `