928 lines
31 KiB
JavaScript
928 lines
31 KiB
JavaScript
// 在文件开头添加调试日志
|
||
console.log('monitor.js 加载完成');
|
||
|
||
// 全局变量声明
|
||
let currentDirectory = null;
|
||
let selectedPid = null;
|
||
let updateInterval = null;
|
||
let cpuChart = null;
|
||
let memoryChart = null;
|
||
let gpuChart = null;
|
||
|
||
// 更新监控数据
|
||
function updateMonitorData(pid) {
|
||
// 使用保存的监控类型
|
||
const type = currentMonitorType;
|
||
console.log('正在更新数据,类型:', type); // 调试日志
|
||
|
||
// 构建 URL,确保包含 type 参数
|
||
const url = new URL(`${window.location.origin}/api/process/${pid}/status/`);
|
||
url.searchParams.append('type', type);
|
||
console.log('请求 URL:', url.toString()); // 调试日志
|
||
|
||
fetch(url)
|
||
.then(response => response.json())
|
||
.then(response => {
|
||
if (response.status === 'success') {
|
||
const data = response.data;
|
||
updateUI(data, type);
|
||
}
|
||
})
|
||
.catch(error => handleError(error, '获取监控数据失败'));
|
||
}
|
||
|
||
// 获取所有监控按钮和停止按钮
|
||
const monitorButtons = document.querySelectorAll('[data-type]');
|
||
const stopBtn = document.getElementById('stopMonitor');
|
||
const pidInput = document.getElementById('pidInput');
|
||
|
||
// 保存当前监控类型的全局变量
|
||
let currentMonitorType = null;
|
||
|
||
// 开始监控
|
||
function startMonitoring(pid) {
|
||
console.log('开始监控,类型:', currentMonitorType); // 调试日志
|
||
updateMonitorData(pid); // 立即执行一次更新
|
||
monitorInterval = setInterval(() => {
|
||
updateMonitorData(pid);
|
||
}, 60000);
|
||
}
|
||
|
||
// 停止监控
|
||
function stopMonitoring() {
|
||
if (!currentDirectory) {
|
||
console.error('没有正在监控的目录');
|
||
showMessage('没有正在监控的目录', 'error');
|
||
return;
|
||
}
|
||
|
||
const stopBtn = document.getElementById('stopDirectoryMonitor');
|
||
if (!stopBtn) return;
|
||
|
||
stopBtn.disabled = true;
|
||
stopBtn.textContent = '正在停止...';
|
||
|
||
// 先清理定时器
|
||
if (updateInterval) {
|
||
clearInterval(updateInterval);
|
||
updateInterval = null;
|
||
}
|
||
|
||
const directoryToStop = currentDirectory;
|
||
|
||
fetch('/monitor/stop-directory-monitor/', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRFToken': getCSRFToken(),
|
||
},
|
||
body: JSON.stringify({ directory: directoryToStop })
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success') {
|
||
cleanupMonitoringState();
|
||
showMessage('监控已停止', 'success');
|
||
} else {
|
||
throw new Error(data.message || '停止监控失败');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('停止监控失败:', error);
|
||
showMessage(error.message || '停止监控失败', 'error');
|
||
stopBtn.disabled = false;
|
||
})
|
||
.finally(() => {
|
||
stopBtn.textContent = '停止监控';
|
||
});
|
||
}
|
||
|
||
// 初始化图表
|
||
function initCharts() {
|
||
console.log('初始化图表');
|
||
cpuChart = echarts.init(document.getElementById('cpuChart'));
|
||
memoryChart = echarts.init(document.getElementById('memoryChart'));
|
||
gpuChart = echarts.init(document.getElementById('gpuChart'));
|
||
|
||
const baseOption = {
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
formatter: function(params) {
|
||
const time = new Date(params[0].value[0]).toLocaleTimeString();
|
||
return `${time}<br/>${params[0].seriesName}: ${params[0].value[1].toFixed(2)}%`;
|
||
}
|
||
},
|
||
xAxis: {
|
||
type: 'time',
|
||
splitLine: { show: false }
|
||
},
|
||
yAxis: {
|
||
type: 'value',
|
||
min: 0,
|
||
max: 100,
|
||
splitLine: { show: true }
|
||
},
|
||
grid: {
|
||
left: '3%',
|
||
right: '4%',
|
||
bottom: '3%',
|
||
containLabel: true
|
||
},
|
||
series: [{
|
||
type: 'line',
|
||
showSymbol: false,
|
||
data: [],
|
||
smooth: true,
|
||
areaStyle: {
|
||
opacity: 0.1
|
||
}
|
||
}]
|
||
};
|
||
|
||
cpuChart.setOption({
|
||
...baseOption,
|
||
series: [{
|
||
...baseOption.series[0],
|
||
name: 'CPU使用率',
|
||
itemStyle: { color: '#2196F3' }
|
||
}]
|
||
});
|
||
|
||
memoryChart.setOption({
|
||
...baseOption,
|
||
series: [{
|
||
...baseOption.series[0],
|
||
name: '内存使用量',
|
||
itemStyle: { color: '#4CAF50' }
|
||
}]
|
||
});
|
||
|
||
gpuChart.setOption({
|
||
...baseOption,
|
||
series: [{
|
||
...baseOption.series[0],
|
||
name: 'GPU使用率',
|
||
itemStyle: { color: '#FF5722' }
|
||
}]
|
||
});
|
||
}
|
||
|
||
// 更新图表数据
|
||
function updateCharts(process) {
|
||
console.log('更新图表:', process);
|
||
const now = new Date();
|
||
|
||
// 更新CPU图表
|
||
if (cpuChart) {
|
||
updateChartData(cpuChart, now, process.cpu_usage);
|
||
}
|
||
|
||
// 更新内存图表
|
||
if (memoryChart) {
|
||
updateChartData(memoryChart, now, process.memory_usage);
|
||
}
|
||
|
||
// 更新GPU图表
|
||
if (gpuChart && process.gpu_info) {
|
||
updateChartData(gpuChart, now, process.gpu_info.usage);
|
||
}
|
||
}
|
||
|
||
// 辅助函数:更新图表数据
|
||
function updateChartData(chart, time, value) {
|
||
if (!chart) return;
|
||
|
||
try {
|
||
const option = chart.getOption();
|
||
const data = option.series[0].data || [];
|
||
data.push([time, value]);
|
||
|
||
// 保持最近60个数据点
|
||
if (data.length > 60) {
|
||
data.shift();
|
||
}
|
||
|
||
chart.setOption({
|
||
series: [{
|
||
data: data
|
||
}]
|
||
});
|
||
} catch (error) {
|
||
console.error('更新图表数据失败:', error);
|
||
}
|
||
}
|
||
|
||
// 修改更新进程表格函数
|
||
function updateProcessTable(processes) {
|
||
console.log('更新进程表格:', processes); // 调试日志
|
||
const table = document.getElementById('processTable');
|
||
if (!table) {
|
||
console.error('找不到进程表格元素');
|
||
return;
|
||
}
|
||
|
||
if (!processes || processes.length === 0) {
|
||
table.innerHTML = `
|
||
<tr>
|
||
<td colspan="7" class="text-center">暂无进程数据</td>
|
||
</tr>
|
||
`;
|
||
return;
|
||
}
|
||
|
||
table.innerHTML = processes.map(proc => `
|
||
<tr class="${selectedPid && selectedPid == proc.pid ? 'table-primary' : ''}">
|
||
<td>${proc.pid}</td>
|
||
<td>${proc.name}</td>
|
||
<td>
|
||
<div class="d-flex align-items-center">
|
||
<div class="progress flex-grow-1" style="height: 6px;">
|
||
<div class="progress-bar" role="progressbar"
|
||
style="width: ${proc.cpu_usage}%;"
|
||
aria-valuenow="${proc.cpu_usage}"
|
||
aria-valuemin="0"
|
||
aria-valuemax="100">
|
||
</div>
|
||
</div>
|
||
<span class="ms-2">${proc.cpu_usage.toFixed(1)}%</span>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<div class="d-flex align-items-center">
|
||
<div class="progress flex-grow-1" style="height: 6px;">
|
||
<div class="progress-bar bg-success" role="progressbar"
|
||
style="width: ${(proc.memory_usage/1000)*100}%;"
|
||
aria-valuenow="${proc.memory_usage}"
|
||
aria-valuemin="0"
|
||
aria-valuemax="100">
|
||
</div>
|
||
</div>
|
||
<span class="ms-2">${proc.memory_usage.toFixed(1)} MB</span>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<div class="d-flex align-items-center">
|
||
<div class="progress flex-grow-1" style="height: 6px;">
|
||
<div class="progress-bar bg-warning" role="progressbar"
|
||
style="width: ${proc.gpu_info.usage}%;"
|
||
aria-valuenow="${proc.gpu_info.usage}"
|
||
aria-valuemin="0"
|
||
aria-valuemax="100">
|
||
</div>
|
||
</div>
|
||
<span class="ms-2">${proc.gpu_info.usage}%</span>
|
||
</div>
|
||
</td>
|
||
<td>${proc.gpu_info.memory.toFixed(1)} MB</td>
|
||
<td>
|
||
<span class="badge bg-success">运行中</span>
|
||
<button class="btn btn-sm btn-outline-primary ms-2"
|
||
onclick="selectProcess(${proc.pid})">
|
||
查看详情
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
// 修改选择进程的函数
|
||
function selectProcess(pid) {
|
||
console.log('选择进程:', pid);
|
||
selectedPid = pid.toString(); // 确保转换为字符串
|
||
|
||
// 更新选择器
|
||
const selector = document.getElementById('processSelector');
|
||
if (selector) {
|
||
selector.value = selectedPid;
|
||
}
|
||
|
||
// 更新表格中的选中状态
|
||
const rows = document.querySelectorAll('#processTable tr');
|
||
rows.forEach(row => {
|
||
if (row.cells && row.cells[0] && row.cells[0].textContent === selectedPid) {
|
||
row.classList.add('table-primary');
|
||
} else {
|
||
row.classList.remove('table-primary');
|
||
}
|
||
});
|
||
|
||
// 获取最新数据并更新图表
|
||
if (currentDirectory) {
|
||
fetch(`/monitor/directory-status/?directory=${encodeURIComponent(currentDirectory)}`)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success' && data.processes) {
|
||
const selectedProcess = data.processes.find(p => p.pid.toString() === selectedPid);
|
||
if (selectedProcess) {
|
||
// 更新图表
|
||
updateCharts(selectedProcess);
|
||
// 更新详细信息
|
||
updateProcessDetails(selectedProcess);
|
||
}
|
||
}
|
||
})
|
||
.catch(error => console.error('获取进程详情失败:', error));
|
||
}
|
||
}
|
||
|
||
// 修改进程选择器更新函数
|
||
function updateProcessSelector(processes) {
|
||
console.log('更新进程选择器,进程列表:', processes); // 调试日志
|
||
|
||
const selector = document.getElementById('processSelector');
|
||
const processInfo = document.getElementById('selectedProcessInfo');
|
||
|
||
if (!selector) {
|
||
console.error('找不到进程选择器元素');
|
||
return;
|
||
}
|
||
|
||
// 启用选择器
|
||
selector.disabled = false;
|
||
|
||
// 获取当前的进程列表
|
||
const currentPids = processes.map(p => p.pid.toString());
|
||
console.log('当前PID列表:', currentPids); // 调试日志
|
||
|
||
// 如果当前选中的进程不在列表中,清除选择
|
||
if (selectedPid && !currentPids.includes(selectedPid.toString())) {
|
||
console.log('选中的进程不再存在,清除选择'); // 调试日志
|
||
selectedPid = null;
|
||
clearCharts();
|
||
}
|
||
|
||
// 移除旧的事件监听器
|
||
const newSelector = selector.cloneNode(true);
|
||
selector.parentNode.replaceChild(newSelector, selector);
|
||
|
||
// 更新选择器选项
|
||
newSelector.innerHTML = `
|
||
<option value="">选择要监控的进程</option>
|
||
${processes.map(proc => `
|
||
<option value="${proc.pid}" ${proc.pid.toString() === selectedPid ? 'selected' : ''}>
|
||
PID: ${proc.pid} - ${proc.name} (CPU: ${proc.cpu_usage.toFixed(2)}%)
|
||
</option>
|
||
`).join('')}
|
||
`;
|
||
|
||
// 添加新的事件监听器
|
||
newSelector.addEventListener('change', function() {
|
||
console.log('进程选择变更:', this.value);
|
||
selectedPid = this.value;
|
||
if (selectedPid) {
|
||
const selected = processes.find(p => p.pid === parseInt(selectedPid));
|
||
if (selected) {
|
||
processInfo.textContent = `监控中: PID ${selected.pid} - ${selected.name}`;
|
||
updateProcessDetails(selected); // 更新详细信息
|
||
clearCharts();
|
||
}
|
||
} else {
|
||
processInfo.textContent = '未选择进程';
|
||
clearCharts();
|
||
// 清空详细信息
|
||
['basicInfo', 'resourceInfo', 'networkInfo', 'fileInfo'].forEach(id => {
|
||
document.getElementById(id).innerHTML = '<p>选择进程查看详细信息</p>';
|
||
});
|
||
}
|
||
});
|
||
|
||
console.log('进程选择器更新完成'); // 调试日志
|
||
}
|
||
|
||
// 添加清除图表数据函数
|
||
function clearCharts() {
|
||
const emptyOption = {
|
||
series: [{
|
||
data: []
|
||
}]
|
||
};
|
||
cpuChart.setOption(emptyOption);
|
||
memoryChart.setOption(emptyOption);
|
||
gpuChart.setOption(emptyOption);
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
console.log('DOM加载完成,开始初始化');
|
||
|
||
const startBtn = document.getElementById('startDirectoryMonitor');
|
||
const stopBtn = document.getElementById('stopDirectoryMonitor');
|
||
|
||
if (!startBtn || !stopBtn) {
|
||
console.error('找不到监控按钮元素');
|
||
return;
|
||
}
|
||
|
||
// 初始化图表
|
||
initCharts();
|
||
|
||
// 开始监控按钮事件
|
||
startBtn.addEventListener('click', function() {
|
||
console.log('点击了开始监控按钮');
|
||
const directory = document.getElementById('directoryInput').value;
|
||
const statusDiv = document.getElementById('directoryMonitorStatus');
|
||
|
||
if (!directory) {
|
||
statusDiv.style.display = 'block';
|
||
statusDiv.className = 'alert alert-warning';
|
||
statusDiv.textContent = '请输入目录路径';
|
||
return;
|
||
}
|
||
|
||
// 显示加载状态
|
||
startBtn.disabled = true;
|
||
startBtn.textContent = '启动中...';
|
||
statusDiv.style.display = 'block';
|
||
statusDiv.className = 'alert alert-info';
|
||
statusDiv.textContent = '正在启动监控...';
|
||
|
||
console.log('开始监控目录:', directory);
|
||
|
||
// 清除旧的选择
|
||
selectedPid = null;
|
||
clearCharts();
|
||
|
||
fetch('/monitor/scan-directory/', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({ directory: directory })
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
console.log('接口返回:', data);
|
||
if (data.status === 'success') {
|
||
currentDirectory = directory;
|
||
statusDiv.className = 'alert alert-success';
|
||
statusDiv.textContent = data.message;
|
||
startBtn.disabled = true;
|
||
stopBtn.disabled = false;
|
||
|
||
// 开始定期获取详细信息
|
||
if (updateInterval) {
|
||
clearInterval(updateInterval);
|
||
}
|
||
currentDirectory = directory;
|
||
getProcessDetails(directory); // 立即获取一次
|
||
updateInterval = setInterval(() => getProcessDetails(directory), 5000); // 每5秒更新一次
|
||
} else {
|
||
statusDiv.className = 'alert alert-danger';
|
||
statusDiv.textContent = data.message;
|
||
startBtn.disabled = false;
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('监控启动失败:', error);
|
||
statusDiv.className = 'alert alert-danger';
|
||
statusDiv.textContent = '启动监控失败: ' + error.message;
|
||
startBtn.disabled = false;
|
||
})
|
||
.finally(() => {
|
||
startBtn.textContent = '开始监控';
|
||
});
|
||
});
|
||
|
||
// 停止监控按钮事件
|
||
if (stopBtn) {
|
||
stopBtn.addEventListener('click', function() {
|
||
console.log('停止监控,当前目录:', currentDirectory);
|
||
|
||
// 检查是否有当前目录
|
||
if (!currentDirectory) {
|
||
console.error('没有正在监控的目录');
|
||
showMessage('没有正在监控的目录', 'error');
|
||
return;
|
||
}
|
||
|
||
// 禁用按钮,防止重复点击
|
||
stopBtn.disabled = true;
|
||
stopBtn.textContent = '正在停止...';
|
||
|
||
// 先清理定时器,防止继续发送请求
|
||
if (updateInterval) {
|
||
clearInterval(updateInterval);
|
||
updateInterval = null;
|
||
}
|
||
|
||
// 保存当前目录的副本
|
||
const directoryToStop = currentDirectory;
|
||
|
||
// 发送停止监控请求到服务器
|
||
fetch('/monitor/stop-directory-monitor/', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRFToken': getCSRFToken(),
|
||
},
|
||
body: JSON.stringify({
|
||
directory: directoryToStop,
|
||
timestamp: new Date().getTime() // 添加时间戳防止缓存
|
||
})
|
||
})
|
||
.then(response => {
|
||
if (!response.ok) {
|
||
throw new Error('Network response was not ok');
|
||
}
|
||
return response.json();
|
||
})
|
||
.then(data => {
|
||
console.log('停止监控响应:', data);
|
||
if (data.status === 'success') {
|
||
// 清理前端状态
|
||
cleanupMonitoringState();
|
||
// 显示成功消息
|
||
showMessage('监控已停止', 'success');
|
||
} else {
|
||
throw new Error(data.message || '停止监控失败');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('停止监控失败:', error);
|
||
showMessage(error.message || '停止监控请求失败', 'error');
|
||
// 恢复按钮状态
|
||
stopBtn.disabled = false;
|
||
stopBtn.textContent = '停止监控';
|
||
});
|
||
});
|
||
}
|
||
|
||
// 初始状态设置
|
||
stopBtn.disabled = true; // 初始状态下停止按钮禁用
|
||
console.log('初始化完成');
|
||
|
||
// 为每个监控按钮添加点击事件
|
||
monitorButtons.forEach(button => {
|
||
button.addEventListener('click', function() {
|
||
const pid = pidInput.value.trim();
|
||
const type = this.dataset.type; // 从按钮的 data-type 属性获取类型
|
||
|
||
if (!pid) {
|
||
alert('请输入进程ID');
|
||
return;
|
||
}
|
||
|
||
// 保存当前选择的监控类型
|
||
currentMonitorType = type;
|
||
console.log('设置监控类型为:', currentMonitorType);
|
||
|
||
fetch(`/monitor/start/?pid=${pid}&type=${type}`)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success') {
|
||
startMonitoring(pid);
|
||
// 禁用所有监控按钮
|
||
monitorButtons.forEach(btn => btn.disabled = true);
|
||
stopBtn.disabled = false;
|
||
pidInput.disabled = true;
|
||
} else {
|
||
alert(data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('启动监控失败:', error);
|
||
alert('启动监控失败');
|
||
});
|
||
});
|
||
});
|
||
|
||
// 获取自动检测按钮
|
||
const startAutoDetectBtn = document.getElementById('startAutoDetectBtn');
|
||
const stopAutoDetectBtn = document.getElementById('stopAutoDetectBtn');
|
||
|
||
// 获取CSRF Token
|
||
function getCSRFToken() {
|
||
const name = 'csrftoken';
|
||
let cookieValue = null;
|
||
if (document.cookie && document.cookie !== '') {
|
||
const cookies = document.cookie.split(';');
|
||
for (let i = 0; i < cookies.length; i++) {
|
||
const cookie = cookies[i].trim();
|
||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return cookieValue;
|
||
}
|
||
|
||
// 添加自动检测开始按钮事件
|
||
startAutoDetectBtn.addEventListener('click', function() {
|
||
fetch('/auto_detect/', {
|
||
method: 'POST',
|
||
headers: {
|
||
'X-CSRFToken': getCSRFToken(),
|
||
'Content-Type': 'application/json'
|
||
}
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success') {
|
||
alert('已开始自动检测高资源进程');
|
||
startAutoDetectBtn.disabled = true;
|
||
stopAutoDetectBtn.disabled = false;
|
||
} else {
|
||
alert(data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('启动自动检测失败:', error);
|
||
alert('启动自动检测失败');
|
||
});
|
||
});
|
||
|
||
// 添加自动检测停止按钮事件
|
||
stopAutoDetectBtn.addEventListener('click', function() {
|
||
fetch('/stop_auto_detect/', {
|
||
method: 'POST',
|
||
headers: {
|
||
'X-CSRFToken': getCSRFToken(),
|
||
'Content-Type': 'application/json'
|
||
}
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status === 'success') {
|
||
alert('已停止自动检测');
|
||
startAutoDetectBtn.disabled = false;
|
||
stopAutoDetectBtn.disabled = true;
|
||
} else {
|
||
alert(data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('停止自动检测失败:', error);
|
||
alert('停止自动检测失败');
|
||
});
|
||
});
|
||
});
|
||
|
||
// 更新 UI 的函数
|
||
function updateUI(data, type) {
|
||
// 根据监控类型更新对应的表格
|
||
if (type === 'all' || type === 'cpu') {
|
||
document.getElementById('cpuTable').innerHTML = `
|
||
<tr><td>使用率</td><td>${data.cpu.usage}</td></tr>
|
||
<tr><td>用户态时间</td><td>${data.cpu.user_time}</td></tr>
|
||
<tr><td>内核态时间</td><td>${data.cpu.system_time}</td></tr>
|
||
<tr><td>CPU核心数</td><td>${data.cpu.cores}</td></tr>
|
||
<tr><td>CPU频率</td><td>${data.cpu.frequency}</td></tr>
|
||
<tr><td>上下文切换</td><td>${data.cpu.context_switches}</td></tr>
|
||
`;
|
||
document.getElementById('cpuStatus').className = 'badge bg-success status-badge';
|
||
document.getElementById('cpuStatus').textContent = '监控中';
|
||
}
|
||
|
||
if (type === 'all' || type === 'memory') {
|
||
document.getElementById('memoryTable').innerHTML = `
|
||
<tr><td>物理内存</td><td>${data.memory.physical}</td></tr>
|
||
<tr><td>虚拟内存</td><td>${data.memory.virtual}</td></tr>
|
||
<tr><td>内存映射</td><td>${data.memory.mappings}</td></tr>
|
||
<tr><td>系统内存使用</td><td>${data.memory.system_usage}</td></tr>
|
||
<tr><td>交换空间使用</td><td>${data.memory.swap_usage}</td></tr>
|
||
`;
|
||
document.getElementById('memoryStatus').className = 'badge bg-success status-badge';
|
||
document.getElementById('memoryStatus').textContent = '监控中';
|
||
}
|
||
|
||
if (type === 'all' || type === 'gpu') {
|
||
document.getElementById('gpuTable').innerHTML = `
|
||
<tr><td>使用率</td><td>${data.gpu.usage}</td></tr>
|
||
<tr><td>显存使用</td><td>${data.gpu.memory}</td></tr>
|
||
`;
|
||
document.getElementById('gpuStatus').className = 'badge bg-success status-badge';
|
||
document.getElementById('gpuStatus').textContent = '监控中';
|
||
}
|
||
|
||
// 更新最后更新时间
|
||
document.getElementById('lastUpdate').textContent =
|
||
`最后更新: ${data.timestamp}`;
|
||
}
|
||
|
||
// 添加错误处理函数
|
||
function handleError(error, message) {
|
||
console.error(message, error);
|
||
['cpu', 'gpu', 'memory'].forEach(type => {
|
||
const statusElement = document.getElementById(`${type}Status`);
|
||
if (statusElement) {
|
||
statusElement.className = 'badge bg-danger status-badge';
|
||
statusElement.textContent = '错误';
|
||
}
|
||
});
|
||
alert(message);
|
||
}
|
||
|
||
// 窗口大小改变时调整图表大小
|
||
window.addEventListener('resize', function() {
|
||
if (cpuChart) cpuChart.resize();
|
||
if (memoryChart) memoryChart.resize();
|
||
if (gpuChart) gpuChart.resize();
|
||
});
|
||
|
||
// 更新进程详细信息的函数
|
||
function updateProcessDetails(process) {
|
||
if (!process) return;
|
||
|
||
// 检查元素是否存在
|
||
const basicInfo = document.getElementById('basicInfo');
|
||
const resourceInfo = document.getElementById('resourceInfo');
|
||
|
||
if (!basicInfo || !resourceInfo) {
|
||
console.error('找不到详情显示元素');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 更新基本信息
|
||
basicInfo.innerHTML = `
|
||
<dl class="row mb-0">
|
||
<dt class="col-sm-4">PID</dt>
|
||
<dd class="col-sm-8">${process.pid}</dd>
|
||
|
||
<dt class="col-sm-4">进程名</dt>
|
||
<dd class="col-sm-8">${process.name}</dd>
|
||
|
||
<dt class="col-sm-4">命令行</dt>
|
||
<dd class="col-sm-8"><small class="text-muted">${process.command_line}</small></dd>
|
||
|
||
<dt class="col-sm-4">工作目录</dt>
|
||
<dd class="col-sm-8"><small class="text-muted">${process.working_directory}</small></dd>
|
||
|
||
<dt class="col-sm-4">创建时间</dt>
|
||
<dd class="col-sm-8">${process.create_time}</dd>
|
||
</dl>
|
||
`;
|
||
|
||
// 更新资源信息
|
||
resourceInfo.innerHTML = `
|
||
<dl class="row mb-0">
|
||
<dt class="col-sm-4">CPU使用率</dt>
|
||
<dd class="col-sm-8">${process.cpu_usage.toFixed(2)}%</dd>
|
||
|
||
<dt class="col-sm-4">内存使用</dt>
|
||
<dd class="col-sm-8">${process.memory_usage.toFixed(2)} MB</dd>
|
||
|
||
<dt class="col-sm-4">线程数</dt>
|
||
<dd class="col-sm-8">${process.threads}</dd>
|
||
|
||
<dt class="col-sm-4">GPU使用率</dt>
|
||
<dd class="col-sm-8">${process.gpu_info.usage}%</dd>
|
||
|
||
<dt class="col-sm-4">GPU内存</dt>
|
||
<dd class="col-sm-8">${process.gpu_info.memory.toFixed(2)} MB</dd>
|
||
</dl>
|
||
`;
|
||
} catch (error) {
|
||
console.error('更新进程详情失败:', error);
|
||
}
|
||
}
|
||
|
||
// 修改定期更新函数
|
||
function startPeriodicUpdate(directory) {
|
||
console.log('开始定期更新, 目录:', directory);
|
||
|
||
if (updateInterval) {
|
||
clearInterval(updateInterval);
|
||
}
|
||
|
||
// 立即执行一次更新
|
||
getProcessDetails(directory);
|
||
|
||
// 设置定时更新
|
||
updateInterval = setInterval(() => {
|
||
getProcessDetails(directory);
|
||
}, 5000);
|
||
}
|
||
|
||
// 修改获取进程详情的函数
|
||
function getProcessDetails(directory) {
|
||
if (!directory || !currentDirectory) { // 添加currentDirectory检查
|
||
console.log('没有目录或已停止监控');
|
||
return;
|
||
}
|
||
|
||
// 使用 AbortController 来控制fetch请求
|
||
if (window.currentFetch) {
|
||
window.currentFetch.abort();
|
||
}
|
||
window.currentFetch = new AbortController();
|
||
|
||
fetch(`/monitor/directory-status/?directory=${encodeURIComponent(directory)}`, {
|
||
signal: window.currentFetch.signal
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (!currentDirectory) { // 再次检查是否已停止监控
|
||
console.log('监控已停止,不更新数据');
|
||
return;
|
||
}
|
||
|
||
console.log('收到进程数据:', data);
|
||
if (data.status === 'success' && data.processes && data.processes.length > 0) {
|
||
updateProcessTable(data.processes);
|
||
|
||
if (selectedPid) {
|
||
const selectedProcess = data.processes.find(p => p.pid.toString() === selectedPid);
|
||
if (selectedProcess) {
|
||
updateCharts(selectedProcess);
|
||
updateProcessDetails(selectedProcess);
|
||
}
|
||
}
|
||
}
|
||
})
|
||
.catch(error => {
|
||
if (error.name === 'AbortError') {
|
||
console.log('请求被中止');
|
||
} else {
|
||
console.error('获取进程详情失败:', error);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 获取所有正在监控的进程ID
|
||
function getAllMonitoredPids() {
|
||
const table = document.getElementById('processTable');
|
||
if (!table) return [];
|
||
|
||
const pids = [];
|
||
const rows = table.getElementsByTagName('tr');
|
||
for (let row of rows) {
|
||
const firstCell = row.cells[0];
|
||
if (firstCell && !isNaN(firstCell.textContent)) {
|
||
pids.push(firstCell.textContent);
|
||
}
|
||
}
|
||
return pids;
|
||
}
|
||
|
||
// 修改清理监控状态的函数
|
||
function cleanupMonitoringState() {
|
||
console.log('清理监控状态');
|
||
|
||
// 先取消所有正在进行的请求
|
||
if (window.currentFetch) {
|
||
window.currentFetch.abort();
|
||
window.currentFetch = null;
|
||
}
|
||
|
||
// 清除定时器
|
||
if (updateInterval) {
|
||
clearInterval(updateInterval);
|
||
updateInterval = null;
|
||
}
|
||
|
||
// 清除状态变量(在清理完其他内容后再清除)
|
||
const oldDirectory = currentDirectory;
|
||
currentDirectory = null;
|
||
selectedPid = null;
|
||
|
||
console.log('已清除的目录:', oldDirectory);
|
||
|
||
// 清空图表
|
||
clearCharts();
|
||
|
||
// 清空进程列表
|
||
const processTable = document.getElementById('processTable');
|
||
if (processTable) {
|
||
processTable.innerHTML = `
|
||
<tr>
|
||
<td colspan="8" class="text-center">未开始监控</td>
|
||
</tr>
|
||
`;
|
||
}
|
||
|
||
// 清空详细信息
|
||
const basicInfo = document.getElementById('basicInfo');
|
||
const resourceInfo = document.getElementById('resourceInfo');
|
||
|
||
if (basicInfo) {
|
||
basicInfo.innerHTML = '<p class="text-center text-muted">未选择进程</p>';
|
||
}
|
||
if (resourceInfo) {
|
||
resourceInfo.innerHTML = '<p class="text-center text-muted">未选择进程</p>';
|
||
}
|
||
|
||
// 更新按钮状态
|
||
const startBtn = document.getElementById('startDirectoryMonitor');
|
||
const stopBtn = document.getElementById('stopDirectoryMonitor');
|
||
if (startBtn) startBtn.disabled = false;
|
||
if (stopBtn) {
|
||
stopBtn.disabled = true;
|
||
stopBtn.textContent = '停止监控';
|
||
}
|
||
}
|
||
|
||
// 添加显示消息的函数
|
||
function showMessage(message, type = 'info') {
|
||
const statusDiv = document.getElementById('directoryMonitorStatus');
|
||
if (statusDiv) {
|
||
statusDiv.style.display = 'block';
|
||
statusDiv.className = `alert alert-${type}`;
|
||
statusDiv.textContent = message;
|
||
|
||
// 3秒后自动隐藏
|
||
setTimeout(() => {
|
||
statusDiv.style.display = 'none';
|
||
}, 3000);
|
||
}
|
||
} |