|
|
| const API_BASE = window.location.origin;
|
|
|
|
|
| let authToken = localStorage.getItem('auth_token');
|
|
|
|
|
| document.addEventListener('DOMContentLoaded', function() {
|
| const currentPage = window.location.pathname;
|
| console.log('[DEBUG] Current page:', currentPage);
|
| console.log('[DEBUG] Auth token:', authToken ? 'exists' : 'none');
|
|
|
| if (currentPage.includes('dashboard')) {
|
| console.log('[DEBUG] Loading dashboard...');
|
| if (!authToken) {
|
| window.location.href = '/static/index.html';
|
| return;
|
| }
|
| loadDashboard();
|
| } else {
|
|
|
| console.log('[DEBUG] Loading login page...');
|
| if (authToken) {
|
| console.log('[DEBUG] Already logged in, redirecting to dashboard...');
|
| window.location.href = '/dashboard';
|
| return;
|
| }
|
| setupLoginForm();
|
| }
|
| });
|
|
|
|
|
|
|
|
|
| function setupLoginForm() {
|
| console.log('[DEBUG] setupLoginForm called');
|
| const loginForm = document.getElementById('loginForm');
|
| console.log('[DEBUG] loginForm element:', loginForm);
|
| if (loginForm) {
|
| console.log('[DEBUG] Adding submit event listener to loginForm');
|
| loginForm.addEventListener('submit', async (e) => {
|
| e.preventDefault();
|
| console.log('[DEBUG] Form submitted!');
|
|
|
| const username = document.getElementById('username').value;
|
| const password = document.getElementById('password').value;
|
| const errorDiv = document.getElementById('loginError');
|
|
|
| console.log('[DEBUG] Attempting login with username:', username);
|
|
|
| try {
|
| console.log('[DEBUG] Sending request to:', `${API_BASE}/api/auth/login`);
|
| const response = await fetch(`${API_BASE}/api/auth/login`, {
|
| method: 'POST',
|
| headers: {
|
| 'Content-Type': 'application/json'
|
| },
|
| body: JSON.stringify({ username, password })
|
| });
|
|
|
| const data = await response.json();
|
|
|
| if (response.ok) {
|
| authToken = data.token;
|
| localStorage.setItem('auth_token', authToken);
|
| window.location.href = '/dashboard';
|
| } else {
|
| errorDiv.textContent = data.error || '登录失败';
|
| errorDiv.style.display = 'block';
|
| }
|
| } catch (error) {
|
| errorDiv.textContent = '网络错误,请稍后重试';
|
| errorDiv.style.display = 'block';
|
| }
|
| });
|
| }
|
| }
|
|
|
|
|
| function logout() {
|
| if (confirm('确定要退出吗?')) {
|
| localStorage.removeItem('auth_token');
|
| authToken = null;
|
| window.location.href = '/';
|
| }
|
| }
|
|
|
|
|
| function showChangePasswordModal() {
|
| document.getElementById('changePasswordModal').style.display = 'flex';
|
| document.getElementById('changePasswordForm').reset();
|
| document.getElementById('changePasswordError').style.display = 'none';
|
| }
|
|
|
|
|
| function closeChangePasswordModal() {
|
| document.getElementById('changePasswordModal').style.display = 'none';
|
| }
|
|
|
|
|
| async function changePassword(oldPassword, newPassword) {
|
| try {
|
| const response = await apiRequest('/api/auth/password', {
|
| method: 'PUT',
|
| body: JSON.stringify({
|
| old_password: oldPassword,
|
| new_password: newPassword
|
| })
|
| });
|
|
|
| if (response.ok) {
|
| showToast('密码修改成功', 'success');
|
| closeChangePasswordModal();
|
| return true;
|
| } else {
|
| const data = await response.json();
|
| return { error: data.error || '密码修改失败' };
|
| }
|
| } catch (error) {
|
| console.error('修改密码错误:', error);
|
| return { error: '网络错误,请重试' };
|
| }
|
| }
|
|
|
|
|
| function setupChangePasswordForm() {
|
| const form = document.getElementById('changePasswordForm');
|
| if (form) {
|
| form.addEventListener('submit', async (e) => {
|
| e.preventDefault();
|
|
|
| const oldPassword = document.getElementById('oldPassword').value;
|
| const newPassword = document.getElementById('newPassword').value;
|
| const confirmPassword = document.getElementById('confirmPassword').value;
|
| const errorDiv = document.getElementById('changePasswordError');
|
|
|
|
|
| if (newPassword.length < 6) {
|
| errorDiv.textContent = '新密码至少需要6位字符';
|
| errorDiv.style.display = 'block';
|
| return;
|
| }
|
|
|
|
|
| if (newPassword !== confirmPassword) {
|
| errorDiv.textContent = '两次输入的密码不一致';
|
| errorDiv.style.display = 'block';
|
| return;
|
| }
|
|
|
| const result = await changePassword(oldPassword, newPassword);
|
| if (result === true) {
|
|
|
| } else if (result && result.error) {
|
| errorDiv.textContent = result.error;
|
| errorDiv.style.display = 'block';
|
| }
|
| });
|
| }
|
| }
|
|
|
|
|
| async function apiRequest(url, options = {}) {
|
| const headers = {
|
| 'Content-Type': 'application/json',
|
| ...options.headers
|
| };
|
|
|
| if (authToken) {
|
| headers['Authorization'] = `Bearer ${authToken}`;
|
| }
|
|
|
| const response = await fetch(`${API_BASE}${url}`, {
|
| ...options,
|
| headers
|
| });
|
|
|
|
|
| if (response.status === 401) {
|
| localStorage.removeItem('auth_token');
|
| authToken = null;
|
| window.location.href = '/';
|
| return;
|
| }
|
|
|
| return response;
|
| }
|
|
|
|
|
|
|
|
|
| async function loadDashboard() {
|
| setupChangePasswordForm();
|
| await loadUserInfo();
|
| await loadStats();
|
| await loadCookies();
|
| }
|
|
|
|
|
| async function loadUserInfo() {
|
| try {
|
| const response = await apiRequest('/api/auth/me');
|
| if (response.ok) {
|
| const user = await response.json();
|
| document.getElementById('currentUser').textContent = user.username;
|
| }
|
| } catch (error) {
|
| console.error('加载用户信息失败:', error);
|
| }
|
| }
|
|
|
|
|
| async function loadStats() {
|
| try {
|
| const response = await apiRequest('/api/cookies/stats');
|
| if (response.ok) {
|
| const stats = await response.json();
|
| document.getElementById('totalCount').textContent = stats.total_count;
|
| document.getElementById('validCount').textContent = stats.valid_count;
|
| document.getElementById('invalidCount').textContent = stats.invalid_count;
|
| document.getElementById('totalUsage').textContent = stats.total_usage.toLocaleString();
|
| }
|
| } catch (error) {
|
| console.error('加载统计信息失败:', error);
|
| }
|
| }
|
|
|
|
|
| async function loadCookies() {
|
| try {
|
| const response = await apiRequest('/api/cookies');
|
| if (response.ok) {
|
| const data = await response.json();
|
|
|
| renderCookieTable(Array.isArray(data) ? data : (data.cookies || []));
|
| }
|
| } catch (error) {
|
| console.error('加载 Cookie 列表失败:', error);
|
| }
|
| }
|
|
|
|
|
| function renderCookieTable(cookies) {
|
| const tbody = document.getElementById('cookieTableBody');
|
| const emptyState = document.getElementById('emptyState');
|
|
|
| if (cookies.length === 0) {
|
| tbody.innerHTML = '';
|
| emptyState.style.display = 'block';
|
| return;
|
| }
|
|
|
| emptyState.style.display = 'none';
|
|
|
| tbody.innerHTML = cookies.map((cookie, index) => `
|
| <tr>
|
| <td>${index + 1}</td>
|
| <td>${escapeHtml(cookie.name)}</td>
|
| <td>
|
| <span class="status-badge ${cookie.is_valid ? 'status-valid' : 'status-invalid'}">
|
| ${cookie.is_valid ? '✅ 有效' : '❌ 无效'}
|
| </span>
|
| </td>
|
| <td>${(cookie.usage_count || 0).toLocaleString()}</td>
|
| <td>${cookie.priority || 0}</td>
|
| <td>${formatTime(cookie.last_validated)}</td>
|
| <td>
|
| <div class="action-buttons">
|
| <button class="btn btn-secondary btn-sm" onclick="validateCookie(${cookie.id})">🔄</button>
|
| <button class="btn btn-secondary btn-sm" onclick="editCookie(${cookie.id})">⚙️</button>
|
| <button class="btn btn-danger btn-sm" onclick="deleteCookie(${cookie.id})">🗑️</button>
|
| </div>
|
| </td>
|
| </tr>
|
| `).join('');
|
| }
|
|
|
|
|
| function refreshCookies() {
|
| loadCookies();
|
| loadStats();
|
| }
|
|
|
|
|
|
|
|
|
| function showAddModal() {
|
| document.getElementById('addModal').style.display = 'flex';
|
| document.getElementById('addCookieForm').reset();
|
| }
|
|
|
|
|
| function closeAddModal() {
|
| document.getElementById('addModal').style.display = 'none';
|
| }
|
|
|
|
|
| document.getElementById('addCookieForm')?.addEventListener('submit', async (e) => {
|
| e.preventDefault();
|
|
|
| const formData = new FormData(e.target);
|
| const data = {
|
| name: formData.get('name'),
|
| api_key: formData.get('api_key'),
|
| session_key: formData.get('session_key') || '',
|
| priority: parseInt(formData.get('priority') || '0')
|
| };
|
|
|
| try {
|
| const response = await apiRequest('/api/cookies', {
|
| method: 'POST',
|
| body: JSON.stringify(data)
|
| });
|
|
|
| if (response.ok) {
|
| showToast('Cookie 添加成功', 'success');
|
| closeAddModal();
|
| refreshCookies();
|
| } else {
|
| const error = await response.json();
|
| showToast(error.error || '添加失败', 'error');
|
| }
|
| } catch (error) {
|
| showToast('网络错误', 'error');
|
| }
|
| });
|
|
|
|
|
| async function editCookie(id) {
|
| try {
|
| const response = await apiRequest(`/api/cookies/${id}`);
|
| if (response.ok) {
|
| const cookie = await response.json();
|
| document.getElementById('editCookieId').value = cookie.id;
|
| document.getElementById('editCookieName').value = cookie.name;
|
| document.getElementById('editApiKey').value = cookie.api_key || '';
|
| document.getElementById('editSessionKey').value = cookie.session_key || '';
|
| document.getElementById('editCookiePriority').value = cookie.priority || 0;
|
| document.getElementById('editModal').style.display = 'flex';
|
| }
|
| } catch (error) {
|
| showToast('加载失败', 'error');
|
| }
|
| }
|
|
|
|
|
| function closeEditModal() {
|
| document.getElementById('editModal').style.display = 'none';
|
| }
|
|
|
|
|
| document.getElementById('editCookieForm')?.addEventListener('submit', async (e) => {
|
| e.preventDefault();
|
|
|
| const id = document.getElementById('editCookieId').value;
|
| const formData = new FormData(e.target);
|
| const data = {
|
| name: formData.get('name'),
|
| api_key: formData.get('api_key'),
|
| session_key: formData.get('session_key') || '',
|
| priority: parseInt(formData.get('priority') || '0')
|
| };
|
|
|
| try {
|
| const response = await apiRequest(`/api/cookies/${id}`, {
|
| method: 'PUT',
|
| body: JSON.stringify(data)
|
| });
|
|
|
| if (response.ok) {
|
| showToast('Cookie 更新成功', 'success');
|
| closeEditModal();
|
| refreshCookies();
|
| } else {
|
| const error = await response.json();
|
| showToast(error.error || '更新失败', 'error');
|
| }
|
| } catch (error) {
|
| showToast('网络错误', 'error');
|
| }
|
| });
|
|
|
|
|
| async function deleteCookie(id) {
|
| if (!confirm('确定要删除这个 Cookie 吗?')) {
|
| return;
|
| }
|
|
|
| try {
|
| const response = await apiRequest(`/api/cookies/${id}`, {
|
| method: 'DELETE'
|
| });
|
|
|
| if (response.ok) {
|
| showToast('Cookie 删除成功', 'success');
|
| refreshCookies();
|
| } else {
|
| const error = await response.json();
|
| showToast(error.error || '删除失败', 'error');
|
| }
|
| } catch (error) {
|
| showToast('网络错误', 'error');
|
| }
|
| }
|
|
|
|
|
| async function validateCookie(id) {
|
| try {
|
| showToast('正在验证...', 'success');
|
| const response = await apiRequest(`/api/cookies/${id}/validate`, {
|
| method: 'POST'
|
| });
|
|
|
| if (response.ok) {
|
| const result = await response.json();
|
| showToast(result.is_valid ? '✅ Cookie 有效' : '❌ Cookie 无效', result.is_valid ? 'success' : 'error');
|
| refreshCookies();
|
| } else {
|
| const error = await response.json();
|
| showToast(error.error || '验证失败', 'error');
|
| }
|
| } catch (error) {
|
| showToast('网络错误', 'error');
|
| }
|
| }
|
|
|
|
|
| async function validateAll() {
|
| if (!confirm('确定要验证所有 Cookie 吗?这可能需要一些时间。')) {
|
| return;
|
| }
|
|
|
| try {
|
| showToast('正在批量验证...', 'success');
|
| const response = await apiRequest('/api/cookies/validate/all', {
|
| method: 'POST'
|
| });
|
|
|
| if (response.ok) {
|
| const result = await response.json();
|
| showToast(`验证完成:${result.valid_count} 个有效,${result.invalid_count} 个无效`, 'success');
|
| refreshCookies();
|
| } else {
|
| const error = await response.json();
|
| showToast(error.error || '验证失败', 'error');
|
| }
|
| } catch (error) {
|
| showToast('网络错误', 'error');
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| function showToast(message, type = 'success') {
|
| const toast = document.getElementById('toast');
|
| toast.textContent = message;
|
| toast.className = `toast ${type}`;
|
| toast.style.display = 'block';
|
|
|
| setTimeout(() => {
|
| toast.style.display = 'none';
|
| }, 3000);
|
| }
|
|
|
|
|
| function formatTime(timeStr) {
|
| if (!timeStr) return '-';
|
| const date = new Date(timeStr);
|
| const now = new Date();
|
| const diff = Math.floor((now - date) / 1000);
|
|
|
| if (diff < 60) return '刚刚';
|
| if (diff < 3600) return `${Math.floor(diff / 60)} 分钟前`;
|
| if (diff < 86400) return `${Math.floor(diff / 3600)} 小时前`;
|
| return `${Math.floor(diff / 86400)} 天前`;
|
| }
|
|
|
|
|
| function escapeHtml(text) {
|
| const div = document.createElement('div');
|
| div.textContent = text;
|
| return div.innerHTML;
|
| } |