当前位置: 首页 > ds >正文

19、云端工业物联网生态组件 - 工厂能效与预测维护 - /数据与物联网组件/cloud-iiot-factory-analysis

76个工业组件库示例汇总

云端工业物联网生态组件 - 工厂能效与预测维护 (模拟)

概述

这是一个交互式的 Web 组件,旨在模拟一个云端工业物联网 (IIoT) 平台的核心界面,专注于工厂层面的能效分析和基于传感器数据的预测性维护概念。用户可以监控模拟的设备状态,查看全局或单个设备的能耗指标,并观察预测性维护警报的生成。

请注意:这是一个高度简化的前端模拟演示,不连接任何真实的云平台或物理设备。所有数据、状态变化、警报和预测都是在浏览器端模拟生成的。

主要功能

  • 设备监控列表:
    • 展示工厂内的模拟设备列表(如 CNC、冲压机、机器人臂等)。
    • 显示每个设备的实时状态(在线、离线、警告、错误),状态会动态变化。
    • 提供搜索功能,可以按设备名称、类型、位置或 ID 过滤列表。
  • 全局 KPI 概览: 页眉实时显示工厂级的关键绩效指标 (KPI),包括:
    • 总实时功率 (kW)
    • 综合设备效率 (OEE %)
    • 活跃的预测性维护警报数量
  • 能效分析面板:
    • 默认显示全局能耗信息。
    • 当选择某个设备时,切换显示该单个设备的能耗信息。
    • 展示关键指标:当前功率、今日累计能耗、本周累计能耗、能效指标 (kWh/件,模拟计算)。
    • 包含模拟的实时功率趋势图和产线能耗占比饼图(占位符)。
  • 预测性维护面板:
    • 当选择某个设备时,显示该设备的预测性维护相关信息。
    • 活跃警报列表: 显示针对该设备的警告(如传感器值偏高、RUL 低)或错误(传感器值异常)信息,包含警报级别、消息和时间戳。
    • 关键传感器信息: 显示模拟的传感器类型(如振动、温度)、模拟的传感器数值趋势图(占位符)以及最重要的预估剩余使用寿命 (RUL) (小时)。
  • 动态模拟:
    • 设备状态(在线/离线/警告/错误)会基于模拟的传感器读数和随机事件动态变化。
    • 能耗数据(功率、累计能耗)会根据设备状态和模拟逻辑实时更新。
    • 预测性警报会根据模拟的传感器值和 RUL 阈值动态生成。
  • 界面风格: 采用苹果科技风格,简洁、直观,三栏布局并支持响应式设计,适应不同屏幕尺寸。

如何使用

  1. 打开页面: 在浏览器中打开 index.html
  2. 查看全局状态: 默认加载后,页面显示工厂的全局 KPI 和全局能效数据。
  3. 监控设备: 在左侧"设备监控"列表中查看所有模拟设备及其当前状态。
  4. 搜索设备: 使用列表上方的搜索框输入关键字(名称、类型、位置、ID)来快速查找特定设备。
  5. 选择设备: 点击设备列表中的任意一项:
    • 该项会高亮显示。
    • 中间的"能效分析"面板会更新,显示该设备的能耗数据。
    • 右侧的"预测性维护"面板会更新,显示该设备的活跃警报、传感器类型和预估 RUL。
  6. 取消选择: 再次点击已选中的设备项,将取消选择,面板恢复显示全局信息或占位符。
  7. 观察动态变化: 页面上的数据(KPI、设备状态、能耗、警报、RUL)会随时间自动更新,模拟工厂的动态运行。

模拟细节

  • 设备数据: 组件初始化时会生成一组包含不同类型、位置和传感器配置的模拟设备。
  • 状态变化: 设备的在线/离线状态会随机改变。警告/错误状态主要由模拟的传感器读数决定。当传感器读数超过预设的警告或错误阈值时,状态会改变;当读数回落后,有一定几率恢复为在线状态。
  • 能耗模拟: 在线设备的功率会在一个基础值附近随机波动。累计能耗根据功率和时间间隔累加。生产件数也是随机模拟的,用于计算简单的能效指标。
  • 传感器模拟: 每个设备关联一个模拟的关键传感器(类型随机)。其读数值会波动,且当 RUL 较低时,读数值偏高的可能性更大。
  • RUL 模拟: 每个设备的 RUL 会随时间线性递减。这是预测性维护的核心输入之一。
  • 警报生成: 当模拟的传感器值超过警告或错误阈值,或者 RUL 低于特定阈值(如 100 小时)时,会生成对应的预测性维护警报。
  • OEE 模拟: 这是一个非常简化的 OEE 计算,主要基于在线设备比例、模拟的生产效率和有问题的设备比例。

文件结构

