284 lines
8.2 KiB
JavaScript
284 lines
8.2 KiB
JavaScript
|
/**
|
|||
|
* 智能保镖 - 单页面应用
|
|||
|
* 此脚本处理页面内容的无刷新加载和路由管理
|
|||
|
*/
|
|||
|
|
|||
|
// 缓存已加载的页面内容
|
|||
|
const pageCache = {};
|
|||
|
// 当前页面
|
|||
|
let currentPage = null;
|
|||
|
// 页面内容预加载状态
|
|||
|
let preloadingPages = false;
|
|||
|
|
|||
|
// 页面配置
|
|||
|
const pages = {
|
|||
|
'live-management': {
|
|||
|
path: './live-management.html',
|
|||
|
title: '直播管理 - 智能保镖',
|
|||
|
isDefault: true, // 设置为默认页面
|
|||
|
},
|
|||
|
'smart-bodyguard': {
|
|||
|
path: './smart-bodyguard.html',
|
|||
|
title: '保镖设置 - 智能保镖',
|
|||
|
},
|
|||
|
'id-whitelist-blacklist': {
|
|||
|
path: './id-whitelist-blacklist.html',
|
|||
|
title: 'ID黑白名单 - 智能保镖',
|
|||
|
},
|
|||
|
'id-blacklist': {
|
|||
|
path: './id-blacklist.html',
|
|||
|
title: '拉黑记录 - 智能保镖',
|
|||
|
},
|
|||
|
'logging': {
|
|||
|
path: './Logging.html',
|
|||
|
title: '运行日志 - 智能保镖',
|
|||
|
},
|
|||
|
'tutorial': {
|
|||
|
path: '#',
|
|||
|
title: '使用教程 - 智能保镖',
|
|||
|
},
|
|||
|
'feedback': {
|
|||
|
path: '#',
|
|||
|
title: '意见反馈 - 智能保镖',
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
// 提取页面主要内容的函数
|
|||
|
function extractMainContent(htmlContent, pageId) {
|
|||
|
const parser = new DOMParser();
|
|||
|
const doc = parser.parseFromString(htmlContent, 'text/html');
|
|||
|
|
|||
|
// 提取页面样式,确保样式能够正确应用
|
|||
|
const styles = doc.querySelectorAll('style');
|
|||
|
let styleContent = '';
|
|||
|
styles.forEach(style => {
|
|||
|
styleContent += style.outerHTML;
|
|||
|
});
|
|||
|
|
|||
|
// 提取页面主要内容,具体选择器根据页面结构调整
|
|||
|
let content;
|
|||
|
|
|||
|
// 非登录页面,直接获取主要内容
|
|||
|
content = doc.querySelector('main');
|
|||
|
// 如果没有找到main,尝试找其他容器
|
|||
|
if (!content) {
|
|||
|
content = doc.querySelector('.bg-white.rounded-xl') ||
|
|||
|
doc.querySelector('body > .container') ||
|
|||
|
doc.querySelector('body > div');
|
|||
|
}
|
|||
|
|
|||
|
// 提取页面的脚本部分,以便执行
|
|||
|
const scripts = doc.querySelectorAll('script:not([src])');
|
|||
|
const scriptContents = Array.from(scripts).map(script => script.textContent).join('\n');
|
|||
|
|
|||
|
let contentHtml = '';
|
|||
|
if (content) {
|
|||
|
// 如果找到了内容元素,使用它的HTML
|
|||
|
contentHtml = content.outerHTML;
|
|||
|
} else {
|
|||
|
// 如果没有找到特定内容元素,使用整个body内容
|
|||
|
console.warn(`无法在${pageId}页面找到主要内容,使用完整body内容`);
|
|||
|
contentHtml = doc.body.innerHTML;
|
|||
|
}
|
|||
|
|
|||
|
return {
|
|||
|
styles: styleContent,
|
|||
|
content: contentHtml,
|
|||
|
scripts: scriptContents
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
// 加载页面内容的函数
|
|||
|
async function loadPageContent(pageId) {
|
|||
|
if (!pages[pageId]) {
|
|||
|
console.error(`未找到页面: ${pageId}`);
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
// 如果页面内容已缓存,直接返回
|
|||
|
if (pageCache[pageId]) {
|
|||
|
return pageCache[pageId];
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
const page = pages[pageId];
|
|||
|
// 跳过非实际页面的加载
|
|||
|
if (page.path === '#') {
|
|||
|
return {
|
|||
|
styles: '',
|
|||
|
content: '<div class="flex items-center justify-center h-full"><p class="text-xl text-gray-500">此功能正在开发中...</p></div>',
|
|||
|
scripts: ''
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
console.log(`正在加载页面: ${page.path}`);
|
|||
|
const response = await fetch(page.path);
|
|||
|
if (!response.ok) {
|
|||
|
throw new Error(`无法加载页面: ${page.path}`);
|
|||
|
}
|
|||
|
|
|||
|
const html = await response.text();
|
|||
|
const extractedContent = extractMainContent(html, pageId);
|
|||
|
|
|||
|
// 缓存页面内容
|
|||
|
pageCache[pageId] = extractedContent;
|
|||
|
console.log(`页面 ${pageId} 加载成功`);
|
|||
|
return extractedContent;
|
|||
|
} catch (error) {
|
|||
|
console.error(`加载页面失败: ${error.message}`);
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 在后台预加载所有页面内容
|
|||
|
async function preloadPages() {
|
|||
|
if (preloadingPages) return;
|
|||
|
preloadingPages = true;
|
|||
|
|
|||
|
console.log('开始预加载所有页面...');
|
|||
|
for (const pageId in pages) {
|
|||
|
if (!pageCache[pageId] && pages[pageId].path !== '#') {
|
|||
|
await loadPageContent(pageId);
|
|||
|
console.log(`预加载完成: ${pageId}`);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
preloadingPages = false;
|
|||
|
console.log('所有页面预加载完成');
|
|||
|
}
|
|||
|
|
|||
|
// 显示页面的函数
|
|||
|
async function showPage(pageId) {
|
|||
|
console.log(`尝试显示页面: ${pageId}`);
|
|||
|
if (currentPage === pageId) return;
|
|||
|
|
|||
|
// 加载页面内容
|
|||
|
const pageData = await loadPageContent(pageId);
|
|||
|
if (!pageData) {
|
|||
|
console.error(`无法显示页面: ${pageId}`);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 更新页面标题
|
|||
|
document.title = pages[pageId].title || '智能保镖';
|
|||
|
|
|||
|
// 获取页面容器
|
|||
|
const pageContainer = document.getElementById(`${pageId}-page`);
|
|||
|
if (!pageContainer) {
|
|||
|
console.error(`未找到页面容器: ${pageId}-page`);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// 隐藏所有页面
|
|||
|
document.querySelectorAll('.page-container').forEach(container => {
|
|||
|
container.classList.remove('active');
|
|||
|
});
|
|||
|
|
|||
|
// 更新导航状态
|
|||
|
document.querySelectorAll('.sidebar-item').forEach(item => {
|
|||
|
item.classList.remove('active');
|
|||
|
if (item.getAttribute('data-page') === pageId) {
|
|||
|
item.classList.add('active');
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// 创建一个包含样式和内容的完整HTML
|
|||
|
let pageHtml = '';
|
|||
|
if (pageData.styles) {
|
|||
|
pageHtml += pageData.styles;
|
|||
|
}
|
|||
|
pageHtml += pageData.content;
|
|||
|
|
|||
|
// 设置页面内容
|
|||
|
pageContainer.innerHTML = pageHtml;
|
|||
|
|
|||
|
// 执行页面脚本
|
|||
|
if (pageData.scripts) {
|
|||
|
try {
|
|||
|
console.log(`执行 ${pageId} 页面脚本`);
|
|||
|
const scriptElement = document.createElement('script');
|
|||
|
scriptElement.textContent = pageData.scripts;
|
|||
|
document.body.appendChild(scriptElement);
|
|||
|
// 清理,防止重复添加
|
|||
|
setTimeout(() => {
|
|||
|
document.body.removeChild(scriptElement);
|
|||
|
}, 500);
|
|||
|
} catch (error) {
|
|||
|
console.error(`执行页面脚本失败: ${error.message}`);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 显示页面
|
|||
|
pageContainer.classList.add('active');
|
|||
|
currentPage = pageId;
|
|||
|
|
|||
|
console.log(`页面 ${pageId} 已显示`);
|
|||
|
|
|||
|
// 在移动设备上,导航后自动关闭侧边栏
|
|||
|
if (window.innerWidth < 1024) {
|
|||
|
const sidebar = document.getElementById('sidebar');
|
|||
|
sidebar.classList.add('hidden');
|
|||
|
}
|
|||
|
|
|||
|
// 当显示 live-management 页面时,获取初始账号列表
|
|||
|
if (pageId === 'live-management' && window.pywebview && window.pywebview.api) {
|
|||
|
window.pywebview.api.get_initial_accounts();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 路由处理函数
|
|||
|
function handleRoute() {
|
|||
|
let hash = window.location.hash.substring(1);
|
|||
|
if (!hash) {
|
|||
|
// 默认页面处理,直接使用live-management
|
|||
|
hash = 'live-management';
|
|||
|
window.location.hash = `#${hash}`;
|
|||
|
}
|
|||
|
console.log(`路由切换到: ${hash}`);
|
|||
|
showPage(hash);
|
|||
|
}
|
|||
|
|
|||
|
// 移动端菜单按钮事件
|
|||
|
function setupMobileMenu() {
|
|||
|
const menuButton = document.getElementById('mobile-menu-button');
|
|||
|
const sidebar = document.getElementById('sidebar');
|
|||
|
|
|||
|
if (menuButton && sidebar) {
|
|||
|
menuButton.addEventListener('click', () => {
|
|||
|
console.log('按钮点击事件触发');
|
|||
|
sidebar.classList.toggle('hidden');
|
|||
|
if (!sidebar.classList.contains('hidden')) {
|
|||
|
sidebar.classList.add('fixed', 'inset-0');
|
|||
|
sidebar.classList.remove('lg:block', 'lg:w-64');
|
|||
|
} else {
|
|||
|
sidebar.classList.remove('fixed', 'inset-0');
|
|||
|
sidebar.classList.add('lg:block', 'lg:w-64');
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 初始化应用
|
|||
|
function initApp() {
|
|||
|
console.log('应用初始化中...');
|
|||
|
|
|||
|
// 设置路由事件监听
|
|||
|
window.addEventListener('hashchange', handleRoute);
|
|||
|
|
|||
|
// 设置移动端菜单
|
|||
|
setupMobileMenu();
|
|||
|
|
|||
|
// 首次加载路由
|
|||
|
handleRoute();
|
|||
|
|
|||
|
// 预加载其他页面,提高用户体验
|
|||
|
setTimeout(() => {
|
|||
|
preloadPages();
|
|||
|
}, 1000);
|
|||
|
|
|||
|
console.log('应用初始化完成');
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// 初始化应用
|
|||
|
document.addEventListener('DOMContentLoaded', initApp);
|