/* ===== 文件柜前端逻辑 ===== */ (function () { 'use strict'; // ===== 状态 ===== let currentCode = ''; // 当前取件码输入 let selectedFiles = []; // 已选择的文件 // ===== DOM 元素 ===== const $ = (id) => document.getElementById(id); const dropZone = $('dropZone'); const fileInput = $('fileInput'); const selectBtn = $('selectBtn'); const uploadProgress = $('uploadProgress'); const progressList = $('progressList'); const uploadResult = $('uploadResult'); const resultList = $('resultList'); const codeDots = $('codeDots'); const codeClear = $('codeClear'); const codeDisplay = document.querySelector('.code-display'); const queryBtn = $('queryBtn'); const queryResult = $('queryResult'); const toast = $('toast'); // ===== 禁用扩展名(与后端一致)===== const FORBIDDEN_EXTS = [ '.exe', '.bat', '.cmd', '.vbs', '.ps1', '.jar', '.com', '.msi', '.scr', '.pif', '.dll', '.ocx', '.hta', '.wsf', '.cpl', '.run', '.app', '.deb', '.rpm' ]; const MAX_SIZE = 100 * 1024 * 1024; // 100MB // ===== Toast 提示 ===== let toastTimer = null; function showToast(msg, type = '') { toast.textContent = msg; toast.className = 'toast show ' + type; if (toastTimer) clearTimeout(toastTimer); toastTimer = setTimeout(() => { toast.className = 'toast'; }, 3000); } // ===== 格式化文件大小 ===== function formatSize(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; return (bytes / (1024 * 1024 * 1024)).toFixed(1) + ' GB'; } // ===== 取件码输入处理 ===== function updateCodeDisplay() { if (currentCode.length === 0) { codeDots.textContent = '--------'; codeDots.classList.add('empty'); codeClear.classList.add('hidden'); } else { // 显示输入的数字 + 剩余位置用下划线 const display = currentCode + '-'.repeat(8 - currentCode.length); codeDots.textContent = display; codeDots.classList.remove('empty'); codeClear.classList.remove('hidden'); } queryBtn.disabled = currentCode.length !== 8; } function inputDigit(digit) { if (currentCode.length >= 8) return; currentCode += digit; updateCodeDisplay(); // 触发按键动画 const btn = document.querySelector(`.numpad-btn[data-key="${digit}"]`); if (btn) flashButton(btn); } function backspace() { currentCode = currentCode.slice(0, -1); updateCodeDisplay(); } function clearCode() { currentCode = ''; updateCodeDisplay(); queryResult.classList.add('hidden'); } function flashButton(btn) { btn.classList.add('pressed'); setTimeout(() => btn.classList.remove('pressed'), 120); } // ===== 小键盘事件 ===== document.querySelectorAll('.numpad-btn').forEach(btn => { btn.addEventListener('click', () => { const key = btn.dataset.key; if (key === 'clear') { clearCode(); } else if (key === 'back') { backspace(); flashButton(btn); } else { inputDigit(key); } }); }); // ===== 物理键盘事件 ===== document.addEventListener('keydown', (e) => { // 只处理数字键、退格、回车、Delete if (/^[0-9]$/.test(e.key)) { e.preventDefault(); inputDigit(e.key); } else if (e.key === 'Backspace') { e.preventDefault(); backspace(); } else if (e.key === 'Delete' || e.key === 'Escape') { e.preventDefault(); clearCode(); } else if (e.key === 'Enter') { e.preventDefault(); if (!queryBtn.disabled) doQuery(); } }); // ===== 粘贴监听:只提取 8 位数字 ===== document.addEventListener('paste', (e) => { // 如果焦点在上传区的 input 或 textarea,不拦截 const target = e.target; if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') && target.id !== 'hidden-code-input') { return; } const clipText = (e.clipboardData || window.clipboardData).getData('text'); if (!clipText) return; // 只保留数字 const digits = clipText.replace(/\D/g, ''); if (!digits) { showToast('剪贴板中没有数字内容', 'error'); return; } e.preventDefault(); // 清空再填入前 8 位 currentCode = digits.slice(0, 8); updateCodeDisplay(); showToast(`已粘贴 ${currentCode.length} 位数字`, 'success'); }); // ===== 取件码显示区点击 = 复制当前取件码 ===== codeDisplay.style.cursor = 'pointer'; codeDisplay.title = '点击复制当前取件码'; codeDisplay.addEventListener('click', () => { if (!currentCode) { showToast('还没有输入取件码', 'error'); return; } copyToClipboard(currentCode, '取件码已复制'); }); function copyToClipboard(text, toastMsg) { if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(text).then(() => showToast(toastMsg, 'success')); } else { // 兜底:hidden textarea + execCommand const ta = document.createElement('textarea'); ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); showToast(toastMsg, 'success'); } catch { showToast('复制失败,请手动选择', 'error'); } document.body.removeChild(ta); } } // ===== 清空按钮 ===== codeClear.addEventListener('click', (e) => { e.stopPropagation(); clearCode(); }); // ===== 拖拽上传 ===== ['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) handleFiles(files); }); dropZone.addEventListener('click', () => fileInput.click()); selectBtn.addEventListener('click', (e) => { e.stopPropagation(); fileInput.click(); }); fileInput.addEventListener('change', (e) => { const files = Array.from(e.target.files); if (files.length) handleFiles(files); fileInput.value = ''; // 重置,允许重复选择同一文件 }); // ===== 文件校验 ===== function validateFile(file) { const ext = '.' + file.name.split('.').pop().toLowerCase(); if (FORBIDDEN_EXTS.includes(ext)) { return { ok: false, msg: `禁止上传 ${ext} 类型文件` }; } if (file.size > MAX_SIZE) { return { ok: false, msg: `文件过大(${formatSize(file.size)}),上限 ${formatSize(MAX_SIZE)}` }; } if (file.size === 0) { return { ok: false, msg: '文件为空' }; } return { ok: true }; } // ===== 上传处理 ===== function handleFiles(files) { const validFiles = []; const errors = []; files.forEach(f => { const v = validateFile(f); if (v.ok) validFiles.push(f); else errors.push(`${f.name}: ${v.msg}`); }); if (errors.length) { showToast(errors[0] + (errors.length > 1 ? `(另有 ${errors.length - 1} 个文件问题)` : ''), 'error'); } if (!validFiles.length) return; selectedFiles = validFiles; doUpload(); } // ===== 执行上传 ===== function doUpload() { uploadProgress.classList.remove('hidden'); uploadResult.classList.add('hidden'); progressList.innerHTML = ''; resultList.innerHTML = ''; const formData = new FormData(); selectedFiles.forEach(f => formData.append('files', f)); // 为每个文件创建进度条 const progressItems = selectedFiles.map((f, i) => { const div = document.createElement('div'); div.className = 'progress-item'; div.innerHTML = `