整合下载逻辑,修复下载历史记录和显示问题
This commit is contained in:
@@ -80,12 +80,11 @@ class ArtistService {
|
|||||||
|
|
||||||
const response = await this.makeRequest('GET', `/v1/user/illusts?${stringify(params)}`);
|
const response = await this.makeRequest('GET', `/v1/user/illusts?${stringify(params)}`);
|
||||||
|
|
||||||
// 获取作者作品列表
|
// 获取作者作品列表 - 不在这里处理 limit,让调用方处理
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
artworks: response.illusts,
|
artworks: response.illusts || [],
|
||||||
next_url: response.next_url,
|
next_url: response.next_url,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -264,15 +264,22 @@ class ArtworkService {
|
|||||||
content,
|
content,
|
||||||
filter,
|
filter,
|
||||||
offset,
|
offset,
|
||||||
limit,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await this.makeRequest('GET', `/v1/illust/ranking?${stringify(params)}`);
|
const response = await this.makeRequest('GET', `/v1/illust/ranking?${stringify(params)}`);
|
||||||
|
|
||||||
|
// 获取排行榜作品列表
|
||||||
|
let artworks = response.illusts || [];
|
||||||
|
|
||||||
|
// 如果指定了 limit,则截取相应数量的作品
|
||||||
|
if (limit && limit < artworks.length) {
|
||||||
|
artworks = artworks.slice(0, limit);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
artworks: response.illusts,
|
artworks: artworks,
|
||||||
next_url: response.next_url,
|
next_url: response.next_url,
|
||||||
mode,
|
mode,
|
||||||
date: response.date,
|
date: response.date,
|
||||||
|
|||||||
@@ -167,19 +167,31 @@ class DownloadExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行批量下载
|
* 执行批量下载 - 统一的批量下载方法
|
||||||
|
* @param {Object} task - 任务对象
|
||||||
|
* @param {Array} items - 要下载的项目列表(可以是作品ID数组或作品对象数组)
|
||||||
|
* @param {Object} options - 下载选项
|
||||||
*/
|
*/
|
||||||
async executeBatchDownload(task, artworkIds, options) {
|
async executeBatchDownload(task, items, options = {}) {
|
||||||
// 获取动态并发配置
|
// 获取动态并发配置
|
||||||
const concurrentConfig = await this.downloadService.getConcurrentConfig();
|
const concurrentConfig = await this.downloadService.getConcurrentConfig();
|
||||||
const { concurrent = concurrentConfig.concurrentDownloads, size = 'original', quality = 'high', format = 'auto' } = options;
|
const {
|
||||||
|
concurrent = concurrentConfig.concurrentDownloads,
|
||||||
|
maxConcurrent = concurrentConfig.maxConcurrentFiles,
|
||||||
|
size = 'original',
|
||||||
|
quality = 'high',
|
||||||
|
format = 'auto'
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
// 使用合适的并发数
|
||||||
|
const batchSize = concurrent || maxConcurrent;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = [];
|
const results = [];
|
||||||
const recentCompleted = []; // 最近完成的作品列表
|
const recentCompleted = []; // 最近完成的作品列表
|
||||||
|
|
||||||
// 分批下载
|
// 分批下载
|
||||||
for (let i = 0; i < artworkIds.length; i += concurrent) {
|
for (let i = 0; i < items.length; i += batchSize) {
|
||||||
if (task.status === 'cancelled') {
|
if (task.status === 'cancelled') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -190,9 +202,12 @@ class DownloadExecutor {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const batch = artworkIds.slice(i, i + concurrent);
|
const batch = items.slice(i, i + batchSize);
|
||||||
const batchPromises = batch.map(async artworkId => {
|
const batchPromises = batch.map(async item => {
|
||||||
try {
|
try {
|
||||||
|
// 获取作品ID - 支持直接传入ID或作品对象
|
||||||
|
const artworkId = typeof item === 'object' ? item.id : item;
|
||||||
|
|
||||||
// 使用专门的批量下载方法,避免创建重复任务
|
// 使用专门的批量下载方法,避免创建重复任务
|
||||||
const downloadResult = await this.downloadService.downloadSingleArtworkForBatch(artworkId, {
|
const downloadResult = await this.downloadService.downloadSingleArtworkForBatch(artworkId, {
|
||||||
size,
|
size,
|
||||||
@@ -215,8 +230,12 @@ class DownloadExecutor {
|
|||||||
// 添加到最近完成列表
|
// 添加到最近完成列表
|
||||||
const completedItem = {
|
const completedItem = {
|
||||||
artwork_id: artworkId,
|
artwork_id: artworkId,
|
||||||
artwork_title: downloadResult.artwork_title || `作品 ${artworkId}`,
|
artwork_title: downloadResult.artwork_title ||
|
||||||
artist_name: downloadResult.artist_name || '未知作者'
|
(typeof item === 'object' ? item.title : null) ||
|
||||||
|
`作品 ${artworkId}`,
|
||||||
|
artist_name: downloadResult.artist_name ||
|
||||||
|
(typeof item === 'object' ? item.user?.name : null) ||
|
||||||
|
'未知作者'
|
||||||
};
|
};
|
||||||
|
|
||||||
recentCompleted.unshift(completedItem);
|
recentCompleted.unshift(completedItem);
|
||||||
@@ -241,6 +260,7 @@ class DownloadExecutor {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 异常情况
|
// 异常情况
|
||||||
|
const artworkId = typeof item === 'object' ? item.id : item;
|
||||||
task.failed_files++;
|
task.failed_files++;
|
||||||
const result = { artwork_id: artworkId, success: false, error: error.message };
|
const result = { artwork_id: artworkId, success: false, error: error.message };
|
||||||
results.push(result);
|
results.push(result);
|
||||||
@@ -256,7 +276,7 @@ class DownloadExecutor {
|
|||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
this.progressManager.notifyProgressUpdate(task.id, task);
|
||||||
|
|
||||||
// 添加延迟避免请求过于频繁
|
// 添加延迟避免请求过于频繁
|
||||||
if (i + concurrent < artworkIds.length) {
|
if (i + batchSize < items.length) {
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,244 +291,12 @@ class DownloadExecutor {
|
|||||||
// 添加到历史记录
|
// 添加到历史记录
|
||||||
const historyItem = {
|
const historyItem = {
|
||||||
id: task.id,
|
id: task.id,
|
||||||
type: 'batch',
|
type: task.type, // 使用任务的原始类型
|
||||||
total_files: task.total_files,
|
artist_name: task.artist_name, // 如果是作者下载任务会有这个字段
|
||||||
completed_files: task.completed_files,
|
artist_id: task.artist_id, // 作者ID
|
||||||
failed_files: task.failed_files,
|
mode: task.mode, // 如果是排行榜下载任务会有这个字段
|
||||||
start_time: task.start_time,
|
ranking_type: task.ranking_type, // 排行榜类型
|
||||||
end_time: task.end_time instanceof Date ? task.end_time.toISOString() : task.end_time,
|
task_description: task.task_description, // 任务描述
|
||||||
status: task.status,
|
|
||||||
};
|
|
||||||
|
|
||||||
await this.historyManager.addHistoryItem(historyItem);
|
|
||||||
} catch (error) {
|
|
||||||
task.status = 'failed';
|
|
||||||
task.error = error.message;
|
|
||||||
task.end_time = new Date();
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行作者作品下载
|
|
||||||
*/
|
|
||||||
async executeArtistDownload(task, newArtworks, options) {
|
|
||||||
// 获取动态并发配置
|
|
||||||
const concurrentConfig = await this.downloadService.getConcurrentConfig();
|
|
||||||
const { maxConcurrent = concurrentConfig.maxConcurrentFiles, size = 'original', quality = 'high', format = 'auto' } = options;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const results = [];
|
|
||||||
const recentCompleted = []; // 最近完成的作品列表
|
|
||||||
|
|
||||||
// 分批下载作品
|
|
||||||
for (let i = 0; i < newArtworks.length; i += maxConcurrent) {
|
|
||||||
if (task.status === 'cancelled') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const batch = newArtworks.slice(i, i + maxConcurrent);
|
|
||||||
const batchPromises = batch.map(async artwork => {
|
|
||||||
try {
|
|
||||||
// 使用专门的批量下载方法,避免创建重复任务
|
|
||||||
const downloadResult = await this.downloadService.downloadSingleArtworkForBatch(artwork.id, {
|
|
||||||
size,
|
|
||||||
quality,
|
|
||||||
format,
|
|
||||||
skipExisting: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (downloadResult.success) {
|
|
||||||
// 检查是否跳过下载
|
|
||||||
if (downloadResult.skipped) {
|
|
||||||
// 跳过下载,不计入失败,但也不计入完成
|
|
||||||
const result = { artwork_id: artwork.id, success: true, skipped: true };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
// 真正下载成功
|
|
||||||
task.completed_files++;
|
|
||||||
|
|
||||||
// 添加到最近完成列表
|
|
||||||
const completedItem = {
|
|
||||||
artwork_id: artwork.id,
|
|
||||||
artwork_title: downloadResult.artwork_title || artwork.title || `作品 ${artwork.id}`,
|
|
||||||
artist_name: downloadResult.artist_name || artwork.user?.name || '未知作者'
|
|
||||||
};
|
|
||||||
|
|
||||||
recentCompleted.unshift(completedItem);
|
|
||||||
// 只保留最近5个
|
|
||||||
if (recentCompleted.length > 5) {
|
|
||||||
recentCompleted.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新任务的recent_completed
|
|
||||||
task.recent_completed = [...recentCompleted];
|
|
||||||
|
|
||||||
const result = { artwork_id: artwork.id, success: true };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 下载失败
|
|
||||||
task.failed_files++;
|
|
||||||
const result = { artwork_id: artwork.id, success: false, error: downloadResult.error };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// 异常情况
|
|
||||||
task.failed_files++;
|
|
||||||
const result = { artwork_id: artwork.id, success: false, error: error.message };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(batchPromises);
|
|
||||||
|
|
||||||
// 更新进度并通知
|
|
||||||
task.progress = Math.round((task.completed_files / task.total_files) * 100);
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
|
||||||
|
|
||||||
// 添加延迟避免请求过于频繁
|
|
||||||
if (i + maxConcurrent < newArtworks.length) {
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新任务状态
|
|
||||||
task.status = task.failed_files === 0 ? 'completed' : 'partial';
|
|
||||||
task.end_time = new Date();
|
|
||||||
task.results = results;
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
|
||||||
|
|
||||||
// 添加到历史记录
|
|
||||||
const historyItem = {
|
|
||||||
id: task.id,
|
|
||||||
type: 'artist',
|
|
||||||
artist_name: task.artist_name,
|
|
||||||
total_files: task.total_files,
|
|
||||||
completed_files: task.completed_files,
|
|
||||||
failed_files: task.failed_files,
|
|
||||||
start_time: task.start_time,
|
|
||||||
end_time: task.end_time instanceof Date ? task.end_time.toISOString() : task.end_time,
|
|
||||||
status: task.status,
|
|
||||||
};
|
|
||||||
|
|
||||||
await this.historyManager.addHistoryItem(historyItem);
|
|
||||||
} catch (error) {
|
|
||||||
task.status = 'failed';
|
|
||||||
task.error = error.message;
|
|
||||||
task.end_time = new Date();
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行排行榜作品下载
|
|
||||||
*/
|
|
||||||
async executeRankingDownload(task, newArtworks, options) {
|
|
||||||
// 获取动态并发配置
|
|
||||||
const concurrentConfig = await this.downloadService.getConcurrentConfig();
|
|
||||||
const { maxConcurrent = concurrentConfig.maxConcurrentFiles, size = 'original', quality = 'high', format = 'auto' } = options;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const results = [];
|
|
||||||
const recentCompleted = []; // 最近完成的作品列表
|
|
||||||
|
|
||||||
// 分批下载作品
|
|
||||||
for (let i = 0; i < newArtworks.length; i += maxConcurrent) {
|
|
||||||
if (task.status === 'cancelled') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const batch = newArtworks.slice(i, i + maxConcurrent);
|
|
||||||
const batchPromises = batch.map(async artwork => {
|
|
||||||
try {
|
|
||||||
// 使用专门的批量下载方法,避免创建重复任务
|
|
||||||
const downloadResult = await this.downloadService.downloadSingleArtworkForBatch(artwork.id, {
|
|
||||||
size,
|
|
||||||
quality,
|
|
||||||
format,
|
|
||||||
skipExisting: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (downloadResult.success) {
|
|
||||||
// 检查是否跳过下载
|
|
||||||
if (downloadResult.skipped) {
|
|
||||||
// 跳过下载,不计入失败,但也不计入完成
|
|
||||||
const result = { artwork_id: artwork.id, success: true, skipped: true };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
// 真正下载成功
|
|
||||||
task.completed_files++;
|
|
||||||
|
|
||||||
// 添加到最近完成列表
|
|
||||||
const completedItem = {
|
|
||||||
artwork_id: artwork.id,
|
|
||||||
artwork_title: downloadResult.artwork_title || artwork.title || `作品 ${artwork.id}`,
|
|
||||||
artist_name: downloadResult.artist_name || artwork.user?.name || '未知作者'
|
|
||||||
};
|
|
||||||
|
|
||||||
recentCompleted.unshift(completedItem);
|
|
||||||
// 只保留最近5个
|
|
||||||
if (recentCompleted.length > 5) {
|
|
||||||
recentCompleted.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新任务的recent_completed
|
|
||||||
task.recent_completed = [...recentCompleted];
|
|
||||||
|
|
||||||
const result = { artwork_id: artwork.id, success: true };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 下载失败
|
|
||||||
task.failed_files++;
|
|
||||||
const result = { artwork_id: artwork.id, success: false, error: downloadResult.error };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// 异常情况
|
|
||||||
task.failed_files++;
|
|
||||||
const result = { artwork_id: artwork.id, success: false, error: error.message };
|
|
||||||
results.push(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(batchPromises);
|
|
||||||
|
|
||||||
// 更新进度并通知
|
|
||||||
task.progress = Math.round((task.completed_files / task.total_files) * 100);
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
|
||||||
|
|
||||||
// 添加延迟避免请求过于频繁
|
|
||||||
if (i + maxConcurrent < newArtworks.length) {
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新任务状态
|
|
||||||
task.status = task.failed_files === 0 ? 'completed' : 'partial';
|
|
||||||
task.end_time = new Date();
|
|
||||||
task.results = results;
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
|
||||||
|
|
||||||
// 添加到历史记录
|
|
||||||
const historyItem = {
|
|
||||||
id: task.id,
|
|
||||||
type: 'ranking',
|
|
||||||
total_files: task.total_files,
|
total_files: task.total_files,
|
||||||
completed_files: task.completed_files,
|
completed_files: task.completed_files,
|
||||||
failed_files: task.failed_files,
|
failed_files: task.failed_files,
|
||||||
|
|||||||
+165
-204
@@ -626,72 +626,12 @@ class DownloadService {
|
|||||||
* 批量下载作品
|
* 批量下载作品
|
||||||
*/
|
*/
|
||||||
async downloadMultipleArtworks(artworkIds, options = {}) {
|
async downloadMultipleArtworks(artworkIds, options = {}) {
|
||||||
// 获取动态并发配置
|
|
||||||
const concurrentConfig = await this.getConcurrentConfig();
|
|
||||||
const { concurrent = concurrentConfig.concurrentDownloads, size = 'original', quality = 'high', format = 'auto', skipExisting = true } = options;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 检查重复下载
|
// 使用统一的批量下载方法
|
||||||
let filteredIds = artworkIds;
|
return await this.downloadBatchArtworks(artworkIds, {
|
||||||
let skippedCount = 0;
|
...options,
|
||||||
|
taskType: 'batch',
|
||||||
if (skipExisting) {
|
|
||||||
const downloadedIds = await this.getDownloadedArtworkIds();
|
|
||||||
const downloadedSet = new Set(downloadedIds);
|
|
||||||
|
|
||||||
filteredIds = artworkIds.filter(id => !downloadedSet.has(id));
|
|
||||||
skippedCount = artworkIds.length - filteredIds.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建任务记录
|
|
||||||
const task = this.taskManager.createTask('batch', {
|
|
||||||
artwork_ids: artworkIds,
|
|
||||||
filtered_ids: filteredIds,
|
|
||||||
total_files: filteredIds.length,
|
|
||||||
completed_files: 0,
|
|
||||||
failed_files: 0,
|
|
||||||
skipped: skippedCount,
|
|
||||||
results: [],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
|
|
||||||
// 立即发送初始状态更新,让前端能立即看到进度条
|
|
||||||
this.progressManager.notifyProgressUpdate(task.id, task);
|
|
||||||
|
|
||||||
// 如果没有需要下载的作品,直接返回
|
|
||||||
if (filteredIds.length === 0) {
|
|
||||||
await this.taskManager.updateTask(task.id, {
|
|
||||||
status: 'completed',
|
|
||||||
end_time: new Date(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
task_id: task.id,
|
|
||||||
total_artworks: artworkIds.length,
|
|
||||||
completed_artworks: 0,
|
|
||||||
failed_artworks: 0,
|
|
||||||
skipped_artworks: skippedCount,
|
|
||||||
message: '所有作品都已下载完成',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 异步执行批量下载
|
|
||||||
this.downloadExecutor.executeBatchDownload(task, filteredIds, options);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
task_id: task.id,
|
|
||||||
total_artworks: task.total,
|
|
||||||
completed_artworks: task.completed,
|
|
||||||
failed_artworks: task.failed,
|
|
||||||
message: '批量下载任务已创建,正在后台执行',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('批量下载失败:', error);
|
logger.error('批量下载失败:', error);
|
||||||
return {
|
return {
|
||||||
@@ -848,11 +788,131 @@ class DownloadService {
|
|||||||
return match ? match[1] : 'jpg';
|
return match ? match[1] : 'jpg';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载批量作品 - 统一的批量下载方法
|
||||||
|
* @param {Array} items - 要下载的项目列表(可以是作品ID数组或作品对象数组)
|
||||||
|
* @param {Object} options - 下载选项
|
||||||
|
*/
|
||||||
|
async downloadBatchArtworks(items, options = {}) {
|
||||||
|
const { size = 'original', quality = 'high', format = 'auto', skipExisting = true, maxConcurrent = 3, taskType = 'batch' } = options;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 生成任务描述
|
||||||
|
let taskDescription = '';
|
||||||
|
let taskTitle = '';
|
||||||
|
|
||||||
|
if (taskType === 'ranking') {
|
||||||
|
const modeMap = {
|
||||||
|
'day': '日榜',
|
||||||
|
'week': '周榜',
|
||||||
|
'month': '月榜',
|
||||||
|
'rookie': '新人榜'
|
||||||
|
};
|
||||||
|
const typeMap = {
|
||||||
|
'art': '插画',
|
||||||
|
'manga': '漫画',
|
||||||
|
'novel': '小说'
|
||||||
|
};
|
||||||
|
const modeText = modeMap[options.mode] || options.mode;
|
||||||
|
const typeText = typeMap[options.type] || options.type;
|
||||||
|
taskDescription = `${modeText}${typeText}排行榜`;
|
||||||
|
taskTitle = `排行榜下载 - ${taskDescription}`;
|
||||||
|
} else if (taskType === 'artist') {
|
||||||
|
const artistName = options.artist_name || `作者ID: ${options.artist_id}`;
|
||||||
|
taskDescription = `作者作品 - ${artistName}`;
|
||||||
|
taskTitle = `作者作品下载 - ${artistName}`;
|
||||||
|
} else {
|
||||||
|
taskDescription = '批量下载';
|
||||||
|
taskTitle = '批量下载';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建任务记录
|
||||||
|
const task = this.taskManager.createTask(taskType, {
|
||||||
|
total_files: 0,
|
||||||
|
completed_files: 0,
|
||||||
|
failed_files: 0,
|
||||||
|
skipped: 0,
|
||||||
|
results: [],
|
||||||
|
task_description: taskDescription,
|
||||||
|
task_title: taskTitle,
|
||||||
|
// 保留原有的任务特定字段
|
||||||
|
...(options.artist_id && { artist_id: options.artist_id }),
|
||||||
|
...(options.artist_name && { artist_name: options.artist_name }),
|
||||||
|
...(options.mode && { mode: options.mode }),
|
||||||
|
...(options.type && { type: options.type }),
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.taskManager.saveTasks();
|
||||||
|
|
||||||
|
// 获取已下载的作品ID
|
||||||
|
const downloadedIds = skipExisting ? await this.getDownloadedArtworkIds() : [];
|
||||||
|
const downloadedSet = new Set(downloadedIds);
|
||||||
|
|
||||||
|
// 过滤已下载的作品
|
||||||
|
let newItems;
|
||||||
|
if (skipExisting) {
|
||||||
|
newItems = items.filter(item => {
|
||||||
|
const artworkId = typeof item === 'object' ? item.id : item;
|
||||||
|
return !downloadedSet.has(artworkId);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
newItems = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
const skippedCount = items.length - newItems.length;
|
||||||
|
|
||||||
|
await this.taskManager.updateTask(task.id, {
|
||||||
|
skipped: skippedCount,
|
||||||
|
total_files: newItems.length,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果没有需要下载的作品,直接返回
|
||||||
|
if (newItems.length === 0) {
|
||||||
|
await this.taskManager.updateTask(task.id, {
|
||||||
|
status: 'completed',
|
||||||
|
end_time: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
task_id: task.id,
|
||||||
|
total_artworks: items.length,
|
||||||
|
completed_artworks: 0,
|
||||||
|
failed_artworks: 0,
|
||||||
|
skipped_artworks: skippedCount,
|
||||||
|
message: '所有作品都已下载完成',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 异步执行批量下载
|
||||||
|
this.downloadExecutor.executeBatchDownload(task, newItems, options);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
task_id: task.id,
|
||||||
|
total_artworks: task.total_files,
|
||||||
|
completed_artworks: task.completed_files,
|
||||||
|
failed_artworks: task.failed_files,
|
||||||
|
message: '批量下载任务已创建,正在后台执行',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('批量下载失败:', error);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载作者作品
|
* 下载作者作品
|
||||||
*/
|
*/
|
||||||
async downloadArtistArtworks(artistId, options = {}) {
|
async downloadArtistArtworks(artistId, options = {}) {
|
||||||
const { type = 'art', limit = 50, size = 'original', quality = 'high', format = 'auto', skipExisting = true, maxConcurrent = 3, pageSize = 30 } = options;
|
const { type = 'art', limit = 50, pageSize = 30 } = options;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 先获取作者信息
|
// 先获取作者信息
|
||||||
@@ -866,23 +926,6 @@ class DownloadService {
|
|||||||
logger.warn(`获取作者 ${artistId} 信息失败:`, err.message);
|
logger.warn(`获取作者 ${artistId} 信息失败:`, err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建任务记录
|
|
||||||
const task = this.taskManager.createTask('artist', {
|
|
||||||
artist_id: artistId,
|
|
||||||
artist_name: artistName,
|
|
||||||
total_files: 0,
|
|
||||||
completed_files: 0,
|
|
||||||
failed_files: 0,
|
|
||||||
skipped: 0,
|
|
||||||
results: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
|
|
||||||
// 获取已下载的作品ID
|
|
||||||
const downloadedIds = skipExisting ? await this.getDownloadedArtworkIds() : [];
|
|
||||||
const downloadedSet = new Set(downloadedIds);
|
|
||||||
|
|
||||||
// 分页获取作者作品列表
|
// 分页获取作者作品列表
|
||||||
let allArtworks = [];
|
let allArtworks = [];
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
@@ -892,7 +935,6 @@ class DownloadService {
|
|||||||
const artworksResult = await this.artistService.getArtistArtworks(artistId, {
|
const artworksResult = await this.artistService.getArtistArtworks(artistId, {
|
||||||
type,
|
type,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: Math.min(pageSize, limit - allArtworks.length),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!artworksResult.success) {
|
if (!artworksResult.success) {
|
||||||
@@ -903,66 +945,28 @@ class DownloadService {
|
|||||||
if (artworks.length === 0) {
|
if (artworks.length === 0) {
|
||||||
hasMore = false;
|
hasMore = false;
|
||||||
} else {
|
} else {
|
||||||
allArtworks.push(...artworks);
|
// 确保不超过指定的 limit
|
||||||
|
const remainingSlots = limit - allArtworks.length;
|
||||||
|
const artworksToAdd = artworks.slice(0, remainingSlots);
|
||||||
|
|
||||||
|
allArtworks.push(...artworksToAdd);
|
||||||
offset += artworks.length;
|
offset += artworks.length;
|
||||||
|
|
||||||
// 基于 next_url 判断是否还有更多页面
|
// 基于 next_url 判断是否还有更多页面
|
||||||
hasMore = !!artworksResult.data.next_url;
|
hasMore = !!artworksResult.data.next_url && allArtworks.length < limit;
|
||||||
|
|
||||||
// 添加延迟避免请求过于频繁
|
// 添加延迟避免请求过于频繁
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 过滤已下载的作品
|
// 使用统一的批量下载方法
|
||||||
const newArtworks = skipExisting ? allArtworks.filter(artwork => !downloadedSet.has(artwork.id)) : allArtworks;
|
return await this.downloadBatchArtworks(allArtworks, {
|
||||||
|
...options,
|
||||||
const skippedCount = allArtworks.length - newArtworks.length;
|
taskType: 'artist',
|
||||||
|
artist_id: artistId,
|
||||||
await this.taskManager.updateTask(task.id, {
|
artist_name: artistName,
|
||||||
skipped: skippedCount,
|
|
||||||
total_files: newArtworks.length,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 作者作品下载统计
|
|
||||||
|
|
||||||
// 如果没有需要下载的作品,直接返回
|
|
||||||
if (newArtworks.length === 0) {
|
|
||||||
await this.taskManager.updateTask(task.id, {
|
|
||||||
status: 'completed',
|
|
||||||
end_time: new Date(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
task_id: task.id,
|
|
||||||
artist_id: artistId,
|
|
||||||
artist_name: artistName,
|
|
||||||
total_artworks: allArtworks.length,
|
|
||||||
completed_artworks: 0,
|
|
||||||
failed_artworks: 0,
|
|
||||||
skipped_artworks: skippedCount,
|
|
||||||
message: '所有作品都已下载完成',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 异步执行作者作品下载
|
|
||||||
this.downloadExecutor.executeArtistDownload(task, newArtworks, options);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
task_id: task.id,
|
|
||||||
artist_id: artistId,
|
|
||||||
artist_name: artistName,
|
|
||||||
total_artworks: task.total_files,
|
|
||||||
completed_artworks: task.completed_files,
|
|
||||||
failed_artworks: task.failed_files,
|
|
||||||
message: '作者作品下载任务已创建,正在后台执行',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('作者作品下载失败:', error);
|
logger.error('作者作品下载失败:', error);
|
||||||
return {
|
return {
|
||||||
@@ -976,35 +980,21 @@ class DownloadService {
|
|||||||
* 下载排行榜作品
|
* 下载排行榜作品
|
||||||
*/
|
*/
|
||||||
async downloadRankingArtworks(options = {}) {
|
async downloadRankingArtworks(options = {}) {
|
||||||
const { mode = 'day', type = 'art', limit = 50, size = 'original', quality = 'high', format = 'auto', skipExisting = true, maxConcurrent = 3, pageSize = 30 } = options;
|
const { mode = 'day', type = 'art', limit = 50, pageSize = 30 } = options;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 创建任务记录
|
|
||||||
const task = this.taskManager.createTask('ranking', {
|
|
||||||
mode: mode,
|
|
||||||
type: type,
|
|
||||||
total_files: 0,
|
|
||||||
completed_files: 0,
|
|
||||||
failed_files: 0,
|
|
||||||
skipped: 0,
|
|
||||||
results: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.taskManager.saveTasks();
|
|
||||||
|
|
||||||
// 获取已下载的作品ID
|
|
||||||
const downloadedIds = skipExisting ? await this.getDownloadedArtworkIds() : [];
|
|
||||||
const downloadedSet = new Set(downloadedIds);
|
|
||||||
|
|
||||||
// 分页获取排行榜作品列表
|
// 分页获取排行榜作品列表
|
||||||
let allArtworks = [];
|
let allArtworks = [];
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
let hasMore = true;
|
let hasMore = true;
|
||||||
|
|
||||||
while (hasMore && allArtworks.length < limit) {
|
while (hasMore && allArtworks.length < limit) {
|
||||||
|
const remainingLimit = limit - allArtworks.length;
|
||||||
|
const requestLimit = Math.min(pageSize, remainingLimit);
|
||||||
|
|
||||||
const rankingResult = await this.getRankingArtworks(mode, type, {
|
const rankingResult = await this.getRankingArtworks(mode, type, {
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: Math.min(pageSize, limit - allArtworks.length),
|
limit: requestLimit,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!rankingResult.success) {
|
if (!rankingResult.success) {
|
||||||
@@ -1015,66 +1005,28 @@ class DownloadService {
|
|||||||
if (artworks.length === 0) {
|
if (artworks.length === 0) {
|
||||||
hasMore = false;
|
hasMore = false;
|
||||||
} else {
|
} else {
|
||||||
allArtworks.push(...artworks);
|
// 确保不超过指定的 limit
|
||||||
|
const remainingSlots = limit - allArtworks.length;
|
||||||
|
const artworksToAdd = artworks.slice(0, remainingSlots);
|
||||||
|
|
||||||
|
allArtworks.push(...artworksToAdd);
|
||||||
offset += artworks.length;
|
offset += artworks.length;
|
||||||
|
|
||||||
// 基于 next_url 判断是否还有更多页面
|
// 基于 next_url 判断是否还有更多页面
|
||||||
hasMore = !!rankingResult.data.next_url;
|
hasMore = !!rankingResult.data.next_url && allArtworks.length < limit;
|
||||||
|
|
||||||
// 添加延迟避免请求过于频繁
|
// 添加延迟避免请求过于频繁
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 过滤已下载的作品
|
// 使用统一的批量下载方法
|
||||||
const newArtworks = skipExisting ? allArtworks.filter(artwork => !downloadedSet.has(artwork.id)) : allArtworks;
|
return await this.downloadBatchArtworks(allArtworks, {
|
||||||
|
...options,
|
||||||
const skippedCount = allArtworks.length - newArtworks.length;
|
taskType: 'ranking',
|
||||||
|
mode: mode,
|
||||||
await this.taskManager.updateTask(task.id, {
|
type: type,
|
||||||
skipped: skippedCount,
|
|
||||||
total_files: newArtworks.length,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 排行榜作品下载统计
|
|
||||||
|
|
||||||
// 如果没有需要下载的作品,直接返回
|
|
||||||
if (newArtworks.length === 0) {
|
|
||||||
await this.taskManager.updateTask(task.id, {
|
|
||||||
status: 'completed',
|
|
||||||
end_time: new Date(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
task_id: task.id,
|
|
||||||
mode: mode,
|
|
||||||
type: type,
|
|
||||||
total_artworks: allArtworks.length,
|
|
||||||
completed_artworks: 0,
|
|
||||||
failed_artworks: 0,
|
|
||||||
skipped_artworks: skippedCount,
|
|
||||||
message: '所有作品都已下载完成',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 异步执行排行榜作品下载
|
|
||||||
this.downloadExecutor.executeRankingDownload(task, newArtworks, options);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
task_id: task.id,
|
|
||||||
mode: mode,
|
|
||||||
type: type,
|
|
||||||
total_artworks: task.total,
|
|
||||||
completed_artworks: task.completed,
|
|
||||||
failed_artworks: task.failed,
|
|
||||||
message: '排行榜作品下载任务已创建,正在后台执行',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('排行榜作品下载失败:', error);
|
logger.error('排行榜作品下载失败:', error);
|
||||||
return {
|
return {
|
||||||
@@ -1101,11 +1053,20 @@ class DownloadService {
|
|||||||
limit,
|
limit,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 检查 ArtworkService 返回的结果
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.error || '获取排行榜数据失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保数据结构正确
|
||||||
|
const artworks = result.data?.artworks || [];
|
||||||
|
const nextUrl = result.data?.next_url || null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
artworks: result.artworks,
|
artworks: artworks,
|
||||||
next_url: result.next_url || null,
|
next_url: nextUrl,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -82,7 +82,11 @@ class HistoryManager {
|
|||||||
// 只保存关键信息
|
// 只保存关键信息
|
||||||
artwork_id: item.artwork_id,
|
artwork_id: item.artwork_id,
|
||||||
artist_name: item.artist_name,
|
artist_name: item.artist_name,
|
||||||
artwork_title: item.artwork_title
|
artist_id: item.artist_id,
|
||||||
|
artwork_title: item.artwork_title,
|
||||||
|
mode: item.mode,
|
||||||
|
ranking_type: item.ranking_type,
|
||||||
|
task_description: item.task_description
|
||||||
};
|
};
|
||||||
|
|
||||||
this.history.unshift(simplifiedItem);
|
this.history.unshift(simplifiedItem);
|
||||||
@@ -219,4 +223,4 @@ class HistoryManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = HistoryManager;
|
module.exports = HistoryManager;
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 按钮操作区域 - 单独的第二行 -->
|
<!-- 按钮操作区域 - 单独的第二行 -->
|
||||||
<div class="artwork-actions">
|
<div class="artwork-actions">
|
||||||
<!-- 下载按钮 -->
|
<!-- 下载按钮 -->
|
||||||
@@ -267,7 +267,7 @@ const handleCaptionToggleChange = (event: Event) => {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
max-width: 420px;
|
max-width: 400px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@@ -123,11 +123,21 @@ const indicatorClass = computed(() => {
|
|||||||
|
|
||||||
// 获取任务标题
|
// 获取任务标题
|
||||||
const getTaskTitle = (task: DownloadTask) => {
|
const getTaskTitle = (task: DownloadTask) => {
|
||||||
|
// 优先使用后端生成的任务标题
|
||||||
|
if (task.task_title) {
|
||||||
|
return task.task_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容旧版本的任务标题生成逻辑
|
||||||
if (task.type === 'artwork') {
|
if (task.type === 'artwork') {
|
||||||
return task.artwork_title || `作品 ${task.artwork_id}`;
|
return task.artwork_title || `作品 ${task.artwork_id}`;
|
||||||
} else if (task.type === 'artist') {
|
} else if (task.type === 'artist') {
|
||||||
return `作者作品 - ${task.artist_name || '未知作者'}`;
|
return `作者作品 - ${task.artist_name || '未知作者'}`;
|
||||||
} else if (task.type === 'batch') {
|
} else if (task.type === 'batch') {
|
||||||
|
// 如果有任务描述,使用任务描述
|
||||||
|
if (task.task_description) {
|
||||||
|
return `${task.task_description} (${task.total_files} 个作品)`;
|
||||||
|
}
|
||||||
return `批量下载 (${task.total_files} 个作品)`;
|
return `批量下载 (${task.total_files} 个作品)`;
|
||||||
}
|
}
|
||||||
return '未知任务';
|
return '未知任务';
|
||||||
|
|||||||
@@ -1,29 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="download-progress" v-if="task">
|
<div class="download-progress" v-if="task">
|
||||||
<div class="progress-header">
|
<div class="progress-header">
|
||||||
<h4 class="progress-title">{{ task.artwork_title || '下载中...' }}</h4>
|
<h4 class="progress-title">{{ getTaskTitle(task) }}</h4>
|
||||||
<div class="progress-actions">
|
<div class="progress-actions">
|
||||||
<button
|
<button v-if="task.status === 'downloading'" @click="pauseTask" class="btn btn-sm btn-secondary"
|
||||||
v-if="task.status === 'downloading'"
|
:disabled="loading">
|
||||||
@click="pauseTask"
|
|
||||||
class="btn btn-sm btn-secondary"
|
|
||||||
:disabled="loading"
|
|
||||||
>
|
|
||||||
暂停
|
暂停
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button v-if="task.status === 'paused'" @click="resumeTask" class="btn btn-sm btn-primary" :disabled="loading">
|
||||||
v-if="task.status === 'paused'"
|
|
||||||
@click="resumeTask"
|
|
||||||
class="btn btn-sm btn-primary"
|
|
||||||
:disabled="loading"
|
|
||||||
>
|
|
||||||
恢复
|
恢复
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button @click="cancelTask" class="btn btn-sm btn-danger" :disabled="loading">
|
||||||
@click="cancelTask"
|
|
||||||
class="btn btn-sm btn-danger"
|
|
||||||
:disabled="loading"
|
|
||||||
>
|
|
||||||
取消
|
取消
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,11 +18,7 @@
|
|||||||
|
|
||||||
<div class="progress-overview">
|
<div class="progress-overview">
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
<div
|
<div class="progress-fill" :style="{ width: `${task.progress}%` }" :class="progressClass"></div>
|
||||||
class="progress-fill"
|
|
||||||
:style="{ width: `${task.progress}%` }"
|
|
||||||
:class="progressClass"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-text">
|
<div class="progress-text">
|
||||||
{{ task.progress }}% ({{ task.completed_files }}/{{ task.total_files }})
|
{{ task.progress }}% ({{ task.completed_files }}/{{ task.total_files }})
|
||||||
@@ -58,7 +41,7 @@
|
|||||||
<span class="stat-value">{{ task.total_files - task.completed_files - task.failed_files }}</span>
|
<span class="stat-value">{{ task.total_files - task.completed_files - task.failed_files }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 最近完成的作品列表 -->
|
<!-- 最近完成的作品列表 -->
|
||||||
<div v-if="task.recent_completed && task.recent_completed.length > 0" class="recent-completed">
|
<div v-if="task.recent_completed && task.recent_completed.length > 0" class="recent-completed">
|
||||||
<h4>最近完成:</h4>
|
<h4>最近完成:</h4>
|
||||||
@@ -119,6 +102,27 @@ const statusClass = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 方法
|
// 方法
|
||||||
|
const getTaskTitle = (task: DownloadTask) => {
|
||||||
|
// 优先使用后端生成的任务标题
|
||||||
|
if (task.task_title) {
|
||||||
|
return task.task_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容旧版本的任务标题生成逻辑
|
||||||
|
if (task.type === 'artwork') {
|
||||||
|
return task.artwork_title || `作品 ${task.artwork_id}`;
|
||||||
|
} else if (task.type === 'artist') {
|
||||||
|
return `作者作品 - ${task.artist_name || '未知作者'}`;
|
||||||
|
} else if (task.type === 'batch') {
|
||||||
|
// 如果有任务描述,使用任务描述
|
||||||
|
if (task.task_description) {
|
||||||
|
return `${task.task_description} (${task.total_files} 个作品)`;
|
||||||
|
}
|
||||||
|
return `批量下载 (${task.total_files} 个作品)`;
|
||||||
|
}
|
||||||
|
return '下载中...';
|
||||||
|
};
|
||||||
|
|
||||||
const getStatusText = (status: string) => {
|
const getStatusText = (status: string) => {
|
||||||
const statusMap: Record<string, string> = {
|
const statusMap: Record<string, string> = {
|
||||||
downloading: '下载中',
|
downloading: '下载中',
|
||||||
@@ -525,4 +529,4 @@ const cancelTask = async () => {
|
|||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -107,6 +107,9 @@ export interface DownloadTask {
|
|||||||
artwork_id?: number;
|
artwork_id?: number;
|
||||||
artist_name?: string;
|
artist_name?: string;
|
||||||
artwork_title?: string;
|
artwork_title?: string;
|
||||||
|
task_description?: string;
|
||||||
|
task_title?: string;
|
||||||
|
mode?: string;
|
||||||
start_time: string;
|
start_time: string;
|
||||||
end_time?: string;
|
end_time?: string;
|
||||||
error?: string;
|
error?: string;
|
||||||
@@ -135,4 +138,4 @@ export interface DownloadParams {
|
|||||||
quality?: 'high' | 'medium' | 'low';
|
quality?: 'high' | 'medium' | 'low';
|
||||||
format?: 'auto' | 'jpg' | 'png';
|
format?: 'auto' | 'jpg' | 'png';
|
||||||
concurrent?: number;
|
concurrent?: number;
|
||||||
}
|
}
|
||||||
@@ -211,11 +211,21 @@ const activeTasks = computed(() => {
|
|||||||
|
|
||||||
// 获取任务标题
|
// 获取任务标题
|
||||||
const getTaskTitle = (task: DownloadTask) => {
|
const getTaskTitle = (task: DownloadTask) => {
|
||||||
|
// 优先使用后端生成的任务标题
|
||||||
|
if (task.task_title) {
|
||||||
|
return task.task_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 兼容旧版本的任务标题生成逻辑
|
||||||
if (task.type === 'artwork') {
|
if (task.type === 'artwork') {
|
||||||
return task.artwork_title || `作品 ${task.artwork_id}`;
|
return task.artwork_title || `作品 ${task.artwork_id}`;
|
||||||
} else if (task.type === 'artist') {
|
} else if (task.type === 'artist') {
|
||||||
return `作者作品 - ${task.artist_name || '未知作者'}`;
|
return `作者作品 - ${task.artist_name || '未知作者'}`;
|
||||||
} else if (task.type === 'batch') {
|
} else if (task.type === 'batch') {
|
||||||
|
// 如果有任务描述,使用任务描述
|
||||||
|
if (task.task_description) {
|
||||||
|
return `${task.task_description} (${task.total_files} 个作品)`;
|
||||||
|
}
|
||||||
return `批量下载 (${task.total_files} 个作品)`;
|
return `批量下载 (${task.total_files} 个作品)`;
|
||||||
}
|
}
|
||||||
return '未知任务';
|
return '未知任务';
|
||||||
@@ -239,6 +249,7 @@ const getTypeText = (type: string) => {
|
|||||||
const typeMap: Record<string, string> = {
|
const typeMap: Record<string, string> = {
|
||||||
'artwork': '单个作品',
|
'artwork': '单个作品',
|
||||||
'artist': '作者作品',
|
'artist': '作者作品',
|
||||||
|
'art': '作者作品',
|
||||||
'batch': '批量下载',
|
'batch': '批量下载',
|
||||||
'ranking': '排行榜下载'
|
'ranking': '排行榜下载'
|
||||||
};
|
};
|
||||||
@@ -251,13 +262,33 @@ const getHistoryTitle = (item: any) => {
|
|||||||
const title = item.artwork_title || '未知作品';
|
const title = item.artwork_title || '未知作品';
|
||||||
const artist = item.artist_name || '未知作者';
|
const artist = item.artist_name || '未知作者';
|
||||||
return `${title} (${artist})`;
|
return `${title} (${artist})`;
|
||||||
} else if (item.type === 'artist') {
|
} else if (item.type === 'artist' || item.type === 'art') {
|
||||||
const artist = item.artist_name || '未知作者';
|
const artist = item.artist_name || '未知作者';
|
||||||
return `作者作品 (${artist})`;
|
const count = item.total_files || 0;
|
||||||
|
// 如果有任务描述,优先使用任务描述
|
||||||
|
if (item.task_description) {
|
||||||
|
return `${item.task_description} - ${count} 个作品`;
|
||||||
|
}
|
||||||
|
return `作者作品 (${artist}) - ${count} 个作品`;
|
||||||
} else if (item.type === 'batch') {
|
} else if (item.type === 'batch') {
|
||||||
return `批量下载 (${item.total_files || 0} 个作品)`;
|
const count = item.total_files || 0;
|
||||||
|
// 如果有任务描述,使用任务描述
|
||||||
|
if (item.task_description) {
|
||||||
|
return `${item.task_description} - ${count} 个作品`;
|
||||||
|
}
|
||||||
|
return `批量下载 - ${count} 个作品`;
|
||||||
} else if (item.type === 'ranking') {
|
} else if (item.type === 'ranking') {
|
||||||
return `排行榜下载 (${item.total_files || 0} 个作品)`;
|
const count = item.total_files || 0;
|
||||||
|
let title = '排行榜下载';
|
||||||
|
if (item.mode && item.ranking_type) {
|
||||||
|
const modeText = item.mode === 'daily' ? '日榜' :
|
||||||
|
item.mode === 'weekly' ? '周榜' :
|
||||||
|
item.mode === 'monthly' ? '月榜' : item.mode;
|
||||||
|
const typeText = item.ranking_type === 'illust' ? '插画' :
|
||||||
|
item.ranking_type === 'manga' ? '漫画' : item.ranking_type;
|
||||||
|
title = `${modeText}${typeText}`;
|
||||||
|
}
|
||||||
|
return `${title} - ${count} 个作品`;
|
||||||
}
|
}
|
||||||
return '未知下载任务';
|
return '未知下载任务';
|
||||||
};
|
};
|
||||||
@@ -307,10 +338,10 @@ const fetchHistory = async () => {
|
|||||||
// 监听任务完成,刷新历史记录
|
// 监听任务完成,刷新历史记录
|
||||||
watch(tasks, (newTasks, oldTasks) => {
|
watch(tasks, (newTasks, oldTasks) => {
|
||||||
// 检查是否有任务完成
|
// 检查是否有任务完成
|
||||||
const completedTasks = newTasks.filter(task =>
|
const completedTasks = newTasks.filter(task =>
|
||||||
['completed', 'failed', 'cancelled', 'partial'].includes(task.status)
|
['completed', 'failed', 'cancelled', 'partial'].includes(task.status)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (completedTasks.length > 0) {
|
if (completedTasks.length > 0) {
|
||||||
// 延迟刷新历史记录
|
// 延迟刷新历史记录
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user