class DownloadManager { constructor() { this.port = window.location.port || '55830'; this.baseUrl = `http://127.0.0.1:${this.port}/api`; this.currentDownload = null; this.init(); } init() { document.getElementById('port').textContent = this.port; // 绑定事件 document.getElementById('reloadBtn').addEventListener('click', () => this.reloadFolders()); document.getElementById('cleanupBtn').addEventListener('click', () => this.cleanupJson()); document.getElementById('closeModalBtn').addEventListener('click', () => this.hideModal()); document.querySelector('.close-btn').addEventListener('click', () => this.hideModal()); // 点击模态框外部关闭 document.getElementById('downloadModal').addEventListener('click', (e) => { if (e.target === document.getElementById('downloadModal')) { this.hideModal(); } }); // 初始加载 this.reloadFolders(); } showStatus(message, type = 'info') { const statusEl = document.getElementById('statusMessage'); statusEl.textContent = message; statusEl.style.borderLeftColor = type === 'error' ? '#ef4444' : type === 'warning' ? '#f59e0b' : '#10b981'; } showModal(title) { document.getElementById('modalTitle').textContent = title; document.getElementById('downloadModal').style.display = 'flex'; this.resetModal(); } hideModal() { document.getElementById('downloadModal').style.display = 'none'; if (this.currentDownload && this.currentDownload.abort) { this.currentDownload.abort(); } } resetModal() { document.getElementById('progressBar').style.width = '0%'; document.getElementById('progressText').textContent = '0%'; document.getElementById('totalFiles').textContent = '0'; document.getElementById('downloadedFiles').textContent = '0'; document.getElementById('pendingFiles').textContent = '0'; document.getElementById('downloadLog').innerHTML = ''; } updateProgress(progress, stats) { document.getElementById('progressBar').style.width = `${progress}%`; document.getElementById('progressText').textContent = `${Math.round(progress)}%`; if (stats) { document.getElementById('totalFiles').textContent = stats.total || 0; document.getElementById('downloadedFiles').textContent = stats.downloaded || 0; document.getElementById('pendingFiles').textContent = stats.pending || 0; } } addLogEntry(message, type = 'info') { const logEl = document.getElementById('downloadLog'); const entry = document.createElement('div'); entry.className = `log-entry ${type}`; entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; logEl.appendChild(entry); logEl.scrollTop = logEl.scrollHeight; } async reloadFolders() { try { this.showStatus('正在加载文件夹...', 'info'); document.getElementById('reloadBtn').disabled = true; const response = await fetch(`${this.baseUrl}/reload_folders`); const data = await response.json(); if (data.success) { this.displayFolders(data.folders); this.showStatus(`已加载 ${data.folders.length} 个未完成的任务`, 'success'); } else { throw new Error(data.message || '加载失败'); } } catch (error) { console.error('加载失败:', error); this.showStatus(`加载失败: ${error.message}`, 'error'); this.displayFolders([]); } finally { document.getElementById('reloadBtn').disabled = false; } } displayFolders(folders) { const foldersList = document.getElementById('foldersList'); const noFolders = document.getElementById('noFolders'); // 过滤掉进度为100%的文件夹 const incompleteFolders = folders.filter(folder => folder.progress < 100); if (incompleteFolders.length === 0) { foldersList.innerHTML = ''; noFolders.style.display = 'block'; return; } noFolders.style.display = 'none'; foldersList.innerHTML = incompleteFolders.map(folder => `