下载模组更新,新增下载组件,下载监听改为全局,全量改为增量监听
This commit is contained in:
@@ -60,12 +60,30 @@
|
||||
<div class="artworks-section">
|
||||
<div class="section-header">
|
||||
<h2>作品列表</h2>
|
||||
<div class="artwork-filters">
|
||||
<select v-model="artworkType" @change="handleTypeChange" class="filter-select">
|
||||
<option value="art">插画</option>
|
||||
<option value="manga">漫画</option>
|
||||
<option value="novel">小说</option>
|
||||
</select>
|
||||
<div class="header-controls">
|
||||
<div class="artwork-filters">
|
||||
<select v-model="artworkType" @change="handleTypeChange" class="filter-select">
|
||||
<option value="art">插画</option>
|
||||
<option value="manga">漫画</option>
|
||||
<option value="novel">小说</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 顶部分页导航 -->
|
||||
<div v-if="totalPages > 1 && artworks.length > 0" class="simple-pagination">
|
||||
<button @click="goToPage(currentPage - 1)" class="simple-page-btn" :disabled="currentPage <= 1">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" class="simple-page-icon">
|
||||
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
|
||||
</svg>
|
||||
</button>
|
||||
<span class="simple-page-info">{{ currentPage }} / {{ totalPages }}</span>
|
||||
<button @click="goToPage(currentPage + 1)" class="simple-page-btn"
|
||||
:disabled="currentPage >= totalPages">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" class="simple-page-icon">
|
||||
<path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -704,6 +722,7 @@ onMounted(async () => {
|
||||
border-radius: 1rem;
|
||||
padding: 2rem;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
@@ -720,6 +739,12 @@ onMounted(async () => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.artwork-filters {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
@@ -734,6 +759,58 @@ onMounted(async () => {
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
/* 顶部分页导航样式 */
|
||||
.simple-pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: #f9fafb;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.simple-page-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 0.375rem;
|
||||
background: white;
|
||||
color: #374151;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.simple-page-btn:hover:not(:disabled) {
|
||||
background: #f3f4f6;
|
||||
border-color: #9ca3af;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.simple-page-btn:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.simple-page-icon {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.simple-page-info {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
min-width: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.artworks-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
@@ -901,6 +978,12 @@ onMounted(async () => {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
/* 移动端简洁分页导航样式调整 */
|
||||
.simple-pagination {
|
||||
justify-content: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.artist-profile {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
@@ -930,6 +1013,12 @@ onMounted(async () => {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.header-controls {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.artworks-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
+41
-115
@@ -25,7 +25,7 @@
|
||||
<ArtworkInfoPanel :artwork="artwork" :downloading="downloading" :is-downloaded="isDownloaded"
|
||||
:current-task="currentTask" :loading="loading" :show-navigation="showNavigation"
|
||||
:previous-artwork="previousArtwork" :next-artwork="nextArtwork" :selected-tags="selectedTags"
|
||||
@download="handleDownload" @bookmark="handleBookmark" @update-task="updateTask" @remove-task="removeTask"
|
||||
@download="handleDownload" @bookmark="handleBookmark"
|
||||
@go-back="goBackToArtist" @navigate-previous="navigateToPrevious" @navigate-next="navigateToNext"
|
||||
@tag-click="handleTagClick" />
|
||||
</div>
|
||||
@@ -38,6 +38,7 @@ import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useRepositoryStore } from '@/stores/repository';
|
||||
import { useDownloadStore } from '@/stores/download';
|
||||
import artworkService from '@/services/artwork';
|
||||
import artistService from '@/services/artist';
|
||||
import downloadService from '@/services/download';
|
||||
@@ -53,6 +54,7 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
const repositoryStore = useRepositoryStore();
|
||||
const downloadStore = useDownloadStore();
|
||||
|
||||
// 状态
|
||||
const artwork = ref<Artwork | null>(null);
|
||||
@@ -62,9 +64,11 @@ const currentPage = ref(0);
|
||||
const downloading = ref(false);
|
||||
const isDownloaded = ref(false);
|
||||
|
||||
// 下载任务状态
|
||||
const currentTask = ref<DownloadTask | null>(null);
|
||||
const sseConnection = ref<(() => void) | null>(null);
|
||||
// 下载任务状态 - 使用Pinia store
|
||||
const currentTask = computed(() => {
|
||||
if (!artwork.value) return null;
|
||||
return downloadStore.getArtworkTask(artwork.value.id);
|
||||
});
|
||||
|
||||
// 收藏错误状态
|
||||
const bookmarkError = ref<string | null>(null);
|
||||
@@ -105,10 +109,8 @@ const fetchArtworkDetail = async () => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
// 立即清理所有下载相关状态
|
||||
currentTask.value = null;
|
||||
// 清理下载状态
|
||||
downloading.value = false;
|
||||
stopTaskStreaming();
|
||||
|
||||
const response = await artworkService.getArtworkDetail(artworkId);
|
||||
|
||||
@@ -137,19 +139,19 @@ const checkDownloadStatus = async (artworkId: number, retryCount = 0) => {
|
||||
try {
|
||||
const response = await repositoryStore.checkArtworkDownloaded(artworkId);
|
||||
|
||||
console.log('下载状态检查响应:', response);
|
||||
// console.log('下载状态检查响应:', response);
|
||||
|
||||
// repository store的apiCall返回的是data.data,所以response直接是数据对象
|
||||
if (response && typeof response === 'object') {
|
||||
const newStatus = response.is_downloaded || false;
|
||||
|
||||
// 如果状态发生变化,记录日志
|
||||
if (isDownloaded.value !== newStatus) {
|
||||
console.log(`作品下载状态变化: ${isDownloaded.value} -> ${newStatus}`);
|
||||
}
|
||||
// if (isDownloaded.value !== newStatus) {
|
||||
// console.log(`作品下载状态变化: ${isDownloaded.value} -> ${newStatus}`);
|
||||
// }
|
||||
|
||||
isDownloaded.value = newStatus;
|
||||
console.log('作品下载状态:', isDownloaded.value);
|
||||
// console.log('作品下载状态:', isDownloaded.value);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('检查下载状态失败:', err);
|
||||
@@ -170,8 +172,7 @@ const handleDownload = async () => {
|
||||
if (!artwork.value) return;
|
||||
|
||||
try {
|
||||
// 清理之前的任务状态
|
||||
currentTask.value = null;
|
||||
// 清理下载状态
|
||||
downloading.value = true;
|
||||
|
||||
// 如果已经下载过,则强制重新下载(跳过现有文件检查)
|
||||
@@ -191,10 +192,10 @@ const handleDownload = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是新任务,立即创建任务状态并开始监听进度
|
||||
// 如果是新任务,立即添加到store
|
||||
if (response.data.task_id) {
|
||||
// 立即创建任务状态,让进度条立即显示
|
||||
currentTask.value = {
|
||||
const newTask: DownloadTask = {
|
||||
id: response.data.task_id,
|
||||
type: 'artwork',
|
||||
status: 'downloading',
|
||||
@@ -208,8 +209,8 @@ const handleDownload = async () => {
|
||||
start_time: new Date().toISOString()
|
||||
};
|
||||
|
||||
// 立即开始SSE监听任务进度
|
||||
startTaskStreaming(response.data.task_id);
|
||||
// 添加到store,store会自动管理SSE连接
|
||||
downloadStore.addTask(newTask);
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.error || '下载失败');
|
||||
@@ -222,93 +223,25 @@ const handleDownload = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 开始SSE监听任务进度
|
||||
const startTaskStreaming = (taskId: string) => {
|
||||
// 清除之前的连接
|
||||
if (sseConnection.value) {
|
||||
sseConnection.value();
|
||||
}
|
||||
|
||||
console.log('开始SSE监听任务进度:', taskId);
|
||||
|
||||
// 建立SSE连接
|
||||
sseConnection.value = downloadService.streamTaskProgress(
|
||||
taskId,
|
||||
(task) => {
|
||||
console.log('收到SSE进度更新:', {
|
||||
taskId,
|
||||
status: task.status,
|
||||
progress: task.progress,
|
||||
completed: task.completed_files,
|
||||
total: task.total_files
|
||||
});
|
||||
|
||||
// 立即更新任务状态,让进度条立即显示
|
||||
currentTask.value = task;
|
||||
|
||||
// 如果任务完成,清理连接并检查下载状态
|
||||
if (['completed', 'failed', 'cancelled', 'partial'].includes(task.status)) {
|
||||
console.log('任务完成,关闭SSE连接');
|
||||
stopTaskStreaming();
|
||||
|
||||
// 延迟检查下载状态,确保文件写入完成
|
||||
// 减少延迟时间,提高响应速度
|
||||
const delay = task.total_files > 1 ? 1500 : 1000; // 多文件延迟1.5秒,单文件延迟1秒
|
||||
|
||||
setTimeout(async () => {
|
||||
// 检查当前页面是否还是同一个作品,避免页面切换后的状态更新
|
||||
if (artwork.value && artwork.value.id === task.artwork_id) {
|
||||
console.log(`延迟 ${delay}ms 后检查下载状态`);
|
||||
await checkDownloadStatus(artwork.value.id);
|
||||
|
||||
// 如果任务完成但状态检查显示未下载,再次延迟检查
|
||||
if (task.status === 'completed' && !isDownloaded.value) {
|
||||
console.log('任务完成但状态检查失败,再次延迟检查');
|
||||
setTimeout(async () => {
|
||||
if (artwork.value && artwork.value.id === task.artwork_id) {
|
||||
await checkDownloadStatus(artwork.value.id);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 清理任务状态,显示下载完成状态
|
||||
currentTask.value = null;
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
},
|
||||
() => {
|
||||
console.log('SSE连接完成');
|
||||
stopTaskStreaming();
|
||||
// 监听任务完成状态
|
||||
watch(currentTask, (newTask, oldTask) => {
|
||||
if (oldTask && !newTask) {
|
||||
// 任务被移除,检查下载状态
|
||||
if (artwork.value) {
|
||||
setTimeout(async () => {
|
||||
await checkDownloadStatus(artwork.value!.id);
|
||||
}, 1000);
|
||||
}
|
||||
} else if (newTask && ['completed', 'failed', 'cancelled', 'partial'].includes(newTask.status)) {
|
||||
// 任务完成,延迟检查下载状态
|
||||
if (artwork.value && artwork.value.id === newTask.artwork_id) {
|
||||
const delay = newTask.total_files > 1 ? 1500 : 1000;
|
||||
setTimeout(async () => {
|
||||
await checkDownloadStatus(artwork.value!.id);
|
||||
}, delay);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 停止SSE监听
|
||||
const stopTaskStreaming = () => {
|
||||
if (sseConnection.value) {
|
||||
sseConnection.value();
|
||||
sseConnection.value = null;
|
||||
}
|
||||
// 确保清理任务状态
|
||||
currentTask.value = null;
|
||||
downloading.value = false;
|
||||
};
|
||||
|
||||
// 更新任务状态
|
||||
const updateTask = (task: DownloadTask) => {
|
||||
currentTask.value = task;
|
||||
};
|
||||
|
||||
// 移除任务
|
||||
const removeTask = (taskId: string) => {
|
||||
if (currentTask.value?.id === taskId) {
|
||||
currentTask.value = null;
|
||||
stopTaskStreaming();
|
||||
}
|
||||
};
|
||||
}, { immediate: true });
|
||||
|
||||
// 收藏/取消收藏
|
||||
const handleBookmark = async () => {
|
||||
@@ -386,10 +319,8 @@ const fetchArtistArtworks = async () => {
|
||||
// 导航到上一个作品
|
||||
const navigateToPrevious = () => {
|
||||
if (previousArtwork.value && !loading.value) {
|
||||
// 立即清理下载任务状态
|
||||
currentTask.value = null;
|
||||
// 清理下载状态
|
||||
downloading.value = false;
|
||||
stopTaskStreaming();
|
||||
|
||||
// 立即设置加载状态
|
||||
loading.value = true;
|
||||
@@ -409,10 +340,8 @@ const navigateToPrevious = () => {
|
||||
// 导航到下一个作品
|
||||
const navigateToNext = () => {
|
||||
if (nextArtwork.value && !loading.value) {
|
||||
// 立即清理下载任务状态
|
||||
currentTask.value = null;
|
||||
// 清理下载状态
|
||||
downloading.value = false;
|
||||
stopTaskStreaming();
|
||||
|
||||
// 立即设置加载状态
|
||||
loading.value = true;
|
||||
@@ -538,10 +467,8 @@ watch(() => route.params.id, (newId, oldId) => {
|
||||
// 确保页面滚动到顶部
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
// 立即清理所有下载相关状态
|
||||
currentTask.value = null;
|
||||
downloading.value = false;
|
||||
stopTaskStreaming();
|
||||
// 清理下载状态
|
||||
downloading.value = false;
|
||||
|
||||
// 重新获取作品详情
|
||||
fetchArtworkDetail();
|
||||
@@ -583,12 +510,11 @@ onMounted(() => {
|
||||
document.addEventListener('keyup', handleKeyUp);
|
||||
});
|
||||
|
||||
// 组件卸载时移除事件监听和清理SSE连接
|
||||
// 组件卸载时移除事件监听
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
document.removeEventListener('keyup', handleKeyUp);
|
||||
stopTaskStreaming();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
+27
-156
@@ -197,22 +197,23 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useDownloadStore } from '@/stores/download';
|
||||
import downloadService from '@/services/download';
|
||||
import type { DownloadTask } from '@/types';
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const downloadStore = useDownloadStore();
|
||||
|
||||
// 状态
|
||||
const activeTab = ref<'tasks' | 'history'>('tasks');
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
const tasks = ref<DownloadTask[]>([]);
|
||||
const history = ref<any[]>([]);
|
||||
|
||||
// SSE连接管理
|
||||
const sseConnections = ref<Map<string, () => void>>(new Map());
|
||||
// 使用store中的任务数据
|
||||
const tasks = computed(() => downloadStore.tasks);
|
||||
|
||||
// 计算属性:显示活跃任务和暂停任务
|
||||
const activeTasks = computed(() => {
|
||||
@@ -295,32 +296,11 @@ const formatDate = (dateString: string) => {
|
||||
// 刷新数据
|
||||
const refreshData = async () => {
|
||||
await Promise.all([
|
||||
fetchTasks(),
|
||||
downloadStore.fetchTasks(),
|
||||
fetchHistory()
|
||||
]);
|
||||
};
|
||||
|
||||
// 获取任务列表
|
||||
const fetchTasks = async () => {
|
||||
try {
|
||||
const response = await downloadService.getAllTasks();
|
||||
if (response.success) {
|
||||
tasks.value = response.data || [];
|
||||
|
||||
// 只为正在下载的任务建立SSE连接,避免为暂停任务建立连接
|
||||
activeTasks.value.forEach(task => {
|
||||
if (task.status === 'downloading' && !sseConnections.value.has(task.id)) {
|
||||
startTaskStreaming(task.id);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new Error(response.error || '获取任务列表失败');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取任务列表失败:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取历史记录(只获取最近200条)
|
||||
const fetchHistory = async () => {
|
||||
try {
|
||||
@@ -337,105 +317,25 @@ const fetchHistory = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 开始SSE监听任务进度
|
||||
const startTaskStreaming = (taskId: string) => {
|
||||
// 如果已经有连接,先关闭
|
||||
if (sseConnections.value.has(taskId)) {
|
||||
sseConnections.value.get(taskId)!();
|
||||
}
|
||||
|
||||
console.log('开始SSE监听任务进度:', taskId);
|
||||
|
||||
// 添加超时处理
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.warn('SSE连接超时,关闭连接:', taskId);
|
||||
stopTaskStreaming(taskId);
|
||||
}, 30000); // 30秒超时
|
||||
|
||||
const closeConnection = downloadService.streamTaskProgress(
|
||||
taskId,
|
||||
(task) => {
|
||||
console.log('收到SSE进度更新:', {
|
||||
taskId,
|
||||
status: task.status,
|
||||
progress: task.progress,
|
||||
completed: task.completed_files,
|
||||
total: task.total_files
|
||||
});
|
||||
|
||||
// 清除超时
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
// 更新任务状态
|
||||
const index = tasks.value.findIndex(t => t.id === taskId);
|
||||
if (index !== -1) {
|
||||
tasks.value[index] = task;
|
||||
}
|
||||
|
||||
// 如果任务完成或暂停,清理连接
|
||||
if (['completed', 'failed', 'cancelled', 'partial', 'paused'].includes(task.status)) {
|
||||
console.log('任务状态变更,关闭SSE连接:', taskId);
|
||||
stopTaskStreaming(taskId);
|
||||
|
||||
// 延迟刷新历史记录
|
||||
if (['completed', 'failed', 'cancelled', 'partial'].includes(task.status)) {
|
||||
setTimeout(() => {
|
||||
fetchHistory();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
},
|
||||
() => {
|
||||
console.log('SSE连接完成:', taskId);
|
||||
clearTimeout(timeoutId);
|
||||
stopTaskStreaming(taskId);
|
||||
}
|
||||
// 监听任务完成,刷新历史记录
|
||||
watch(tasks, (newTasks, oldTasks) => {
|
||||
// 检查是否有任务完成
|
||||
const completedTasks = newTasks.filter(task =>
|
||||
['completed', 'failed', 'cancelled', 'partial'].includes(task.status)
|
||||
);
|
||||
|
||||
sseConnections.value.set(taskId, closeConnection);
|
||||
};
|
||||
|
||||
// 停止SSE监听
|
||||
const stopTaskStreaming = (taskId: string) => {
|
||||
if (sseConnections.value.has(taskId)) {
|
||||
sseConnections.value.get(taskId)!();
|
||||
sseConnections.value.delete(taskId);
|
||||
}
|
||||
};
|
||||
|
||||
// 管理SSE连接
|
||||
const manageSSEConnections = () => {
|
||||
// 清理不需要的连接
|
||||
const currentTaskIds = new Set(activeTasks.value.map(task => task.id));
|
||||
|
||||
// 关闭已不存在的任务的连接
|
||||
sseConnections.value.forEach((closeConnection, taskId) => {
|
||||
if (!currentTaskIds.has(taskId)) {
|
||||
console.log('清理已不存在的任务连接:', taskId);
|
||||
closeConnection();
|
||||
sseConnections.value.delete(taskId);
|
||||
}
|
||||
});
|
||||
|
||||
// 为正在下载的任务建立连接
|
||||
activeTasks.value.forEach(task => {
|
||||
if (task.status === 'downloading' && !sseConnections.value.has(task.id)) {
|
||||
startTaskStreaming(task.id);
|
||||
}
|
||||
});
|
||||
};
|
||||
if (completedTasks.length > 0) {
|
||||
// 延迟刷新历史记录
|
||||
setTimeout(() => {
|
||||
fetchHistory();
|
||||
}, 1000);
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
// 取消任务
|
||||
const cancelTask = async (taskId: string) => {
|
||||
try {
|
||||
const response = await downloadService.cancelTask(taskId);
|
||||
if (response.success) {
|
||||
// 立即停止SSE连接
|
||||
stopTaskStreaming(taskId);
|
||||
await fetchTasks();
|
||||
} else {
|
||||
throw new Error(response.error || '取消任务失败');
|
||||
}
|
||||
await downloadStore.cancelTask(taskId);
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '取消任务失败';
|
||||
console.error('取消任务失败:', err);
|
||||
@@ -445,14 +345,7 @@ const cancelTask = async (taskId: string) => {
|
||||
// 恢复任务
|
||||
const resumeTask = async (taskId: string) => {
|
||||
try {
|
||||
const response = await downloadService.resumeTask(taskId);
|
||||
if (response.success) {
|
||||
await fetchTasks();
|
||||
// 重新管理SSE连接
|
||||
manageSSEConnections();
|
||||
} else {
|
||||
throw new Error(response.error || '恢复任务失败');
|
||||
}
|
||||
await downloadStore.resumeTask(taskId);
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '恢复任务失败';
|
||||
console.error('恢复任务失败:', err);
|
||||
@@ -464,13 +357,9 @@ const cleanupHistory = async () => {
|
||||
if (confirm('确定要清理下载历史吗?这将保留最新的500条记录。')) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await downloadService.cleanupHistory(500);
|
||||
if (response.success) {
|
||||
await fetchHistory(); // 重新获取历史记录
|
||||
alert('下载历史已清理!');
|
||||
} else {
|
||||
throw new Error(response.error || '清理历史失败');
|
||||
}
|
||||
await downloadStore.cleanupHistory(500);
|
||||
await fetchHistory(); // 重新获取历史记录
|
||||
alert('下载历史已清理!');
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '清理历史失败';
|
||||
console.error('清理历史失败:', err);
|
||||
@@ -485,13 +374,8 @@ const cleanupTasks = async () => {
|
||||
if (confirm('确定要清理已完成的任务吗?这将保留活跃任务和最新的100个已完成任务。')) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await downloadService.cleanupTasks(true, 100);
|
||||
if (response.success) {
|
||||
await fetchTasks(); // 重新获取任务列表
|
||||
alert('下载任务已清理!');
|
||||
} else {
|
||||
throw new Error(response.error || '清理任务失败');
|
||||
}
|
||||
await downloadStore.cleanupCompletedTasks(100);
|
||||
alert('下载任务已清理!');
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '清理任务失败';
|
||||
console.error('清理任务失败:', err);
|
||||
@@ -506,27 +390,14 @@ const clearError = () => {
|
||||
error.value = null;
|
||||
};
|
||||
|
||||
// 清理所有SSE连接
|
||||
const cleanupSSEConnections = () => {
|
||||
sseConnections.value.forEach(closeConnection => {
|
||||
closeConnection();
|
||||
});
|
||||
sseConnections.value.clear();
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
// 先获取数据,不阻塞页面渲染
|
||||
await Promise.all([
|
||||
fetchTasks(),
|
||||
downloadStore.fetchTasks(),
|
||||
fetchHistory()
|
||||
]);
|
||||
|
||||
// 数据加载完成后,异步管理SSE连接
|
||||
setTimeout(() => {
|
||||
manageSSEConnections();
|
||||
}, 100);
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '加载数据失败';
|
||||
} finally {
|
||||
@@ -535,7 +406,7 @@ onMounted(async () => {
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
cleanupSSEConnections();
|
||||
// 组件卸载时不需要清理SSE连接,因为store会统一管理
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user