| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- <!doctype html>
- <html lang="zh-CN">
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>Realtime Gateway Console</title>
- <link rel="stylesheet" href="/assets/style.css?v=20260327e">
- </head>
- <body>
- <div class="shell">
- <aside class="sidebar">
- <div class="brand">
- <div class="brand__eyebrow">REALTIME GATEWAY</div>
- <h1>控制台</h1>
- <div id="serviceBadge" class="badge">Loading</div>
- </div>
- <div class="sidebar__section">
- <div class="sidebar__label">运行信息</div>
- <div class="meta-list">
- <div class="meta-row"><span>监听</span><strong id="listenText">--</strong></div>
- <div class="meta-row"><span>运行时长</span><strong id="uptimeText">--</strong></div>
- <div class="meta-row"><span>匿名订阅</span><strong id="anonymousText">--</strong></div>
- </div>
- </div>
- <div class="sidebar__section">
- <div class="sidebar__label">接口</div>
- <div class="endpoint-list">
- <code>/ws</code>
- <code>/healthz</code>
- <code>/metrics</code>
- <code>/api/admin/overview</code>
- <code>/api/admin/sessions</code>
- <code>/api/admin/latest</code>
- <code>/api/admin/traffic</code>
- <code>/api/admin/live</code>
- </div>
- </div>
- <div class="sidebar__section">
- <button id="refreshBtn" class="action-btn">立即刷新</button>
- <label class="toggle">
- <input id="autoRefreshInput" type="checkbox" checked>
- <span>自动刷新 (3s)</span>
- </label>
- </div>
- </aside>
- <main class="main">
- <section class="hero">
- <div class="hero__title">
- <span class="hero__tag">Router Style</span>
- <h2>实时设备网关管理台</h2>
- </div>
- <p id="heroText" class="hero__text">正在加载运行状态...</p>
- </section>
- <section class="grid stats-grid">
- <article class="card metric-card">
- <div class="card__label">Sessions</div>
- <div id="sessionsCount" class="metric-card__value">0</div>
- </article>
- <article class="card metric-card">
- <div class="card__label">Subscribers</div>
- <div id="subscribersCount" class="metric-card__value">0</div>
- </article>
- <article class="card metric-card">
- <div class="card__label">Latest State</div>
- <div id="latestCount" class="metric-card__value">0</div>
- </article>
- <article class="card metric-card">
- <div class="card__label">Channels</div>
- <div id="channelsCount" class="metric-card__value">0</div>
- </article>
- <article class="card metric-card">
- <div class="card__label">Published</div>
- <div id="publishedCount" class="metric-card__value">0</div>
- </article>
- <article class="card metric-card">
- <div class="card__label">Dropped</div>
- <div id="droppedCount" class="metric-card__value">0</div>
- </article>
- <article class="card metric-card">
- <div class="card__label">Fanout</div>
- <div id="fanoutCount" class="metric-card__value">0</div>
- </article>
- <article class="card metric-card">
- <div class="card__label">Plugins</div>
- <div id="pluginsCount" class="metric-card__value">0</div>
- </article>
- </section>
- <section class="grid detail-grid">
- <article class="card">
- <div class="card__header">
- <div>
- <div class="card__title">Channel 管理</div>
- <div class="card__hint">创建临时通道并查看当前在线角色</div>
- </div>
- </div>
- <div class="channel-form">
- <input id="channelLabelInput" class="filter-select" type="text" placeholder="可选标签,例如: debug-a">
- <select id="channelModeSelect" class="filter-select">
- <option value="cache_latest">cache_latest</option>
- <option value="drop_if_no_consumer">drop_if_no_consumer</option>
- </select>
- <input id="channelTTLInput" class="filter-select" type="number" min="60" value="28800" placeholder="TTL 秒">
- <button id="createChannelBtn" class="action-btn">创建 Channel</button>
- </div>
- <div class="card__hint">创建成功后,这里会显示 `channelId` 与三种 token。</div>
- <pre id="createChannelResult" class="result-box">创建结果会显示在这里。</pre>
- <div id="channelsTable" class="table-wrap"></div>
- </article>
- <article class="card">
- <div class="card__header">
- <div>
- <div class="card__title">会话列表</div>
- <div id="sessionsHint" class="card__hint">当前连接与订阅</div>
- </div>
- </div>
- <div id="sessionsTable" class="table-wrap"></div>
- </article>
- <article class="card">
- <div class="card__header">
- <div>
- <div class="card__title">Latest State</div>
- <div class="card__hint">每个设备最近一条消息</div>
- </div>
- <select id="topicFilter" class="filter-select">
- <option value="">全部 Topic</option>
- <option value="telemetry.location">telemetry.location</option>
- <option value="telemetry.heart_rate">telemetry.heart_rate</option>
- </select>
- </div>
- <div id="latestTable" class="table-wrap"></div>
- </article>
- <article class="card traffic-card">
- <div class="card__header">
- <div>
- <div class="card__title">流量统计</div>
- <div class="card__hint">按 topic 和 channel 看累计发布、丢弃和扇出</div>
- </div>
- </div>
- <div class="traffic-grid">
- <section>
- <div class="card__hint">Topic 统计</div>
- <div id="topicTrafficTable" class="table-wrap"></div>
- </section>
- <section>
- <div class="card__hint">Channel 统计</div>
- <div id="channelTrafficTable" class="table-wrap"></div>
- </section>
- </div>
- </article>
- <article class="card live-card">
- <div class="card__header">
- <div>
- <div class="card__title">实时数据窗口</div>
- <div class="card__hint">直接查看网关收到的实时 GPS / 心率数据</div>
- </div>
- <div class="live-controls">
- <select id="liveTopicFilter" class="filter-select">
- <option value="">全部 Topic</option>
- <option value="telemetry.location">telemetry.location</option>
- <option value="telemetry.heart_rate">telemetry.heart_rate</option>
- </select>
- <input id="liveChannelFilter" class="filter-select" type="text" placeholder="channelId 可选">
- <input id="liveDeviceFilter" class="filter-select" type="text" placeholder="deviceId 可选">
- <button id="liveReconnectBtn" class="action-btn action-btn--inline">重连实时流</button>
- <button id="liveClearBtn" class="action-btn action-btn--inline action-btn--muted">清空窗口</button>
- </div>
- </div>
- <div class="live-meta">
- <div id="liveStatus" class="badge">Connecting</div>
- <div id="liveSummary" class="card__hint">等待实时流...</div>
- </div>
- <div class="live-stats">
- <div class="live-stat">
- <span class="live-stat__label">定位消息</span>
- <strong id="liveLocationCount">0</strong>
- </div>
- <div class="live-stat">
- <span class="live-stat__label">心率消息</span>
- <strong id="liveHeartRateCount">0</strong>
- </div>
- <div class="live-stat">
- <span class="live-stat__label">最后设备</span>
- <strong id="liveLastDevice">--</strong>
- </div>
- <div class="live-stat">
- <span class="live-stat__label">最后主题</span>
- <strong id="liveLastTopic">--</strong>
- </div>
- </div>
- <div class="live-panel-grid">
- <section class="live-track-panel">
- <div class="card__hint">轨迹预览,建议配合 `channelId / deviceId` 过滤使用</div>
- <div id="liveTrack" class="live-track"></div>
- <div id="liveTrackLegend" class="live-track-legend"></div>
- </section>
- <section>
- <div id="liveFeed" class="live-feed"></div>
- </section>
- </div>
- </article>
- </section>
- </main>
- </div>
- <script src="/assets/app.js?v=20260327e"></script>
- </body>
- </html>
|