diff --git a/bin/static/script.js b/bin/static/script.js index 4775382..55aecaf 100644 --- a/bin/static/script.js +++ b/bin/static/script.js @@ -1,15 +1,28 @@ let currentDbPath = '/home/zjk/project/H100/H100PowerManger/data/power_data.db'; // 数据库下载功能 -document.getElementById('download-db').addEventListener('click', function() { - fetch('/api/download-db') - .then(response => { - if (!response.ok) { - throw new Error('下载失败:' + response.statusText); - } - return response.blob(); - }) - .then(blob => { +function downloadDatabase() { + const downloadBtn = document.getElementById('download-db'); + const progressBar = document.getElementById('download-progress'); + + downloadBtn.disabled = true; + progressBar.style.display = 'block'; + progressBar.value = 0; + + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/api/download-db', true); + xhr.responseType = 'blob'; + + xhr.onprogress = function(event) { + if (event.lengthComputable) { + const percentComplete = (event.loaded / event.total) * 100; + progressBar.value = percentComplete; + } + }; + + xhr.onload = function() { + if (this.status === 200) { + const blob = this.response; const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; @@ -17,12 +30,28 @@ document.getElementById('download-db').addEventListener('click', function() { document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); - }) - .catch(error => { - console.error('下载数据库失败:', error); - alert('下载数据库失败:' + error.message); - }); -}); + + progressBar.value = 100; + setTimeout(() => { + progressBar.style.display = 'none'; + downloadBtn.disabled = false; + }, 500); + } else { + throw new Error('下载失败:' + this.statusText); + } + }; + + xhr.onerror = function() { + console.error('下载数据库失败:', this.statusText); + alert('下载数据库失败:' + this.statusText); + progressBar.style.display = 'none'; + downloadBtn.disabled = false; + }; + + xhr.send(); +} + +document.getElementById('download-db').addEventListener('click', downloadDatabase); // WebSocket连接 let ws = null; @@ -61,40 +90,44 @@ function initWebSocket() { }; } - // 更新UI - function updateUI(data) { - // 更新数据库状态 - if (data.db_status) { - const dbStatus = document.getElementById('db-status'); - if (dbStatus) { - dbStatus.className = data.db_status.connected ? 'db-status connected' : 'db-status disconnected'; - dbStatus.innerHTML = `已连接到数据库:${data.db_status.database}`; - } +// 更新UI +function updateUI(data) { + // 更新数据库状态 + if (data.db_status) { + const dbStatus = document.getElementById('db-status'); + const dbSizeElement = document.querySelector('#db-size .size-value'); + + if (dbStatus) { + dbStatus.className = data.db_status.connected ? 'db-status connected' : 'db-status disconnected'; + dbStatus.innerHTML = `已连接到数据库:${data.db_status.database}`; } - // 更新MOOS数据库状态 - if (data.moos_db_status) { - const moosDbStatus = document.getElementById('moos-db-status'); - if (data.moos_db_status.connected) { - moosDbStatus.className = 'db-status connected'; - moosDbStatus.innerHTML = `已连接到MOOS数据库:${data.moos_db_status.host}:${data.moos_db_status.port}`; - } else { - moosDbStatus.className = 'db-status disconnected'; - moosDbStatus.innerHTML = `MOOS数据库连接失败`; - } + if (dbSizeElement && data.db_status.size) { + const sizeInMB = (data.db_status.size / 1024 / 1024).toFixed(2); + dbSizeElement.textContent = `${sizeInMB} MB`; } + } + + // 更新MOOS数据库状态 + if (data.moos_db_status) { + const moosDbStatus = document.getElementById('moos-db-status'); + if (data.moos_db_status.connected) { + moosDbStatus.className = 'db-status connected'; + moosDbStatus.innerHTML = `已连接到MOOS数据库:${data.moos_db_status.host}:${data.moos_db_status.port}`; + } else { + moosDbStatus.className = 'db-status disconnected'; + moosDbStatus.innerHTML = `MOOS数据库连接失败`; + } + } - // 更新状态机面板 - const stateInfo = ` -更新时间 ${data.state.time} -状态ID ${data.state.state_id} -状态名称 ${data.state.state_name} -事件 ${data.state.event} -事件ID ${data.state.event_id} -故障代码 ${data.state.fault_code} -备注 ${data.state.note} -`; - document.getElementById('state-machine-state').innerHTML = stateInfo; + // 更新状态机面板 + document.getElementById('state-time').textContent = data.state.time; + document.getElementById('state-id').textContent = data.state.state_id; + document.getElementById('state-name').textContent = data.state.state_name; + document.getElementById('state-event').textContent = data.state.event; + document.getElementById('state-event-id').textContent = data.state.event_id; + document.getElementById('state-fault-code').textContent = data.state.fault_code; + document.getElementById('state-note').textContent = data.state.note; // 更新DIS系统状态 document.getElementById('dis-sys-state').textContent = JSON.stringify(data.status.disSys, null, 2); @@ -146,5 +179,3 @@ document.getElementById('moos-send-btn').addEventListener('click', sendMoosNotif // 初始化WebSocket连接 initWebSocket(); - -// 删除旧的定时检查,现在通过WebSocket实时更新 diff --git a/bin/static/style.css b/bin/static/style.css index 7fd9e1d..ee81fa8 100644 --- a/bin/static/style.css +++ b/bin/static/style.css @@ -14,11 +14,34 @@ body { .db-status-panel { grid-column: 1 / -1; - background-color: #333; - border: 1px solid #61dafb; - border-radius: 8px; + background-color: #1e2128; + border: 2px solid rgba(97, 218, 251, 0.3); + border-radius: 12px; padding: 20px; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); + position: relative; + overflow: auto; + transition: all 0.3s ease; + display: flex; + min-width: 1200px; + min-height: 400px; + margin-bottom: 20px; +} + +.db-status-panel:hover { + transform: translateY(-4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + border-color: rgba(97, 218, 251, 0.6); +} + +.db-status-group { + display: flex; + flex-direction: column; + gap: 15px; + padding: 15px; + background: rgba(97, 218, 251, 0.05); + border-radius: 6px; + border: 1px solid rgba(97, 218, 251, 0.1); } .control-panel { @@ -30,6 +53,13 @@ body { border: 1px solid #61dafb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; +} + +.control-panel:hover { + transform: translateY(-2px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); + border-color: rgba(97, 218, 251, 0.8); } .db-status { @@ -37,6 +67,56 @@ body { align-items: center; gap: 10px; font-size: 16px; + position: relative; + padding: 10px; + border-radius: 6px; + background: rgba(97, 218, 251, 0.05); + border: 1px solid rgba(97, 218, 251, 0.2); +} + +.db-status span { + position: relative; + color: #61dafb; + background: linear-gradient(90deg, #61dafb, #4fa8c7); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: textShine 2s infinite alternate; +} + +@keyframes textShine { + 0% { + background-position: 0% 50%; + } + 100% { + background-position: 100% 50%; + } +} + +.db-status::before { + content: ''; + width: 8px; + height: 8px; + border-radius: 50%; + background: #61dafb; + box-shadow: 0 0 8px #61dafb; + animation: pulse 1.5s infinite; + margin-right: 8px; +} + +@keyframes pulse { + 0% { + transform: scale(0.8); + opacity: 0.7; + } + 50% { + transform: scale(1); + opacity: 1; + } + 100% { + transform: scale(0.8); + opacity: 0.7; + } } .db-status i { @@ -51,6 +131,156 @@ body { color: #f44336; } +.db-size { + display: flex; + align-items: center; + gap: 10px; + font-size: 16px; + color: #61dafb; + margin-top: 10px; + padding: 15px; + background: linear-gradient(145deg, rgba(97, 218, 251, 0.1), rgba(97, 218, 251, 0.2)); + border-radius: 8px; + border: 1px solid rgba(97, 218, 251, 0.3); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); + position: relative; + transition: all 0.3s ease; +} + +.db-size:hover { + transform: translateY(-2px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); + border-color: rgba(97, 218, 251, 0.5); +} + +.db-size button { + margin-left: auto; + padding: 8px 12px; + font-size: 14px; + background: linear-gradient(145deg, #61dafb, #4fa8c7); + border: none; + border-radius: 4px; + color: #282c34; + cursor: pointer; + transition: all 0.3s ease; +} + +.db-size button:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); +} + +.db-size .size-value { + font-weight: bold; + color: #4caf50; + background-color: rgba(76, 175, 80, 0.1); + padding: 4px 8px; + border-radius: 4px; + border: 1px solid rgba(76, 175, 80, 0.3); +} + +#download-db { + width: auto; + min-width: 160px; + padding: 12px 20px; + background: linear-gradient(145deg, #61dafb, #4fa8c7); + border: none; + border-radius: 8px; + color: #282c34; + cursor: pointer; + font-weight: bold; + font-size: 14px; + text-align: center; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + transition: all 0.3s ease; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); + margin: 10px 0; + margin-left: auto; + position: relative; + overflow: hidden; +} + +#download-db::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent, + rgba(255, 255, 255, 0.3), + transparent + ); + animation: buttonShine 3s infinite; +} + +#download-db:hover { + transform: translateY(-2px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); + background: linear-gradient(145deg, #4fa8c7, #61dafb); +} + +@keyframes buttonShine { + 0% { + left: -100%; + } + 100% { + left: 100%; + } +} + +#download-db i { + font-size: 18px; +} + +#download-progress { + width: 100%; + height: 8px; + margin-top: 10px; + background: rgba(97, 218, 251, 0.1); + border-radius: 4px; + border: 1px solid rgba(97, 218, 251, 0.3); + overflow: hidden; + position: relative; +} + +#download-progress::after { + content: ''; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 0; + background: linear-gradient(90deg, #61dafb, #4fa8c7); + animation: progressAnimation 2s infinite; +} + +@keyframes progressAnimation { + 0% { + width: 0; + } + 50% { + width: 100%; + } + 100% { + width: 0; + } +} + +.db-size .size-value { + font-weight: bold; + color: #4caf50; + background-color: rgba(76, 175, 80, 0.1); + padding: 4px 8px; + border-radius: 4px; + border: 1px solid rgba(76, 175, 80, 0.3); +} + .control-panel button { flex: 1; padding: 15px 20px; @@ -86,6 +316,13 @@ body { padding: 20px; overflow: auto; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; +} + +.panel:hover { + transform: translateY(-2px); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); + border-color: rgba(97, 218, 251, 0.8); } .panel h2 { @@ -93,47 +330,251 @@ body { margin-top: 0; margin-bottom: 15px; font-size: 18px; + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + background: linear-gradient(145deg, rgba(97, 218, 251, 0.1), rgba(97, 218, 251, 0.2)); + border-radius: 6px; + border: 1px solid rgba(97, 218, 251, 0.3); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + position: relative; + overflow: hidden; +} + +.panel h2::before { + content: ''; + display: inline-block; + width: 12px; + height: 12px; + border-radius: 50%; + background: #61dafb; + box-shadow: 0 0 8px #61dafb; + animation: glow 2s infinite alternate; +} + +.panel h2::after { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent, + rgba(97, 218, 251, 0.3), + transparent + ); + animation: shine 4s infinite; +} + +@keyframes glow { + 0% { + box-shadow: 0 0 8px #61dafb; + } + 100% { + box-shadow: 0 0 16px #61dafb, 0 0 24px #61dafb; + } +} + + +.status-columns { + display: flex; + gap: 20px; + width: 100%; +} + +.status-column { + flex: 1; + min-width: 400px; + max-width: 45%; + height: 380px; + overflow: auto; + padding: 20px; + margin: 10px; + background: rgba(97, 218, 251, 0.05); + border-radius: 12px; + border: 2px solid rgba(97, 218, 251, 0.2); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + position: relative; } .status-columns { display: flex; gap: 20px; + width: 100%; + justify-content: space-between; + overflow: hidden; } -.status-column { - flex: 1; +.status-column::before { + content: ''; + position: absolute; + top: 0; + left: -10px; + width: 2px; + height: 100%; + background: linear-gradient( + to bottom, + transparent, + rgba(97, 218, 251, 0.5), + transparent + ); +} + +.status-column::after { + content: ''; + position: absolute; + top: 0; + right: -10px; + width: 2px; + height: 100%; + background: linear-gradient( + to bottom, + transparent, + rgba(97, 218, 251, 0.5), + transparent + ); } .status-column h3 { - color: #61dafb; + color: #ffeb3b; margin-top: 0; + margin-bottom: 6px; + font-size: 18px; + display: flex; + align-items: center; + gap: 6px; + padding: 4px 8px; + background: linear-gradient(145deg, rgba(255, 235, 59, 0.1), rgba(255, 235, 59, 0.2)); + border-radius: 4px; + border: 1px solid rgba(255, 235, 59, 0.3); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + position: relative; + overflow: hidden; +} + +.status-column h3::before { + content: ''; + display: inline-block; + width: 12px; + height: 12px; + border-radius: 50%; + background: #ffeb3b; + box-shadow: 0 0 8px #ffeb3b; + animation: glow 2s infinite alternate; +} + +.status-column h3::after { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent, + rgba(255, 235, 59, 0.3), + transparent + ); + animation: shine 4s infinite; +} + +/* MOOS通知面板样式 */ +.moos-notify-panel { + margin-top: 20px; + padding: 15px; + background: rgba(97, 218, 251, 0.05); + border-radius: 8px; + border: 1px solid rgba(97, 218, 251, 0.2); +} + +.moos-notify-panel .input-group { margin-bottom: 10px; - font-size: 14px; +} + +.moos-notify-panel label { + display: block; + color: #61dafb; + margin-bottom: 5px; + font-weight: bold; +} + +.moos-notify-panel input { + width: 100%; + padding: 8px; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(97, 218, 251, 0.3); + border-radius: 4px; + color: #ffffff; +} + +.moos-notify-panel input:focus { + outline: none; + border-color: #61dafb; + box-shadow: 0 0 0 2px rgba(97, 218, 251, 0.3); +} + +.moos-notify-panel button { + width: 100%; + padding: 10px; + background: linear-gradient(145deg, #61dafb, #4fa8c7); + border: none; + border-radius: 6px; + color: #282c34; + font-weight: bold; + cursor: pointer; + transition: all 0.3s ease; +} + +.moos-notify-panel button:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); +} + +/* 状态信息面板样式 */ +.state-info { + padding: 20px; + background: linear-gradient(145deg, #3a3f4b, #2e323a); + border-radius: 8px; + border: 2px solid rgba(97, 218, 251, 0.3); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + transition: all 0.3s ease; + margin-top: 20px; } .log-panel { - grid-column: 1; - grid-row: 4; -} - -.ccu-state-panel { - grid-column: 2; - grid-row: 3; -} - -.dis-sys-panel { grid-column: 1; grid-row: 3; } .state-machine-panel { + grid-column: 2; + grid-row: 3; + min-height: 600px; + max-height: 800px; + overflow: auto; +} + +.dis-sys-panel { + grid-column: 1; + grid-row: 4; + min-height: 600px; + max-height: 800px; + overflow: auto; +} + +.ccu-state-panel { grid-column: 2; grid-row: 4; display: flex; flex-direction: column; gap: 15px; - min-height: 400px; - max-height: 600px; + min-height: 600px; + max-height: 800px; + overflow: auto; } .state-machine-panel h2 { @@ -152,95 +593,118 @@ body { box-shadow: 0 0 8px #61dafb; } -.state-machine-panel pre { - margin: 0; - white-space: pre-wrap; - word-wrap: break-word; - font-size: 13px; - line-height: 1.4; - background-color: #3a3f4b; - padding: 15px; - border-radius: 6px; - border-left: 4px solid #61dafb; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -.state-machine-panel pre span { - display: block; - margin-bottom: 8px; - color: #61dafb; - font-weight: bold; -} - -.state-machine-panel pre span::after { - content: ':'; - margin-left: 4px; -} - -.file-input { - display: none; -} - -.file-label { - display: inline-block; - padding: 10px 15px; - background: #61dafb; - color: #282c34; - border-radius: 4px; - cursor: pointer; - margin-left: 10px; -} - -/* MOOS通知面板样式 */ -.moos-notify-panel { - margin-top: 20px; - padding: 15px; - background-color: #3a3f4b; - border: 1px solid #61dafb; - border-radius: 6px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); -} - -.moos-notify-panel .input-group { - margin-bottom: 15px; -} - -.moos-notify-panel label { - display: block; - margin-bottom: 5px; - color: #61dafb; - font-size: 14px; -} - -.moos-notify-panel input { - width: 80%; - padding: 8px 8px; - background-color: #282c34; - border: 1px solid #61dafb; - border-radius: 4px; - color: #ffffff; - font-size: 14px; -} - -.moos-notify-panel input:focus { - outline: none; - border-color: #4fa8c7; - box-shadow: 0 0 0 2px rgba(97, 218, 251, 0.2); -} - -.moos-notify-panel button { - width: 80%; - padding: 8px; - background: linear-gradient(145deg, #61dafb, #4fa8c7); - border: none; - border-radius: 4px; - color: #282c34; - font-weight: bold; - cursor: pointer; +.state-info { + padding: 20px; + background: linear-gradient(145deg, #3a3f4b, #2e323a); + border-radius: 8px; + border: 2px solid rgba(97, 218, 251, 0.3); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); transition: all 0.3s ease; } -.moos-notify-panel button:hover { - transform: translateY(-1px); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +.state-info:hover { + transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3); + border-color: rgba(97, 218, 251, 0.5); +} + +.state-row { + display: flex; + align-items: center; + margin-bottom: 8px; + padding: 8px; + border-radius: 4px; + background: linear-gradient( + 90deg, + rgba(97, 218, 251, 0.05), + rgba(97, 218, 251, 0.1), + rgba(97, 218, 251, 0.05) + ); + position: relative; + overflow: hidden; + border: 2px solid transparent; + animation: borderGlow 3s infinite alternate; +} + +@keyframes borderGlow { + 0% { + border-color: rgba(97, 218, 251, 0.3); + box-shadow: 0 0 8px rgba(97, 218, 251, 0.3); + } + 50% { + border-color: rgba(97, 218, 251, 0.6); + box-shadow: 0 0 16px rgba(97, 218, 251, 0.6); + } + 100% { + border-color: rgba(97, 218, 251, 0.3); + box-shadow: 0 0 8px rgba(97, 218, 251, 0.3); + } +} + +.state-row::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent, + rgba(97, 218, 251, 0.3), + transparent + ); + animation: shine 4s infinite; +} + +@keyframes shine { + 0% { + left: -100%; + } + 100% { + left: 100%; + } +} + +.state-label { + font-weight: bold; + min-width: 80px; + margin-right: 10px; + background: linear-gradient(90deg, #61dafb, #4fa8c7); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: textShine 2s infinite alternate; +} + +@keyframes textShine { + 0% { + background-position: 0% 50%; + } + 100% { + background-position: 100% 50%; + } +} + +.state-label i { + width: 20px; + text-align: center; + margin-right: 8px; + background: linear-gradient(90deg, #61dafb, #4fa8c7); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + animation: textShine 2s infinite alternate; +} + +.state-value { + flex-grow: 1; + font-family: 'Courier New', monospace; + font-weight: bold; + padding: 4px 8px; + border-radius: 4px; + background-color: rgba(76, 175, 80, 0.1); + border: 1px solid rgba(76, 175, 80, 0.3); + position: relative; + overflow: hidden; } diff --git a/bin/templates/index.html b/bin/templates/index.html index 0e4e1c8..eae5ec5 100644 --- a/bin/templates/index.html +++ b/bin/templates/index.html @@ -34,7 +34,19 @@

