// Dashboard Business logic and data visualization for ChemiFactory MES document.addEventListener("DOMContentLoaded", () => { fetchAPIStatus(); loadDashboardData(); }); const BACKEND_URL = `${window.location.protocol}//${window.location.host}`; // API 연결 상태 확인 async function fetchAPIStatus() { const badge = document.getElementById("api-status-badge"); try { const response = await fetch(`${BACKEND_URL}/api/status`); if (response.ok) { badge.textContent = "시스템 정상"; badge.className = "badge badge-online"; } else { throw new Error("HTTP Status Error"); } } catch (e) { badge.textContent = "연결 실패"; badge.className = "badge badge-offline"; } } // 대시보드 데이터 바인딩 async function loadDashboardData() { try { // 1. 고객사 개수 로드 (API: /customers/) const custRes = await fetch(`${BACKEND_URL}/customers/`); if (custRes.ok) { const list = await custRes.json(); document.getElementById("customer-count").textContent = `${list.length} 개사`; } // 2. 재고 정보 로드 (API: /inventory/) const invRes = await fetch(`${BACKEND_URL}/inventory/`); if (invRes.ok) { const list = await invRes.json(); // 품절되거나 소진 임계에 도달한 재고 경보 카운트 const lowStockCount = list.filter(item => item.is_depleted === 1 || item.stock <= 10).length; document.getElementById("low-inventory-count").textContent = `${lowStockCount} 건`; } // 3. 설비 리스트 및 작동 요약 로드 (⚠️ 제외 대상에 따른 대시보드 미니 가동기기 출력 유지) const equipRes = await fetch(`${BACKEND_URL}/equipment/`); let totalEquip = 0; let activeEquip = 0; if (equipRes.ok) { const list = await equipRes.json(); totalEquip = list.length; // 미니 HMI 대시보드 리스트 생성 const hmiContainer = document.getElementById("equipment-mini-list"); if (list.length === 0) { hmiContainer.innerHTML = `
등록된 설비가 없습니다.
`; } else { hmiContainer.innerHTML = ""; // 초기화 list.forEach(eq => { const isOnline = eq.status === "available" || eq.is_online; // 활성화 체크 필드 if (isOnline) activeEquip++; const dotClass = isOnline ? "dot-green" : "dot-red"; const statusText = isOnline ? "가동준비" : "점검필요"; const miniItem = document.createElement("div"); miniItem.className = "hmi-mini-card"; miniItem.innerHTML = `
${eq.name || eq.id} ${eq.status || "상태미필"}
${statusText}
`; hmiContainer.appendChild(miniItem); }); } document.getElementById("active-equip-count").textContent = `${activeEquip} / ${totalEquip}`; } // 4. 생산 지시 리스트 및 실적 요약 (API: /plans/) const planRes = await fetch(`${BACKEND_URL}/plans/`); if (planRes.ok) { const list = await planRes.json(); const planTable = document.getElementById("plan-list"); // 실적 합계 계산 let totalActualQty = 0; let totalTargetQty = 0; if (list.length === 0) { planTable.innerHTML = `등록된 생산 지시가 없습니다.`; } else { planTable.innerHTML = ""; // 초기화 // 최신 계획 5개만 대시보드에 표기 const recentPlans = list.slice(0, 5); recentPlans.forEach(plan => { // actual_quantity 속성이 없는 경우 baseline 0kg으로 방어 const actual = plan.actual_quantity || 0; const target = plan.requested_quantity_kg || 0; totalActualQty += actual; totalTargetQty += target; const row = document.createElement("tr"); row.innerHTML = ` Plan #${plan.plan_id} ${plan.plan_name || "-"} ${target.toLocaleString()} kg ${actual.toLocaleString()} kg ${plan.status === 'Completed' ? '완료' : '예정'} `; planTable.appendChild(row); }); } // 오늘의 생산량 카드 바인딩 document.getElementById("today-prod").textContent = `${totalActualQty.toLocaleString()} kg`; const progress = totalTargetQty > 0 ? Math.round((totalActualQty / totalTargetQty) * 100) : 0; const statCard = document.querySelector(".stat-card:nth-child(2) .stat-desc"); if (statCard) { statCard.textContent = `전체 목표 대비 진행도 ${progress}%`; } } } catch (e) { console.error("Failed to load dashboard statistics:", e); } }