重大重构
This commit is contained in:
@@ -440,18 +440,60 @@
|
||||
},
|
||||
"company": "广州市动景计算机科技有限公司"
|
||||
},
|
||||
"腾讯": {
|
||||
"微信": {
|
||||
"name": "微信",
|
||||
"categoryId": 7,
|
||||
"url": {
|
||||
"1": "https://wx.qq.com/",
|
||||
"2": "https://weixin.qq.com/",
|
||||
"3": "https://res.wx.qq.com/",
|
||||
"4": "dns.weixin.qq.com",
|
||||
"5": "pc.weixin.qq.com"
|
||||
"腾讯系列": {
|
||||
"微信相关": {
|
||||
"微信": {
|
||||
"name": "微信",
|
||||
"categoryId": 7,
|
||||
"url": {
|
||||
"1": "https://wx.qq.com/",
|
||||
"2": "https://weixin.qq.com/",
|
||||
"3": "https://res.wx.qq.com/",
|
||||
"4": "dns.weixin.qq.com",
|
||||
"5": "pc.weixin.qq.com"
|
||||
},
|
||||
"icon": "https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico"
|
||||
},
|
||||
"icon": "https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico"
|
||||
"微信公众号文章缩略图CDN节点": {
|
||||
"name": "微信公众号文章缩略图与广告图片分发CDN节点",
|
||||
"categoryId": 2,
|
||||
"url": "wxsnsdythumb.wxs.qq.com",
|
||||
"icon": "https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico"
|
||||
},
|
||||
"微信公众号动态内容主CDN节点": {
|
||||
"name": "微信公众号动态内容主CDN/文章正文图片素材分发",
|
||||
"categoryId": 2,
|
||||
"url": "wxsnsdy.wxs.qq.com",
|
||||
"icon": "https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico"
|
||||
},
|
||||
"微信公众号内容备用CDN节点": {
|
||||
"name": "微信公众号内容备用CDN/图片资源访问分流服务",
|
||||
"categoryId": 2,
|
||||
"url": "snsdy.tc.qq.com",
|
||||
"icon": "https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico"
|
||||
},
|
||||
"微信生态视频缩略图CDN节点": {
|
||||
"name": "微信生态视频缩略图CDN/公众号视频号封面截图分发",
|
||||
"categoryId": 2,
|
||||
"url": "vweixinthumb.tc.qq.com",
|
||||
"icon": "https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico"
|
||||
}
|
||||
},
|
||||
"腾讯视频相关": {
|
||||
"腾讯视频图片缓存CDN节点": {
|
||||
"name": "腾讯视频封面、海报、截图等静态图片CDN分发节点",
|
||||
"categoryId": 2,
|
||||
"url": "imgcache.tc.qq.com",
|
||||
"icon": "https://v.qq.com/favicon.ico"
|
||||
}
|
||||
},
|
||||
"QQ音乐相关": {
|
||||
"QQ音乐音频资源CDN节点": {
|
||||
"name": "QQ音乐音频资源与封面图片CDN分发节点",
|
||||
"categoryId": 2,
|
||||
"url": "tsmusic.tc.qq.com",
|
||||
"icon": "https://y.qq.com/favicon.ico"
|
||||
}
|
||||
},
|
||||
"腾讯会议核心代理服务": {
|
||||
"name": "腾讯会议核心代理服务",
|
||||
|
||||
@@ -14312,6 +14312,13 @@
|
||||
"companyId": "tencent",
|
||||
"source": "AdGuard"
|
||||
},
|
||||
"weixin":{
|
||||
"name": "微信广告",
|
||||
"categoryId": 12,
|
||||
"url": "https://wxsnsdythumb.wxs.qq.com",
|
||||
"companyId": "tencent",
|
||||
"source": "本地"
|
||||
},
|
||||
"qrius": {
|
||||
"name": "Qrius",
|
||||
"categoryId": 7,
|
||||
|
||||
@@ -34,7 +34,7 @@ let errorQueries = 0;
|
||||
// 初始化仪表盘
|
||||
async function initDashboard() {
|
||||
try {
|
||||
console.log('页面打开时强制刷新数据...');
|
||||
|
||||
|
||||
// 优先加载初始数据,确保页面显示最新信息
|
||||
await loadDashboardData();
|
||||
@@ -63,14 +63,12 @@ function connectWebSocket() {
|
||||
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsUrl = `${wsProtocol}//${window.location.host}/ws/stats`;
|
||||
|
||||
console.log('正在连接WebSocket:', wsUrl);
|
||||
|
||||
// 创建WebSocket连接
|
||||
dashboardWsConnection = new WebSocket(wsUrl);
|
||||
|
||||
// 连接打开事件
|
||||
dashboardWsConnection.onopen = function() {
|
||||
console.log('WebSocket连接已建立');
|
||||
showNotification('数据更新成功', 'success');
|
||||
|
||||
// 清除重连计时器
|
||||
@@ -86,7 +84,6 @@ function connectWebSocket() {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if (data.type === 'initial_data' || data.type === 'stats_update') {
|
||||
console.log('收到实时数据更新');
|
||||
processRealTimeData(data.data);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -122,7 +119,6 @@ function setupReconnect() {
|
||||
}
|
||||
|
||||
const reconnectDelay = 5000; // 5秒后重连
|
||||
console.log(`将在${reconnectDelay}ms后尝试重新连接WebSocket`);
|
||||
|
||||
dashboardWsReconnectTimer = setTimeout(() => {
|
||||
connectWebSocket();
|
||||
@@ -139,7 +135,6 @@ function processRealTimeData(stats) {
|
||||
lastProcessedTime = now;
|
||||
|
||||
try {
|
||||
console.log('收到实时数据:', stats);
|
||||
|
||||
// 确保stats是有效的对象
|
||||
if (!stats || typeof stats !== 'object') {
|
||||
@@ -179,15 +174,6 @@ function processRealTimeData(stats) {
|
||||
allowedQueries = Number(stats.allowedQueries) || 0;
|
||||
}
|
||||
|
||||
console.log('实时数据处理完成,更新后的值:', {
|
||||
totalQueries,
|
||||
allowedQueries,
|
||||
blockedQueries,
|
||||
errorQueries
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (document.getElementById('top-query-type')) {
|
||||
const queryType = stats.topQueryType || '---';
|
||||
document.getElementById('top-query-type').textContent = queryType;
|
||||
@@ -472,7 +458,6 @@ function cleanupResources() {
|
||||
|
||||
// 更新统计卡片
|
||||
function updateStatsCards(stats) {
|
||||
console.log('更新统计卡片,收到数据:', stats);
|
||||
|
||||
// 适配不同的数据结构
|
||||
// 保存当前显示的值,用于在数据缺失时保留
|
||||
@@ -876,7 +861,6 @@ function updateStatsCards(stats) {
|
||||
|
||||
// 更新Top屏蔽域名表格
|
||||
async function updateTopBlockedTable(domains) {
|
||||
console.log('更新Top屏蔽域名表格,收到数据:', domains);
|
||||
const tableBody = document.getElementById('top-blocked-table');
|
||||
|
||||
let tableData = [];
|
||||
@@ -902,7 +886,6 @@ async function updateTopBlockedTable(domains) {
|
||||
{ name: '---.---.---', count: '---' },
|
||||
{ name: '---.---.---', count: '---' }
|
||||
];
|
||||
console.log('使用示例数据填充Top屏蔽域名表格');
|
||||
}
|
||||
|
||||
// 计算总拦截次数
|
||||
@@ -985,12 +968,10 @@ async function updateTopBlockedTable(domains) {
|
||||
|
||||
// 更新最近屏蔽域名表格
|
||||
function updateRecentBlockedTable(domains) {
|
||||
console.log('更新最近屏蔽域名表格,收到数据:', domains);
|
||||
const tableBody = document.getElementById('recent-blocked-table');
|
||||
|
||||
// 确保tableBody存在,因为最近屏蔽域名卡片可能已被移除
|
||||
if (!tableBody) {
|
||||
console.log('未找到recent-blocked-table元素,跳过更新');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1015,7 +996,6 @@ function updateRecentBlockedTable(domains) {
|
||||
{ name: '---.---.---', timestamp: now - 45 * 60 * 1000, type: '追踪' },
|
||||
{ name: '---.---.---', timestamp: now - 60 * 60 * 1000, type: '恶意' }
|
||||
];
|
||||
console.log('使用示例数据填充最近屏蔽域名表格');
|
||||
}
|
||||
|
||||
let html = '';
|
||||
@@ -1217,7 +1197,6 @@ function isPrivateIP(ip) {
|
||||
|
||||
// 更新TOP客户端表格
|
||||
async function updateTopClientsTable(clients) {
|
||||
console.log('更新TOP客户端表格,收到数据:', clients);
|
||||
const tableBody = document.getElementById('top-clients-table');
|
||||
|
||||
// 确保tableBody存在
|
||||
@@ -1260,7 +1239,6 @@ async function updateTopClientsTable(clients) {
|
||||
{ ip: '---.---.---', count: '---' },
|
||||
{ ip: '---.---.---', count: '---' }
|
||||
];
|
||||
console.log('使用示例数据填充TOP客户端表格');
|
||||
}
|
||||
|
||||
|
||||
@@ -1291,7 +1269,6 @@ async function updateTopClientsTable(clients) {
|
||||
|
||||
// 更新请求域名排行表格
|
||||
async function updateTopDomainsTable(domains) {
|
||||
console.log('更新请求域名排行表格,收到数据:', domains);
|
||||
const tableBody = document.getElementById('top-domains-table');
|
||||
|
||||
// 确保tableBody存在
|
||||
@@ -1325,7 +1302,6 @@ async function updateTopDomainsTable(domains) {
|
||||
{ name: 'twitter.com', count: 35 },
|
||||
{ name: 'youtube.com', count: 30 }
|
||||
];
|
||||
console.log('使用示例数据填充请求域名排行表格');
|
||||
}
|
||||
|
||||
// 计算总请求次数
|
||||
@@ -1415,7 +1391,6 @@ let detailedCurrentTimeRange = '24h'; // 详细图表当前时间范围
|
||||
|
||||
// 初始化时间范围切换
|
||||
function initTimeRangeToggle() {
|
||||
console.log('初始化时间范围切换');
|
||||
// 查找所有可能的时间范围按钮类名
|
||||
const allTimeRangeButtons = document.querySelectorAll('.time-range-btn, .time-range-button, .timerange-btn, button[data-range]');
|
||||
|
||||
@@ -1426,7 +1401,6 @@ function initTimeRangeToggle() {
|
||||
return !chartModal || !chartModal.contains(button);
|
||||
});
|
||||
|
||||
console.log('找到时间范围按钮数量:', timeRangeButtons.length, '排除了图表模态框内的按钮');
|
||||
|
||||
if (timeRangeButtons.length === 0) {
|
||||
console.warn('未找到时间范围按钮,请检查HTML中的类名');
|
||||
@@ -1471,13 +1445,11 @@ function initTimeRangeToggle() {
|
||||
|
||||
// 移除鼠标悬停提示
|
||||
|
||||
console.log('为按钮设置初始样式:', button.textContent.trim(), '索引:', index, '类名:', Array.from(button.classList).join(', '));
|
||||
|
||||
button.addEventListener('click', function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
console.log('点击按钮:', button.textContent.trim(), '索引:', index);
|
||||
|
||||
// 重置所有按钮为非选中状态
|
||||
timeRangeButtons.forEach((btn, btnIndex) => {
|
||||
@@ -1520,7 +1492,6 @@ function initTimeRangeToggle() {
|
||||
}
|
||||
}
|
||||
currentTimeRange = rangeValue;
|
||||
console.log('更新时间范围为:', currentTimeRange);
|
||||
|
||||
// 重新加载数据
|
||||
loadDashboardData();
|
||||
@@ -1554,7 +1525,6 @@ function initTimeRangeToggle() {
|
||||
defaultButton.classList.add('active');
|
||||
defaultButton.classList.add(...defaultStyle.active);
|
||||
defaultButton.classList.add(...defaultStyle.activeHover);
|
||||
console.log('默认选中24小时按钮:', defaultButton.textContent.trim());
|
||||
|
||||
// 设置默认时间范围为24小时
|
||||
currentTimeRange = '24h';
|
||||
@@ -1877,12 +1847,10 @@ function initExpandButton() {
|
||||
const closeModalBtn = document.getElementById('close-modal-btn'); // 修复ID匹配
|
||||
|
||||
// 添加调试日志
|
||||
console.log('初始化展开按钮功能:', { expandBtn, chartModal, closeModalBtn });
|
||||
|
||||
if (expandBtn && chartModal && closeModalBtn) {
|
||||
// 展开按钮点击事件
|
||||
expandBtn.addEventListener('click', () => {
|
||||
console.log('展开按钮被点击');
|
||||
// 显示浮窗
|
||||
chartModal.classList.remove('hidden');
|
||||
|
||||
@@ -1902,7 +1870,6 @@ function initExpandButton() {
|
||||
|
||||
// 关闭按钮点击事件
|
||||
closeModalBtn.addEventListener('click', () => {
|
||||
console.log('关闭按钮被点击');
|
||||
chartModal.classList.add('hidden');
|
||||
});
|
||||
|
||||
@@ -1910,7 +1877,6 @@ function initExpandButton() {
|
||||
chartModal.addEventListener('click', (e) => {
|
||||
// 检查点击目标是否是遮罩层本身(即最外层div)
|
||||
if (e.target === chartModal) {
|
||||
console.log('点击遮罩层关闭');
|
||||
chartModal.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
@@ -1918,7 +1884,6 @@ function initExpandButton() {
|
||||
// ESC键关闭浮窗
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && !chartModal.classList.contains('hidden')) {
|
||||
console.log('ESC键关闭浮窗');
|
||||
chartModal.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
@@ -1933,7 +1898,6 @@ function initDetailedTimeRangeToggle() {
|
||||
const chartModal = document.getElementById('chart-modal');
|
||||
const detailedTimeRangeButtons = chartModal ? chartModal.querySelectorAll('.time-range-btn') : [];
|
||||
|
||||
console.log('初始化详细图表时间范围切换,找到按钮数量:', detailedTimeRangeButtons.length);
|
||||
|
||||
// 初始化详细图表的默认状态,与主图表保持一致
|
||||
detailedCurrentTimeRange = currentTimeRange;
|
||||
@@ -2016,7 +1980,6 @@ function initDetailedTimeRangeToggle() {
|
||||
}
|
||||
}
|
||||
detailedCurrentTimeRange = rangeValue;
|
||||
console.log('详细图表更新时间范围为:', detailedCurrentTimeRange);
|
||||
|
||||
// 重新绘制详细图表
|
||||
drawDetailedDNSRequestsChart();
|
||||
@@ -2026,7 +1989,6 @@ function initDetailedTimeRangeToggle() {
|
||||
|
||||
// 绘制详细的DNS请求趋势图表
|
||||
function drawDetailedDNSRequestsChart() {
|
||||
console.log('绘制详细DNS请求趋势图表,时间范围:', detailedCurrentTimeRange);
|
||||
|
||||
const ctx = document.getElementById('detailed-dns-requests-chart');
|
||||
if (!ctx) {
|
||||
@@ -2270,8 +2232,6 @@ function drawDNSRequestsChart() {
|
||||
|
||||
// 更新图表数据
|
||||
function updateCharts(stats, queryTypeStats) {
|
||||
console.log('更新图表,收到统计数据:', stats);
|
||||
console.log('查询类型统计数据:', queryTypeStats);
|
||||
|
||||
// 空值检查
|
||||
if (!stats) {
|
||||
@@ -2497,7 +2457,6 @@ function getHostsCountFromStats(stats) {
|
||||
|
||||
// 初始化统计卡片折线图
|
||||
function initStatCardCharts() {
|
||||
console.log('===== 开始初始化统计卡片折线图 =====');
|
||||
|
||||
// 清理已存在的图表实例
|
||||
for (const key in statCardCharts) {
|
||||
@@ -2509,7 +2468,6 @@ function initStatCardCharts() {
|
||||
statCardHistoryData = {};
|
||||
|
||||
// 检查Chart.js是否加载
|
||||
console.log('Chart.js是否可用:', typeof Chart !== 'undefined');
|
||||
|
||||
// 统计卡片配置信息
|
||||
const cardConfigs = [
|
||||
@@ -2525,7 +2483,6 @@ function initStatCardCharts() {
|
||||
{ id: 'hosts-chart', color: '#16a085', label: 'Hosts条目数' }
|
||||
];
|
||||
|
||||
console.log('图表配置:', cardConfigs);
|
||||
|
||||
cardConfigs.forEach(config => {
|
||||
const canvas = document.getElementById(config.id);
|
||||
@@ -3011,7 +2968,6 @@ function addRetryEventListeners() {
|
||||
const retryTopClientsBtn = document.getElementById('retry-top-clients');
|
||||
if (retryTopClientsBtn) {
|
||||
retryTopClientsBtn.addEventListener('click', async () => {
|
||||
console.log('重试获取TOP客户端数据');
|
||||
const clientsData = await api.getTopClients();
|
||||
if (clientsData && !clientsData.error && Array.isArray(clientsData) && clientsData.length > 0) {
|
||||
// 使用真实数据
|
||||
@@ -3030,7 +2986,6 @@ function addRetryEventListeners() {
|
||||
const retryTopDomainsBtn = document.getElementById('retry-top-domains');
|
||||
if (retryTopDomainsBtn) {
|
||||
retryTopDomainsBtn.addEventListener('click', async () => {
|
||||
console.log('重试获取TOP域名数据');
|
||||
const domainsData = await api.getTopDomains();
|
||||
if (domainsData && !domainsData.error && Array.isArray(domainsData) && domainsData.length > 0) {
|
||||
// 使用真实数据
|
||||
@@ -3068,7 +3023,6 @@ window.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
});// 重写loadDashboardData函数,修复语法错误
|
||||
async function loadDashboardData() {
|
||||
console.log('开始加载仪表盘数据');
|
||||
try {
|
||||
// 并行获取所有数据,提高加载效率
|
||||
const [stats, queryTypeStatsResult, topBlockedDomainsResult, recentBlockedDomainsResult, topClientsResult] = await Promise.all([
|
||||
@@ -3093,26 +3047,22 @@ async function loadDashboardData() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('统计数据:', stats);
|
||||
|
||||
// 处理查询类型统计数据
|
||||
let queryTypeStats = null;
|
||||
if (queryTypeStatsResult) {
|
||||
console.log('查询类型统计数据:', queryTypeStatsResult);
|
||||
queryTypeStats = queryTypeStatsResult;
|
||||
} else if (stats.dns && stats.dns.QueryTypes) {
|
||||
queryTypeStats = Object.entries(stats.dns.QueryTypes).map(([type, count]) => ({
|
||||
type,
|
||||
count
|
||||
}));
|
||||
console.log('从stats中提取的查询类型统计:', queryTypeStats);
|
||||
}
|
||||
|
||||
// 处理TOP被屏蔽域名
|
||||
let topBlockedDomains = [];
|
||||
if (topBlockedDomainsResult && Array.isArray(topBlockedDomainsResult)) {
|
||||
topBlockedDomains = topBlockedDomainsResult;
|
||||
console.log('TOP被屏蔽域名:', topBlockedDomains);
|
||||
} else {
|
||||
topBlockedDomains = [
|
||||
{ domain: 'example-blocked.com', count: 15, lastSeen: new Date().toISOString() },
|
||||
@@ -3125,7 +3075,6 @@ async function loadDashboardData() {
|
||||
let recentBlockedDomains = [];
|
||||
if (recentBlockedDomainsResult && Array.isArray(recentBlockedDomainsResult)) {
|
||||
recentBlockedDomains = recentBlockedDomainsResult;
|
||||
console.log('最近屏蔽域名:', recentBlockedDomains);
|
||||
} else {
|
||||
recentBlockedDomains = [
|
||||
{ domain: '---.---.---', ip: '---.---.---.---', timestamp: new Date().toISOString() },
|
||||
@@ -3145,7 +3094,6 @@ async function loadDashboardData() {
|
||||
let topClients = [];
|
||||
if (topClientsResult && !topClientsResult.error && Array.isArray(topClientsResult) && topClientsResult.length > 0) {
|
||||
topClients = topClientsResult;
|
||||
console.log('TOP客户端:', topClients);
|
||||
} else {
|
||||
console.warn('获取TOP客户端失败或数据无效,使用模拟数据');
|
||||
topClients = [
|
||||
@@ -3162,7 +3110,6 @@ async function loadDashboardData() {
|
||||
let topDomains = [];
|
||||
try {
|
||||
const domainsData = await api.getTopDomains();
|
||||
console.log('TOP域名:', domainsData);
|
||||
|
||||
if (domainsData && !domainsData.error && Array.isArray(domainsData) && domainsData.length > 0) {
|
||||
topDomains = domainsData;
|
||||
|
||||
@@ -7,7 +7,7 @@ let logsPerPage = 30; // 默认显示30条记录
|
||||
let currentFilter = '';
|
||||
let currentSearch = '';
|
||||
let logsChart = null;
|
||||
let currentSortField = '';
|
||||
let currentSortField = 'timestamp'; // 默认按时间排序,显示最新记录
|
||||
let currentSortDirection = 'desc'; // 默认降序
|
||||
|
||||
// IP地理位置缓存(检查是否已经存在,避免重复声明)
|
||||
@@ -165,15 +165,12 @@ async function loadTrackersDatabase() {
|
||||
|
||||
// 加载域名信息数据库
|
||||
async function loadDomainInfoDatabase() {
|
||||
console.log('开始加载域名信息数据库');
|
||||
|
||||
if (domainInfoLoaded) {
|
||||
console.log('域名信息数据库已加载,直接返回');
|
||||
return domainInfoDatabase;
|
||||
}
|
||||
|
||||
if (domainInfoLoading) {
|
||||
console.log('域名信息数据库正在加载中,等待完成');
|
||||
// 等待正在进行的加载完成
|
||||
while (domainInfoLoading) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
@@ -184,7 +181,6 @@ async function loadDomainInfoDatabase() {
|
||||
domainInfoLoading = true;
|
||||
|
||||
try {
|
||||
console.log('发起请求获取域名信息数据库');
|
||||
const response = await fetch('domain-info/domains/domain-info.json');
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -194,9 +190,7 @@ async function loadDomainInfoDatabase() {
|
||||
return domainInfoDatabase;
|
||||
}
|
||||
|
||||
console.log('域名信息数据库请求成功,开始解析JSON');
|
||||
domainInfoDatabase = await response.json();
|
||||
console.log('域名信息数据库解析成功,包含', Object.keys(domainInfoDatabase.domains || {}).length, '个公司');
|
||||
domainInfoLoaded = true;
|
||||
return domainInfoDatabase;
|
||||
} catch (error) {
|
||||
@@ -206,7 +200,6 @@ async function loadDomainInfoDatabase() {
|
||||
return domainInfoDatabase;
|
||||
} finally {
|
||||
domainInfoLoading = false;
|
||||
console.log('域名信息数据库加载完成');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,10 +240,8 @@ async function isDomainInTrackerDatabase(domain) {
|
||||
|
||||
// 根据域名查找对应的网站信息
|
||||
async function getDomainInfo(domain) {
|
||||
console.log('开始查找域名信息,域名:', domain);
|
||||
|
||||
if (!domainInfoDatabase || !domainInfoLoaded) {
|
||||
console.log('域名信息数据库未加载,调用loadDomainInfoDatabase');
|
||||
await loadDomainInfoDatabase();
|
||||
}
|
||||
|
||||
@@ -261,29 +252,23 @@ async function getDomainInfo(domain) {
|
||||
|
||||
// 规范化域名,移除可能的端口号
|
||||
const normalizedDomain = domain.replace(/:\d+$/, '').toLowerCase();
|
||||
console.log('规范化后的域名:', normalizedDomain);
|
||||
|
||||
// 遍历所有公司
|
||||
console.log('开始遍历公司,总公司数:', Object.keys(domainInfoDatabase.domains).length);
|
||||
for (const companyKey in domainInfoDatabase.domains) {
|
||||
if (domainInfoDatabase.domains.hasOwnProperty(companyKey)) {
|
||||
console.log('检查公司:', companyKey);
|
||||
const companyData = domainInfoDatabase.domains[companyKey];
|
||||
const companyName = companyData.company || companyKey;
|
||||
|
||||
// 遍历公司下的所有网站和类别
|
||||
for (const websiteKey in companyData) {
|
||||
if (companyData.hasOwnProperty(websiteKey) && websiteKey !== 'company') {
|
||||
console.log(' 检查网站/类别:', websiteKey);
|
||||
const website = companyData[websiteKey];
|
||||
|
||||
// 如果有URL属性,直接检查域名
|
||||
if (website.url) {
|
||||
// 处理字符串类型的URL
|
||||
if (typeof website.url === 'string') {
|
||||
console.log(' 检查字符串URL:', website.url);
|
||||
if (isDomainMatch(website.url, normalizedDomain, website.categoryId)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: website.name,
|
||||
icon: website.icon,
|
||||
@@ -295,13 +280,10 @@ async function getDomainInfo(domain) {
|
||||
}
|
||||
// 处理对象类型的URL
|
||||
else if (typeof website.url === 'object') {
|
||||
console.log(' 检查对象类型URL,包含', Object.keys(website.url).length, '个URL');
|
||||
for (const urlKey in website.url) {
|
||||
if (website.url.hasOwnProperty(urlKey)) {
|
||||
const urlValue = website.url[urlKey];
|
||||
console.log(' 检查URL', urlKey, ':', urlValue);
|
||||
if (isDomainMatch(urlValue, normalizedDomain, website.categoryId)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: website.name,
|
||||
icon: website.icon,
|
||||
@@ -315,18 +297,14 @@ async function getDomainInfo(domain) {
|
||||
}
|
||||
} else if (typeof website === 'object' && website !== null) {
|
||||
// 没有URL属性,可能是嵌套的类别
|
||||
console.log(' 发现嵌套类别,进一步检查');
|
||||
for (const nestedWebsiteKey in website) {
|
||||
if (website.hasOwnProperty(nestedWebsiteKey) && nestedWebsiteKey !== 'company') {
|
||||
console.log(' 检查嵌套网站/类别:', nestedWebsiteKey);
|
||||
const nestedWebsite = website[nestedWebsiteKey];
|
||||
|
||||
if (nestedWebsite.url) {
|
||||
// 处理字符串类型的URL
|
||||
if (typeof nestedWebsite.url === 'string') {
|
||||
console.log(' 检查字符串URL:', nestedWebsite.url);
|
||||
if (isDomainMatch(nestedWebsite.url, normalizedDomain, nestedWebsite.categoryId)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: nestedWebsite.name,
|
||||
icon: nestedWebsite.icon,
|
||||
@@ -338,13 +316,10 @@ async function getDomainInfo(domain) {
|
||||
}
|
||||
// 处理对象类型的URL
|
||||
else if (typeof nestedWebsite.url === 'object') {
|
||||
console.log(' 检查对象类型URL,包含', Object.keys(nestedWebsite.url).length, '个URL');
|
||||
for (const urlKey in nestedWebsite.url) {
|
||||
if (nestedWebsite.url.hasOwnProperty(urlKey)) {
|
||||
const urlValue = nestedWebsite.url[urlKey];
|
||||
console.log(' 检查URL', urlKey, ':', urlValue);
|
||||
if (isDomainMatch(urlValue, normalizedDomain, nestedWebsite.categoryId)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: nestedWebsite.name,
|
||||
icon: nestedWebsite.icon,
|
||||
@@ -358,18 +333,14 @@ async function getDomainInfo(domain) {
|
||||
}
|
||||
} else if (typeof nestedWebsite === 'object' && nestedWebsite !== null) {
|
||||
// 嵌套类别中的嵌套类别,递归检查
|
||||
console.log(' 发现二级嵌套类别,进一步检查');
|
||||
for (const secondNestedWebsiteKey in nestedWebsite) {
|
||||
if (nestedWebsite.hasOwnProperty(secondNestedWebsiteKey) && secondNestedWebsiteKey !== 'company') {
|
||||
console.log(' 检查二级嵌套网站:', secondNestedWebsiteKey);
|
||||
const secondNestedWebsite = nestedWebsite[secondNestedWebsiteKey];
|
||||
|
||||
if (secondNestedWebsite.url) {
|
||||
// 处理字符串类型的URL
|
||||
if (typeof secondNestedWebsite.url === 'string') {
|
||||
console.log(' 检查字符串URL:', secondNestedWebsite.url);
|
||||
if (isDomainMatch(secondNestedWebsite.url, normalizedDomain, secondNestedWebsite.categoryId)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: secondNestedWebsite.name,
|
||||
icon: secondNestedWebsite.icon,
|
||||
@@ -381,13 +352,10 @@ async function getDomainInfo(domain) {
|
||||
}
|
||||
// 处理对象类型的URL
|
||||
else if (typeof secondNestedWebsite.url === 'object') {
|
||||
console.log(' 检查对象类型URL,包含', Object.keys(secondNestedWebsite.url).length, '个URL');
|
||||
for (const urlKey in secondNestedWebsite.url) {
|
||||
if (secondNestedWebsite.url.hasOwnProperty(urlKey)) {
|
||||
const urlValue = secondNestedWebsite.url[urlKey];
|
||||
console.log(' 检查URL', urlKey, ':', urlValue);
|
||||
if (isDomainMatch(urlValue, normalizedDomain, secondNestedWebsite.categoryId)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: secondNestedWebsite.name,
|
||||
icon: secondNestedWebsite.icon,
|
||||
@@ -403,83 +371,67 @@ async function getDomainInfo(domain) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(' 嵌套网站没有URL属性且不是对象类型');
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(' 网站没有URL属性');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('未找到匹配的域名信息');
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查域名是否匹配
|
||||
function isDomainMatch(urlValue, targetDomain, categoryId) {
|
||||
console.log(' 开始匹配URL:', urlValue, '目标域名:', targetDomain, '类别ID:', categoryId);
|
||||
|
||||
// 规范化目标域名,去除末尾的点
|
||||
const normalizedTargetDomain = targetDomain.replace(/\.$/, '').toLowerCase();
|
||||
|
||||
try {
|
||||
// 尝试将URL值解析为完整URL
|
||||
console.log(' 尝试解析URL为完整URL');
|
||||
const url = new URL(urlValue);
|
||||
let hostname = url.hostname.toLowerCase();
|
||||
// 规范化主机名,去除末尾的点
|
||||
hostname = hostname.replace(/\.$/, '');
|
||||
console.log(' 解析成功,主机名:', hostname, '规范化目标域名:', normalizedTargetDomain);
|
||||
|
||||
// 根据类别ID选择匹配方式
|
||||
if (categoryId === 2) {
|
||||
// CDN类别,使用域名后缀匹配
|
||||
if (normalizedTargetDomain.endsWith('.' + hostname) || normalizedTargetDomain === hostname) {
|
||||
console.log(' CDN域名后缀匹配成功');
|
||||
return true;
|
||||
} else {
|
||||
console.log(' CDN域名后缀不匹配');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// 其他类别,使用完整域名匹配
|
||||
if (hostname === normalizedTargetDomain) {
|
||||
console.log(' 完整域名匹配成功');
|
||||
return true;
|
||||
} else {
|
||||
console.log(' 完整域名不匹配');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(' 解析URL失败,将其视为纯域名处理,错误信息:', e.message);
|
||||
// 如果是纯域名而不是完整URL
|
||||
let urlDomain = urlValue.toLowerCase();
|
||||
// 规范化纯域名,去除末尾的点
|
||||
urlDomain = urlDomain.replace(/\.$/, '');
|
||||
console.log(' 处理为纯域名:', urlDomain, '规范化目标域名:', normalizedTargetDomain);
|
||||
|
||||
// 根据类别ID选择匹配方式
|
||||
if (categoryId === 2) {
|
||||
// CDN类别,使用域名后缀匹配
|
||||
if (normalizedTargetDomain.endsWith('.' + urlDomain) || normalizedTargetDomain === urlDomain) {
|
||||
console.log(' CDN域名后缀匹配成功');
|
||||
return true;
|
||||
} else {
|
||||
console.log(' CDN域名后缀不匹配');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// 其他类别,使用完整域名匹配
|
||||
if (urlDomain === normalizedTargetDomain) {
|
||||
console.log(' 完整域名匹配成功');
|
||||
return true;
|
||||
} else {
|
||||
console.log(' 完整域名不匹配');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -488,42 +440,34 @@ function isDomainMatch(urlValue, targetDomain, categoryId) {
|
||||
|
||||
// 提取主域名
|
||||
function extractPrimaryDomain(domain) {
|
||||
console.log(' 开始提取主域名,原始域名:', domain);
|
||||
|
||||
const parts = domain.split('.');
|
||||
console.log(' 域名分割为:', parts);
|
||||
|
||||
if (parts.length <= 2) {
|
||||
console.log(' 域名长度小于等于2,直接返回:', domain);
|
||||
return domain;
|
||||
}
|
||||
|
||||
// 处理常见的三级域名
|
||||
const commonSubdomains = ['www', 'mail', 'news', 'map', 'image', 'video', 'cdn', 'api', 'blog', 'shop', 'cloud', 'docs', 'help', 'support', 'dev', 'test', 'staging'];
|
||||
console.log(' 检查是否为常见三级域名');
|
||||
|
||||
if (commonSubdomains.includes(parts[0])) {
|
||||
const result = parts.slice(1).join('.');
|
||||
console.log(' 是常见三级域名,返回:', result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 处理特殊情况,如co.uk, co.jp等
|
||||
const countryTLDs = ['co.uk', 'co.jp', 'co.kr', 'co.in', 'co.ca', 'co.au', 'co.nz', 'co.th', 'co.sg', 'co.my', 'co.id', 'co.za', 'com.cn', 'org.cn', 'net.cn', 'gov.cn', 'edu.cn'];
|
||||
console.log(' 检查是否为特殊国家TLD');
|
||||
|
||||
for (const tld of countryTLDs) {
|
||||
if (domain.endsWith('.' + tld)) {
|
||||
const mainParts = domain.split('.');
|
||||
const result = mainParts.slice(-tld.split('.').length - 1).join('.');
|
||||
console.log(' 是特殊国家TLD,返回:', result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认情况:返回最后两个部分
|
||||
const result = parts.slice(-2).join('.');
|
||||
console.log(' 默认情况,返回最后两个部分:', result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -793,7 +737,6 @@ function initResizableColumns() {
|
||||
|
||||
// 初始化查询日志页面
|
||||
function initLogsPage() {
|
||||
console.log('初始化查询日志页面');
|
||||
|
||||
// 加载日志统计数据
|
||||
loadLogsStats();
|
||||
@@ -992,6 +935,9 @@ function bindLogsEvents() {
|
||||
loadLogs();
|
||||
});
|
||||
});
|
||||
|
||||
// 初始化排序图标
|
||||
updateSortIcons();
|
||||
}
|
||||
|
||||
// 更新排序图标
|
||||
@@ -1345,7 +1291,6 @@ async function updateLogsTable(logs) {
|
||||
if (e.target.closest('button')) {
|
||||
return;
|
||||
}
|
||||
console.log('Row clicked, log object:', log);
|
||||
showLogDetailModal(log);
|
||||
});
|
||||
|
||||
@@ -1479,14 +1424,12 @@ function connectLogsWebSocket() {
|
||||
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsUrl = `${wsProtocol}//${window.location.host}/ws/stats`;
|
||||
|
||||
console.log('正在连接WebSocket:', wsUrl);
|
||||
|
||||
// 创建WebSocket连接
|
||||
logsWsConnection = new WebSocket(wsUrl);
|
||||
|
||||
// 连接打开事件
|
||||
logsWsConnection.onopen = function() {
|
||||
console.log('WebSocket连接已建立');
|
||||
};
|
||||
|
||||
// 接收消息事件
|
||||
@@ -1495,7 +1438,6 @@ function connectLogsWebSocket() {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if (data.type === 'initial_data' || data.type === 'stats_update') {
|
||||
console.log('收到实时数据更新');
|
||||
// 只更新统计数据,不更新日志详情
|
||||
updateLogsStatsFromWebSocket(data.data);
|
||||
}
|
||||
@@ -1530,7 +1472,6 @@ function setupLogsReconnect() {
|
||||
}
|
||||
|
||||
const reconnectDelay = 5000; // 5秒后重连
|
||||
console.log(`将在${reconnectDelay}ms后尝试重新连接WebSocket`);
|
||||
|
||||
logsWsReconnectTimer = setTimeout(() => {
|
||||
connectLogsWebSocket();
|
||||
@@ -1567,17 +1508,13 @@ function updateLogsStatsFromWebSocket(stats) {
|
||||
// 拦截域名
|
||||
async function blockDomain(domain) {
|
||||
try {
|
||||
console.log(`开始拦截域名: ${domain}`);
|
||||
|
||||
// 创建拦截规则,使用AdBlock Plus格式
|
||||
const blockRule = `||${domain}^`;
|
||||
console.log(`创建的拦截规则: ${blockRule}`);
|
||||
|
||||
// 调用API添加拦截规则
|
||||
console.log(`调用API添加拦截规则,路径: /shield, 方法: POST`);
|
||||
const response = await apiRequest('/shield', 'POST', { rule: blockRule });
|
||||
|
||||
console.log(`API响应:`, response);
|
||||
|
||||
// 处理不同的响应格式
|
||||
if (response && (response.success || response.status === 'success')) {
|
||||
@@ -1665,17 +1602,13 @@ async function refreshRulesList() {
|
||||
// 放行域名
|
||||
async function unblockDomain(domain) {
|
||||
try {
|
||||
console.log(`开始放行域名: ${domain}`);
|
||||
|
||||
// 创建放行规则,使用AdBlock Plus格式
|
||||
const allowRule = `@@||${domain}^`;
|
||||
console.log(`创建的放行规则: ${allowRule}`);
|
||||
|
||||
// 调用API添加放行规则
|
||||
console.log(`调用API添加放行规则,路径: /shield, 方法: POST`);
|
||||
const response = await apiRequest('/shield', 'POST', { rule: allowRule });
|
||||
|
||||
console.log(`API响应:`, response);
|
||||
|
||||
// 处理不同的响应格式
|
||||
if (response && (response.success || response.status === 'success')) {
|
||||
@@ -1808,7 +1741,6 @@ function formatDNSString(str) {
|
||||
|
||||
// 显示日志详情弹窗
|
||||
async function showLogDetailModal(log) {
|
||||
console.log('showLogDetailModal called with log:', JSON.stringify(log, null, 2)); // 输出完整的log对象
|
||||
|
||||
if (!log) {
|
||||
console.error('No log data provided!');
|
||||
|
||||
Reference in New Issue
Block a user