web异常待修复

This commit is contained in:
Alex Yang
2025-11-24 10:50:03 +08:00
parent 534878fa4d
commit 4467a0bf4c
14 changed files with 30715 additions and 243 deletions

View File

@@ -6,8 +6,36 @@
<meta name="description" content="DNS服务器管理控制台 - 高性能DNS服务器支持规则屏蔽和Hosts管理">
<title>DNS服务器管理控制台</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.css">
<!-- Chart.js 4.x不需要单独的CSS文件 -->
<link rel="stylesheet" href="css/style.css">
<style>
/* 光晕效果样式 */
.stat-value.update {
animation: glow 1s ease-out;
}
@keyframes glow {
0% { box-shadow: 0 0 5px rgba(75, 192, 192, 0.5); }
50% { box-shadow: 0 0 20px rgba(75, 192, 192, 0.8); }
100% { box-shadow: 0 0 5px rgba(75, 192, 192, 0); }
}
/* 小型图表容器 */
.mini-chart-container {
position: absolute;
bottom: 5px;
right: 5px;
width: 60px;
height: 20px;
opacity: 0.7;
}
/* 小型图表 */
.mini-chart {
width: 100% !important;
height: 100% !important;
}
</style>
</head>
<body>
<div class="container">
@@ -63,42 +91,54 @@
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-card" style="position: relative;">
<i class="fas fa-ban"></i>
<div class="stat-value" id="blocked-count">--</div>
<div class="stat-label">屏蔽请求</div>
<div class="mini-chart-container">
<canvas id="blocked-chart" class="mini-chart"></canvas>
</div>
</div>
<div class="stat-card">
<div class="stat-card" style="position: relative;">
<i class="fas fa-check-circle"></i>
<div class="stat-value" id="allowed-count">--</div>
<div class="stat-label">允许请求</div>
</div>
<div class="stat-card">
<div class="stat-card" style="position: relative;">
<i class="fas fa-question-circle"></i>
<div class="stat-value" id="error-count">--</div>
<div class="stat-label">错误请求</div>
</div>
<div class="stat-card">
<div class="stat-card" style="position: relative;">
<i class="fas fa-history"></i>
<div class="stat-value" id="total-queries">--</div>
<div class="stat-label">总请求数</div>
<div class="mini-chart-container">
<canvas id="query-chart" class="mini-chart"></canvas>
</div>
</div>
<div class="stat-card">
<div class="stat-card" style="position: relative;">
<i class="fas fa-list"></i>
<div class="stat-value" id="rules-count">--</div>
<div class="stat-label">屏蔽规则数</div>
<div class="mini-chart-container">
<canvas id="rules-chart" class="mini-chart"></canvas>
</div>
</div>
<div class="stat-card">
<div class="stat-card" style="position: relative;">
<i class="fas fa-globe"></i>
<div class="stat-value" id="hosts-count">--</div>
<div class="stat-label">Hosts条目</div>
<div class="mini-chart-container">
<canvas id="hosts-chart" class="mini-chart"></canvas>
</div>
</div>
</div>
<div class="charts-container">
<div class="chart-card">
<h3>24小时屏蔽统计</h3>
<canvas id="hourly-chart"></canvas>
<canvas id="hourly-chart" style="height: 300px;"></canvas>
</div>
<div class="chart-card">
<h3>请求类型分布</h3>
@@ -411,7 +451,158 @@
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="js/vendor/chart.umd.min.js"></script>
<script>
// 全局数据变化检测和图表管理
let previousStats = {};
let miniCharts = {};
let dataHistory = {
rules: Array(10).fill(0),
hosts: Array(10).fill(0),
query: Array(10).fill(0),
blocked: Array(10).fill(0)
};
let updateTimer = null;
const UPDATE_INTERVAL = 2000;
let previousFullData = null;
let previousChartData = null;
// 初始化小型图表
function initMiniCharts() {
const chartConfigs = {
'rules-chart': { label: '规则数', color: 'rgb(75, 192, 192)' },
'hosts-chart': { label: 'Hosts数', color: 'rgb(153, 102, 255)' },
'query-chart': { label: '查询数', color: 'rgb(255, 159, 64)' },
'blocked-chart': { label: '屏蔽数', color: 'rgb(255, 99, 132)' }
};
Object.entries(chartConfigs).forEach(([id, config]) => {
const ctx = document.getElementById(id);
if (!ctx) return;
miniCharts[id] = new Chart(ctx, {
type: 'line',
data: {
labels: Array(10).fill(''),
datasets: [{
label: config.label,
data: Array(10).fill(0),
borderColor: config.color,
backgroundColor: 'rgba(75, 192, 192, 0.2)',
tension: 0.4,
pointRadius: 0,
borderWidth: 2,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
tooltip: { enabled: false }
},
scales: {
x: { display: false },
y: { display: false, beginAtZero: true }
},
animation: false
}
});
});
}
// 更新小型图表
function updateMiniChart(chartId, data) {
if (miniCharts[chartId]) {
miniCharts[chartId].data.datasets[0].data = data;
miniCharts[chartId].update();
}
}
// 更新数据历史记录
function updateDataHistory(key, value) {
dataHistory[key].shift();
dataHistory[key].push(value);
}
// 检查数据是否变化并添加光晕效果
function checkAndAnimate(elementId, newValue) {
const element = document.getElementById(elementId);
if (!element) return;
const oldValue = previousStats[elementId] || 0;
if (newValue !== oldValue && oldValue !== 0 && oldValue !== '--') {
element.classList.add('update');
setTimeout(() => {
element.classList.remove('update');
}, 1000);
}
previousStats[elementId] = newValue;
}
// 启动实时更新
function startRealTimeUpdate() {
if (updateTimer) {
clearInterval(updateTimer);
}
updateTimer = setInterval(() => {
// 仅当当前面板是仪表盘时更新数据
if (document.getElementById('dashboard').classList.contains('active')) {
loadDashboardData();
}
}, UPDATE_INTERVAL);
}
// 停止实时更新
function stopRealTimeUpdate() {
if (updateTimer) {
clearInterval(updateTimer);
updateTimer = null;
}
}
// 显示悬浮通知
function showNotification(type, message) {
// 创建通知元素
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
// 设置图标
let iconClass = 'info-circle';
if (type === 'success') iconClass = 'check-circle';
else if (type === 'danger') iconClass = 'exclamation-circle';
else if (type === 'warning') iconClass = 'exclamation-triangle';
// 设置通知内容
notification.innerHTML = `
<div class="notification-icon">
<i class="fas fa-${iconClass}"></i>
</div>
<div class="notification-content">${message}</div>
<button class="notification-close">
<i class="fas fa-times"></i>
</button>
`;
// 添加关闭事件
notification.querySelector('.notification-close').addEventListener('click', () => {
notification.style.animation = 'slideIn 0.3s ease-out reverse';
setTimeout(() => notification.remove(), 300);
});
// 添加到页面
document.body.appendChild(notification);
// 3秒后自动关闭
setTimeout(() => {
notification.style.animation = 'slideIn 0.3s ease-out reverse';
setTimeout(() => notification.remove(), 300);
}, 3000);
}
</script>
<script src="js/app.js"></script>
<script src="js/modules/dashboard.js"></script>
<script src="js/modules/rules.js"></script>
@@ -419,5 +610,47 @@
<script src="js/modules/blacklists.js"></script>
<script src="js/modules/query.js"></script>
<script src="js/modules/config.js"></script>
<script>
// 页面加载完成后初始化
window.addEventListener('load', function() {
initMiniCharts();
// 为侧边栏导航添加切换事件
const navItems = document.querySelectorAll('.nav-item');
navItems.forEach(item => {
item.addEventListener('click', function() {
const target = this.getAttribute('data-target');
const panels = document.querySelectorAll('.panel');
const navItems = document.querySelectorAll('.nav-item');
// 更新面板显示
panels.forEach(panel => {
panel.classList.remove('active');
if (panel.id === target) {
panel.classList.add('active');
}
});
// 更新导航高亮
navItems.forEach(navItem => {
navItem.classList.remove('active');
});
this.classList.add('active');
// 根据面板类型控制更新
if (target === 'dashboard') {
startRealTimeUpdate();
} else {
stopRealTimeUpdate();
}
});
});
});
// 页面卸载时清理定时器
window.addEventListener('beforeunload', function() {
stopRealTimeUpdate();
});
</script>
</body>
</html>