let apiToken = localStorage.getItem('pan_api_token') || ''; // 代理 fetch 请求注入凭证 const originalFetch = window.fetch; window.fetch = async function () { let [resource, config] = arguments; if (!config) config = {}; if (!config.headers) config.headers = {}; if (apiToken) { config.headers['Authorization'] = `Bearer ${apiToken}`; } const response = await originalFetch(resource, config); if (response.status === 403) { showAuthModal(); } return response; }; // 身份验证逻辑 function showAuthModal() { document.getElementById('auth-modal').style.display = 'flex'; } function saveAuth() { const val = document.getElementById('auth-input').value; if (val) { localStorage.setItem('pan_api_token', val); apiToken = val; document.getElementById('auth-modal').style.display = 'none'; showToast('身份验证成功', 'success'); document.getElementById('auth-input').value = ''; loadImages(); } else { showToast('Token 不能为空', 'error'); } } document.addEventListener('DOMContentLoaded', () => { initDragAndDrop(); loadImages(); }); // Toast 全局提示 function showToast(message, type = 'info') { const container = document.getElementById('toast-container'); const toast = document.createElement('div'); toast.className = `toast ${type}`; toast.textContent = message; container.appendChild(toast); setTimeout(() => { toast.style.animation = 'slideOutRight 0.3s ease forwards'; setTimeout(() => toast.remove(), 300); }, 3000); } // 拖拽与剪贴板处理 function initDragAndDrop() { const dropZone = document.getElementById('drop-zone'); const fileInput = document.getElementById('file-input'); dropZone.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', (e) => { handleFiles(e.target.files); e.target.value = ''; }); ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, preventDefaults, false); }); ['dragenter', 'dragover'].forEach(eventName => { dropZone.addEventListener(eventName, () => dropZone.classList.add('drag-over'), false); }); ['dragleave', 'drop'].forEach(eventName => { dropZone.addEventListener(eventName, () => dropZone.classList.remove('drag-over'), false); }); dropZone.addEventListener('drop', (e) => { const dt = e.dataTransfer; const files = dt.files; handleFiles(files); }, false); // 全局剪贴板监听 document.addEventListener('paste', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; const files = (e.clipboardData || window.clipboardData).files; if (files && files.length > 0) { e.preventDefault(); handleFiles(files); showToast('正在上传剪贴板图片...', 'info'); } }); } function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } function handleFiles(files) { const validFiles = Array.from(files).filter(f => f.type.startsWith('image/')); if (validFiles.length === 0) { showToast('仅支持上传图片格式', 'error'); return; } validFiles.forEach(uploadFile); } // 执行上传流程 async function uploadFile(file) { const queue = document.getElementById('upload-queue'); const item = document.createElement('div'); item.className = 'queue-item'; item.innerHTML = ` 正在上传: ${file.name}
`; queue.appendChild(item); const formData = new FormData(); formData.append('file', file); try { const response = await fetch('/api/upload', { method: 'POST', body: formData }); const result = await response.json(); item.style.animation = 'slideOutRight 0.3s forwards'; setTimeout(() => item.remove(), 300); if (result.code === 0 || result.code === 200) { showToast(`上传成功: ${file.name}`, 'success'); loadImages(); } else { showToast(`上传失败: ${result.message || '未知错误'}`, 'error'); } } catch (err) { item.remove(); showToast(`网络错误: ${err.message}`, 'error'); } } // 画廊视图获取 async function loadImages() { try { const response = await fetch('/api/images'); if (response.status !== 200) { if (response.status === 403) { document.getElementById('stats-counter').textContent = '未授权验证'; } return; } const result = await response.json(); if (result.code === 0 || result.code === 200) { renderGallery(result.data || []); document.getElementById('stats-counter').textContent = `共 ${(result.data || []).length} 张图片`; } else { showToast(`加载失败: ${result.message}`, 'error'); document.getElementById('stats-counter').textContent = '获取失败'; } } catch (err) { showToast('网络连接异常', 'error'); document.getElementById('stats-counter').textContent = '离线'; } } // 侧信道XSS安全防备渲染 function renderGallery(images) { const grid = document.getElementById('gallery-grid'); grid.innerHTML = ''; if (images.length === 0) { grid.innerHTML = '暂无图片'; return; } images.forEach(img => { const kbSize = (img.size / 1024).toFixed(1); const card = document.createElement('div'); card.className = 'img-card'; const finalUrl = img.url || img.origin_url; const safeName = (img.name || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); card.innerHTML = `