完整提交;
This commit is contained in:
408
index.html
408
index.html
@@ -1,125 +1,291 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>性能监控</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
font-family: Arial, sans-serif;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.drag-bar {
|
||||
height: 30px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 5px;
|
||||
-webkit-app-region: drag;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
button {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.metrics {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.settings {
|
||||
margin-top: 15px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="drag-bar">
|
||||
<div>性能监控</div>
|
||||
<div class="controls">
|
||||
<button id="minimize">最小化</button>
|
||||
<button id="close">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="metrics">
|
||||
<div class="metric-item">CPU: <span id="cpu">0%</span></div>
|
||||
<div class="metric-item">内存: <span id="memory">0%</span></div>
|
||||
<div class="metric-item">网络: <span id="network">0 KB/s</span></div>
|
||||
</div>
|
||||
|
||||
<div class="settings">
|
||||
<label>
|
||||
<input type="checkbox" id="auto-launch"> 开机启动
|
||||
</label>
|
||||
</div>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>性能监控</title>
|
||||
<style>
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
color: black;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
user-select: none;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
<script>
|
||||
// 引入Electron的remote模块(需要在主进程中启用nodeIntegration)
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
// 获取元素
|
||||
const minimizeBtn = document.getElementById('minimize');
|
||||
const closeBtn = document.getElementById('close');
|
||||
const cpuEl = document.getElementById('cpu');
|
||||
const memoryEl = document.getElementById('memory');
|
||||
const networkEl = document.getElementById('network');
|
||||
const autoLaunchCheckbox = document.getElementById('auto-launch');
|
||||
|
||||
// 最小化按钮事件
|
||||
minimizeBtn.addEventListener('click', () => {
|
||||
// 发送最小化事件到主进程
|
||||
ipcRenderer.send('window-minimize');
|
||||
});
|
||||
|
||||
// 关闭按钮事件
|
||||
closeBtn.addEventListener('click', () => {
|
||||
// 发送关闭事件到主进程
|
||||
ipcRenderer.send('window-close');
|
||||
});
|
||||
|
||||
// 开机启动设置事件
|
||||
autoLaunchCheckbox.addEventListener('change', () => {
|
||||
// 发送开机启动设置事件到主进程
|
||||
ipcRenderer.send('set-auto-launch', autoLaunchCheckbox.checked);
|
||||
});
|
||||
|
||||
// 模拟性能数据更新
|
||||
setInterval(() => {
|
||||
// 生成随机数据
|
||||
const cpu = Math.floor(Math.random() * 100);
|
||||
const memory = Math.floor(Math.random() * 100);
|
||||
const network = Math.floor(Math.random() * 1000);
|
||||
.drag-bar {
|
||||
height: 32px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-radius: 4px;
|
||||
-webkit-app-region: drag;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.controls {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
button {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
color: black;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
backdrop-filter: blur(5px);
|
||||
transition: all 0.2s ease;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: rgba(255, 255, 255, 1);
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
button:active {
|
||||
background: rgba(240, 240, 240, 1);
|
||||
border: 1px solid rgba(0, 0, 0, 0.25);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) inset;
|
||||
}
|
||||
|
||||
.metrics {
|
||||
font-size: 14px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
margin: 0;
|
||||
padding: 4px 0;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
padding: 10px 14px;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.metric-item:hover {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-weight: 600;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.settings {
|
||||
margin-top: 15px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid rgba(200, 200, 200, 0.1);
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
accent-color: #0078d4;
|
||||
}
|
||||
|
||||
/* 动画类 */
|
||||
.window-container {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.minimized {
|
||||
transform: scale(0.1);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 350px) {
|
||||
.metrics {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
.metric-value {
|
||||
font-weight: 600;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 150px) {
|
||||
.metrics {
|
||||
grid-template-columns: 1fr;
|
||||
font-size: 10px;
|
||||
gap: 3px;
|
||||
}
|
||||
body {
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="window-container" id="window-container">
|
||||
<!-- 拖动区域 -->
|
||||
<div style="-webkit-app-region: drag; position: absolute; top: 0; left: 0; right: 0; height: 30px; z-index: -1"></div>
|
||||
|
||||
<div class="metrics">
|
||||
<div class="metric-item">
|
||||
<span class="metric-label">CPU</span>
|
||||
<span class="metric-value" id="cpu">0%</span>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-label">内存</span>
|
||||
<span class="metric-value" id="memory">0%</span>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-label">网络</span>
|
||||
<span class="metric-value" id="network">0 KB/s</span>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-label">GPU</span>
|
||||
<span class="metric-value" id="gpu">0%</span>
|
||||
</div>
|
||||
<div class="metric-item">
|
||||
<span class="metric-label">显存</span>
|
||||
<span class="metric-value" id="gpu-memory">0 MB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 引入性能监控库
|
||||
const si = require('systeminformation')
|
||||
const pidusage = require('pidusage')
|
||||
const process = require('process')
|
||||
|
||||
// 获取元素
|
||||
const cpuEl = document.getElementById('cpu')
|
||||
const memoryEl = document.getElementById('memory')
|
||||
const networkEl = document.getElementById('network')
|
||||
const gpuEl = document.getElementById('gpu')
|
||||
const gpuMemoryEl = document.getElementById('gpu-memory')
|
||||
|
||||
// 跟踪窗口聚焦状态
|
||||
let isWindowFocused = true;
|
||||
let lastUpdateTime = 0;
|
||||
|
||||
// 更新UI
|
||||
cpuEl.textContent = cpu + '%';
|
||||
memoryEl.textContent = memory + '%';
|
||||
networkEl.textContent = network + ' KB/s';
|
||||
}, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
// 监听窗口聚焦/失焦事件
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
ipcRenderer.on('window-focused', () => {
|
||||
isWindowFocused = true;
|
||||
});
|
||||
|
||||
ipcRenderer.on('window-blurred', () => {
|
||||
isWindowFocused = false;
|
||||
});
|
||||
|
||||
// 监听主进程发送的GPU信息
|
||||
ipcRenderer.on('gpu-info', (event, gpuInfo) => {
|
||||
// 过滤掉任何剩余的虚拟GPU信息
|
||||
const physicalGpus = gpuInfo.filter(gpu => {
|
||||
// 检查是否为虚拟GPU
|
||||
const isVirtual = gpu.name.includes('Oray') || gpu.name.includes('Virtual') || gpu.name.includes('Software')
|
||||
return !isVirtual && (gpu.memoryUsed !== undefined || gpu.vram !== undefined)
|
||||
})
|
||||
|
||||
if (physicalGpus && physicalGpus.length > 0) {
|
||||
// 显示第一个物理GPU的显存使用情况
|
||||
const gpu = physicalGpus[0]
|
||||
// 优先使用memoryUsed和memoryTotal,如果没有则使用vram
|
||||
if (gpu.memoryUsed !== undefined && gpu.memoryTotal !== undefined) {
|
||||
// 转换为MB单位
|
||||
const usedMB = Math.round(gpu.memoryUsed)
|
||||
const totalMB = Math.round(gpu.memoryTotal)
|
||||
gpuMemoryEl.textContent = usedMB + ' / ' + totalMB + ' MB'
|
||||
} else if (gpu.vram !== undefined) {
|
||||
// 如果只有vram信息,显示总显存
|
||||
const totalMB = Math.round(gpu.vram)
|
||||
gpuMemoryEl.textContent = '总共: ' + totalMB + ' MB'
|
||||
} else {
|
||||
gpuMemoryEl.textContent = 'N/A'
|
||||
}
|
||||
} else {
|
||||
gpuMemoryEl.textContent = 'N/A'
|
||||
}
|
||||
})
|
||||
|
||||
// 使用requestAnimationFrame实现性能数据更新
|
||||
let lastTime = 0;
|
||||
const focusedUpdateInterval = 200; // 聚焦时200ms更新一次
|
||||
const blurredUpdateInterval = 2000; // 失焦时2秒更新一次
|
||||
|
||||
async function updatePerformanceData(timestamp) {
|
||||
// 根据窗口聚焦状态确定更新间隔
|
||||
const updateInterval = isWindowFocused ? focusedUpdateInterval : blurredUpdateInterval;
|
||||
|
||||
if (timestamp - lastTime >= updateInterval) {
|
||||
try {
|
||||
// 获取CPU使用率
|
||||
const cpuData = await si.currentLoad();
|
||||
const cpuUsage = Math.round(cpuData.currentLoad);
|
||||
|
||||
// 获取内存使用率
|
||||
const memData = await si.mem();
|
||||
const memoryUsage = Math.round((memData.active / memData.total) * 100);
|
||||
|
||||
// 获取进程内存使用率
|
||||
const pid = process.pid;
|
||||
const pidData = await pidusage(pid);
|
||||
const processMemory = Math.round(pidData.memory / 1024 / 1024); // 转换为MB
|
||||
|
||||
// 获取网络使用情况
|
||||
const networkData = await si.networkStats();
|
||||
const networkUsage = networkData[0] ? Math.round((networkData[0].rx_sec + networkData[0].tx_sec) / 1024) : 0; // KB/s
|
||||
|
||||
// 获取GPU使用率
|
||||
const gpuData = await si.graphics();
|
||||
let gpuUsage = 0;
|
||||
if (gpuData.controllers && gpuData.controllers.length > 0) {
|
||||
// 尝试获取GPU使用率,如果没有则使用默认值
|
||||
gpuUsage = gpuData.controllers[0].utilizationMemory || gpuData.controllers[0].fanSpeed || 0;
|
||||
}
|
||||
|
||||
// 更新UI
|
||||
cpuEl.textContent = cpuUsage + '%';
|
||||
memoryEl.textContent = memoryUsage + '%';
|
||||
networkEl.textContent = networkUsage + ' KB/s';
|
||||
gpuEl.textContent = gpuUsage + '%';
|
||||
} catch (error) {
|
||||
console.error('获取性能数据时出错:', error);
|
||||
}
|
||||
|
||||
lastTime = timestamp;
|
||||
}
|
||||
|
||||
requestAnimationFrame(updatePerformanceData);
|
||||
}
|
||||
|
||||
// 启动动画循环
|
||||
requestAnimationFrame(updatePerformanceData)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user