// 配置管理页面功能实现 // 工具函数:安全获取DOM元素 function getElement(id) { const element = document.getElementById(id); if (!element) { console.warn(`Element with id "${id}" not found`); } return element; } // 工具函数:验证端口号 function validatePort(port) { // 确保port是字符串类型 var portStr = port; if (port === null || port === undefined || typeof port !== 'string') { return null; } // 去除前后空白并验证是否为纯数字 portStr = port.trim(); if (!/^\d+$/.test(portStr)) { return null; } const num = parseInt(portStr, 10); return num >= 1 && num <= 65535 ? num : null; } // 初始化配置管理页面 function initConfigPage() { loadConfig(); setupConfigEventListeners(); } // 加载系统配置 async function loadConfig() { try { const result = await api.getConfig(); // 检查API返回的错误 if (result && result.error) { showErrorMessage('加载配置失败: ' + result.error); return; } populateConfigForm(result); } catch (error) { // 捕获可能的异常(虽然apiRequest不应该再抛出异常) showErrorMessage('加载配置失败: ' + (error.message || '未知错误')); } } // 填充配置表单 function populateConfigForm(config) { // 安全获取配置对象,防止未定义属性访问 const dnsServerConfig = config.DNSServer || {}; const httpServerConfig = config.HTTPServer || {}; const shieldConfig = config.Shield || {}; // DNS配置 - 使用函数安全设置值,避免 || 操作符可能的错误处理 setElementValue('dns-port', getSafeValue(dnsServerConfig.Port, 53)); setElementValue('dns-upstream-servers', getSafeArray(dnsServerConfig.UpstreamServers).join(', ')); setElementValue('dns-timeout', getSafeValue(dnsServerConfig.Timeout, 5)); setElementValue('dns-stats-file', getSafeValue(dnsServerConfig.StatsFile, 'data/stats.json')); setElementValue('dns-save-interval', getSafeValue(dnsServerConfig.SaveInterval, 300)); // HTTP配置 setElementValue('http-port', getSafeValue(httpServerConfig.Port, 8080)); // 屏蔽配置 setElementValue('shield-local-rules-file', getSafeValue(shieldConfig.LocalRulesFile, 'data/rules.txt')); setElementValue('shield-update-interval', getSafeValue(shieldConfig.UpdateInterval, 3600)); setElementValue('shield-hosts-file', getSafeValue(shieldConfig.HostsFile, 'data/hosts.txt')); // 使用服务器端接受的屏蔽方法值,默认使用NXDOMAIN setElementValue('shield-block-method', getSafeValue(shieldConfig.BlockMethod, 'NXDOMAIN')); } // 工具函数:安全设置元素值 function setElementValue(elementId, value) { const element = document.getElementById(elementId); if (element && element.tagName === 'INPUT') { element.value = value; } else if (!element) { console.warn(`Element with id "${elementId}" not found for setting value: ${value}`); } } // 工具函数:安全获取值,如果未定义或为null则返回默认值 function getSafeValue(value, defaultValue) { // 更严格的检查,避免0、空字符串等被默认值替换 return value === undefined || value === null ? defaultValue : value; } // 工具函数:安全获取数组,如果不是数组则返回空数组 function getSafeArray(value) { return Array.isArray(value) ? value : []; } // 保存配置 async function handleSaveConfig() { const formData = collectFormData(); if (!formData) return; try { const result = await api.saveConfig(formData); // 检查API返回的错误 if (result && result.error) { showErrorMessage('保存配置失败: ' + result.error); return; } showSuccessMessage('配置保存成功'); } catch (error) { // 捕获可能的异常(虽然apiRequest不应该再抛出异常) showErrorMessage('保存配置失败: ' + (error.message || '未知错误')); } } // 重启服务 async function handleRestartService() { if (!confirm('确定要重启DNS服务吗?重启期间服务可能会短暂不可用。')) return; try { const result = await api.restartService(); // 检查API返回的错误 if (result && result.error) { showErrorMessage('服务重启失败: ' + result.error); return; } showSuccessMessage('服务重启成功'); } catch (error) { // 捕获可能的异常(虽然apiRequest不应该再抛出异常) showErrorMessage('重启服务失败: ' + (error.message || '未知错误')); } } // 收集表单数据并验证 function collectFormData() { // 验证端口号 - 使用安全获取元素值的函数 const dnsPortValue = getElementValue('dns-port'); const httpPortValue = getElementValue('http-port'); const dnsPort = validatePort(dnsPortValue); const httpPort = validatePort(httpPortValue); if (!dnsPort) { showErrorMessage('DNS端口号无效(必须是1-65535之间的整数)'); return null; } if (!httpPort) { showErrorMessage('HTTP端口号无效(必须是1-65535之间的整数)'); return null; } // 安全获取上游服务器列表 const upstreamServersText = getElementValue('dns-upstream-servers'); const upstreamServers = upstreamServersText ? upstreamServersText.split(',').map(function(s) { return s.trim(); }).filter(function(s) { return s !== ''; }) : []; // 安全获取并转换整数值 const timeoutValue = getElementValue('dns-timeout'); const timeout = timeoutValue ? parseInt(timeoutValue, 10) : 5; const saveIntervalValue = getElementValue('dns-save-interval'); const saveInterval = saveIntervalValue ? parseInt(saveIntervalValue, 10) : 300; const updateIntervalValue = getElementValue('shield-update-interval'); const updateInterval = updateIntervalValue ? parseInt(updateIntervalValue, 10) : 3600; return { DNSServer: { Port: dnsPort, UpstreamServers: upstreamServers, Timeout: timeout, StatsFile: getElementValue('dns-stats-file') || './data/stats.json', SaveInterval: saveInterval }, HTTPServer: { Port: httpPort }, Shield: { LocalRulesFile: getElementValue('shield-local-rules-file') || './data/rules.txt', UpdateInterval: updateInterval, HostsFile: getElementValue('shield-hosts-file') || './data/hosts.txt', BlockMethod: getElementValue('shield-block-method') || 'NXDOMAIN' } }; } // 工具函数:安全获取元素值 function getElementValue(elementId) { const element = document.getElementById(elementId); if (element && element.tagName === 'INPUT') { return element.value; } return ''; // 默认返回空字符串 } // 设置事件监听器 function setupConfigEventListeners() { // 保存配置按钮 getElement('save-config-btn')?.addEventListener('click', handleSaveConfig); // 重启服务按钮 getElement('restart-service-btn')?.addEventListener('click', handleRestartService); } // 显示成功消息 function showSuccessMessage(message) { showNotification(message, 'success'); } // 显示错误消息 function showErrorMessage(message) { showNotification(message, 'error'); } // 显示通知 function showNotification(message, type = 'info') { // 移除现有通知 const existingNotification = document.querySelector('.notification'); if (existingNotification) { existingNotification.remove(); } // 创建新通知 const notification = document.createElement('div'); notification.className = `notification fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg z-50 transform transition-transform duration-300 ease-in-out translate-y-0 opacity-0`; // 设置通知样式(兼容Tailwind和原生CSS) notification.style.cssText += ` position: fixed; bottom: 16px; right: 16px; padding: 16px 24px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 1000; transition: all 0.3s ease; opacity: 0; `; if (type === 'success') { notification.style.backgroundColor = '#10b981'; notification.style.color = 'white'; } else if (type === 'error') { notification.style.backgroundColor = '#ef4444'; notification.style.color = 'white'; } else { notification.style.backgroundColor = '#3b82f6'; notification.style.color = 'white'; } notification.textContent = message; document.body.appendChild(notification); // 显示通知 setTimeout(() => { notification.style.opacity = '1'; }, 10); // 3秒后隐藏通知 setTimeout(() => { notification.style.opacity = '0'; setTimeout(() => { notification.remove(); }, 300); }, 3000); } // 页面加载完成后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initConfigPage); } else { initConfigPage(); }