From 8dc3501990c961dc63de791cf419ac5a28c92902 Mon Sep 17 00:00:00 2001 From: sion123 <450702724@qq.com> Date: Wed, 4 Mar 2026 03:49:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/web-gold/src/views/material/Mix.vue | 7 +- .../composables/useTaskOperations.js | 48 ++++-- .../system/task-management/mix-task/index.vue | 162 ++++++++++++++++-- 3 files changed, 186 insertions(+), 31 deletions(-) diff --git a/frontend/app/web-gold/src/views/material/Mix.vue b/frontend/app/web-gold/src/views/material/Mix.vue index 699aa426ac..e04ed81878 100644 --- a/frontend/app/web-gold/src/views/material/Mix.vue +++ b/frontend/app/web-gold/src/views/material/Mix.vue @@ -323,7 +323,7 @@ const formData = ref({ produceCount: Number(localStorage.getItem('mix-produce-count')) || 3, totalDuration: 15, clipDuration: 5, - cropMode: 'center' + cropMode: localStorage.getItem('mix-crop-mode') || 'center' }) const uiState = ref({ @@ -377,6 +377,11 @@ const saveProduceCount = () => { localStorage.setItem('mix-produce-count', formData.value.produceCount.toString()) } +// 监听裁剪模式变化,保存到 localStorage +watch(() => formData.value.cropMode, (newVal) => { + localStorage.setItem('mix-crop-mode', newVal) +}) + const getFileById = (fileId) => { let file = dataState.value.groupFiles.find(f => f.id === fileId) if (file) return file diff --git a/frontend/app/web-gold/src/views/system/task-management/composables/useTaskOperations.js b/frontend/app/web-gold/src/views/system/task-management/composables/useTaskOperations.js index c9dcecd590..485dbe1d42 100644 --- a/frontend/app/web-gold/src/views/system/task-management/composables/useTaskOperations.js +++ b/frontend/app/web-gold/src/views/system/task-management/composables/useTaskOperations.js @@ -118,15 +118,25 @@ export function useTaskOperations(apiHandlers, onSuccess) { }) } - // 下载单个文件 - function downloadFile(url, filename = 'download') { - const link = document.createElement('a') - link.href = url - link.download = filename - link.target = '_blank' - document.body.appendChild(link) - link.click() - document.body.removeChild(link) + // 下载单个文件(使用 fetch + blob 强制下载) + async function downloadFile(url, filename = 'download') { + try { + const response = await fetch(url) + if (!response.ok) throw new Error('下载失败') + const blob = await response.blob() + const blobUrl = URL.createObjectURL(blob) + const link = document.createElement('a') + link.href = blobUrl + link.download = filename + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(blobUrl) + } catch (error) { + console.error('下载失败:', error) + // 降级:直接打开让浏览器处理 + window.open(url, '_blank') + } } // 获取签名URL @@ -156,17 +166,21 @@ export function useTaskOperations(apiHandlers, onSuccess) { } message.destroy() - message.loading('正在下载文件...', 0) + message.loading(`正在下载 ${downloadUrls.length} 个文件...`, 0) - // 逐个触发下载,避免浏览器阻止多个弹窗 - downloadUrls.forEach((url, index) => { - setTimeout(() => { - downloadFile(url) - }, index * DOWNLOAD_INTERVAL) - }) + // 逐个下载文件 + for (let i = 0; i < downloadUrls.length; i++) { + const url = downloadUrls[i] + const filename = `video_${taskId}_${i + 1}.mp4` + await downloadFile(url, filename) + // 短暂延迟避免浏览器阻止 + if (i < downloadUrls.length - 1) { + await new Promise(resolve => setTimeout(resolve, DOWNLOAD_INTERVAL)) + } + } message.destroy() - message.success(`已触发 ${downloadUrls.length} 个文件的下载`) + message.success(`成功下载 ${downloadUrls.length} 个文件`) } catch (error) { message.destroy() message.error('下载失败,请稍后重试') diff --git a/frontend/app/web-gold/src/views/system/task-management/mix-task/index.vue b/frontend/app/web-gold/src/views/system/task-management/mix-task/index.vue index 7af45028a0..a47c3e057e 100644 --- a/frontend/app/web-gold/src/views/system/task-management/mix-task/index.vue +++ b/frontend/app/web-gold/src/views/system/task-management/mix-task/index.vue @@ -50,10 +50,37 @@ :row-key="record => record.id" :pagination="paginationConfig" :expanded-row-keys="expandedRowKeys" + :row-selection="rowSelection" :scroll="{ x: 'max-content' }" @change="handleTableChange" @expandedRowsChange="handleExpandedRowsChange" > + + +