数据与物联网组件/cloud-iiot-factory-analysis/
├── index.html         # 组件的 HTML 结构
├── styles.css         # 组件的 CSS 样式 (苹果风格, 三栏响应式布局)
├── script.js          # 组件的 JavaScript 逻辑 (模拟数据, 状态更新, 交互)
└── README.md          # 本说明文件

技术栈

  • HTML5
  • CSS3 (使用了 CSS 变量, Grid 布局, Flexbox, 媒体查询)
  • JavaScript (原生 JS, 无外部库依赖)

效果展示

在这里插入图片描述

源码

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>云IIoT - 工厂能效与预测维护</title><link rel="stylesheet" href="styles.css"><!-- Placeholder for potential charting library -->
</head>
<body><div class="iiot-ecosystem-container"><header class="main-header"><h1>云端IIoT生态 - 工厂能效与预测维护</h1><div class="header-kpis"><div class="kpi-item"><span class="kpi-label">总实时功率 (kW)</span><span class="kpi-value" id="totalPower">--</span></div><div class="kpi-item"><span class="kpi-label">综合设备效率 (OEE %)</span><span class="kpi-value" id="overallOEE">--</span></div><div class="kpi-item"><span class="kpi-label">预测维护警报</span><span class="kpi-value alert" id="predictiveAlertsCount">0</span></div><div class="kpi-item"><span class="kpi-label">时间</span><span class="kpi-value" id="currentTime">--:--:--</span></div></div></header><main class="main-content"><!-- Column 1: Device List & Status --><aside class="device-list-panel"><h2><i class="icon icon-device"></i> 设备监控</h2><div class="toolbar"><input type="search" id="deviceSearch" placeholder="搜索设备..."></div><ul id="deviceList" class="device-list"><!-- Device items populated by JS --><li class="placeholder">加载设备列表中...</li></ul></aside><!-- Column 2: Energy Efficiency Analysis --><section class="energy-analysis-panel"><h2><i class="icon icon-energy"></i> 能效分析 (<span id="selectedDeviceEnergy">全局</span>)</h2><div class="analysis-grid"><div class="chart-widget"><h3>实时功率趋势 (kW)</h3><div class="chart-placeholder" id="powerTrendChart"><div class="fake-chart energy-trend"></div><span class="chart-axis-label y-axis">功率 (kW)</span><span class="chart-axis-label x-axis">时间</span></div></div><div class="stats-widget"><h3>关键指标</h3><div class="stats-list"><div class="stat-item"><span>当前功率 (kW):</span> <strong id="currentPower">--</strong></div><div class="stat-item"><span>今日累计能耗 (kWh):</span> <strong id="todayEnergy">--</strong></div><div class="stat-item"><span>本周累计能耗 (kWh):</span> <strong id="weekEnergy">--</strong></div><div class="stat-item"><span>能效指标 (kWh/):</span> <strong id="efficiencyMetric">--</strong></div></div></div><div class="chart-widget"><h3>产线能耗占比 (%)</h3><div class="chart-placeholder" id="energyDistributionChart"><div class="fake-chart energy-pie"></div></div></div></div></section><!-- Column 3: Predictive Maintenance --><section class="predictive-maintenance-panel"><h2><i class="icon icon-predictive"></i> 预测性维护 (<span id="selectedDeviceMaintenance">--</span>)</h2><div class="maintenance-content"><div class="alerts-widget"><h3><i class="icon icon-alert"></i> 活跃警报</h3><ul id="alertList" class="alert-list"><li class="placeholder">无活跃警报</li><!-- Alerts populated by JS --></ul></div><div class="sensors-widget"><h3><i class="icon icon-sensor"></i> 关键传感器 (<span id="selectedSensorType">--</span>)</h3><div class="chart-placeholder" id="sensorTrendChart"><div class="fake-chart sensor-trend"></div><span class="chart-axis-label y-axis">数值</span><span class="chart-axis-label x-axis">时间</span></div><div class="sensor-details"><span>剩余寿命 (RUL): </span><strong id="rulEstimate">--</strong> 小时</div></div></div></section></main><footer class="main-footer"><p>&copy; 2024 云端IIoT模拟系统. 概念演示.</p></footer></div><script src="script.js"></script>
</body>
</html> 

styles.css

