// logs.js - 查询日志页面功能

// 全局变量
let currentPage = 1;
let totalPages = 1;
let logsPerPage = 30; // 默认显示30条记录
let currentFilter = '';
let currentSearch = '';
let logsChart = null;
let currentSortField = 'timestamp'; // 默认按时间排序，显示最新记录
let currentSortDirection = 'desc'; // 默认降序

// IP地理位置缓存（检查是否已经存在，避免重复声明）
if (typeof ipGeolocationCache === 'undefined') {
    var ipGeolocationCache = {};
    var GEOLOCATION_CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 缓存有效期24小时
}

// 获取IP地理位置信息
async function getIpGeolocation(ip) {
    // 检查是否为内网IP
    if (isPrivateIP(ip)) {
        return "内网 内网";
    }
    
    // 检查缓存
    const now = Date.now();
    if (ipGeolocationCache[ip] && (now - ipGeolocationCache[ip].timestamp) < GEOLOCATION_CACHE_EXPIRY) {
        return ipGeolocationCache[ip].location;
    }
    
    try {
        // 使用whois.pconline.com.cn API获取IP地理位置
        const url = `https://whois.pconline.com.cn/ipJson.jsp?ip=${ip}&json=true`;
        const response = await fetch(url, {
            headers: {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
            }
        });
        
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        // 解析响应数据
        const data = await response.json();
        let location = "未知 未知";
        
        if (data && data.addr) {
            // 直接使用addr字段作为完整的地理位置信息
            location = data.addr;
        }
        
        // 保存到缓存
        ipGeolocationCache[ip] = {
            location: location,
            timestamp: now
        };
        
        return location;
    } catch (error) {
        console.error('获取IP地理位置失败:', error);
        return "未知 未知";
    }
}

// 检查是否为内网IP
function isPrivateIP(ip) {
    const parts = ip.split('.');
    
    // 检查IPv4内网地址
    if (parts.length === 4) {
        const first = parseInt(parts[0]);
        const second = parseInt(parts[1]);
        
        // 10.0.0.0/8
        if (first === 10) {
            return true;
        }
        // 172.16.0.0/12
        if (first === 172 && second >= 16 && second <= 31) {
            return true;
        }
        // 192.168.0.0/16
        if (first === 192 && second === 168) {
            return true;
        }
        // 127.0.0.0/8 (localhost)
        if (first === 127) {
            return true;
        }
        // 169.254.0.0/16 (link-local)
        if (first === 169 && second === 254) {
            return true;
        }
    }
    
    // 检查IPv6内网地址
    if (ip.includes(':')) {
        // ::1/128 (localhost)
        if (ip === '::1' || ip.startsWith('0:0:0:0:0:0:0:1')) {
            return true;
        }
        // fc00::/7 (unique local address)
        if (ip.startsWith('fc') || ip.startsWith('fd')) {
            return true;
        }
        // fe80::/10 (link-local)
        if (ip.startsWith('fe80:')) {
            return true;
        }
    }
    
    return false;
}

// 跟踪器数据库缓存（检查是否已经存在，避免重复声明）
if (typeof trackersDatabase === 'undefined') {
    var trackersDatabase = null;
    var trackersLoaded = false;
    var trackersLoading = false;
}

// 域名信息数据库缓存
let domainInfoDatabase = null;
let domainInfoLoaded = false;
let domainInfoLoading = false;

// WebSocket连接和重连计时器
let logsWsConnection = null;
let logsWsReconnectTimer = null;

// 加载跟踪器数据库
async function loadTrackersDatabase() {
    if (trackersLoaded) return trackersDatabase;
    if (trackersLoading) {
        // 等待正在进行的加载完成
        while (trackersLoading) {
            await new Promise(resolve => setTimeout(resolve, 100));
        }
        return trackersDatabase;
    }
    
    trackersLoading = true;
    
    try {
        const response = await fetch('domain-info/tracker/trackers.json');
        if (!response.ok) {
            console.error('加载跟踪器数据库失败:', response.statusText);
            trackersDatabase = { trackers: {} };
            return trackersDatabase;
        }
        
        trackersDatabase = await response.json();
        trackersLoaded = true;
        return trackersDatabase;
    } catch (error) {
        console.error('加载跟踪器数据库失败:', error);
        trackersDatabase = { trackers: {} };
        return trackersDatabase;
    } finally {
        trackersLoading = false;
    }
}

// 加载域名信息数据库
async function loadDomainInfoDatabase() {
    
    if (domainInfoLoaded) {
        return domainInfoDatabase;
    }
    
    if (domainInfoLoading) {
        // 等待正在进行的加载完成
        while (domainInfoLoading) {
            await new Promise(resolve => setTimeout(resolve, 100));
        }
        return domainInfoDatabase;
    }
    
    domainInfoLoading = true;
    
    try {
        const response = await fetch('domain-info/domains/domain-info.json');
        
        if (!response.ok) {
            console.error('加载域名信息数据库失败，HTTP状态:', response.status, response.statusText);
            console.error('请求URL:', response.url);
            domainInfoDatabase = { domains: {}, categories: {} };
            return domainInfoDatabase;
        }
        
        domainInfoDatabase = await response.json();
        domainInfoLoaded = true;
        return domainInfoDatabase;
    } catch (error) {
        console.error('加载域名信息数据库失败，错误信息:', error.message);
        console.error('错误堆栈:', error.stack);
        domainInfoDatabase = { domains: {}, categories: {} };
        return domainInfoDatabase;
    } finally {
        domainInfoLoading = false;
    }
}

// 检查域名是否在跟踪器数据库中，并返回跟踪器信息
async function isDomainInTrackerDatabase(domain) {
    if (!trackersDatabase || !trackersLoaded) {
        await loadTrackersDatabase();
    }
    
    if (!trackersDatabase || !trackersDatabase.trackers) {
        return null;
    }
    
    // 检查域名是否直接作为跟踪器键存在
    if (trackersDatabase.trackers.hasOwnProperty(domain)) {
        return trackersDatabase.trackers[domain];
    }
    
    // 检查域名是否在跟踪器URL中
    for (const trackerKey in trackersDatabase.trackers) {
        if (trackersDatabase.trackers.hasOwnProperty(trackerKey)) {
            const tracker = trackersDatabase.trackers[trackerKey];
            if (tracker && tracker.url) {
                try {
                    const trackerUrl = new URL(tracker.url);
                    if (trackerUrl.hostname === domain) {
                        return tracker;
                    }
                } catch (e) {
                    // 忽略无效URL
                }
            }
        }
    }
    
    return null;
}

