Spaces:
Running
Running
| /** | |
| * HuggingFace 保活管理器 - 前端交互脚本 | |
| */ | |
| // Toast 通知函数 | |
| function showToast(message, type = 'info') { | |
| const container = document.getElementById('toast-container'); | |
| const toast = document.createElement('div'); | |
| toast.className = `toast toast-${type}`; | |
| const icons = { | |
| success: '<svg viewBox="0 0 24 24" fill="none"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" stroke="currentColor" stroke-width="2"/><polyline points="22,4 12,14.01 9,11.01" stroke="currentColor" stroke-width="2"/></svg>', | |
| error: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/><line x1="15" y1="9" x2="9" y2="15" stroke="currentColor" stroke-width="2"/><line x1="9" y1="9" x2="15" y2="15" stroke="currentColor" stroke-width="2"/></svg>', | |
| warning: '<svg viewBox="0 0 24 24" fill="none"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" stroke="currentColor" stroke-width="2"/><line x1="12" y1="9" x2="12" y2="13" stroke="currentColor" stroke-width="2"/><line x1="12" y1="17" x2="12.01" y2="17" stroke="currentColor" stroke-width="2"/></svg>', | |
| info: '<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/><line x1="12" y1="16" x2="12" y2="12" stroke="currentColor" stroke-width="2"/><line x1="12" y1="8" x2="12.01" y2="8" stroke="currentColor" stroke-width="2"/></svg>' | |
| }; | |
| toast.innerHTML = ` | |
| <span class="toast-icon">${icons[type] || icons.info}</span> | |
| <span class="toast-message">${message}</span> | |
| <button class="toast-close" onclick="this.parentElement.remove()"> | |
| <svg viewBox="0 0 24 24" fill="none"><line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" stroke-width="2"/><line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" stroke-width="2"/></svg> | |
| </button> | |
| `; | |
| container.appendChild(toast); | |
| // 自动移除 | |
| setTimeout(() => { | |
| toast.classList.add('fade-out'); | |
| setTimeout(() => toast.remove(), 300); | |
| }, 4000); | |
| } | |
| // 刷新页面 | |
| function refreshPage() { | |
| location.reload(); | |
| } | |
| // 添加URL | |
| document.getElementById('add-url-form').addEventListener('submit', async (e) => { | |
| e.preventDefault(); | |
| const urlInput = document.getElementById('url-input'); | |
| const nameInput = document.getElementById('name-input'); | |
| const btn = e.target.querySelector('button[type="submit"]'); | |
| const url = urlInput.value.trim(); | |
| const name = nameInput.value.trim(); | |
| if (!url) { | |
| showToast('请输入URL地址', 'error'); | |
| return; | |
| } | |
| btn.disabled = true; | |
| btn.innerHTML = '<span class="loading"></span> 添加中...'; | |
| try { | |
| const response = await fetch('/api/urls', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ url, name }) | |
| }); | |
| const data = await response.json(); | |
| if (response.ok) { | |
| showToast('URL添加成功', 'success'); | |
| setTimeout(refreshPage, 500); | |
| } else { | |
| showToast(data.error || '添加失败', 'error'); | |
| } | |
| } catch (error) { | |
| showToast('网络错误,请重试', 'error'); | |
| } finally { | |
| btn.disabled = false; | |
| btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none"><line x1="12" y1="5" x2="12" y2="19" stroke="currentColor" stroke-width="2"/><line x1="5" y1="12" x2="19" y2="12" stroke="currentColor" stroke-width="2"/></svg> 添加'; | |
| } | |
| }); | |
| // 删除URL | |
| document.querySelectorAll('.delete-btn').forEach(btn => { | |
| btn.addEventListener('click', async () => { | |
| const index = btn.dataset.index; | |
| if (!confirm('确定要删除这个URL吗?')) return; | |
| btn.disabled = true; | |
| try { | |
| const response = await fetch(`/api/urls/${index}`, { | |
| method: 'DELETE' | |
| }); | |
| if (response.ok) { | |
| showToast('删除成功', 'success'); | |
| setTimeout(refreshPage, 500); | |
| } else { | |
| showToast('删除失败', 'error'); | |
| } | |
| } catch (error) { | |
| showToast('网络错误', 'error'); | |
| } finally { | |
| btn.disabled = false; | |
| } | |
| }); | |
| }); | |
| // Ping单个URL | |
| document.querySelectorAll('.ping-btn').forEach(btn => { | |
| btn.addEventListener('click', async () => { | |
| const index = btn.dataset.index; | |
| const urlItem = btn.closest('.url-item'); | |
| const urlName = urlItem.querySelector('.url-name').textContent; | |
| btn.disabled = true; | |
| btn.innerHTML = '<span class="loading"></span>'; | |
| try { | |
| const response = await fetch(`/api/ping/${index}`, { | |
| method: 'POST' | |
| }); | |
| const data = await response.json(); | |
| if (data.result && data.result.status === 'success') { | |
| showToast(`${urlName} 连接成功 (${data.result.code})`, 'success'); | |
| } else if (data.result && data.result.status === 'warning') { | |
| showToast(`${urlName} 返回状态码: ${data.result.code}`, 'warning'); | |
| } else { | |
| showToast(`${urlName} 连接失败: ${data.result?.message || '未知错误'}`, 'error'); | |
| } | |
| } catch (error) { | |
| showToast('网络错误', 'error'); | |
| } finally { | |
| btn.disabled = false; | |
| btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" stroke="currentColor" stroke-width="2"/><polyline points="22,4 12,14.01 9,11.01" stroke="currentColor" stroke-width="2"/></svg>'; | |
| } | |
| }); | |
| }); | |
| // 全部保活 | |
| document.getElementById('ping-all-btn')?.addEventListener('click', async () => { | |
| const btn = document.getElementById('ping-all-btn'); | |
| btn.disabled = true; | |
| btn.innerHTML = '<span class="loading"></span> 执行中...'; | |
| showToast('正在执行保活任务...', 'info'); | |
| try { | |
| const response = await fetch('/api/ping', { | |
| method: 'POST' | |
| }); | |
| const data = await response.json(); | |
| if (data.results) { | |
| const successCount = data.results.filter(r => r.status === 'success').length; | |
| showToast(`保活完成: ${successCount}/${data.results.length} 成功`, | |
| successCount === data.results.length ? 'success' : 'warning'); | |
| setTimeout(refreshPage, 1000); | |
| } | |
| } catch (error) { | |
| showToast('执行失败', 'error'); | |
| } finally { | |
| btn.disabled = false; | |
| btn.innerHTML = '<svg viewBox="0 0 24 24" fill="none"><path d="M23 4v6h-6M1 20v-6h6" stroke="currentColor" stroke-width="2"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" stroke="currentColor" stroke-width="2"/></svg> 立即全部保活'; | |
| } | |
| }); | |
| // 清空日志 | |
| document.getElementById('clear-logs-btn')?.addEventListener('click', async () => { | |
| if (!confirm('确定要清空所有日志吗?')) return; | |
| try { | |
| const response = await fetch('/api/logs', { | |
| method: 'DELETE' | |
| }); | |
| if (response.ok) { | |
| showToast('日志已清空', 'success'); | |
| setTimeout(refreshPage, 500); | |
| } | |
| } catch (error) { | |
| showToast('清空失败', 'error'); | |
| } | |
| }); | |
| // 页面加载完成 | |
| document.addEventListener('DOMContentLoaded', () => { | |
| console.log('HuggingFace 保活管理器已加载'); | |
| }); | |