:root {--bg-color-light: #f9f9f9;--bg-color-container: #ffffff;--header-bg: #f5f5f7; /* Apple-like light grey */--panel-bg: #ffffff;--border-color: #e1e1e1;--text-primary: #1d1d1f;--text-secondary: #515154;--text-label: #6e6e73;--accent-blue: #007aff;--accent-green: #34c759;--accent-orange: #ff9500;--accent-red: #ff3b30;--kpi-value-color: var(--text-primary);--kpi-alert-color: var(--accent-red);--list-item-hover-bg: #f0f0f0;--list-item-selected-bg: #e8f3ff;--list-item-selected-text: var(--accent-blue);--input-bg: #f0f2f5;--input-border: transparent;--input-focus-border: var(--accent-blue);--placeholder-text: #aaaaaa;--chart-placeholder-bg: #f8f8f8;--chart-axis-color: #b0b0b0;--shadow-color: rgba(0, 0, 0, 0.05);--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--border-radius: 8px;--border-radius-small: 4px;--transition-speed: 0.2s;
}* {box-sizing: border-box;margin: 0;padding: 0;
}body {font-family: var(--font-family);background-color: var(--bg-color-light);color: var(--text-primary);line-height: 1.4;overflow-x: hidden;
}.iiot-ecosystem-container {max-width: 1600px;margin: 1rem auto;background-color: var(--bg-color-container);border-radius: var(--border-radius);box-shadow: 0 4px 12px var(--shadow-color);overflow: hidden;display: flex;flex-direction: column;height: calc(100vh - 2rem); /* Limit height */min-height: 700px; /* Minimum reasonable height */
}/* Header */
.main-header {background-color: var(--header-bg);padding: 0.75rem 1.5rem;border-bottom: 1px solid var(--border-color);flex-shrink: 0;display: flex;justify-content: space-between;align-items: center;
}.main-header h1 {font-size: 1.3rem;font-weight: 600;color: var(--text-primary);
}.header-kpis {display: flex;align-items: center;gap: 1.5rem;
}.kpi-item {display: flex;flex-direction: column;align-items: flex-end;
}.kpi-label {font-size: 0.75rem;color: var(--text-label);margin-bottom: 0.1rem;
}.kpi-value {font-size: 1rem;font-weight: 600;color: var(--kpi-value-color);
}.kpi-value.alert {color: var(--kpi-alert-color);font-weight: 700;
}/* Main Content Layout */
.main-content {flex-grow: 1;padding: 1rem;overflow: hidden;display: grid;grid-template-columns: 300px 1fr 1fr; /* Device List | Energy | Predictive */gap: 1rem;
}/* Panels */
.device-list-panel,
.energy-analysis-panel,
.predictive-maintenance-panel {background-color: var(--panel-bg);/* border: 1px solid var(--border-color); */ /* Optional border */border-radius: var(--border-radius);padding: 1rem;display: flex;flex-direction: column;overflow: hidden;
}/* Panel Headers */
.device-list-panel h2,
.energy-analysis-panel h2,
.predictive-maintenance-panel h2 {font-size: 1.1rem;font-weight: 600;margin-bottom: 1rem;padding-bottom: 0.6rem;border-bottom: 1px solid var(--border-color);display: flex;align-items: center;color: var(--text-primary);flex-shrink: 0;
}.device-list-panel h2 .icon,
.energy-analysis-panel h2 .icon,
.predictive-maintenance-panel h2 .icon {margin-right: 0.6rem;color: var(--accent-blue);
}.energy-analysis-panel h2 span,
.predictive-maintenance-panel h2 span {font-weight: normal;font-size: 0.9em;color: var(--text-secondary);margin-left: 0.3rem;
}/* Device List Panel */
.device-list-panel .toolbar {margin-bottom: 0.75rem;flex-shrink: 0;
}#deviceSearch {width: 100%;padding: 0.5rem 0.75rem;font-size: 0.9rem;border: 1px solid var(--input-border);background-color: var(--input-bg);border-radius: var(--border-radius-small);outline: none;transition: border-color var(--transition-speed), box-shadow var(--transition-speed);
}#deviceSearch:focus {border-color: var(--input-focus-border);box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.2);
}.device-list {list-style: none;overflow-y: auto;flex-grow: 1;
}.device-item {padding: 0.75rem 0.5rem;margin-bottom: 0.2rem;border-radius: var(--border-radius-small);cursor: pointer;transition: background-color var(--transition-speed);display: flex;justify-content: space-between;align-items: center;font-size: 0.9rem;
}.device-item:hover {background-color: var(--list-item-hover-bg);
}.device-item.selected {background-color: var(--list-item-selected-bg);color: var(--list-item-selected-text);font-weight: 500;
}.device-item .device-name {font-weight: 500;
}.device-status {font-size: 0.8rem;padding: 0.15rem 0.4rem;border-radius: 10px;color: white;
}.device-status.online {background-color: var(--accent-green);
}.device-status.offline {background-color: var(--text-secondary);
}.device-status.warning {background-color: var(--accent-orange);
}.device-status.error {background-color: var(--accent-red);
}/* Energy Analysis Panel */
.energy-analysis-panel .analysis-grid {display: grid;grid-template-columns: 1fr; /* Single column for now, could be 2 */grid-template-rows: auto auto 1fr;gap: 1rem;flex-grow: 1;overflow-y: auto;
}.chart-widget, .stats-widget {background-color: #fff; /* Slightly different bg if needed *//* border: 1px solid var(--border-color); */border-radius: var(--border-radius-small);padding: 1rem;
}.chart-widget h3, .stats-widget h3 {font-size: 0.95rem;font-weight: 500;margin-bottom: 0.75rem;color: var(--text-label);
}.stats-list {display: flex;flex-direction: column;gap: 0.6rem;
}.stat-item {font-size: 0.9rem;display: flex;justify-content: space-between;
}.stat-item span {color: var(--text-secondary);
}.stat-item strong {font-weight: 600;color: var(--kpi-value-color);
}/* Predictive Maintenance Panel */
.predictive-maintenance-panel .maintenance-content {display: grid;grid-template-rows: auto 1fr; /* Alerts list then sensor */gap: 1rem;flex-grow: 1;overflow-y: auto;
}.alerts-widget, .sensors-widget {background-color: #fff;border-radius: var(--border-radius-small);padding: 1rem;
}.alerts-widget h3, .sensors-widget h3 {font-size: 0.95rem;font-weight: 500;margin-bottom: 0.75rem;color: var(--text-label);display: flex;align-items: center;
}.alerts-widget h3 .icon, .sensors-widget h3 .icon {margin-right: 0.4rem;font-size: 0.9em;
}.sensors-widget h3 span {font-weight: normal;font-size: 0.9em;color: var(--text-secondary);margin-left: 0.3rem;
}.alert-list {list-style: none;max-height: 150px; /* Limit alert list height */overflow-y: auto;
}.alert-item {padding: 0.5rem 0;border-bottom: 1px dashed var(--border-color);font-size: 0.85rem;display: flex;align-items: center;gap: 0.5rem;
}.alert-item:last-child {border-bottom: none;
}.alert-icon {flex-shrink: 0;font-size: 1.1em;
}
.alert-icon.warning { color: var(--accent-orange); }
.alert-icon.error { color: var(--accent-red); }.alert-message {flex-grow: 1;
}.alert-time {font-size: 0.75rem;color: var(--text-secondary);flex-shrink: 0;
}.sensors-widget {display: flex;flex-direction: column;
}.sensors-widget .chart-placeholder {flex-grow: 1; /* Let chart take available space */min-height: 150px;
}.sensor-details {margin-top: 0.75rem;font-size: 0.9rem;text-align: center;flex-shrink: 0;
}.sensor-details span {color: var(--text-secondary);
}.sensor-details strong {font-weight: 600;color: var(--accent-orange); /* Highlight RUL */
}/* Chart Placeholders */
.chart-placeholder {background-color: var(--chart-placeholder-bg);border-radius: var(--border-radius-small);display: flex;align-items: center;justify-content: center;position: relative;overflow: hidden;border: 1px solid var(--border-color);
}.chart-axis-label {position: absolute;font-size: 0.7rem;color: var(--chart-axis-color);transform: rotate(-90deg);white-space: nowrap;
}.chart-axis-label.y-axis {left: -10px;top: 50%;transform-origin: left top;
}.chart-axis-label.x-axis {bottom: -10px;left: 50%;transform: translateX(-50%);
}.fake-chart {width: 90%;height: 80%;position: relative;
}/* Different fake chart styles */
.fake-chart.energy-trend::after,
.fake-chart.sensor-trend::after {content: '';position: absolute;inset: 0;background: linear-gradient(to right, transparent, rgba(0, 122, 255, 0.1), rgba(52, 199, 89, 0.15), rgba(255, 149, 0, 0.1), transparent);animation: fakePulse 6s ease-in-out infinite;border-radius: 3px;
}.fake-chart.energy-pie {width: 60%;height: 0;padding-bottom: 60%; /* Make it square */border-radius: 50%;background: conic-gradient(var(--accent-blue) 0% 30%,var(--accent-green) 30% 55%,var(--accent-orange) 55% 75%,var(--text-secondary) 75% 100%);animation: fakeSpin 20s linear infinite;border: 3px solid var(--chart-placeholder-bg);
}@keyframes fakePulse {0%, 100% { transform: scaleY(0.6); opacity: 0.5; }50% { transform: scaleY(1); opacity: 0.8; }
}@keyframes fakeSpin {from { transform: rotate(0deg); }to { transform: rotate(360deg); }
}/* Generic Placeholder */
.placeholder {color: var(--placeholder-text);font-style: italic;text-align: center;padding: 1rem;font-size: 0.9rem;
}/* Footer */
.main-footer {background-color: var(--header-bg); /* Match header */padding: 0.6rem 1.5rem;text-align: center;font-size: 0.8rem;color: var(--text-secondary);border-top: 1px solid var(--border-color);flex-shrink: 0;
}/* Icons (Basic Placeholders) */
.icon::before {display: inline-block;font-weight: normal;font-style: normal;font-variant: normal;text-rendering: auto;-webkit-font-smoothing: antialiased;margin-right: 0.3em;/* Consider using a proper icon font like Font Awesome or Material Icons */
}
.icon-device::before { content: "📱"; }
.icon-energy::before { content: "⚡️"; }
.icon-predictive::before { content: "🔧"; }
.icon-alert::before { content: "⚠️"; } /* Warning triangle */
.icon-sensor::before { content: "🌡️"; } /* Thermometer */
.alert-icon.warning::before { content: "🔶"; } /* Orange Diamond */
.alert-icon.error::before { content: "🔴"; } /* Red Circle *//* Responsive Design */
@media (max-width: 1200px) {.main-content {grid-template-columns: 250px 1fr 1fr; /* Smaller sidebar */}.header-kpis { gap: 1rem; }.main-header h1 { font-size: 1.15rem; }.kpi-label { font-size: 0.7rem; }.kpi-value { font-size: 0.9rem; }
}@media (max-width: 992px) {.iiot-ecosystem-container {height: auto; /* Allow content to determine height */min-height: 100vh;margin: 0.5rem;}.main-content {grid-template-columns: 1fr; /* Stack columns */grid-template-rows: auto auto auto; /* Let rows size automatically */padding: 0.5rem;gap: 0.5rem;}.device-list-panel,.energy-analysis-panel,.predictive-maintenance-panel {padding: 0.75rem;overflow-y: visible; /* Allow panels to grow */}.device-list { max-height: 250px; } /* Limit list height on mobile */.alert-list { max-height: 120px; }.energy-analysis-panel .analysis-grid,.predictive-maintenance-panel .maintenance-content {overflow-y: visible;}.main-header {flex-direction: column;align-items: flex-start;gap: 0.5rem;padding: 0.75rem;}.header-kpis {width: 100%;justify-content: space-between;flex-wrap: wrap;gap: 0.5rem 1rem;}.kpi-item { align-items: flex-start; }
}@media (max-width: 576px) {.main-header h1 { font-size: 1rem; }.header-kpis { gap: 0.3rem 0.8rem; }.kpi-label { font-size: 0.65rem; }.kpi-value { font-size: 0.8rem; }.device-list-panel h2,.energy-analysis-panel h2,.predictive-maintenance-panel h2 {font-size: 1rem;}
} 

