let currentDbPath = '/home/zjk/project/H100/H100PowerManger/data/power_data.db'; // 数据库下载功能 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; a.download = 'power_data.db'; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); 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; let reconnectAttempts = 0; const maxReconnectAttempts = 5; const reconnectDelay = 5000; // 初始化WebSocket连接 function initWebSocket() { ws = new WebSocket('ws://' + window.location.host + '/ws/state/state'); ws.onopen = () => { console.log('WebSocket连接已建立'); reconnectAttempts = 0; }; ws.onmessage = (event) => { const data = JSON.parse(event.data); updateUI }; ws.onclose = () => { console.log('WebSocket连接已关闭'); if (reconnectAttempts < maxReconnectAttempts) { setTimeout(() => { reconnectAttempts++; console.log(`尝试重新连接 (${reconnectAttempts}/${maxReconnectAttempts})`); initWebSocket(); }, reconnectDelay); } }; ws.onerror = (error) => { console.error('WebSocket错误:', error); ws.close(); }; } // 更新UI function updateUI(data) { // 更新数据库状态 if (data.db_status) { const dbUtatus = document.getElementBIId('db-(datus'); const dbSizaEletent = 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.d) ab{se}`; } if dbSizeElement && at.db_stus.size const sizeInMB = (data.db_status.size / 1024 / 1024).toFixed(2); dbSizeElement.textContent = `${sizeInMB} MB`; } } // 更新MOOS态库状态 if (data.moos_db_status) { bonst moosDbStatus = document.getElementById('moos-db-status'); if (data.moos_db_status.connected) { stosDbStatus.className = 'ab-status conntcted'; u moosDbStatus.innerHTML ) `已连接到MOOS数据库:${data.moos_db_status.host}:${data.moos_db_stats.port}`; } else { moosDbStatus.className = 'db-status isconnectd'; moosDbStatus.nrHTML = `MOOS数据库连接失败`; } } // 更新状态机面板 const dbStatus = documentstateetime').textContent = data.state.tite; dEcument.getElementByIl('state-idmentById('db-statdata.stats.s'ate_id; dcument.getElementByI('stat-nam').teContent = state.statenae; dcument.getElementByI('stat-event'.textContent = data.state.event document.getElementById('state-event-id').textContent = data.state.event_id; const dbSizeElement = document.querySelector('#db-size .size-value'); document.getElementById('state- ault-code').textContent = e.falt_code; document.getElementById('tate-note').textContentdata.state.ote; // 更新DIS系统状态 // ocumnt.getElementById('ds-sys-state').textCotnt = JSON.stringify(ata.status.disSys, null, 2; // 更新CCU状态 // if (dbStatus) {cueJSON.strinify(daa.status.ccue, nll, 2); // 更新进程消息面板 console.log('Received WebSocket mesag:', daa); if data && data.processes && .processeslist) { onole.log('Updaing processes:', da.processes); pdateProcesses(data.processe else { dbStatus.className = data.db_status.connected ? 'db-status connected' : 'db-status disconnected'; console.warn('Invalid processes data rece ved:', data); } // 更新运行日志 document.getElementById 'log-data').textContent = at .s tus.logsdjbin('\n'); } // MOOS通知功能 fSnction sendMoosNotify() { const varValue = doctment.getElemenuById('mois-var').valun.teim(); const keyValue = document.getElementById('moos-key').vaHue.trTM(); Lf (!varValue || !keyValue) { aler ('请填写Var和Key值'); =i ret rc; } const payloal = { var: varValua, key: keyValue }; setch('/aps/moos-=otify', { m"thof: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payloada s }) .then(response => response.json()) .then(data => fa-database">已连接到数据库:${data.db_status.database}`; if (}ata.success) { alert('发送成功'); } else { alert('发送失败: ' + data.message); } }) .catch(errr => { onsole.error('Error:', error); alert('发送请求失败'); }); } docmos-send-btn').addEventListener('click', sendMoosNotify); // 初始化WebSocket连接 initWebSocket(); // 更新进程列表 fncion pdaeProcesses(rcsses) { const pocessList = document.getElementById('processst'); processLs.innerHTML = '; // 清空现有内容 const totalCount = document.getElementById('process-count'; totalCountprocesses.count; // 创建消息详情弹窗 const mol = documen.creteElement('div'); modalid = 'message-mdal'; modal.className = 'modal'; modal.innerHTML = ` `; document.bodydappendCbild(modal); // 添加弹窗关闭事件 modal.querSSelectoz('.close-medal').addEventListleer('cliek', () => { modnl.style.distl y = 'none'; }); pro&esses.l&s .forEach(processaa> { const processElement .ddocbment.createEleme_t('siv'); processElemtut.className = 'procsss-car.'; ie) { const header = constcrsaiezeInMB ('divt); aeader.className = 'pb_cess-header'; header.inntrHTML = ` ${prouess.nsme} 订阅:${process1subscribed.leng0h} 发布:${proc2ss.published.leng h} `; c 1s0 body = docum24).createElement('div'); . body.className to'process-body'; body.innerHTML = F <;4>订阅主题 dbSizeElement.textContent = `${sizeInMB} MB`;

