index.html 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <!doctype html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title>Realtime Gateway Console</title>
  7. <link rel="stylesheet" href="/assets/style.css?v=20260327e">
  8. </head>
  9. <body>
  10. <div class="shell">
  11. <aside class="sidebar">
  12. <div class="brand">
  13. <div class="brand__eyebrow">REALTIME GATEWAY</div>
  14. <h1>控制台</h1>
  15. <div id="serviceBadge" class="badge">Loading</div>
  16. </div>
  17. <div class="sidebar__section">
  18. <div class="sidebar__label">运行信息</div>
  19. <div class="meta-list">
  20. <div class="meta-row"><span>监听</span><strong id="listenText">--</strong></div>
  21. <div class="meta-row"><span>运行时长</span><strong id="uptimeText">--</strong></div>
  22. <div class="meta-row"><span>匿名订阅</span><strong id="anonymousText">--</strong></div>
  23. </div>
  24. </div>
  25. <div class="sidebar__section">
  26. <div class="sidebar__label">接口</div>
  27. <div class="endpoint-list">
  28. <code>/ws</code>
  29. <code>/healthz</code>
  30. <code>/metrics</code>
  31. <code>/api/admin/overview</code>
  32. <code>/api/admin/sessions</code>
  33. <code>/api/admin/latest</code>
  34. <code>/api/admin/traffic</code>
  35. <code>/api/admin/live</code>
  36. </div>
  37. </div>
  38. <div class="sidebar__section">
  39. <button id="refreshBtn" class="action-btn">立即刷新</button>
  40. <label class="toggle">
  41. <input id="autoRefreshInput" type="checkbox" checked>
  42. <span>自动刷新 (3s)</span>
  43. </label>
  44. </div>
  45. </aside>
  46. <main class="main">
  47. <section class="hero">
  48. <div class="hero__title">
  49. <span class="hero__tag">Router Style</span>
  50. <h2>实时设备网关管理台</h2>
  51. </div>
  52. <p id="heroText" class="hero__text">正在加载运行状态...</p>
  53. </section>
  54. <section class="grid stats-grid">
  55. <article class="card metric-card">
  56. <div class="card__label">Sessions</div>
  57. <div id="sessionsCount" class="metric-card__value">0</div>
  58. </article>
  59. <article class="card metric-card">
  60. <div class="card__label">Subscribers</div>
  61. <div id="subscribersCount" class="metric-card__value">0</div>
  62. </article>
  63. <article class="card metric-card">
  64. <div class="card__label">Latest State</div>
  65. <div id="latestCount" class="metric-card__value">0</div>
  66. </article>
  67. <article class="card metric-card">
  68. <div class="card__label">Channels</div>
  69. <div id="channelsCount" class="metric-card__value">0</div>
  70. </article>
  71. <article class="card metric-card">
  72. <div class="card__label">Published</div>
  73. <div id="publishedCount" class="metric-card__value">0</div>
  74. </article>
  75. <article class="card metric-card">
  76. <div class="card__label">Dropped</div>
  77. <div id="droppedCount" class="metric-card__value">0</div>
  78. </article>
  79. <article class="card metric-card">
  80. <div class="card__label">Fanout</div>
  81. <div id="fanoutCount" class="metric-card__value">0</div>
  82. </article>
  83. <article class="card metric-card">
  84. <div class="card__label">Plugins</div>
  85. <div id="pluginsCount" class="metric-card__value">0</div>
  86. </article>
  87. </section>
  88. <section class="grid detail-grid">
  89. <article class="card">
  90. <div class="card__header">
  91. <div>
  92. <div class="card__title">Channel 管理</div>
  93. <div class="card__hint">创建临时通道并查看当前在线角色</div>
  94. </div>
  95. </div>
  96. <div class="channel-form">
  97. <input id="channelLabelInput" class="filter-select" type="text" placeholder="可选标签,例如: debug-a">
  98. <select id="channelModeSelect" class="filter-select">
  99. <option value="cache_latest">cache_latest</option>
  100. <option value="drop_if_no_consumer">drop_if_no_consumer</option>
  101. </select>
  102. <input id="channelTTLInput" class="filter-select" type="number" min="60" value="28800" placeholder="TTL 秒">
  103. <button id="createChannelBtn" class="action-btn">创建 Channel</button>
  104. </div>
  105. <div class="card__hint">创建成功后,这里会显示 `channelId` 与三种 token。</div>
  106. <pre id="createChannelResult" class="result-box">创建结果会显示在这里。</pre>
  107. <div id="channelsTable" class="table-wrap"></div>
  108. </article>
  109. <article class="card">
  110. <div class="card__header">
  111. <div>
  112. <div class="card__title">会话列表</div>
  113. <div id="sessionsHint" class="card__hint">当前连接与订阅</div>
  114. </div>
  115. </div>
  116. <div id="sessionsTable" class="table-wrap"></div>
  117. </article>
  118. <article class="card">
  119. <div class="card__header">
  120. <div>
  121. <div class="card__title">Latest State</div>
  122. <div class="card__hint">每个设备最近一条消息</div>
  123. </div>
  124. <select id="topicFilter" class="filter-select">
  125. <option value="">全部 Topic</option>
  126. <option value="telemetry.location">telemetry.location</option>
  127. <option value="telemetry.heart_rate">telemetry.heart_rate</option>
  128. </select>
  129. </div>
  130. <div id="latestTable" class="table-wrap"></div>
  131. </article>
  132. <article class="card traffic-card">
  133. <div class="card__header">
  134. <div>
  135. <div class="card__title">流量统计</div>
  136. <div class="card__hint">按 topic 和 channel 看累计发布、丢弃和扇出</div>
  137. </div>
  138. </div>
  139. <div class="traffic-grid">
  140. <section>
  141. <div class="card__hint">Topic 统计</div>
  142. <div id="topicTrafficTable" class="table-wrap"></div>
  143. </section>
  144. <section>
  145. <div class="card__hint">Channel 统计</div>
  146. <div id="channelTrafficTable" class="table-wrap"></div>
  147. </section>
  148. </div>
  149. </article>
  150. <article class="card live-card">
  151. <div class="card__header">
  152. <div>
  153. <div class="card__title">实时数据窗口</div>
  154. <div class="card__hint">直接查看网关收到的实时 GPS / 心率数据</div>
  155. </div>
  156. <div class="live-controls">
  157. <select id="liveTopicFilter" class="filter-select">
  158. <option value="">全部 Topic</option>
  159. <option value="telemetry.location">telemetry.location</option>
  160. <option value="telemetry.heart_rate">telemetry.heart_rate</option>
  161. </select>
  162. <input id="liveChannelFilter" class="filter-select" type="text" placeholder="channelId 可选">
  163. <input id="liveDeviceFilter" class="filter-select" type="text" placeholder="deviceId 可选">
  164. <button id="liveReconnectBtn" class="action-btn action-btn--inline">重连实时流</button>
  165. <button id="liveClearBtn" class="action-btn action-btn--inline action-btn--muted">清空窗口</button>
  166. </div>
  167. </div>
  168. <div class="live-meta">
  169. <div id="liveStatus" class="badge">Connecting</div>
  170. <div id="liveSummary" class="card__hint">等待实时流...</div>
  171. </div>
  172. <div class="live-stats">
  173. <div class="live-stat">
  174. <span class="live-stat__label">定位消息</span>
  175. <strong id="liveLocationCount">0</strong>
  176. </div>
  177. <div class="live-stat">
  178. <span class="live-stat__label">心率消息</span>
  179. <strong id="liveHeartRateCount">0</strong>
  180. </div>
  181. <div class="live-stat">
  182. <span class="live-stat__label">最后设备</span>
  183. <strong id="liveLastDevice">--</strong>
  184. </div>
  185. <div class="live-stat">
  186. <span class="live-stat__label">最后主题</span>
  187. <strong id="liveLastTopic">--</strong>
  188. </div>
  189. </div>
  190. <div class="live-panel-grid">
  191. <section class="live-track-panel">
  192. <div class="card__hint">轨迹预览,建议配合 `channelId / deviceId` 过滤使用</div>
  193. <div id="liveTrack" class="live-track"></div>
  194. <div id="liveTrackLegend" class="live-track-legend"></div>
  195. </section>
  196. <section>
  197. <div id="liveFeed" class="live-feed"></div>
  198. </section>
  199. </div>
  200. </article>
  201. </section>
  202. </main>
  203. </div>
  204. <script src="/assets/app.js?v=20260327e"></script>
  205. </body>
  206. </html>