// 全局变量 let cookies = []; let authToken = ''; let currentUser = null; // 页面初始化 document.addEventListener('DOMContentLoaded', function() { // 检查是否已登录 checkLoginStatus(); // 绑定登录表单事件 const loginForm = document.getElementById('loginForm'); if (loginForm) { loginForm.addEventListener('submit', handleLogin); } // 监听窗口大小变化 window.addEventListener('resize', debounce(updateUI, 250)); }); // 防抖函数 function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // 检查登录状态 function checkLoginStatus() { const savedSession = localStorage.getItem('adminSession'); if (savedSession) { try { const session = JSON.parse(savedSession); // 检查会话是否过期(24小时) if (new Date().getTime() - session.timestamp < 24 * 60 * 60 * 1000) { currentUser = session.user; authToken = session.token; showMainContent(); return; } } catch (e) { console.error('Invalid session data'); } } // 检查记住的用户名 const rememberedUser = localStorage.getItem('rememberedUser'); if (rememberedUser) { document.getElementById('username').value = rememberedUser; document.getElementById('remember').checked = true; } } // 处理登录 async function handleLogin(e) { e.preventDefault(); const username = document.getElementById('username').value.trim(); const password = document.getElementById('password').value; const remember = document.getElementById('remember').checked; // 显示加载状态 const submitBtn = e.target.querySelector('button[type="submit"]'); const originalText = submitBtn.innerHTML; submitBtn.innerHTML = '登录中...'; submitBtn.disabled = true; try { // 发送登录请求 const response = await fetch('/admin/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const result = await response.json(); if (response.ok && result.success) { // 登录成功 currentUser = result.user; authToken = result.token; // 保存会话 const session = { user: currentUser, token: authToken, timestamp: new Date().getTime() }; localStorage.setItem('adminSession', JSON.stringify(session)); // 记住用户名 if (remember) { localStorage.setItem('rememberedUser', username); } else { localStorage.removeItem('rememberedUser'); } // 隐藏错误提示 document.getElementById('loginError').style.display = 'none'; // 显示主内容 showMainContent(); } else { // 登录失败 document.getElementById('loginErrorText').textContent = result.message || '用户名或密码错误'; document.getElementById('loginError').style.display = 'block'; } } catch (error) { console.error('Login error:', error); document.getElementById('loginErrorText').textContent = '登录失败,请稍后重试'; document.getElementById('loginError').style.display = 'block'; } finally { // 恢复按钮状态 submitBtn.innerHTML = originalText; submitBtn.disabled = false; } } // 显示主内容 function showMainContent() { // 隐藏登录页面 document.getElementById('loginContainer').style.display = 'none'; // 显示主内容 document.getElementById('mainContent').style.display = 'block'; // 更新用户信息 if (currentUser) { document.getElementById('currentUser').textContent = currentUser.username; document.getElementById('userAvatar').textContent = currentUser.username.charAt(0).toUpperCase(); } // 初始化主页面 initMainPage(); } // 初始化主页面 function initMainPage() { // 更新时间 updateTime(); setInterval(updateTime, 1000); // 加载Cookie数据 loadCookies(); // 定期刷新数据 setInterval(loadCookies, 30000); // 每30秒刷新一次 } // 退出登录 function logout() { if (confirm('确定要退出登录吗?')) { // 清除会话 localStorage.removeItem('adminSession'); currentUser = null; authToken = ''; // 重新加载页面 window.location.reload(); } } // 更新时间 function updateTime() { const now = new Date(); const timeString = now.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); const timeElement = document.getElementById('currentTime'); if (timeElement) { timeElement.textContent = timeString; } } // 显示加载动画 function showLoading() { document.querySelector('.loading-spinner').classList.add('active'); } // 隐藏加载动画 function hideLoading() { document.querySelector('.loading-spinner').classList.remove('active'); } // 显示提示消息 function showToast(message, type = 'success') { const toastHtml = ` `; const toastContainer = document.querySelector('.toast-container'); const toastElement = document.createElement('div'); toastElement.innerHTML = toastHtml; toastContainer.appendChild(toastElement); const toast = new bootstrap.Toast(toastElement.querySelector('.toast')); toast.show(); setTimeout(() => { toastElement.remove(); }, 5000); } // 添加日志 function addLog(message, type = 'info') { const logContainer = document.getElementById('logContainer'); if (!logContainer) return; // 移动端可能没有日志容器 const timestamp = new Date().toLocaleTimeString('zh-CN'); const logEntry = document.createElement('div'); logEntry.className = `log-entry mb-2 p-2 rounded bg-light`; logEntry.innerHTML = ` [${timestamp}] ${message} `; // 清空默认提示 if (logContainer.querySelector('.text-center')) { logContainer.innerHTML = ''; } logContainer.appendChild(logEntry); logContainer.scrollTop = logContainer.scrollHeight; } // 加载Cookie数据 async function loadCookies() { try { const response = await fetch('/cookies/status', { headers: { 'Authorization': `Bearer ${authToken}` } }); if (!response.ok) { if (response.status === 401) { // 认证失败,重新登录 localStorage.removeItem('adminSession'); window.location.reload(); return; } throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); cookies = data.cookies || []; updateUI(); addLog('成功加载Cookie数据', 'success'); } catch (error) { console.error('加载Cookie失败:', error); showToast('加载Cookie数据失败', 'danger'); addLog(`加载Cookie失败: ${error.message}`, 'error'); } } // 更新UI function updateUI() { // 更新统计信息 const totalCookies = cookies.length; const activeCookies = cookies.filter(c => c.valid && c.enabled).length; const threadIdCount = cookies.filter(c => c.threadId).length; document.getElementById('totalCookies').textContent = totalCookies; document.getElementById('activeCookies').textContent = activeCookies; document.getElementById('threadIdCount').textContent = threadIdCount; // 更新表格 const tbody = document.getElementById('cookieTableBody'); const emptyState = document.getElementById('emptyCookieState'); if (cookies.length === 0) { tbody.innerHTML = ''; emptyState.style.display = 'block'; } else { emptyState.style.display = 'none'; // 检测是否为移动设备 const isMobile = window.innerWidth <= 768; tbody.innerHTML = cookies.map((cookie, index) => { if (isMobile) { // 移动端简化表格 return `
${index + 1}
${cookie.userId.substring(0, 8)}... ${cookie.threadId ? '
Thread已配置' : ''}
${cookie.valid ? ' 有效' : ' 无效'} ${!cookie.enabled ? '
禁用' : ''}
`; } else { // 桌面端完整表格 return `
${index + 1} ${cookie.userId} ${cookie.spaceId} ${cookie.cookiePreview || '***'} ${cookie.valid ? '有效' : '无效'} ${!cookie.enabled ? '已禁用' : ''} ${cookie.lastUsed || '从未使用'} ${cookie.threadId ? `${cookie.threadId.substring(0, 12)}...` : '未设置'}
`; } }).join(''); } } // 移动端操作菜单 function showMobileActions(index) { const cookie = cookies[index]; // 创建操作菜单模态框 const modalHtml = ` `; // 移除旧的模态框 const oldModal = document.getElementById('mobileActionsModal'); if (oldModal) { oldModal.remove(); } // 添加新模态框 document.body.insertAdjacentHTML('beforeend', modalHtml); // 显示模态框 const modal = new bootstrap.Modal(document.getElementById('mobileActionsModal')); modal.show(); } // 查看Cookie详情(移动端) function viewCookieDetails(index) { const cookie = cookies[index]; const detailsHtml = ` `; // 移除旧的模态框 const oldModal = document.getElementById('cookieDetailsModal'); if (oldModal) { oldModal.remove(); } // 添加新模态框 document.body.insertAdjacentHTML('beforeend', detailsHtml); // 显示模态框 const modal = new bootstrap.Modal(document.getElementById('cookieDetailsModal')); modal.show(); } // 切换Cookie启用状态 async function toggleCookieEnabled(userId, enabled) { try { const response = await fetch(`/cookies/${userId}/toggle`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${authToken}` }, body: JSON.stringify({ enabled }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // 更新本地数据 const cookie = cookies.find(c => c.userId === userId); if (cookie) { cookie.enabled = enabled; } // 更新UI updateUI(); showToast(`Cookie已${enabled ? '启用' : '禁用'}`, 'success'); addLog(`${enabled ? '启用' : '禁用'}了用户 ${userId} 的Cookie`, 'info'); } catch (error) { console.error('切换Cookie状态失败:', error); showToast('切换Cookie状态失败', 'danger'); addLog(`切换Cookie状态失败: ${error.message}`, 'error'); // 恢复原状态 await loadCookies(); } } // 刷新Cookie状态 async function refreshCookies() { showLoading(); addLog('正在刷新Cookie状态...'); try { const response = await fetch('/cookies/refresh', { method: 'POST', headers: { 'Authorization': `Bearer ${authToken}` } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } await loadCookies(); showToast('Cookie状态已刷新', 'success'); addLog('Cookie状态刷新成功', 'success'); } catch (error) { console.error('刷新失败:', error); showToast('刷新Cookie状态失败', 'danger'); addLog(`刷新失败: ${error.message}`, 'error'); } finally { hideLoading(); } } // 添加Cookie async function addCookie() { const cookieContent = document.getElementById('cookieContent').value.trim(); const threadId = document.getElementById('cookieThreadId').value.trim(); if (!cookieContent) { showToast('请输入Cookie内容', 'warning'); return; } showLoading(); addLog('正在添加新Cookie...'); try { const response = await fetch('/cookies/add', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${authToken}` }, body: JSON.stringify({ cookies: cookieContent, threadId: threadId || undefined }) }); const result = await response.json(); if (!response.ok) { throw new Error(result.error?.message || `HTTP error! status: ${response.status}`); } // 显示详细结果 console.log('添加Cookie结果:', result); // 关闭模态框 bootstrap.Modal.getInstance(document.getElementById('addCookieModal')).hide(); // 清空表单 document.getElementById('cookieContent').value = ''; document.getElementById('cookieThreadId').value = ''; // 重新加载数据 await loadCookies(); // 显示详细的结果信息 if (result.added > 0) { showToast(`成功添加 ${result.added} 个Cookie`, 'success'); addLog(`成功添加 ${result.added} 个Cookie`, 'success'); } else if (result.failed > 0) { showToast(`添加失败: ${result.failed} 个Cookie无效`, 'danger'); addLog(`添加失败: ${result.failed} 个Cookie无效`, 'error'); // 如果有错误详情,显示它们 if (result.errors && result.errors.length > 0) { result.errors.forEach(error => { addLog(`错误详情: ${error}`, 'error'); }); } } else { showToast('未添加任何Cookie', 'warning'); addLog('未添加任何Cookie', 'warning'); } } catch (error) { console.error('添加Cookie失败:', error); showToast(`添加Cookie失败: ${error.message}`, 'danger'); addLog(`添加Cookie失败: ${error.message}`, 'error'); } finally { hideLoading(); } } // 编辑Thread ID function editThreadId(index) { const cookie = cookies[index]; document.getElementById('editCookieIndex').value = index; document.getElementById('editUserId').value = cookie.userId; document.getElementById('editThreadId').value = cookie.threadId || ''; const modal = new bootstrap.Modal(document.getElementById('editThreadIdModal')); modal.show(); } // 保存Thread ID async function saveThreadId() { const index = parseInt(document.getElementById('editCookieIndex').value); const threadId = document.getElementById('editThreadId').value.trim(); const cookie = cookies[index]; showLoading(); addLog(`正在更新用户 ${cookie.userId} 的Thread ID...`); try { const response = await fetch('/cookies/thread', { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${authToken}` }, body: JSON.stringify({ userId: cookie.userId, threadId: threadId || null }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // 关闭模态框 bootstrap.Modal.getInstance(document.getElementById('editThreadIdModal')).hide(); // 重新加载数据 await loadCookies(); showToast('Thread ID已更新', 'success'); addLog(`成功更新用户 ${cookie.userId} 的Thread ID`, 'success'); } catch (error) { console.error('更新Thread ID失败:', error); showToast('更新Thread ID失败', 'danger'); addLog(`更新Thread ID失败: ${error.message}`, 'error'); } finally { hideLoading(); } } // 删除Cookie async function deleteCookie(index) { const cookie = cookies[index]; if (!confirm(`确定要删除用户 ${cookie.userId} 的Cookie吗?`)) { return; } showLoading(); addLog(`正在删除用户 ${cookie.userId} 的Cookie...`); try { const response = await fetch(`/cookies/${cookie.userId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${authToken}` } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } // 重新加载数据 await loadCookies(); showToast('Cookie已删除', 'success'); addLog(`成功删除用户 ${cookie.userId} 的Cookie`, 'success'); } catch (error) { console.error('删除Cookie失败:', error); showToast('删除Cookie失败', 'danger'); addLog(`删除Cookie失败: ${error.message}`, 'error'); } finally { hideLoading(); } } // 导出功能(可选) function exportCookies() { const dataStr = JSON.stringify(cookies, null, 2); const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr); const exportFileDefaultName = `cookies_${new Date().toISOString().split('T')[0]}.json`; const linkElement = document.createElement('a'); linkElement.setAttribute('href', dataUri); linkElement.setAttribute('download', exportFileDefaultName); linkElement.click(); showToast('Cookie数据已导出', 'success'); addLog('导出Cookie数据', 'info'); } // 触摸事件优化 if ('ontouchstart' in window) { document.addEventListener('touchstart', function() {}, {passive: true}); }