From d915be42dd7813b7ff9d1b011bc76ab705bb60fe Mon Sep 17 00:00:00 2001
From: kjqwer <2990346238@qq.com>
Date: Mon, 6 Oct 2025 07:49:19 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=96=E6=B6=88=E4=B8=8B?=
=?UTF-8?q?=E8=BD=BD=E5=93=8D=E5=BA=94=E6=85=A2=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../common/DownloadProgressWidget.vue | 5 +-
.../components/download/DownloadProgress.vue | 51 +++++---
ui/src/stores/download.ts | 121 ++++++++++++++++--
ui/src/types/index.ts | 2 +-
ui/src/views/DownloadsView.vue | 37 ++++--
5 files changed, 170 insertions(+), 46 deletions(-)
diff --git a/ui/src/components/common/DownloadProgressWidget.vue b/ui/src/components/common/DownloadProgressWidget.vue
index 58d9f2d..1bda39e 100644
--- a/ui/src/components/common/DownloadProgressWidget.vue
+++ b/ui/src/components/common/DownloadProgressWidget.vue
@@ -151,7 +151,10 @@ const getStatusText = (status: string) => {
'failed': '失败',
'cancelled': '已取消',
'partial': '部分完成',
- 'paused': '已暂停'
+ 'paused': '已暂停',
+ 'pausing': '暂停中',
+ 'resuming': '恢复中',
+ 'cancelling': '取消中'
};
return statusMap[status] || status;
};
diff --git a/ui/src/components/download/DownloadProgress.vue b/ui/src/components/download/DownloadProgress.vue
index 386d47c..75fe268 100644
--- a/ui/src/components/download/DownloadProgress.vue
+++ b/ui/src/components/download/DownloadProgress.vue
@@ -3,15 +3,17 @@
@@ -74,7 +76,7 @@
diff --git a/ui/src/stores/download.ts b/ui/src/stores/download.ts
index 3ea11a5..eac1e94 100644
--- a/ui/src/stores/download.ts
+++ b/ui/src/stores/download.ts
@@ -156,7 +156,22 @@ export const useDownloadStore = defineStore('download', () => {
// 更新任务状态
const index = tasks.value.findIndex(t => t.id === taskId);
if (index !== -1) {
- tasks.value[index] = task;
+ // 保留临时状态(如pausing, resuming, cancelling)
+ const currentTask = tasks.value[index];
+ const isTemporaryStatus = ['pausing', 'resuming', 'cancelling'].includes(currentTask.status);
+
+ if (!isTemporaryStatus) {
+ tasks.value[index] = task;
+ } else {
+ // 只更新进度相关字段,保留临时状态
+ tasks.value[index] = {
+ ...currentTask,
+ progress: task.progress,
+ completed_files: task.completed_files,
+ failed_files: task.failed_files,
+ recent_completed: task.recent_completed
+ };
+ }
} else {
// 如果是新任务,添加到列表
tasks.value.push(task);
@@ -285,18 +300,42 @@ export const useDownloadStore = defineStore('download', () => {
// 取消任务
const cancelTask = async (taskId: string) => {
try {
+ // 立即停止SSE连接
+ stopTaskStreaming(taskId);
+
+ // 立即更新本地状态为取消中
+ updateTask(taskId, { status: 'cancelling' as any });
+
const response = await downloadService.cancelTask(taskId);
if (response.success) {
- // 立即停止SSE连接
- stopTaskStreaming(taskId);
- await fetchTasks();
+ // 立即从任务列表中移除
+ removeTask(taskId);
+ // 异步刷新任务列表以确保同步
+ setTimeout(() => fetchTasks(), 500);
} else {
+ // 如果取消失败,恢复原状态
+ await fetchTasks();
throw new Error(response.error || '取消任务失败');
}
} catch (err) {
- error.value = err instanceof Error ? err.message : '取消任务失败';
+ // 如果是网络错误或超时,提供更友好的错误信息
+ let errorMessage = '取消任务失败';
+ if (err instanceof Error) {
+ if (err.message.includes('timeout') || err.message.includes('network')) {
+ errorMessage = '网络连接超时,请检查网络连接后重试';
+ } else if (err.message.includes('404')) {
+ errorMessage = '任务不存在或已被删除';
+ } else {
+ errorMessage = err.message;
+ }
+ }
+
+ error.value = errorMessage;
console.error('取消任务失败:', err);
- throw err;
+
+ // 恢复任务状态
+ await fetchTasks();
+ throw new Error(errorMessage);
}
};
@@ -305,6 +344,10 @@ export const useDownloadStore = defineStore('download', () => {
try {
// 获取任务信息以确定类型
const task = getTask(taskId);
+
+ // 立即更新本地状态为恢复中
+ updateTask(taskId, { status: 'resuming' as any });
+
let response;
// 判断是否为批量下载任务(batch、artist、art类型都是批量下载)
@@ -317,16 +360,38 @@ export const useDownloadStore = defineStore('download', () => {
}
if (response.success) {
- await fetchTasks();
- // 重新管理SSE连接
- manageSSEConnections();
+ // 立即更新状态为下载中
+ updateTask(taskId, { status: 'downloading' });
+ // 立即建立SSE连接
+ startTaskStreaming(taskId);
+ // 异步刷新任务列表以确保同步
+ setTimeout(() => fetchTasks(), 500);
} else {
+ // 如果恢复失败,恢复原状态
+ await fetchTasks();
throw new Error(response.error || '恢复任务失败');
}
} catch (err) {
- error.value = err instanceof Error ? err.message : '恢复任务失败';
+ // 提供更友好的错误信息
+ let errorMessage = '恢复任务失败';
+ if (err instanceof Error) {
+ if (err.message.includes('timeout') || err.message.includes('network')) {
+ errorMessage = '网络连接超时,请检查网络连接后重试';
+ } else if (err.message.includes('404')) {
+ errorMessage = '任务不存在或已被删除';
+ } else if (err.message.includes('already running')) {
+ errorMessage = '任务已在运行中';
+ } else {
+ errorMessage = err.message;
+ }
+ }
+
+ error.value = errorMessage;
console.error('恢复任务失败:', err);
- throw err;
+
+ // 恢复任务状态
+ await fetchTasks();
+ throw new Error(errorMessage);
}
};
@@ -335,6 +400,10 @@ export const useDownloadStore = defineStore('download', () => {
try {
// 获取任务信息以确定类型
const task = getTask(taskId);
+
+ // 立即更新本地状态为暂停中
+ updateTask(taskId, { status: 'pausing' as any });
+
let response;
// 判断是否为批量下载任务(batch、artist、art类型都是批量下载)
@@ -347,14 +416,38 @@ export const useDownloadStore = defineStore('download', () => {
}
if (response.success) {
- await fetchTasks();
+ // 立即更新状态为已暂停
+ updateTask(taskId, { status: 'paused' });
+ // 停止SSE连接
+ stopTaskStreaming(taskId);
+ // 异步刷新任务列表以确保同步
+ setTimeout(() => fetchTasks(), 500);
} else {
+ // 如果暂停失败,恢复原状态
+ await fetchTasks();
throw new Error(response.error || '暂停任务失败');
}
} catch (err) {
- error.value = err instanceof Error ? err.message : '暂停任务失败';
+ // 提供更友好的错误信息
+ let errorMessage = '暂停任务失败';
+ if (err instanceof Error) {
+ if (err.message.includes('timeout') || err.message.includes('network')) {
+ errorMessage = '网络连接超时,请检查网络连接后重试';
+ } else if (err.message.includes('404')) {
+ errorMessage = '任务不存在或已被删除';
+ } else if (err.message.includes('already paused')) {
+ errorMessage = '任务已暂停';
+ } else {
+ errorMessage = err.message;
+ }
+ }
+
+ error.value = errorMessage;
console.error('暂停任务失败:', err);
- throw err;
+
+ // 恢复任务状态
+ await fetchTasks();
+ throw new Error(errorMessage);
}
};
diff --git a/ui/src/types/index.ts b/ui/src/types/index.ts
index 64138a2..fd05278 100644
--- a/ui/src/types/index.ts
+++ b/ui/src/types/index.ts
@@ -99,7 +99,7 @@ export interface LoginStatus {
export interface DownloadTask {
id: string;
type: 'artwork' | 'batch' | 'artist' | 'art';
- status: 'downloading' | 'completed' | 'failed' | 'partial' | 'cancelled' | 'paused';
+ status: 'downloading' | 'completed' | 'failed' | 'partial' | 'cancelled' | 'paused' | 'pausing' | 'resuming' | 'cancelling';
progress: number;
total_files: number;
completed_files: number;
diff --git a/ui/src/views/DownloadsView.vue b/ui/src/views/DownloadsView.vue
index 2eb5ee8..04f3697 100644
--- a/ui/src/views/DownloadsView.vue
+++ b/ui/src/views/DownloadsView.vue
@@ -62,17 +62,21 @@
-
@@ -242,7 +246,10 @@ const getStatusText = (status: string) => {
'failed': '失败',
'cancelled': '已取消',
'partial': '部分完成',
- 'paused': '已暂停'
+ 'paused': '已暂停',
+ 'pausing': '暂停中',
+ 'resuming': '恢复中',
+ 'cancelling': '取消中'
};
return statusMap[status] || status;
};
@@ -360,6 +367,10 @@ const cancelTask = async (taskId: string) => {
} catch (err) {
error.value = err instanceof Error ? err.message : '取消任务失败';
console.error('取消任务失败:', err);
+ // 显示用户友好的错误提示
+ if (err instanceof Error) {
+ alert(`取消失败: ${err.message}`);
+ }
}
};
@@ -370,6 +381,10 @@ const resumeTask = async (taskId: string) => {
} catch (err) {
error.value = err instanceof Error ? err.message : '恢复任务失败';
console.error('恢复任务失败:', err);
+ // 显示用户友好的错误提示
+ if (err instanceof Error) {
+ alert(`恢复失败: ${err.message}`);
+ }
}
};
@@ -380,6 +395,10 @@ const pauseTask = async (taskId: string) => {
} catch (err) {
error.value = err instanceof Error ? err.message : '暂停任务失败';
console.error('暂停任务失败:', err);
+ // 显示用户友好的错误提示
+ if (err instanceof Error) {
+ alert(`暂停失败: ${err.message}`);
+ }
}
};