diff --git a/bin/static/script.js b/bin/static/script.js index 4eae34e..ef051c8 100644 --- a/bin/static/script.js +++ b/bin/static/script.js @@ -197,34 +197,109 @@ function updateProcesses(processes) { const totalCount = document.getElementById('process-count'); totalCount.textContent = processes.count; - processes.list.forEach(process => { - const processElement = document.createElement('div'); - processElement.className = 'process-card'; - - const header = document.createElement('div'); - header.className = 'process-header'; - header.innerHTML = ` - ${process.name} - 订阅:${process.subscribed.length} 发布:${process.published.length} - `; - - const body = document.createElement('div'); - body.className = 'process-body'; - body.innerHTML = ` -
-

订阅主题

- -
-
-

发布主题

- + // 创建消息详情弹窗 + const modal = document.createElement('div'); + modal.id = 'message-modal'; + modal.className = 'modal'; + modal.innerHTML = ` + `; + document.body.appendChild(modal); - processElement.appendChild(header); - processElement.appendChild(body); - processList.appendChild(processElement); - }); + // 添加弹窗关闭事件 + modal.querySelector('.close-modal').addEventListener('click', () => { + modal.style.display = 'none'; + }); + + processes.list.forEach(process => { + const processElement = document.createElement('div'); + processElement.className = 'process-card'; + + const header = document.createElement('div'); + header.className = 'process-header'; + header.innerHTML = ` + ${process.name} + 订阅:${process.subscribed.length} 发布:${process.published.length} + `; + + const body = document.createElement('div'); + body.className = 'process-body'; + body.innerHTML = ` +
+

订阅主题

+ +
+
+

发布主题

+ +
+ `; + + body.querySelectorAll('.message-item').forEach(item => { + let timeoutId; + item.addEventListener('mouseenter', function(event) { + timeoutId = setTimeout(async () => { + const spinner = createSpinner(event.clientX, event.clientY); + + try { + const messageName = item.textContent; // 新增获取消息名称 + const messageType = item.dataset.type; // 新增获取消息类型 + const response = await fetch(`/api/message-details?name=${encodeURIComponent(messageName)}&type=${messageType}`); + const data = await response.json(); + + if (data.success) { + // 根据C++的CVar结构映射字段 + document.getElementById('message-name').textContent = data.name || 'N/A'; + document.getElementById('message-type').textContent = data.type || '未知类型'; + document.getElementById('message-timestamp').textContent = new Date(data.time * 1000).toLocaleString(); // 时间戳转换 + document.getElementById('message-content').textContent = JSON.stringify({ + value: data.value, + source: data.source + }, null, 2); + modal.style.display = 'block'; + } else { + showErrorTooltip(event, `获取失败: ${data.message || '未知错误'}`); + } + } catch (error) { + showErrorTooltip(event, '网络连接异常,请检查后重试'); + console.error('获取消息详情失败:', error); + } finally { + spinner.remove(); + } + }, 300); + }); + + item.addEventListener('mouseleave', () => { + clearTimeout(timeoutId); + modal.style.display = 'none'; + }); + }); + + processElement.appendChild(header); + processElement.appendChild(body); + processList.appendChild(processElement); + }); } // 渲染单个进程信息 @@ -259,3 +334,46 @@ function clearProcessList() { processLog.removeChild(processLog.firstChild); } } + +// 新增工具函数 +function createSpinner(x, y) { + const spinner = document.createElement('div'); + spinner.className = 'loading-spinner'; + spinner.style = ` + position: fixed; + left: ${x + 15}px; + top: ${y + 15}px; + width: 24px; + height: 24px; + border: 3px solid rgba(97, 218, 251, 0.3); + border-radius: 50%; + border-top-color: #61dafb; + animation: spin 1s ease-in-out infinite; + z-index: 1000; + `; + document.body.appendChild(spinner); + return spinner; +} + +function showErrorTooltip(event, message) { + const tooltip = document.createElement('div'); + tooltip.className = 'error-tooltip'; + tooltip.innerHTML = ` + + ${message} + `; + tooltip.style = ` + position: fixed; + left: ${event.clientX + 20}px; + top: ${event.clientY + 20}px; + padding: 8px 12px; + background: rgba(255, 87, 87, 0.9); + color: white; + border-radius: 4px; + font-size: 14px; + z-index: 1000; + animation: fadeIn 0.3s ease; + `; + document.body.appendChild(tooltip); + setTimeout(() => tooltip.remove(), 3000); +} diff --git a/bin/static/style.css b/bin/static/style.css index 45e0fc0..b883c38 100644 --- a/bin/static/style.css +++ b/bin/static/style.css @@ -734,13 +734,7 @@ body { padding: 15px; border: 1px solid rgba(97, 218, 251, 0.3); box-shadow: 0 2px 4px rgba(0,0,0,0.1); - transition: all 0.3s ease; -} - -.process-card:hover { - transform: translateY(-3px); - box-shadow: 0 4px 8px rgba(0,0,0,0.2); - border-color: rgba(97, 218, 251, 0.6); + transition: box-shadow 0.3s ease; /* 简化为仅阴影过渡 */ } .process-header { @@ -851,11 +845,214 @@ body { background: rgba(97, 218, 251, 0.05); border-radius: 4px; border-left: 3px solid rgba(97, 218, 251, 0.3); - transition: all 0.2s ease; + transition: background-color 0.2s ease, border-color 0.2s ease; /* 修改过渡属性 */ } .subscribed-list li:hover, .published-list li:hover { background: rgba(97, 218, 251, 0.1); border-left-color: #61dafb; - transform: translateX(4px); + /* 移除transform位移 */ + transform: none; +} + +/* 消息详情弹窗样式 */ +.message-detail-modal { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 600px; + max-width: 90%; + background: linear-gradient(145deg, #3a3f4b, #2e323a); + border-radius: 12px; + border: 2px solid rgba(97, 218, 251, 0.3); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); + z-index: 1000; + padding: 20px; + animation: modalFadeIn 0.3s ease; +} + +@keyframes modalFadeIn { + from { + opacity: 0; + transform: translate(-50%, -60%); + } + to { + opacity: 1; + transform: translate(-50%, -50%); + } +} + +.message-detail-header { + display: flex; + justify-content: space-between; + align-items: center; + padding-bottom: 15px; + margin-bottom: 15px; + border-bottom: 1px solid rgba(97, 218, 251, 0.2); +} + +.message-detail-title { + color: #61dafb; + font-size: 18px; + font-weight: bold; +} + +.message-detail-close { + cursor: pointer; + color: #61dafb; + font-size: 20px; + transition: all 0.2s ease; +} + +.message-detail-close:hover { + transform: scale(1.1); + color: #4fa8c7; +} + +.message-detail-content { + max-height: 60vh; + overflow-y: auto; + padding-right: 10px; +} + +.message-detail-item { + margin-bottom: 15px; + padding: 10px; + background: rgba(97, 218, 251, 0.05); + border-radius: 6px; + border-left: 3px solid rgba(97, 218, 251, 0.3); +} + +.message-detail-label { + color: #ffeb3b; + font-weight: bold; + margin-bottom: 5px; +} + +.message-detail-value { + color: #ffffff; + word-break: break-all; + font-family: 'Courier New', monospace; +} + +.message-detail-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + z-index: 999; + animation: overlayFadeIn 0.3s ease; +} + +@keyframes overlayFadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +/* 新增消息提示框样式 */ +.message-tooltip { + position: fixed; + z-index: 1000; + background: rgba(40, 44, 52, 0.95); + border: 1px solid rgba(97, 218, 251, 0.3); + border-radius: 6px; + padding: 12px; + max-width: 300px; + box-shadow: 0 4px 12px rgba(0,0,0,0.25); + backdrop-filter: blur(4px); + pointer-events: none; + transform: translate(10px, 10px); + transition: opacity 0.2s ease; +} + +.message-tooltip-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; + color: #61dafb; + font-weight: bold; +} + +.tooltip-label { + color: #4fa8c7; + margin-right: 6px; +} + +.message-tooltip-item { + margin: 4px 0; + font-size: 14px; +} + +.message-tooltip::before { + content: ''; + position: absolute; + top: -10px; + left: 50%; + transform: translateX(-50%); + border-width: 5px; + border-style: solid; + border-color: transparent transparent rgba(97, 218, 251, 0.3) transparent; +} + +.message-tooltip-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; + padding-bottom: 8px; + border-bottom: 1px solid rgba(97, 218, 251, 0.2); +} + +.message-tooltip-title { + color: #61dafb; + font-size: 14px; + font-weight: bold; +} + +.message-tooltip-close { + cursor: pointer; + color: #61dafb; + font-size: 16px; + transition: all 0.2s ease; +} + +.message-tooltip-close:hover { + color: #4fa8c7; + transform: scale(1.1); +} + +.message-tooltip-content { + max-height: 200px; + overflow-y: auto; + padding-right: 8px; +} + +.message-tooltip-item { + margin-bottom: 8px; + padding: 6px; + background: rgba(97, 218, 251, 0.05); + border-radius: 4px; + border-left: 2px solid rgba(97, 218, 251, 0.2); +} + +.message-tooltip-label { + color: #ffeb3b; + font-size: 12px; + font-weight: bold; + margin-bottom: 4px; +} + +.message-tooltip-value { + color: #ffffff; + font-size: 12px; + word-break: break-word; + font-family: 'Courier New', monospace; } diff --git a/bin/templates/index.html b/bin/templates/index.html index ed72bf3..11b024e 100644 --- a/bin/templates/index.html +++ b/bin/templates/index.html @@ -129,6 +129,37 @@
正在加载...
+ + + + diff --git a/src/appPowerMangerWebUI/main.cpp b/src/appPowerMangerWebUI/main.cpp index 0a21b89..d863fd4 100644 --- a/src/appPowerMangerWebUI/main.cpp +++ b/src/appPowerMangerWebUI/main.cpp @@ -74,7 +74,6 @@ void sendStateUpdate() { if(dbImage->GetProcInfo(proc, subs, pubs)) { crow::json::wvalue processInfo; processInfo["name"] = proc; - // 将STRING_LIST转换为std::vector std::vector subs_vec(subs.begin(), subs.end()); std::vector pubs_vec(pubs.begin(), pubs.end()); processInfo["subscribed"] = subs_vec; @@ -93,16 +92,25 @@ void sendStateUpdate() { { lock_guard lock(wsMutex); int varCount = dbImage->GetNumVariables(); - CDBImage::CVar lastVar; - bool hasLastVar = (varCount > 0) && dbImage->Get(lastVar, varCount-1); + crow::json::wvalue::list varList; + + // 遍历所有变量 + for(int i = 0; i < varCount; i++) { + CDBImage::CVar var; + if(dbImage->Get(var, i)) { + varList.push_back({ + {"name", var.GetName()}, + {"value", var.GetValue()}, + {"time", var.GetTime()}, + {"type", var.GetType()}, + {"source", var.GetSource()} + }); + } + } msg["variables"] = { {"count", varCount}, - {"last_updated", { - {"name", hasLastVar ? lastVar.GetName() : ""}, - {"value", hasLastVar ? lastVar.GetValue() : ""}, - {"time", hasLastVar ? lastVar.GetTime() : "0.0"} - }} + {"data", std::move(varList)} // 包含所有变量的数组 }; } @@ -132,9 +140,9 @@ bool FetchLoop(MOOS::MOOSAsyncCommClient* comms, CDBImage* m_DBImage) m_DBImage->SetProcInfo(procMail); // 打印进程信息 - STRING_LIST processes; - m_DBImage->GetProcesses(processes); - std::cout << "Active processes: " << processes.size() << std::endl; + // STRING_LIST processes; + // m_DBImage->GetProcesses(processes); + // std::cout << "Active processes: " << processes.size() << std::endl; } } @@ -146,15 +154,15 @@ bool FetchLoop(MOOS::MOOSAsyncCommClient* comms, CDBImage* m_DBImage) // 打印数据库变量信息 int varCount = m_DBImage->GetNumVariables(); - std::cout << "Database variables: " << varCount << std::endl; + // std::cout << "Database variables: " << varCount << std::endl; // 打印最近更新的变量 if(varCount > 0) { CDBImage::CVar lastVar; if(m_DBImage->Get(lastVar, varCount-1)) { - std::cout << "Last updated variable: " - << lastVar.GetName() << " = " - << lastVar.GetValue() << std::endl; + // std::cout << "Last updated variable: " + // << lastVar.GetName() << " = " + // << lastVar.GetValue() << std::endl; } } } diff --git a/src/pPowerManger/PowerManger.cpp b/src/pPowerManger/PowerManger.cpp index a5b2536..b5c5736 100644 --- a/src/pPowerManger/PowerManger.cpp +++ b/src/pPowerManger/PowerManger.cpp @@ -182,7 +182,7 @@ bool PowerManger::Iterate() { //a. 配电系统操作 disSysOption(); - //b. ccu操作 + //b. ccu操作 ccuOption(); //c. 上位机反馈 buildPowerSysReport(); @@ -686,39 +686,55 @@ int PowerManger::handleStandby_s2(FSM_State &fsm, void* pData) { case 0: pm->m_pmEvent = "收到上位机控制指令:关机"; - pm->shutdown(); + // pm->shutdown(); break; case 1: pm->m_pmEvent = "动力电上电"; + // pm->powerOn(); + //1.先上动力锂电池 + pm->m_CcuColCmd.powerBatCmd = 0x10; + //2.检查燃料电池是否就绪,如果就绪则启动 + if(pm->m_pmCurrentState.ccustate.fcuState = 0x04) + pm->m_CcuColCmd.fcuCmd = 0x02; break; case 2: pm->m_pmEvent = "锂动力电启动"; + pm->m_CcuColCmd.powerBatCmd = 0x10; break; case 3: pm->m_pmEvent = "燃料电池启动"; + pm->m_CcuColCmd.fcuCmd = 0x02; break; case 4: pm->m_pmEvent = "锂动力电关闭"; + pm->m_CcuColCmd.powerBatCmd = 0x20; case 5: pm->m_pmEvent = "燃料电池停机"; + pm->m_CcuColCmd.fcuCmd = 0x03; break; case 6: pm->m_pmEvent = "燃料电池预热指令"; + pm->m_CcuColCmd.fcuCmd = 0x07; break; case 7: pm->m_pmEvent = "燃料电池自检指令"; + pm->m_CcuColCmd.fcuCmd = 0x01; break; case 8: pm->m_pmEvent = "燃料电池紧急停机"; + pm->m_CcuColCmd.fcuCmd = 0x05; break; case 9: pm->m_pmEvent = "燃料电池复位指令"; + pm->m_CcuColCmd.fcuCmd = 0x04; break; case 10: pm->m_pmEvent = "燃料电池补给指令"; + pm->m_CcuColCmd.fcuCmd = 0x06; break; case 11: pm->m_pmEvent = "燃料电池停机维护"; + pm->m_CcuColCmd.fcuCmd = 0x08; break; default: break; @@ -773,9 +789,11 @@ int PowerManger::handleStandby_s2(FSM_State &fsm, void* pData) break; case 1: pm->m_pmEvent = "试验模式"; + pm->currentMod = 1; break; case 2: pm->m_pmEvent = "调试模式"; + pm->currentMod = 2; break; } MOOSPause(1000); @@ -859,12 +877,10 @@ void PowerManger::initControlCmd() m_CcuColCmd.powerBatEfficiency = 230; //默认为最大 m_CcuColCmd.heartbeat = 0; m_CcuColCmd.masterState = 0xAA;//主站状态,运行中 - //================初始化上位机指令========================= m_msCmd.modCMD = 99; m_msCmd.powerCMD = 99; m_msCmd.workCMD = 99; - //================初始化设备驱动指令======================== } diff --git a/src/pPowerManger/PowerManger.h b/src/pPowerManger/PowerManger.h index 66e6486..b56b07b 100644 --- a/src/pPowerManger/PowerManger.h +++ b/src/pPowerManger/PowerManger.h @@ -58,8 +58,6 @@ #define DB_TO_PM_EQUIPMENTCMD "uPower_equState_cmd" #define DB_TO_PM_SUBDISSTATE "uDevice_secdistState_st" - - class PowerManger : public AppCastingMOOSApp { public: @@ -99,10 +97,9 @@ class PowerManger : public AppCastingMOOSApp double msg_disHighBVolBusFbMsg_Update_time; double msg_disLowBusFbMsg_Update_time; - protected: //===========================交互状态变量================================== - Driver m_driver; + Driver m_driver; //设备驱动 pmState m_pmCurrentState; //能源系统的当前状态 disSysBreakerList m_currentDisBreakerState; //配电断路器状态 disSysBreakerList m_targetDisBreakerState; @@ -120,7 +117,6 @@ class PowerManger : public AppCastingMOOSApp unsigned int soc; unsigned int sustainableTime; - // 配电和CCU的反馈状态 msg_CcuStateFbMsg m_CcuCurrentState; msg_disHighVolBusFbMsg m_disHighVolBusCurrentState; @@ -189,4 +185,4 @@ class PowerManger : public AppCastingMOOSApp }; -#endif +#endif diff --git a/src/pPowerManger/driver.cpp b/src/pPowerManger/driver.cpp index 16ee49a..b5af163 100644 --- a/src/pPowerManger/driver.cpp +++ b/src/pPowerManger/driver.cpp @@ -23,8 +23,7 @@ int Driver::getDriverTable(workCondition condition, DriverTable* driverTable) switch (condition) { case STANDBY: - - + break; case SHORE_BASED_READY: @@ -770,7 +769,6 @@ std::string Driver::saveDriverTableToJson(const DriverTable* driverTable) root["sideSonar"] = driverTable->sideSonar; root["buoyage"] = driverTable->buoyage; - return root.toStyledString(); } std::string Driver::getDriverTableJson()