Files
QingAnVue2TV/public/看板画面.html
2026-06-24 14:42:30 +08:00

1543 lines
46 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>产线通讯信号可视化监控看板</title>
<style>
:root {
--bg: #07111d;
--bg-soft: rgba(10, 22, 38, 0.84);
--panel: rgba(10, 24, 42, 0.76);
--panel-strong: rgba(8, 18, 32, 0.9);
--line: rgba(114, 206, 255, 0.22);
--cyan: #6fd4ff;
--cyan-strong: #4bb5ff;
--green: #27d980;
--blue: #31a6ff;
--yellow: #f3c64e;
--red: #ff5d6c;
--text: #e8f3ff;
--text-soft: #8ca8c8;
--shadow: 0 16px 48px rgba(0, 0, 0, 0.35);
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
min-height: 100%;
background:
radial-gradient(circle at top left, rgba(39, 117, 203, 0.18), transparent 28%),
radial-gradient(circle at top right, rgba(0, 195, 255, 0.1), transparent 24%),
linear-gradient(180deg, #06101a 0%, #07111d 45%, #081523 100%);
color: var(--text);
font-family: "Microsoft YaHei", "PingFang SC", "Segoe UI", sans-serif;
}
body {
padding: 14px;
}
.dashboard {
min-height: calc(100vh - 28px);
display: grid;
grid-template-rows: 86px minmax(0, 1fr) 272px;
gap: 14px;
}
.panel {
border: 1px solid var(--line);
background: var(--panel);
box-shadow: var(--shadow);
backdrop-filter: blur(10px);
border-radius: 8px;
overflow: hidden;
}
.topbar {
display: grid;
grid-template-columns: 360px 1fr 560px;
align-items: stretch;
gap: 14px;
}
.title-block {
padding: 16px 20px;
display: flex;
flex-direction: column;
justify-content: center;
background:
linear-gradient(90deg, rgba(38, 102, 173, 0.28), rgba(10, 24, 42, 0.2)),
var(--panel-strong);
}
.eyebrow {
color: var(--cyan);
font-size: 12px;
letter-spacing: 1px;
text-transform: uppercase;
margin-bottom: 6px;
}
h1 {
margin: 0;
font-size: 28px;
line-height: 1.1;
font-weight: 700;
}
.subtitle {
margin-top: 8px;
color: var(--text-soft);
font-size: 13px;
}
.top-center {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
padding: 12px;
}
.kpi {
padding: 14px 16px;
border: 1px solid rgba(114, 206, 255, 0.16);
background: linear-gradient(180deg, rgba(14, 30, 50, 0.92), rgba(8, 20, 34, 0.8));
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: center;
gap: 6px;
}
.kpi-label {
color: var(--text-soft);
font-size: 12px;
}
.kpi-value {
display: flex;
align-items: baseline;
gap: 8px;
font-size: 30px;
font-weight: 700;
}
.kpi-meta {
color: var(--text-soft);
font-size: 12px;
}
.status-board {
padding: 12px;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
align-content: center;
}
.mini-stat {
border-radius: 8px;
padding: 12px 14px;
background: linear-gradient(180deg, rgba(12, 28, 48, 0.94), rgba(8, 18, 32, 0.84));
border: 1px solid rgba(114, 206, 255, 0.15);
}
.mini-stat .label {
font-size: 12px;
color: var(--text-soft);
margin-bottom: 6px;
}
.mini-stat .value {
font-size: 22px;
font-weight: 700;
}
.main {
display: grid;
grid-template-columns: 360px minmax(0, 1fr) 380px;
gap: 14px;
min-height: 0;
}
.column {
min-height: 0;
display: grid;
gap: 14px;
}
.column.left {
grid-template-rows: 268px 1fr 230px;
}
.column.right {
grid-template-rows: 360px 1fr;
}
.section {
display: flex;
flex-direction: column;
min-height: 0;
}
.section-header {
height: 44px;
padding: 0 16px;
border-bottom: 1px solid rgba(114, 206, 255, 0.12);
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(8, 18, 32, 0.44);
}
.section-title {
font-size: 15px;
font-weight: 700;
}
.section-note {
color: var(--text-soft);
font-size: 12px;
}
.section-body {
flex: 1;
min-height: 0;
padding: 14px;
}
.unit-list {
display: grid;
gap: 10px;
}
.unit-card {
border: 1px solid rgba(114, 206, 255, 0.14);
border-radius: 8px;
padding: 12px;
background: rgba(8, 18, 32, 0.58);
}
.unit-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.unit-name {
font-size: 15px;
font-weight: 700;
}
.unit-status {
font-size: 12px;
padding: 4px 8px;
border-radius: 999px;
background: rgba(39, 217, 128, 0.18);
color: #8effc2;
}
.unit-status.warn {
background: rgba(243, 198, 78, 0.18);
color: #ffe08b;
}
.unit-status.alarm {
background: rgba(255, 93, 108, 0.18);
color: #ff98a3;
}
.signal-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.signal {
display: flex;
align-items: center;
gap: 8px;
color: var(--text-soft);
font-size: 12px;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.04);
flex: 0 0 auto;
}
.dot.green { background: var(--green); }
.dot.blue { background: var(--blue); }
.dot.yellow { background: var(--yellow); }
.dot.red { background: var(--red); }
.dot.gray { background: #54667d; }
.task-grid {
display: grid;
gap: 12px;
}
.task-card {
padding: 14px;
border-radius: 8px;
border: 1px solid rgba(114, 206, 255, 0.14);
background: linear-gradient(180deg, rgba(11, 24, 42, 0.9), rgba(8, 18, 32, 0.75));
}
.task-head,
.task-foot,
.flow-head {
display: flex;
justify-content: space-between;
gap: 8px;
align-items: center;
}
.task-id {
font-size: 18px;
font-weight: 700;
}
.badge {
padding: 4px 8px;
border-radius: 999px;
font-size: 12px;
background: rgba(49, 166, 255, 0.18);
color: #8cccff;
}
.task-route {
margin: 14px 0 10px;
padding: 12px;
border-radius: 8px;
background: rgba(7, 18, 31, 0.72);
border: 1px solid rgba(114, 206, 255, 0.12);
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.route-node {
flex: 1;
text-align: center;
}
.route-label {
font-size: 11px;
color: var(--text-soft);
margin-bottom: 4px;
}
.route-value {
font-size: 22px;
font-weight: 700;
}
.route-arrow {
color: var(--cyan);
font-size: 26px;
flex: 0 0 auto;
}
.task-meta {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
margin-top: 10px;
}
.meta-card {
padding: 10px;
border-radius: 8px;
background: rgba(255, 255, 255, 0.03);
}
.meta-label {
font-size: 11px;
color: var(--text-soft);
margin-bottom: 6px;
}
.meta-value {
font-size: 14px;
font-weight: 700;
}
.flow-grid {
display: grid;
gap: 12px;
}
.flow-card {
padding: 12px;
border-radius: 8px;
border: 1px solid rgba(114, 206, 255, 0.14);
background: rgba(8, 18, 32, 0.65);
}
.flow-title {
font-weight: 700;
}
.steps {
margin-top: 12px;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
align-items: center;
}
.step {
position: relative;
text-align: center;
padding-top: 22px;
color: var(--text-soft);
font-size: 11px;
}
.step::before {
content: "";
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 12px;
height: 12px;
border-radius: 50%;
background: #54667d;
box-shadow: 0 0 0 4px rgba(255,255,255,0.03);
}
.step.active::before {
background: var(--blue);
box-shadow: 0 0 12px rgba(49, 166, 255, 0.55);
}
.step.done::before {
background: var(--green);
box-shadow: 0 0 12px rgba(39, 217, 128, 0.45);
}
.step.error::before {
background: var(--red);
box-shadow: 0 0 12px rgba(255, 93, 108, 0.45);
}
.model-panel {
position: relative;
min-height: 0;
overflow: hidden;
background:
radial-gradient(ellipse at center, rgba(17, 110, 180, 0.08), transparent 50%),
linear-gradient(180deg, rgba(6, 14, 25, 0.08), rgba(8, 18, 32, 0.22));
}
.model-stage {
position: absolute;
inset: 0;
overflow: hidden;
}
.model-frame {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
border: 0;
opacity: 0.92;
filter: saturate(0.75) contrast(1.05) brightness(0.8);
}
.model-overlay {
position: absolute;
inset: 0;
background:
radial-gradient(circle at center, rgba(17, 110, 180, 0.12), transparent 44%),
linear-gradient(180deg, rgba(4, 12, 22, 0.1), rgba(5, 10, 18, 0.4));
pointer-events: none;
}
.model-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(111, 212, 255, 0.08) 1px, transparent 1px),
linear-gradient(90deg, rgba(111, 212, 255, 0.08) 1px, transparent 1px);
background-size: 72px 72px;
mask-image: linear-gradient(180deg, transparent 0%, rgba(0,0,0,0.75) 18%, rgba(0,0,0,0.75) 82%, transparent 100%);
opacity: 0.32;
}
.hud-top {
position: absolute;
top: 18px;
left: 18px;
right: 18px;
display: flex;
justify-content: space-between;
gap: 16px;
pointer-events: none;
}
.hud-card {
min-width: 220px;
max-width: 32%;
border-radius: 8px;
border: 1px solid rgba(114, 206, 255, 0.22);
background: rgba(8, 18, 32, 0.42);
padding: 12px 14px;
backdrop-filter: blur(6px);
}
.hud-card h3 {
margin: 0 0 10px;
font-size: 13px;
color: var(--cyan);
}
.hud-row {
display: flex;
justify-content: space-between;
gap: 12px;
font-size: 12px;
color: var(--text-soft);
margin-top: 6px;
}
.hud-row strong {
color: var(--text);
font-size: 14px;
}
.device-tag {
position: absolute;
padding: 8px 10px;
border-radius: 8px;
border: 1px solid rgba(114, 206, 255, 0.18);
background: rgba(8, 18, 32, 0.42);
backdrop-filter: blur(6px);
min-width: 116px;
pointer-events: none;
}
.device-tag.alert {
border-color: rgba(255, 93, 108, 0.52);
box-shadow: 0 0 18px rgba(255, 93, 108, 0.16);
}
.device-name {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
font-weight: 700;
margin-bottom: 6px;
}
.device-meta {
font-size: 11px;
color: var(--text-soft);
line-height: 1.45;
}
.path-line {
position: absolute;
left: 14%;
right: 16%;
bottom: 24%;
height: 2px;
background: linear-gradient(90deg, rgba(111, 212, 255, 0), rgba(111, 212, 255, 0.85), rgba(111, 212, 255, 0));
box-shadow: 0 0 14px rgba(111, 212, 255, 0.3);
}
.path-line::before,
.path-line::after {
content: "";
position: absolute;
top: 50%;
width: 12px;
height: 12px;
margin-top: -6px;
border-radius: 50%;
background: var(--cyan);
box-shadow: 0 0 18px rgba(111, 212, 255, 0.55);
}
.path-line::before { left: 0; }
.path-line::after { right: 0; }
.path-flow {
position: absolute;
top: -4px;
left: 22%;
width: 10px;
height: 10px;
border-radius: 50%;
background: #89ddff;
box-shadow: 0 0 18px rgba(111, 212, 255, 0.85);
animation: travel 3.8s linear infinite;
}
@keyframes travel {
from { left: 0; }
to { left: calc(100% - 10px); }
}
.stage-caption {
position: absolute;
left: 18px;
bottom: 18px;
padding: 12px 14px;
border-radius: 8px;
background: rgba(8, 18, 32, 0.48);
border: 1px solid rgba(114, 206, 255, 0.18);
backdrop-filter: blur(6px);
max-width: 360px;
}
.stage-caption strong {
display: block;
margin-bottom: 6px;
font-size: 14px;
}
.stage-caption p {
margin: 0;
color: var(--text-soft);
font-size: 12px;
line-height: 1.55;
}
.equipment-table,
.assist-grid,
.bottom-grid {
display: grid;
gap: 10px;
}
.equipment-row {
display: grid;
grid-template-columns: 116px 88px 88px 1fr 62px;
gap: 10px;
align-items: center;
border: 1px solid rgba(114, 206, 255, 0.12);
border-radius: 8px;
padding: 10px 12px;
background: rgba(8, 18, 32, 0.58);
font-size: 12px;
}
.equipment-row.alarm {
border-color: rgba(255, 93, 108, 0.35);
background: rgba(52, 10, 18, 0.5);
}
.equip-name {
font-weight: 700;
font-size: 13px;
}
.equip-col .label {
color: var(--text-soft);
font-size: 11px;
margin-bottom: 4px;
}
.equip-col .value {
font-weight: 700;
white-space: nowrap;
}
.status-strip {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.status-pill {
padding: 4px 8px;
border-radius: 999px;
font-size: 11px;
background: rgba(255,255,255,0.05);
color: var(--text-soft);
}
.status-pill.on {
color: #9be7ff;
background: rgba(49, 166, 255, 0.18);
}
.status-pill.ok {
color: #8effc2;
background: rgba(39, 217, 128, 0.18);
}
.status-pill.warn {
color: #ffe08b;
background: rgba(243, 198, 78, 0.18);
}
.status-pill.alarm {
color: #ff98a3;
background: rgba(255, 93, 108, 0.18);
}
.assist-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.assist-card {
padding: 12px;
border-radius: 8px;
border: 1px solid rgba(114, 206, 255, 0.12);
background: rgba(8, 18, 32, 0.58);
}
.assist-title {
display: flex;
justify-content: space-between;
gap: 8px;
align-items: center;
font-weight: 700;
margin-bottom: 10px;
}
.mini-flow {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.bottom {
display: grid;
grid-template-columns: 1.2fr 1fr 1fr;
gap: 14px;
min-height: 0;
}
.storage-groups {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
}
.storage-card {
border-radius: 8px;
border: 1px solid rgba(114, 206, 255, 0.12);
background: rgba(8, 18, 32, 0.58);
padding: 12px;
}
.storage-head {
display: flex;
justify-content: space-between;
gap: 8px;
align-items: center;
margin-bottom: 10px;
}
.storage-head strong {
font-size: 14px;
}
.storage-head span {
color: var(--text-soft);
font-size: 12px;
}
.slots {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
}
.slot {
aspect-ratio: 1;
border-radius: 6px;
border: 1px solid rgba(114, 206, 255, 0.14);
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: var(--text-soft);
background: rgba(255, 255, 255, 0.03);
}
.slot.filled {
color: #d8f5ff;
background: linear-gradient(180deg, rgba(49, 166, 255, 0.26), rgba(39, 217, 128, 0.2));
box-shadow: inset 0 0 0 1px rgba(126, 233, 255, 0.2);
}
.table-list {
display: grid;
gap: 8px;
max-height: 100%;
overflow: auto;
padding-right: 2px;
}
.event-row,
.log-row {
display: grid;
gap: 10px;
border-radius: 8px;
padding: 10px 12px;
border: 1px solid rgba(114, 206, 255, 0.12);
background: rgba(8, 18, 32, 0.58);
font-size: 12px;
}
.event-row {
grid-template-columns: 66px 76px 82px 62px 1fr;
align-items: center;
}
.event-level {
font-size: 11px;
padding: 4px 8px;
border-radius: 999px;
text-align: center;
}
.event-level.critical {
color: #ff98a3;
background: rgba(255, 93, 108, 0.18);
}
.event-level.warn {
color: #ffe08b;
background: rgba(243, 198, 78, 0.18);
}
.log-row {
grid-template-columns: 66px 1fr;
align-items: start;
}
.muted {
color: var(--text-soft);
}
.scroll {
overflow: auto;
}
@media (max-width: 1600px) {
.main {
grid-template-columns: 320px minmax(0, 1fr) 340px;
}
.topbar {
grid-template-columns: 320px 1fr 500px;
}
}
</style>
</head>
<body>
<div class="dashboard">
<div class="topbar">
<section class="panel title-block">
<div class="eyebrow">Industrial signal board</div>
<h1>产线通讯信号可视化监控看板</h1>
<div class="subtitle">长地轨 / 短地轨 / 关节机器人 / 加工设备 / 物料库联动监控</div>
</section>
<section class="panel top-center">
<div class="kpi">
<div class="kpi-label">在线单元</div>
<div class="kpi-value">3 <span class="muted">/ 3</span></div>
<div class="kpi-meta">PCS 运行信号全部在线</div>
</div>
<div class="kpi">
<div class="kpi-label">自动模式</div>
<div class="kpi-value">2 <span class="muted">单元</span></div>
<div class="kpi-meta">关节单元等待人工复位</div>
</div>
<div class="kpi">
<div class="kpi-label">允许接收任务</div>
<div class="kpi-value">3 <span class="muted">单元</span></div>
<div class="kpi-meta">当前可派发搬运任务</div>
</div>
<div class="kpi">
<div class="kpi-label">执行中任务</div>
<div class="kpi-value">2 <span class="muted"></span></div>
<div class="kpi-meta">短地轨与关节单元忙碌</div>
</div>
<div class="kpi">
<div class="kpi-label">当前报警</div>
<div class="kpi-value">3 <span class="muted"></span></div>
<div class="kpi-meta">含设备报警和测量错误</div>
</div>
<div class="kpi">
<div class="kpi-label">库位占用率</div>
<div class="kpi-value">67% <span class="muted">16 / 24</span></div>
<div class="kpi-meta">可用于节拍与供料判断</div>
</div>
</section>
<section class="panel status-board">
<div class="mini-stat">
<div class="label">通讯状态</div>
<div class="value">稳定</div>
</div>
<div class="mini-stat">
<div class="label">最近刷新</div>
<div class="value" id="clock">2026-06-24 10:31:25</div>
</div>
<div class="mini-stat">
<div class="label">任务节拍</div>
<div class="value">92s</div>
</div>
<div class="mini-stat">
<div class="label">程序一致性</div>
<div class="value">5 / 6</div>
</div>
</section>
</div>
<div class="main">
<div class="column left">
<section class="panel section">
<div class="section-header">
<div class="section-title">线体状态总览</div>
<div class="section-note">PCS / AUTO / ALLOW / EMG</div>
</div>
<div class="section-body scroll">
<div class="unit-list">
<div class="unit-card">
<div class="unit-top">
<div class="unit-name">长地轨</div>
<div class="unit-status">可派发任务</div>
</div>
<div class="signal-grid">
<div class="signal"><span class="dot green"></span>PCS 运行</div>
<div class="signal"><span class="dot green"></span>允许接收任务</div>
<div class="signal"><span class="dot green"></span>自动模式</div>
<div class="signal"><span class="dot gray"></span>急停未触发</div>
</div>
</div>
<div class="unit-card">
<div class="unit-top">
<div class="unit-name">短地轨</div>
<div class="unit-status">可派发任务</div>
</div>
<div class="signal-grid">
<div class="signal"><span class="dot green"></span>PCS 运行</div>
<div class="signal"><span class="dot green"></span>允许接收任务</div>
<div class="signal"><span class="dot green"></span>自动模式</div>
<div class="signal"><span class="dot gray"></span>急停未触发</div>
</div>
</div>
<div class="unit-card">
<div class="unit-top">
<div class="unit-name">关节</div>
<div class="unit-status warn">人工确认中</div>
</div>
<div class="signal-grid">
<div class="signal"><span class="dot green"></span>PCS 运行</div>
<div class="signal"><span class="dot green"></span>允许接收任务</div>
<div class="signal"><span class="dot yellow"></span>自动待恢复</div>
<div class="signal"><span class="dot gray"></span>急停未触发</div>
</div>
</div>
</div>
</div>
</section>
<section class="panel section">
<div class="section-header">
<div class="section-title">机器人任务监控</div>
<div class="section-note">TASK / START / END / RECIPE</div>
</div>
<div class="section-body scroll">
<div class="task-grid">
<div class="task-card">
<div class="task-head">
<div>
<div class="muted">长地轨</div>
<div class="task-id">#1024</div>
</div>
<div class="badge">执行中</div>
</div>
<div class="task-route">
<div class="route-node">
<div class="route-label">起始位置</div>
<div class="route-value">01</div>
</div>
<div class="route-arrow"></div>
<div class="route-node">
<div class="route-label">结束位置</div>
<div class="route-value">06</div>
</div>
</div>
<div class="task-meta">
<div class="meta-card">
<div class="meta-label">配方号</div>
<div class="meta-value">RCP-01</div>
</div>
<div class="meta-card">
<div class="meta-label">托盘类型</div>
<div class="meta-value">Pallet-A</div>
</div>
<div class="meta-card">
<div class="meta-label">零件类型</div>
<div class="meta-value">-</div>
</div>
</div>
</div>
<div class="task-card">
<div class="task-head">
<div>
<div class="muted">短地轨</div>
<div class="task-id">#2048</div>
</div>
<div class="badge">准备就绪</div>
</div>
<div class="task-route">
<div class="route-node">
<div class="route-label">起始位置</div>
<div class="route-value">03</div>
</div>
<div class="route-arrow"></div>
<div class="route-node">
<div class="route-label">结束位置</div>
<div class="route-value">09</div>
</div>
</div>
<div class="task-meta">
<div class="meta-card">
<div class="meta-label">配方号</div>
<div class="meta-value">RCP-09</div>
</div>
<div class="meta-card">
<div class="meta-label">托盘类型</div>
<div class="meta-value">Pallet-C</div>
</div>
<div class="meta-card">
<div class="meta-label">零件类型</div>
<div class="meta-value">短轴</div>
</div>
</div>
</div>
<div class="task-card">
<div class="task-head">
<div>
<div class="muted">关节</div>
<div class="task-id">#3086</div>
</div>
<div class="badge" style="background: rgba(255, 93, 108, 0.18); color: #ff98a3;">异常中断</div>
</div>
<div class="task-route">
<div class="route-node">
<div class="route-label">起始位置</div>
<div class="route-value">02</div>
</div>
<div class="route-arrow"></div>
<div class="route-node">
<div class="route-label">结束位置</div>
<div class="route-value">04</div>
</div>
</div>
<div class="task-meta">
<div class="meta-card">
<div class="meta-label">配方号</div>
<div class="meta-value">RCP-11</div>
</div>
<div class="meta-card">
<div class="meta-label">托盘类型</div>
<div class="meta-value">Pallet-B</div>
</div>
<div class="meta-card">
<div class="meta-label">零件类型</div>
<div class="meta-value">长轴</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="panel section">
<div class="section-header">
<div class="section-title">机器人反馈流程</div>
<div class="section-note">FLAG → READY → BUSY → COMPLETE</div>
</div>
<div class="section-body scroll">
<div class="flow-grid">
<div class="flow-card">
<div class="flow-head">
<div class="flow-title">长地轨</div>
<div class="badge">BUSY</div>
</div>
<div class="steps">
<div class="step done">FLAG</div>
<div class="step done">READY</div>
<div class="step active">BUSY</div>
<div class="step">COMPLETE</div>
</div>
</div>
<div class="flow-card">
<div class="flow-head">
<div class="flow-title">短地轨</div>
<div class="badge">READY</div>
</div>
<div class="steps">
<div class="step done">FLAG</div>
<div class="step active">READY</div>
<div class="step">BUSY</div>
<div class="step">COMPLETE</div>
</div>
</div>
<div class="flow-card">
<div class="flow-head">
<div class="flow-title">关节</div>
<div class="badge" style="background: rgba(255, 93, 108, 0.18); color: #ff98a3;">ERROR</div>
</div>
<div class="steps">
<div class="step done">FLAG</div>
<div class="step done">READY</div>
<div class="step error">BUSY</div>
<div class="step">COMPLETE</div>
</div>
</div>
</div>
</div>
</section>
</div>
<section class="panel model-panel">
<div class="model-stage">
<iframe class="model-frame" src="https://www.baidu.com" title="三维模型占位"></iframe>
<div class="model-overlay"></div>
<div class="model-grid"></div>
<div class="hud-top">
<div class="hud-card">
<h3>搬运路径</h3>
<div class="hud-row"><span>当前任务</span><strong>#1024</strong></div>
<div class="hud-row"><span>路径</span><strong>长地轨 01 → 06</strong></div>
<div class="hud-row"><span>状态</span><strong>执行中</strong></div>
</div>
<div class="hud-card">
<h3>模型叠加说明</h3>
<div class="hud-row"><span>iframe</span><strong>百度占位</strong></div>
<div class="hud-row"><span>图表层</span><strong>半透明 HUD</strong></div>
<div class="hud-row"><span>交互</span><strong>可替换真实三维模型</strong></div>
</div>
<div class="hud-card">
<h3>模型区域联动</h3>
<div class="hud-row"><span>高亮单元</span><strong>关节 / 短地轨</strong></div>
<div class="hud-row"><span>报警设备</span><strong>MAZAK / 测量仪</strong></div>
<div class="hud-row"><span>库位同步</span><strong>长地轨 S4 / S7</strong></div>
</div>
</div>
<div class="device-tag" style="left: 8%; top: 26%;">
<div class="device-name"><span class="dot green"></span>长地轨</div>
<div class="device-meta">PCS 运行<br>任务 #1024</div>
</div>
<div class="device-tag" style="left: 28%; top: 18%;">
<div class="device-name"><span class="dot blue"></span>F500</div>
<div class="device-meta">程序 1202 / 1202<br>自动运行中</div>
</div>
<div class="device-tag" style="left: 44%; top: 23%;">
<div class="device-name"><span class="dot green"></span>L2000LSY</div>
<div class="device-meta">上料完成<br>下料完成</div>
</div>
<div class="device-tag" style="left: 62%; top: 19%;">
<div class="device-name"><span class="dot yellow"></span>L2100SY</div>
<div class="device-meta">程序待同步<br>D:3301 A:3298</div>
</div>
<div class="device-tag" style="left: 18%; top: 58%;">
<div class="device-name"><span class="dot green"></span>短地轨</div>
<div class="device-meta">允许接收任务<br>任务 #2048</div>
</div>
<div class="device-tag alert" style="left: 52%; top: 54%;">
<div class="device-name"><span class="dot red"></span>MAZAK</div>
<div class="device-meta">自动运行中<br>报警触发</div>
</div>
<div class="device-tag" style="left: 72%; top: 62%;">
<div class="device-name"><span class="dot blue"></span>YKD5132H</div>
<div class="device-meta">上料就绪<br>下料就绪</div>
</div>
<div class="device-tag alert" style="left: 78%; top: 34%;">
<div class="device-name"><span class="dot red"></span>测量仪</div>
<div class="device-meta">运行异常<br>等待复测</div>
</div>
<div class="path-line">
<div class="path-flow"></div>
</div>
<div class="stage-caption">
<strong>中央三维模型区</strong>
<p>当前使用百度页面作为 iframe 占位。后续替换真实三维模型地址后,可保留上方透明状态层,继续叠加设备标签、任务路径和报警定位。</p>
</div>
</div>
</section>
<div class="column right">
<section class="panel section">
<div class="section-header">
<div class="section-title">加工设备状态</div>
<div class="section-note">程序号 / 上下料 / 运行 / 报警</div>
</div>
<div class="section-body scroll">
<div class="equipment-table">
<div class="equipment-row">
<div class="equip-name">F500</div>
<div class="equip-col">
<div class="label">目标</div>
<div class="value">1202</div>
</div>
<div class="equip-col">
<div class="label">实际</div>
<div class="value">1202</div>
</div>
<div class="status-strip">
<span class="status-pill ok">上料完成</span>
<span class="status-pill ok">下料完成</span>
<span class="status-pill on">运行中</span>
</div>
<div class="status-pill ok">正常</div>
</div>
<div class="equipment-row">
<div class="equip-name">L2000LSY</div>
<div class="equip-col">
<div class="label">目标</div>
<div class="value">2206</div>
</div>
<div class="equip-col">
<div class="label">实际</div>
<div class="value">2206</div>
</div>
<div class="status-strip">
<span class="status-pill ok">上料完成</span>
<span class="status-pill ok">下料完成</span>
<span class="status-pill">待命</span>
</div>
<div class="status-pill ok">正常</div>
</div>
<div class="equipment-row">
<div class="equip-name">L2100SY</div>
<div class="equip-col">
<div class="label">目标</div>
<div class="value">3301</div>
</div>
<div class="equip-col">
<div class="label">实际</div>
<div class="value">3298</div>
</div>
<div class="status-strip">
<span class="status-pill warn">程序待同步</span>
<span class="status-pill on">运行中</span>
</div>
<div class="status-pill warn">预警</div>
</div>
<div class="equipment-row">
<div class="equip-name">新日</div>
<div class="equip-col">
<div class="label">目标</div>
<div class="value">4108</div>
</div>
<div class="equip-col">
<div class="label">实际</div>
<div class="value">4108</div>
</div>
<div class="status-strip">
<span class="status-pill ok">上料就绪</span>
<span class="status-pill">下料等待</span>
<span class="status-pill on">运行中</span>
</div>
<div class="status-pill ok">正常</div>
</div>
<div class="equipment-row alarm">
<div class="equip-name">MAZAK</div>
<div class="equip-col">
<div class="label">目标</div>
<div class="value">-</div>
</div>
<div class="equip-col">
<div class="label">实际</div>
<div class="value">-</div>
</div>
<div class="status-strip">
<span class="status-pill ok">上料就绪</span>
<span class="status-pill on">运行中</span>
<span class="status-pill alarm">报警</span>
</div>
<div class="status-pill alarm">异常</div>
</div>
<div class="equipment-row">
<div class="equip-name">YKD5132H</div>
<div class="equip-col">
<div class="label">目标</div>
<div class="value">5104</div>
</div>
<div class="equip-col">
<div class="label">实际</div>
<div class="value">5104</div>
</div>
<div class="status-strip">
<span class="status-pill ok">上料就绪</span>
<span class="status-pill ok">下料就绪</span>
<span class="status-pill">待命</span>
</div>
<div class="status-pill ok">正常</div>
</div>
</div>
</div>
</section>
<section class="panel section">
<div class="section-header">
<div class="section-title">辅助设备状态</div>
<div class="section-note">打标机 / 清洗机 / 测量仪</div>
</div>
<div class="section-body scroll">
<div class="assist-grid">
<div class="assist-card">
<div class="assist-title">
<span>长地轨打标机</span>
<span class="status-pill ok">待机中</span>
</div>
<div class="mini-flow">
<span class="status-pill ok">开机中</span>
<span class="status-pill">未触发 START</span>
<span class="status-pill">BUSY=0</span>
</div>
</div>
<div class="assist-card">
<div class="assist-title">
<span>短地轨打标机</span>
<span class="status-pill on">打标完成保持</span>
</div>
<div class="mini-flow">
<span class="status-pill ok">开机中</span>
<span class="status-pill warn">脉冲 START 已触发</span>
<span class="status-pill on">BUSY 保持 1</span>
</div>
</div>
<div class="assist-card">
<div class="assist-title">
<span>关节打标机</span>
<span class="status-pill">待命</span>
</div>
<div class="mini-flow">
<span class="status-pill ok">开机中</span>
<span class="status-pill">等待任务</span>
<span class="status-pill">IDLE=1</span>
</div>
</div>
<div class="assist-card">
<div class="assist-title">
<span>清洗机</span>
<span class="status-pill on">运行中</span>
</div>
<div class="mini-flow">
<span class="status-pill ok">上料就绪</span>
<span class="status-pill on">BUSY=1</span>
<span class="status-pill">等待下料</span>
</div>
</div>
<div class="assist-card">
<div class="assist-title">
<span>测量仪</span>
<span class="status-pill alarm">错误</span>
</div>
<div class="mini-flow">
<span class="status-pill warn">复测等待</span>
<span class="status-pill alarm">ERROR=1</span>
<span class="status-pill">下料未就绪</span>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<div class="bottom">
<section class="panel section">
<div class="section-header">
<div class="section-title">物料库位矩阵</div>
<div class="section-note">总库位 24 / 当前有件 16</div>
</div>
<div class="section-body">
<div class="storage-groups">
<div class="storage-card">
<div class="storage-head">
<strong>长地轨</strong>
<span>6 / 9</span>
</div>
<div class="slots">
<div class="slot filled">S1</div>
<div class="slot filled">S2</div>
<div class="slot">S3</div>
<div class="slot filled">S4</div>
<div class="slot">S5</div>
<div class="slot filled">S6</div>
<div class="slot filled">S7</div>
<div class="slot">S8</div>
<div class="slot filled">S9</div>
</div>
</div>
<div class="storage-card">
<div class="storage-head">
<strong>短地轨</strong>
<span>6 / 9</span>
</div>
<div class="slots">
<div class="slot filled">S1</div>
<div class="slot">S2</div>
<div class="slot filled">S3</div>
<div class="slot filled">S4</div>
<div class="slot">S5</div>
<div class="slot filled">S6</div>
<div class="slot">S7</div>
<div class="slot filled">S8</div>
<div class="slot filled">S9</div>
</div>
</div>
<div class="storage-card">
<div class="storage-head">
<strong>关节</strong>
<span>4 / 6</span>
</div>
<div class="slots">
<div class="slot filled">S1</div>
<div class="slot">S2</div>
<div class="slot filled">S3</div>
<div class="slot">S4</div>
<div class="slot filled">S5</div>
<div class="slot filled">S6</div>
</div>
</div>
</div>
</div>
</section>
<section class="panel section">
<div class="section-header">
<div class="section-title">报警与异常事件</div>
<div class="section-note">EMG / ERROR / ALARM / 程序不一致</div>
</div>
<div class="section-body">
<div class="table-list">
<div class="event-row">
<div>10:31:04</div>
<div>短地轨</div>
<div>MAZAK</div>
<div class="event-level critical">严重</div>
<div>设备报警触发ALARM=1建议定位机床侧运行条件。</div>
</div>
<div class="event-row">
<div>10:30:57</div>
<div>关节</div>
<div>测量仪</div>
<div class="event-level critical">严重</div>
<div>测量仪 ERROR=1任务 #3086 中断,等待复测确认。</div>
</div>
<div class="event-row">
<div>10:30:32</div>
<div>长地轨</div>
<div>L2100SY</div>
<div class="event-level warn">警告</div>
<div>目标程序号 3301 与实际程序号 3298 不一致。</div>
</div>
<div class="event-row">
<div>10:29:48</div>
<div>关节</div>
<div>自动模式</div>
<div class="event-level warn">警告</div>
<div>AUTO_ACTIVE 从 1 变为 0当前处于人工确认中。</div>
</div>
</div>
</div>
</section>
<section class="panel section">
<div class="section-header">
<div class="section-title">任务日志</div>
<div class="section-note">创建 / 启动 / 执行 / 完成 / 异常</div>
</div>
<div class="section-body">
<div class="table-list">
<div class="log-row">
<div>10:31:08</div>
<div>长地轨 任务 #1024 起点 01 → 终点 06配方 RCP-01机器人保持 BUSY。</div>
</div>
<div class="log-row">
<div>10:30:54</div>
<div>短地轨 任务 #2048 已下发READY=1等待进入 BUSY。</div>
</div>
<div class="log-row">
<div>10:30:35</div>
<div>关节 任务 #3086 在测量仪工位异常中断ERROR=1。</div>
</div>
<div class="log-row">
<div>10:29:40</div>
<div>长地轨 F500 上料完成L2000LSY 下料完成,任务链路可继续派发。</div>
</div>
<div class="log-row">
<div>10:28:52</div>
<div>短地轨打标机 START 脉冲触发BUSY 保持,等待后续清零。</div>
</div>
</div>
</div>
</section>
</div>
</div>
<script>
function updateClock() {
const now = new Date();
const pad = (value) => String(value).padStart(2, "0");
const text = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
const clock = document.getElementById("clock");
if (clock) {
clock.textContent = text;
}
}
updateClock();
setInterval(updateClock, 1000);
</script>
</body>
</html>