script.js

// script.js - Cloud IIoT Factory Analysis Componentdocument.addEventListener('DOMContentLoaded', () => {// --- DOM Elements ---const totalPowerEl = document.getElementById('totalPower');const overallOEEEl = document.getElementById('overallOEE');const predictiveAlertsCountEl = document.getElementById('predictiveAlertsCount');const currentTimeEl = document.getElementById('currentTime');const deviceSearchInput = document.getElementById('deviceSearch');const deviceListUl = document.getElementById('deviceList');const selectedDeviceEnergyEl = document.getElementById('selectedDeviceEnergy');const currentPowerEl = document.getElementById('currentPower');const todayEnergyEl = document.getElementById('todayEnergy');const weekEnergyEl = document.getElementById('weekEnergy');const efficiencyMetricEl = document.getElementById('efficiencyMetric');const selectedDeviceMaintenanceEl = document.getElementById('selectedDeviceMaintenance');const alertListUl = document.getElementById('alertList');const selectedSensorTypeEl = document.getElementById('selectedSensorType');const rulEstimateEl = document.getElementById('rulEstimate');// Chart placeholders are mostly for styling in this versionconst powerTrendChartEl = document.getElementById('powerTrendChart');const energyDistributionChartEl = document.getElementById('energyDistributionChart');const sensorTrendChartEl = document.getElementById('sensorTrendChart');// --- Simulation State & Parameters ---let simulationTime = new Date();let selectedDeviceId = null; // null means global viewlet searchTerm = '';let factoryDevices = {}; // Store device datalet factoryState = {totalPower: 0,overallOEE: 0,alerts: [],todayEnergyGlobal: 0,weekEnergyGlobal: 0,};// Update intervals (in ms)const timeUpdateInterval = 1000;const dataUpdateInterval = 3000; // Update device data less frequentlyconst alertCheckInterval = 7000; // Check for new alerts periodically// --- Sample Data Generation ---function generateSampleDevices(count = 15) {const devices = {};const types = ['CNC机床', '冲压机', '注塑机', '机器人臂', '传送带', '压缩机'];const locations = ['A栋1楼', 'A栋2楼', 'B栋1楼', 'C栋动力房'];const sensorTypes = ['振动', '温度', '压力', '电流'];for (let i = 1; i <= count; i++) {const id = `DEV-${String(i).padStart(3, '0')}`;const type = types[Math.floor(Math.random() * types.length)];const location = locations[Math.floor(Math.random() * locations.length)];devices[id] = {id: id,name: `${type} #${i}`,type: type,location: location,status: 'offline', // Initial statuspower: 0, // kWtodayEnergy: 0, // kWhweekEnergy: 0, // kWhunitsProduced: 0,efficiencyMetric: null, // kWh/unitsensors: {type: sensorTypes[Math.floor(Math.random() * sensorTypes.length)],value: 0,thresholdWarning: 50 + Math.random() * 20,thresholdError: 80 + Math.random() * 15,rul: 1000 + Math.random() * 2000, // Remaining Useful Life in hours},alerts: [] // Active alerts for this device};}return devices;}// --- Initialization ---function initializeIIoTMonitor() {factoryDevices = generateSampleDevices();setupEventListeners();updateTime();setInterval(updateTime, timeUpdateInterval);// Start simulation loopsupdateFactoryData(); // Initial data loadsetInterval(updateFactoryData, dataUpdateInterval);setInterval(checkForNewAlerts, alertCheckInterval);renderDeviceList(); // Initial renderdisplayGlobalEnergyData(); // Show global initiallydisplayMaintenanceInfo(); // Show placeholder initiallyconsole.log("Cloud IIoT Monitor Initialized");}// --- Event Handlers ---function setupEventListeners() {deviceSearchInput.addEventListener('input', handleSearchInput);deviceListUl.addEventListener('click', handleDeviceSelect);}function handleSearchInput(event) {searchTerm = event.target.value.toLowerCase();renderDeviceList();}function handleDeviceSelect(event) {const listItem = event.target.closest('.device-item');if (listItem && listItem.dataset.id) {const deviceId = listItem.dataset.id;if (selectedDeviceId === deviceId) {// Clicked selected device again: Deselect and show globalselectedDeviceId = null;displayGlobalEnergyData();displayMaintenanceInfo(); // Clear maintenance panel or show global summary?} else {selectedDeviceId = deviceId;displayDeviceEnergyData(selectedDeviceId);displayMaintenanceInfo(selectedDeviceId);}renderDeviceList(); // Re-render to update selection highlight}}// --- Simulation & Data Update Logic ---function updateTime() {simulationTime = new Date();currentTimeEl.textContent = simulationTime.toLocaleTimeString('zh-CN');}function updateFactoryData() {let currentTotalPower = 0;let totalUnits = 0;let onlineDevices = 0;let devicesWithIssues = 0;Object.values(factoryDevices).forEach(device => {// Simulate status changesconst randStatus = Math.random();if (device.status === 'offline' && randStatus < 0.1) {device.status = 'online'; // Chance to come online} else if (device.status === 'online' && randStatus < 0.02) {device.status = 'offline'; // Chance to go offlinedevice.power = 0;} else if (device.status !== 'offline') {// Simulate power fluctuation for online/warning/error devicesconst basePower = (device.type === 'CNC机床' || device.type === '冲压机') ? 15 : 8;device.power = basePower + (Math.random() - 0.3) * 5;if (device.power < 0) device.power = 0;// Simulate energy consumptionconst energyConsumed = device.power * (dataUpdateInterval / (1000 * 3600)); // kWhdevice.todayEnergy += energyConsumed;device.weekEnergy += energyConsumed;factoryState.todayEnergyGlobal += energyConsumed;factoryState.weekEnergyGlobal += energyConsumed;// Simulate productionif (device.power > basePower * 0.5) {const units = Math.floor(Math.random() * 3);device.unitsProduced += units;totalUnits += units;if (device.unitsProduced > 0) {device.efficiencyMetric = device.todayEnergy / device.unitsProduced;}}onlineDevices++;}// Simulate sensor readings & RUL decreaseif (device.status !== 'offline') {device.sensors.rul -= (dataUpdateInterval / (1000 * 3600)); // Decrease RULif (device.sensors.rul < 0) device.sensors.rul = 0;const sensorRand = Math.random();// Fluctuate sensor value, more likely to increase if RUL is lowconst baseSensorValue = 20 + (1000 / (device.sensors.rul + 10)) * 2; // Higher base value for lower RULdevice.sensors.value = baseSensorValue + (sensorRand - 0.5 + (device.sensors.rul < 200 ? 0.2 : 0)) * 15;if (device.sensors.value < 0) device.sensors.value = 0;if (device.sensors.value > 100) device.sensors.value = 100;// Update status based on sensor thresholdsif (device.sensors.value >= device.sensors.thresholdError && device.status !== 'offline') {if (device.status !== 'error') device.status = 'error';devicesWithIssues++;} else if (device.sensors.value >= device.sensors.thresholdWarning && device.status !== 'offline') {if (device.status !== 'error' && device.status !== 'warning') device.status = 'warning';devicesWithIssues++;} else if (device.status === 'error' || device.status === 'warning') {// Chance to recover if value drops (less likely for error)if (Math.random() < (device.status === 'error' ? 0.05 : 0.2)) {device.status = 'online';}}}currentTotalPower += device.power;});factoryState.totalPower = currentTotalPower;// Simulate OEE (simple version based on online and issue states)const availability = onlineDevices / Object.keys(factoryDevices).length;const performance = totalUnits > 0 ? 0.8 + Math.random() * 0.15 : 0; // Simplified performanceconst quality = 1 - (devicesWithIssues / (onlineDevices + 0.1)); // Simplified qualityfactoryState.overallOEE = availability * performance * quality * 100;if (factoryState.overallOEE < 0) factoryState.overallOEE = 0;if (factoryState.overallOEE > 100) factoryState.overallOEE = 100;// Update header KPIstotalPowerEl.textContent = factoryState.totalPower.toFixed(1);overallOEEEl.textContent = factoryState.overallOEE.toFixed(1);// Re-render lists and panels if necessary (e.g., status changed)renderDeviceList();if (selectedDeviceId) {displayDeviceEnergyData(selectedDeviceId);displayMaintenanceInfo(selectedDeviceId);} else {displayGlobalEnergyData();}}function checkForNewAlerts() {factoryState.alerts = []; // Clear global alerts, rebuild from deviceslet activeAlertCount = 0;Object.values(factoryDevices).forEach(device => {device.alerts = []; // Clear device alerts firstconst sensorVal = device.sensors.value;let alertLevel = null;let message = '';if (device.status === 'error' || sensorVal >= device.sensors.thresholdError) {alertLevel = 'error';message = `${device.sensors.type}值异常 (${sensorVal.toFixed(1)}),可能导致故障`;} else if (device.status === 'warning' || sensorVal >= device.sensors.thresholdWarning) {alertLevel = 'warning';message = `${device.sensors.type}值偏高 (${sensorVal.toFixed(1)}),请关注`;}if (alertLevel && Math.random() < 0.8) { // Don't generate alert every single timeconst newAlert = {id: `alrt-${device.id}-${Date.now()}`,deviceId: device.id,deviceName: device.name,level: alertLevel,message: message,timestamp: new Date()};device.alerts.push(newAlert);factoryState.alerts.push(newAlert);activeAlertCount++;}});// Add a RUL based alertObject.values(factoryDevices).forEach(device => {if (device.sensors.rul < 100 && device.status !== 'offline' && Math.random() < 0.5) { // RUL warning < 100 hoursconst newAlert = {id: `alrt-${device.id}-rul-${Date.now()}`,deviceId: device.id,deviceName: device.name,level: 'warning',message: `预估剩余寿命低 (${device.sensors.rul.toFixed(0)} 小时),建议安排维护`,timestamp: new Date()};// Avoid duplicate RUL alerts for the same device if one already existsif (!device.alerts.some(a => a.message.includes('剩余寿命'))) {device.alerts.push(newAlert);factoryState.alerts.push(newAlert);activeAlertCount++;}}});factoryState.alerts.sort((a, b) => b.timestamp - a.timestamp); // Sort newest firstpredictiveAlertsCountEl.textContent = activeAlertCount;if (activeAlertCount > 0) {predictiveAlertsCountEl.classList.add('alert');} else {predictiveAlertsCountEl.classList.remove('alert');}// Update maintenance panel if a device is selectedif (selectedDeviceId) {displayMaintenanceInfo(selectedDeviceId);}}// --- Rendering Functions ---function renderDeviceList() {deviceListUl.innerHTML = ''; // Clear listconst filteredDevices = Object.values(factoryDevices).filter(device =>device.name.toLowerCase().includes(searchTerm)|| device.type.toLowerCase().includes(searchTerm)|| device.location.toLowerCase().includes(searchTerm)|| device.id.toLowerCase().includes(searchTerm));if (filteredDevices.length === 0) {deviceListUl.innerHTML = '<li class="placeholder">未找到匹配设备</li>';return;}filteredDevices.sort((a, b) => a.name.localeCompare(b.name)) // Sort alphabetically.forEach(device => {const li = document.createElement('li');li.className = 'device-item';li.dataset.id = device.id;if (device.id === selectedDeviceId) {li.classList.add('selected');}li.innerHTML = `<span class="device-name">${device.name} <small>(${device.location})</small></span><span class="device-status ${device.status}">${device.status.toUpperCase()}</span>`;deviceListUl.appendChild(li);});}function displayGlobalEnergyData() {selectedDeviceEnergyEl.textContent = '全局';currentPowerEl.textContent = factoryState.totalPower.toFixed(1);todayEnergyEl.textContent = factoryState.todayEnergyGlobal.toFixed(1);weekEnergyEl.textContent = factoryState.weekEnergyGlobal.toFixed(1);// Global efficiency metric might be complex, leave blank or use an averageefficiencyMetricEl.textContent = '--';// TODO: Update global charts (placeholders for now)}function displayDeviceEnergyData(deviceId) {const device = factoryDevices[deviceId];if (!device) return;selectedDeviceEnergyEl.textContent = device.name;currentPowerEl.textContent = device.power.toFixed(1);todayEnergyEl.textContent = device.todayEnergy.toFixed(1);weekEnergyEl.textContent = device.weekEnergy.toFixed(1);efficiencyMetricEl.textContent = device.efficiencyMetric ? device.efficiencyMetric.toFixed(2) : '--';// TODO: Update energy charts for the specific device (placeholders)}function displayMaintenanceInfo(deviceId = null) {if (!deviceId) {selectedDeviceMaintenanceEl.textContent = '全局概览'; // Or maybe show all active alerts?selectedSensorTypeEl.textContent = '--';rulEstimateEl.textContent = '--';alertListUl.innerHTML = '<li class="placeholder">选择设备查看警报</li>';// TODO: Clear or show global sensor overview chart (placeholder)return;}const device = factoryDevices[deviceId];if (!device) return;selectedDeviceMaintenanceEl.textContent = device.name;selectedSensorTypeEl.textContent = device.sensors.type;rulEstimateEl.textContent = device.sensors.rul.toFixed(0);// Display alerts for this devicealertListUl.innerHTML = '';const deviceAlerts = factoryState.alerts.filter(a => a.deviceId === deviceId);if (deviceAlerts.length === 0) {alertListUl.innerHTML = '<li class="placeholder">无活跃警报</li>';} else {deviceAlerts.forEach(alert => {const li = document.createElement('li');li.className = 'alert-item';li.innerHTML = `<span class="alert-icon ${alert.level}"></span><span class="alert-message">${alert.message}</span><span class="alert-time">${alert.timestamp.toLocaleTimeString('zh-CN')}</span>`;alertListUl.appendChild(li);});}// TODO: Update sensor trend chart for the device (placeholder)}// --- Initial Call ---initializeIIoTMonitor();
}); 
http://www.xdnf.cn/news/6377.html

