<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>智造驾驶舱 | 生产异常驱动与决策看板</title>
<!-- 字体与图标库 -->
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700\&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<!-- ECharts CDN -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #0a0f1c;
font-family: 'Inter', sans-serif;
padding: 20px;
color: #eef2ff;
}
/* 整体容器 */
.dashboard {
max-width: 1600px;
margin: 0 auto;
}
/* 头部驾驶舱导航 */
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
flex-wrap: wrap;
gap: 12px;
}
.title h1 {
font-size: 1.8rem;
font-weight: 600;
background: linear-gradient(135deg, #C0F2FF, #5E9EFF);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
letter-spacing: -0.3px;
}
.title p {
font-size: 0.85rem;
color: #8B9AC6;
margin-top: 4px;
}
.badge-group {
display: flex;
gap: 16px;
background: #101624;
padding: 8px 20px;
border-radius: 60px;
backdrop-filter: blur(4px);
}
.badge {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.85rem;
font-weight: 500;
}
.badge i {
font-size: 1rem;
}
.live-dot {
width: 8px;
height: 8px;
background: #22c55e;
border-radius: 50%;
display: inline-block;
box-shadow: 0 0 6px #22c55e;
animation: pulse 1.5s infinite;
}
@keyframes pulse { 0% { opacity: 0.4; } 100% { opacity: 1; } }
/* 网格布局 */
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 20px;
}
.card {
background: rgba(18, 24, 38, 0.75);
backdrop-filter: blur(2px);
border-radius: 28px;
border: 1px solid rgba(56, 78, 120, 0.3);
box-shadow: 0 12px 28px -8px rgba(0,0,0,0.4);
overflow: hidden;
transition: all 0.2s;
}
.card-header {
padding: 16px 20px 8px 20px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(72, 96, 144, 0.3);
font-weight: 600;
}
.card-header span:first-child {
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 1px;
color: #A0B3E9;
}
.card-body {
padding: 12px 16px 20px;
}
/* 大卡片跨列 */
.colspan-2 { grid-column: span 2; }
.colspan-full { grid-column: 1 / -1; }
/* 指标数值 */
.kpi-row {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-top: 8px;
}
.kpi-value {
font-size: 2rem;
font-weight: 700;
}
.trend-up { color: #4ade80; font-size: 0.75rem; }
.trend-down { color: #f97316; }
.alert-badge {
background: #dc2626;
padding: 2px 8px;
border-radius: 30px;
font-size: 0.7rem;
font-weight: 600;
}
/* 环境&设备状态列表 */
.env-item, .machine-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #1f2a44;
}
.env-label i, .machine-label i { width: 24px; }
.warning-text { color: #f97316; font-weight: 600; }
.critical { color: #ef4444; }
.status-badge {
padding: 2px 8px;
border-radius: 40px;
font-size: 0.7rem;
font-weight: 600;
}
.status-running { background: #22c55e20; color: #4ade80; border: 0.5px solid #22c55e; }
.status-down { background: #ef444420; color: #ff8a8a; border: 0.5px solid #ef4444; }
.status-idle { background: #facc1520; color: #facc15; }
/* 异常预警滚动区 */
.alert-list {
max-height: 220px;
overflow-y: auto;
}
.alert-item {
background: rgba(220, 38, 38, 0.1);
border-left: 3px solid #ef4444;
margin-bottom: 10px;
padding: 10px 12px;
border-radius: 12px;
font-size: 0.8rem;
}
.alert-time { font-size: 0.7rem; color: #8b9ad0; margin-bottom: 4px; }
.alert-action { margin-top: 6px; display: flex; gap: 8px; }
.btn-sm {
background: #2d3a60;
border: none;
color: white;
padding: 4px 10px;
border-radius: 20px;
font-size: 0.7rem;
cursor: pointer;
transition: 0.2s;
}
.btn-sm:hover { background: #3f4e7a; }
.btn-primary-sm {
background: #3b82f6;
}
.btn-primary-sm:hover { background: #2563eb; }
/* 驾驶舱图表容器 */
.chart-container {
height: 280px;
width: 100%;
}
.flex-between { display: flex; justify-content: space-between; align-items: center; }
.mt-2 { margin-top: 12px; }
.text-muted { color: #7e8bb6; font-size: 0.7rem; }
/* 响应式 */
@media (max-width: 1200px) {
.grid { grid-template-columns: repeat(2, 1fr); }
.colspan-2 { grid-column: span 1; }
}
@media (max-width: 768px) {
.grid { grid-template-columns: 1fr; }
body { padding: 12px; }
}
footer {
text-align: center;
margin-top: 30px;
font-size: 0.7rem;
color: #4c5a7a;
}
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: #1a1f2e; }
::-webkit-scrollbar-thumb { background: #3b4b6e; border-radius: 4px; }
</style>
</head>
<body>
<div class="dashboard">
<!-- 头部领导驾驶舱氛围 -->
<div class="header">
<div class="title">
<h1><i class="fas fa-chalkboard-user"></i> 智造驾驶舱 · 异常闭环决策中心</h1>
<p>人机料法环实时融合 | 动态预警 | 驱动生产增效</p>
</div>
<div class="badge-group">
<div class="badge"><span class="live-dot"></span> 实时同步</div>
<div class="badge"><i class="fas fa-chart-line"></i> OEE 动态</div>
<div class="badge"><i class="fas fa-bell"></i> 主动预警闭环</div>
</div>
</div>
<!-- 核心KPI + 领导驾驶舱指标 -->
<div class="grid">
<div class="card">
<div class="card-header"><span>📊 综合 OEE</span><i class="fas fa-microchip"></i></div>
<div class="card-body">
<div class="kpi-value" id="oeeValue">78.5%</div>
<div class="kpi-row"><span>↑ 较昨日 +2.3%</span><span class="trend-up"><i class="fas fa-arrow-up"></i> 增效趋势</span></div>
<div class="mt-2 text-muted">性能 × 质量 × 可用率</div>
</div>
</div>
<div class="card">
<div class="card-header"><span>⚠️ 异常中断 TOP1</span><i class="fas fa-stopwatch"></i></div>
<div class="card-body">
<div class="kpi-value" id="topAnomaly">设备过载</div>
<div>累计停线时长: <strong id="downtimeHours">47</strong> min</div>
<div class="trend-down mt-2"><i class="fas fa-clock"></i> 响应平均 4.2min</div>
</div>
</div>
<div class="card">
<div class="card-header"><span>🏭 直通率(FPY)</span><i class="fas fa-check-double"></i></div>
<div class="card-body">
<div class="kpi-value" id="fpyValue">94.2%</div>
<div>目标96% | 湿度关联预警激活</div>
</div>
</div>
<div class="card">
<div class="card-header"><span>📦 在制品堆积</span><i class="fas fa-layer-group"></i></div>
<div class="card-body">
<div class="kpi-value" id="wipValue">342</div>
<div>瓶颈工序: <span id="bottleneck">装配线#3</span> <span class="trend-down">等待物料</span></div>
</div>
</div>
</div>
<!-- 第二行: 人机料法环状态 + 异常预警闭环区 -->
<div class="grid">
<!-- 设备状态 & 环境 -->
<div class="card">
<div class="card-header"><span>⚙️ 设备实时状态 (机)</span><i class="fas fa-industry"></i></div>
<div class="card-body" id="machineStatusContainer">
<!-- 动态渲染设备列表 -->
</div>
</div>
<div class="card">
<div class="card-header"><span>🌡️ 车间物理环境 (环+法)</span><i class="fas fa-temperature-low"></i></div>
<div class="card-body" id="envContainer">
<!-- 环境温湿度、噪音 -->
</div>
<div class="card-body pt-0"><div class="text-muted" style="font-size:12px">* 超标自动触发预警 → 关联质量</div></div>
</div>
<!-- 物料+人员看板 (人/料) -->
<div class="card">
<div class="card-header"><span>🧑🏭 人员状态 & 物料齐套 (人+料)</span><i class="fas fa-people-arrows"></i></div>
<div class="card-body">
<div class="flex-between"><span>👥 产线在岗率</span><span id="laborRate">92%</span></div>
<div class="flex-between mt-2"><span>📦 关键物料 A-001</span><span id="materialStatus" class="warning-text">紧缺预警</span></div>
<div class="flex-between mt-2"><span>🔧 技能匹配度</span><span>86% <i class="fas fa-chart-simple"></i></span></div>
<div class="mt-2 alert-badge" style="background:#f97316;" id="materialAlertMsg">缺料待补: 电机部件</div>
</div>
</div>
<!-- 异常预警滚动+闭环操作 -->
<div class="card">
<div class="card-header"><span>🚨 实时异常预警 (自动驱动闭环)</span><i class="fas fa-bell-ring"></i></div>
<div class="card-body alert-list" id="alertFeed">
<!-- 动态预警卡片 -->
</div>
</div>
</div>
<!-- 深度分析 + 领导驾驶舱图表: 关联不良分析 & OEE趋势 -->
<div class="grid">
<div class="card colspan-2">
<div class="card-header"><span>📈 关联分析 | 温湿度 vs 不良率 (环法对质量影响)</span><i class="fas fa-chart-line"></i></div>
<div class="card-body">
<div id="qualityCorrChart" class="chart-container"></div>
<div class="text-muted mt-2">洞察: 湿度>68%时 装配段不良率上升32% → 自动建议启用除湿</div>
</div>
</div>
<div class="card colspan-2">
<div class="card-header"><span>📉 OEE 趋势 & 瓶颈设备分析 (决策支持)</span><i class="fas fa-chart-simple"></i></div>
<div class="card-body">
<div id="oeeTrendChart" class="chart-container"></div>
<div class="flex-between mt-2"><span>🔻 主要损失: 设备故障(32%) + 换线等待(28%)</span><span class="btn-sm" id="simulateAlertBtn" style="cursor:pointer;">+ 模拟新增异常(测试闭环)</span></div>
</div>
</div>
</div>
<!-- 生产增效闭环说明 -->
<footer>
✅ 异常自动推送 → 可点击"闭环处理" | 数据与生产流程联动 | 领导驾驶舱实时下钻决策
</footer>
</div>
<script>
// ---------- 模拟生产实时数据存储 ----------
let state = {
machines: [
{ id: 'M-01', name: 'CNC 铣床', status: 'running', temp: 52, lastAlert: false },
{ id: 'M-02', name: '注塑机', status: 'down', reason: '刀具磨损', downtime: 12 },
{ id: 'M-03', name: '装配线', status: 'idle', reason: '缺料等待', downtime: 8 },
{ id: 'M-04', name: '检测仪', status: 'running', temp: 45 }
],
env: { temp: 29.3, humidity: 71, noise: 82, pm25: 35 }, // 湿度超标预警触发
material: { partA: '紧缺', partB: '充足', eta: '30分钟' },
labor: { attendance: 92, skillMatch: 86 },
alerts: [
{ id: 'a1', type: '设备故障', desc: '注塑机停机超过5分钟', time: '10:23:15', status: 'active', actionTarget: 'M-02' },
{ id: 'a2', type: '环境超标', desc: '湿度71% 超过阈值(65%),可能影响SMT贴片', time: '10:18:42', status: 'active' },
{ id: 'a3', type: '物料预警', desc: '电机壳体库存低于安全水位', time: '10:05:10', status: 'active' }
],
oee: 78.5,
fpy: 94.2,
wip: 342,
bottleneck: '装配线#3',
downtimeMain: 47,
topAnomalyName: '设备过载'
};
// 辅助函数:更新界面所有动态组件
function updateUI() {
// 更新KPI
document.getElementById('oeeValue').innerText = state.oee + '%';
document.getElementById('topAnomaly').innerText = state.topAnomalyName;
document.getElementById('downtimeHours').innerText = state.downtimeMain;
document.getElementById('fpyValue').innerText = state.fpy + '%';
document.getElementById('wipValue').innerText = state.wip;
document.getElementById('bottleneck').innerText = state.bottleneck;
document.getElementById('laborRate').innerText = state.labor.attendance + '%';
document.getElementById('materialStatus').innerHTML = state.material.partA === '紧缺' ? '<span class="warning-text">紧缺预警</span>' : '充足';
document.getElementById('materialAlertMsg').innerHTML = state.material.partA === '紧缺' ? '缺料待补: 电机部件 · 预计30分钟' : '物料正常';
// 渲染设备列表
const machineContainer = document.getElementById('machineStatusContainer');
machineContainer.innerHTML = state.machines.map(m => {
let statusClass = '', statusText = '';
if (m.status === 'running') { statusClass = 'status-running'; statusText = '运行中'; }
else if (m.status === 'down') { statusClass = 'status-down'; statusText = '故障/停机'; }
else { statusClass = 'status-idle'; statusText = '待料/闲置'; }
return `<div class="machine-item">
<div><i class="fas fa-microchip"></i> ${m.name}</div>
<div><span class="status-badge {statusClass}"\>{statusText}</span> {m.reason ? \`\({m.reason})</span>` : ''}</div>
</div>`;
}).join('');
// 环境渲染
const envContainer = document.getElementById('envContainer');
let humidityWarning = state.env.humidity > 68 ? '<span class="warning-text"><i class="fas fa-exclamation-triangle"></i> 超标(>68%)关联质量不良</span>' : '正常范围';
envContainer.innerHTML = `
<div class="env-item"><span><i class="fas fa-thermometer-half"></i> 温度</span><span>{state.env.temp}°C \<div class="env-item"><span><i class="fas fa-tint"></i> 湿度</span><span>{state.env.humidity}% {humidityWarning}</span></div>
<div class="env-item"><span><i class="fas fa-volume-up"></i> 噪音</span><span>${state.env.noise} dB</span></div>
<div class="env-item"><span><i class="fas fa-dust"></i> 粉尘(PM2.5)</span><span>${state.env.pm25} μg/m³</span></div>
`;
// 预警列表动态 (支持闭环操作)
const alertContainer = document.getElementById('alertFeed');
if (state.alerts.length === 0) {
alertContainer.innerHTML = '<div class="text-muted" style="padding:12px;">✅ 当前无活跃异常,闭环有效</div>';
} else {
alertContainer.innerHTML = state.alerts.map(alert => `
<div class="alert-item" data-id="${alert.id}">
<div class="alert-time"><i class="far fa-clock"></i> {alert.time} · {alert.type}</div>
<div>⚠️ ${alert.desc}</div>
<div class="alert-action">
<button class="btn-sm btn-primary-sm" onclick="closeAlert('${alert.id}')"><i class="fas fa-check-circle"></i> 闭环处理</button>
<button class="btn-sm" onclick="assignTask('${alert.id}')"><i class="fas fa-user-check"></i> 指派责任人</button>
</div>
</div>
`).join('');
}
}
// 闭环处理函数:移除预警并记录增效模拟
window.closeAlert = function(alertId) {
const index = state.alerts.findIndex(a => a.id === alertId);
if (index !== -1) {
const removed = state.alerts[index];
state.alerts.splice(index, 1);
// 模拟处理动作提升OEE
if (removed.type === '设备故障') {
state.oee = Math.min(99, state.oee + 2.5);
state.downtimeMain = Math.max(10, state.downtimeMain - 8);
// 将对应设备状态恢复
const downMachine = state.machines.find(m => m.id === 'M-02');
if (downMachine) { downMachine.status = 'running'; downMachine.reason = null; }
}
if (removed.type === '环境超标') {
state.env.humidity = 63;
state.fpy = Math.min(98, state.fpy + 1.2);
// 添加系统消息
addSystemNotice('环境异常已处理, 湿度恢复63%, 预计直通率提升');
}
if (removed.type === '物料预警') {
state.material.partA = '充足';
state.wip = Math.max(200, state.wip - 45);
state.bottleneck = '装配线#3 (缓解)';
addSystemNotice('物料补货完成, 装配线等待减少, 在制品下降');
}
updateUI();
refreshCharts(); // 刷新图表
}
};
window.assignTask = function(alertId) {
alert(`✅ 已通知班长处理异常[${alertId}],系统将记录响应速度,实现人机法闭环。`);
// 模拟改善响应速度增效展示
addSystemNotice(`异常${alertId}已指派,响应时效<2min, 提效闭环`);
};
function addSystemNotice(msg) {
// 可以控制台或者显示临时小toast,此处简单将提示写入预警区临时?提升体验
const tempDiv = document.createElement('div');
tempDiv.style.position = 'fixed';
tempDiv.style.bottom = '20px';
tempDiv.style.right = '20px';
tempDiv.style.background = '#1f2a48';
tempDiv.style.padding = '8px 16px';
tempDiv.style.borderRadius = '24px';
tempDiv.style.fontSize = '12px';
tempDiv.style.zIndex = 999;
tempDiv.innerText = `🔔 ${msg}`;
document.body.appendChild(tempDiv);
setTimeout(() => tempDiv.remove(), 3000);
}
// 模拟新增异常 (演示预警驱动)
document.getElementById('simulateAlertBtn')?.addEventListener('click', () => {
const newAlert = {
id: 'a' + Date.now(),
type: '突发异常',
desc: '装配线传感器报温度过高, 可能影响焊接质量',
time: new Date().toLocaleTimeString(),
status: 'active'
};
state.alerts.unshift(newAlert);
// 同时模拟环境温度升高
state.env.temp = 32.5;
state.fpy = Math.max(85, state.fpy - 1.5);
updateUI();
refreshCharts();
addSystemNotice('新异常产生 → 请尽快闭环处置, 避免质量损失');
});
// echarts 图表初始化及刷新
let corrChart, trendChart;
function initCharts() {
const corrDom = document.getElementById('qualityCorrChart');
const trendDom = document.getElementById('oeeTrendChart');
if (corrDom) corrChart = echarts.init(corrDom);
if (trendDom) trendChart = echarts.init(trendDom);
refreshCharts();
}
function refreshCharts() {
if (!corrChart) return;
// 关联分析图表 (湿度 vs 不良率模拟)
const humidityLevels = [45, 52, 60, 68, 71, 75];
const defectRates = [2.1, 2.3, 3.0, 5.2, 7.1, 9.4];
const currentHumidity = state.env.humidity;
corrChart.setOption({
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
xAxis: { name: '湿度 (%)', type: 'category', data: humidityLevels },
yAxis: { name: '不良率 (%)', type: 'value' },
series: [{
name: '历史不良率', type: 'line', smooth: true, data: defectRates, lineStyle: { color: '#f97316', width: 3 },
areaStyle: { opacity: 0.2, color: '#f97316' },
markPoint: {
data: currentHumidity > 68 ? [{ coord: [humidityLevels.findIndex(h => h >= currentHumidity), defectRates[humidityLevels.findIndex(h => h >= currentHumidity)]], name: '当前湿度点' }] : []
}
}],
title: { show: false },
backgroundColor: 'transparent',
textStyle: { color: '#ddd' }
});
// OEE趋势 + 瓶颈设备分析
const weeks = ['W1', 'W2', 'W3', '本周'];
const oeeData = [72, 74, 76.2, state.oee];
trendChart.setOption({
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: weeks, name: '周期' },
yAxis: { name: 'OEE %' },
series: [{
name: '整体设备效率', type: 'bar', data: oeeData, itemStyle: { borderRadius: [8,8,0,0], color: '#3b82f6' },
label: { show: true, position: 'top', color: '#cbd5ff' }
}],
grid: { containLabel: true },
textStyle: { color: '#b9c8ff' }
});
}
// 模拟生产数据自动刷新(动态展示真实增效)
let interval;
function startAutoRefresh() {
interval = setInterval(() => {
// 动态小范围波动模拟真实生产,并且基于预警闭环后的增效趋势:如果alert数量少,OEE逐渐上升
if (state.alerts.length === 0 && state.oee < 92) {
state.oee = Math.min(94, state.oee + 0.2);
state.fpy = Math.min(97.5, state.fpy + 0.1);
}
// 模拟环境微变
if (state.alerts.some(a => a.type === '环境超标') === false && state.env.humidity > 65) {
state.env.humidity = Math.max(58, state.env.humidity - 0.5);
}
// 更新设备随机状态优化演示
const downMach = state.machines.find(m => m.status === 'down');
if (!downMach && state.alerts.length === 0) {
// 无事发生,平稳增效
}
updateUI();
refreshCharts();
}, 5000);
}
// 页面加载完成
window.addEventListener('load', () => {
updateUI();
initCharts();
startAutoRefresh();
});
// 清理定时器可选,但demo无需清理
</script>
</body>
</html>