增加了数据库下载的功能
This commit is contained in:
Vendored
+21
-1
@@ -53,7 +53,27 @@
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "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",
|
||||
"marscode.chatLanguage": "cn",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"HVABFTDev123Cur_uint16": 0,
|
||||
"HVABFTDev123Cur_uint16": 1024,
|
||||
"HVABactCur_uint16": 0,
|
||||
"HVABbowRudCur_uint16": 0,
|
||||
"HVABbusBCur_uint16": 1792,
|
||||
|
||||
@@ -16,6 +16,7 @@ INCLUDE_DIRECTORIES(${LOCAL_LIBRARY_DIRS})
|
||||
# List the subdirectories to build...
|
||||
#============================================================================
|
||||
ADD_SUBDIRECTORY(pPowerManger)
|
||||
ADD_SUBDIRECTORY(appPowerMangerWebUI)
|
||||
|
||||
##############################################################################
|
||||
# END of CMakeLists.txt
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -123,14 +123,7 @@ bool PowerManger::Iterate()
|
||||
else
|
||||
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. 输出报告
|
||||
buildPowerSysReport();
|
||||
//4. 打印错误信息
|
||||
@@ -281,7 +274,6 @@ bool PowerManger::FsmLoop()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PowerManger::updatePmState()
|
||||
{
|
||||
|
||||
|
||||
@@ -97,6 +97,32 @@ void SQLiteDB::insertStateData(StateData stateData) {
|
||||
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> data;
|
||||
if (!m_db) return data;
|
||||
@@ -124,4 +150,4 @@ std::vector<PowerData> SQLiteDB::getPowerData(int limit) {
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ public:
|
||||
void insertStateData(StateData stateData);
|
||||
std::vector<PowerData> getPowerData(int limit = 100);
|
||||
|
||||
//使用函数
|
||||
bool isDatabaseConnected(const std::string& path, const std::string& dbName);
|
||||
|
||||
private:
|
||||
sqlite3* m_db;
|
||||
};
|
||||
|
||||
@@ -9,12 +9,8 @@ TEST_CASE("SQLiteDB Test", "[SQLiteDB]") {
|
||||
db.createStateTables();
|
||||
}
|
||||
|
||||
SECTION("Query Data") {
|
||||
std::vector<PowerData> results = db.getPowerData();
|
||||
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);
|
||||
SECTION("Test isDatabaseConnected") {
|
||||
REQUIRE(db.isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/bin","test.db") == true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user