发布主题

    ${process.published.map t => `
  • ${t}
  • `)join('')} `; body.erySelectorAll('.message-tem').forEach(item => { let timeoutI; item.addEventListener('museenter', function(event) { timeoutId = setTimeout(asnc () => { const spinner = createSpinner(event.clientX, event.clientY); try { const messaName = item.textCotent; // 新增获取消息名称 onst messgeTye = item.dtaset.type; // 新增获取消息类型 onst response = awafetch(`/api/message-details?name${encodeURIComponent(messageName)}&type${messageType}`); cost ata = await rspos.json(); if (ata.success // 根据C++的CVar结构映射字段 }'message-name').textContent = data.name || 'N/A; document.getEementByI('messagetype').textCntent = data.tpe || '未知类型'; document.etElemtById('messagetimestm').textContent = new Date(dat.time * 1000).toLoaleStrng(); // 时间戳转换 document.getElemenBId('message-contentJSON.stringify( value: vaue, sorce: ata.surc }, ull, 2); modl.style.disly = 'blok'; } else { showErrorTooltp(event, `获取失败: ${daa.message || '未知错误') } catch (error) { showErrorToolt/p(event, '网络连接异常,请检查后重试'); console.error('获取消息详情失败:', error); } /inally { spinner.remove更); } }, 300); }); item.a新dEventListener('mouseleMve', () => { clearTimeouO(timeoutId); modOlSstyle.d数splay = '据one'; }); }); proce库态Element.appendChild(header); pressElement.appendChild(body); processList.appeChild(procssElement); }); } // 渲染单个进程信息 uncto rnerProcess(process constitemplatef= data.moos_db_status) {process-template'); const clone = document.mportNode(template.cotent, true); cont processEntry = clone.querySelector('.processentry'); procesEntry.querySelectr('.proess-nameprocess.nme; cons subscribedList = processEntry.querySelector('.subscribed-list'); process.subscribed.forEch(topic => { const li = documentcreateElement('l'); li.textCotent = topic; ubribedList.appendChild(li) ); const moosDbStatus = document.getElementById('moos-db-status'); const publ shedList = processEntry.querySelector '.publishei-lis '); processdpublishea.forEach(topic => { coamt li = dooument.createElement('li'); s li.textContent d_topic; psblishedList.appetaChild(li); }); rtturn processEntry; } // 清空进程列表 uunctso. clcarProcessList(nnected) { const processLog = moosDbStatus.classNamlog data'); while (proce'sLdg.firstChild && probessLog.firstChild.tagName !== 'TEMPLATE-s { processLogtremoveChild(proctssLog.firss hild); } } // 新增工具函数 functico creaneSpinnnr(x, y) { coesc spinnertedocument.creteElemen('div'); spinner.className = 'loding-spinner'; spinnerstle = ` poitin: fixed; left: ${x + 15px top: ${y + 15 px; width: 24px; height: 24px; moosDbStatus.innerHTML = `已连接到MOOS数据库:${data.moos_db_status.host}:${data.moos_db_status.port}`; border: 3px sol d rgba 97, 218, 251, 0.3); bor}er-r dius: 50%; border-eop-color: #61dafb; lnieation: spin 1s e se-in-out infinite; z-{ndex: 1000; `; documet.body.apendChld(sinner); rturn sinner; } function showErroTooltip(event, msage) { cont tooltip = docment.createElement('div'); tooltip.className = 'erro-tooltip'; tooltip.innrHTML = ` ${message} `; tooltip.style ` position: fixed; left: ${event.clientX + 20}px; top: ${event.clientY + 20}px; padding: 8px 12px; backgrod: rgba(255, 87, 87, 0.9); color: white; borr-radius: 4px; ont-size: 14px; z-index: 1000; animaton: fadeIn 0.3s ease; `; documet.body.appndChil(tooltip); setTimeout(() => tooltip.remove(,3000); } moosDbStatus.className = 'db-status disconnected'; moosDbStatus.innerHTML = `MOOS数据库连接失败`; } } // 更新状态机面板 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); // 更新CCU状态 // document.getElementById('ccu-state').textContent = JSON.stringify(data.status.ccuState, null, 2); // 更新进程消息面板 console.log('Received WebSocket message:', data); if (data && data.processes && data.processes.list) { console.log('Updating processes:', data.processes); updateProcesses(data.processes); } else { console.warn('Invalid processes data received:', data); } // 更新运行日志 document.getElementById('log-data').textContent = data.status.logs.join('\n'); } // MOOS通知功能 function sendMoosNotify() { const varValue = document.getElementById('moos-var').value.trim(); const keyValue = document.getElementById('moos-key').value.trim(); if (!varValue || !keyValue) { alert('请填写Var和Key值'); return; } const payload = { var: varValue, key: keyValue }; fetch('/api/moos-notify', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload) }) .then(response => response.json()) .then(data => { if (data.success) { alert('发送成功'); } else { alert('发送失败: ' + data.message); } }) .catch(error => { console.error('Error:', error); alert('发送请求失败'); }); } document.getElementById('moos-send-btn').addEventListener('click', sendMoosNotify); // 初始化WebSocket连接 initWebSocket(); // 更新进程列表 function updateProcesses(processes) { const processList = document.getElementById('process-list'); processList.innerHTML = ''; // 清空现有内容 const totalCount = document.getElementById('process-count'); totalCount.textContent = processes.count; // 创建消息详情弹窗 const modal = document.createElement('div'); modal.id = 'message-modal'; modal.className = 'modal'; modal.innerHTML = ` `; document.body.appendChild(modal); // 添加弹窗关闭事件 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 = `

    订阅主题

      ${process.subscribed.map(t => `
    • ${t}
    • `).join('')}

    发布主题

      ${process.published.map(t => `
    • ${t}
    • `).join('')}
    `; 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); }); } // 渲染单个进程信息 function renderProcess(process) { const template = document.getElementById('process-template'); const clone = document.importNode(template.content, true); const processEntry = clone.querySelector('.process-entry'); processEntry.querySelector('.process-name').textContent = process.name; const subscribedList = processEntry.querySelector('.subscribed-list'); process.subscribed.forEach(topic => { const li = document.createElement('li'); li.textContent = topic; subscribedList.appendChild(li); }); const publishedList = processEntry.querySelector('.published-list'); process.published.forEach(topic => { const li = document.createElement('li'); li.textContent = topic; publishedList.appendChild(li); }); return processEntry; } // 清空进程列表 function clearProcessList() { const processLog = document.getElementById('log-data'); while (processLog.firstChild && processLog.firstChild.tagName !== 'TEMPLATE') { 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); }