添加了Swagger API文档以及诸多优化

This commit is contained in:
Alex Yang
2025-11-28 02:15:42 +08:00
parent 67c651c804
commit 2e7d5fb1ce
9 changed files with 1080 additions and 125 deletions

View File

@@ -1,5 +1,32 @@
// 配置管理页面功能实现
// 工具函数安全获取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();
@@ -9,85 +36,192 @@ function initConfigPage() {
// 加载系统配置
async function loadConfig() {
try {
showLoading(true);
const config = await api.getConfig();
populateConfigForm(config);
} catch (error) {
showErrorMessage('加载配置失败: ' + error.message);
} finally {
showLoading(false);
}
}
// 填充配置表单
function populateConfigForm(config) {
// DNS配置
document.getElementById('dns-port')?.value = config.DNSServer.Port || 53;
document.getElementById('dns-upstream-servers')?.value = (config.DNSServer.UpstreamServers || []).join(', ');
document.getElementById('dns-timeout')?.value = config.DNSServer.Timeout || 5;
document.getElementById('dns-stats-file')?.value = config.DNSServer.StatsFile || './stats.json';
document.getElementById('dns-save-interval')?.value = config.DNSServer.SaveInterval || 300;
// 安全获取配置对象,防止未定义属性访问
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配置
document.getElementById('http-port')?.value = config.HTTPServer.Port || 8080;
setElementValue('http-port', getSafeValue(httpServerConfig.Port, 8080));
// 屏蔽配置
document.getElementById('shield-local-rules-file')?.value = config.Shield.LocalRulesFile || './rules.txt';
document.getElementById('shield-update-interval')?.value = config.Shield.UpdateInterval || 3600;
document.getElementById('shield-hosts-file')?.value = config.Shield.HostsFile || '/etc/hosts';
document.getElementById('shield-block-method')?.value = config.Shield.BlockMethod || '0.0.0.0';
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'));
setElementValue('shield-block-method', getSafeValue(shieldConfig.BlockMethod, '0.0.0.0'));
}
// 工具函数:安全设置元素值
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 {
showLoading(true);
await api.saveConfig(formData);
showSuccessMessage('配置保存成功');
} catch (error) {
showErrorMessage('保存配置失败: ' + error.message);
} finally {
showLoading(false);
}
}
// 重启服务
async function handleRestartService() {
if (confirm('确定要重启DNS服务吗重启期间服务可能会短暂不可用。')) {
try {
await api.restartService();
showSuccessMessage('服务重启成功');
} catch (error) {
showErrorMessage('重启服务失败: ' + error.message);
}
if (!confirm('确定要重启DNS服务吗重启期间服务可能会短暂不可用。')) return;
try {
showLoading(true);
await api.restartService();
showSuccessMessage('服务重启成功');
} catch (error) {
showErrorMessage('重启服务失败: ' + error.message);
} finally {
showLoading(false);
}
}
// 收集表单数据
// 收集表单数据并验证
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: parseInt(document.getElementById('dns-port')?.value) || 53,
UpstreamServers: document.getElementById('dns-upstream-servers')?.value.split(',').map(s => s.trim()).filter(Boolean) || [],
Timeout: parseInt(document.getElementById('dns-timeout')?.value) || 5,
StatsFile: document.getElementById('dns-stats-file')?.value || './data/stats.json',
SaveInterval: parseInt(document.getElementById('dns-save-interval')?.value) || 300
Port: dnsPort,
UpstreamServers: upstreamServers,
Timeout: timeout,
StatsFile: getElementValue('dns-stats-file') || './data/stats.json',
SaveInterval: saveInterval
},
HTTPServer: {
Port: parseInt(document.getElementById('http-port')?.value) || 8080
Port: httpPort
},
Shield: {
LocalRulesFile: document.getElementById('shield-local-rules-file')?.value || './data/rules.txt',
UpdateInterval: parseInt(document.getElementById('shield-update-interval')?.value) || 3600,
HostsFile: document.getElementById('shield-hosts-file')?.value || './data/hosts.txt',
BlockMethod: document.getElementById('shield-block-method')?.value || '0.0.0.0'
LocalRulesFile: getElementValue('shield-local-rules-file') || './data/rules.txt',
UpdateInterval: updateInterval,
HostsFile: getElementValue('shield-hosts-file') || './data/hosts.txt',
BlockMethod: getElementValue('shield-block-method') || '0.0.0.0'
}
};
}
// 工具函数:安全获取元素值
function getElementValue(elementId) {
const element = document.getElementById(elementId);
if (element && element.tagName === 'INPUT') {
return element.value;
}
return ''; // 默认返回空字符串
}
// 设置事件监听器
function setupConfigEventListeners() {
// 保存配置按钮
document.getElementById('save-config-btn')?.addEventListener('click', handleSaveConfig);
getElement('save-config-btn')?.addEventListener('click', handleSaveConfig);
// 重启服务按钮
document.getElementById('restart-service-btn')?.addEventListener('click', handleRestartService);
getElement('restart-service-btn')?.addEventListener('click', handleRestartService);
}
// 显示加载状态
function showLoading(show) {
const loadingElement = document.getElementById('loading-overlay');
if (show) {
if (!loadingElement) {
const overlay = document.createElement('div');
overlay.id = 'loading-overlay';
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
color: white;
font-size: 18px;
`;
overlay.innerHTML = '<div>处理中...</div>';
document.body.appendChild(overlay);
}
} else {
loadingElement?.remove();
}
}
// 显示成功消息
@@ -112,13 +246,28 @@ function showNotification(message, type = 'info') {
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.classList.add('bg-green-500', 'text-white');
notification.style.backgroundColor = '#10b981';
notification.style.color = 'white';
} else if (type === 'error') {
notification.classList.add('bg-red-500', 'text-white');
notification.style.backgroundColor = '#ef4444';
notification.style.color = 'white';
} else {
notification.classList.add('bg-blue-500', 'text-white');
notification.style.backgroundColor = '#3b82f6';
notification.style.color = 'white';
}
notification.textContent = message;
@@ -126,14 +275,12 @@ function showNotification(message, type = 'info') {
// 显示通知
setTimeout(() => {
notification.classList.remove('opacity-0');
notification.classList.add('opacity-100');
notification.style.opacity = '1';
}, 10);
// 3秒后隐藏通知
setTimeout(() => {
notification.classList.remove('opacity-100');
notification.classList.add('opacity-0');
notification.style.opacity = '0';
setTimeout(() => {
notification.remove();
}, 300);