Files
PerToolBoxFront/js/common.js

197 lines
5.7 KiB
JavaScript

/**
* PerToolBox Front - 公共 JavaScript
*/
// ========== 全局变量 ==========
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 baseUrl = window.API_BASE || '/api/v1';
const url = endpoint.startsWith('http') ? endpoint : `${baseUrl}${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) {
setToken(null);
if (!window.location.pathname.includes('/login.php')) {
window.location.href = '/login.php';
}
return null;
}
// 先获取响应文本,用于调试
const text = await response.text();
if (!response.ok) {
let errorMsg;
try {
const errorData = JSON.parse(text);
errorMsg = errorData.detail || errorData.message || JSON.stringify(errorData);
} catch (e) {
errorMsg = text || '请求失败';
}
throw new Error(errorMsg);
}
return JSON.parse(text);
} catch (error) {
console.error('API 请求错误:', error);
throw error;
}
}
// ========== 热度上报 ==========
async function recordUsage(toolName) {
try {
await apiRequest(`/tool/usage?tool_name=${toolName}`, { method: 'POST' });
console.log(`✅ 热度上报: ${toolName}`);
} 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 || '用户';
if (userInfoDiv) {
userInfoDiv.innerHTML = `
<div class="px-6 py-3 bg-blue-800 rounded-lg mx-4 mb-2">
<div class="text-sm text-blue-200">欢迎,</div>
<div class="font-semibold">${escapeHtml(displayName)}</div>
</div>
`;
}
if (profileLink) profileLink.style.display = 'flex';
if (logoutBtn) logoutBtn.style.display = 'flex';
if (loginLink) loginLink.style.display = 'none';
} else {
if (userInfoDiv) 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);
}
// ========== 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();
});
}
});