增加作品完整性检查
This commit is contained in:
@@ -650,4 +650,41 @@ router.get('/stats', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制重新检查作品下载状态
|
||||||
|
* POST /api/download/force-check/:artworkId
|
||||||
|
*/
|
||||||
|
router.post('/force-check/:artworkId', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { artworkId } = req.params;
|
||||||
|
|
||||||
|
if (!artworkId || isNaN(parseInt(artworkId))) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid artwork ID'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadService = req.backend.getDownloadService();
|
||||||
|
|
||||||
|
// 强制重新检查,包括清理不完整的文件
|
||||||
|
const result = await downloadService.forceCheckArtworkDownloaded(parseInt(artworkId));
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
artwork_id: parseInt(artworkId),
|
||||||
|
is_downloaded: result.is_downloaded,
|
||||||
|
cleaned_files: result.cleaned_files || 0,
|
||||||
|
message: result.message
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
@@ -59,21 +59,37 @@ class DownloadExecutor {
|
|||||||
const fileName = `image_${index + 1}.${this.getFileExtension(imageUrl)}`;
|
const fileName = `image_${index + 1}.${this.getFileExtension(imageUrl)}`;
|
||||||
const filePath = path.join(artworkDir, fileName);
|
const filePath = path.join(artworkDir, fileName);
|
||||||
|
|
||||||
// 检查文件是否已存在
|
// 检查文件是否已存在且完整
|
||||||
if (await this.fileManager.fileExists(filePath)) {
|
if (await this.fileManager.fileExists(filePath)) {
|
||||||
task.completed_files++;
|
// 验证文件完整性
|
||||||
task.progress = Math.round((task.completed_files / task.total_files) * 100);
|
const integrity = await this.fileManager.checkFileIntegrity(filePath);
|
||||||
await this.taskManager.saveTasks();
|
if (integrity.valid) {
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
task.completed_files++;
|
||||||
continue;
|
task.progress = Math.round((task.completed_files / task.total_files) * 100);
|
||||||
|
await this.taskManager.saveTasks();
|
||||||
|
this.progressManager.notifyProgressUpdate(task.id, task);
|
||||||
|
results.push({ success: true, file: fileName, skipped: true });
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// 文件不完整,删除重新下载
|
||||||
|
console.log(`文件不完整,重新下载: ${filePath}`);
|
||||||
|
await this.fileManager.safeDeleteFile(filePath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 确保目录存在
|
// 确保目录存在
|
||||||
await this.fileManager.ensureDirectory(path.dirname(filePath));
|
await this.fileManager.ensureDirectory(path.dirname(filePath));
|
||||||
|
|
||||||
|
// 下载文件并等待完成
|
||||||
await this.fileManager.downloadFile(imageUrl, filePath);
|
await this.fileManager.downloadFile(imageUrl, filePath);
|
||||||
|
|
||||||
|
// 验证下载的文件完整性
|
||||||
|
const integrity = await this.fileManager.checkFileIntegrity(filePath);
|
||||||
|
if (!integrity.valid) {
|
||||||
|
throw new Error(`文件下载不完整: ${integrity.reason}`);
|
||||||
|
}
|
||||||
|
|
||||||
task.completed_files++;
|
task.completed_files++;
|
||||||
task.progress = Math.round((task.completed_files / task.total_files) * 100);
|
task.progress = Math.round((task.completed_files / task.total_files) * 100);
|
||||||
await this.taskManager.saveTasks();
|
await this.taskManager.saveTasks();
|
||||||
@@ -92,7 +108,7 @@ class DownloadExecutor {
|
|||||||
const infoPath = path.join(artworkDir, 'artwork_info.json');
|
const infoPath = path.join(artworkDir, 'artwork_info.json');
|
||||||
await fs.writeJson(infoPath, artwork, { spaces: 2 });
|
await fs.writeJson(infoPath, artwork, { spaces: 2 });
|
||||||
|
|
||||||
// 更新任务状态
|
// 更新任务状态 - 确保所有文件都处理完成后再更新
|
||||||
task.status = task.failed_files === 0 ? 'completed' : 'partial';
|
task.status = task.failed_files === 0 ? 'completed' : 'partial';
|
||||||
task.end_time = new Date();
|
task.end_time = new Date();
|
||||||
task.progress = 100;
|
task.progress = 100;
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ class DownloadService {
|
|||||||
// 检查作品信息文件
|
// 检查作品信息文件
|
||||||
const infoPath = path.join(artworkPath, 'artwork_info.json');
|
const infoPath = path.join(artworkPath, 'artwork_info.json');
|
||||||
if (!(await this.fileManager.fileExists(infoPath))) {
|
if (!(await this.fileManager.fileExists(infoPath))) {
|
||||||
|
console.log(`作品 ${artworkId} 缺少信息文件`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,19 +329,30 @@ class DownloadService {
|
|||||||
const imageFiles = files.filter(file => /\.(jpg|jpeg|png|gif|webp)$/i.test(file) && file !== 'artwork_info.json');
|
const imageFiles = files.filter(file => /\.(jpg|jpeg|png|gif|webp)$/i.test(file) && file !== 'artwork_info.json');
|
||||||
|
|
||||||
if (imageFiles.length === 0) {
|
if (imageFiles.length === 0) {
|
||||||
|
console.log(`作品 ${artworkId} 没有图片文件`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查每个图片文件的完整性
|
// 检查每个图片文件的完整性
|
||||||
|
let validFiles = 0;
|
||||||
for (const imageFile of imageFiles) {
|
for (const imageFile of imageFiles) {
|
||||||
const imagePath = path.join(artworkPath, imageFile);
|
const imagePath = path.join(artworkPath, imageFile);
|
||||||
const integrity = await this.fileManager.checkFileIntegrity(imagePath);
|
const integrity = await this.fileManager.checkFileIntegrity(imagePath);
|
||||||
if (!integrity.valid) {
|
if (integrity.valid) {
|
||||||
return false;
|
validFiles++;
|
||||||
|
} else {
|
||||||
|
console.log(`作品 ${artworkId} 的图片文件 ${imageFile} 不完整: ${integrity.reason}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// 只有当所有图片文件都完整时,才认为作品已下载
|
||||||
|
if (validFiles === imageFiles.length) {
|
||||||
|
console.log(`作品 ${artworkId} 已完整下载,共 ${validFiles} 个文件`);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
console.log(`作品 ${artworkId} 下载不完整,${validFiles}/${imageFiles.length} 个文件有效`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,6 +364,116 @@ class DownloadService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制重新检查作品下载状态,包括清理不完整的文件
|
||||||
|
*/
|
||||||
|
async forceCheckArtworkDownloaded(artworkId) {
|
||||||
|
try {
|
||||||
|
const downloadPath = await this.fileManager.getDownloadPath();
|
||||||
|
let cleanedFiles = 0;
|
||||||
|
|
||||||
|
// 扫描所有作者目录
|
||||||
|
const artistEntries = await this.fileManager.listDirectory(downloadPath);
|
||||||
|
|
||||||
|
for (const artistEntry of artistEntries) {
|
||||||
|
const artistPath = path.join(downloadPath, artistEntry);
|
||||||
|
const artistStat = await this.fileManager.getFileInfo(artistPath);
|
||||||
|
|
||||||
|
if (!artistStat.exists || !artistStat.isDirectory) continue;
|
||||||
|
|
||||||
|
// 扫描作者下的作品目录
|
||||||
|
const artworkEntries = await this.fileManager.listDirectory(artistPath);
|
||||||
|
|
||||||
|
for (const artworkEntry of artworkEntries) {
|
||||||
|
// 检查是否是目标作品目录(包含数字ID)
|
||||||
|
const artworkMatch = artworkEntry.match(/^(\d+)_(.+)$/);
|
||||||
|
if (artworkMatch && artworkMatch[1] === artworkId.toString()) {
|
||||||
|
const artworkPath = path.join(artistPath, artworkEntry);
|
||||||
|
|
||||||
|
// 检查作品信息文件
|
||||||
|
const infoPath = path.join(artworkPath, 'artwork_info.json');
|
||||||
|
if (!(await this.fileManager.fileExists(infoPath))) {
|
||||||
|
console.log(`作品 ${artworkId} 缺少信息文件,清理目录`);
|
||||||
|
await this.fileManager.removeDirectory(artworkPath);
|
||||||
|
return {
|
||||||
|
is_downloaded: false,
|
||||||
|
cleaned_files: 1,
|
||||||
|
message: '作品目录不完整,已清理'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查图片文件
|
||||||
|
const files = await this.fileManager.listDirectory(artworkPath);
|
||||||
|
const imageFiles = files.filter(file => /\.(jpg|jpeg|png|gif|webp)$/i.test(file) && file !== 'artwork_info.json');
|
||||||
|
|
||||||
|
if (imageFiles.length === 0) {
|
||||||
|
console.log(`作品 ${artworkId} 没有图片文件,清理目录`);
|
||||||
|
await this.fileManager.removeDirectory(artworkPath);
|
||||||
|
return {
|
||||||
|
is_downloaded: false,
|
||||||
|
cleaned_files: 1,
|
||||||
|
message: '作品目录没有图片文件,已清理'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查每个图片文件的完整性,清理不完整的文件
|
||||||
|
let validFiles = 0;
|
||||||
|
for (const imageFile of imageFiles) {
|
||||||
|
const imagePath = path.join(artworkPath, imageFile);
|
||||||
|
const integrity = await this.fileManager.checkFileIntegrity(imagePath);
|
||||||
|
if (integrity.valid) {
|
||||||
|
validFiles++;
|
||||||
|
} else {
|
||||||
|
console.log(`作品 ${artworkId} 的图片文件 ${imageFile} 不完整,删除: ${integrity.reason}`);
|
||||||
|
await this.fileManager.safeDeleteFile(imagePath);
|
||||||
|
cleanedFiles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果所有文件都被清理了,删除整个目录
|
||||||
|
if (validFiles === 0) {
|
||||||
|
console.log(`作品 ${artworkId} 所有图片文件都不完整,清理目录`);
|
||||||
|
await this.fileManager.removeDirectory(artworkPath);
|
||||||
|
return {
|
||||||
|
is_downloaded: false,
|
||||||
|
cleaned_files: cleanedFiles + 1,
|
||||||
|
message: '所有图片文件都不完整,已清理整个目录'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有当所有图片文件都完整时,才认为作品已下载
|
||||||
|
if (validFiles === imageFiles.length) {
|
||||||
|
return {
|
||||||
|
is_downloaded: true,
|
||||||
|
cleaned_files: cleanedFiles,
|
||||||
|
message: `作品已完整下载,共 ${validFiles} 个文件`
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
is_downloaded: false,
|
||||||
|
cleaned_files: cleanedFiles,
|
||||||
|
message: `作品下载不完整,${validFiles}/${imageFiles.length} 个文件有效,已清理 ${cleanedFiles} 个不完整文件`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
is_downloaded: false,
|
||||||
|
cleaned_files: cleanedFiles,
|
||||||
|
message: '作品未找到'
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('强制检查作品下载状态失败:', error);
|
||||||
|
return {
|
||||||
|
is_downloaded: false,
|
||||||
|
cleaned_files: 0,
|
||||||
|
message: `检查失败: ${error.message}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载单个作品
|
* 下载单个作品
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -83,6 +83,59 @@ class FileManager {
|
|||||||
return { valid: false, reason: '文件为空' };
|
return { valid: false, reason: '文件为空' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查文件是否过小(可能下载不完整)
|
||||||
|
if (stats.size < 1024) { // 小于1KB的文件可能是损坏的
|
||||||
|
return { valid: false, reason: '文件过小,可能下载不完整', size: stats.size };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件头,验证是否为有效的图片文件
|
||||||
|
try {
|
||||||
|
const fileHandle = await fs.open(filePath, 'r');
|
||||||
|
const buffer = Buffer.alloc(12);
|
||||||
|
await fileHandle.read(buffer, 0, 12, 0);
|
||||||
|
await fileHandle.close();
|
||||||
|
|
||||||
|
// 检查常见图片格式的文件头
|
||||||
|
const isJPEG = buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF;
|
||||||
|
const isPNG = buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47;
|
||||||
|
const isGIF = (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46) ||
|
||||||
|
(buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38);
|
||||||
|
const isWebP = buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46;
|
||||||
|
|
||||||
|
if (!isJPEG && !isPNG && !isGIF && !isWebP) {
|
||||||
|
return { valid: false, reason: '文件格式无效或损坏', size: stats.size };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于JPEG文件,检查文件尾
|
||||||
|
if (isJPEG) {
|
||||||
|
const endBuffer = Buffer.alloc(2);
|
||||||
|
const endHandle = await fs.open(filePath, 'r');
|
||||||
|
await endHandle.read(endBuffer, 0, 2, stats.size - 2);
|
||||||
|
await endHandle.close();
|
||||||
|
|
||||||
|
if (endBuffer[0] !== 0xFF || endBuffer[1] !== 0xD9) {
|
||||||
|
return { valid: false, reason: 'JPEG文件不完整(缺少结束标记)', size: stats.size };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于PNG文件,检查文件尾
|
||||||
|
if (isPNG) {
|
||||||
|
const endBuffer = Buffer.alloc(8);
|
||||||
|
const endHandle = await fs.open(filePath, 'r');
|
||||||
|
await endHandle.read(endBuffer, 0, 8, stats.size - 8);
|
||||||
|
await endHandle.close();
|
||||||
|
|
||||||
|
const pngEnd = Buffer.from([0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82]);
|
||||||
|
if (!endBuffer.equals(pngEnd)) {
|
||||||
|
return { valid: false, reason: 'PNG文件不完整(缺少结束标记)', size: stats.size };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (headerError) {
|
||||||
|
console.warn('文件头检查失败,但继续验证:', headerError.message);
|
||||||
|
// 如果文件头检查失败,但文件大小正常,仍然认为是有效的
|
||||||
|
}
|
||||||
|
|
||||||
return { valid: true, size: stats.size };
|
return { valid: true, size: stats.size };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { valid: false, reason: '检查文件失败', error: error.message };
|
return { valid: false, reason: '检查文件失败', error: error.message };
|
||||||
|
|||||||
@@ -48,9 +48,19 @@
|
|||||||
<div class="artwork-info">
|
<div class="artwork-info">
|
||||||
<div class="artwork-header">
|
<div class="artwork-header">
|
||||||
<h1 class="artwork-title">{{ artwork.title }}</h1>
|
<h1 class="artwork-title">{{ artwork.title }}</h1>
|
||||||
|
<!-- 下载按钮 -->
|
||||||
<div class="artwork-actions">
|
<div class="artwork-actions">
|
||||||
<button @click="handleDownload" class="btn btn-primary" :disabled="downloading">
|
<button @click="handleDownload" :disabled="downloading || !artwork" class="btn btn-primary">
|
||||||
{{ downloading ? '下载中...' : (isDownloaded ? '重新下载' : '下载') }}
|
<span v-if="downloading">下载中...</span>
|
||||||
|
<span v-else-if="isDownloaded">重新下载</span>
|
||||||
|
<span v-else>下载</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- 强制检查按钮 -->
|
||||||
|
<button @click="handleForceCheck" :disabled="checkingDownloadStatus || !artwork" class="btn btn-secondary"
|
||||||
|
title="强制检查下载状态">
|
||||||
|
<span v-if="checkingDownloadStatus">检查中...</span>
|
||||||
|
<span v-else>检查状态</span>
|
||||||
</button>
|
</button>
|
||||||
<button @click="handleBookmark" class="btn btn-secondary">
|
<button @click="handleBookmark" class="btn btn-secondary">
|
||||||
{{ artwork.is_bookmarked ? '取消收藏' : '收藏' }}
|
{{ artwork.is_bookmarked ? '取消收藏' : '收藏' }}
|
||||||
@@ -172,13 +182,14 @@
|
|||||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useAuthStore } from '@/stores/auth';
|
import { useAuthStore } from '@/stores/auth';
|
||||||
|
import { useRepositoryStore } from '@/stores/repository';
|
||||||
import artworkService from '@/services/artwork';
|
import artworkService from '@/services/artwork';
|
||||||
import artistService from '@/services/artist';
|
import artistService from '@/services/artist';
|
||||||
import downloadService from '@/services/download';
|
import downloadService from '@/services/download';
|
||||||
import { useRepositoryStore } from '@/stores/repository';
|
import { getApiBaseUrl, getImageProxyUrl } from '@/services/api';
|
||||||
import { getImageProxyUrl } from '@/services/api';
|
|
||||||
import type { Artwork, DownloadTask } from '@/types';
|
import type { Artwork, DownloadTask } from '@/types';
|
||||||
|
import ErrorMessage from '@/components/common/ErrorMessage.vue';
|
||||||
|
import LoadingSpinner from '@/components/common/LoadingSpinner.vue';
|
||||||
import DownloadProgress from '@/components/download/DownloadProgress.vue';
|
import DownloadProgress from '@/components/download/DownloadProgress.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -283,7 +294,7 @@ const fetchArtworkDetail = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 检查下载状态
|
// 检查下载状态
|
||||||
const checkDownloadStatus = async (artworkId: number) => {
|
const checkDownloadStatus = async (artworkId: number, retryCount = 0) => {
|
||||||
try {
|
try {
|
||||||
checkingDownloadStatus.value = true;
|
checkingDownloadStatus.value = true;
|
||||||
const response = await repositoryStore.checkArtworkDownloaded(artworkId);
|
const response = await repositoryStore.checkArtworkDownloaded(artworkId);
|
||||||
@@ -292,12 +303,27 @@ const checkDownloadStatus = async (artworkId: number) => {
|
|||||||
|
|
||||||
// repository store的apiCall返回的是data.data,所以response直接是数据对象
|
// repository store的apiCall返回的是data.data,所以response直接是数据对象
|
||||||
if (response && typeof response === 'object') {
|
if (response && typeof response === 'object') {
|
||||||
isDownloaded.value = response.is_downloaded || false;
|
const newStatus = response.is_downloaded || false;
|
||||||
|
|
||||||
|
// 如果状态发生变化,记录日志
|
||||||
|
if (isDownloaded.value !== newStatus) {
|
||||||
|
console.log(`作品下载状态变化: ${isDownloaded.value} -> ${newStatus}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
isDownloaded.value = newStatus;
|
||||||
console.log('作品下载状态:', isDownloaded.value);
|
console.log('作品下载状态:', isDownloaded.value);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('检查下载状态失败:', err);
|
console.error('检查下载状态失败:', err);
|
||||||
isDownloaded.value = false;
|
isDownloaded.value = false;
|
||||||
|
|
||||||
|
// 如果是网络错误且重试次数少于3次,延迟重试
|
||||||
|
if (retryCount < 3 && (err instanceof Error && err.message.includes('network') || err instanceof TypeError)) {
|
||||||
|
console.log(`下载状态检查失败,${2000 * (retryCount + 1)}ms 后重试 (${retryCount + 1}/3)`);
|
||||||
|
setTimeout(() => {
|
||||||
|
checkDownloadStatus(artworkId, retryCount + 1);
|
||||||
|
}, 2000 * (retryCount + 1));
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
checkingDownloadStatus.value = false;
|
checkingDownloadStatus.value = false;
|
||||||
}
|
}
|
||||||
@@ -357,6 +383,50 @@ const handleDownload = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 强制检查下载状态
|
||||||
|
const handleForceCheck = async () => {
|
||||||
|
if (!artwork.value) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
checkingDownloadStatus.value = true;
|
||||||
|
console.log('开始强制检查下载状态...');
|
||||||
|
|
||||||
|
// 调用强制检查API
|
||||||
|
const response = await fetch(`${getApiBaseUrl()}/api/download/force-check/${artwork.value.id}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
console.log('强制检查结果:', result.data);
|
||||||
|
|
||||||
|
// 更新下载状态
|
||||||
|
isDownloaded.value = result.data.is_downloaded;
|
||||||
|
|
||||||
|
// 显示检查结果
|
||||||
|
if (result.data.cleaned_files > 0) {
|
||||||
|
alert(`检查完成!${result.data.message}`);
|
||||||
|
} else {
|
||||||
|
alert(`检查完成!${result.data.message}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(result.error || '强制检查失败');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('强制检查请求失败');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('强制检查失败:', err);
|
||||||
|
alert(`强制检查失败: ${err instanceof Error ? err.message : '未知错误'}`);
|
||||||
|
} finally {
|
||||||
|
checkingDownloadStatus.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 开始SSE监听任务进度
|
// 开始SSE监听任务进度
|
||||||
const startTaskStreaming = (taskId: string) => {
|
const startTaskStreaming = (taskId: string) => {
|
||||||
// 清除之前的连接
|
// 清除之前的连接
|
||||||
@@ -386,14 +456,29 @@ const startTaskStreaming = (taskId: string) => {
|
|||||||
stopTaskStreaming();
|
stopTaskStreaming();
|
||||||
|
|
||||||
// 延迟检查下载状态,确保文件写入完成
|
// 延迟检查下载状态,确保文件写入完成
|
||||||
|
// 对于大文件,可能需要更长时间
|
||||||
|
const delay = task.total_files > 1 ? 3000 : 2000; // 多文件延迟3秒,单文件延迟2秒
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
// 检查当前页面是否还是同一个作品,避免页面切换后的状态更新
|
// 检查当前页面是否还是同一个作品,避免页面切换后的状态更新
|
||||||
if (artwork.value && artwork.value.id === task.artwork_id) {
|
if (artwork.value && artwork.value.id === task.artwork_id) {
|
||||||
|
console.log(`延迟 ${delay}ms 后检查下载状态`);
|
||||||
await checkDownloadStatus(artwork.value.id);
|
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);
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
// 清理任务状态,显示下载完成状态
|
// 清理任务状态,显示下载完成状态
|
||||||
currentTask.value = null;
|
currentTask.value = null;
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, delay);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user