修复前端一些BUG
This commit is contained in:
@@ -986,7 +986,10 @@
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
displayFilteredTags(tags);
|
displayFilteredTags(tags);
|
||||||
|
|
||||||
|
// 确保显示tag列表并滚动到顶部
|
||||||
elements.tagList.classList.add('show');
|
elements.tagList.classList.add('show');
|
||||||
|
elements.tagList.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示过滤后的标签
|
// 显示过滤后的标签
|
||||||
|
|||||||
@@ -677,34 +677,26 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="input"
|
class="input"
|
||||||
id="architectureInput"
|
id="architectureInput"
|
||||||
placeholder="输入架构,例如:linux/amd64"
|
placeholder="输入架构,例如:amd64"
|
||||||
value="linux/amd64"
|
value="amd64"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="arch-buttons">
|
<div class="arch-buttons">
|
||||||
<button class="arch-button" data-arch="linux/amd64">linux/amd64</button>
|
<button class="arch-button" data-arch="amd64">amd64</button>
|
||||||
<button class="arch-button" data-arch="linux/arm64">linux/arm64</button>
|
<button class="arch-button" data-arch="arm64">arm64</button>
|
||||||
<button class="arch-button" data-arch="linux/arm/v7">linux/arm/v7</button>
|
<button class="arch-button" data-arch="arm">arm</button>
|
||||||
<button class="arch-button" data-arch="linux/386">linux/386</button>
|
<button class="arch-button" data-arch="386">386</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">输出格式</label>
|
|
||||||
<div class="input-info">
|
|
||||||
📦 系统自动使用 Docker Archive (.tar) 格式
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
|
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
|
||||||
<button class="button button-primary" id="startDownload">
|
<button class="button button-primary" id="downloadButton">
|
||||||
🚀 开始下载
|
📥 下载
|
||||||
</button>
|
</button>
|
||||||
<button class="button button-warning" id="pauseDownload" disabled>
|
<button class="button button-success" id="downloadFileButton" style="display: none;">
|
||||||
⏸️ 暂停下载
|
📦 下载压缩包
|
||||||
</button>
|
|
||||||
<button class="button button-error" id="stopDownload" disabled>
|
|
||||||
⏹️ 停止下载
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -770,16 +762,14 @@
|
|||||||
// 全局变量
|
// 全局变量
|
||||||
let downloadTasks = [];
|
let downloadTasks = [];
|
||||||
let isDownloading = false;
|
let isDownloading = false;
|
||||||
let currentTaskIndex = 0;
|
let currentTaskId = null;
|
||||||
let downloadInterval = null;
|
|
||||||
|
|
||||||
// DOM 元素
|
// DOM 元素
|
||||||
const elements = {
|
const elements = {
|
||||||
imageListInput: document.getElementById('imageListInput'),
|
imageListInput: document.getElementById('imageListInput'),
|
||||||
architectureInput: document.getElementById('architectureInput'),
|
architectureInput: document.getElementById('architectureInput'),
|
||||||
startDownload: document.getElementById('startDownload'),
|
downloadButton: document.getElementById('downloadButton'),
|
||||||
pauseDownload: document.getElementById('pauseDownload'),
|
downloadFileButton: document.getElementById('downloadFileButton'),
|
||||||
stopDownload: document.getElementById('stopDownload'),
|
|
||||||
progressContainer: document.getElementById('progressContainer'),
|
progressContainer: document.getElementById('progressContainer'),
|
||||||
progressTitle: document.getElementById('progressTitle'),
|
progressTitle: document.getElementById('progressTitle'),
|
||||||
progressStats: document.getElementById('progressStats'),
|
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) {
|
function parseImageList(input) {
|
||||||
@@ -918,51 +908,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化任务
|
isDownloading = true;
|
||||||
downloadTasks = imageList.map((image, index) => ({
|
elements.downloadButton.disabled = true;
|
||||||
id: index,
|
elements.downloadButton.textContent = '下载中...';
|
||||||
image: image,
|
elements.downloadFileButton.style.display = 'none';
|
||||||
architecture: architecture,
|
|
||||||
status: 'pending'
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 清空任务列表并重新创建
|
|
||||||
elements.taskList.innerHTML = '';
|
|
||||||
downloadTasks.forEach((task, index) => {
|
|
||||||
const taskItem = createTaskItem(task.image, index);
|
|
||||||
elements.taskList.appendChild(taskItem);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 显示进度容器
|
// 显示进度容器
|
||||||
elements.progressContainer.classList.add('show');
|
elements.progressContainer.classList.add('show');
|
||||||
|
elements.progressTitle.textContent = '正在下载镜像...';
|
||||||
// 更新按钮状态
|
|
||||||
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();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 调用后端API开始下载
|
// 调用后端API开始下载
|
||||||
@@ -972,119 +925,84 @@
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
images: [task.image],
|
images: imageList,
|
||||||
platform: task.architecture
|
platform: architecture
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.taskId) {
|
if (result.taskId) {
|
||||||
// 下载任务已创建,等待完成
|
currentTaskId = result.taskId;
|
||||||
task.taskId = result.taskId;
|
showToast('下载任务已创建', 'success');
|
||||||
await waitForTaskCompletion(task);
|
await waitForDownloadCompletion();
|
||||||
} else {
|
} else {
|
||||||
task.status = 'failed';
|
throw new Error(result.error || '创建下载任务失败');
|
||||||
updateTaskStatus(currentTaskIndex, 'failed', result.error || '下载失败');
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('下载错误:', error);
|
console.error('下载错误:', error);
|
||||||
task.status = 'failed';
|
showToast('下载失败: ' + error.message, 'error');
|
||||||
updateTaskStatus(currentTaskIndex, 'failed', '网络错误');
|
resetDownloadState();
|
||||||
}
|
|
||||||
|
|
||||||
updateProgress();
|
|
||||||
currentTaskIndex++;
|
|
||||||
|
|
||||||
// 继续下一个任务
|
|
||||||
if (isDownloading && currentTaskIndex < downloadTasks.length) {
|
|
||||||
setTimeout(() => processNextTask(), 1000); // 延迟1秒继续下一个
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 等待任务完成
|
// 等待下载完成
|
||||||
async function waitForTaskCompletion(task) {
|
async function waitForDownloadCompletion() {
|
||||||
return new Promise((resolve) => {
|
const checkStatus = async () => {
|
||||||
const checkStatus = async () => {
|
try {
|
||||||
try {
|
const response = await fetch(`/api/task/${currentTaskId}`);
|
||||||
const response = await fetch(`/api/task/${task.taskId}`);
|
const data = await response.json();
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (data.status === 'completed') {
|
if (data.status === 'completed') {
|
||||||
task.status = 'completed';
|
elements.progressTitle.textContent = '下载完成';
|
||||||
updateTaskStatus(currentTaskIndex, 'completed', '下载完成');
|
elements.progressBar.style.width = '100%';
|
||||||
resolve();
|
showToast('镜像下载完成', 'success');
|
||||||
} else if (data.status === 'failed') {
|
|
||||||
task.status = 'failed';
|
// 显示下载压缩包按钮
|
||||||
updateTaskStatus(currentTaskIndex, 'failed', '下载失败');
|
elements.downloadFileButton.style.display = 'inline-flex';
|
||||||
resolve();
|
elements.downloadFileButton.onclick = () => downloadFile();
|
||||||
} else {
|
|
||||||
// 继续检查
|
resetDownloadState();
|
||||||
setTimeout(checkStatus, 2000);
|
} 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', '状态查询失败');
|
setTimeout(checkStatus, 2000);
|
||||||
resolve();
|
|
||||||
}
|
}
|
||||||
};
|
} catch (error) {
|
||||||
|
elements.progressTitle.textContent = '状态查询失败';
|
||||||
|
showToast('状态查询失败', 'error');
|
||||||
|
resetDownloadState();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
checkStatus();
|
checkStatus();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 暂停下载
|
// 重置下载状态
|
||||||
function pauseDownload() {
|
function resetDownloadState() {
|
||||||
isDownloading = false;
|
isDownloading = false;
|
||||||
elements.startDownload.disabled = false;
|
elements.downloadButton.disabled = false;
|
||||||
elements.pauseDownload.disabled = true;
|
elements.downloadButton.textContent = '📥 下载';
|
||||||
elements.progressTitle.textContent = '下载已暂停';
|
|
||||||
showToast('下载已暂停', 'warning');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 停止下载
|
// 下载文件
|
||||||
function stopDownload() {
|
function downloadFile() {
|
||||||
isDownloading = false;
|
if (currentTaskId) {
|
||||||
currentTaskIndex = 0;
|
window.open(`/api/download/${currentTaskId}/file`, '_blank');
|
||||||
|
|
||||||
elements.startDownload.disabled = false;
|
|
||||||
elements.pauseDownload.disabled = true;
|
|
||||||
elements.stopDownload.disabled = true;
|
|
||||||
|
|
||||||
if (downloadTasks.length > 0) {
|
|
||||||
elements.progressTitle.textContent = '下载已停止';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 恢复下载
|
|
||||||
function resumeDownload() {
|
|
||||||
if (downloadTasks.length === 0) {
|
|
||||||
showToast('没有可恢复的任务', 'error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isDownloading = true;
|
|
||||||
elements.startDownload.disabled = true;
|
|
||||||
elements.pauseDownload.disabled = false;
|
|
||||||
elements.stopDownload.disabled = false;
|
|
||||||
|
|
||||||
elements.progressTitle.textContent = '恢复下载...';
|
|
||||||
showToast('恢复下载', 'success');
|
|
||||||
|
|
||||||
processNextTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 事件监听
|
// 事件监听
|
||||||
elements.startDownload.addEventListener('click', () => {
|
elements.downloadButton.addEventListener('click', startDownload);
|
||||||
if (downloadTasks.length > 0 && currentTaskIndex < downloadTasks.length) {
|
|
||||||
resumeDownload();
|
|
||||||
} else {
|
|
||||||
startDownload();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
elements.pauseDownload.addEventListener('click', pauseDownload);
|
|
||||||
elements.stopDownload.addEventListener('click', stopDownload);
|
|
||||||
|
|
||||||
// 页面初始化
|
// 页面初始化
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user