浏览代码

style: 导航菜单居中、内容居中、控件居中靠左 + 历史查询默认中国时区昨天到今天

Coze-Commit-Type: user
Coze-User-ID: 256649704250362
Coze-Conversation-ID: 11640025
steven_roc 2 月之前
父节点
当前提交
f96a583d14
共有 5 个文件被更改,包括 98 次插入 和 63 次删除
  1. 12 0
      mppt_monitor/CHANGELOG.md
  2. 二进制
      mppt_monitor/mppt_data.db
  3. 二进制
      mppt_monitor/mppt_data.db-shm
  4. 二进制
      mppt_monitor/mppt_data.db-wal
  5. 86 63
      mppt_monitor/www/index.html

+ 12 - 0
mppt_monitor/CHANGELOG.md

@@ -4,6 +4,18 @@
 
 ---
 
+## [2.2.0] - 2026-08-06
+
+### UI 优化:页面布局居中 + 历史查询默认时间范围
+
+- **导航菜单居中**:顶部导航栏居中显示
+- **内容区域居中**:主内容区域最大宽度 1400px,居中显示
+- **控件居中靠左**:历史查询控件居中容器内靠左对齐
+- **历史查询默认时间**:开始时间 = 中国时区(UTC+8)昨天 00:00,结束时间 = 中国时区当前时间
+- **快捷按钮使用本地时间**:1h/24h/7d 快捷按钮使用本地时区格式化
+
+---
+
 ## [2.1.2] - 2026-08-06
 
 ### Bug 修复:设置写入 Empty request body 和 Modbus 响应混淆

二进制
mppt_monitor/mppt_data.db


二进制
mppt_monitor/mppt_data.db-shm


二进制
mppt_monitor/mppt_data.db-wal


+ 86 - 63
mppt_monitor/www/index.html

@@ -8,15 +8,18 @@
 <style>
 *{margin:0;padding:0;box-sizing:border-box}
 body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0f172a;color:#e2e8f0;min-height:100vh}
