增加了数据库下载的功能

This commit is contained in:
zjk
2025-02-13 09:34:12 +08:00
parent ed0d7f7fe0
commit f83f737a79
10 changed files with 436 additions and 19 deletions
+21 -1
View File
@@ -53,7 +53,27 @@
"streambuf": "cpp", "streambuf": "cpp",
"cinttypes": "cpp", "cinttypes": "cpp",
"typeinfo": "cpp", "typeinfo": "cpp",
"queue": "cpp" "queue": "cpp",
"csignal": "cpp",
"any": "cpp",
"bitset": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"optional": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"future": "cpp",
"mutex": "cpp",
"semaphore": "cpp",
"stop_token": "cpp",
"thread": "cpp",
"typeindex": "cpp",
"variant": "cpp"
}, },
"C_Cpp.errorSquiggles": "disabled", "C_Cpp.errorSquiggles": "disabled",
"marscode.chatLanguage": "cn", "marscode.chatLanguage": "cn",
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"HVABFTDev123Cur_uint16": 0, "HVABFTDev123Cur_uint16": 1024,
"HVABactCur_uint16": 0, "HVABactCur_uint16": 0,
"HVABbowRudCur_uint16": 0, "HVABbowRudCur_uint16": 0,
"HVABbusBCur_uint16": 1792, "HVABbusBCur_uint16": 1792,
+1
View File
@@ -16,6 +16,7 @@ INCLUDE_DIRECTORIES(${LOCAL_LIBRARY_DIRS})
# List the subdirectories to build... # List the subdirectories to build...
#============================================================================ #============================================================================
ADD_SUBDIRECTORY(pPowerManger) ADD_SUBDIRECTORY(pPowerManger)
ADD_SUBDIRECTORY(appPowerMangerWebUI)
############################################################################## ##############################################################################
# END of CMakeLists.txt # END of CMakeLists.txt
+32
View File
@@ -0,0 +1,32 @@
#--------------------------------------------------------
# The CMakeLists.txt for: appPowerMangerWebUI
# Author(s):
#--------------------------------------------------------
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 设置 vcpkg 工具链文件路径
set(CMAKE_TOOLCHAIN_FILE "/home/zjk/project/lib/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
#find crow库
find_package(Crow CONFIG REQUIRED)
# Find SQLite3 package
find_package(SQLite3 REQUIRED)
SET(SRC
main.cpp
)
ADD_EXECUTABLE(appPowerMangerWebUI ${SRC})
TARGET_LINK_LIBRARIES(appPowerMangerWebUI
${MOOS_LIBRARIES}
mbutil
m
pthread
Crow::Crow
asio::asio
jsoncpp
SQLiteDB
sqlite3)
+281
View File
@@ -0,0 +1,281 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电源管理</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
/* 全局样式 */
body {
font-family: 'Arial', sans-serif;
background-color: #282c34;
color: #ffffff;
margin: 0;
padding: 20px;
height: 100vh;
display: grid;
grid-template-rows: auto 1fr 1fr;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.control-panel {
grid-column: 1 / -1;
display: flex;
gap: 20px;
padding: 20px;
background-color: #333;
border: 1px solid #61dafb;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.db-status-panel {
grid-column: 1 / -1;
background-color: #333;
border: 1px solid #61dafb;
border-radius: 8px;
padding: 20px;
margin-top: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.db-status {
display: flex;
align-items: center;
gap: 10px;
font-size: 16px;
}
.db-status i {
font-size: 20px;
}
.db-status.connected {
color: #4caf50;
}
.db-status.disconnected {
color: #f44336;
}
.control-panel button {
flex: 1;
padding: 15px 20px;
background: linear-gradient(145deg, #61dafb, #4fa8c7);
border: none;
border-radius: 6px;
color: #282c34;
cursor: pointer;
font-weight: bold;
font-size: 14px;
text-align: left;
display: flex;
align-items: center;
gap: 10px;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.control-panel button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
background: linear-gradient(145deg, #4fa8c7, #61dafb);
}
.control-panel button i {
font-size: 18px;
}
.panel {
background-color: #333;
border: 1px solid #61dafb;
border-radius: 8px;
padding: 20px;
overflow: auto;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.panel h2 {
color: #61dafb;
margin-top: 0;
margin-bottom: 15px;
font-size: 18px;
}
.status-columns {
display: flex;
gap: 20px;
}
.status-column {
flex: 1;
}
.status-column h3 {
color: #61dafb;
margin-top: 0;
margin-bottom: 10px;
font-size: 14px;
}
.log-panel {
grid-column: 1;
grid-row: 3;
}
.ccu-state-panel {
grid-column: 2;
grid-row: 2;
}
.dis-sys-panel {
grid-column: 1;
grid-row: 2;
}
.state-machine-panel {
grid-column: 2;
grid-row: 3;
}
pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
font-size: 13px;
line-height: 1.4;
}
</style>
</head>
<body>
<div class="control-panel">
<button id="mode-switch">
<i class="fas fa-exchange-alt"></i>
系统模式切换
</button>
<button id="condition-switch">
<i class="fas fa-cogs"></i>
系统工况切换
</button>
<button id="system-reset">
<i class="fas fa-redo"></i>
系统复位操作
</button>
<div class="control-panel">
<!-- 其他按钮 -->
<button id="download-db">
<i class="fas fa-download"></i>
下载数据库
</button>
</div>
</div>
<div class="db-status-panel">
<h2>数据库操作</h2>
<div class="db-status" id="db-status">
<i class="fas fa-database"></i>
<span>正在连接数据库...</span>
</div>
</div>
<div class="panel dis-sys-panel">
<h2>DIS系统状态</h2>
<pre id="dis-sys-state">正在加载...</pre>
</div>
<div class="panel ccu-state-panel">
<h2>CCU状态</h2>
<pre id="ccu-state">正在加载...</pre>
</div>
<div class="panel log-panel">
<h2>运行日志</h2>
<pre id="log-data">正在加载...</pre>
</div>
<div class="panel state-machine-panel">
<h2>状态机状态</h2>
<pre id="state-machine-state">正在加载...</pre>
</div>
<script>
// 更新页面数据的函数
function updateData() {
fetch('/api/status')
.then(response => response.json())
.then(data => {
// 更新DIS系统状态
document.getElementById('dis-sys-state').textContent = JSON.stringify(data.disSys, null, 2);
// 更新CCU状态
document.getElementById('ccu-state').textContent = JSON.stringify(data.ccuState, null, 2);
// 更新运行日志
document.getElementById('log-data').textContent = data.logs.join('\n');
// 更新状态机状态
document.getElementById('state-machine-state').textContent = JSON.stringify(data.stateMachine, null, 2);
})
.catch(error => console.error('Error fetching data:', error));
}
// 检查数据库连接状态
function checkDbConnection() {
fetch('/api/db-status')
.then(response => response.json())
.then(data => {
const dbStatus = document.getElementById('db-status');
if (data.connected) {
dbStatus.className = 'db-status connected';
dbStatus.innerHTML = `<i class="fas fa-database"></i><span>已连接到数据库:${data.database}</span>`;
} else {
dbStatus.className = 'db-status disconnected';
dbStatus.innerHTML = `<i class="fas fa-database"></i><span>数据库连接失败</span>`;
}
})
.catch(error => {
const dbStatus = document.getElementById('db-status');
dbStatus.className = 'db-status disconnected';
dbStatus.innerHTML = `<i class="fas fa-database"></i><span>数据库连接错误</span>`;
});
}
document.getElementById('download-db').addEventListener('click', function() {
const dbPath = 'data/power_data.db';
fetch(dbPath)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.blob();
})
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'power_data.db'; // 文件名
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
})
.catch(error => {
console.error('Error downloading database:', error);
alert('下载数据库失败,请检查文件路径或网络连接');
});
});
// 每2秒更新一次数据
setInterval(updateData, 2000);
updateData(); // 初始加载
// 每5秒检查一次数据库连接状态
setInterval(checkDbConnection, 5000);
checkDbConnection(); // 初始检查
</script>
</body>
</html>
+66
View File
@@ -0,0 +1,66 @@
#include <string>
#include "crow.h"
#include <iostream>
#include "json/json.h"
#include <sys/inotify.h>
#include <unistd.h>
#include <dirent.h>
#include <fstream>
#include <vector>
#include <thread>
#include <mutex>
#include "../pPowerManger/SQLiteDB.h"
using namespace std;
// 读取 HTML 文件内容
string read_file(const string& path) {
ifstream file(path);
stringstream buffer;
buffer << file.rdbuf();
return buffer.str();
}
int main() {
crow::SimpleApp app;
SQLiteDB db("/home/zjk/project/H100/H100PowerManger/data/power_data.db");
// 初始化 SQLite 数据库
// 路由返回 HTML 页面
CROW_ROUTE(app, "/")([](){
// 读取 HTML 文件
string html_content = read_file("/home/zjk/project/H100/H100PowerManger/src/appPowerMangerWebUI/index.html");
return html_content;
});
CROW_ROUTE(app, "/api/db-status")
([&db]() {
crow::json::wvalue response;
if (db.isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/data", "power_data.db")) {
response["connected"] = true;
response["database"] = "YourDatabaseName"; // 替换为实际的数据库名称
} else {
response["connected"] = false;
}
return response;
});
CROW_ROUTE(app, "/api/download-db")
([&db]() {
std::ifstream file("/home/zjk/project/H100/H100PowerManger/data/power_data.db", std::ios::binary);
if (!file) {
return crow::response(404, "Database file not found");
}
std::vector<char> buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
// 将 buffer.size() 转换为 std::string
std::string contentLength = std::to_string(buffer.size());
crow::response response(buffer.size(), contentLength, "application/octet-stream");
response.add_header("Content-Disposition", "attachment; filename=power_data.db");
return response;
});
// 启动服务器,监听端口 18080
app.port(18080).multithreaded().run();
return 0;
}
+1 -9
View File
@@ -123,14 +123,7 @@ bool PowerManger::Iterate()
else else
m_FsmThread.Stop(); m_FsmThread.Stop();
// 数据库测试 // 数据库测试
PowerData data;
// data.id = 1;
data.timestamp = "2023-05-22 10:00:00";
data.voltage = 12.3 + rand() % 100 / 100.0;
data.current = 4.5 + rand() % 100 / 100.0;
data.power = 56.7 + rand() % 100 / 100.0;
data.temperature = 25.0 + rand() % 100 / 100.0;
m_db->insertPowerData(data.voltage, data.current, data.power, data.temperature);
//3. 输出报告 //3. 输出报告
buildPowerSysReport(); buildPowerSysReport();
//4. 打印错误信息 //4. 打印错误信息
@@ -281,7 +274,6 @@ bool PowerManger::FsmLoop()
return true; return true;
} }
bool PowerManger::updatePmState() bool PowerManger::updatePmState()
{ {
+27 -1
View File
@@ -97,6 +97,32 @@ void SQLiteDB::insertStateData(StateData stateData) {
std::cerr << "Error preparing statement: " << sqlite3_errmsg(m_db) << std::endl; std::cerr << "Error preparing statement: " << sqlite3_errmsg(m_db) << std::endl;
} }
} }
bool SQLiteDB::isDatabaseConnected(const std::string& path, const std::string& dbName) {
if (!m_db) return false;
// 尝试执行简单查询验证连接
const char* sql = "SELECT name FROM sqlite_master WHERE type='table';";
char* errMsg = nullptr;
int rc = sqlite3_exec(m_db, sql, nullptr, nullptr, &errMsg);
if (rc != SQLITE_OK) {
std::cerr << "Database connection check failed: " << errMsg << std::endl;
sqlite3_free(errMsg);
return false;
}
// 检查数据库路径和名称是否匹配
std::string fullPath = path + "/" + dbName;
const char* dbPath = sqlite3_db_filename(m_db, "main");
if (!dbPath || fullPath != dbPath) {
std::cerr << "Database path mismatch: expected " << fullPath << ", got " << (dbPath ? dbPath : "null") << std::endl;
return false;
}
return true;
}
std::vector<PowerData> SQLiteDB::getPowerData(int limit) { std::vector<PowerData> SQLiteDB::getPowerData(int limit) {
std::vector<PowerData> data; std::vector<PowerData> data;
if (!m_db) return data; if (!m_db) return data;
@@ -124,4 +150,4 @@ std::vector<PowerData> SQLiteDB::getPowerData(int limit) {
} }
return data; return data;
} }
+3
View File
@@ -35,6 +35,9 @@ public:
void insertStateData(StateData stateData); void insertStateData(StateData stateData);
std::vector<PowerData> getPowerData(int limit = 100); std::vector<PowerData> getPowerData(int limit = 100);
//使用函数
bool isDatabaseConnected(const std::string& path, const std::string& dbName);
private: private:
sqlite3* m_db; sqlite3* m_db;
}; };
+3 -7
View File
@@ -9,12 +9,8 @@ TEST_CASE("SQLiteDB Test", "[SQLiteDB]") {
db.createStateTables(); db.createStateTables();
} }
SECTION("Query Data") { SECTION("Test isDatabaseConnected") {
std::vector<PowerData> results = db.getPowerData(); REQUIRE(db.isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/bin","test.db") == true);
REQUIRE(results.size() == 1);
REQUIRE(results[0].voltage == 12.5);
REQUIRE(results[0].current == 2.5);
REQUIRE(results[0].power == 31.25);
REQUIRE(results[0].temperature == 25.0);
} }
} }