// 根据域名查找对应的网站信息
async function getDomainInfo(domain) {
    
    if (!domainInfoDatabase || !domainInfoLoaded) {
        await loadDomainInfoDatabase();
    }
    
    if (!domainInfoDatabase || !domainInfoDatabase.domains) {
        console.error('域名信息数据库无效或为空');
        return null;
    }
    
    // 规范化域名，移除可能的端口号
    const normalizedDomain = domain.replace(/:\d+$/, '').toLowerCase();
    
    // 遍历所有公司
    for (const companyKey in domainInfoDatabase.domains) {
        if (domainInfoDatabase.domains.hasOwnProperty(companyKey)) {
            const companyData = domainInfoDatabase.domains[companyKey];
            const companyName = companyData.company || companyKey;
            
            // 遍历公司下的所有网站和类别
            for (const websiteKey in companyData) {
                if (companyData.hasOwnProperty(websiteKey) && websiteKey !== 'company') {
                    const website = companyData[websiteKey];
                    
                    // 如果有URL属性，直接检查域名
                    if (website.url) {
                        // 处理字符串类型的URL
                        if (typeof website.url === 'string') {
                            if (isDomainMatch(website.url, normalizedDomain, website.categoryId)) {
                                return {
                                    name: website.name,
                                    icon: website.icon,
                                    categoryId: website.categoryId,
                                    categoryName: domainInfoDatabase.categories[website.categoryId] || '未知',
                                    company: website.company || companyName
                                };
                            }
                        }
                        // 处理对象类型的URL
                        else if (typeof website.url === 'object') {
                            for (const urlKey in website.url) {
                                if (website.url.hasOwnProperty(urlKey)) {
                                    const urlValue = website.url[urlKey];
                                    if (isDomainMatch(urlValue, normalizedDomain, website.categoryId)) {
                                        return {
                                            name: website.name,
                                            icon: website.icon,
                                            categoryId: website.categoryId,
                                            categoryName: domainInfoDatabase.categories[website.categoryId] || '未知',
                                            company: website.company || companyName
                                        };
                                    }
                                }
                            }
                        }
                    } else if (typeof website === 'object' && website !== null) {
                        // 没有URL属性，可能是嵌套的类别
                        for (const nestedWebsiteKey in website) {
                            if (website.hasOwnProperty(nestedWebsiteKey) && nestedWebsiteKey !== 'company') {
                                const nestedWebsite = website[nestedWebsiteKey];
                                
                                if (nestedWebsite.url) {
                                    // 处理字符串类型的URL
                                    if (typeof nestedWebsite.url === 'string') {
                                        if (isDomainMatch(nestedWebsite.url, normalizedDomain, nestedWebsite.categoryId)) {
                                            return {
                                                name: nestedWebsite.name,
                                                icon: nestedWebsite.icon,
                                                categoryId: nestedWebsite.categoryId,
                                                categoryName: domainInfoDatabase.categories[nestedWebsite.categoryId] || '未知',
                                                company: nestedWebsite.company || companyName
                                            };
                                        }
                                    }
                                    // 处理对象类型的URL
                                    else if (typeof nestedWebsite.url === 'object') {
                                        for (const urlKey in nestedWebsite.url) {
                                            if (nestedWebsite.url.hasOwnProperty(urlKey)) {
                                                const urlValue = nestedWebsite.url[urlKey];
                                                if (isDomainMatch(urlValue, normalizedDomain, nestedWebsite.categoryId)) {
                                                    return {
                                                        name: nestedWebsite.name,
                                                        icon: nestedWebsite.icon,
                                                        categoryId: nestedWebsite.categoryId,
                                                        categoryName: domainInfoDatabase.categories[nestedWebsite.categoryId] || '未知',
                                                        company: nestedWebsite.company || companyName
                                                    };
                                                }
                                            }
                                        }
                                    }
                                } else if (typeof nestedWebsite === 'object' && nestedWebsite !== null) {
                                    // 嵌套类别中的嵌套类别，递归检查
                                    for (const secondNestedWebsiteKey in nestedWebsite) {
                                        if (nestedWebsite.hasOwnProperty(secondNestedWebsiteKey) && secondNestedWebsiteKey !== 'company') {
                                            const secondNestedWebsite = nestedWebsite[secondNestedWebsiteKey];
                                            
                                            if (secondNestedWebsite.url) {
                                                // 处理字符串类型的URL
                                                if (typeof secondNestedWebsite.url === 'string') {
                                                    if (isDomainMatch(secondNestedWebsite.url, normalizedDomain, secondNestedWebsite.categoryId)) {
                                                        return {
                                                            name: secondNestedWebsite.name,
                                                            icon: secondNestedWebsite.icon,
                                                            categoryId: secondNestedWebsite.categoryId,
                                                            categoryName: domainInfoDatabase.categories[secondNestedWebsite.categoryId] || '未知',
                                                            company: secondNestedWebsite.company || companyName
                                                        };
                                                    }
                                                }
                                                // 处理对象类型的URL
                                                else if (typeof secondNestedWebsite.url === 'object') {
                                                    for (const urlKey in secondNestedWebsite.url) {
                                                        if (secondNestedWebsite.url.hasOwnProperty(urlKey)) {
                                                            const urlValue = secondNestedWebsite.url[urlKey];
                                                            if (isDomainMatch(urlValue, normalizedDomain, secondNestedWebsite.categoryId)) {
                                                                return {
                                                                    name: secondNestedWebsite.name,
                                                                    icon: secondNestedWebsite.icon,
                                                                    categoryId: secondNestedWebsite.categoryId,
                                                                    categoryName: domainInfoDatabase.categories[secondNestedWebsite.categoryId] || '未知',
                                                                    company: secondNestedWebsite.company || companyName
                                                                };
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                } else {
                                }
                            }
                        }
                    } else {
                    }
                }
            }
        }
    }
    
    return null;
}

// 检查域名是否匹配
function isDomainMatch(urlValue, targetDomain, categoryId) {
    
    // 规范化目标域名，去除末尾的点
    const normalizedTargetDomain = targetDomain.replace(/\.$/, '').toLowerCase();
    
    try {
        // 尝试将URL值解析为完整URL
        const url = new URL(urlValue);
        let hostname = url.hostname.toLowerCase();
        // 规范化主机名，去除末尾的点
        hostname = hostname.replace(/\.$/, '');
        
        // 根据类别ID选择匹配方式
        if (categoryId === 2) {
            // CDN类别，使用域名后缀匹配
            if (normalizedTargetDomain.endsWith('.' + hostname) || normalizedTargetDomain === hostname) {
                return true;
            } else {
                return false;
            }
        } else {
            // 其他类别，使用完整域名匹配
            if (hostname === normalizedTargetDomain) {
                return true;
            } else {
                return false;
            }
        }
    } catch (e) {
        // 如果是纯域名而不是完整URL
        let urlDomain = urlValue.toLowerCase();
        // 规范化纯域名，去除末尾的点
        urlDomain = urlDomain.replace(/\.$/, '');
        
        // 根据类别ID选择匹配方式
        if (categoryId === 2) {
            // CDN类别，使用域名后缀匹配
            if (normalizedTargetDomain.endsWith('.' + urlDomain) || normalizedTargetDomain === urlDomain) {
                return true;
            } else {
                return false;
            }
        } else {
            // 其他类别，使用完整域名匹配
            if (urlDomain === normalizedTargetDomain) {
                return true;
            } else {
                return false;
            }
        }
    }
}

// 提取主域名
function extractPrimaryDomain(domain) {
    
    const parts = domain.split('.');
    
    if (parts.length <= 2) {
        return domain;
    }
    
    // 处理常见的三级域名
    const commonSubdomains = ['www', 'mail', 'news', 'map', 'image', 'video', 'cdn', 'api', 'blog', 'shop', 'cloud', 'docs', 'help', 'support', 'dev', 'test', 'staging'];
    
    if (commonSubdomains.includes(parts[0])) {
        const result = parts.slice(1).join('.');
        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'];
    
    for (const tld of countryTLDs) {
        if (domain.endsWith('.' + tld)) {
            const mainParts = domain.split('.');
            const result = mainParts.slice(-tld.split('.').length - 1).join('.');
            return result;
        }
    }
    
    // 默认情况：返回最后两个部分
    const result = parts.slice(-2).join('.');
    return result;
}

// 初始化列宽调节功能
function initResizableColumns() {
    const table = document.querySelector('.resizable-table');
    if (!table) return;
    
    // 为每个表头添加调整手柄元素
    function addResizeHandles() {
        const headers = table.querySelectorAll('th');
        headers.forEach(header => {
            // 移除已存在的手柄
            const existingHandle = header.querySelector('.resize-handle');
            if (existingHandle) {
                existingHandle.remove();
            }
            
            // 创建新的调整手柄
            const resizeHandle = document.createElement('div');
            resizeHandle.className = 'resize-handle';
            resizeHandle.style.cssText = `
                position: absolute;
                top: 0;
                right: 0;
                width: 10px;
                height: 100%;
                cursor: col-resize;
                background: rgba(59, 130, 246, 0.1);
                z-index: 10;
                transition: background-color 0.2s ease;
            `;
            
            // 添加悬停效果
            resizeHandle.addEventListener('mouseenter', () => {
                resizeHandle.style.background = 'rgba(59, 130, 246, 0.3)';
            });
            
            resizeHandle.addEventListener('mouseleave', () => {
                if (!resizeHandle.classList.contains('dragging')) {
                    resizeHandle.style.background = 'rgba(59, 130, 246, 0.1)';
                }
            });
            
            header.style.position = 'relative';
            header.appendChild(resizeHandle);
        });
    }
    
    // 计算列宽并设置固定宽度
    function calculateAndSetColumnWidths() {
        // 确保表格可见
        table.style.visibility = 'visible';
        
        // 保存当前表格布局
        const originalLayout = table.style.tableLayout;
        table.style.tableLayout = 'auto';
        
        // 获取所有表头和数据行
        const headers = table.querySelectorAll('th');
        const rows = table.querySelectorAll('tbody tr');
        
        // 计算每列的最大宽度
        const columnWidths = [];
        headers.forEach((header, index) => {
            // 获取表头宽度
            let maxWidth = header.offsetWidth;
            
            // 遍历所有数据行，找到该列的最大宽度
            rows.forEach(row => {
                const cell = row.children[index];
                if (cell) {
                    maxWidth = Math.max(maxWidth, cell.offsetWidth);
                }
            });
            
            // 添加一些 padding
            maxWidth += 20;
            
            // 保存最大宽度
            columnWidths[index] = maxWidth;
        });
        
        // 设置每列的固定宽度
        headers.forEach((header, index) => {
            const width = `${columnWidths[index]}px`;
            header.style.width = width;
            header.style.minWidth = width;
            header.style.maxWidth = width;
            
            // 找到对应的数据列并设置宽度
            rows.forEach(row => {
                const cell = row.children[index];
                if (cell) {
                    cell.style.width = width;
                    cell.style.minWidth = width;
                    cell.style.maxWidth = width;
                }
            });
        });
        
        // 恢复表格布局
        table.style.tableLayout = 'fixed';
    }
    
    // 保存列宽设置的函数
    function saveColumnWidths() {
        const headers = table.querySelectorAll('th');
        const columnWidths = {};
        headers.forEach((header, index) => {
            columnWidths[index] = header.style.width;
        });
        localStorage.setItem('logsTableColumnWidths', JSON.stringify(columnWidths));
    }
    
    // 恢复列宽设置的函数
    function restoreColumnWidths() {
        const headers = table.querySelectorAll('th');
        const savedWidths = localStorage.getItem('logsTableColumnWidths');
        
        if (savedWidths) {
            const columnWidths = JSON.parse(savedWidths);
            
            // 设置表格布局为fixed
            table.style.tableLayout = 'fixed';
            
            headers.forEach((header, index) => {
                if (columnWidths[index]) {
                    const width = columnWidths[index];
                    header.style.width = width;
                    header.style.minWidth = width;
                    header.style.maxWidth = width;
                    
                    // 找到对应的数据列并设置宽度
                    const rows = table.querySelectorAll('tbody tr');
                    rows.forEach(row => {
                        const cell = row.children[index];
                        if (cell) {
                            cell.style.width = width;
                            cell.style.minWidth = width;
                            cell.style.maxWidth = width;
                        }
                    });
                }
            });
        } else {
            // 没有保存的宽度，计算并设置列宽
            calculateAndSetColumnWidths();
        }
    }
    
    // 恢复保存的列宽设置或计算初始列宽
    restoreColumnWidths();
    
    // 添加调整手柄
    addResizeHandles();
    
    // 拖拽状态变量
    let currentHeader = null;
    let startX = 0;
    let startWidth = 0;
    let isDragging = false;
    
    // 鼠标按下事件
    table.addEventListener('mousedown', (e) => {
        const resizeHandle = e.target.closest('.resize-handle');
        if (resizeHandle) {
            currentHeader = resizeHandle.parentElement;
            startX = e.clientX;
            startWidth = currentHeader.offsetWidth;
            isDragging = true;
            
            // 添加拖拽状态类
            currentHeader.classList.add('dragging');
            resizeHandle.classList.add('dragging');
            
            // 改变拖拽手柄样式
            resizeHandle.style.background = 'rgba(59, 130, 246, 0.6)';
            
            // 阻止默认事件和冒泡
            e.preventDefault();
            e.stopPropagation();
            
            // 阻止文本选择
            document.addEventListener('selectstart', preventSelect, { capture: true });
            document.addEventListener('copy', preventCopy, { capture: true });
            
            // 添加全局事件监听器
            document.addEventListener('mousemove', onMouseMove, { capture: true });
            document.addEventListener('mouseup', onMouseUp, { capture: true });
        }
    });
    
    // 鼠标移动事件处理函数
    function onMouseMove(e) {
        if (!currentHeader) return;
        
        // 阻止默认事件
        e.preventDefault();
        e.stopPropagation();
        
        // 计算新宽度
        const deltaX = e.clientX - startX;
        const newWidth = Math.max(50, startWidth + deltaX);
        
        // 设置新宽度
        const width = `${newWidth}px`;
        currentHeader.style.width = width;
        currentHeader.style.minWidth = width;
        currentHeader.style.maxWidth = width;
        
        // 找到对应的数据列并设置宽度
        const headers = table.querySelectorAll('th');
        const index = Array.from(headers).indexOf(currentHeader);
        const rows = table.querySelectorAll('tbody tr');
        rows.forEach(row => {
            const cell = row.children[index];
            if (cell) {
                cell.style.width = width;
                cell.style.minWidth = width;
                cell.style.maxWidth = width;
            }
        });
    }
    
    // 鼠标释放事件处理函数
    function onMouseUp(e) {
        if (!currentHeader) return;
        
        // 阻止默认事件
        e.preventDefault();
        e.stopPropagation();
        
        // 获取调整手柄
        const resizeHandle = currentHeader.querySelector('.resize-handle');
        
        // 移除拖拽状态类
        currentHeader.classList.remove('dragging');
        resizeHandle.classList.remove('dragging');
        
        // 恢复拖拽手柄样式
        resizeHandle.style.background = 'rgba(59, 130, 246, 0.1)';
        
        // 保存列宽设置
        saveColumnWidths();
        
        // 重置状态
        currentHeader = null;
        isDragging = false;
        
        // 移除事件监听器
        document.removeEventListener('selectstart', preventSelect, { capture: true });
        document.removeEventListener('copy', preventCopy, { capture: true });
        document.removeEventListener('mousemove', onMouseMove, { capture: true });
        document.removeEventListener('mouseup', onMouseUp, { capture: true });
    }
    
    // 阻止文本选择和复制
    function preventSelect(e) {
        e.preventDefault();
    }
    
    function preventCopy(e) {
        e.preventDefault();
    }
}

// 初始化查询日志页面
function initLogsPage() {
    
    // 加载日志统计数据
    loadLogsStats();
    
    // 加载日志详情
    loadLogs();
    
    // 初始化图表
    initLogsChart();
    
    // 绑定事件
    bindLogsEvents();
    
    // 初始化日志详情弹窗
    initLogDetailModal();
    
    // 建立WebSocket连接，用于实时更新统计数据和图表
    connectLogsWebSocket();
    
    // 初始化列宽调节功能
    initResizableColumns();
    
    // 窗口大小改变时重新加载日志表格
    window.addEventListener('resize', handleWindowResize);
    
    // 在页面卸载时清理资源
    window.addEventListener('beforeunload', cleanupLogsResources);
}

// 处理窗口大小改变
function handleWindowResize() {
    // 重新加载日志表格，以适应新的屏幕尺寸
    loadLogs();
}

// 清理资源
function cleanupLogsResources() {
    // 清除WebSocket连接
    if (logsWsConnection) {
        logsWsConnection.close();
        logsWsConnection = null;
    }
    
    // 清除重连计时器
    if (logsWsReconnectTimer) {
        clearTimeout(logsWsReconnectTimer);
        logsWsReconnectTimer = null;
    }
    
    // 清除窗口大小改变事件监听器
    window.removeEventListener('resize', handleWindowResize);
}

// 绑定事件
function bindLogsEvents() {
    // 搜索按钮
    const searchBtn = document.getElementById('logs-search-btn');
    if (searchBtn) {
        searchBtn.addEventListener('click', () => {
            currentSearch = document.getElementById('logs-search').value;
            currentPage = 1;
            loadLogs();
        });
    }
    
    // 搜索框回车事件
    const searchInput = document.getElementById('logs-search');
    if (searchInput) {
        searchInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                currentSearch = searchInput.value;
                currentPage = 1;
                loadLogs();
            }
        });
    }
    
    // 结果过滤
    const resultFilter = document.getElementById('logs-result-filter');
    if (resultFilter) {
        resultFilter.addEventListener('change', () => {
            currentFilter = resultFilter.value;
            currentPage = 1;
            loadLogs();
        });
    }
    
    // 自定义记录数量
    const perPageSelect = document.getElementById('logs-per-page');
    if (perPageSelect) {
        perPageSelect.addEventListener('change', () => {
            logsPerPage = parseInt(perPageSelect.value);
            currentPage = 1;
            loadLogs();
        });
    }
    
    // 分页按钮
    const prevBtn = document.getElementById('logs-prev-page');
    const nextBtn = document.getElementById('logs-next-page');
    
    if (prevBtn) {
        prevBtn.addEventListener('click', () => {
            if (currentPage > 1) {
                currentPage--;
                loadLogs();
            }
        });
    }
    
    if (nextBtn) {
        nextBtn.addEventListener('click', () => {
            if (currentPage < totalPages) {
                currentPage++;
                loadLogs();
            }
        });
    }
    
    // 页码跳转
    const pageInput = document.getElementById('logs-page-input');
    const goBtn = document.getElementById('logs-go-page');
    
    if (pageInput) {
        // 页码输入框回车事件
        pageInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                const page = parseInt(pageInput.value);
                if (page >= 1 && page <= totalPages) {
                    currentPage = page;
                    loadLogs();
                }
            }
        });
    }
    
    if (goBtn) {
        // 前往按钮点击事件
        goBtn.addEventListener('click', () => {
            const page = parseInt(pageInput.value);
            if (page >= 1 && page <= totalPages) {
                currentPage = page;
                loadLogs();
            }
        });
    }
    
    // 时间范围切换
    const timeRangeBtns = document.querySelectorAll('.time-range-btn');
    timeRangeBtns.forEach(btn => {
        btn.addEventListener('click', () => {
            // 更新按钮样式
            timeRangeBtns.forEach(b => {
                b.classList.remove('bg-primary', 'text-white');
                b.classList.add('bg-gray-200', 'text-gray-700');
            });
            btn.classList.remove('bg-gray-200', 'text-gray-700');
            btn.classList.add('bg-primary', 'text-white');
            
            // 更新图表
            const range = btn.getAttribute('data-range');
            updateLogsChart(range);
        });
    });
    
    // 刷新按钮事件
    const refreshBtn = document.getElementById('logs-refresh-btn');
    if (refreshBtn) {
        refreshBtn.addEventListener('click', () => {
            // 重新加载日志
            currentPage = 1;
            loadLogs();
        });
    }
    
    // 排序按钮事件
    const sortHeaders = document.querySelectorAll('th[data-sort]');
    sortHeaders.forEach(header => {
        header.addEventListener('click', () => {
            const sortField = header.getAttribute('data-sort');
            
            // 如果点击的是当前排序字段，则切换排序方向
            if (sortField === currentSortField) {
                currentSortDirection = currentSortDirection === 'asc' ? 'desc' : 'asc';
            } else {
                // 否则，设置新的排序字段，默认降序
                currentSortField = sortField;
                currentSortDirection = 'desc';
            }
            
            // 更新排序图标
            updateSortIcons();
            
            // 重新加载日志
            currentPage = 1;
            loadLogs();
        });
    });
    
    // 初始化排序图标
    updateSortIcons();
}

// 更新排序图标
function updateSortIcons() {
    const sortHeaders = document.querySelectorAll('th[data-sort]');
    sortHeaders.forEach(header => {
        const sortField = header.getAttribute('data-sort');
        const icon = header.querySelector('i');
        
        // 重置所有图标
        icon.className = 'fa fa-sort ml-1 text-xs';
        
        // 设置当前排序字段的图标
        if (sortField === currentSortField) {
            if (currentSortDirection === 'asc') {
                icon.className = 'fa fa-sort-asc ml-1 text-xs';
            } else {
                icon.className = 'fa fa-sort-desc ml-1 text-xs';
            }
        }
    });
}

// 加载日志统计数据
function loadLogsStats() {
    // 使用封装的apiRequest函数进行API调用
    apiRequest('/logs/stats')
        .then(data => {
            if (data && data.error) {
                console.error('加载日志统计数据失败:', data.error);
                return;
            }
            
            // 更新统计卡片
            document.getElementById('logs-total-queries').textContent = data.totalQueries;
            document.getElementById('logs-avg-response-time').textContent = data.avgResponseTime.toFixed(2) + 'ms';
            document.getElementById('logs-active-ips').textContent = data.activeIPs;
            
            // 计算屏蔽率
            const blockRate = data.totalQueries > 0 ? (data.blockedQueries / data.totalQueries * 100).toFixed(1) : '0';
            document.getElementById('logs-block-rate').textContent = blockRate + '%';
        })
        .catch(error => {
            console.error('加载日志统计数据失败:', error);
        });
}

// 加载日志详情
async function loadLogs() {
    // 显示加载状态
    const loadingEl = document.getElementById('logs-loading');
    if (loadingEl) {
        loadingEl.classList.remove('hidden');
    }
    
    // 构建请求URL
    let endpoint = `/logs/query?limit=${logsPerPage}&offset=${(currentPage - 1) * logsPerPage}`;
    
    // 添加过滤条件
    if (currentFilter) {
        endpoint += `&result=${currentFilter}`;
    }
    
    // 添加搜索条件
    if (currentSearch) {
        endpoint += `&search=${encodeURIComponent(currentSearch)}`;
    }
    
    // 添加排序条件
    if (currentSortField) {
        endpoint += `&sort=${currentSortField}&direction=${currentSortDirection}`;
    }
    
    try {
        // 使用封装的apiRequest函数进行API调用
        const logsData = await apiRequest(endpoint);
        
        if (logsData && logsData.error) {
            console.error('加载日志详情失败:', logsData.error);
            // 隐藏加载状态
            if (loadingEl) {
                loadingEl.classList.add('hidden');
            }
            return;
        }
        
        // 加载日志总数
        const [logs, countData] = await Promise.all([
            Promise.resolve(logsData || []), // 确保logsData是数组
            apiRequest('/logs/count')
        ]);
        
        // 确保logs是数组
        const logsArray = Array.isArray(logs) ? logs : [];
        // 确保countData是有效的
        const totalLogs = countData && countData.count ? countData.count : logsArray.length;
        
        // 计算总页数
        totalPages = Math.ceil(totalLogs / logsPerPage);
        
        // 更新日志表格
        await updateLogsTable(logsArray);
        
        // 绑定操作按钮事件
        bindActionButtonsEvents();
        
        // 更新分页信息
        updateLogsPagination();
        
        // 重新初始化列宽调节功能，确保新添加的行也能继承列宽设置
        initResizableColumns();
        
        // 隐藏加载状态
        if (loadingEl) {
            loadingEl.classList.add('hidden');
        }
    } catch (error) {
        console.error('加载日志详情失败:', error);
        
        // 隐藏加载状态
        if (loadingEl) {
            loadingEl.classList.add('hidden');
        }
        
        // 显示空状态
        const tableBody = document.getElementById('logs-table-body');
        if (tableBody) {
            tableBody.innerHTML = `
                <tr>
                    <td colspan="5" class="py-8 text-center text-gray-500 border-b border-gray-100">
                        <i class="fa fa-file-text-o text-4xl mb-2 text-gray-300"></i>
                        <div>暂无查询日志</div>
                    </td>
                </tr>
            `;
        }
    }
}

// 更新日志表格
async function updateLogsTable(logs) {
    const tableBody = document.getElementById('logs-table-body');
    if (!tableBody) return;
    
    // 清空表格
    tableBody.innerHTML = '';
    
    if (logs.length === 0) {
        // 显示空状态
        const emptyRow = document.createElement('tr');
        emptyRow.innerHTML = `
            <td colspan="5" class="py-8 text-center text-gray-500 border-b border-gray-100">
                <i class="fa fa-file-text-o text-4xl mb-2 text-gray-300"></i>
                <div>暂无查询日志</div>
            </td>
        `;
        tableBody.appendChild(emptyRow);
        return;
    }
    
    // 检测是否为移动设备
    const isMobile = window.innerWidth <= 768;
    
    // 填充表格
    for (const log of logs) {
        const row = document.createElement('tr');
        row.className = 'border-b border-gray-100 hover:bg-gray-50 transition-colors';
        
        // 格式化时间 - 两行显示，第一行显示时间，第二行显示日期
        const time = new Date(log.timestamp);
        const formattedDate = time.toLocaleDateString('zh-CN', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit'
        });
        const formattedTime = time.toLocaleTimeString('zh-CN', {
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });
        
        // 根据结果添加不同的背景色
        let rowClass = '';
        switch (log.result) {
            case 'blocked':
                rowClass = 'bg-red-50'; // 淡红色填充
                break;
            case 'allowed':
                // 检查是否是规则允许项目
                if (log.blockRule && log.blockRule.includes('allow')) {
                    rowClass = 'bg-green-50'; // 规则允许项目用淡绿色填充
                } else {
                    rowClass = ''; // 允许的不填充
                }
                break;
            default:
                rowClass = '';
        }
        
        // 添加行背景色
        if (rowClass) {
            row.classList.add(rowClass);
        }
        
        // 添加被屏蔽或允许显示，并增加颜色
        let statusText = '';
        let statusClass = '';
        switch (log.result) {
            case 'blocked':
                statusText = '被屏蔽';
                statusClass = 'text-danger';
                break;
            case 'allowed':
                statusText = '允许';
                statusClass = 'text-success';
                break;
            case 'error':
                statusText = '错误';
                statusClass = 'text-warning';
                break;
            default:
                statusText = '';
                statusClass = '';
        }
        
        // 检查域名是否在跟踪器数据库中
            const trackerInfo = await isDomainInTrackerDatabase(log.domain);
            const isTracker = trackerInfo !== null;
            
            // 构建行内容 - 根据设备类型决定显示内容
                // 添加缓存状态显示
                const cacheStatusClass = log.fromCache ? 'text-primary' : 'text-gray-500';
                const cacheStatusText = log.fromCache ? '缓存' : '非缓存';
                
                // 检查域名是否被拦截
                const isBlocked = log.result === 'blocked';
                
                // 构建跟踪器浮窗内容
                const trackerTooltip = isTracker ? `
                    <div class="tracker-tooltip absolute z-50 bg-white shadow-lg rounded-md border p-3 min-w-64 text-sm">
                        <div class="font-semibold mb-2">已知跟踪器</div>
                        <div class="mb-1"><strong>名称:</strong> ${trackerInfo.name || '未知'}</div>
                        <div class="mb-1"><strong>类别:</strong> ${trackerInfo.categoryId && trackersDatabase && trackersDatabase.categories ? trackersDatabase.categories[trackerInfo.categoryId] : '未知'}</div>
                        ${trackerInfo.url ? `<div class="mb-1"><strong>URL:</strong> <a href="${trackerInfo.url}" target="_blank" class="text-blue-500 hover:underline">${trackerInfo.url}</a></div>` : ''}
                        ${trackerInfo.source ? `<div class="mb-1"><strong>源:</strong> ${trackerInfo.source}</div>` : ''}
                    </div>
                ` : '';
                
                if (isMobile) {
                    // 移动设备只显示时间和请求信息
                    row.innerHTML = `
                        <td class="py-3 px-4">
                            <div class="text-sm font-medium">${formattedTime}</div>
                            <div class="text-xs text-gray-500 mt-1">${formattedDate}</div>
                        </td>
                        <td class="py-3 px-4 text-sm" colspan="4">
                            <div class="font-medium flex items-center relative">
                                ${log.dnssec ? '<i class="fa fa-lock text-green-500 mr-1" title="DNSSEC已启用"></i>' : ''}
                                <div class="tracker-icon-container relative">
                                    ${isTracker ? '<i class="fa fa-eye text-red-500 mr-1"></i>' : '<i class="fa fa-eye-slash text-gray-300 mr-1"></i>'}
                                    ${trackerTooltip}
                                </div>
                                ${log.domain}
                            </div>
                            <div class="text-xs text-gray-500 mt-1">类型: ${log.queryType}, <span class="${statusClass}">${statusText}</span></div>
                            <div class="text-xs text-gray-500 mt-1">客户端: ${log.clientIP}</div>
                        </td>
                    `;
                } else {
                    // 桌面设备显示完整信息
                                row.innerHTML = `
                                    <td class="py-3 px-4">
                                        <div class="text-sm font-medium">${formattedTime}</div>
                                        <div class="text-xs text-gray-500 mt-1">${formattedDate}</div>
                                    </td>
                                    <td class="py-3 px-4 text-sm">
                                        <div class="font-medium">${log.clientIP}</div>
                                        <div class="text-xs text-gray-500 mt-1 location-${log.clientIP.replace(/[.:]/g, '-')}">${log.location || '未知 未知'}</div>
                                    </td>
                                    <td class="py-3 px-4 text-sm">
                                        <div class="font-medium flex items-center relative">
                                            ${log.dnssec ? '<i class="fa fa-lock text-green-500 mr-1" title="DNSSEC已启用"></i>' : ''}
                                            <div class="tracker-icon-container relative">
                                                ${isTracker ? '<i class="fa fa-eye text-red-500 mr-1"></i>' : '<i class="fa fa-eye-slash text-gray-300 mr-1"></i>'}
                                                ${trackerTooltip}
                                            </div>
                                            ${log.domain}
                                        </div>
                                        <div class="text-xs text-gray-500 mt-1">类型: ${log.queryType}, <span class="${statusClass}">${statusText}</span>, <span class="${cacheStatusClass}">${log.fromCache ? '缓存' : '非缓存'}</span>${log.dnssec ? ', <span class="text-green-500"><i class="fa fa-lock"></i> DNSSEC</span>' : ''}${log.edns ? ', <span class="text-blue-500"><i class="fa fa-exchange"></i> EDNS</span>' : ''}</div>
                                        <div class="text-xs text-gray-500 mt-1">DNS 服务器: ${log.dnsServer || '无'}, DNSSEC专用: ${log.dnssecServer || '无'}</div>
                                    </td>
                                    <td class="py-3 px-4 text-sm">${log.responseTime}ms</td>
                                    <td class="py-3 px-4 text-sm text-center">
                                        ${isBlocked ? 
                                            `<button class="unblock-btn px-3 py-1 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors text-xs" data-domain="${log.domain}">放行</button>` : 
                                            `<button class="block-btn px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs" data-domain="${log.domain}">拦截</button>`
                                        }
                                    </td>
                                `;
                                
                                // 更新IP地理位置信息
                                const locationElement = row.querySelector(`.location-${log.clientIP.replace(/[.:]/g, '-')}`);
                                if (locationElement) {
                                    // 调用getIpGeolocation函数获取地理位置
                                    getIpGeolocation(log.clientIP).then(location => {
                                        locationElement.textContent = location;
                                    });
                                }
                }
                
                // 添加跟踪器图标悬停事件
                if (isTracker) {
                    const iconContainer = row.querySelector('.tracker-icon-container');
                    const tooltip = iconContainer.querySelector('.tracker-tooltip');
                    if (iconContainer && tooltip) {
                        // 移除内联样式，使用CSS类控制显示
                        tooltip.removeAttribute('style');
                        
                        iconContainer.addEventListener('mouseenter', () => {
                            tooltip.classList.add('visible');
                        });
                        
                        iconContainer.addEventListener('mouseleave', () => {
                            tooltip.classList.remove('visible');
                        });
                    }
                }
            
            // 绑定按钮事件
            const blockBtn = row.querySelector('.block-btn');
            if (blockBtn) {
                blockBtn.addEventListener('click', (e) => {
                    e.preventDefault();
                    const domain = e.currentTarget.dataset.domain;
                    blockDomain(domain);
                });
            }
            
            const unblockBtn = row.querySelector('.unblock-btn');
            if (unblockBtn) {
                unblockBtn.addEventListener('click', (e) => {
                    e.preventDefault();
                    const domain = e.currentTarget.dataset.domain;
                    unblockDomain(domain);
                });
            }
            
            // 绑定日志详情点击事件
            row.addEventListener('click', (e) => {
                // 如果点击的是按钮，不触发详情弹窗
                if (e.target.closest('button')) {
                    return;
                }
                showLogDetailModal(log);
            });
        
        tableBody.appendChild(row);
    }
}

// 更新分页信息
function updateLogsPagination() {
    // 更新页码显示
    document.getElementById('logs-current-page').textContent = currentPage;
    document.getElementById('logs-total-pages').textContent = totalPages;
    
    // 更新页码输入框
    const pageInput = document.getElementById('logs-page-input');
    if (pageInput) {
        pageInput.max = totalPages;
        pageInput.value = currentPage;
    }
    
    // 更新按钮状态
    const prevBtn = document.getElementById('logs-prev-page');
    const nextBtn = document.getElementById('logs-next-page');
    
    if (prevBtn) {
        prevBtn.disabled = currentPage === 1;
    }
    
    if (nextBtn) {
        nextBtn.disabled = currentPage === totalPages;
    }
}

// 初始化日志图表
function initLogsChart() {
    const ctx = document.getElementById('logs-trend-chart');
    if (!ctx) return;
    
    // 获取24小时统计数据
    apiRequest('/hourly-stats')
        .then(data => {
            if (data && data.error) {
                console.error('初始化日志图表失败:', data.error);
                return;
            }
            
            // 创建图表
            logsChart = new Chart(ctx, {
                type: 'line',
                data: {
                    labels: data.labels,
                    datasets: [{
                        label: '查询数',
                        data: data.data,
                        borderColor: '#3b82f6',
                        backgroundColor: 'rgba(59, 130, 246, 0.1)',
                        tension: 0.4,
                        fill: true
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                        legend: {
                            display: true,
                            position: 'top'
                        },
                        tooltip: {
                            mode: 'index',
                            intersect: false
                        }
                    },
                    scales: {
                        y: {
                            beginAtZero: true,
                            ticks: {
                                precision: 0
                            }
                        }
                    }
                }
            });
        })
        .catch(error => {
            console.error('初始化日志图表失败:', error);
        });
}

// 更新日志图表
function updateLogsChart(range) {
    if (!logsChart) return;
    
    let endpoint = '';
    switch (range) {
        case '24h':
            endpoint = '/hourly-stats';
            break;
        case '7d':
            endpoint = '/daily-stats';
            break;
        case '30d':
            endpoint = '/monthly-stats';
            break;
        default:
            endpoint = '/hourly-stats';
    }
    
    // 使用封装的apiRequest函数进行API调用
    apiRequest(endpoint)
        .then(data => {
            if (data && data.error) {
                console.error('更新日志图表失败:', data.error);
                return;
            }
            
            // 更新图表数据
            logsChart.data.labels = data.labels;
            logsChart.data.datasets[0].data = data.data;
            logsChart.update();
        })
        .catch(error => {
            console.error('更新日志图表失败:', error);
        });
}

// 建立WebSocket连接
function connectLogsWebSocket() {
    try {
        // 构建WebSocket URL
        const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = `${wsProtocol}//${window.location.host}/ws/stats`;
        
        
        // 创建WebSocket连接
        logsWsConnection = new WebSocket(wsUrl);
        
        // 连接打开事件
        logsWsConnection.onopen = function() {
        };
        
        // 接收消息事件
        logsWsConnection.onmessage = function(event) {
            try {
                const data = JSON.parse(event.data);
                
                if (data.type === 'initial_data' || data.type === 'stats_update') {
                    // 只更新统计数据，不更新日志详情
                    updateLogsStatsFromWebSocket(data.data);
                }
            } catch (error) {
                console.error('处理WebSocket消息失败:', error);
            }
        };
        
        // 连接关闭事件
        logsWsConnection.onclose = function(event) {
            console.warn('WebSocket连接已关闭，代码:', event.code);
            logsWsConnection = null;
            
            // 设置重连
            setupLogsReconnect();
        };
        
        // 连接错误事件
        logsWsConnection.onerror = function(error) {
            console.error('WebSocket连接错误:', error);
        };
        
    } catch (error) {
        console.error('创建WebSocket连接失败:', error);
    }
}

// 设置重连逻辑
function setupLogsReconnect() {
    if (logsWsReconnectTimer) {
        return; // 已经有重连计时器在运行
    }
    
    const reconnectDelay = 5000; // 5秒后重连
    
    logsWsReconnectTimer = setTimeout(() => {
        connectLogsWebSocket();
    }, reconnectDelay);
}

// 从WebSocket更新日志统计数据
function updateLogsStatsFromWebSocket(stats) {
    try {
        // 更新统计卡片
        if (stats.dns) {
            // 适配不同的数据结构
            const totalQueries = stats.dns.Queries || 0;
            const blockedQueries = stats.dns.Blocked || 0;
            const allowedQueries = stats.dns.Allowed || 0;
            const errorQueries = stats.dns.Errors || 0;
            const avgResponseTime = stats.dns.AvgResponseTime || 0;
            const activeIPs = stats.activeIPs || Object.keys(stats.dns.SourceIPs || {}).length;
            
            // 更新统计卡片
            document.getElementById('logs-total-queries').textContent = totalQueries;
            document.getElementById('logs-avg-response-time').textContent = avgResponseTime.toFixed(2) + 'ms';
            document.getElementById('logs-active-ips').textContent = activeIPs;
            
            // 计算屏蔽率
            const blockRate = totalQueries > 0 ? (blockedQueries / totalQueries * 100).toFixed(1) : '0';
            document.getElementById('logs-block-rate').textContent = blockRate + '%';
        }
    } catch (error) {
        console.error('从WebSocket更新日志统计数据失败:', error);
    }
}

// 拦截域名
async function blockDomain(domain) {
    try {
        
        // 创建拦截规则，使用AdBlock Plus格式
        const blockRule = `||${domain}^`;
        
        // 调用API添加拦截规则
        const response = await apiRequest('/shield', 'POST', { rule: blockRule });
        
        
        // 处理不同的响应格式
        if (response && (response.success || response.status === 'success')) {
            // 重新加载日志，显示更新后的状态
            loadLogs();
            
            // 刷新规则列表
            refreshRulesList();
            
            // 显示成功通知
            if (typeof window.showNotification === 'function') {
                window.showNotification(`已成功拦截域名: ${domain}`, 'success');
            }
        } else {
            const errorMsg = response ? (response.message || '添加拦截规则失败') : '添加拦截规则失败: 无效的API响应';
            console.error(`拦截域名失败: ${errorMsg}`);
            throw new Error(errorMsg);
        }
    } catch (error) {
        console.error('拦截域名失败:', error);
        
        // 显示错误通知
        if (typeof window.showNotification === 'function') {
            window.showNotification(`拦截域名失败: ${error.message}`, 'danger');
        }
    }
}

// 绑定操作按钮事件
function bindActionButtonsEvents() {
    // 绑定拦截按钮事件
    const blockBtns = document.querySelectorAll('.block-btn');
    blockBtns.forEach(btn => {
        btn.addEventListener('click', async (e) => {
            e.preventDefault();
            const domain = e.currentTarget.dataset.domain;
            await blockDomain(domain);
        });
    });
    
    // 绑定放行按钮事件
    const unblockBtns = document.querySelectorAll('.unblock-btn');
    unblockBtns.forEach(btn => {
        btn.addEventListener('click', async (e) => {
            e.preventDefault();
            const domain = e.currentTarget.dataset.domain;
            await unblockDomain(domain);
        });
    });
}

// 刷新规则列表
async function refreshRulesList() {
    try {
        // 调用API重新加载规则
        const response = await apiRequest('/shield', 'GET');
        
        if (response) {
            // 处理规则列表响应
            let allRules = [];
            if (response && typeof response === 'object') {
                // 合并所有类型的规则到一个数组
                if (Array.isArray(response.domainRules)) allRules = allRules.concat(response.domainRules);
                if (Array.isArray(response.domainExceptions)) allRules = allRules.concat(response.domainExceptions);
                if (Array.isArray(response.regexRules)) allRules = allRules.concat(response.regexRules);
                if (Array.isArray(response.regexExceptions)) allRules = allRules.concat(response.regexExceptions);
            }
            
            // 更新规则列表
            if (window.rules) {
                rules = allRules;
                filteredRules = [...rules];
                
                // 更新规则数量统计
                if (window.updateRulesCount && typeof window.updateRulesCount === 'function') {
                    window.updateRulesCount(rules.length);
                }
            }
        }
    } catch (error) {
        console.error('刷新规则列表失败:', error);
    }
}

// 放行域名
async function unblockDomain(domain) {
    try {
        
        // 创建放行规则，使用AdBlock Plus格式
        const allowRule = `@@||${domain}^`;
        
        // 调用API添加放行规则
        const response = await apiRequest('/shield', 'POST', { rule: allowRule });
        
        
        // 处理不同的响应格式
        if (response && (response.success || response.status === 'success')) {
            // 重新加载日志，显示更新后的状态
            loadLogs();
            
            // 刷新规则列表
            refreshRulesList();
            
            // 显示成功通知
            if (typeof window.showNotification === 'function') {
                window.showNotification(`已成功放行域名: ${domain}`, 'success');
            }
        } else {
            const errorMsg = response ? (response.message || '添加放行规则失败') : '添加放行规则失败: 无效的API响应';
            console.error(`放行域名失败: ${errorMsg}`);
            throw new Error(errorMsg);
        }
    } catch (error) {
        console.error('放行域名失败:', error);
        
        // 显示错误通知
        if (typeof window.showNotification === 'function') {
            window.showNotification(`放行域名失败: ${error.message}`, 'danger');
        }
    }
}

// 独立的DNS记录格式化函数
function formatDNSRecords(log, result) {
    if (result === 'blocked') return '无';
    
    let records = '';
    const sources = [
        log.answers,
        log.answer,
        log.Records,
        log.records,
        log.response
    ];
    
    for (const source of sources) {
        if (records) break;
        if (!source || source === '无') continue;
        
        // 处理数组类型
        if (Array.isArray(source)) {
            records = source.map(answer => {
                const type = answer.type || answer.Type || '未知';
                let value = answer.value || answer.Value || answer.data || answer.Data || '未知';
                const ttl = answer.TTL || answer.ttl || answer.expires || '未知';
                
                // 增强的记录值提取逻辑
                if (typeof value === 'string') {
                    value = value.trim();
                    // 处理制表符分隔的格式
                    if (value.includes('\t') || value.includes('\\t')) {
                        const parts = value.replace(/\\t/g, '\t').split('\t');
                        if (parts.length >= 4) {
                            value = parts[parts.length - 1].trim();
                        }
                    }
                    // 处理JSON格式
                    else if (value.startsWith('{') && value.endsWith('}')) {
                        try {
                            const parsed = JSON.parse(value);
                            value = parsed.data || parsed.value || value;
                        } catch (e) {}
                    }
                }
                
                return `${type}: ${value} (ttl=${ttl})`;
            }).join('\n').trim();
        }
        // 处理字符串类型
        else if (typeof source === 'string') {
            // 尝试解析为JSON数组
            if (source.startsWith('[') && source.endsWith(']')) {
                try {
                    const parsed = JSON.parse(source);
                    if (Array.isArray(parsed)) {
                        records = parsed.map(answer => {
                            const type = answer.type || answer.Type || '未知';
                            let value = answer.value || answer.Value || answer.data || answer.Data || '未知';
                            const ttl = answer.TTL || answer.ttl || answer.expires || '未知';
                            
                            if (typeof value === 'string') {
                                value = value.trim();
                            }
                            
                            return `${type}: ${value} (ttl=${ttl})`;
                        }).join('\n').trim();
                    }
                } catch (e) {
                    // 解析失败，尝试直接格式化
                    records = formatDNSString(source);
                }
            } else {
                // 直接格式化字符串
                records = formatDNSString(source);
            }
        }
    }
    
    return records || '无解析记录';
}

// 格式化DNS字符串记录
function formatDNSString(str) {
    // 处理可能的转义字符并分割行
    const recordLines = str.split(/\r?\n/).map(line => line.replace(/^\s+/, '')).filter(line => line.trim() !== '');
    
    return recordLines.map(line => {
        // 检查是否已经是标准格式
        if (line.includes(':') && line.includes('(')) {
            return line;
        }
        // 尝试解析为标准DNS格式
        const parts = line.split(/\s+/);
        if (parts.length >= 5) {
            const type = parts[3];
            const value = parts.slice(4).join(' ');
            const ttl = parts[1];
            return `${type}: ${value} (ttl=${ttl})`;
        }
        // 无法解析，返回原始行但移除前导空格
        return line.replace(/^\s+/, '');
    }).join('\n');
}

// 显示日志详情弹窗
async function showLogDetailModal(log) {
    
    if (!log) {
        console.error('No log data provided!');
        return;
    }
    
    try {
        // 安全获取log属性，提供默认值
        const timestamp = log.timestamp ? new Date(log.timestamp) : null;
        const dateStr = timestamp ? timestamp.toLocaleDateString() : '未知';
        const timeStr = timestamp ? timestamp.toLocaleTimeString() : '未知';
        const domain = log.domain || '未知';
        const queryType = log.queryType || '未知';
        const result = log.result || '未知';
        const responseTime = log.responseTime || '未知';
        const clientIP = log.clientIP || '未知';
        const location = log.location || '未知';
        const fromCache = log.fromCache || false;
        const dnssec = log.dnssec || false;
        const edns = log.edns || false;
        const dnsServer = log.dnsServer || '无';
        const dnssecServer = log.dnssecServer || '无';
        const blockRule = log.blockRule || '无';
        
        // 检查域名是否在跟踪器数据库中
        const trackerInfo = await isDomainInTrackerDatabase(log.domain);
        const isTracker = trackerInfo !== null;
        
        // 获取域名信息
        const domainInfo = await getDomainInfo(domain);
        
        // 格式化DNS解析记录
        const dnsRecords = formatDNSRecords(log, result);
        
        // 创建模态框容器
        const modalContainer = document.createElement('div');
        modalContainer.className = 'fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4 animate-fade-in';
        modalContainer.style.zIndex = '9999';
        
        // 创建模态框内容
        const modalContent = document.createElement('div');
        modalContent.className = 'bg-white dark:bg-gray-800 dark:text-gray-100 rounded-xl shadow-2xl w-full max-w-2xl max-h-[90vh] overflow-y-auto animate-slide-in';
        
        // 创建标题栏
        const header = document.createElement('div');
        header.className = 'sticky top-0 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-6 py-4 flex justify-between items-center';
        
        const title = document.createElement('h3');
        title.className = 'text-xl font-semibold text-gray-900 dark:text-gray-100';
        title.textContent = '日志详情';
        
        const closeButton = document.createElement('button');
        closeButton.innerHTML = '<i class="fa fa-times text-xl"></i>';
        closeButton.className = 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 focus:outline-none transition-colors';
        closeButton.onclick = () => closeModal();
        
        header.appendChild(title);
        header.appendChild(closeButton);
        
        // 创建内容区域
        const content = document.createElement('div');
        content.className = 'p-6 space-y-6';
        
        // 基本信息部分
        const basicInfo = document.createElement('div');
        basicInfo.className = 'space-y-4';
        
        const basicInfoTitle = document.createElement('h4');
        basicInfoTitle.className = 'text-sm font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider';
        basicInfoTitle.textContent = '基本信息';
        
        const basicInfoGrid = document.createElement('div');
        basicInfoGrid.className = 'grid grid-cols-1 md:grid-cols-2 gap-4';
        
        // 添加基本信息项
        basicInfoGrid.innerHTML = `
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">日期</div>
                <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${dateStr}</div>
            </div>
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">时间</div>
                <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${timeStr}</div>
            </div>
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">状态</div>
                <div class="text-sm font-medium ${result === 'blocked' ? 'text-red-600 dark:text-red-400' : result === 'allowed' ? 'text-green-600 dark:text-green-400' : 'text-gray-500 dark:text-gray-400'}">
                    ${result === 'blocked' ? '已拦截' : result === 'allowed' ? '允许' : result}
                </div>
            </div>
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">域名</div>
                <div class="text-sm font-medium text-gray-900 dark:text-gray-100 break-all">${domain}</div>
            </div>
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">类型</div>
                <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${queryType}</div>
            </div>
        `;
        
        // DNS特性
        const dnsFeatures = document.createElement('div');
        dnsFeatures.className = 'col-span-1 md:col-span-2 space-y-1';
        dnsFeatures.innerHTML = `
            <div class="text-xs text-gray-500 dark:text-gray-400">DNS特性</div>
            <div class="text-sm font-medium text-gray-900 dark:text-gray-100">
                ${dnssec ? '<i class="fa fa-lock text-green-500 dark:text-green-400 mr-1" title="DNSSEC已启用"></i>DNSSEC ' : ''}
                ${edns ? '<i class="fa fa-exchange text-blue-500 dark:text-blue-400 mr-1" title="EDNS已启用"></i>EDNS' : ''}
                ${!dnssec && !edns ? '无' : ''}
            </div>
        `;
        
        // 域名信息
        const domainInfoDiv = document.createElement('div');
        domainInfoDiv.className = 'col-span-1 md:col-span-2 space-y-1';
        domainInfoDiv.innerHTML = `
            <div class="text-xs text-gray-500 dark:text-gray-400">域名信息</div>
            <div class="text-sm font-medium text-gray-900 dark:text-gray-100 p-3 bg-gray-50 dark:bg-gray-700 rounded-md border border-gray-200 dark:border-gray-600 w-full">
                ${domainInfo ? `
                    <div class="flex items-center mb-2">
                        ${domainInfo.icon ? `<img src="${domainInfo.icon}" alt="${domainInfo.name}" class="w-6 h-6 mr-2 rounded-sm" onerror="this.style.display='none'" />` : ''}
                        <span class="text-base font-semibold flex-grow">${domainInfo.name || '未知'}</span>
                    </div>
                    <div class="mt-1">
                        <div class="flex items-center mb-1 flex-wrap">
                            <span class="text-gray-500 dark:text-gray-400 mr-2">类别：</span>
                            <span class="flex-grow">${domainInfo.categoryName || '未知'}</span>
                        </div>
                        <div class="flex items-center flex-wrap">
                            <span class="text-gray-500 dark:text-gray-400 mr-2">所属单位/公司：</span>
                            <span class="flex-grow">${domainInfo.company || '未知'}</span>
                        </div>
                    </div>
                ` : '无'}
            </div>
        `;
        
        // 构建跟踪器浮窗内容
        const trackerTooltip = isTracker ? `
            <div class="tracker-tooltip absolute z-50 bg-white dark:bg-gray-800 shadow-lg rounded-md border border-gray-200 dark:border-gray-700 p-3 min-w-64 text-sm text-gray-900 dark:text-gray-100">
                <div class="font-semibold mb-2">已知跟踪器</div>
                <div class="mb-1"><strong>名称:</strong> ${trackerInfo.name || '未知'}</div>
                <div class="mb-1"><strong>类别:</strong> ${trackerInfo.categoryId && trackersDatabase && trackersDatabase.categories ? trackersDatabase.categories[trackerInfo.categoryId] : '未知'}</div>
                ${trackerInfo.url ? `<div class="mb-1"><strong>URL:</strong> <a href="${trackerInfo.url}" target="_blank" class="text-blue-500 dark:text-blue-400 hover:underline">${trackerInfo.url}</a></div>` : ''}
                ${trackerInfo.source ? `<div class="mb-1"><strong>源:</strong> ${trackerInfo.source}</div>` : ''}
            </div>
        ` : '';
        
        // 跟踪器信息
        const trackerDiv = document.createElement('div');
        trackerDiv.className = 'col-span-1 md:col-span-2 space-y-1';
        trackerDiv.innerHTML = `
            <div class="text-xs text-gray-500 dark:text-gray-400">跟踪器信息</div>
            <div class="text-sm font-medium text-gray-900 dark:text-gray-100">
                ${isTracker ? `
                    <div class="flex items-center">
                        <div class="tracker-icon-container relative">
                            <i class="fa fa-eye text-red-500 dark:text-red-400 mr-1" title="已知跟踪器"></i>
                            ${trackerTooltip}
                        </div>
                        <span>${trackerInfo.name} (${trackerInfo.categoryId && trackersDatabase && trackersDatabase.categories ? trackersDatabase.categories[trackerInfo.categoryId] : '未知'})</span>
                    </div>
                ` : '无'}
            </div>
        `;
        
        // 添加跟踪器图标悬停事件
        if (isTracker) {
            const iconContainer = trackerDiv.querySelector('.tracker-icon-container');
            const tooltip = iconContainer.querySelector('.tracker-tooltip');
            if (iconContainer && tooltip) {
                // 移除内联样式，使用CSS类控制显示
                tooltip.removeAttribute('style');
                
                iconContainer.addEventListener('mouseenter', () => {
                    tooltip.classList.add('visible');
                });
                
                iconContainer.addEventListener('mouseleave', () => {
                    tooltip.classList.remove('visible');
                });
            }
        }
        
        // 解析记录
        const recordsDiv = document.createElement('div');
        recordsDiv.className = 'col-span-1 md:col-span-2 space-y-1';
        recordsDiv.innerHTML = `
            <div class="text-xs text-gray-500 dark:text-gray-400">解析记录</div>
            <div class="text-sm font-medium text-gray-900 dark:text-gray-100 whitespace-pre-wrap break-all bg-gray-50 dark:bg-gray-700 p-3 rounded-md border border-gray-200 dark:border-gray-600">${dnsRecords}</div>
        `;
        
        // DNS服务器
        const dnsServerDiv = document.createElement('div');
        dnsServerDiv.className = 'col-span-1 md:col-span-2 space-y-1';
        dnsServerDiv.innerHTML = `
            <div class="text-xs text-gray-500 dark:text-gray-400">DNS服务器</div>
            <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${dnsServer}</div>
        `;
        
        // DNSSEC专用服务器
        const dnssecServerDiv = document.createElement('div');
        dnssecServerDiv.className = 'col-span-1 md:col-span-2 space-y-1';
        dnssecServerDiv.innerHTML = `
            <div class="text-xs text-gray-500 dark:text-gray-400">DNSSEC专用服务器</div>
            <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${dnssecServer}</div>
        `;
        
        basicInfoGrid.appendChild(dnsFeatures);
        basicInfoGrid.appendChild(domainInfoDiv);
        basicInfoGrid.appendChild(trackerDiv);
        basicInfoGrid.appendChild(recordsDiv);
        basicInfoGrid.appendChild(dnsServerDiv);
        basicInfoGrid.appendChild(dnssecServerDiv);
        
        basicInfo.appendChild(basicInfoTitle);
        basicInfo.appendChild(basicInfoGrid);
        
        // 响应细节部分
        const responseDetails = document.createElement('div');
        responseDetails.className = 'space-y-4 pt-4 border-t border-gray-200 dark:border-gray-700';
        
        const responseDetailsTitle = document.createElement('h4');
        responseDetailsTitle.className = 'text-sm font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider';
        responseDetailsTitle.textContent = '响应细节';
        
        // 准备响应细节内容，根据条件添加规则信息
        let responseDetailsHTML = `
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">响应时间</div>
                <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${responseTime}毫秒</div>
            </div>
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">响应代码</div>
                <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${getResponseCodeText(log.responseCode)}</div>
            </div>
            <div class="space-y-1">
                <div class="text-xs text-gray-500 dark:text-gray-400">缓存状态</div>
                <div class="text-sm font-medium ${fromCache ? 'text-primary dark:text-blue-400' : 'text-gray-500 dark:text-gray-400'}">
                    ${fromCache ? '缓存' : '非缓存'}
                </div>
            </div>
        `;
        
        // 只有被屏蔽时才显示规则信息
        if (result === 'blocked') {
            responseDetailsHTML += `
                <div class="space-y-1">
                    <div class="text-xs text-gray-500 dark:text-gray-400">规则</div>
                    <div class="text-sm font-medium text-gray-900 dark:text-gray-100">${blockRule || '-'}</div>
                </div>
            `;
        }
        
        const responseGrid = document.createElement('div');
        responseGrid.className = 'grid grid-cols-1 md:grid-cols-2 gap-4';
        responseGrid.innerHTML = responseDetailsHTML;
        
        responseDetails.appendChild(responseDetailsTitle);
        responseDetails.appendChild(responseGrid);
        
        // 客户端详情部分
        const clientDetails = document.createElement('div');
        clientDetails.className = 'space-y-4 pt-4 border-t border-gray-200 dark:border-gray-700';
        
        const clientDetailsTitle = document.createElement('h4');
        clientDetailsTitle.className = 'text-sm font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider';
        clientDetailsTitle.textContent = '客户端详情';
        
        // 创建客户端IP容器，为后续更新地理位置做准备
        const clientIPContainer = document.createElement('div');
        clientIPContainer.className = 'text-sm font-medium text-gray-900 dark:text-gray-100';
        clientIPContainer.innerHTML = `${clientIP} <span id="modal-location-${clientIP.replace(/[.:]/g, '-')}">(${location})</span>`;
        
        const clientIPDiv = document.createElement('div');
        clientIPDiv.className = 'space-y-1';
        clientIPDiv.innerHTML = `
            <div class="text-xs text-gray-500 dark:text-gray-400">IP地址</div>
        `;
        clientIPDiv.appendChild(clientIPContainer);
        
        clientDetails.appendChild(clientDetailsTitle);
        clientDetails.appendChild(clientIPDiv);
        
        // 动态更新地理位置信息
        const locationElement = clientIPDiv.querySelector(`#modal-location-${clientIP.replace(/[.:]/g, '-')}`);
        if (locationElement) {
            getIpGeolocation(clientIP).then(location => {
                locationElement.textContent = `(${location})`;
            });
        }
        
        // 操作按钮区域
        const actionButtons = document.createElement('div');
        actionButtons.className = 'pt-4 border-t border-gray-200 dark:border-gray-700 flex justify-end space-x-2';
        
        // 根据域名状态显示不同的操作按钮
        if (result === 'blocked') {
            // 被拦截时显示放行按钮
            actionButtons.innerHTML = `
                <button class="px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors text-sm" id="unblock-domain-btn">
                    <i class="fa fa-unlock-alt mr-1"></i>放行
                </button>
            `;
        } else {
            // 未被拦截时显示拦截按钮
            actionButtons.innerHTML = `
                <button class="px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-sm" id="block-domain-btn">
                    <i class="fa fa-lock mr-1"></i>拦截
                </button>
            `;
        }
        
        // 组装内容
        content.appendChild(basicInfo);
        content.appendChild(responseDetails);
        content.appendChild(clientDetails);
        content.appendChild(actionButtons);
        
        // 组装模态框
        modalContent.appendChild(header);
        modalContent.appendChild(content);
        modalContainer.appendChild(modalContent);
        
        // 绑定操作按钮事件
        if (result === 'blocked') {
            const unblockBtn = modalContent.querySelector('#unblock-domain-btn');
            if (unblockBtn) {
                unblockBtn.addEventListener('click', async () => {
                    await unblockDomain(domain);
                    closeModal();
                    loadLogs(); // 刷新日志列表
                });
            }
        } else {
            const blockBtn = modalContent.querySelector('#block-domain-btn');
            if (blockBtn) {
                blockBtn.addEventListener('click', async () => {
                    await blockDomain(domain);
                    closeModal();
                    loadLogs(); // 刷新日志列表
                });
            }
        }
        
        // 添加到页面
        document.body.appendChild(modalContainer);
        
        // 关闭模态框函数
        function closeModal() {
            modalContainer.classList.add('animate-fade-out');
            modalContent.classList.add('animate-slide-out');
            
            // 等待动画结束后移除元素
            setTimeout(() => {
                document.body.removeChild(modalContainer);
            }, 300);
        }
        
        // 点击外部关闭
        modalContainer.addEventListener('click', (e) => {
            if (e.target === modalContainer) {
                closeModal();
            }
        });
        
        // ESC键关闭
        const handleEsc = (e) => {
            if (e.key === 'Escape') {
                closeModal();
                document.removeEventListener('keydown', handleEsc);
            }
        };
        document.addEventListener('keydown', handleEsc);
        
    } catch (error) {
        console.error('Error in showLogDetailModal:', error);
        
        // 显示错误提示
        const errorModal = document.createElement('div');
        errorModal.className = 'fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4 animate-fade-in';
        errorModal.style.zIndex = '9999';
        
        const errorContent = document.createElement('div');
        errorContent.className = 'bg-white dark:bg-gray-800 dark:text-gray-100 rounded-xl shadow-2xl p-6 w-full max-w-md animate-slide-in';
        
        errorContent.innerHTML = `
            <div class="flex justify-between items-center mb-4">
                <h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100">错误</h3>
                <button onclick="closeErrorModal()" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 focus:outline-none transition-colors">
                    <i class="fa fa-times text-xl"></i>
                </button>
            </div>
            <div class="text-red-600 dark:text-red-400 text-sm">
                加载日志详情失败: ${error.message}
            </div>
        `;
        
        errorModal.appendChild(errorContent);
        document.body.appendChild(errorModal);
        
        // 关闭错误模态框函数
        function closeErrorModal() {
            errorModal.classList.add('animate-fade-out');
            errorContent.classList.add('animate-slide-out');
            
            // 等待动画结束后移除元素
            setTimeout(() => {
                document.body.removeChild(errorModal);
            }, 300);
        }
        
        // ESC键关闭错误模态框
        const handleErrorEsc = (e) => {
            if (e.key === 'Escape') {
                closeErrorModal();
                document.removeEventListener('keydown', handleErrorEsc);
            }
        };
        document.addEventListener('keydown', handleErrorEsc);
    }
}

// 关闭日志详情弹窗
// 获取响应代码文本
function getResponseCodeText(rcode) {
    const rcodeMap = {
        0: 'NOERROR',
        1: 'FORMERR',
        2: 'SERVFAIL',
        3: 'NXDOMAIN',
        4: 'NOTIMP',
        5: 'REFUSED',
        6: 'YXDOMAIN',
        7: 'YXRRSET',
        8: 'NXRRSET',
        9: 'NOTAUTH',
        10: 'NOTZONE'
    };
    return rcodeMap[rcode] || `UNKNOWN(${rcode})`;
}

function closeLogDetailModal() {
    const modal = document.getElementById('log-detail-modal');
    modal.classList.add('hidden');
}

// 初始化日志详情弹窗事件
function initLogDetailModal() {
    // 关闭按钮事件
    const closeBtn = document.getElementById('close-log-modal-btn');
    if (closeBtn) {
        closeBtn.addEventListener('click', closeLogDetailModal);
    }
    
    // 点击模态框外部关闭
    const modal = document.getElementById('log-detail-modal');
    if (modal) {
        modal.addEventListener('click', (e) => {
            if (e.target === modal) {
                closeLogDetailModal();
            }
        });
    }
    
    // ESC键关闭
    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape') {
            closeLogDetailModal();
        }
    });
}

// 定期更新日志统计数据（备用方案）
setInterval(() => {
    // 只有在查询日志页面时才更新
    if (window.location.hash === '#logs') {
        loadLogsStats();
        // 不自动更新日志详情，只更新统计数据
    }
}, 30000); // 每30秒更新一次
