重构了main.html的主函数
重构了大量的页面的sidebar 优化了代码结构
This commit is contained in:
392
web/js/services/system.js
Normal file
392
web/js/services/system.js
Normal file
@@ -0,0 +1,392 @@
|
||||
/**
|
||||
* 系统监控服务
|
||||
* 处理系统性能指标获取和展示
|
||||
*/
|
||||
|
||||
// 日志自动刷新相关变量
|
||||
let logRefreshTimer = null;
|
||||
let logCountdownTimer = null;
|
||||
let logCurrentInterval = 10;
|
||||
let logFullContent = '';
|
||||
|
||||
// 设置自动刷新间隔
|
||||
function setRefreshInterval() {
|
||||
const select = document.getElementById('logRefreshInterval');
|
||||
const countdownEl = document.getElementById('logRefreshCountdown');
|
||||
const secondsEl = document.getElementById('countdownNumber');
|
||||
|
||||
if (!select) return;
|
||||
|
||||
logCurrentInterval = parseInt(select.value) || 10;
|
||||
|
||||
// 清除之前的定时器
|
||||
if (logRefreshTimer) {
|
||||
clearInterval(logRefreshTimer);
|
||||
logRefreshTimer = null;
|
||||
}
|
||||
if (logCountdownTimer) {
|
||||
clearInterval(logCountdownTimer);
|
||||
logCountdownTimer = null;
|
||||
}
|
||||
|
||||
// 如果选择关闭,不显示倒计时
|
||||
if (select.value === '0') {
|
||||
countdownEl.classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示倒计时
|
||||
countdownEl.classList.remove('hidden');
|
||||
secondsEl.textContent = logCurrentInterval;
|
||||
|
||||
// 启动倒计时
|
||||
let countdown = logCurrentInterval;
|
||||
logCountdownTimer = setInterval(() => {
|
||||
countdown--;
|
||||
if (countdown <= 0) {
|
||||
countdown = logCurrentInterval;
|
||||
}
|
||||
secondsEl.textContent = countdown;
|
||||
}, 1000);
|
||||
|
||||
// 启动自动刷新
|
||||
logRefreshTimer = setInterval(() => {
|
||||
if (typeof refreshLogs === 'function') {
|
||||
refreshLogs();
|
||||
}
|
||||
}, logCurrentInterval * 1000);
|
||||
}
|
||||
|
||||
// 获取系统性能监控数据
|
||||
async function fetchSystemMetrics() {
|
||||
try {
|
||||
const response = await fetch(`${window.API_BASE}/health`);
|
||||
const result = await response.json();
|
||||
if (result.code === 0 && result.data) {
|
||||
const data = result.data;
|
||||
// 更新CPU使用率
|
||||
const cpuEl = document.getElementById('cpuUsage');
|
||||
if (cpuEl && data.cpu_percent !== undefined) {
|
||||
cpuEl.textContent = data.cpu_percent;
|
||||
cpuEl.className = data.cpu_percent > 80 ? 'text-red-500 font-medium' : '';
|
||||
}
|
||||
// 更新内存使用率
|
||||
const memEl = document.getElementById('memUsage');
|
||||
if (memEl && data.memory_percent !== undefined) {
|
||||
memEl.textContent = data.memory_percent;
|
||||
memEl.className = data.memory_percent > 80 ? 'text-red-500 font-medium' : '';
|
||||
}
|
||||
// 更新磁盘使用率
|
||||
const diskEl = document.getElementById('diskUsage');
|
||||
if (diskEl && data.disk_percent !== undefined) {
|
||||
diskEl.textContent = data.disk_percent;
|
||||
diskEl.className = data.disk_percent > 80 ? 'text-red-500 font-medium' : '';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取系统监控数据失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 停止日志自动刷新(离开页面时调用)
|
||||
function stopLogAutoRefresh() {
|
||||
if (logRefreshTimer) {
|
||||
clearInterval(logRefreshTimer);
|
||||
logRefreshTimer = null;
|
||||
}
|
||||
if (logCountdownTimer) {
|
||||
clearInterval(logCountdownTimer);
|
||||
logCountdownTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新日志
|
||||
function refreshLogs() {
|
||||
if (typeof switchLogTab === 'function') {
|
||||
const currentLogTab = window.currentLogTab || 'system';
|
||||
if (currentLogTab === 'system') {
|
||||
if (typeof loadLogFiles === 'function' && document.getElementById('logTypeSelect')?.value) {
|
||||
loadSelectedLog();
|
||||
} else {
|
||||
loadLogFiles();
|
||||
}
|
||||
} else {
|
||||
loadTrainingLogFiles();
|
||||
}
|
||||
} else {
|
||||
loadLogFiles();
|
||||
}
|
||||
// 重置倒计时
|
||||
const select = document.getElementById('logRefreshInterval');
|
||||
const secondsEl = document.getElementById('countdownNumber');
|
||||
if (select && select.value !== '0' && secondsEl) {
|
||||
secondsEl.textContent = logCurrentInterval;
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动到日志底部
|
||||
function scrollToLogBottom() {
|
||||
const logContent = document.getElementById('logContent');
|
||||
if (logContent) {
|
||||
logContent.scrollTop = logContent.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// 当前日志类型:system 或 training
|
||||
window.currentLogTab = 'system';
|
||||
|
||||
// 切换日志类型标签
|
||||
function switchLogTab(tab) {
|
||||
window.currentLogTab = tab;
|
||||
const systemTab = document.getElementById('logTabSystem');
|
||||
const trainingTab = document.getElementById('logTabTraining');
|
||||
const systemOptions = document.getElementById('systemLogOptions');
|
||||
const trainingOptions = document.getElementById('trainingLogOptions');
|
||||
|
||||
if (tab === 'system') {
|
||||
systemTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors bg-white shadow-sm text-primary';
|
||||
trainingTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors text-gray-600 hover:text-gray-800';
|
||||
systemOptions.classList.remove('hidden');
|
||||
trainingOptions.classList.add('hidden');
|
||||
loadLogFiles();
|
||||
} else {
|
||||
trainingTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors bg-white shadow-sm text-primary';
|
||||
systemTab.className = 'px-4 py-1.5 text-sm rounded-md transition-colors text-gray-600 hover:text-gray-800';
|
||||
trainingOptions.classList.remove('hidden');
|
||||
systemOptions.classList.add('hidden');
|
||||
loadTrainingLogFiles();
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化日志查看器
|
||||
function initLogViewer() {
|
||||
const datePicker = document.getElementById('logDatePicker');
|
||||
if (datePicker) {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
datePicker.value = today;
|
||||
}
|
||||
// 加载默认日志类型
|
||||
loadLogFiles();
|
||||
// 启动自动刷新
|
||||
setRefreshInterval();
|
||||
}
|
||||
|
||||
// 加载训练日志文件列表
|
||||
async function loadTrainingLogFiles() {
|
||||
const logSelect = document.getElementById('trainingLogSelect');
|
||||
if (!logSelect) return;
|
||||
|
||||
logSelect.innerHTML = '<option value="">加载中...</option>';
|
||||
|
||||
try {
|
||||
const response = await fetch(`${window.API_BASE}/training-log-files`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.code === 0 && result.data) {
|
||||
logSelect.innerHTML = '<option value="">请选择训练日志</option>';
|
||||
result.data.forEach(log => {
|
||||
const option = document.createElement('option');
|
||||
option.value = log.file;
|
||||
option.textContent = `${log.name} (PID: ${log.pid}, ${log.date}, ${log.size})`;
|
||||
logSelect.appendChild(option);
|
||||
});
|
||||
// 如果有日志文件,自动加载第一个
|
||||
if (result.data.length > 0) {
|
||||
logSelect.value = result.data[0].file;
|
||||
loadSelectedTrainingLog();
|
||||
} else {
|
||||
document.getElementById('logContent').textContent = '暂无训练日志';
|
||||
document.getElementById('logFileInfo').textContent = '无训练日志';
|
||||
}
|
||||
} else {
|
||||
logSelect.innerHTML = '<option value="">暂无训练日志</option>';
|
||||
document.getElementById('logContent').textContent = '暂无训练日志';
|
||||
document.getElementById('logFileInfo').textContent = '无训练日志';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载训练日志列表失败:', error);
|
||||
logSelect.innerHTML = '<option value="">加载失败</option>';
|
||||
document.getElementById('logContent').textContent = '加载训练日志列表失败: ' + error.message;
|
||||
}
|
||||
}
|
||||
|
||||
// 加载选中的训练日志
|
||||
async function loadSelectedTrainingLog() {
|
||||
const logSelect = document.getElementById('trainingLogSelect');
|
||||
const logFile = logSelect.value;
|
||||
const logContent = document.getElementById('logContent');
|
||||
const logFileInfo = document.getElementById('logFileInfo');
|
||||
|
||||
if (!logFile) {
|
||||
logContent.textContent = '请选择训练日志';
|
||||
logFileInfo.textContent = '无训练日志';
|
||||
return;
|
||||
}
|
||||
|
||||
logContent.textContent = '加载中...';
|
||||
logFileInfo.textContent = '加载中...';
|
||||
|
||||
try {
|
||||
const response = await fetch(`${window.API_BASE}/training-log-content?file=${encodeURIComponent(logFile)}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.code === 0 && result.data) {
|
||||
logFullContent = result.data.content || '';
|
||||
logContent.textContent = logFullContent || '(空日志)';
|
||||
logFileInfo.textContent = result.data.file + ' (' + result.data.size + ')';
|
||||
// 清空搜索
|
||||
document.getElementById('logSearchInput').value = '';
|
||||
document.getElementById('logMatchCount').textContent = '';
|
||||
// 滚动到底部
|
||||
scrollToLogBottom();
|
||||
} else {
|
||||
logContent.textContent = '加载失败: ' + (result.message || '未知错误');
|
||||
logFileInfo.textContent = '加载失败';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载训练日志内容失败:', error);
|
||||
logContent.textContent = '加载失败: ' + error.message;
|
||||
logFileInfo.textContent = '加载失败';
|
||||
}
|
||||
}
|
||||
|
||||
// 加载日志文件列表
|
||||
async function loadLogFiles() {
|
||||
const datePicker = document.getElementById('logDatePicker');
|
||||
const logTypeSelect = document.getElementById('logTypeSelect');
|
||||
const selectedDate = datePicker ? datePicker.value : new Date().toISOString().split('T')[0];
|
||||
|
||||
if (!logTypeSelect) return;
|
||||
logTypeSelect.innerHTML = '<option value="">加载中...</option>';
|
||||
|
||||
try {
|
||||
const response = await fetch(`${window.API_BASE}/log-files?date=${selectedDate}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.code === 0 && result.data) {
|
||||
logTypeSelect.innerHTML = '<option value="">请选择日志文件</option>';
|
||||
result.data.forEach(log => {
|
||||
const option = document.createElement('option');
|
||||
option.value = log.file;
|
||||
option.textContent = log.name + ' (' + log.size + ')';
|
||||
logTypeSelect.appendChild(option);
|
||||
});
|
||||
// 如果有日志文件,自动加载第一个
|
||||
if (result.data.length > 0) {
|
||||
logTypeSelect.value = result.data[0].file;
|
||||
loadSelectedLog();
|
||||
} else {
|
||||
logTypeSelect.innerHTML = '<option value="">暂无日志文件</option>';
|
||||
document.getElementById('logContent').textContent = '该日期暂无日志文件';
|
||||
document.getElementById('logFileInfo').textContent = '无日志文件';
|
||||
}
|
||||
} else {
|
||||
logTypeSelect.innerHTML = '<option value="">暂无日志文件</option>';
|
||||
document.getElementById('logContent').textContent = '该日期暂无日志文件';
|
||||
document.getElementById('logFileInfo').textContent = '无日志文件';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载日志文件列表失败:', error);
|
||||
logTypeSelect.innerHTML = '<option value="">加载失败</option>';
|
||||
document.getElementById('logContent').textContent = '加载日志文件列表失败: ' + error.message;
|
||||
}
|
||||
}
|
||||
|
||||
// 加载选中的日志
|
||||
async function loadSelectedLog() {
|
||||
const logTypeSelect = document.getElementById('logTypeSelect');
|
||||
const logFile = logTypeSelect.value;
|
||||
const logContent = document.getElementById('logContent');
|
||||
const logFileInfo = document.getElementById('logFileInfo');
|
||||
|
||||
if (!logFile) {
|
||||
logContent.textContent = '请选择日志文件';
|
||||
logFileInfo.textContent = '无日志文件';
|
||||
return;
|
||||
}
|
||||
|
||||
logContent.textContent = '加载中...';
|
||||
logFileInfo.textContent = '加载中...';
|
||||
|
||||
try {
|
||||
const response = await fetch(`${window.API_BASE}/log-content?file=${encodeURIComponent(logFile)}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.code === 0) {
|
||||
logFullContent = result.data.content || '';
|
||||
logContent.textContent = logFullContent || '(空日志)';
|
||||
logFileInfo.textContent = result.data.file + ' (' + result.data.size + ')';
|
||||
// 清空搜索框和匹配计数
|
||||
document.getElementById('logSearchInput').value = '';
|
||||
document.getElementById('logMatchCount').textContent = '';
|
||||
// 滚动到最底部
|
||||
scrollToLogBottom();
|
||||
} else {
|
||||
logContent.textContent = '加载失败: ' + (result.message || '未知错误');
|
||||
logFileInfo.textContent = '加载失败';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载日志内容失败:', error);
|
||||
logContent.textContent = '加载日志内容失败: ' + error.message;
|
||||
logFileInfo.textContent = '加载失败';
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤日志内容
|
||||
function filterLogContent() {
|
||||
const searchInput = document.getElementById('logSearchInput');
|
||||
const matchCount = document.getElementById('logMatchCount');
|
||||
const logContent = document.getElementById('logContent');
|
||||
|
||||
if (!searchInput || !matchCount || !logContent) return;
|
||||
|
||||
const keyword = searchInput.value.trim();
|
||||
|
||||
if (!keyword) {
|
||||
logContent.textContent = logFullContent || '(空日志)';
|
||||
matchCount.textContent = '';
|
||||
scrollToLogBottom();
|
||||
return;
|
||||
}
|
||||
|
||||
const lines = logFullContent.split('\n');
|
||||
const matchingLines = lines.filter(line => line.toLowerCase().includes(keyword.toLowerCase()));
|
||||
|
||||
if (matchingLines.length > 0) {
|
||||
logContent.textContent = matchingLines.join('\n');
|
||||
matchCount.textContent = `(${matchingLines.length}条匹配)`;
|
||||
// 滚动到最底部查看最新匹配
|
||||
scrollToLogBottom();
|
||||
} else {
|
||||
logContent.textContent = '未找到匹配的日志';
|
||||
matchCount.textContent = '(0条匹配)';
|
||||
}
|
||||
}
|
||||
|
||||
// 清空日志内容显示
|
||||
function clearLogContent() {
|
||||
document.getElementById('logContent').textContent = '日志内容将在这里显示...';
|
||||
document.getElementById('logFileInfo').textContent = '请选择日志文件';
|
||||
const logTypeSelect = document.getElementById('logTypeSelect');
|
||||
if (logTypeSelect) logTypeSelect.value = '';
|
||||
document.getElementById('logSearchInput').value = '';
|
||||
document.getElementById('logMatchCount').textContent = '';
|
||||
logFullContent = '';
|
||||
}
|
||||
|
||||
// 导出服务函数
|
||||
window.SystemService = {
|
||||
fetchSystemMetrics,
|
||||
setRefreshInterval,
|
||||
stopLogAutoRefresh,
|
||||
refreshLogs,
|
||||
scrollToLogBottom,
|
||||
switchLogTab,
|
||||
initLogViewer,
|
||||
loadTrainingLogFiles,
|
||||
loadSelectedTrainingLog,
|
||||
loadLogFiles,
|
||||
loadSelectedLog,
|
||||
filterLogContent,
|
||||
clearLogContent
|
||||
};
|
||||
Reference in New Issue
Block a user