-.header{background:linear-gradient(135deg,#1e293b,#334155);padding:16px 24px;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #475569}
+.header{background:linear-gradient(135deg,#1e293b,#334155);padding:16px 24px;display:flex;justify-content:center;align-items:center;border-bottom:1px solid #475569}
+.header-inner{max-width:1200px;width:100%;display:flex;justify-content:space-between;align-items:center}
 .header h1{font-size:20px;color:#38bdf8}
 .header .status{display:flex;gap:16px;align-items:center;font-size:13px}
 .header .status .dot{width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:4px}
 .dot-green{background:#22c55e}.dot-red{background:#ef4444}.dot-yellow{background:#eab308}
-.tabs{display:flex;background:#1e293b;border-bottom:1px solid #334155}
+.tabs{display:flex;justify-content:center;background:#1e293b;border-bottom:1px solid #334155}
+.tabs-inner{max-width:1200px;width:100%;display:flex;justify-content:center}
 .tab{padding:12px 24px;cursor:pointer;font-size:14px;color:#94a3b8;border-bottom:2px solid transparent;transition:all .2s}
 .tab:hover{color:#e2e8f0}.tab.active{color:#38bdf8;border-bottom-color:#38bdf8}
 .page{display:none;padding:20px 24px}.page.active{display:block}
+.page-inner{max-width:1200px;margin:0 auto}
 /* Device Cards */
 .device-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(380px,1fr));gap:16px;margin-bottom:24px}
 .device-card{background:#1e293b;border-radius:12px;border:1px solid #334155;overflow:hidden}
@@ -32,7 +35,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;b
 .section-title{font-size:13px;color:#38bdf8;margin:12px 0 8px;padding-bottom:4px;border-bottom:1px solid #334155}
 /* History Page */
 .history-controls{background:#1e293b;border-radius:12px;padding:16px;margin-bottom:20px;border:1px solid #334155}
-.controls-row{display:flex;flex-wrap:wrap;gap:12px;align-items:end}
+.controls-row{display:flex;flex-wrap:wrap;gap:12px;align-items:end;justify-content:center}
 .control-group{display:flex;flex-direction:column;gap:4px}
 .control-group label{font-size:12px;color:#94a3b8}
 .control-group input,.control-group select{background:#0f172a;border:1px solid #475569;color:#e2e8f0;padding:8px 12px;border-radius:6px;font-size:13px}
@@ -61,49 +64,56 @@ tr:hover td{background:#1e293b}
 </head>
 <body>
 <div class="header">
-  <h1>MPPT Solar Monitor - DM Series</h1>
-  <div class="status">
-    <span><span class="dot dot-green" id="conn-dot"></span> <span id="conn-status">Connecting...</span></span>
-    <span>Devices: <strong id="dev-online">0</strong>/<strong id="dev-total">0</strong></span>
-    <span>Records: <strong id="db-records">0</strong></span>
+  <div class="header-inner">
+    <h1>MPPT Solar Monitor - DM Series</h1>
+    <div class="status">
+      <span><span class="dot dot-green" id="conn-dot"></span> <span id="conn-status">Connecting...</span></span>
+      <span>Devices: <strong id="dev-online">0</strong>/<strong id="dev-total">0</strong></span>
+      <span>Records: <strong id="db-records">0</strong></span>
+    </div>
   </div>
 </div>
 <div class="tabs">
-  <div class="tab active" onclick="switchPage('realtime')">Real-time Monitor</div>
-  <div class="tab" onclick="switchPage('history')">History Query</div>
-  <div class="tab" onclick="switchPage('settings')">Device Settings</div>
+  <div class="tabs-inner">
+    <div class="tab active" onclick="switchPage('realtime')">Real-time Monitor</div>
+    <div class="tab" onclick="switchPage('history')">History Query</div>
+    <div class="tab" onclick="switchPage('settings')">Device Settings</div>
+  </div>
 </div>
 
 <!-- Real-time Page -->
 <div class="page active" id="page-realtime">
-  <div class="device-grid" id="device-grid"></div>
+  <div class="page-inner">
+    <div class="device-grid" id="device-grid"></div>
+  </div>
 </div>
 
 <!-- History Page -->
 <div class="page" id="page-history">
-  <div class="history-controls">
-    <div class="controls-row">
-      <div class="control-group">
-        <label>Device</label>
-        <select id="hist-device"><option value="0">All Devices</option></select>
-      </div>
-      <div class="control-group">
-        <label>Start Time</label>
-        <input type="datetime-local" id="hist-start">
-      </div>
-      <div class="control-group">
-        <label>End Time</label>
-        <input type="datetime-local" id="hist-end">
-      </div>
-      <div class="control-group">
-        <label>Page Size</label>
-        <select id="hist-size">
-          <option value="20">20</option><option value="50">50</option>
-          <option value="100">100</option><option value="200">200</option>
-        </select>
-      </div>
-      <div class="control-group">
-        <label>Sort</label>
+  <div class="page-inner">
+    <div class="history-controls">
+      <div class="controls-row">
+        <div class="control-group">
+          <label>Device</label>
+          <select id="hist-device"><option value="0">All Devices</option></select>
+        </div>
+        <div class="control-group">
+          <label>Start Time</label>
+          <input type="datetime-local" id="hist-start">
+        </div>
+        <div class="control-group">
+          <label>End Time</label>
+          <input type="datetime-local" id="hist-end">
+        </div>
+        <div class="control-group">
+          <label>Page Size</label>
+          <select id="hist-size">
+            <option value="20">20</option><option value="50">50</option>
+            <option value="100">100</option><option value="200">200</option>
+          </select>
+        </div>
+        <div class="control-group">
+          <label>Sort</label>
         <select id="hist-sort"><option value="desc">Newest First</option><option value="asc">Oldest First</option></select>
       </div>
       <div class="control-group">
@@ -137,16 +147,18 @@ tr:hover td{background:#1e293b}
       </div>
     </div>
   </div>
+  </div>
 </div>
 
 <!-- Settings Page -->
 <div class="page" id="page-settings">
-  <div class="history-controls">
-    <h3 style="color:#38bdf8;margin-bottom:12px;font-size:16px">Device Configuration (Output Registers)</h3>
-    <p style="color:#94a3b8;font-size:13px;margin-bottom:16px">Write parameters to MPPT device via Modbus function code 0x10. Changes take effect immediately.</p>
-    <div class="controls-row">
-      <div class="control-group">
-        <label>Target Device</label>
+  <div class="page-inner">
+    <div class="history-controls">
+      <h3 style="color:#38bdf8;margin-bottom:12px;font-size:16px">Device Configuration (Output Registers)</h3>
+      <p style="color:#94a3b8;font-size:13px;margin-bottom:16px">Write parameters to MPPT device via Modbus function code 0x10. Changes take effect immediately.</p>
+      <div class="controls-row">
+        <div class="control-group">
+          <label>Target Device</label>
         <select id="set-device"></select>
       </div>
       <div class="control-group">
@@ -171,22 +183,23 @@ tr:hover td{background:#1e293b}
     </div>
     <div id="param-info" style="margin-top:12px;padding:10px;background:#0f172a;border-radius:6px;font-size:12px;color:#94a3b8"></div>
     <div id="write-result" style="margin-top:12px;padding:10px;border-radius:6px;display:none"></div>
-  </div>
-  <div class="table-container" style="margin-top:20px">
-    <table>
-      <thead><tr><th>Register</th><th>Address</th><th>Range</th><th>Description</th><th>Access</th></tr></thead>
-      <tbody>
-        <tr><td>Battery Type</td><td>40001 (0x0000)</td><td>0-5</td><td>0=胶体 1=密封 2=磷酸铁锂 3=三元锂电 4=自定义 5=加水</td><td style="color:#22c55e">R/W</td></tr>
-        <tr><td>Battery Level</td><td>40002 (0x0001)</td><td>0-6</td><td>0=自动识别 1=12V 2=24V 3=36V 4=48V 5=60V 6=72V</td><td style="color:#22c55e">R/W</td></tr>
-        <tr><td>Charge Current Limit</td><td>40003 (0x0002)</td><td>5-100</td><td>PV充电电流限制 (%)</td><td style="color:#22c55e">R/W</td></tr>
-        <tr><td>Over-discharge Voltage</td><td>40004 (0x0003)</td><td>80-600</td><td>电池过放电压 (0.1V)</td><td style="color:#ef4444">Read Only</td></tr>
-        <tr><td>Boost Voltage</td><td>40005 (0x0004)</td><td>80-600</td><td>电池提升电压 (0.1V)</td><td style="color:#ef4444">Read Only</td></tr>
-        <tr><td>Full Charge Voltage</td><td>40006 (0x0005)</td><td>80-600</td><td>电池充满电压 (0.1V) - 仅自定义电池可写</td><td style="color:#eab308">R/W (Custom only)</td></tr>
-        <tr><td>Recovery Voltage</td><td>40007 (0x0006)</td><td>80-600</td><td>电池过放恢复电压 (0.1V)</td><td style="color:#ef4444">Read Only</td></tr>
-        <tr><td>485 Address</td><td>40008 (0x0007)</td><td>0-247</td><td>设备485通信地址</td><td style="color:#22c55e">R/W</td></tr>
-        <tr><td>Charge Mode</td><td>40009 (0x0008)</td><td>0-1</td><td>0=MPPT 1=DCDC</td><td style="color:#22c55e">R/W</td></tr>
-      </tbody>
-    </table>
+    </div>
+    <div class="table-container" style="margin-top:20px">
+      <table>
+        <thead><tr><th>Register</th><th>Address</th><th>Range</th><th>Description</th><th>Access</th></tr></thead>
+        <tbody>
+          <tr><td>Battery Type</td><td>40001 (0x0000)</td><td>0-5</td><td>0=胶体 1=密封 2=磷酸铁锂 3=三元锂电 4=自定义 5=加水</td><td style="color:#22c55e">R/W</td></tr>
+          <tr><td>Battery Level</td><td>40002 (0x0001)</td><td>0-6</td><td>0=自动识别 1=12V 2=24V 3=36V 4=48V 5=60V 6=72V</td><td style="color:#22c55e">R/W</td></tr>
+          <tr><td>Charge Current Limit</td><td>40003 (0x0002)</td><td>5-100</td><td>PV充电电流限制 (%)</td><td style="color:#22c55e">R/W</td></tr>
+          <tr><td>Over-discharge Voltage</td><td>40004 (0x0003)</td><td>80-600</td><td>电池过放电压 (0.1V)</td><td style="color:#ef4444">Read Only</td></tr>
+          <tr><td>Boost Voltage</td><td>40005 (0x0004)</td><td>80-600</td><td>电池提升电压 (0.1V)</td><td style="color:#ef4444">Read Only</td></tr>
+          <tr><td>Full Charge Voltage</td><td>40006 (0x0005)</td><td>80-600</td><td>电池充满电压 (0.1V) - 仅自定义电池可写</td><td style="color:#eab308">R/W (Custom only)</td></tr>
+          <tr><td>Recovery Voltage</td><td>40007 (0x0006)</td><td>80-600</td><td>电池过放恢复电压 (0.1V)</td><td style="color:#ef4444">Read Only</td></tr>
+          <tr><td>485 Address</td><td>40008 (0x0007)</td><td>0-247</td><td>设备485通信地址</td><td style="color:#22c55e">R/W</td></tr>
+          <tr><td>Charge Mode</td><td>40009 (0x0008)</td><td>0-1</td><td>0=MPPT 1=DCDC</td><td style="color:#22c55e">R/W</td></tr>
+        </tbody>
+      </table>
+    </div>
   </div>
 </div>
 
@@ -288,11 +301,17 @@ async function fetchStatus() {
   } catch(e) {}
 }
 
+// Helper: format Date to datetime-local string in local timezone
+function toLocalDatetime(d) {
+  const pad = n => String(n).padStart(2, '0');
+  return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
+}
+
 function setQuickRange(hours) {
   const now = new Date();
   const start = new Date(now.getTime() - hours * 3600000);
-  document.getElementById('hist-start').value = start.toISOString().slice(0, 16);
-  document.getElementById('hist-end').value = now.toISOString().slice(0, 16);
+  document.getElementById('hist-start').value = toLocalDatetime(start);
+  document.getElementById('hist-end').value = toLocalDatetime(now);
   loadHistory(1);
 }
 
@@ -388,11 +407,15 @@ fetchRealtime();
 fetchStatus();
 setInterval(fetchRealtime, 2000);
 setInterval(fetchStatus, 10000);
-// Set default time range
+// Set default time range: yesterday to today in China timezone (UTC+8)
 const now = new Date();
-const start = new Date(now.getTime() - 24*3600000);
-document.getElementById('hist-end').value = now.toISOString().slice(0,16);
-document.getElementById('hist-start').value = start.toISOString().slice(0,16);
+// Convert to China timezone (UTC+8)
+const chinaOffset = 8 * 60;
+const localOffset = now.getTimezoneOffset();
+const chinaTime = new Date(now.getTime() + (chinaOffset + localOffset) * 60000);
+const yesterday = new Date(chinaTime.getTime() - 24*3600000);
+document.getElementById('hist-end').value = toLocalDatetime(chinaTime);
+document.getElementById('hist-start').value = toLocalDatetime(yesterday);
 
 // ===== Settings Page Functions =====
 const paramInfo = {