class SystemInfo extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.charts = []; this.chartOptions = [ '内存使用率', '磁盘使用率', '网络带宽' ]; // 动态添加CPU核心选项 this.cpuCoreCount = 8; // 默认值,后续会从系统获取 for (let i = 0; i < this.cpuCoreCount; i++) { this.chartOptions.push(`CPU${i}使用率`); } // 每个图表的默认选择 this.chartSelections = [ 'CPU0使用率', 'CPU1使用率', '内存使用率', '网络带宽' ]; // 存储历史数据 this.historyData = {}; this.chartOptions.forEach(option => { this.historyData[option] = Array(60).fill(0); }); // 为上传带宽单独存储数据 this.historyData['上传带宽'] = Array(60).fill(0); this.historyData['下载带宽'] = Array(60).fill(0); // 初始化状态 this.chartsInitialized = false; this.setupInProgress = false; this.chartJsLoaded = false; this.domInitialized = false; this.isActive = false; // 添加活动状态标记 } connectedCallback() { this.isActive = true; // 组件连接到DOM时设置为活动状态 this.render(); // 创建一个MutationObserver来监听shadowRoot内容变化 this.observer = new MutationObserver(this.onDomChange.bind(this)); this.observer.observe(this.shadowRoot, { childList: true, subtree: true }); // 立即尝试初始化事件监听器 setTimeout(() => this.setupEventListeners(), 0); // 获取系统信息 this.fetchSystemInfo(); // 加载Chart.js this.loadChartJs(); // 设置定时刷新 this.refreshInterval = setInterval(() => { if (!this.isActive) return; // 非活动状态时不执行更新 this.fetchSystemInfo(); // 图表初始化后才更新 if (this.chartsInitialized) { this.updateCharts(); } }, 2000); } disconnectedCallback() { this.isActive = false; // 组件断开连接时设置为非活动状态 if (this.refreshInterval) { clearInterval(this.refreshInterval); this.refreshInterval = null; } if (this.observer) { this.observer.disconnect(); } this.cleanupCharts(); } // 清理所有图表 cleanupCharts() { // 销毁图表 if (this.charts) { this.charts.forEach((chart, index) => { if (chart) { try { chart.destroy(); } catch (e) { console.error(`销毁图表${index}失败:`, e); } this.charts[index] = null; } }); } this.chartsInitialized = false; } // 重新激活组件的方法(当标签页重新被选中时调用) reactivate() { if (this.isActive) return; // 如果已经是活动状态,不重复处理 this.isActive = true; // 重置图表状态 this.cleanupCharts(); this.domInitialized = false; // 重新设置刷新定时器 if (!this.refreshInterval) { this.refreshInterval = setInterval(() => { if (!this.isActive) return; this.fetchSystemInfo(); if (this.chartsInitialized) { this.updateCharts(); } }, 2000); } // 重新初始化图表 setTimeout(() => { if (this.chartJsLoaded) { // 确保DOM已初始化 const canvasElements = this.shadowRoot.querySelectorAll('canvas'); if (canvasElements.length === 4) { this.domInitialized = true; this.initializeCharts(); } else { // 如果DOM还没准备好,等待DOM变化 this.observer = new MutationObserver(this.onDomChange.bind(this)); this.observer.observe(this.shadowRoot, { childList: true, subtree: true }); } } else { // 如果Chart.js还没加载,重新加载 this.loadChartJs(); } }, 300); } // 监听DOM变化 onDomChange(mutations) { if (this.domInitialized) return; // 检查canvas元素是否已添加到DOM const canvasElements = this.shadowRoot.querySelectorAll('canvas'); if (canvasElements.length === 4) { this.domInitialized = true; // 如果Chart.js已加载,初始化图表 if (this.chartJsLoaded) { this.initializeCharts(); } } } // 加载Chart.js loadChartJs() { if (typeof Chart !== 'undefined') { this.chartJsLoaded = true; // 如果DOM已准备就绪,初始化图表 if (this.domInitialized) { this.initializeCharts(); } return; } const script = document.createElement('script'); script.src = './chart.min.js'; script.onload = () => { this.chartJsLoaded = true; // 如果DOM已准备就绪,初始化图表 if (this.domInitialized) { this.initializeCharts(); } }; script.onerror = () => { const cdnScript = document.createElement('script'); cdnScript.src = 'https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js'; cdnScript.onload = () => { this.chartJsLoaded = true; // 如果DOM已准备就绪,初始化图表 if (this.domInitialized) { this.initializeCharts(); } }; document.head.appendChild(cdnScript); }; document.head.appendChild(script); } render() { // 提前生成图表选项HTML字符串 const options0 = this.generateChartOptions(0); const options1 = this.generateChartOptions(1); const options2 = this.generateChartOptions(2); const options3 = this.generateChartOptions(3); this.shadowRoot.innerHTML = `
系统信息
操作系统
Loading...
Loading...
CPU核心数
Loading...
IP地址
Loading...
已隔离CPU核心号
Loading...
监控图表 1
监控图表 2
监控图表 3
监控图表 4
`; } setupEventListeners() { // 设置图表选择监听器 const selects = this.shadowRoot.querySelectorAll('.chart-select'); if (selects.length !== 4) { setTimeout(() => this.setupEventListeners(), 100); return; } selects.forEach(select => { select.addEventListener('change', (e) => { const chartIndex = parseInt(e.target.getAttribute('data-chart-index')); const newMetric = e.target.value; const oldMetric = this.chartSelections[chartIndex]; // 更新选择 this.chartSelections[chartIndex] = newMetric; // 如果图表已初始化,重新创建图表而不是更新 if (this.charts[chartIndex]) { this.recreateChart(chartIndex); } }); }); } // 初始化所有图表 initializeCharts() { if (this.setupInProgress || this.chartsInitialized) { return; } this.setupInProgress = true; try { for (let i = 0; i < 4; i++) { this.createChart(i); } this.chartsInitialized = true; } catch (error) { console.error('图表初始化失败:', error); } finally { this.setupInProgress = false; } } // 创建单个图表 createChart(index) { const canvas = this.shadowRoot.getElementById(`chart${index}`); if (!canvas) { throw new Error(`找不到图表${index}的canvas元素`); } // 确保canves宽高被设置 canvas.style.width = '100%'; canvas.style.height = '100%'; const ctx = canvas.getContext('2d'); if (!ctx) { throw new Error(`无法获取图表${index}的2D上下文`); } // 获取指标和数据 const metric = this.chartSelections[index]; const data = [...(this.historyData[metric] || Array(60).fill(0))]; // 针对不同指标设置不同的y轴配置和数据集 const yAxisConfig = this.getYAxisConfig(metric); let datasets = []; if (metric === '网络带宽') { // 网络带宽显示两条线:上传和下载 datasets = [ { label: '下载带宽', data: [...this.historyData['下载带宽']], borderColor: '#4CAF50', // 绿色 borderWidth: 2, fill: false, tension: 0.4, pointRadius: 0, // 去掉点 pointHoverRadius: 0 // 去掉悬停点 }, { label: '上传带宽', data: [...this.historyData['上传带宽']], borderColor: '#F44336', // 红色 borderWidth: 2, fill: false, tension: 0.4, pointRadius: 0, // 去掉点 pointHoverRadius: 0 // 去掉悬停点 } ]; } else { // 其他指标只显示一条线 datasets = [ { label: metric, data: data, borderColor: this.getChartColor(metric), borderWidth: 2, fill: false, tension: 0.4, pointRadius: 0, // 去掉点 pointHoverRadius: 0 // 去掉悬停点 } ]; } // 创建图表 this.charts[index] = new Chart(ctx, { type: 'line', data: { labels: Array(60).fill(''), datasets: datasets }, options: { responsive: true, maintainAspectRatio: false, animation: { duration: 0 // 关闭动画提高性能 }, elements: { point: { radius: 0 // 全局去掉点 }, line: { tension: 0.4 // 平滑曲线 } }, scales: { y: yAxisConfig, x: { display: false } }, plugins: { legend: { display: metric === '网络带宽', // 只在网络带宽图表显示图例 position: 'top', labels: { boxWidth: 12, font: { size: 10 } } }, tooltip: { mode: 'index', intersect: false, callbacks: { label: function(context) { const value = context.raw; // 为网络带宽添加单位 if (metric === '网络带宽' || context.dataset.label === '上传带宽' || context.dataset.label === '下载带宽') { return `${value} Mbps`; } // 为其他指标添加百分比单位 return `${value}%`; } } } } } }); } // 根据指标类型获取y轴配置 getYAxisConfig(metric) { // 网络带宽使用Mbps单位,其他使用百分比 if (metric === '网络带宽') { return { beginAtZero: true, // 自动计算最大值,但最少为1 suggestedMax: 1, title: { display: true, text: 'Mbps' } }; } else { return { beginAtZero: true, max: 100, title: { display: true, text: '%' } }; } } // 根据指标类型获取图表颜色 getChartColor(metric) { if (metric === '下载带宽') { return '#4CAF50'; // 绿色 } else if (metric === '上传带宽') { return '#F44336'; // 红色 } else if (metric === '内存使用率') { return '#2196F3'; // 蓝色 } else if (metric === '磁盘使用率') { return '#FF9800'; // 橙色 } else if (metric.includes('CPU')) { // CPU使用率显示紫色色调 return '#9C27B0'; } // 默认颜色 const colors = [ '#4285F4', // 蓝色 '#EA4335', // 红色 '#34A853', // 绿色 '#FBBC05' // 黄色 ]; // 为不同的指标分配不同的默认颜色 const hash = metric.split('').reduce((hash, char) => { return char.charCodeAt(0) + ((hash << 5) - hash); }, 0); return colors[Math.abs(hash) % colors.length]; } // 更新单个图表 updateChart(index) { try { if (!this.charts[index]) { return; } const metric = this.chartSelections[index]; if (!this.historyData[metric] && metric !== '网络带宽') { return; } if (metric === '网络带宽') { // 获取上传和下载数据 const downloadData = [...this.historyData['下载带宽']]; const uploadData = [...this.historyData['上传带宽']]; // 找出最大值来设置Y轴 const maxDownload = Math.max(...downloadData); const maxUpload = Math.max(...uploadData); const maxValue = Math.max(maxDownload, maxUpload); // 网络带宽图表根据数据自动调整y轴刻度 if (this.charts[index].options.scales.y) { // 根据当前最大值动态设置y轴,但至少为1 const suggestedMax = Math.max(maxValue * 1.2, 1); this.charts[index].options.scales.y.suggestedMax = suggestedMax; } // 更新两个数据集 this.charts[index].data.datasets[0].data = downloadData; this.charts[index].data.datasets[1].data = uploadData; } else { // 其他指标只有一个数据集 const currentData = [...this.historyData[metric]]; this.charts[index].data.datasets[0].data = currentData; } this.charts[index].update(); } catch (error) { console.error(`更新图表${index}失败:`, error); } } // 更新所有图表 updateCharts() { if (!this.chartsInitialized) { return; } for (let i = 0; i < 4; i++) { this.updateChart(i); } } // 重新创建单个图表 recreateChart(index) { try { // 销毁现有图表 if (this.charts[index]) { this.charts[index].destroy(); this.charts[index] = null; } // 重新创建 this.createChart(index); } catch (error) { console.error(`重新创建图表${index}失败:`, error); } } // 获取系统信息 async fetchSystemInfo() { try { const response = await fetch('/api/system-info'); if (!response.ok) { throw new Error(`获取系统信息失败: ${response.status}`); } const data = await response.json(); // 更新系统概览 const osInfo = this.shadowRoot.getElementById('os-info'); const kernelInfo = this.shadowRoot.getElementById('kernel-info'); const cpuCores = this.shadowRoot.getElementById('cpu-cores'); const ipAddress = this.shadowRoot.getElementById('ip-address'); const isolatedCores = this.shadowRoot.getElementById('isolated-cores'); if (osInfo) osInfo.textContent = data.os; if (kernelInfo) kernelInfo.textContent = data.kernel || ''; if (cpuCores) cpuCores.textContent = data.cpuCores; if (ipAddress) ipAddress.textContent = data.ipAddress; if (isolatedCores) isolatedCores.textContent = data.isolatedCores.join(',') || '无'; // 更新CPU核心数并重新生成选项 if (this.cpuCoreCount !== data.cpuCores) { this.cpuCoreCount = data.cpuCores; this.updateCpuOptions(); } // 更新历史数据 for (const [key, value] of Object.entries(data.metrics)) { if (this.historyData[key]) { this.historyData[key].shift(); this.historyData[key].push(value); } } // 如果图表已初始化,则更新图表 if (this.chartsInitialized) { this.updateCharts(); } } catch (error) { console.error('获取系统信息失败:', error); } } // 更新CPU选项 updateCpuOptions() { // 清除旧的CPU选项 this.chartOptions = this.chartOptions.filter(opt => !opt.startsWith('CPU')); // 添加新的CPU选项 for (let i = 0; i < this.cpuCoreCount; i++) { const option = `CPU${i}使用率`; this.chartOptions.push(option); // 确保历史数据中有此项 if (!this.historyData[option]) { this.historyData[option] = Array(60).fill(0); } } // 更新图表选择下拉框 const selects = this.shadowRoot.querySelectorAll('.chart-select'); if (selects.length === 4) { selects.forEach((select, index) => { // 保存当前选择 const currentValue = this.chartSelections[index]; // 更新选项 select.innerHTML = this.generateChartOptions(index); // 如果当前选择的值不在新选项中,则更新为第一个选项 if (!this.chartOptions.includes(currentValue)) { this.chartSelections[index] = this.chartOptions[0]; if (this.charts[index]) { this.recreateChart(index); } } }); } } // 生成图表选项HTML generateChartOptions(chartIndex) { let html = ''; this.chartOptions.forEach(option => { const selected = option === this.chartSelections[chartIndex] ? 'selected' : ''; html += ``; }); return html; } } customElements.define('system-info', SystemInfo);