diff --git a/src/components/dialog/TransferQueueDialog.vue b/src/components/dialog/TransferQueueDialog.vue index adeb9b33..f947cb40 100644 --- a/src/components/dialog/TransferQueueDialog.vue +++ b/src/components/dialog/TransferQueueDialog.vue @@ -165,8 +165,9 @@ function handleCurrentFileProgressMessage(event: MessageEvent) { } // 使用优化的进度SSE连接 - 整体进度 +const overallProgressUrl = `${import.meta.env.VITE_API_BASE_URL}system/progress/filetransfer` const overallProgressSSE = useProgressSSE( - `${import.meta.env.VITE_API_BASE_URL}system/progress/filetransfer`, + overallProgressUrl, handleOverallProgressMessage, 'transfer-queue-overall-progress', progressActive, @@ -184,10 +185,14 @@ function startCurrentFileProgress(filePath: string) { if (filePath) { // filePath计算md5 const filePathMd5 = CryptoJS.MD5(filePath).toString() + // 使用包含文件路径的唯一监听器ID,避免SSE管理器复用连接导致的消息串流 + const uniqueListenerId = `transfer-queue-current-file-progress-${filePathMd5}` + const currentFileProgressUrl = `${import.meta.env.VITE_API_BASE_URL}system/progress/${filePathMd5}` + currentFileProgressSSE = useProgressSSE( - `${import.meta.env.VITE_API_BASE_URL}system/progress/${filePathMd5}`, + currentFileProgressUrl, handleCurrentFileProgressMessage, - 'transfer-queue-current-file-progress', + uniqueListenerId, progressActive, ) currentFileProgressSSE.start() diff --git a/src/composables/useBackgroundOptimization.ts b/src/composables/useBackgroundOptimization.ts index c425e5fa..5eedb81e 100644 --- a/src/composables/useBackgroundOptimization.ts +++ b/src/composables/useBackgroundOptimization.ts @@ -25,7 +25,8 @@ export function useBackgroundOptimization() { connectDelay?: number // 新增:连接延迟 }, ) => { - const manager = sseManagerSingleton.getManager(url, options) + // 使用独立的SSE管理器,确保每个监听器都有独立的连接 + const manager = sseManagerSingleton.getIndependentManager(url, listenerId, options) const isConnected = ref(false) onMounted(() => { @@ -101,7 +102,8 @@ export function useBackgroundOptimization() { delay: number = 3000, options?: Parameters[3], ) => { - const manager = sseManagerSingleton.getManager(url, options) + // 使用独立的SSE管理器,确保每个监听器都有独立的连接 + const manager = sseManagerSingleton.getIndependentManager(url, listenerId, options) onMounted(() => { setTimeout(() => { @@ -133,7 +135,8 @@ export function useBackgroundOptimization() { listenerId: string, isActive: Ref, ) => { - const manager = sseManagerSingleton.getManager(url, { + // 使用独立的SSE管理器,确保每个监听器都有独立的连接 + const manager = sseManagerSingleton.getIndependentManager(url, listenerId, { backgroundCloseDelay: 1000, // 进度SSE更快关闭 reconnectDelay: 1000, maxReconnectAttempts: 5, diff --git a/src/utils/sseManager.ts b/src/utils/sseManager.ts index 86a6706c..b74231ef 100644 --- a/src/utils/sseManager.ts +++ b/src/utils/sseManager.ts @@ -119,11 +119,12 @@ export class SSEManager { this.eventSource.onmessage = event => { // 分发消息给所有监听器 - this.listeners.forEach(listener => { + this.listeners.forEach((listener, listenerId) => { try { + // 为每个监听器提供独立的错误处理 listener(event) } catch (error) { - console.error('SSE: 监听器错误', error) + console.error(`SSE: 监听器错误 [${listenerId}]`, error) } }) } @@ -245,12 +246,37 @@ class SSEManagerSingleton { /** * 获取或创建SSE管理器 + * @param url SSE连接URL + * @param options SSE选项 + * @returns SSE管理器实例 */ getManager(url: string, options?: ConstructorParameters[1]): SSEManager { - if (!this.managers.has(url)) { - this.managers.set(url, new SSEManager(url, options)) + // 使用完整的URL作为key,确保不同路径的SSE连接不会复用 + const managerKey = url + if (!this.managers.has(managerKey)) { + this.managers.set(managerKey, new SSEManager(url, options)) } - return this.managers.get(url)! + return this.managers.get(managerKey)! + } + + /** + * 获取或创建独立的SSE管理器(为每个监听器创建独立连接) + * @param url SSE连接URL + * @param listenerId 监听器ID + * @param options SSE选项 + * @returns SSE管理器实例 + */ + getIndependentManager( + url: string, + listenerId: string, + options?: ConstructorParameters[1], + ): SSEManager { + // 使用URL + 监听器ID作为key,确保每个监听器都有独立的连接 + const managerKey = `${url}::${listenerId}` + if (!this.managers.has(managerKey)) { + this.managers.set(managerKey, new SSEManager(url, options)) + } + return this.managers.get(managerKey)! } /**