diff --git a/src/public/search.html b/src/public/search.html index 18ba8ed..87a1557 100644 --- a/src/public/search.html +++ b/src/public/search.html @@ -986,7 +986,10 @@ `; displayFilteredTags(tags); + + // 确保显示tag列表并滚动到顶部 elements.tagList.classList.add('show'); + elements.tagList.scrollIntoView({ behavior: 'smooth', block: 'start' }); } // 显示过滤后的标签 diff --git a/src/public/skopeo.html b/src/public/skopeo.html index d4ba38d..dce9385 100644 --- a/src/public/skopeo.html +++ b/src/public/skopeo.html @@ -677,34 +677,26 @@ type="text" class="input" id="architectureInput" - placeholder="输入架构,例如:linux/amd64" - value="linux/amd64" + placeholder="输入架构,例如:amd64" + value="amd64" >
- - - - + + + +
-
- -
- 📦 系统自动使用 Docker Archive (.tar) 格式 -
-
+
- - -
@@ -770,16 +762,14 @@ // 全局变量 let downloadTasks = []; let isDownloading = false; - let currentTaskIndex = 0; - let downloadInterval = null; + let currentTaskId = null; // DOM 元素 const elements = { imageListInput: document.getElementById('imageListInput'), architectureInput: document.getElementById('architectureInput'), - startDownload: document.getElementById('startDownload'), - pauseDownload: document.getElementById('pauseDownload'), - stopDownload: document.getElementById('stopDownload'), + downloadButton: document.getElementById('downloadButton'), + downloadFileButton: document.getElementById('downloadFileButton'), progressContainer: document.getElementById('progressContainer'), progressTitle: document.getElementById('progressTitle'), progressStats: document.getElementById('progressStats'), @@ -814,7 +804,7 @@ }); // 默认选中第一个架构 - document.querySelector('.arch-button[data-arch="linux/amd64"]').classList.add('selected'); + document.querySelector('.arch-button[data-arch="amd64"]').classList.add('selected'); // 解析镜像列表 function parseImageList(input) { @@ -918,51 +908,14 @@ return; } - // 初始化任务 - downloadTasks = imageList.map((image, index) => ({ - id: index, - image: image, - architecture: architecture, - status: 'pending' - })); - - // 清空任务列表并重新创建 - elements.taskList.innerHTML = ''; - downloadTasks.forEach((task, index) => { - const taskItem = createTaskItem(task.image, index); - elements.taskList.appendChild(taskItem); - }); + isDownloading = true; + elements.downloadButton.disabled = true; + elements.downloadButton.textContent = '下载中...'; + elements.downloadFileButton.style.display = 'none'; // 显示进度容器 elements.progressContainer.classList.add('show'); - - // 更新按钮状态 - elements.startDownload.disabled = true; - elements.pauseDownload.disabled = false; - elements.stopDownload.disabled = false; - - isDownloading = true; - currentTaskIndex = 0; - - elements.progressTitle.textContent = '开始下载...'; - showToast('开始批量下载镜像', 'success'); - - // 开始处理任务 - processNextTask(); - } - - // 处理下一个任务 - async function processNextTask() { - if (!isDownloading || currentTaskIndex >= downloadTasks.length) { - return; - } - - const task = downloadTasks[currentTaskIndex]; - - // 更新任务状态为运行中 - task.status = 'running'; - updateTaskStatus(currentTaskIndex, 'running', '正在下载...'); - updateProgress(); + elements.progressTitle.textContent = '正在下载镜像...'; try { // 调用后端API开始下载 @@ -972,119 +925,84 @@ 'Content-Type': 'application/json' }, body: JSON.stringify({ - images: [task.image], - platform: task.architecture + images: imageList, + platform: architecture }) }); const result = await response.json(); if (result.taskId) { - // 下载任务已创建,等待完成 - task.taskId = result.taskId; - await waitForTaskCompletion(task); + currentTaskId = result.taskId; + showToast('下载任务已创建', 'success'); + await waitForDownloadCompletion(); } else { - task.status = 'failed'; - updateTaskStatus(currentTaskIndex, 'failed', result.error || '下载失败'); + throw new Error(result.error || '创建下载任务失败'); } } catch (error) { console.error('下载错误:', error); - task.status = 'failed'; - updateTaskStatus(currentTaskIndex, 'failed', '网络错误'); - } - - updateProgress(); - currentTaskIndex++; - - // 继续下一个任务 - if (isDownloading && currentTaskIndex < downloadTasks.length) { - setTimeout(() => processNextTask(), 1000); // 延迟1秒继续下一个 + showToast('下载失败: ' + error.message, 'error'); + resetDownloadState(); } } - // 等待任务完成 - async function waitForTaskCompletion(task) { - return new Promise((resolve) => { - const checkStatus = async () => { - try { - const response = await fetch(`/api/task/${task.taskId}`); - const data = await response.json(); + // 等待下载完成 + async function waitForDownloadCompletion() { + const checkStatus = async () => { + try { + const response = await fetch(`/api/task/${currentTaskId}`); + const data = await response.json(); + + if (data.status === 'completed') { + elements.progressTitle.textContent = '下载完成'; + elements.progressBar.style.width = '100%'; + showToast('镜像下载完成', 'success'); - if (data.status === 'completed') { - task.status = 'completed'; - updateTaskStatus(currentTaskIndex, 'completed', '下载完成'); - resolve(); - } else if (data.status === 'failed') { - task.status = 'failed'; - updateTaskStatus(currentTaskIndex, 'failed', '下载失败'); - resolve(); - } else { - // 继续检查 - setTimeout(checkStatus, 2000); + // 显示下载压缩包按钮 + elements.downloadFileButton.style.display = 'inline-flex'; + elements.downloadFileButton.onclick = () => downloadFile(); + + resetDownloadState(); + } else if (data.status === 'failed') { + elements.progressTitle.textContent = '下载失败'; + showToast('下载失败', 'error'); + resetDownloadState(); + } else { + // 更新进度 + if (data.images && data.images.length > 0) { + const totalProgress = data.images.reduce((sum, img) => sum + (img.progress || 0), 0) / data.images.length; + elements.progressBar.style.width = `${totalProgress}%`; } - } catch (error) { - task.status = 'failed'; - updateTaskStatus(currentTaskIndex, 'failed', '状态查询失败'); - resolve(); + + // 继续检查 + setTimeout(checkStatus, 2000); } - }; - - checkStatus(); - }); - } - - // 暂停下载 - function pauseDownload() { - isDownloading = false; - elements.startDownload.disabled = false; - elements.pauseDownload.disabled = true; - elements.progressTitle.textContent = '下载已暂停'; - showToast('下载已暂停', 'warning'); - } - - // 停止下载 - function stopDownload() { - isDownloading = false; - currentTaskIndex = 0; + } catch (error) { + elements.progressTitle.textContent = '状态查询失败'; + showToast('状态查询失败', 'error'); + resetDownloadState(); + } + }; - elements.startDownload.disabled = false; - elements.pauseDownload.disabled = true; - elements.stopDownload.disabled = true; - - if (downloadTasks.length > 0) { - elements.progressTitle.textContent = '下载已停止'; - } + checkStatus(); } - // 恢复下载 - function resumeDownload() { - if (downloadTasks.length === 0) { - showToast('没有可恢复的任务', 'error'); - return; + // 重置下载状态 + function resetDownloadState() { + isDownloading = false; + elements.downloadButton.disabled = false; + elements.downloadButton.textContent = '📥 下载'; + } + + // 下载文件 + function downloadFile() { + if (currentTaskId) { + window.open(`/api/download/${currentTaskId}/file`, '_blank'); } - - isDownloading = true; - elements.startDownload.disabled = true; - elements.pauseDownload.disabled = false; - elements.stopDownload.disabled = false; - - elements.progressTitle.textContent = '恢复下载...'; - showToast('恢复下载', 'success'); - - processNextTask(); } // 事件监听 - elements.startDownload.addEventListener('click', () => { - if (downloadTasks.length > 0 && currentTaskIndex < downloadTasks.length) { - resumeDownload(); - } else { - startDownload(); - } - }); - - elements.pauseDownload.addEventListener('click', pauseDownload); - elements.stopDownload.addEventListener('click', stopDownload); + elements.downloadButton.addEventListener('click', startDownload); // 页面初始化 document.addEventListener('DOMContentLoaded', () => {