index.html 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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.0">
  6. <title>OpenCode Monitor</title>
  7. <style>
  8. * { margin: 0; padding: 0; box-sizing: border-box; }
  9. body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 20px; }
  10. .container { max-width: 1200px; margin: 0 auto; }
  11. h1 { color: #333; margin-bottom: 20px; }
  12. .status-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
  13. .status-card { padding: 16px 0; }
  14. .status-card h2 { color: #666; font-size: 14px; margin-bottom: 8px; }
  15. .status-value { font-size: 32px; font-weight: bold; margin-bottom: 8px; }
  16. .status-time { color: #999; font-size: 12px; }
  17. .status-空闲 { color: #52c41a; }
  18. .status-工作中 { color: #ff4d4f; }
  19. .status-思考中 { color: #faad14; }
  20. .status-运行中 { color: #1890ff; }
  21. .status-完成 { color: #52c41a; }
  22. .status-错误 { color: #ff4d4f; }
  23. .status-重试中 { color: #faad14; }
  24. .status-修改中 { color: #722ed1; }
  25. .log { margin-top: 20px; }
  26. .log h2 { color: #666; font-size: 14px; margin-bottom: 12px; }
  27. .log-list { max-height: 300px; overflow-y: auto; }
  28. .log-item { padding: 8px 0; border-bottom: 1px solid #f0f0f0; font-size: 14px; }
  29. .log-item:last-child { border-bottom: none; }
  30. .log-time { color: #999; margin-right: 8px; }
  31. .log-port { color: #1890ff; margin-right: 8px; }
  32. .connected { color: #52c41a; font-size: 12px; margin-left: 10px; }
  33. .disconnected { color: #ff4d4f; font-size: 12px; margin-left: 10px; }
  34. </style>
  35. </head>
  36. <body>
  37. <div class="container">
  38. <h1>OpenCode Monitor <span id="connectionStatus" class="disconnected">● 未连接</span></h1>
  39. <div class="status-grid" id="statusGrid">
  40. <div class="status-card">
  41. <h2>当前状态</h2>
  42. <div class="status-value" id="currentStatus">等待中...</div>
  43. <div class="status-time" id="statusTime"></div>
  44. </div>
  45. </div>
  46. <div class="log">
  47. <h2>状态日志</h2>
  48. <div class="log-list" id="logList"></div>
  49. </div>
  50. </div>
  51. <script>
  52. const statusGrid = document.getElementById('statusGrid');
  53. const logList = document.getElementById('logList');
  54. const currentStatus = document.getElementById('currentStatus');
  55. const statusTime = document.getElementById('statusTime');
  56. const connectionStatus = document.getElementById('connectionStatus');
  57. let ws = null;
  58. let reconnectTimer = null;
  59. function connect() {
  60. const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
  61. ws = new WebSocket(protocol + '//' + window.location.host + '/ws');
  62. ws.onopen = function() {
  63. connectionStatus.textContent = '● 已连接';
  64. connectionStatus.className = 'connected';
  65. if (reconnectTimer) {
  66. clearTimeout(reconnectTimer);
  67. reconnectTimer = null;
  68. }
  69. };
  70. ws.onmessage = function(event) {
  71. try {
  72. const data = JSON.parse(event.data);
  73. updateStatus(data);
  74. addLog(data);
  75. } catch (e) {
  76. console.error('解析消息失败:', e);
  77. }
  78. };
  79. ws.onclose = function() {
  80. connectionStatus.textContent = '● 未连接';
  81. connectionStatus.className = 'disconnected';
  82. reconnectTimer = setTimeout(connect, 3000);
  83. };
  84. ws.onerror = function() {
  85. ws.close();
  86. };
  87. }
  88. function updateStatus(data) {
  89. currentStatus.textContent = data.status;
  90. currentStatus.className = 'status-value status-' + data.status;
  91. statusTime.textContent = '端口: ' + data.port + ' | 更新时间: ' + new Date().toLocaleTimeString();
  92. }
  93. function addLog(data) {
  94. const item = document.createElement('div');
  95. item.className = 'log-item';
  96. item.innerHTML = '<span class="log-time">' + new Date().toLocaleTimeString() + '</span>' +
  97. '<span class="log-port">[:' + data.port + ']</span>' +
  98. '<span class="status-' + data.status + '">' + data.status + '</span>';
  99. logList.insertBefore(item, logList.firstChild);
  100. while (logList.children.length > 50) {
  101. logList.removeChild(logList.lastChild);
  102. }
  103. }
  104. connect();
  105. </script>
  106. </body>
  107. </html>