Files
dns-server/static/js/main.js
2026-01-31 21:56:12 +08:00

567 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// main.js - 主脚本文件
// 页面数据缓存对象
const pageDataCache = {
// 页面初始化状态
initializedPages: {},
// 页面数据缓存
data: {
dashboard: {
timestamp: 0,
data: null,
expiry: 5 * 60 * 1000 // 5分钟过期
},
logs: {
timestamp: 0,
data: null,
expiry: 5 * 60 * 1000 // 5分钟过期
},
shield: {
timestamp: 0,
data: null,
expiry: 10 * 60 * 1000 // 10分钟过期
},
hosts: {
timestamp: 0,
data: null,
expiry: 10 * 60 * 1000 // 10分钟过期
},
gfwlist: {
timestamp: 0,
data: null,
expiry: 10 * 60 * 1000 // 10分钟过期
}
},
// 检查缓存是否有效
isCacheValid: function(page) {
const cache = this.data[page];
if (!cache || !cache.data) return false;
const now = Date.now();
return (now - cache.timestamp) < cache.expiry;
},
// 获取缓存数据
getCache: function(page) {
if (this.isCacheValid(page)) {
return this.data[page].data;
}
return null;
},
// 设置缓存数据
setCache: function(page, data) {
if (this.data[page]) {
this.data[page].data = data;
this.data[page].timestamp = Date.now();
}
},
// 清除缓存
clearCache: function(page) {
if (this.data[page]) {
this.data[page].data = null;
this.data[page].timestamp = 0;
}
},
// 标记页面已初始化
markPageInitialized: function(page) {
this.initializedPages[page] = true;
},
// 检查页面是否已初始化
isPageInitialized: function(page) {
return this.initializedPages[page] || false;
}
};
// 页面可见性状态
let isPageVisible = true;
// 页面初始化函数 - 根据当前hash值初始化对应页面
function initPageByHash() {
const hash = window.location.hash.substring(1);
// 隐藏所有内容区域
const contentSections = [
document.getElementById('dashboard-content'),
document.getElementById('shield-content'),
document.getElementById('hosts-content'),
document.getElementById('gfwlist-content'),
document.getElementById('query-content'),
document.getElementById('logs-content'),
document.getElementById('config-content')
];
contentSections.forEach(section => {
if (section) {
section.classList.add('hidden');
}
});
// 显示当前页面内容
const currentSection = document.getElementById(`${hash}-content`);
if (currentSection) {
currentSection.classList.remove('hidden');
}
// 更新页面标题
const pageTitle = document.getElementById('page-title');
if (pageTitle) {
const titles = {
'dashboard': '仪表盘',
'shield': '屏蔽管理',
'hosts': 'Hosts管理',
'gfwlist': 'GFWList管理',
'query': 'DNS屏蔽查询',
'logs': '查询日志',
'config': '系统设置'
};
pageTitle.textContent = titles[hash] || '仪表盘';
}
// 页面特定初始化 - 使用setTimeout延迟调用确保所有脚本文件都已加载完成
if (hash === 'shield') {
setTimeout(() => {
if (typeof initShieldPage === 'function') {
// 检查页面是否已经初始化
if (!pageDataCache.isPageInitialized('shield') || !pageDataCache.isCacheValid('shield')) {
initShieldPage();
pageDataCache.markPageInitialized('shield');
}
}
}, 0);
} else if (hash === 'hosts') {
setTimeout(() => {
if (typeof initHostsPage === 'function') {
// 检查页面是否已经初始化
if (!pageDataCache.isPageInitialized('hosts') || !pageDataCache.isCacheValid('hosts')) {
initHostsPage();
pageDataCache.markPageInitialized('hosts');
}
}
}, 0);
} else if (hash === 'gfwlist') {
setTimeout(() => {
if (typeof initGFWListPage === 'function') {
// 检查页面是否已经初始化
if (!pageDataCache.isPageInitialized('gfwlist') || !pageDataCache.isCacheValid('gfwlist')) {
initGFWListPage();
pageDataCache.markPageInitialized('gfwlist');
}
}
}, 0);
} else if (hash === 'logs') {
setTimeout(() => {
if (typeof initLogsPage === 'function') {
// 检查页面是否已经初始化
if (!pageDataCache.isPageInitialized('logs') || !pageDataCache.isCacheValid('logs')) {
initLogsPage();
pageDataCache.markPageInitialized('logs');
}
}
}, 0);
} else if (hash === 'dashboard') {
setTimeout(() => {
if (typeof loadDashboardData === 'function') {
// 检查页面是否已经初始化
if (!pageDataCache.isPageInitialized('dashboard') || !pageDataCache.isCacheValid('dashboard')) {
loadDashboardData();
pageDataCache.markPageInitialized('dashboard');
}
}
}, 0);
}
}
// 格式化运行时间
function formatUptime(milliseconds) {
// 简化版的格式化实际使用时需要根据API返回的数据格式调整
const seconds = Math.floor(milliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) {
return `${days}${hours % 24}小时`;
} else if (hours > 0) {
return `${hours}小时${minutes % 60}分钟`;
} else if (minutes > 0) {
return `${minutes}分钟${seconds % 60}`;
} else {
return `${seconds}`;
}
}
// 更新系统状态
function updateSystemStatus() {
api.getStatus()
.then(data => {
if (data.error) {
throw new Error(data.error);
}
const uptimeElement = document.getElementById('uptime');
if (uptimeElement) {
uptimeElement.textContent = `正常运行中 | ${formatUptime(data.uptime)}`;
uptimeElement.classList.remove('text-danger');
}
})
.catch(error => {
console.error('更新系统状态失败:', error);
const uptimeElement = document.getElementById('uptime');
if (uptimeElement) {
uptimeElement.textContent = '连接异常';
uptimeElement.classList.add('text-danger');
}
});
}
// 账户功能 - 下拉菜单、注销和修改密码
function setupAccountFeatures() {
// 下拉菜单功能
const accountDropdown = document.getElementById('account-dropdown');
const accountMenu = document.getElementById('account-menu');
const changePasswordBtn = document.getElementById('change-password-btn');
const logoutBtn = document.getElementById('logout-btn');
const changePasswordModal = document.getElementById('change-password-modal');
const closeModalBtn = document.getElementById('close-modal-btn');
const cancelChangePasswordBtn = document.getElementById('cancel-change-password');
const changePasswordForm = document.getElementById('change-password-form');
const passwordMismatch = document.getElementById('password-mismatch');
const newPassword = document.getElementById('new-password');
const confirmPassword = document.getElementById('confirm-password');
// 点击外部关闭下拉菜单
document.addEventListener('click', (e) => {
if (accountDropdown && !accountDropdown.contains(e.target)) {
accountMenu.classList.add('hidden');
}
});
// 点击账户区域切换下拉菜单
if (accountDropdown) {
accountDropdown.addEventListener('click', (e) => {
e.stopPropagation();
accountMenu.classList.toggle('hidden');
});
}
// 打开修改密码模态框
if (changePasswordBtn) {
changePasswordBtn.addEventListener('click', () => {
accountMenu.classList.add('hidden');
changePasswordModal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
});
}
// 关闭修改密码模态框
function closeModal() {
changePasswordModal.classList.add('hidden');
document.body.style.overflow = '';
changePasswordForm.reset();
passwordMismatch.classList.add('hidden');
}
// 绑定关闭模态框事件
if (closeModalBtn) {
closeModalBtn.addEventListener('click', closeModal);
}
if (cancelChangePasswordBtn) {
cancelChangePasswordBtn.addEventListener('click', closeModal);
}
// 点击模态框外部关闭模态框
if (changePasswordModal) {
changePasswordModal.addEventListener('click', (e) => {
if (e.target === changePasswordModal) {
closeModal();
}
});
}
// 按ESC键关闭模态框
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !changePasswordModal.classList.contains('hidden')) {
closeModal();
}
});
// 密码匹配验证
if (newPassword && confirmPassword) {
confirmPassword.addEventListener('input', () => {
if (newPassword.value !== confirmPassword.value) {
passwordMismatch.classList.remove('hidden');
} else {
passwordMismatch.classList.add('hidden');
}
});
newPassword.addEventListener('input', () => {
if (newPassword.value !== confirmPassword.value) {
passwordMismatch.classList.remove('hidden');
} else {
passwordMismatch.classList.add('hidden');
}
});
}
// 修改密码表单提交
if (changePasswordForm) {
changePasswordForm.addEventListener('submit', async (e) => {
e.preventDefault();
// 验证密码匹配
if (newPassword.value !== confirmPassword.value) {
passwordMismatch.classList.remove('hidden');
return;
}
const formData = new FormData(changePasswordForm);
const data = {
currentPassword: formData.get('currentPassword'),
newPassword: formData.get('newPassword')
};
try {
const response = await fetch('/api/change-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (response.ok && result.status === 'success') {
// 密码修改成功
alert('密码修改成功');
closeModal();
} else {
// 密码修改失败
alert(result.error || '密码修改失败');
}
} catch (error) {
console.error('修改密码失败:', error);
alert('修改密码失败,请稍后重试');
}
});
}
// 注销功能
if (logoutBtn) {
logoutBtn.addEventListener('click', async () => {
try {
await fetch('/api/logout', {
method: 'POST'
});
// 重定向到登录页面
window.location.href = '/login';
} catch (error) {
console.error('注销失败:', error);
alert('注销失败,请稍后重试');
}
});
}
}
// 页面导航功能
function setupNavigation() {
// 侧边栏菜单项
const menuItems = document.querySelectorAll('nav a');
const pageTitle = document.getElementById('page-title');
menuItems.forEach((item, index) => {
item.addEventListener('click', (e) => {
// 允许浏览器自动更新地址栏中的hash不阻止默认行为
// 移动端点击菜单项后自动关闭侧边栏
if (window.innerWidth < 768) {
closeSidebar();
}
});
});
// 移动端侧边栏切换
const toggleSidebar = document.getElementById('toggle-sidebar');
const closeSidebarBtn = document.getElementById('close-sidebar');
const sidebar = document.getElementById('mobile-sidebar');
const sidebarOverlay = document.getElementById('sidebar-overlay');
// 打开侧边栏函数
function openSidebar() {
console.log('Opening sidebar...');
if (sidebar) {
sidebar.classList.remove('-translate-x-full');
sidebar.classList.add('translate-x-0');
}
if (sidebarOverlay) {
sidebarOverlay.classList.remove('hidden');
sidebarOverlay.classList.add('block');
// 防止页面滚动
document.body.style.overflow = 'hidden';
}
console.log('Sidebar opened successfully');
}
// 关闭侧边栏函数
function closeSidebar() {
console.log('Closing sidebar...');
if (sidebar) {
sidebar.classList.add('-translate-x-full');
sidebar.classList.remove('translate-x-0');
}
if (sidebarOverlay) {
sidebarOverlay.classList.add('hidden');
sidebarOverlay.classList.remove('block');
// 恢复页面滚动
document.body.style.overflow = '';
}
console.log('Sidebar closed successfully');
}
// 切换侧边栏函数
function toggleSidebarVisibility() {
console.log('Toggling sidebar visibility...');
console.log('Current sidebar classes:', sidebar ? sidebar.className : 'sidebar not found');
if (sidebar && sidebar.classList.contains('-translate-x-full')) {
console.log('Sidebar is hidden, opening...');
openSidebar();
} else {
console.log('Sidebar is visible, closing...');
closeSidebar();
}
}
// 绑定切换按钮事件
if (toggleSidebar) {
toggleSidebar.addEventListener('click', toggleSidebarVisibility);
}
// 绑定关闭按钮事件
if (closeSidebarBtn) {
closeSidebarBtn.addEventListener('click', closeSidebar);
}
// 绑定遮罩层点击事件
if (sidebarOverlay) {
sidebarOverlay.addEventListener('click', closeSidebar);
}
// 移动端点击菜单项后自动关闭侧边栏
menuItems.forEach(item => {
item.addEventListener('click', () => {
// 检查是否是移动设备视图
if (window.innerWidth < 768) {
closeSidebar();
}
});
});
// 添加键盘事件监听按ESC键关闭侧边栏
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeSidebar();
}
});
}
// 主题切换功能
function setupThemeToggle() {
const themeToggle = document.getElementById('theme-toggle');
const body = document.body;
if (!themeToggle) return;
// 从localStorage加载主题偏好
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
body.classList.toggle('dark', savedTheme === 'dark');
updateThemeIcon(themeToggle, savedTheme === 'dark');
}
// 添加点击事件监听器
themeToggle.addEventListener('click', () => {
const isDark = body.classList.toggle('dark');
updateThemeIcon(themeToggle, isDark);
// 保存主题偏好到localStorage
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
}
// 更新主题图标
function updateThemeIcon(toggleElement, isDark) {
const icon = toggleElement.querySelector('i');
if (icon) {
if (isDark) {
icon.className = 'fa fa-sun-o text-sm sm:text-lg';
} else {
icon.className = 'fa fa-moon-o text-sm sm:text-lg';
}
}
}
// 处理页面可见性变化
function handleVisibilityChange() {
if (document.visibilityState === 'visible') {
isPageVisible = true;
console.log('页面变为可见');
// 当页面重新可见时,检查当前页面是否需要刷新数据
const hash = window.location.hash.substring(1);
// 只有当缓存过期时才重新加载数据
if (hash && !pageDataCache.isCacheValid(hash)) {
console.log(`缓存已过期,重新加载${hash}页面数据`);
// 根据当前页面类型重新加载数据
if (hash === 'dashboard' && typeof loadDashboardData === 'function') {
loadDashboardData();
} else if (hash === 'logs' && typeof loadLogs === 'function') {
loadLogs();
} else if (hash === 'shield' && typeof initShieldPage === 'function') {
initShieldPage();
} else if (hash === 'hosts' && typeof initHostsPage === 'function') {
initHostsPage();
}
}
// 更新系统状态
updateSystemStatus();
} else {
isPageVisible = false;
console.log('页面变为隐藏');
}
}
// 初始化函数
function init() {
// 设置导航
setupNavigation();
// 设置账户功能
setupAccountFeatures();
// 设置主题切换
setupThemeToggle();
// 初始化页面
initPageByHash();
// 添加hashchange事件监听处理浏览器前进/后退按钮
window.addEventListener('hashchange', initPageByHash);
// 添加页面可见性变化监听
document.addEventListener('visibilitychange', handleVisibilityChange);
// 定期更新系统状态
setInterval(updateSystemStatus, 5000);
}
// 页面加载完成后执行初始化
window.addEventListener('DOMContentLoaded', init);