本地数据库

- 正在连接数据库... + 正在连接数据库: +
+
+ + 本地数据库大小: + 0.00 MB +
+
+ +
@@ -53,14 +65,47 @@ 系统复位操作 -
- -
+
+

运行日志

+
正在加载...
+
+ +
+

状态机状态

+
+
+ 更新时间: + 正在加载... +
+
+ 状态ID: + 正在加载... +
+
+ 状态名称: + 正在加载... +
+
+ 事件: + 正在加载... +
+
+ 事件ID: + 正在加载... +
+
+ 故障代码: + 正在加载... +
+
+ 备注: + 正在加载... +
+
+
+

DIS系统状态

正在加载...
@@ -71,16 +116,6 @@
正在加载...
-
-

运行日志

-
正在加载...
-
- -
-

状态机状态

-
正在加载...
-
- diff --git a/src/appPowerMangerWebUI/main.cpp b/src/appPowerMangerWebUI/main.cpp index 669ac1f..4d708d6 100644 --- a/src/appPowerMangerWebUI/main.cpp +++ b/src/appPowerMangerWebUI/main.cpp @@ -24,7 +24,6 @@ vector wsConnections; shared_ptr db; shared_ptr moosClient; - // WebSocket消息处理 void sendStateUpdate() { crow::json::wvalue msg; @@ -47,7 +46,8 @@ void sendStateUpdate() { // 添加数据库状态信息 msg["db_status"] = { {"connected", db->isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/data", "power_data.db")}, - {"database", db->getDBPatch()} + {"database", db->getDBPatch()}, + {"size", db->getDatabaseSize()} }; // 添加MOOS数据库状态信息 @@ -69,7 +69,7 @@ int main() { crow::SimpleApp app; db = make_shared("/home/zjk/project/H100/H100PowerManger/data/power_data.db"); moosClient = make_shared(); - moosClient->Run("localhost", 9000, "appPowerMangerWebUI", 200); // 设置更高的通信频率 + moosClient->Run("localhost", 9000, "appPowerMangerWebUI"); // WebSocket路由 CROW_WEBSOCKET_ROUTE(app, "/ws/state") @@ -86,7 +86,6 @@ int main() { cout << "WebSocket connection closed" << endl; }) .onmessage([&](crow::websocket::connection& conn, const string& data, bool is_binary){ - // 处理收到的WebSocket消息 cout << "Received WebSocket message: " << data << endl; }); @@ -129,6 +128,56 @@ int main() { } }); + // 下载数据库API + CROW_ROUTE(app, "/api/download-db") + ([]() { + const std::string dbPath = "/home/zjk/project/H100/H100PowerManger/data/power_data.db"; + const size_t chunkSize = 4096; // 4KB chunks + + std::ifstream file(dbPath, std::ios::binary | std::ios::ate); + if (!file) { + return crow::response(404, "Database file not found"); + } + + // 获取文件大小 + std::streamsize fileSize = file.tellg(); + file.seekg(0, std::ios::beg); + + if (fileSize == 0) { + return crow::response(500, "Database file is empty"); + } + + // 创建响应 + crow::response res; + res.code = 200; + res.set_header("Content-Type", "application/octet-stream"); + res.set_header("Content-Disposition", "attachment; filename=power_data.db"); + res.set_header("Content-Length", std::to_string(fileSize)); + + try { + // 分块读取和写入文件 + auto buffer = std::make_unique(chunkSize); + size_t totalSent = 0; + + while (totalSent < fileSize) { + size_t remaining = fileSize - totalSent; + size_t readSize = std::min(remaining, chunkSize); + + file.read(buffer.get(), readSize); + if (file.gcount() <= 0) break; + + res.write(std::string(buffer.get(), file.gcount())); + totalSent += file.gcount(); + } + + file.close(); + return res; + } catch (const std::exception& e) { + file.close(); + return crow::response(500, std::string("Download failed: ") + e.what()); + } + }); + // 启动服务器 app.port(18080) .multithreaded() diff --git a/src/pPowerManger/SQLiteDB.cpp b/src/pPowerManger/SQLiteDB.cpp index bdc32e3..7f65a1f 100644 --- a/src/pPowerManger/SQLiteDB.cpp +++ b/src/pPowerManger/SQLiteDB.cpp @@ -2,6 +2,7 @@ #include #include #include +#include SQLiteDB::SQLiteDB(const std::string& dbPath) { if (sqlite3_open(dbPath.c_str(), &m_db) != SQLITE_OK) { @@ -674,6 +675,20 @@ string SQLiteDB::getDBPatch(){ return m_dbPath; } +long SQLiteDB::getDatabaseSize() { + if (m_dbPath.empty()) { + return -1; + } + + struct stat stat_buf; + int rc = stat(m_dbPath.c_str(), &stat_buf); + if (rc != 0) { + return -1; + } + + return stat_buf.st_size; +} + bool SQLiteDB::clearPowerData() { if (!m_db) return false; diff --git a/src/pPowerManger/SQLiteDB.h b/src/pPowerManger/SQLiteDB.h index 69342a5..849d0f1 100644 --- a/src/pPowerManger/SQLiteDB.h +++ b/src/pPowerManger/SQLiteDB.h @@ -78,6 +78,9 @@ public: // 获取数据库状态函数 string getDBPatch(); + + // 获取数据库大小 + long getDatabaseSize(); private: sqlite3* m_db;