class SimulationMonitor extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.monitorStatus = {
isMonitoring: false,
lastError: null
};
this.systemInfo = null;
this.threadInfo = null;
this.statusCheckInterval = null;
this.chart = null;
this.chartInitialized = false;
}
connectedCallback() {
this.render();
// 等待组件完全加载
setTimeout(() => {
this.initializeComponent();
}, 100);
}
initializeComponent() {
if (this.chartInitialized) return;
try {
this.initChart();
this.startStatusCheck();
this.chartInitialized = true;
} catch (error) {
console.error('初始化组件失败:', error);
}
}
disconnectedCallback() {
this.stopStatusCheck();
}
startStatusCheck() {
this.checkMonitorStatus();
this.statusCheckInterval = setInterval(() => {
this.checkMonitorStatus();
}, 1000);
}
stopStatusCheck() {
if (this.statusCheckInterval) {
clearInterval(this.statusCheckInterval);
this.statusCheckInterval = null;
}
}
async checkMonitorStatus() {
try {
// 获取监控状态
const statusResponse = await fetch('/api/system-monitor/status');
const statusData = await statusResponse.json();
this.monitorStatus = statusData;
if (this.monitorStatus.isMonitoring) {
// 获取系统信息
const systemResponse = await fetch('/api/system-monitor/system-info');
const systemData = await systemResponse.json();
this.systemInfo = systemData.data;
// 获取线程信息
const threadResponse = await fetch('/api/system-monitor/thread-info');
const threadData = await threadResponse.json();
this.threadInfo = threadData.data;
}
this.updateUI();
} catch (error) {
console.error('获取监控状态失败:', error);
this.monitorStatus.lastError = error.message;
this.updateUI();
}
}
getStatusDisplay(status) {
switch (status) {
case 0:
return { text: '未运行', color: '#999999' };
case 1:
return { text: '运行中', color: '#4CAF50' };
case 2:
return { text: '暂停中', color: '#FF9800' };
case 3:
return { text: '错误', color: '#f44336' };
default:
return { text: '未知状态', color: '#f44336' };
}
}
getCoreStatusDisplay(status) {
switch (status) {
case 0:
return { text: '未加载', color: '#999999' };
case 1:
return { text: '初始化完成', color: '#FFC107' };
case 2:
return { text: '正常', color: '#4CAF50' };
case 3:
return { text: '异常', color: '#f44336' };
default:
return { text: '未知状态', color: '#f44336' };
}
}
getThreadStatusDisplay(status) {
switch (status) {
case 0:
return { text: '未运行', color: '#999999' };
case 1:
return { text: '运行中', color: '#4CAF50' };
case 2:
return { text: '暂停中', color: '#FF9800' };
case 3:
return { text: '错误', color: '#f44336' };
default:
return { text: '未知状态', color: '#f44336' };
}
}
updateUI() {
const input = this.shadowRoot.querySelector('.domain-input');
const startButton = this.shadowRoot.querySelector('.start-button');
const stopButton = this.shadowRoot.querySelector('.stop-button');
const statusDisplay = this.shadowRoot.querySelector('.status-display');
const engineInfo = this.shadowRoot.querySelector('#engine-info');
const coreStatus = this.shadowRoot.querySelector('#core-status');
const threadTableBody = this.shadowRoot.querySelector('#thread-table-body');
if (this.monitorStatus.isMonitoring) {
input.disabled = true;
startButton.disabled = true;
stopButton.disabled = false;
} else {
input.disabled = false;
startButton.disabled = false;
stopButton.disabled = true;
}
// 更新状态显示
statusDisplay.textContent = `监控状态: ${this.monitorStatus.isMonitoring ? '运行中' : '已停止'}`;
if (this.monitorStatus.lastError) {
statusDisplay.textContent += ` (错误: ${this.monitorStatus.lastError})`;
}
// 更新引擎信息
const engineInfoFields = [
{ label: '引擎名称', key: 'name' },
{ label: '引擎ID', key: 'id' },
{ label: '引擎状态', key: 'status' },
{ label: '引擎亲和性', key: 'affinity' },
{ label: '线程数', key: 'threadCount' }
];
engineInfo.innerHTML = `
${engineInfoFields.map(field => {
let value = '未知';
let color = '#666';
if (this.monitorStatus.isMonitoring && this.systemInfo?.engineInfo) {
if (field.key === 'status') {
const status = this.systemInfo.engineInfo[field.key];
const statusInfo = this.getStatusDisplay(status);
value = statusInfo.text;
color = statusInfo.color;
} else {
value = this.systemInfo.engineInfo[field.key] || '未知';
}
} else if (field.key === 'status') {
const statusInfo = this.getStatusDisplay(0);
value = statusInfo.text;
color = statusInfo.color;
}
return `
`;
}).join('')}
`;
// 更新核心状态
const coreStatusFields = [
{ label: '主框架状态', key: 'fw' },
{ label: '时间管理器状态', key: 'tm' },
{ label: '事件管理器状态', key: 'em' },
{ label: '环境管理器状态', key: 'sd' },
{ label: '线程管理器状态', key: 'thm' },
{ label: '模型管理器状态', key: 'mm' },
{ label: '服务管理器状态', key: 'sm' },
{ label: 'DDS管理器状态', key: 'dm' }
];
// 确保coreStatus元素存在
if (!coreStatus) {
console.error('找不到核心状态元素');
return;
}
// 无论是否有数据,都显示状态项
coreStatus.innerHTML = `
${coreStatusFields.map(field => {
const status = this.monitorStatus.isMonitoring && this.systemInfo?.coreStatus ?
this.systemInfo.coreStatus[field.key] : 0;
const statusInfo = this.getCoreStatusDisplay(status);
return `
${field.label}
${statusInfo.text}
`;
}).join('')}
`;
// 更新线程表格
if (this.monitorStatus.isMonitoring && this.threadInfo && Array.isArray(this.threadInfo)) {
threadTableBody.innerHTML = this.threadInfo.map(thread => {
const statusInfo = this.getThreadStatusDisplay(thread.status);
return `
${thread.name || '未知'} |
${thread.id || '未知'} |
${statusInfo.text} |
${thread.priority || '未知'} |
${thread.runCount || '0'} |
${(thread.setFrequency || 0).toFixed(2)} |
${(thread.avgFrequency || 0).toFixed(2)} |
${(thread.maxFrequency || 0).toFixed(2)} |
${(thread.minFrequency || 0).toFixed(2)} |
${(thread.setPeriod || 0).toFixed(2)} |
${(thread.avgPeriod || 0).toFixed(2)} |
${(thread.maxPeriod || 0).toFixed(2)} |
${(thread.minPeriod || 0).toFixed(2)} |
`;
}).join('');
// 更新图表数据
this.updateChartData();
} else {
threadTableBody.innerHTML = '暂无线程信息 |
';
// 清空图表数据
if (this.chart) {
this.chart.data.labels = [];
this.chart.data.datasets = [];
this.chart.update();
}
}
}
async startMonitoring() {
const domainId = this.shadowRoot.querySelector('.domain-input').value.trim();
// 验证域ID是否为有效的数字字符串
if (!/^\d+$/.test(domainId)) {
console.error('域ID必须是有效的数字');
return;
}
try {
// 首先检查DDS监控状态
const ddsStatusResponse = await fetch('/api/dds-monitor/status');
const ddsStatusData = await ddsStatusResponse.json();
// 如果DDS监控未初始化,先初始化DDS监控
if (!ddsStatusData.isInitialized) {
const ddsInitResponse = await fetch('/api/dds-monitor/initialize', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ domainId })
});
if (!ddsInitResponse.ok) {
const errorData = await ddsInitResponse.json();
console.error('DDS监控初始化失败:', errorData.error);
return;
}
}
// 启动系统监控
const response = await fetch('/api/system-monitor/start', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ domainId })
});
const data = await response.json();
if (response.ok) {
this.monitorStatus = data.status;
this.updateUI();
} else {
console.error('启动监控失败:', data.error);
}
} catch (error) {
console.error('启动监控失败:', error);
}
}
async stopMonitoring() {
try {
const response = await fetch('/api/system-monitor/stop', {
method: 'POST'
});
const data = await response.json();
if (response.ok) {
this.monitorStatus = data.status;
this.updateUI();
} else {
console.error('停止监控失败:', data.error);
}
} catch (error) {
console.error('停止监控失败:', error);
}
}
render() {
this.shadowRoot.innerHTML = `
线程信息
线程名称 |
线程ID |
状态 |
优先级 |
运行次数 |
设定频率(Hz) |
平均频率(Hz) |
最大频率(Hz) |
最小频率(Hz) |
设定周期(ms) |
平均周期(ms) |
最大周期(ms) |
最小周期(ms) |
`;
}
initChart() {
const chartElement = this.shadowRoot.querySelector('#thread-chart');
if (!chartElement) {
console.error('找不到图表元素');
return;
}
// 确保 Chart.js 已加载
if (typeof Chart === 'undefined') {
console.error('Chart.js 未加载');
return;
}
try {
// 创建图表实例
const ctx = chartElement.getContext('2d');
if (!ctx) {
console.error('无法获取 canvas 上下文');
return;
}
// 销毁已存在的图表实例
if (this.chart) {
this.chart.destroy();
}
// 创建新的图表实例
this.chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: []
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
},
animation: false,
plugins: {
legend: {
display: true
},
tooltip: {
enabled: false
}
}
}
});
// 监听显示类型切换
const switchInput = this.shadowRoot.querySelector('#display-type-switch');
const displayTypeLabel = this.shadowRoot.querySelector('#display-type-label');
if (switchInput && displayTypeLabel) {
switchInput.addEventListener('change', (e) => {
const isFrequency = e.target.checked;
displayTypeLabel.textContent = isFrequency ? '频率' : '周期';
this.updateChartDisplayType(isFrequency);
});
}
} catch (error) {
console.error('初始化图表失败:', error);
this.chart = null;
}
}
updateChartData() {
if (!this.chart || !this.threadInfo || !Array.isArray(this.threadInfo)) return;
const isFrequency = this.shadowRoot.querySelector('#display-type-switch').checked;
const currentTime = new Date().toLocaleTimeString();
// 确保图表数据集存在
if (!this.chart.data.datasets || this.chart.data.datasets.length === 0) {
this.updateChartDisplayType(isFrequency);
}
// 更新数据
const newData = {
labels: [...this.chart.data.labels, currentTime].slice(-30),
datasets: this.threadInfo.map((thread, index) => {
const dataset = this.chart.data.datasets[index] || {
label: thread.name,
data: [],
borderColor: this.getRandomColor(),
fill: false
};
const value = isFrequency ? (thread.currentFrequency || 0) : (thread.currentPeriod || 0);
dataset.data = [...dataset.data, value].slice(-30);
return dataset;
})
};
// 使用新数据更新图表
this.chart.data = newData;
this.chart.update('none'); // 使用 'none' 模式更新,避免触发动画和事件
}
updateChartDisplayType(isFrequency) {
if (!this.threadInfo) return;
const datasets = this.threadInfo.map(thread => ({
label: thread.name,
data: [],
borderColor: this.getRandomColor(),
fill: false
}));
this.chart.data.datasets = datasets;
this.chart.update('none'); // 使用 'none' 模式更新
}
getRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
}
customElements.define('simulation-monitor', SimulationMonitor);