// ========== 初始化二维码 ========== document.addEventListener('DOMContentLoaded', function () { new QRCode(document.getElementById('qrcode'), { text: SERVER_URL, width: 140, height: 140, colorDark: '#333333', colorLight: '#ffffff', correctLevel: QRCode.CorrectLevel.M }); loadFiles(); }); // ========== 复制链接 ========== function copyUrl() { const url = document.getElementById('urlValue').textContent; navigator.clipboard.writeText(url).then(() => { const btn = document.querySelector('.btn-copy'); const original = btn.textContent; btn.textContent = '已复制 ✓'; setTimeout(() => btn.textContent = original, 1500); }).catch(() => { // 兼容旧浏览器 const input = document.createElement('input'); input.value = url; document.body.appendChild(input); input.select(); document.execCommand('copy'); document.body.removeChild(input); }); } // ========== 上传相关 ========== const dropZone = document.getElementById('dropZone'); const fileInput = document.getElementById('fileInput'); const progressContainer = document.getElementById('progressContainer'); const progressFill = document.getElementById('progressFill'); const progressName = document.getElementById('progressName'); const progressPercent = document.getElementById('progressPercent'); // 点击触发文件选择 dropZone.addEventListener('click', () => fileInput.click()); // 文件选择 fileInput.addEventListener('change', (e) => { if (e.target.files.length) { uploadFiles(Array.from(e.target.files)); fileInput.value = ''; } }); // 拖拽事件 ['dragenter', 'dragover'].forEach(evt => { dropZone.addEventListener(evt, (e) => { e.preventDefault(); e.stopPropagation(); dropZone.classList.add('dragover'); }); }); ['dragleave', 'drop'].forEach(evt => { dropZone.addEventListener(evt, (e) => { e.preventDefault(); e.stopPropagation(); dropZone.classList.remove('dragover'); }); }); dropZone.addEventListener('drop', (e) => { const files = Array.from(e.dataTransfer.files); if (files.length) uploadFiles(files); }); // 批量上传 function uploadFiles(files) { let index = 0; const total = files.length; function next() { if (index >= total) { progressContainer.style.display = 'none'; loadFiles(); return; } const file = files[index]; index++; uploadSingle(file, () => next()); } next(); } // 单个文件上传 function uploadSingle(file, callback) { const formData = new FormData(); formData.append('file', file); const xhr = new XMLHttpRequest(); progressContainer.style.display = 'block'; progressName.textContent = file.name; progressFill.style.width = '0%'; progressPercent.textContent = '0%'; xhr.upload.addEventListener('progress', (e) => { if (e.lengthComputable) { const percent = Math.round((e.loaded / e.total) * 100); progressFill.style.width = percent + '%'; progressPercent.textContent = percent + '%'; } }); xhr.addEventListener('load', () => { progressFill.style.width = '100%'; progressPercent.textContent = '100%'; setTimeout(callback, 300); }); xhr.addEventListener('error', () => { alert('上传失败:' + file.name); callback(); }); xhr.open('POST', '/upload'); xhr.send(formData); } // ========== 文件列表 ========== function loadFiles() { fetch('/files') .then(res => res.json()) .then(files => renderFiles(files)) .catch(err => console.error('加载文件失败', err)); } function renderFiles(files) { const list = document.getElementById('fileList'); if (!files.length) { list.innerHTML = '
  • 暂无文件
  • '; return; } list.innerHTML = files.map(f => `
  • ${getIcon(f.name)}
    ${escapeHtml(f.name)}
    ${f.size}
    下载
  • `).join(''); } function deleteFile(name) { if (!confirm('确定删除 ' + name + ' ?')) return; fetch('/delete/' + encodeURIComponent(name), { method: 'DELETE' }) .then(res => res.json()) .then(() => loadFiles()) .catch(err => alert('删除失败')); } // ========== 工具函数 ========== function getIcon(name) { const ext = name.split('.').pop().toLowerCase(); const map = { jpg: '🖼️', jpeg: '🖼️', png: '🖼️', gif: '🖼️', webp: '🖼️', svg: '🖼️', mp4: '🎬', mov: '🎬', avi: '🎬', mkv: '🎬', mp3: '🎵', wav: '🎵', flac: '🎵', pdf: '📕', doc: '📘', docx: '📘', xls: '📗', xlsx: '📗', ppt: '📙', pptx: '📙', zip: '🗜️', rar: '🗜️', '7z': '🗜️', tar: '🗜️', gz: '🗜️', txt: '📄', md: '📝', json: '📋', xml: '📋', exe: '⚙️', apk: '📱', dmg: '💿', iso: '💿' }; return map[ext] || '📄'; } function escapeHtml(str) { return String(str).replace(/[&<>"']/g, s => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[s])); } function escapeJs(str) { return String(str).replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/"/g, '\\"'); }