// 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);
}
}