This commit is contained in:
Alex Yang
2025-12-16 00:17:05 +08:00
parent 11d39d6b76
commit c0ddaf8b44
49 changed files with 1514 additions and 941752 deletions

View File

@@ -6,12 +6,18 @@ let dnsRequestsChart = null;
let detailedDnsRequestsChart = null; // 详细DNS请求趋势图表(浮窗)
let queryTypeChart = null; // 解析类型统计饼图
let intervalId = null;
let wsConnection = null;
let wsReconnectTimer = null;
let dashboardWsConnection = null;
let dashboardWsReconnectTimer = null;
// 存储统计卡片图表实例
let statCardCharts = {};
// 存储统计卡片历史数据
let statCardHistoryData = {};
// 存储仪表盘历史数据,用于计算趋势
window.dashboardHistoryData = window.dashboardHistoryData || {
prevResponseTime: null,
prevActiveIPs: null,
prevTopQueryTypeCount: null
};
// 引入颜色配置文件
const COLOR_CONFIG = window.COLOR_CONFIG || {};
@@ -53,22 +59,22 @@ function connectWebSocket() {
console.log('正在连接WebSocket:', wsUrl);
// 创建WebSocket连接
wsConnection = new WebSocket(wsUrl);
dashboardWsConnection = new WebSocket(wsUrl);
// 连接打开事件
wsConnection.onopen = function() {
dashboardWsConnection.onopen = function() {
console.log('WebSocket连接已建立');
showNotification('数据更新成功', 'success');
// 清除重连计时器
if (wsReconnectTimer) {
clearTimeout(wsReconnectTimer);
wsReconnectTimer = null;
if (dashboardWsReconnectTimer) {
clearTimeout(dashboardWsReconnectTimer);
dashboardWsReconnectTimer = null;
}
};
// 接收消息事件
wsConnection.onmessage = function(event) {
dashboardWsConnection.onmessage = function(event) {
try {
const data = JSON.parse(event.data);
@@ -82,16 +88,16 @@ function connectWebSocket() {
};
// 连接关闭事件
wsConnection.onclose = function(event) {
dashboardWsConnection.onclose = function(event) {
console.warn('WebSocket连接已关闭代码:', event.code);
wsConnection = null;
dashboardWsConnection = null;
// 设置重连
setupReconnect();
};
// 连接错误事件
wsConnection.onerror = function(error) {
dashboardWsConnection.onerror = function(error) {
console.error('WebSocket连接错误:', error);
};
@@ -104,14 +110,14 @@ function connectWebSocket() {
// 设置重连逻辑
function setupReconnect() {
if (wsReconnectTimer) {
if (dashboardWsReconnectTimer) {
return; // 已经有重连计时器在运行
}
const reconnectDelay = 5000; // 5秒后重连
console.log(`将在${reconnectDelay}ms后尝试重新连接WebSocket`);
wsReconnectTimer = setTimeout(() => {
dashboardWsReconnectTimer = setTimeout(() => {
connectWebSocket();
}, reconnectDelay);
}
@@ -192,14 +198,42 @@ function processRealTimeData(stats) {
if (document.getElementById('top-query-type')) {
const queryType = stats.topQueryType || '---';
document.getElementById('top-query-type').textContent = queryType;
const queryPercentElem = document.getElementById('query-type-percentage');
if (queryPercentElem) {
queryPercentElem.textContent = '• ---';
queryPercentElem.className = 'text-sm flex items-center text-gray-500';
// 计算查询类型趋势
let queryPercent = '---';
let trendClass = 'text-gray-400';
let trendIcon = '---';
if (stats.topQueryTypeCount !== undefined && stats.topQueryTypeCount !== null) {
// 存储当前值用于下次计算趋势
const prevTopQueryTypeCount = window.dashboardHistoryData.prevTopQueryTypeCount || stats.topQueryTypeCount;
window.dashboardHistoryData.prevTopQueryTypeCount = stats.topQueryTypeCount;
// 计算变化百分比
if (prevTopQueryTypeCount > 0) {
const changePercent = ((stats.topQueryTypeCount - prevTopQueryTypeCount) / prevTopQueryTypeCount) * 100;
queryPercent = Math.abs(changePercent).toFixed(1) + '%';
// 设置趋势图标和颜色
if (changePercent > 0) {
trendIcon = '↑';
trendClass = 'text-primary';
} else if (changePercent < 0) {
trendIcon = '↓';
trendClass = 'text-secondary';
} else {
trendIcon = '•';
trendClass = 'text-gray-500';
}
}
}
queryPercentElem.textContent = trendIcon + ' ' + queryPercent;
queryPercentElem.className = `text-sm flex items-center ${trendClass}`;
}
document.getElementById('top-query-type').textContent = queryType;
}
if (document.getElementById('active-ips')) {
@@ -362,15 +396,15 @@ function fallbackToIntervalRefresh() {
// 清理资源
function cleanupResources() {
// 清除WebSocket连接
if (wsConnection) {
wsConnection.close();
wsConnection = null;
if (dashboardWsConnection) {
dashboardWsConnection.close();
dashboardWsConnection = null;
}
// 清除重连计时器
if (wsReconnectTimer) {
clearTimeout(wsReconnectTimer);
wsReconnectTimer = null;
if (dashboardWsReconnectTimer) {
clearTimeout(dashboardWsReconnectTimer);
dashboardWsReconnectTimer = null;
}
// 清除定时刷新
@@ -797,17 +831,20 @@ function updateStatsCards(stats) {
const originalStyle = element.getAttribute('style') || '';
try {
// 复制原始元素的样式到新元素,确保大小完全一致
const computedStyle = getComputedStyle(element);
// 配置翻页容器样式,确保与原始元素大小完全一致
const containerStyle =
'position: relative; '
+ 'display: ' + computedStyle.display + '; '
+ 'overflow: hidden; '
+ 'height: ' + element.offsetHeight + 'px; '
+ 'width: ' + element.offsetWidth + 'px; '
+ 'margin: ' + computedStyle.margin + '; '
+ 'padding: ' + computedStyle.padding + '; '
+ 'box-sizing: ' + computedStyle.boxSizing + '; '
+ 'line-height: ' + computedStyle.lineHeight + ';';
'position: relative; ' +
'display: ' + computedStyle.display + '; ' +
'overflow: hidden; ' +
'height: ' + element.offsetHeight + 'px; ' +
'width: ' + element.offsetWidth + 'px; ' +
'margin: ' + computedStyle.margin + '; ' +
'padding: ' + computedStyle.padding + '; ' +
'box-sizing: ' + computedStyle.boxSizing + '; ' +
'line-height: ' + computedStyle.lineHeight + ';';
// 创建翻页容器
const flipContainer = document.createElement('div');
@@ -844,9 +881,6 @@ function updateStatsCards(stats) {
'transition: transform 400ms ease-in-out; ' +
'transform-origin: center; ' +
'transform: translateY(100%);';
// 复制原始元素的样式到新元素,确保大小完全一致
const computedStyle = getComputedStyle(element);
[oldValueElement, newValueElement].forEach(el => {
el.style.fontSize = computedStyle.fontSize;
el.style.fontWeight = computedStyle.fontWeight;