/** * PerToolBox Front - 公共 JavaScript * Copyright (C) 2024 Sea Network Technology Studio * Author: Canglan * License: AGPL v3 */ // ========== 全局变量 ========== let currentUser = null; // ========== 工具函数 ========== function getToken() { return localStorage.getItem('token'); } function setToken(token) { if (token) { localStorage.setItem('token', token); } else { localStorage.removeItem('token'); } } function isLoggedIn() { return !!getToken(); } // ========== API 请求封装 ========== async function apiRequest(endpoint, options = {}) { const url = endpoint.startsWith('http') ? endpoint : `${window.API_BASE}${endpoint}`; const headers = { 'Content-Type': 'application/json', ...options.headers }; const token = getToken(); if (token) { headers['Authorization'] = `Bearer ${token}`; } try { const response = await fetch(url, { ...options, headers }); if (response.status === 401) { // token 失效,清除本地存储并跳转登录页 setToken(null); if (!window.location.pathname.includes('/login.php')) { window.location.href = '/login.php'; } return null; } const data = await response.json(); if (!response.ok) { throw new Error(data.detail || data.message || '请求失败'); } return data; } catch (error) { console.error('API 请求错误:', error); throw error; } } // ========== 热度上报 ========== async function recordUsage(toolName) { try { await apiRequest(`/tool/usage?tool_name=${toolName}`, { method: 'POST' }); } catch (error) { console.warn('热度上报失败:', error); } } // ========== 获取用户信息 ========== async function loadUserInfo() { if (!isLoggedIn()) { updateUserUI(null); return null; } try { const user = await apiRequest('/user/profile'); currentUser = user; updateUserUI(user); return user; } catch (error) { console.error('获取用户信息失败:', error); setToken(null); updateUserUI(null); return null; } } // ========== 更新侧边栏 UI ========== function updateUserUI(user) { const userInfoDiv = document.getElementById('userInfo'); const profileLink = document.getElementById('profileLink'); const logoutBtn = document.getElementById('logoutBtn'); const loginLink = document.getElementById('loginLink'); if (user) { const displayName = user.username || user.phone || user.email || '用户'; userInfoDiv.innerHTML = `
欢迎,
${escapeHtml(displayName)}
`; if (profileLink) profileLink.style.display = 'flex'; if (logoutBtn) logoutBtn.style.display = 'flex'; if (loginLink) loginLink.style.display = 'none'; } else { userInfoDiv.innerHTML = ''; if (profileLink) profileLink.style.display = 'none'; if (logoutBtn) logoutBtn.style.display = 'none'; if (loginLink) loginLink.style.display = 'flex'; } } // ========== 退出登录 ========== function logout() { setToken(null); currentUser = null; updateUserUI(null); window.location.href = '/'; } // ========== 侧边栏控制 ========== function initSidebar() { const menuBtn = document.getElementById('menuBtn'); const closeBtn = document.getElementById('closeSidebar'); const sidebar = document.getElementById('sidebar'); const overlay = document.getElementById('overlay'); function openSidebar() { if (sidebar) sidebar.classList.add('open'); if (overlay) overlay.classList.add('active'); document.body.style.overflow = 'hidden'; } function closeSidebar() { if (sidebar) sidebar.classList.remove('open'); if (overlay) overlay.classList.remove('active'); document.body.style.overflow = ''; } if (menuBtn) menuBtn.addEventListener('click', openSidebar); if (closeBtn) closeBtn.addEventListener('click', closeSidebar); if (overlay) overlay.addEventListener('click', closeSidebar); // 点击侧边栏内的链接后自动关闭(移动端) if (sidebar) { sidebar.querySelectorAll('a').forEach(link => { link.addEventListener('click', () => { if (window.innerWidth < 768) { closeSidebar(); } }); }); } } // ========== HTML 转义 ========== function escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // ========== 显示 Toast 消息 ========== function showToast(message, type = 'success') { const toast = document.createElement('div'); toast.className = `fixed bottom-4 right-4 z-50 px-4 py-2 rounded-lg shadow-lg text-white ${ type === 'success' ? 'bg-green-500' : 'bg-red-500' }`; toast.textContent = message; document.body.appendChild(toast); setTimeout(() => toast.remove(), 3000); } // ========== 页面初始化 ========== document.addEventListener('DOMContentLoaded', () => { initSidebar(); loadUserInfo(); // 绑定退出按钮 const logoutBtn = document.getElementById('logoutBtn'); if (logoutBtn) { logoutBtn.addEventListener('click', (e) => { e.preventDefault(); logout(); }); } });