Add SSE second-level dashboard stream and 2s client heartbeat.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-17 21:04:55 +08:00
parent ba74a9cce8
commit d860156b11
8 changed files with 114 additions and 62 deletions
+35 -16
View File
@@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block title %}总览 · {{ app_name }}{% endblock %}
{% block content %}
<h2 style="margin:0 0 14px">总览</h2>
<h2 style="margin:0 0 14px">总览 <span class="muted" style="font-size:13px;font-weight:400" id="live-hint">· 秒级推送</span></h2>
<div class="grid cols-3">
<div class="card"><div class="muted">账户</div><div class="stat">{{ accounts|length }}</div></div>
<div class="card">
@@ -13,7 +13,7 @@
<div class="grid cols-2" style="margin-top:14px">
<div class="card">
<h3>在线机器 <span class="muted" style="font-weight:400;font-size:12px">· 约 5 秒刷新</span></h3>
<h3>在线机器</h3>
<table>
<thead><tr><th>机器</th><th>状态</th><th>最近心跳</th></tr></thead>
<tbody id="online-machines-body">
@@ -24,7 +24,7 @@
<td class="muted">{{ m.last_seen_fmt }}</td>
</tr>
{% else %}
<tr><td colspan="3" class="muted">当前无在线机器(客户端运行中会每分钟心跳)</td></tr>
<tr><td colspan="3" class="muted">当前无在线机器(客户端约每 2 秒心跳)</td></tr>
{% endfor %}
</tbody>
</table>
@@ -41,7 +41,7 @@
</div>
<div class="card" style="margin-top:14px">
<h3>机器实时交易记录 <span class="muted" style="font-weight:400;font-size:12px">· 自动刷新</span></h3>
<h3>机器实时交易记录</h3>
<table>
<thead>
<tr>
@@ -74,8 +74,10 @@
{% block scripts %}
<script>
(function () {
var streamUrl = {{ url_for('dashboard_stream')|tojson }};
var liveUrl = {{ url_for('dashboard_live')|tojson }};
var detailBase = {{ url_for('record_detail', tid=0)|tojson }}.replace(/0$/, '');
var hint = document.getElementById('live-hint');
function esc(s) {
return String(s == null ? '' : s)
@@ -87,7 +89,7 @@
var body = document.getElementById('online-machines-body');
if (!body) return;
if (!list.length) {
body.innerHTML = '<tr><td colspan="3" class="muted">当前无在线机器(客户端运行中会每分钟心跳)</td></tr>';
body.innerHTML = '<tr><td colspan="3" class="muted">当前无在线机器(客户端约每 2 秒心跳)</td></tr>';
return;
}
body.innerHTML = list.map(function (m) {
@@ -129,19 +131,36 @@
}).join('');
}
function tick() {
fetch(liveUrl, { credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(function (data) {
if (!data || !data.ok) return;
document.getElementById('stat-online').textContent = String(data.online_count);
renderMachines(data.online_machines || []);
renderTrades(data.trades || []);
})
.catch(function () {});
function apply(data) {
if (!data || !data.ok) return;
document.getElementById('stat-online').textContent = String(data.online_count);
renderMachines(data.online_machines || []);
renderTrades(data.trades || []);
}
setInterval(tick, 5000);
function startPollFallback() {
if (hint) hint.textContent = '· 轮询 1s(SSE 不可用)';
setInterval(function () {
fetch(liveUrl, { credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(apply)
.catch(function () {});
}, 1000);
}
if (typeof EventSource === 'undefined') {
startPollFallback();
return;
}
var es = new EventSource(streamUrl);
es.onmessage = function (ev) {
try { apply(JSON.parse(ev.data)); } catch (e) {}
};
es.onerror = function () {
es.close();
startPollFallback();
};
})();
</script>
{% endblock %}