添加重启endpoint
This commit is contained in:
+10607
File diff suppressed because it is too large
Load Diff
+82585
File diff suppressed because it is too large
Load Diff
+53291
File diff suppressed because it is too large
Load Diff
+1176
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"blockedDomainsCount": {},
|
||||||
|
"resolvedDomainsCount": {},
|
||||||
|
"lastSaved": "2025-11-27T18:23:48.562056138+08:00"
|
||||||
|
}
|
||||||
+3129
File diff suppressed because it is too large
Load Diff
Executable
BIN
Binary file not shown.
+10
-7
@@ -65,16 +65,18 @@ type Server struct {
|
|||||||
resolvedDomainsMutex sync.RWMutex
|
resolvedDomainsMutex sync.RWMutex
|
||||||
resolvedDomains map[string]*BlockedDomain // 用于记录解析的域名
|
resolvedDomains map[string]*BlockedDomain // 用于记录解析的域名
|
||||||
clientStatsMutex sync.RWMutex
|
clientStatsMutex sync.RWMutex
|
||||||
clientStats map[string]*ClientStats // 用于记录客户端统计
|
clientStats map[string]*ClientStats // 用于记录客户端统计
|
||||||
hourlyStatsMutex sync.RWMutex
|
hourlyStatsMutex sync.RWMutex
|
||||||
hourlyStats map[string]int64 // 按小时统计屏蔽数量
|
hourlyStats map[string]int64 // 按小时统计屏蔽数量
|
||||||
dailyStatsMutex sync.RWMutex
|
dailyStatsMutex sync.RWMutex
|
||||||
dailyStats map[string]int64 // 按天统计屏蔽数量
|
dailyStats map[string]int64 // 按天统计屏蔽数量
|
||||||
monthlyStatsMutex sync.RWMutex
|
monthlyStatsMutex sync.RWMutex
|
||||||
monthlyStats map[string]int64 // 按月统计屏蔽数量
|
monthlyStats map[string]int64 // 按月统计屏蔽数量
|
||||||
saveTicker *time.Ticker // 用于定时保存数据
|
saveTicker *time.Ticker // 用于定时保存数据
|
||||||
startTime time.Time // 服务器启动时间
|
startTime time.Time // 服务器启动时间
|
||||||
saveDone chan struct{} // 用于通知保存协程停止
|
saveDone chan struct{} // 用于通知保存协程停止
|
||||||
|
stopped bool // 服务器是否已经停止
|
||||||
|
stoppedMutex sync.Mutex // 保护stopped标志的互斥锁
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stats DNS服务器统计信息
|
// Stats DNS服务器统计信息
|
||||||
@@ -102,9 +104,9 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
|
|||||||
Net: "udp",
|
Net: "udp",
|
||||||
Timeout: time.Duration(config.Timeout) * time.Millisecond,
|
Timeout: time.Duration(config.Timeout) * time.Millisecond,
|
||||||
},
|
},
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
startTime: time.Now(), // 记录服务器启动时间
|
startTime: time.Now(), // 记录服务器启动时间
|
||||||
stats: &Stats{
|
stats: &Stats{
|
||||||
Queries: 0,
|
Queries: 0,
|
||||||
Blocked: 0,
|
Blocked: 0,
|
||||||
@@ -123,6 +125,7 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
|
|||||||
dailyStats: make(map[string]int64),
|
dailyStats: make(map[string]int64),
|
||||||
monthlyStats: make(map[string]int64),
|
monthlyStats: make(map[string]int64),
|
||||||
saveDone: make(chan struct{}),
|
saveDone: make(chan struct{}),
|
||||||
|
stopped: false, // 初始化为未停止状态
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载已保存的统计数据
|
// 加载已保存的统计数据
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ func (s *Server) Start() error {
|
|||||||
mux.HandleFunc("/api/query", s.handleQuery)
|
mux.HandleFunc("/api/query", s.handleQuery)
|
||||||
mux.HandleFunc("/api/status", s.handleStatus)
|
mux.HandleFunc("/api/status", s.handleStatus)
|
||||||
mux.HandleFunc("/api/config", s.handleConfig)
|
mux.HandleFunc("/api/config", s.handleConfig)
|
||||||
|
mux.HandleFunc("/api/config/restart", s.handleRestart)
|
||||||
// 添加统计相关接口
|
// 添加统计相关接口
|
||||||
mux.HandleFunc("/api/top-blocked", s.handleTopBlockedDomains)
|
mux.HandleFunc("/api/top-blocked", s.handleTopBlockedDomains)
|
||||||
mux.HandleFunc("/api/top-resolved", s.handleTopResolvedDomains)
|
mux.HandleFunc("/api/top-resolved", s.handleTopResolvedDomains)
|
||||||
@@ -1062,3 +1063,37 @@ func isValidIP(ip string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleRestart 处理重启服务请求
|
||||||
|
func (s *Server) handleRestart(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("收到重启服务请求")
|
||||||
|
|
||||||
|
// 停止DNS服务器
|
||||||
|
s.dnsServer.Stop()
|
||||||
|
|
||||||
|
// 重新加载屏蔽规则
|
||||||
|
if err := s.shieldManager.LoadRules(); err != nil {
|
||||||
|
logger.Error("重新加载屏蔽规则失败", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新启动DNS服务器
|
||||||
|
go func() {
|
||||||
|
if err := s.dnsServer.Start(); err != nil {
|
||||||
|
logger.Error("DNS服务器重启失败", "error", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 重新启动定时更新任务
|
||||||
|
s.shieldManager.StopAutoUpdate()
|
||||||
|
s.shieldManager.StartAutoUpdate()
|
||||||
|
|
||||||
|
// 返回成功响应
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success", "message": "服务已重启"})
|
||||||
|
logger.Info("服务重启成功")
|
||||||
|
}
|
||||||
|
|||||||
+52202
File diff suppressed because it is too large
Load Diff
Executable
BIN
Binary file not shown.
+2
-2
@@ -638,9 +638,9 @@
|
|||||||
<div id="shield-content" class="hidden">
|
<div id="shield-content" class="hidden">
|
||||||
<!-- 屏蔽管理页面内容 -->
|
<!-- 屏蔽管理页面内容 -->
|
||||||
<div class="bg-white rounded-lg p-6 card-shadow">
|
<div class="bg-white rounded-lg p-6 card-shadow">
|
||||||
<h3 class="text-lg font-semibold mb-6">屏蔽规则管理</h3>
|
<h3 class="text-lg font-semibold mb-6">远程规则管理</h3>
|
||||||
<!-- 这里将添加屏蔽规则管理相关内容 -->
|
<!-- 这里将添加屏蔽规则管理相关内容 -->
|
||||||
<p>屏蔽管理页面内容待实现</p>
|
<p>远程规则管理页面内容待实现</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+170
-33
@@ -1219,7 +1219,21 @@ function initTimeRangeToggle() {
|
|||||||
button.classList.add(...styleConfig.activeHover); // 添加选中时的浅色悬停
|
button.classList.add(...styleConfig.activeHover); // 添加选中时的浅色悬停
|
||||||
|
|
||||||
// 获取并更新当前时间范围
|
// 获取并更新当前时间范围
|
||||||
const rangeValue = button.dataset.range || button.textContent.trim().replace(/[^0-9a-zA-Z]/g, '');
|
let rangeValue;
|
||||||
|
if (button.dataset.range) {
|
||||||
|
rangeValue = button.dataset.range;
|
||||||
|
} else {
|
||||||
|
const btnText = button.textContent.trim();
|
||||||
|
if (btnText.includes('24')) {
|
||||||
|
rangeValue = '24h';
|
||||||
|
} else if (btnText.includes('7')) {
|
||||||
|
rangeValue = '7d';
|
||||||
|
} else if (btnText.includes('30')) {
|
||||||
|
rangeValue = '30d';
|
||||||
|
} else {
|
||||||
|
rangeValue = btnText.replace(/[^0-9a-zA-Z]/g, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
currentTimeRange = rangeValue;
|
currentTimeRange = rangeValue;
|
||||||
console.log('更新时间范围为:', currentTimeRange);
|
console.log('更新时间范围为:', currentTimeRange);
|
||||||
}
|
}
|
||||||
@@ -1233,7 +1247,7 @@ function initTimeRangeToggle() {
|
|||||||
// 移除自定义鼠标悬停提示效果
|
// 移除自定义鼠标悬停提示效果
|
||||||
});
|
});
|
||||||
|
|
||||||
// 确保默认选中第一个按钮
|
// 确保默认选中第一个按钮并显示混合内容
|
||||||
if (timeRangeButtons.length > 0) {
|
if (timeRangeButtons.length > 0) {
|
||||||
const firstButton = timeRangeButtons[0];
|
const firstButton = timeRangeButtons[0];
|
||||||
const firstStyle = buttonStyles[0];
|
const firstStyle = buttonStyles[0];
|
||||||
@@ -1241,18 +1255,24 @@ function initTimeRangeToggle() {
|
|||||||
// 先重置所有按钮
|
// 先重置所有按钮
|
||||||
timeRangeButtons.forEach((btn, index) => {
|
timeRangeButtons.forEach((btn, index) => {
|
||||||
const btnStyle = buttonStyles[index % buttonStyles.length];
|
const btnStyle = buttonStyles[index % buttonStyles.length];
|
||||||
btn.classList.remove('active', 'bg-blue-500', 'text-white', 'bg-green-500', 'bg-purple-500');
|
btn.classList.remove('active', 'bg-blue-500', 'text-white', 'bg-green-500', 'bg-purple-500', 'bg-gray-500', 'mixed-view-active');
|
||||||
btn.classList.remove(...btnStyle.active);
|
btn.classList.remove(...btnStyle.active);
|
||||||
|
btn.classList.remove(...btnStyle.activeHover);
|
||||||
btn.classList.add(...btnStyle.normal);
|
btn.classList.add(...btnStyle.normal);
|
||||||
btn.classList.add(...btnStyle.hover);
|
btn.classList.add(...btnStyle.hover);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 然后设置第一个按钮为激活状态
|
// 然后设置第一个按钮为激活状态,并标记为混合视图
|
||||||
firstButton.classList.remove(...firstStyle.normal);
|
firstButton.classList.remove(...firstStyle.normal);
|
||||||
firstButton.classList.remove(...firstStyle.hover);
|
firstButton.classList.remove(...firstStyle.hover);
|
||||||
firstButton.classList.add('active');
|
firstButton.classList.add('active', 'mixed-view-active');
|
||||||
firstButton.classList.add(...firstStyle.active);
|
firstButton.classList.add(...firstStyle.active);
|
||||||
console.log('默认选中第一个按钮:', firstButton.textContent.trim());
|
firstButton.classList.add(...firstStyle.activeHover);
|
||||||
|
console.log('默认选中第一个按钮并显示混合内容:', firstButton.textContent.trim());
|
||||||
|
|
||||||
|
// 设置默认显示混合内容
|
||||||
|
isMixedView = true;
|
||||||
|
currentTimeRange = 'mixed';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1479,28 +1499,126 @@ function initDetailedTimeRangeToggle() {
|
|||||||
|
|
||||||
console.log('初始化详细图表时间范围切换,找到按钮数量:', detailedTimeRangeButtons.length);
|
console.log('初始化详细图表时间范围切换,找到按钮数量:', detailedTimeRangeButtons.length);
|
||||||
|
|
||||||
detailedTimeRangeButtons.forEach((button) => {
|
// 初始化详细图表的默认状态,与主图表保持一致
|
||||||
|
detailedCurrentTimeRange = currentTimeRange;
|
||||||
|
detailedIsMixedView = isMixedView;
|
||||||
|
|
||||||
|
// 定义按钮样式配置,与主视图保持一致
|
||||||
|
const buttonStyles = [
|
||||||
|
{ // 24小时按钮
|
||||||
|
normal: ['bg-gray-100', 'text-gray-700'],
|
||||||
|
hover: ['hover:bg-blue-100'],
|
||||||
|
active: ['bg-blue-500', 'text-white'],
|
||||||
|
activeHover: ['hover:bg-blue-400']
|
||||||
|
},
|
||||||
|
{ // 7天按钮
|
||||||
|
normal: ['bg-gray-100', 'text-gray-700'],
|
||||||
|
hover: ['hover:bg-green-100'],
|
||||||
|
active: ['bg-green-500', 'text-white'],
|
||||||
|
activeHover: ['hover:bg-green-400']
|
||||||
|
},
|
||||||
|
{ // 30天按钮
|
||||||
|
normal: ['bg-gray-100', 'text-gray-700'],
|
||||||
|
hover: ['hover:bg-purple-100'],
|
||||||
|
active: ['bg-purple-500', 'text-white'],
|
||||||
|
activeHover: ['hover:bg-purple-400']
|
||||||
|
},
|
||||||
|
{ // 混合视图按钮
|
||||||
|
normal: ['bg-gray-100', 'text-gray-700'],
|
||||||
|
hover: ['hover:bg-gray-200'],
|
||||||
|
active: ['bg-gray-500', 'text-white'],
|
||||||
|
activeHover: ['hover:bg-gray-400']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// 设置初始按钮状态
|
||||||
|
detailedTimeRangeButtons.forEach((button, index) => {
|
||||||
|
const styleConfig = buttonStyles[index % buttonStyles.length];
|
||||||
|
|
||||||
|
// 移除所有初始样式
|
||||||
|
button.classList.remove('active', 'bg-blue-500', 'text-white', 'bg-gray-200', 'text-gray-700',
|
||||||
|
'bg-green-500', 'bg-purple-500', 'bg-gray-100', 'mixed-view-active');
|
||||||
|
|
||||||
|
// 设置非选中状态样式
|
||||||
|
button.classList.add('transition-colors', 'duration-200');
|
||||||
|
button.classList.add(...styleConfig.normal);
|
||||||
|
button.classList.add(...styleConfig.hover);
|
||||||
|
|
||||||
|
// 如果是第一个按钮且当前是混合视图,设置为混合视图激活状态
|
||||||
|
if (index === 0 && detailedIsMixedView) {
|
||||||
|
button.classList.remove(...styleConfig.normal);
|
||||||
|
button.classList.remove(...styleConfig.hover);
|
||||||
|
button.classList.add('active', 'mixed-view-active');
|
||||||
|
button.classList.add(...styleConfig.active);
|
||||||
|
button.classList.add(...styleConfig.activeHover);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
detailedTimeRangeButtons.forEach((button, index) => {
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
// 设置当前时间范围
|
const styleConfig = buttonStyles[index % buttonStyles.length];
|
||||||
const timeRange = button.dataset.range;
|
|
||||||
const isMixedMode = timeRange === 'mixed';
|
|
||||||
|
|
||||||
console.log('时间范围按钮被点击:', { timeRange, isMixedMode });
|
// 检查是否是再次点击已选中的按钮
|
||||||
|
const isActive = button.classList.contains('active');
|
||||||
|
|
||||||
// 更新按钮状态
|
// 重置所有按钮为非选中状态
|
||||||
detailedTimeRangeButtons.forEach((btn) => {
|
detailedTimeRangeButtons.forEach((btn, btnIndex) => {
|
||||||
if (btn === button) {
|
const btnStyle = buttonStyles[btnIndex % buttonStyles.length];
|
||||||
btn.classList.add('bg-blue-500', 'text-white');
|
|
||||||
btn.classList.remove('bg-gray-200', 'text-gray-700');
|
// 移除所有可能的激活状态类
|
||||||
} else {
|
btn.classList.remove('active', 'bg-blue-500', 'text-white', 'bg-green-500', 'bg-purple-500', 'bg-gray-500', 'mixed-view-active');
|
||||||
btn.classList.remove('bg-blue-500', 'text-white');
|
btn.classList.remove(...btnStyle.active);
|
||||||
btn.classList.add('bg-gray-200', 'text-gray-700');
|
btn.classList.remove(...btnStyle.activeHover);
|
||||||
}
|
|
||||||
|
// 添加非选中状态类
|
||||||
|
btn.classList.add(...btnStyle.normal);
|
||||||
|
btn.classList.add(...btnStyle.hover);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 更新详细图表专用变量
|
if (isActive && index < 3) { // 再次点击已选中的时间范围按钮
|
||||||
detailedCurrentTimeRange = timeRange;
|
// 切换到混合视图
|
||||||
detailedIsMixedView = isMixedMode;
|
detailedIsMixedView = true;
|
||||||
|
detailedCurrentTimeRange = 'mixed';
|
||||||
|
console.log('详细图表切换到混合视图');
|
||||||
|
|
||||||
|
// 设置当前按钮为特殊混合视图状态
|
||||||
|
button.classList.remove(...styleConfig.normal);
|
||||||
|
button.classList.remove(...styleConfig.hover);
|
||||||
|
button.classList.add('active', 'mixed-view-active');
|
||||||
|
button.classList.add(...styleConfig.active);
|
||||||
|
button.classList.add(...styleConfig.activeHover);
|
||||||
|
} else {
|
||||||
|
// 普通选中模式
|
||||||
|
detailedIsMixedView = false;
|
||||||
|
|
||||||
|
// 设置当前按钮为激活状态
|
||||||
|
button.classList.remove(...styleConfig.normal);
|
||||||
|
button.classList.remove(...styleConfig.hover);
|
||||||
|
button.classList.add('active');
|
||||||
|
button.classList.add(...styleConfig.active);
|
||||||
|
button.classList.add(...styleConfig.activeHover);
|
||||||
|
|
||||||
|
// 获取并更新当前时间范围
|
||||||
|
let rangeValue;
|
||||||
|
if (button.dataset.range) {
|
||||||
|
rangeValue = button.dataset.range;
|
||||||
|
} else {
|
||||||
|
const btnText = button.textContent.trim();
|
||||||
|
if (btnText.includes('24')) {
|
||||||
|
rangeValue = '24h';
|
||||||
|
} else if (btnText.includes('7')) {
|
||||||
|
rangeValue = '7d';
|
||||||
|
} else if (btnText.includes('30')) {
|
||||||
|
rangeValue = '30d';
|
||||||
|
} else {
|
||||||
|
rangeValue = btnText.replace(/[^0-9a-zA-Z]/g, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
detailedCurrentTimeRange = rangeValue;
|
||||||
|
console.log('详细图表更新时间范围为:', detailedCurrentTimeRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新绘制详细图表
|
||||||
drawDetailedDNSRequestsChart();
|
drawDetailedDNSRequestsChart();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1610,17 +1728,26 @@ function drawDetailedDNSRequestsChart() {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 普通视图
|
// 普通视图
|
||||||
// 根据详细视图时间范围选择API函数
|
// 根据详细视图时间范围选择API函数和对应的颜色
|
||||||
let apiFunction;
|
let apiFunction;
|
||||||
|
let chartColor;
|
||||||
|
let chartFillColor;
|
||||||
|
|
||||||
switch (detailedCurrentTimeRange) {
|
switch (detailedCurrentTimeRange) {
|
||||||
case '7d':
|
case '7d':
|
||||||
apiFunction = (api && api.getDailyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
apiFunction = (api && api.getDailyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
||||||
|
chartColor = '#22c55e'; // 绿色,与混合视图中的7天数据颜色一致
|
||||||
|
chartFillColor = 'rgba(34, 197, 94, 0.1)';
|
||||||
break;
|
break;
|
||||||
case '30d':
|
case '30d':
|
||||||
apiFunction = (api && api.getMonthlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
apiFunction = (api && api.getMonthlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
||||||
|
chartColor = '#a855f7'; // 紫色,与混合视图中的30天数据颜色一致
|
||||||
|
chartFillColor = 'rgba(168, 85, 247, 0.1)';
|
||||||
break;
|
break;
|
||||||
default: // 24h
|
default: // 24h
|
||||||
apiFunction = (api && api.getHourlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
apiFunction = (api && api.getHourlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
||||||
|
chartColor = '#3b82f6'; // 蓝色,与混合视图中的24小时数据颜色一致
|
||||||
|
chartFillColor = 'rgba(59, 130, 246, 0.1)';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取统计数据
|
// 获取统计数据
|
||||||
@@ -1631,8 +1758,8 @@ function drawDetailedDNSRequestsChart() {
|
|||||||
detailedDnsRequestsChart.data.datasets = [{
|
detailedDnsRequestsChart.data.datasets = [{
|
||||||
label: 'DNS请求数量',
|
label: 'DNS请求数量',
|
||||||
data: data.data,
|
data: data.data,
|
||||||
borderColor: '#3b82f6',
|
borderColor: chartColor,
|
||||||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
backgroundColor: chartFillColor,
|
||||||
tension: 0.4,
|
tension: 0.4,
|
||||||
fill: true
|
fill: true
|
||||||
}];
|
}];
|
||||||
@@ -1650,8 +1777,8 @@ function drawDetailedDNSRequestsChart() {
|
|||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'DNS请求数量',
|
label: 'DNS请求数量',
|
||||||
data: data.data,
|
data: data.data,
|
||||||
borderColor: '#3b82f6',
|
borderColor: chartColor,
|
||||||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
backgroundColor: chartFillColor,
|
||||||
tension: 0.4,
|
tension: 0.4,
|
||||||
fill: true
|
fill: true
|
||||||
}]
|
}]
|
||||||
@@ -1762,6 +1889,7 @@ function drawDNSRequestsChart() {
|
|||||||
|
|
||||||
// 创建或更新图表
|
// 创建或更新图表
|
||||||
if (dnsRequestsChart) {
|
if (dnsRequestsChart) {
|
||||||
|
// 使用第一个数据集的标签,但确保每个数据集使用自己的数据
|
||||||
dnsRequestsChart.data.labels = results[0].labels;
|
dnsRequestsChart.data.labels = results[0].labels;
|
||||||
dnsRequestsChart.data.datasets = datasets;
|
dnsRequestsChart.data.datasets = datasets;
|
||||||
dnsRequestsChart.options.plugins.legend.display = showLegend;
|
dnsRequestsChart.options.plugins.legend.display = showLegend;
|
||||||
@@ -1815,17 +1943,26 @@ function drawDNSRequestsChart() {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 普通视图
|
// 普通视图
|
||||||
// 根据当前时间范围选择API函数
|
// 根据当前时间范围选择API函数和对应的颜色
|
||||||
let apiFunction;
|
let apiFunction;
|
||||||
|
let chartColor;
|
||||||
|
let chartFillColor;
|
||||||
|
|
||||||
switch (currentTimeRange) {
|
switch (currentTimeRange) {
|
||||||
case '7d':
|
case '7d':
|
||||||
apiFunction = (api && api.getDailyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
apiFunction = (api && api.getDailyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
||||||
|
chartColor = '#22c55e'; // 绿色,与混合视图中的7天数据颜色一致
|
||||||
|
chartFillColor = 'rgba(34, 197, 94, 0.1)';
|
||||||
break;
|
break;
|
||||||
case '30d':
|
case '30d':
|
||||||
apiFunction = (api && api.getMonthlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
apiFunction = (api && api.getMonthlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
||||||
|
chartColor = '#a855f7'; // 紫色,与混合视图中的30天数据颜色一致
|
||||||
|
chartFillColor = 'rgba(168, 85, 247, 0.1)';
|
||||||
break;
|
break;
|
||||||
default: // 24h
|
default: // 24h
|
||||||
apiFunction = (api && api.getHourlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
apiFunction = (api && api.getHourlyStats) || (() => Promise.resolve({ labels: [], data: [] }));
|
||||||
|
chartColor = '#3b82f6'; // 蓝色,与混合视图中的24小时数据颜色一致
|
||||||
|
chartFillColor = 'rgba(59, 130, 246, 0.1)';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取统计数据
|
// 获取统计数据
|
||||||
@@ -1836,8 +1973,8 @@ function drawDNSRequestsChart() {
|
|||||||
dnsRequestsChart.data.datasets = [{
|
dnsRequestsChart.data.datasets = [{
|
||||||
label: 'DNS请求数量',
|
label: 'DNS请求数量',
|
||||||
data: data.data,
|
data: data.data,
|
||||||
borderColor: '#3b82f6',
|
borderColor: chartColor,
|
||||||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
backgroundColor: chartFillColor,
|
||||||
tension: 0.4,
|
tension: 0.4,
|
||||||
fill: true
|
fill: true
|
||||||
}];
|
}];
|
||||||
@@ -1855,8 +1992,8 @@ function drawDNSRequestsChart() {
|
|||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'DNS请求数量',
|
label: 'DNS请求数量',
|
||||||
data: data.data,
|
data: data.data,
|
||||||
borderColor: '#3b82f6',
|
borderColor: chartColor,
|
||||||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
backgroundColor: chartFillColor,
|
||||||
tension: 0.4,
|
tension: 0.4,
|
||||||
fill: true
|
fill: true
|
||||||
}]
|
}]
|
||||||
|
|||||||
Reference in New Issue
Block a user