4 changed files with 248 additions and 3 deletions
@ -0,0 +1,58 @@ |
|||||
|
#header-container { |
||||
|
background-color: beige; |
||||
|
} |
||||
|
|
||||
|
.card { |
||||
|
border-style: solid; |
||||
|
border-width: 2px; |
||||
|
border-color: black; |
||||
|
/* background-color: aqua; */ |
||||
|
padding: 5px; |
||||
|
margin: 5px; |
||||
|
border-radius: 8px; |
||||
|
} |
||||
|
|
||||
|
.server-name { |
||||
|
background-color: black; |
||||
|
color: white; |
||||
|
border-radius: 8px; |
||||
|
padding: 4px 10px; |
||||
|
font-size: 26px; |
||||
|
} |
||||
|
|
||||
|
.gpu-info { |
||||
|
/* background-color: aqua; */ |
||||
|
border-style: solid; |
||||
|
border-width: 1px; |
||||
|
border-color: #ccc; |
||||
|
border-radius: 8px; |
||||
|
margin-top: 5px; |
||||
|
padding: 4px 8px; |
||||
|
margin-bottom: 5px; |
||||
|
background-color: #f9f9f9; |
||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
.process-item { |
||||
|
color: rgb(26, 92, 247); |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
/*占用状态*/ |
||||
|
.state-free { |
||||
|
color: green; |
||||
|
} |
||||
|
.state-occupy { |
||||
|
color: red; |
||||
|
} |
||||
|
.state-light-occupy { |
||||
|
color: orange; |
||||
|
} |
||||
|
.state-super-occupy { |
||||
|
color: rgb(255, 0, 0); |
||||
|
font-weight: bold; |
||||
|
font-size: 20px; |
||||
|
background-color: rgb(255, 255, 0); |
||||
|
border-radius: 8px; |
||||
|
padding: 1px 6px; |
||||
|
} |
@ -0,0 +1,180 @@ |
|||||
|
// 请求服务器获取数据
|
||||
|
function fetchData() { |
||||
|
fetch('http://127.0.0.1:15002/api/get_data') |
||||
|
// 获取服务器和显卡数据
|
||||
|
.then(response => response.json()) // 解析 JSON 响应
|
||||
|
.then(data => { |
||||
|
// 处理 JSON 数据
|
||||
|
// console.log(data);
|
||||
|
displayServerData(data); // 调用显示数据的函数
|
||||
|
}) |
||||
|
.catch(error => { |
||||
|
// console.error('Error fetching data:', error);
|
||||
|
displayError(error + " (多半是没有正确连接服务器端,可能是没开、网络错误)"); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 显示错误
|
||||
|
function displayError(err_info){ |
||||
|
let serverDataContainer = document.getElementById('server-data'); |
||||
|
serverDataContainer.innerHTML = ''; // 清空容器
|
||||
|
|
||||
|
let errDiv = document.createElement('div'); |
||||
|
errDiv.classList.add('error-info'); |
||||
|
errDiv.innerText = err_info; |
||||
|
serverDataContainer.appendChild(errDiv); |
||||
|
} |
||||
|
|
||||
|
// 将KB转为合适的格式
|
||||
|
function parse_data_unit(num, fixedLen=2){ |
||||
|
if (num < 1024){ |
||||
|
return num.toFixed(fixedLen) + " KB"; |
||||
|
} |
||||
|
|
||||
|
num /= 1024; |
||||
|
if (num < 1024){ |
||||
|
return num.toFixed(fixedLen) + " MB"; |
||||
|
} |
||||
|
|
||||
|
num /= 1024; |
||||
|
if (num < 1024){ |
||||
|
return num.toFixed(fixedLen) + " GB"; |
||||
|
} |
||||
|
|
||||
|
num /= 1024; |
||||
|
if (num < 1024){ |
||||
|
return num.toFixed(fixedLen) + " TB"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
function add_bar(serverCard){ |
||||
|
let bar = document.createElement('hr'); |
||||
|
serverCard.appendChild(bar); |
||||
|
} |
||||
|
|
||||
|
// 添加服务器信息的元素
|
||||
|
function displayServerData(data){ |
||||
|
let serverDataContainer = document.getElementById('server-data'); |
||||
|
serverDataContainer.innerHTML = ''; // 清空容器
|
||||
|
|
||||
|
let serverDataDict = data['server_dict']; |
||||
|
|
||||
|
// 创建每一个服务器的信息
|
||||
|
for (let serverTitle in serverDataDict){ |
||||
|
let serverCard = document.createElement('div'); |
||||
|
serverCard.className = 'card'; |
||||
|
|
||||
|
// 标题
|
||||
|
let serverName = document.createElement('div'); |
||||
|
serverName.className = 'server-name'; |
||||
|
serverName.textContent = serverTitle; |
||||
|
serverCard.appendChild(serverName); |
||||
|
|
||||
|
serverData = serverDataDict[serverTitle]; |
||||
|
// 如果没有数据则跳过
|
||||
|
if (serverData == null){ |
||||
|
let errText = document.createElement('div'); |
||||
|
errText.className = 'error-text'; |
||||
|
errText.textContent = "No data."; |
||||
|
serverCard.appendChild(errText); |
||||
|
serverDataContainer.appendChild(serverCard); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// 内存
|
||||
|
if ('memory' in serverData){ |
||||
|
let memoryInfo = document.createElement('div'); |
||||
|
memoryInfo.className = 'memory-info'; |
||||
|
let totalNum = serverData.memory.total |
||||
|
let usedNum = serverData.memory.used |
||||
|
let totalMem = parse_data_unit(totalNum); |
||||
|
let usedMem = parse_data_unit(usedNum); |
||||
|
let tmpClass = "state-free"; |
||||
|
if (usedNum / totalNum > 0.95) |
||||
|
tmpClass = "state-super-occupy"; |
||||
|
else if (usedNum / totalNum > 0.8) |
||||
|
tmpClass = "state-occupy"; |
||||
|
else if (usedNum / totalNum > 0.6) |
||||
|
tmpClass = "state-light-occupy"; |
||||
|
memoryInfo.innerHTML += "<strong> 内存 : </strong> <span class=\"" + tmpClass + "\">" + usedMem + " / " + totalMem + "</span><br>"; |
||||
|
serverCard.appendChild(memoryInfo); |
||||
|
// 分割线
|
||||
|
add_bar(serverCard); |
||||
|
} |
||||
|
|
||||
|
// 存储空间
|
||||
|
if ('storage_list' in serverData){ |
||||
|
let storageInfo = document.createElement('div'); |
||||
|
storageInfo.className = 'storage-info'; |
||||
|
|
||||
|
for (let i = 0; i < serverData.storage_list.length; i++) { |
||||
|
let targetPath = serverData.storage_list[i].path; |
||||
|
let totalNum = serverData.storage_list[i].total |
||||
|
let availableNum = serverData.storage_list[i].available |
||||
|
let totalStorage = parse_data_unit(totalNum); |
||||
|
let availableStorage = parse_data_unit(totalNum - availableNum); |
||||
|
let tmpClass = "state-free"; |
||||
|
if (availableNum / totalNum < 0.01) |
||||
|
tmpClass = "state-super-occupy"; |
||||
|
else if (availableNum / totalNum < 0.1) |
||||
|
tmpClass = "state-occupy"; |
||||
|
else if (availableNum / totalNum < 0.3) |
||||
|
tmpClass = "state-light-occupy"; |
||||
|
storageInfo.innerHTML += '<strong>' + targetPath + " :</strong> <span class=\"" + tmpClass |
||||
|
+ "\">" + availableStorage + " / " + totalStorage + "</span><br>"; |
||||
|
} |
||||
|
|
||||
|
serverCard.appendChild(storageInfo); |
||||
|
// 分割线
|
||||
|
add_bar(serverCard); |
||||
|
} |
||||
|
|
||||
|
if ('gpu_list' in serverData){ |
||||
|
serverData.gpu_list.forEach(function(gpu){ |
||||
|
let gpuInfo = document.createElement('div'); |
||||
|
gpuInfo.className = 'gpu-info'; |
||||
|
|
||||
|
let markFree = '<span class="state-free"> 空闲</span>'; |
||||
|
let markLightOccupy = '<span class="state-light-occupy"> 占用</span>'; |
||||
|
let markOccupy = '<span class="state-occupy"> 占用</span>'; |
||||
|
let tmpMark = markFree; |
||||
|
if (gpu.used_memory < 1000 && gpu.utilization < 20){ |
||||
|
tmpMark = markFree; |
||||
|
} |
||||
|
else if (gpu.util_mem < 50){ |
||||
|
tmpMark = markLightOccupy; |
||||
|
}else{ |
||||
|
tmpMark = markOccupy; |
||||
|
} |
||||
|
gpuInfo.innerHTML = '<strong>' + gpu.idx + ' - ' + gpu.name + tmpMark + '</strong><br>' |
||||
|
+ '温度: ' + gpu.temperature + '°C<br>' |
||||
|
+ '显存: ' + gpu.used_memory + ' / ' + gpu.total_memory + " MB" + '<br>' |
||||
|
+ '利用率: ' + gpu.utilization + '%'; |
||||
|
|
||||
|
// 添加进程信息
|
||||
|
let processInfo = document.createElement('div'); |
||||
|
processInfo.classList.add('process-info'); |
||||
|
processInfo.innerHTML = "<strong>使用情况:</strong>"; |
||||
|
|
||||
|
gpu.process_list.sort((a, b) => b.memory - a.memory); |
||||
|
gpu.process_list.forEach(function(item, index){ |
||||
|
console.log(item.memory ); |
||||
|
if (item.memory > 40) |
||||
|
processInfo.innerHTML += `<span class="process-item" title="${item.cmd}">${item.user} (${item.memory}) </span>`; |
||||
|
}); |
||||
|
gpuInfo.appendChild(processInfo); // 将用户信息添加到GPU信息中
|
||||
|
|
||||
|
serverCard.appendChild(gpuInfo); |
||||
|
}); |
||||
|
// 分割线
|
||||
|
add_bar(serverCard); |
||||
|
} |
||||
|
|
||||
|
// 单个服务器信息作为child加入
|
||||
|
serverDataContainer.appendChild(serverCard); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// TODO test
|
||||
|
fetchData() |
Loading…
Reference in new issue