修复取消下载响应慢的问题
This commit is contained in:
@@ -151,7 +151,10 @@ const getStatusText = (status: string) => {
|
|||||||
'failed': '失败',
|
'failed': '失败',
|
||||||
'cancelled': '已取消',
|
'cancelled': '已取消',
|
||||||
'partial': '部分完成',
|
'partial': '部分完成',
|
||||||
'paused': '已暂停'
|
'paused': '已暂停',
|
||||||
|
'pausing': '暂停中',
|
||||||
|
'resuming': '恢复中',
|
||||||
|
'cancelling': '取消中'
|
||||||
};
|
};
|
||||||
return statusMap[status] || status;
|
return statusMap[status] || status;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,15 +3,17 @@
|
|||||||
<div class="progress-header">
|
<div class="progress-header">
|
||||||
<h4 class="progress-title">{{ getTaskTitle(task) }}</h4>
|
<h4 class="progress-title">{{ getTaskTitle(task) }}</h4>
|
||||||
<div class="progress-actions">
|
<div class="progress-actions">
|
||||||
<button v-if="task.status === 'downloading'" @click="pauseTask" class="btn btn-sm btn-secondary"
|
<button v-if="task.status === 'downloading' || task.status === 'pausing'" @click="pauseTask" class="btn btn-sm btn-secondary"
|
||||||
:disabled="loading">
|
:disabled="loading || task.status === 'pausing'">
|
||||||
暂停
|
{{ task.status === 'pausing' ? '暂停中...' : '暂停' }}
|
||||||
</button>
|
</button>
|
||||||
<button v-if="task.status === 'paused'" @click="resumeTask" class="btn btn-sm btn-primary" :disabled="loading">
|
<button v-if="task.status === 'paused' || task.status === 'resuming'" @click="resumeTask" class="btn btn-sm btn-primary"
|
||||||
恢复
|
:disabled="loading || task.status === 'resuming'">
|
||||||
|
{{ task.status === 'resuming' ? '恢复中...' : '恢复' }}
|
||||||
</button>
|
</button>
|
||||||
<button @click="cancelTask" class="btn btn-sm btn-danger" :disabled="loading">
|
<button @click="cancelTask" class="btn btn-sm btn-danger"
|
||||||
取消
|
:disabled="loading || task.status === 'cancelling'">
|
||||||
|
{{ task.status === 'cancelling' ? '取消中...' : '取消' }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,7 +76,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import downloadService from '@/services/download';
|
import { useDownloadStore } from '@/stores/download';
|
||||||
import type { DownloadTask } from '@/types';
|
import type { DownloadTask } from '@/types';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -83,6 +85,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
const downloadStore = useDownloadStore();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
update: [task: DownloadTask];
|
update: [task: DownloadTask];
|
||||||
@@ -130,7 +133,10 @@ const getStatusText = (status: string) => {
|
|||||||
failed: '失败',
|
failed: '失败',
|
||||||
partial: '部分完成',
|
partial: '部分完成',
|
||||||
cancelled: '已取消',
|
cancelled: '已取消',
|
||||||
paused: '已暂停'
|
paused: '已暂停',
|
||||||
|
pausing: '暂停中',
|
||||||
|
resuming: '恢复中',
|
||||||
|
cancelling: '取消中'
|
||||||
};
|
};
|
||||||
return statusMap[status] || status;
|
return statusMap[status] || status;
|
||||||
};
|
};
|
||||||
@@ -144,34 +150,37 @@ const formatTime = (timeString: string) => {
|
|||||||
|
|
||||||
const pauseTask = async () => {
|
const pauseTask = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await downloadService.pauseTask(props.task.id);
|
await downloadStore.pauseTask(props.task.id);
|
||||||
if (response.success) {
|
|
||||||
emit('update', { ...props.task, status: 'paused' });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('暂停任务失败:', error);
|
console.error('暂停任务失败:', error);
|
||||||
|
// 显示用户友好的错误提示
|
||||||
|
if (error instanceof Error) {
|
||||||
|
alert(`暂停失败: ${error.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const resumeTask = async () => {
|
const resumeTask = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await downloadService.resumeTask(props.task.id);
|
await downloadStore.resumeTask(props.task.id);
|
||||||
if (response.success) {
|
|
||||||
emit('update', { ...props.task, status: 'downloading' });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('恢复任务失败:', error);
|
console.error('恢复任务失败:', error);
|
||||||
|
// 显示用户友好的错误提示
|
||||||
|
if (error instanceof Error) {
|
||||||
|
alert(`恢复失败: ${error.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelTask = async () => {
|
const cancelTask = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await downloadService.cancelTask(props.task.id);
|
await downloadStore.cancelTask(props.task.id);
|
||||||
if (response.success) {
|
|
||||||
emit('remove', props.task.id);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('取消任务失败:', error);
|
console.error('取消任务失败:', error);
|
||||||
|
// 显示用户友好的错误提示
|
||||||
|
if (error instanceof Error) {
|
||||||
|
alert(`取消失败: ${error.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+107
-14
@@ -156,7 +156,22 @@ export const useDownloadStore = defineStore('download', () => {
|
|||||||
// 更新任务状态
|
// 更新任务状态
|
||||||
const index = tasks.value.findIndex(t => t.id === taskId);
|
const index = tasks.value.findIndex(t => t.id === taskId);
|
||||||
if (index !== -1) {
|
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 {
|
} else {
|
||||||
// 如果是新任务,添加到列表
|
// 如果是新任务,添加到列表
|
||||||
tasks.value.push(task);
|
tasks.value.push(task);
|
||||||
@@ -285,18 +300,42 @@ export const useDownloadStore = defineStore('download', () => {
|
|||||||
// 取消任务
|
// 取消任务
|
||||||
const cancelTask = async (taskId: string) => {
|
const cancelTask = async (taskId: string) => {
|
||||||
try {
|
try {
|
||||||
|
// 立即停止SSE连接
|
||||||
|
stopTaskStreaming(taskId);
|
||||||
|
|
||||||
|
// 立即更新本地状态为取消中
|
||||||
|
updateTask(taskId, { status: 'cancelling' as any });
|
||||||
|
|
||||||
const response = await downloadService.cancelTask(taskId);
|
const response = await downloadService.cancelTask(taskId);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
// 立即停止SSE连接
|
// 立即从任务列表中移除
|
||||||
stopTaskStreaming(taskId);
|
removeTask(taskId);
|
||||||
await fetchTasks();
|
// 异步刷新任务列表以确保同步
|
||||||
|
setTimeout(() => fetchTasks(), 500);
|
||||||
} else {
|
} else {
|
||||||
|
// 如果取消失败,恢复原状态
|
||||||
|
await fetchTasks();
|
||||||
throw new Error(response.error || '取消任务失败');
|
throw new Error(response.error || '取消任务失败');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} 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);
|
console.error('取消任务失败:', err);
|
||||||
throw err;
|
|
||||||
|
// 恢复任务状态
|
||||||
|
await fetchTasks();
|
||||||
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -305,6 +344,10 @@ export const useDownloadStore = defineStore('download', () => {
|
|||||||
try {
|
try {
|
||||||
// 获取任务信息以确定类型
|
// 获取任务信息以确定类型
|
||||||
const task = getTask(taskId);
|
const task = getTask(taskId);
|
||||||
|
|
||||||
|
// 立即更新本地状态为恢复中
|
||||||
|
updateTask(taskId, { status: 'resuming' as any });
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
// 判断是否为批量下载任务(batch、artist、art类型都是批量下载)
|
// 判断是否为批量下载任务(batch、artist、art类型都是批量下载)
|
||||||
@@ -317,16 +360,38 @@ export const useDownloadStore = defineStore('download', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
await fetchTasks();
|
// 立即更新状态为下载中
|
||||||
// 重新管理SSE连接
|
updateTask(taskId, { status: 'downloading' });
|
||||||
manageSSEConnections();
|
// 立即建立SSE连接
|
||||||
|
startTaskStreaming(taskId);
|
||||||
|
// 异步刷新任务列表以确保同步
|
||||||
|
setTimeout(() => fetchTasks(), 500);
|
||||||
} else {
|
} else {
|
||||||
|
// 如果恢复失败,恢复原状态
|
||||||
|
await fetchTasks();
|
||||||
throw new Error(response.error || '恢复任务失败');
|
throw new Error(response.error || '恢复任务失败');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} 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);
|
console.error('恢复任务失败:', err);
|
||||||
throw err;
|
|
||||||
|
// 恢复任务状态
|
||||||
|
await fetchTasks();
|
||||||
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -335,6 +400,10 @@ export const useDownloadStore = defineStore('download', () => {
|
|||||||
try {
|
try {
|
||||||
// 获取任务信息以确定类型
|
// 获取任务信息以确定类型
|
||||||
const task = getTask(taskId);
|
const task = getTask(taskId);
|
||||||
|
|
||||||
|
// 立即更新本地状态为暂停中
|
||||||
|
updateTask(taskId, { status: 'pausing' as any });
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
// 判断是否为批量下载任务(batch、artist、art类型都是批量下载)
|
// 判断是否为批量下载任务(batch、artist、art类型都是批量下载)
|
||||||
@@ -347,14 +416,38 @@ export const useDownloadStore = defineStore('download', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
await fetchTasks();
|
// 立即更新状态为已暂停
|
||||||
|
updateTask(taskId, { status: 'paused' });
|
||||||
|
// 停止SSE连接
|
||||||
|
stopTaskStreaming(taskId);
|
||||||
|
// 异步刷新任务列表以确保同步
|
||||||
|
setTimeout(() => fetchTasks(), 500);
|
||||||
} else {
|
} else {
|
||||||
|
// 如果暂停失败,恢复原状态
|
||||||
|
await fetchTasks();
|
||||||
throw new Error(response.error || '暂停任务失败');
|
throw new Error(response.error || '暂停任务失败');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} 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);
|
console.error('暂停任务失败:', err);
|
||||||
throw err;
|
|
||||||
|
// 恢复任务状态
|
||||||
|
await fetchTasks();
|
||||||
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export interface LoginStatus {
|
|||||||
export interface DownloadTask {
|
export interface DownloadTask {
|
||||||
id: string;
|
id: string;
|
||||||
type: 'artwork' | 'batch' | 'artist' | 'art';
|
type: 'artwork' | 'batch' | 'artist' | 'art';
|
||||||
status: 'downloading' | 'completed' | 'failed' | 'partial' | 'cancelled' | 'paused';
|
status: 'downloading' | 'completed' | 'failed' | 'partial' | 'cancelled' | 'paused' | 'pausing' | 'resuming' | 'cancelling';
|
||||||
progress: number;
|
progress: number;
|
||||||
total_files: number;
|
total_files: number;
|
||||||
completed_files: number;
|
completed_files: number;
|
||||||
|
|||||||
@@ -62,17 +62,21 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="task-actions">
|
<div class="task-actions">
|
||||||
<button v-if="task.status === 'downloading'" @click="pauseTask(task.id)" class="btn btn-warning btn-sm">
|
<button v-if="task.status === 'downloading' || task.status === 'pausing'" @click="pauseTask(task.id)"
|
||||||
暂停
|
class="btn btn-warning btn-sm" :disabled="task.status === 'pausing'">
|
||||||
|
{{ task.status === 'pausing' ? '暂停中...' : '暂停' }}
|
||||||
</button>
|
</button>
|
||||||
<button v-if="task.status === 'downloading'" @click="cancelTask(task.id)" class="btn btn-danger btn-sm">
|
<button v-if="task.status === 'downloading' || task.status === 'cancelling'" @click="cancelTask(task.id)"
|
||||||
取消
|
class="btn btn-danger btn-sm" :disabled="task.status === 'cancelling'">
|
||||||
|
{{ task.status === 'cancelling' ? '取消中...' : '取消' }}
|
||||||
</button>
|
</button>
|
||||||
<button v-if="task.status === 'paused'" @click="resumeTask(task.id)" class="btn btn-primary btn-sm">
|
<button v-if="task.status === 'paused' || task.status === 'resuming'" @click="resumeTask(task.id)"
|
||||||
恢复
|
class="btn btn-primary btn-sm" :disabled="task.status === 'resuming'">
|
||||||
|
{{ task.status === 'resuming' ? '恢复中...' : '恢复' }}
|
||||||
</button>
|
</button>
|
||||||
<button v-if="task.status === 'paused'" @click="cancelTask(task.id)" class="btn btn-danger btn-sm">
|
<button v-if="task.status === 'paused' || task.status === 'cancelling'" @click="cancelTask(task.id)"
|
||||||
删除
|
class="btn btn-danger btn-sm" :disabled="task.status === 'cancelling'">
|
||||||
|
{{ task.status === 'cancelling' ? '删除中...' : '删除' }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -242,7 +246,10 @@ const getStatusText = (status: string) => {
|
|||||||
'failed': '失败',
|
'failed': '失败',
|
||||||
'cancelled': '已取消',
|
'cancelled': '已取消',
|
||||||
'partial': '部分完成',
|
'partial': '部分完成',
|
||||||
'paused': '已暂停'
|
'paused': '已暂停',
|
||||||
|
'pausing': '暂停中',
|
||||||
|
'resuming': '恢复中',
|
||||||
|
'cancelling': '取消中'
|
||||||
};
|
};
|
||||||
return statusMap[status] || status;
|
return statusMap[status] || status;
|
||||||
};
|
};
|
||||||
@@ -360,6 +367,10 @@ const cancelTask = async (taskId: string) => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err instanceof Error ? err.message : '取消任务失败';
|
error.value = err instanceof Error ? err.message : '取消任务失败';
|
||||||
console.error('取消任务失败:', err);
|
console.error('取消任务失败:', err);
|
||||||
|
// 显示用户友好的错误提示
|
||||||
|
if (err instanceof Error) {
|
||||||
|
alert(`取消失败: ${err.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -370,6 +381,10 @@ const resumeTask = async (taskId: string) => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err instanceof Error ? err.message : '恢复任务失败';
|
error.value = err instanceof Error ? err.message : '恢复任务失败';
|
||||||
console.error('恢复任务失败:', err);
|
console.error('恢复任务失败:', err);
|
||||||
|
// 显示用户友好的错误提示
|
||||||
|
if (err instanceof Error) {
|
||||||
|
alert(`恢复失败: ${err.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -380,6 +395,10 @@ const pauseTask = async (taskId: string) => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
error.value = err instanceof Error ? err.message : '暂停任务失败';
|
error.value = err instanceof Error ? err.message : '暂停任务失败';
|
||||||
console.error('暂停任务失败:', err);
|
console.error('暂停任务失败:', err);
|
||||||
|
// 显示用户友好的错误提示
|
||||||
|
if (err instanceof Error) {
|
||||||
|
alert(`暂停失败: ${err.message}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user