相关文章:

  • 紫外波段太阳光模拟器介绍
  • Python Matplotlib 库【绘图基础库】全面解析
  • 在UI 原型设计中,交互规则有哪些核心要素?
  • 数据统计分析及可视化
  • 开源 Web Shell 工具
  • 万文c++继承
  • 前端表格滑动滚动条太费事,做个浮动滑动插件
  • Java基于SpringBoot的外卖系统小程序【附源码、文档说明】
  • 功能连接计算的科学选择:静息态fMRI中20种指标的全面评估
  • 卓力达红外热成像靶标:革新军事训练与航空检测的关键技术
  • FastAPI系列16:从API文档到TypeScript 前端客户端(SDKs)
  • 3天重庆和成都旅游规划
  • 【PmHub后端篇】PmHub集成 Sentinel+OpenFeign实现网关流量控制与服务降级
  • acwing 4275. Dijkstra序列
  • 二叉树复习(C语言版)
  • 国标GB28181视频平台EasyGBS打造交通道路/停车场/公共场所违章视频监控解决方案
  • keil编译时报错:error:Could not open file .\***\core_cm3.o(最有用的方法没有之一!!!)
  • 代码随想录算法训练营第三十九天(打家劫舍专题) | 198.打家劫舍、213.打家劫舍II、337.打家劫舍III
  • Windows更新暂停七天关键注册表
  • 无人机箱号识别系统结合5G技术的应用实践
  • 数字IC后端零基础入门基础理论(Day2)
  • AD 间距规则与布线规则
  • GaussDB 实例 gsql 连接方式详解
  • 在python中使用Json提取数据
  • [思维模式-38]:看透事物的关系:什么是事物的关系?事物之间的关系的种类?什么是因果关系?如何通过数学的方式表达因果关系?
  • 第五部分:第三节 - Express.js 框架入门:厨房的流程管理系统
  • 力扣-102.二叉树的层序遍历
  • 在 Ubuntu 20.04.6 LTS 中将 SCons 从 3.1.2 升级到 4.9.1
  • c++和c的不同
  • 【复刻】人工智能技术应用如何影响企业创新(2007-2023年)