feat(web): show WS connection status indicator in topbar
Green dot + "已连接" when socket is open; red dot + "连接断开,重连中…" on close/error. Reconnect timer (2s) already in place. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b832d98196
commit
b28ac23520
|
|
@ -7,6 +7,9 @@
|
||||||
<div class="topbar-actions">
|
<div class="topbar-actions">
|
||||||
<button type="button" class="secondary" id="clearEquipmentFilter">设备筛选: 全部</button>
|
<button type="button" class="secondary" id="clearEquipmentFilter">设备筛选: 全部</button>
|
||||||
<button type="button" class="secondary" id="openApiDoc">API.md</button>
|
<button type="button" class="secondary" id="openApiDoc">API.md</button>
|
||||||
<div class="status" id="statusText">Ready</div>
|
<div class="status" id="statusText">
|
||||||
|
<span class="ws-dot" id="wsDot"></span>
|
||||||
|
<span id="wsLabel">连接中…</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>PLC Control</title>
|
<title>PLC Control</title>
|
||||||
<link rel="stylesheet" href="/ui/styles.css?v=20260325b" />
|
<link rel="stylesheet" href="/ui/styles.css?v=20260325c" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div data-partial="/ui/html/topbar.html"></div>
|
<div data-partial="/ui/html/topbar.html"></div>
|
||||||
|
|
@ -22,6 +22,6 @@
|
||||||
<div data-partial="/ui/html/modals.html"></div>
|
<div data-partial="/ui/html/modals.html"></div>
|
||||||
<div data-partial="/ui/html/api-doc-drawer.html"></div>
|
<div data-partial="/ui/html/api-doc-drawer.html"></div>
|
||||||
|
|
||||||
<script type="module" src="/ui/js/index.js?v=20260325b"></script>
|
<script type="module" src="/ui/js/index.js?v=20260325c"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ const byId = (id) => document.getElementById(id);
|
||||||
|
|
||||||
export const dom = {
|
export const dom = {
|
||||||
statusText: byId("statusText"),
|
statusText: byId("statusText"),
|
||||||
|
wsDot: byId("wsDot"),
|
||||||
|
wsLabel: byId("wsLabel"),
|
||||||
tabOps: byId("tabOps"),
|
tabOps: byId("tabOps"),
|
||||||
tabConfig: byId("tabConfig"),
|
tabConfig: byId("tabConfig"),
|
||||||
opsUnitList: byId("opsUnitList"),
|
opsUnitList: byId("opsUnitList"),
|
||||||
|
|
|
||||||
|
|
@ -55,11 +55,22 @@ export function stopLogs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWsStatus(connected) {
|
||||||
|
if (dom.wsDot) {
|
||||||
|
dom.wsDot.className = `ws-dot ${connected ? "connected" : "disconnected"}`;
|
||||||
|
}
|
||||||
|
if (dom.wsLabel) {
|
||||||
|
dom.wsLabel.textContent = connected ? "已连接" : "连接断开,重连中…";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function startPointSocket() {
|
export function startPointSocket() {
|
||||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||||
const ws = new WebSocket(`${protocol}://${location.host}/ws/public`);
|
const ws = new WebSocket(`${protocol}://${location.host}/ws/public`);
|
||||||
state.pointSocket = ws;
|
state.pointSocket = ws;
|
||||||
|
|
||||||
|
ws.onopen = () => setWsStatus(true);
|
||||||
|
|
||||||
ws.onmessage = (event) => {
|
ws.onmessage = (event) => {
|
||||||
try {
|
try {
|
||||||
const payload = JSON.parse(event.data);
|
const payload = JSON.parse(event.data);
|
||||||
|
|
@ -110,6 +121,9 @@ export function startPointSocket() {
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
|
setWsStatus(false);
|
||||||
window.setTimeout(startPointSocket, 2000);
|
window.setTimeout(startPointSocket, 2000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ws.onerror = () => setWsStatus(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,20 @@ body {
|
||||||
.status {
|
.status {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: var(--text-3);
|
color: var(--text-3);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
.ws-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--text-3);
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
.ws-dot.connected { background: #22c55e; }
|
||||||
|
.ws-dot.disconnected { background: #ef4444; }
|
||||||
|
|
||||||
.topbar-actions {
|
.topbar-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue