818 lines
27 KiB
JavaScript
818 lines
27 KiB
JavaScript
/**
|
|
* 仪表盘功能模块
|
|
* 提供主题切换、数据统计、系统状态监控等功能
|
|
*/
|
|
|
|
class DashboardManager {
|
|
constructor() {
|
|
this.refreshInterval = null;
|
|
this.timeInterval = null;
|
|
this.activities = [];
|
|
this.lastDataSnapshot = null;
|
|
|
|
this.init();
|
|
}
|
|
|
|
/**
|
|
* 初始化仪表盘
|
|
*/
|
|
init() {
|
|
console.log('初始化仪表盘管理器...');
|
|
|
|
// 初始化主题切换器
|
|
this.initializeThemeSwitcher();
|
|
|
|
// 更新当前时间
|
|
this.updateCurrentTime();
|
|
this.timeInterval = setInterval(() => this.updateCurrentTime(), 1000);
|
|
|
|
// 加载仪表盘数据
|
|
this.loadDashboardData();
|
|
|
|
// 绑定仪表盘事件
|
|
this.bindEvents();
|
|
|
|
// 添加活动记录
|
|
this.addActivity('仪表盘初始化成功', 'success');
|
|
|
|
// 设置自动刷新(30秒)
|
|
this.refreshInterval = setInterval(() => this.loadDashboardData(), 30000);
|
|
}
|
|
|
|
/**
|
|
* 主题切换器初始化
|
|
*/
|
|
initializeThemeSwitcher() {
|
|
const themeToggle = document.getElementById('theme-toggle');
|
|
if (!themeToggle) {
|
|
console.warn('主题切换器元素未找到');
|
|
return;
|
|
}
|
|
|
|
// 获取保存的主题或使用默认主题
|
|
const currentTheme = localStorage.getItem('theme') || 'light';
|
|
console.log('当前主题:', currentTheme);
|
|
|
|
// 应用主题
|
|
this.applyTheme(currentTheme);
|
|
|
|
// 设置切换器状态
|
|
themeToggle.checked = currentTheme === 'dark';
|
|
|
|
// 监听主题切换事件
|
|
themeToggle.addEventListener('change', (event) => {
|
|
const newTheme = event.target.checked ? 'dark' : 'light';
|
|
console.log('切换主题到:', newTheme);
|
|
|
|
this.applyTheme(newTheme);
|
|
localStorage.setItem('theme', newTheme);
|
|
|
|
// 添加活动记录
|
|
this.addActivity(`切换到${newTheme === 'dark' ? '暗色' : '明亮'}主题`, 'info');
|
|
});
|
|
|
|
console.log('主题切换器初始化完成');
|
|
}
|
|
|
|
/**
|
|
* 应用主题
|
|
*/
|
|
applyTheme(theme) {
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
|
|
// 更新元标签以支持系统主题
|
|
let themeColorMeta = document.querySelector('meta[name="theme-color"]');
|
|
if (!themeColorMeta) {
|
|
themeColorMeta = document.createElement('meta');
|
|
themeColorMeta.name = 'theme-color';
|
|
document.head.appendChild(themeColorMeta);
|
|
}
|
|
|
|
// 根据主题设置元标签颜色
|
|
if (theme === 'dark') {
|
|
themeColorMeta.content = '#1e293b';
|
|
} else {
|
|
themeColorMeta.content = '#ffffff';
|
|
}
|
|
|
|
console.log(`主题 ${theme} 已应用`);
|
|
}
|
|
|
|
/**
|
|
* 更新当前时间
|
|
*/
|
|
updateCurrentTime() {
|
|
const now = new Date();
|
|
const timeString = now.toLocaleString('zh-CN', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit'
|
|
});
|
|
|
|
const currentTimeElement = document.getElementById('current-time');
|
|
if (currentTimeElement) {
|
|
currentTimeElement.textContent = timeString;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 加载仪表盘数据
|
|
*/
|
|
async loadDashboardData() {
|
|
try {
|
|
console.log('开始加载仪表盘数据...');
|
|
|
|
// 显示加载状态
|
|
this.setLoadingState(true);
|
|
|
|
// 并行加载各种数据
|
|
const [devices, topology, credentials, activeConnections, terminalSessions] = await Promise.all([
|
|
this.fetchWithFallback('/api/devices', []),
|
|
this.fetchWithFallback('/api/topology', { nodes: {}, links: [] }),
|
|
this.fetchWithFallback('/api/credentials', []),
|
|
this.getActiveSessions(),
|
|
this.getTerminalSessions()
|
|
]);
|
|
|
|
console.log('数据加载完成:', {
|
|
devices: devices.length,
|
|
topology: Object.keys(topology.nodes || {}).length,
|
|
credentials: credentials.length,
|
|
activeConnections: activeConnections.length,
|
|
terminalSessions: terminalSessions.length
|
|
});
|
|
|
|
// 检测数据变化
|
|
const currentSnapshot = {
|
|
devicesCount: devices.length,
|
|
topologyCount: Object.keys(topology.nodes || {}).length,
|
|
credentialsCount: credentials.length,
|
|
connectionsCount: activeConnections.length,
|
|
sessionsCount: terminalSessions.length
|
|
};
|
|
|
|
// 如果有数据变化,记录活动
|
|
if (this.lastDataSnapshot) {
|
|
this.detectDataChanges(this.lastDataSnapshot, currentSnapshot);
|
|
}
|
|
|
|
this.lastDataSnapshot = currentSnapshot;
|
|
|
|
// 更新统计数据
|
|
this.updateDashboardStats(devices, topology, credentials, activeConnections, terminalSessions);
|
|
|
|
// 更新设备概览
|
|
this.updateDevicesOverview(devices);
|
|
|
|
// 检查系统状态
|
|
await this.checkSystemStatus();
|
|
|
|
} catch (error) {
|
|
console.error('加载仪表盘数据失败:', error);
|
|
this.addActivity('加载仪表盘数据失败', 'error');
|
|
} finally {
|
|
this.setLoadingState(false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检测数据变化
|
|
*/
|
|
detectDataChanges(oldSnapshot, newSnapshot) {
|
|
if (newSnapshot.devicesCount !== oldSnapshot.devicesCount) {
|
|
const change = newSnapshot.devicesCount - oldSnapshot.devicesCount;
|
|
this.addActivity(`设备数量${change > 0 ? '增加' : '减少'}${Math.abs(change)}个`, change > 0 ? 'success' : 'warning');
|
|
}
|
|
|
|
if (newSnapshot.topologyCount !== oldSnapshot.topologyCount) {
|
|
const change = newSnapshot.topologyCount - oldSnapshot.topologyCount;
|
|
this.addActivity(`拓扑节点${change > 0 ? '增加' : '减少'}${Math.abs(change)}个`, 'info');
|
|
}
|
|
|
|
if (newSnapshot.credentialsCount !== oldSnapshot.credentialsCount) {
|
|
const change = newSnapshot.credentialsCount - oldSnapshot.credentialsCount;
|
|
this.addActivity(`凭据${change > 0 ? '增加' : '减少'}${Math.abs(change)}个`, 'info');
|
|
}
|
|
|
|
if (newSnapshot.connectionsCount !== oldSnapshot.connectionsCount) {
|
|
const change = newSnapshot.connectionsCount - oldSnapshot.connectionsCount;
|
|
this.addActivity(`活跃连接${change > 0 ? '增加' : '减少'}${Math.abs(change)}个`, change > 0 ? 'success' : 'info');
|
|
}
|
|
|
|
if (newSnapshot.sessionsCount !== oldSnapshot.sessionsCount) {
|
|
const change = newSnapshot.sessionsCount - oldSnapshot.sessionsCount;
|
|
this.addActivity(`终端会话${change > 0 ? '增加' : '减少'}${Math.abs(change)}个`, change > 0 ? 'success' : 'info');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取活跃会话数
|
|
*/
|
|
async getActiveSessions() {
|
|
try {
|
|
// 首先尝试从后端API获取活跃连接
|
|
const response = await fetch('/api/connections/active');
|
|
if (response.ok) {
|
|
const connections = await response.json();
|
|
return connections || [];
|
|
}
|
|
} catch (error) {
|
|
console.warn('无法从API获取活跃连接:', error);
|
|
}
|
|
|
|
// 从全局会话管理器获取活跃会话
|
|
if (window.sessionManager && window.sessionManager.activeSessions) {
|
|
return Object.keys(window.sessionManager.activeSessions);
|
|
}
|
|
|
|
// 从终端管理器获取
|
|
if (window.terminalManager && window.terminalManager.terminals) {
|
|
return Object.keys(window.terminalManager.terminals);
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* 获取真正的终端会话数
|
|
*/
|
|
async getTerminalSessions() {
|
|
try {
|
|
// 尝试从终端管理器获取
|
|
if (window.terminalManager && window.terminalManager.terminals) {
|
|
return Object.keys(window.terminalManager.terminals);
|
|
}
|
|
|
|
// 尝试从会话管理器获取
|
|
if (window.sessionManager && window.sessionManager.activeSessions) {
|
|
return Object.keys(window.sessionManager.activeSessions);
|
|
}
|
|
|
|
// 尝试从DOM获取终端标签页数量
|
|
const terminalTabs = document.querySelectorAll('.terminal-tab');
|
|
if (terminalTabs.length > 0) {
|
|
return Array.from(terminalTabs).map((tab, index) => `terminal-${index}`);
|
|
}
|
|
|
|
return [];
|
|
} catch (error) {
|
|
console.warn('获取终端会话失败:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 带回退的网络请求
|
|
*/
|
|
async fetchWithFallback(url, fallback) {
|
|
try {
|
|
const response = await fetch(url);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
console.log(`API ${url} 请求成功:`, data);
|
|
return data;
|
|
} else {
|
|
console.warn(`API ${url} 请求失败 (${response.status}):`, response.statusText);
|
|
return fallback;
|
|
}
|
|
} catch (error) {
|
|
console.warn(`API ${url} 请求异常:`, error);
|
|
return fallback;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置加载状态
|
|
*/
|
|
setLoadingState(loading) {
|
|
const refreshBtn = document.getElementById('refresh-dashboard');
|
|
if (refreshBtn) {
|
|
if (loading) {
|
|
refreshBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 加载中';
|
|
refreshBtn.disabled = true;
|
|
} else {
|
|
refreshBtn.innerHTML = '<i class="fas fa-sync"></i> 刷新';
|
|
refreshBtn.disabled = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新仪表盘统计数据
|
|
*/
|
|
updateDashboardStats(devices, topology, credentials, activeConnections, terminalSessions) {
|
|
// 设备数量
|
|
const devicesCount = devices.length;
|
|
this.updateStatCard('dashboard-devices-count', devicesCount);
|
|
this.updateStatChange('dashboard-devices-change', `+${devicesCount}`);
|
|
|
|
// 活跃连接数(会话数)
|
|
const connectionsCount = activeConnections.length;
|
|
this.updateStatCard('dashboard-connections-count', connectionsCount);
|
|
this.updateStatChange('dashboard-connections-change', connectionsCount > 0 ? `+${connectionsCount}` : '0');
|
|
|
|
// 拓扑节点数
|
|
const topologyNodes = topology.nodes ? Object.keys(topology.nodes).length : 0;
|
|
this.updateStatCard('dashboard-topology-nodes', topologyNodes);
|
|
this.updateStatChange('dashboard-topology-change', `+${topologyNodes}`);
|
|
|
|
// 终端会话数(修正:之前错误地显示凭据数量)
|
|
const sessionsCount = terminalSessions.length;
|
|
this.updateStatCard('dashboard-sessions-count', sessionsCount);
|
|
this.updateStatChange('dashboard-sessions-change', `+${sessionsCount}`);
|
|
}
|
|
|
|
/**
|
|
* 更新统计卡片的数值
|
|
*/
|
|
updateStatCard(elementId, value) {
|
|
const element = document.getElementById(elementId);
|
|
if (element) {
|
|
const currentValue = parseInt(element.textContent) || 0;
|
|
const targetValue = parseInt(value) || 0;
|
|
|
|
if (currentValue !== targetValue) {
|
|
this.animateNumber(element, currentValue, targetValue, 500);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 更新统计变化指示器
|
|
*/
|
|
updateStatChange(elementId, value) {
|
|
const element = document.getElementById(elementId);
|
|
if (element) {
|
|
element.textContent = value;
|
|
|
|
// 根据值设置样式
|
|
element.className = 'stat-change';
|
|
if (value.startsWith('+') && value !== '+0') {
|
|
element.classList.add('positive');
|
|
} else if (value.startsWith('-')) {
|
|
element.classList.add('negative');
|
|
} else {
|
|
element.classList.add('neutral');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 数字动画效果
|
|
*/
|
|
animateNumber(element, start, end, duration) {
|
|
const startTime = performance.now();
|
|
|
|
const updateNumber = (currentTime) => {
|
|
const elapsed = currentTime - startTime;
|
|
const progress = Math.min(elapsed / duration, 1);
|
|
|
|
// 使用缓动函数
|
|
const easedProgress = 1 - Math.pow(1 - progress, 3);
|
|
const current = Math.round(start + (end - start) * easedProgress);
|
|
element.textContent = current;
|
|
|
|
if (progress < 1) {
|
|
requestAnimationFrame(updateNumber);
|
|
}
|
|
};
|
|
|
|
requestAnimationFrame(updateNumber);
|
|
}
|
|
|
|
/**
|
|
* 更新设备概览
|
|
*/
|
|
updateDevicesOverview(devices) {
|
|
const devicesOverview = document.getElementById('devices-overview');
|
|
if (!devicesOverview) return;
|
|
|
|
if (!devices || devices.length === 0) {
|
|
devicesOverview.innerHTML = `
|
|
<div class="no-devices">
|
|
<i class="fas fa-server"></i>
|
|
<p>暂无设备</p>
|
|
<button class="btn btn-sm" onclick="dashboardManager.goToDevices()">
|
|
<i class="fas fa-plus"></i> 添加设备
|
|
</button>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
// 显示前5个设备
|
|
const displayDevices = devices.slice(0, 5);
|
|
const deviceItems = displayDevices.map(device => `
|
|
<div class="device-overview-item" onclick="dashboardManager.goToDevices('${device.id}')" title="点击查看设备详情">
|
|
<div class="device-overview-icon">
|
|
<i class="fas fa-${this.getDeviceIcon(device.device_type)}"></i>
|
|
</div>
|
|
<div class="device-overview-info">
|
|
<div class="device-overview-name">${device.name}</div>
|
|
<div class="device-overview-details">${device.ip_address} • ${this.getVendorDisplayName(device.vendor)}</div>
|
|
</div>
|
|
<div class="device-overview-status ${device.status || 'unknown'}" title="状态: ${this.getStatusDisplayName(device.status)}"></div>
|
|
</div>
|
|
`).join('');
|
|
|
|
devicesOverview.innerHTML = deviceItems;
|
|
|
|
// 如果设备数量超过5个,显示"查看更多"
|
|
if (devices.length > 5) {
|
|
devicesOverview.innerHTML += `
|
|
<div class="device-overview-item" onclick="dashboardManager.goToDevices()" style="cursor: pointer;" title="查看所有设备">
|
|
<div class="device-overview-icon">
|
|
<i class="fas fa-ellipsis-h"></i>
|
|
</div>
|
|
<div class="device-overview-info">
|
|
<div class="device-overview-name">查看更多</div>
|
|
<div class="device-overview-details">还有 ${devices.length - 5} 个设备</div>
|
|
</div>
|
|
<div class="device-overview-status more-indicator"></div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取设备图标
|
|
*/
|
|
getDeviceIcon(deviceType) {
|
|
const icons = {
|
|
router: 'route',
|
|
switch: 'network-wired',
|
|
firewall: 'shield-alt',
|
|
wireless_controller: 'wifi',
|
|
access_point: 'broadcast-tower',
|
|
load_balancer: 'balance-scale',
|
|
server: 'server'
|
|
};
|
|
return icons[deviceType] || 'server';
|
|
}
|
|
|
|
/**
|
|
* 获取厂商显示名称
|
|
*/
|
|
getVendorDisplayName(vendor) {
|
|
const vendorNames = {
|
|
cisco: 'Cisco',
|
|
huawei: '华为',
|
|
h3c: 'H3C',
|
|
juniper: 'Juniper',
|
|
arista: 'Arista',
|
|
fortinet: 'Fortinet',
|
|
checkpoint: 'CheckPoint',
|
|
other: '其他'
|
|
};
|
|
return vendorNames[vendor] || vendor;
|
|
}
|
|
|
|
/**
|
|
* 获取状态显示名称
|
|
*/
|
|
getStatusDisplayName(status) {
|
|
const statusNames = {
|
|
online: '在线',
|
|
offline: '离线',
|
|
unreachable: '不可达',
|
|
maintenance: '维护中',
|
|
unknown: '未知'
|
|
};
|
|
return statusNames[status] || '未知';
|
|
}
|
|
|
|
/**
|
|
* 检查系统状态
|
|
*/
|
|
async checkSystemStatus() {
|
|
// 检查网络连接
|
|
await this.checkNetworkStatus();
|
|
|
|
// 检查数据库状态
|
|
await this.checkDatabaseStatus();
|
|
}
|
|
|
|
/**
|
|
* 检查网络状态
|
|
*/
|
|
async checkNetworkStatus() {
|
|
const statusIcon = document.getElementById('network-status');
|
|
const statusText = document.getElementById('network-status-text');
|
|
|
|
if (!statusIcon || !statusText) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/devices', {
|
|
method: 'HEAD',
|
|
signal: AbortSignal.timeout(5000) // 5秒超时
|
|
});
|
|
|
|
if (response.ok) {
|
|
statusIcon.className = 'status-icon online';
|
|
statusIcon.innerHTML = '<i class="fas fa-wifi"></i>';
|
|
statusText.textContent = '连接正常';
|
|
} else {
|
|
statusIcon.className = 'status-icon warning';
|
|
statusIcon.innerHTML = '<i class="fas fa-exclamation-triangle"></i>';
|
|
statusText.textContent = '连接异常';
|
|
}
|
|
} catch (error) {
|
|
statusIcon.className = 'status-icon offline';
|
|
statusIcon.innerHTML = '<i class="fas fa-times-circle"></i>';
|
|
statusText.textContent = '连接失败';
|
|
console.error('网络状态检查失败:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查数据库状态
|
|
*/
|
|
async checkDatabaseStatus() {
|
|
const statusIcon = document.getElementById('database-status');
|
|
const statusText = document.getElementById('database-status-text');
|
|
|
|
if (!statusIcon || !statusText) return;
|
|
|
|
try {
|
|
// 通过尝试加载设备列表来检查数据库状态
|
|
const response = await fetch('/api/devices', {
|
|
signal: AbortSignal.timeout(3000) // 3秒超时
|
|
});
|
|
|
|
if (response.ok) {
|
|
statusIcon.className = 'status-icon online';
|
|
statusIcon.innerHTML = '<i class="fas fa-check-circle"></i>';
|
|
statusText.textContent = '正常';
|
|
} else {
|
|
statusIcon.className = 'status-icon warning';
|
|
statusIcon.innerHTML = '<i class="fas fa-exclamation-triangle"></i>';
|
|
statusText.textContent = '异常';
|
|
}
|
|
} catch (error) {
|
|
statusIcon.className = 'status-icon offline';
|
|
statusIcon.innerHTML = '<i class="fas fa-times-circle"></i>';
|
|
statusText.textContent = '错误';
|
|
console.error('数据库状态检查失败:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 绑定事件
|
|
*/
|
|
bindEvents() {
|
|
// 刷新仪表盘按钮
|
|
const refreshBtn = document.getElementById('refresh-dashboard');
|
|
if (refreshBtn) {
|
|
refreshBtn.addEventListener('click', () => {
|
|
this.loadDashboardData();
|
|
this.addActivity('手动刷新仪表盘数据', 'info');
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加活动记录
|
|
*/
|
|
addActivity(text, type = 'info') {
|
|
const activitiesList = document.getElementById('recent-activities');
|
|
if (!activitiesList) return;
|
|
|
|
const now = new Date();
|
|
|
|
// 添加到内部数组
|
|
this.activities.unshift({ text, type, time: now });
|
|
|
|
// 限制活动数量
|
|
if (this.activities.length > 50) {
|
|
this.activities = this.activities.slice(0, 50);
|
|
}
|
|
|
|
const activityItem = document.createElement('div');
|
|
activityItem.className = 'activity-item';
|
|
activityItem.innerHTML = `
|
|
<div class="activity-icon ${type}">
|
|
<i class="fas fa-${this.getActivityIcon(type)}"></i>
|
|
</div>
|
|
<div class="activity-content">
|
|
<div class="activity-text">${text}</div>
|
|
<div class="activity-time">${this.getRelativeTime(now)}</div>
|
|
</div>
|
|
`;
|
|
|
|
// 插入到列表顶部
|
|
activitiesList.insertBefore(activityItem, activitiesList.firstChild);
|
|
|
|
// 限制显示的活动数量(最多保留10条显示)
|
|
const displayedActivities = activitiesList.querySelectorAll('.activity-item');
|
|
if (displayedActivities.length > 10) {
|
|
activitiesList.removeChild(displayedActivities[displayedActivities.length - 1]);
|
|
}
|
|
|
|
// 定期更新活动时间
|
|
setTimeout(() => this.updateActivityTimes(), 60000);
|
|
|
|
console.log(`活动记录: ${text} (${type})`);
|
|
}
|
|
|
|
/**
|
|
* 获取活动图标
|
|
*/
|
|
getActivityIcon(type) {
|
|
const icons = {
|
|
info: 'info-circle',
|
|
success: 'check-circle',
|
|
warning: 'exclamation-triangle',
|
|
error: 'times-circle'
|
|
};
|
|
return icons[type] || 'info-circle';
|
|
}
|
|
|
|
/**
|
|
* 获取相对时间
|
|
*/
|
|
getRelativeTime(date) {
|
|
const now = new Date();
|
|
const diff = now - date;
|
|
const seconds = Math.floor(diff / 1000);
|
|
const minutes = Math.floor(seconds / 60);
|
|
const hours = Math.floor(minutes / 60);
|
|
const days = Math.floor(hours / 24);
|
|
|
|
if (seconds < 60) return '刚刚';
|
|
if (minutes < 60) return `${minutes}分钟前`;
|
|
if (hours < 24) return `${hours}小时前`;
|
|
if (days < 7) return `${days}天前`;
|
|
return date.toLocaleDateString('zh-CN');
|
|
}
|
|
|
|
/**
|
|
* 更新活动时间显示
|
|
*/
|
|
updateActivityTimes() {
|
|
const timeElements = document.querySelectorAll('.activity-time');
|
|
timeElements.forEach((element, index) => {
|
|
if (this.activities[index]) {
|
|
element.textContent = this.getRelativeTime(this.activities[index].time);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 导航到设备页面
|
|
*/
|
|
goToDevices(deviceId = null) {
|
|
const devicesLink = document.querySelector('.nav-link[data-page="devices"]');
|
|
if (devicesLink) {
|
|
devicesLink.click();
|
|
|
|
// 如果指定了设备ID,在设备页面高亮该设备
|
|
if (deviceId) {
|
|
setTimeout(() => {
|
|
const deviceElement = document.getElementById(`device-${deviceId}`);
|
|
if (deviceElement) {
|
|
deviceElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
deviceElement.style.backgroundColor = 'var(--primary-color)';
|
|
deviceElement.style.color = 'white';
|
|
setTimeout(() => {
|
|
deviceElement.style.backgroundColor = '';
|
|
deviceElement.style.color = '';
|
|
}, 2000);
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
this.addActivity('跳转到设备管理页面', 'info');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 刷新系统状态
|
|
*/
|
|
refreshSystemStatus() {
|
|
this.checkSystemStatus();
|
|
this.addActivity('刷新系统状态', 'info');
|
|
}
|
|
|
|
/**
|
|
* 刷新设备概览
|
|
*/
|
|
refreshDevicesOverview() {
|
|
this.loadDashboardData();
|
|
this.addActivity('刷新设备概览', 'info');
|
|
}
|
|
|
|
/**
|
|
* 清空活动记录
|
|
*/
|
|
clearActivities() {
|
|
this.activities = [];
|
|
const activitiesList = document.getElementById('recent-activities');
|
|
if (activitiesList) {
|
|
activitiesList.innerHTML = `
|
|
<div class="activity-item">
|
|
<div class="activity-icon info">
|
|
<i class="fas fa-info-circle"></i>
|
|
</div>
|
|
<div class="activity-content">
|
|
<div class="activity-text">活动记录已清空</div>
|
|
<div class="activity-time">刚刚</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
console.log('活动记录已清空');
|
|
}
|
|
|
|
/**
|
|
* 销毁函数
|
|
*/
|
|
destroy() {
|
|
if (this.refreshInterval) {
|
|
clearInterval(this.refreshInterval);
|
|
this.refreshInterval = null;
|
|
}
|
|
if (this.timeInterval) {
|
|
clearInterval(this.timeInterval);
|
|
this.timeInterval = null;
|
|
}
|
|
console.log('仪表盘管理器已销毁');
|
|
}
|
|
}
|
|
|
|
// 全局仪表盘管理器实例
|
|
let dashboardManager = null;
|
|
|
|
// 初始化仪表盘的全局函数
|
|
function initializeDashboard() {
|
|
if (!dashboardManager) {
|
|
dashboardManager = new DashboardManager();
|
|
console.log('仪表盘管理器初始化完成');
|
|
}
|
|
return dashboardManager;
|
|
}
|
|
|
|
// 全局快捷函数
|
|
function goToDevices(deviceId = null) {
|
|
if (dashboardManager) {
|
|
dashboardManager.goToDevices(deviceId);
|
|
}
|
|
}
|
|
|
|
function refreshSystemStatus() {
|
|
if (dashboardManager) {
|
|
dashboardManager.refreshSystemStatus();
|
|
}
|
|
}
|
|
|
|
function refreshDevicesOverview() {
|
|
if (dashboardManager) {
|
|
dashboardManager.refreshDevicesOverview();
|
|
}
|
|
}
|
|
|
|
function clearActivities() {
|
|
if (dashboardManager) {
|
|
dashboardManager.clearActivities();
|
|
}
|
|
}
|
|
|
|
// 暴露到全局作用域
|
|
window.DashboardManager = DashboardManager;
|
|
window.initializeDashboard = initializeDashboard;
|
|
window.dashboardManager = dashboardManager;
|
|
window.goToDevices = goToDevices;
|
|
window.refreshSystemStatus = refreshSystemStatus;
|
|
window.refreshDevicesOverview = refreshDevicesOverview;
|
|
window.clearActivities = clearActivities;
|
|
|
|
// 页面卸载时清理
|
|
window.addEventListener('beforeunload', () => {
|
|
if (dashboardManager) {
|
|
dashboardManager.destroy();
|
|
}
|
|
});
|
|
|
|
// 页面可见性变化时的处理
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (dashboardManager) {
|
|
if (document.hidden) {
|
|
console.log('页面隐藏,暂停定时器');
|
|
if (dashboardManager.refreshInterval) {
|
|
clearInterval(dashboardManager.refreshInterval);
|
|
dashboardManager.refreshInterval = null;
|
|
}
|
|
} else {
|
|
console.log('页面可见,恢复定时器');
|
|
if (!dashboardManager.refreshInterval) {
|
|
dashboardManager.refreshInterval = setInterval(() => dashboardManager.loadDashboardData(), 30000);
|
|
}
|
|
// 立即刷新一次数据
|
|
dashboardManager.loadDashboardData();
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log('仪表盘模块已加载');
|