diff --git a/src/components/dialog/TransferQueueDialog.vue b/src/components/dialog/TransferQueueDialog.vue index a07ae3b7..f4976a52 100644 --- a/src/components/dialog/TransferQueueDialog.vue +++ b/src/components/dialog/TransferQueueDialog.vue @@ -127,7 +127,7 @@ const progressSSE = useProgressSSE( `${import.meta.env.VITE_API_BASE_URL}system/progress/filetransfer`, handleProgressMessage, 'transfer-queue-progress', - progressActive + progressActive, ) // 使用SSE监听加载进度 @@ -166,6 +166,7 @@ onUnmounted(() => { :value="progressValue" color="primary" indeterminate + :height="2" /> {{ progressText }} diff --git a/src/composables/useBackgroundOptimization.ts b/src/composables/useBackgroundOptimization.ts index 61ae7f2a..c425e5fa 100644 --- a/src/composables/useBackgroundOptimization.ts +++ b/src/composables/useBackgroundOptimization.ts @@ -22,22 +22,38 @@ export function useBackgroundOptimization() { backgroundCloseDelay?: number reconnectDelay?: number maxReconnectAttempts?: number + connectDelay?: number // 新增:连接延迟 }, ) => { const manager = sseManagerSingleton.getManager(url, options) + const isConnected = ref(false) onMounted(() => { - manager.addMessageListener(listenerId, messageHandler) + // 延迟建立连接,确保组件完全挂载 + const connectDelay = options?.connectDelay || 100 + setTimeout(() => { + try { + manager.addMessageListener(listenerId, event => { + messageHandler(event) + isConnected.value = true + }) + } catch (error) { + console.error('SSE连接建立失败:', error) + } + }, connectDelay) }) onUnmounted(() => { manager.removeMessageListener(listenerId) + isConnected.value = false }) return { manager, readyState: () => manager.readyState, close: () => manager.removeMessageListener(listenerId), + isConnected, + forceReconnect: () => manager.forceReconnect(), } } diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index 90093612..034d3564 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -1079,6 +1079,7 @@ export default { program: 'Program', content: 'Content', refreshing: 'Refreshing', + initializing: 'Initializing', }, moduleTest: { normal: 'Normal', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 44f7e257..5ba7e4ee 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -1075,6 +1075,7 @@ export default { program: '程序', content: '内容', refreshing: '正在刷新', + initializing: '正在初始化', }, moduleTest: { normal: '正常', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index d7d9b78d..b41ae3f7 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -1074,6 +1074,7 @@ export default { program: '程序', content: '內容', refreshing: '正在刷新', + initializing: '正在初始化', }, moduleTest: { normal: '正常', diff --git a/src/utils/sseManager.ts b/src/utils/sseManager.ts index 3ab1fed8..1b375e92 100644 --- a/src/utils/sseManager.ts +++ b/src/utils/sseManager.ts @@ -14,6 +14,8 @@ export class SSEManager { reconnectDelay: number maxReconnectAttempts: number } + private reconnectAttempts = 0 + private isConnecting = false constructor(url: string, options: Partial = {}) { this.url = url @@ -21,7 +23,7 @@ export class SSEManager { backgroundCloseDelay: 5000, // 5秒后关闭后台连接 reconnectDelay: 3000, // 3秒后重连 maxReconnectAttempts: 3, - ...options + ...options, } this.setupVisibilityListener() @@ -44,15 +46,14 @@ export class SSEManager { private handleBackground() { this.isBackground = true - + // 延迟关闭SSE连接,避免频繁切换 if (this.backgroundCloseTimer) { clearTimeout(this.backgroundCloseTimer) } - + this.backgroundCloseTimer = window.setTimeout(() => { if (this.isBackground && this.eventSource) { - console.log('SSE: 后台关闭连接') this.eventSource.close() this.eventSource = null } @@ -61,51 +62,57 @@ export class SSEManager { private handleForeground() { this.isBackground = false - + // 清除后台关闭定时器 if (this.backgroundCloseTimer) { clearTimeout(this.backgroundCloseTimer) this.backgroundCloseTimer = null } - + // 立即重新建立连接 if (!this.eventSource || this.eventSource.readyState === EventSource.CLOSED) { - console.log('SSE: 前台恢复连接') this.reconnectSSE() } } private reconnectSSE(attemptCount = 0) { if (attemptCount >= this.options.maxReconnectAttempts) { - console.warn('SSE: 达到最大重连次数') return } + if (this.isConnecting) { + return + } + + this.isConnecting = true + this.reconnectAttempts = attemptCount + try { this.eventSource = new EventSource(this.url) - + this.eventSource.onopen = () => { - console.log('SSE: 连接已建立') + this.isConnecting = false + this.reconnectAttempts = 0 } - - this.eventSource.onerror = (error) => { - console.error('SSE: 连接错误', error) - + + this.eventSource.onerror = error => { + this.isConnecting = false + if (this.eventSource?.readyState === EventSource.CLOSED) { // 连接已关闭,尝试重连 if (this.reconnectTimer) { clearTimeout(this.reconnectTimer) } - + this.reconnectTimer = window.setTimeout(() => { if (!this.isBackground) { - this.reconnectSSE(attemptCount + 1) + this.reconnectSSE(this.reconnectAttempts + 1) } }, this.options.reconnectDelay) } } - - this.eventSource.onmessage = (event) => { + + this.eventSource.onmessage = event => { // 分发消息给所有监听器 this.listeners.forEach(listener => { try { @@ -115,9 +122,19 @@ export class SSEManager { } }) } - } catch (error) { - console.error('SSE: 创建连接失败', error) + this.isConnecting = false + + // 连接创建失败,尝试重连 + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer) + } + + this.reconnectTimer = window.setTimeout(() => { + if (!this.isBackground) { + this.reconnectSSE(this.reconnectAttempts + 1) + } + }, this.options.reconnectDelay) } } @@ -126,9 +143,9 @@ export class SSEManager { */ addMessageListener(id: string, listener: (event: MessageEvent) => void) { this.listeners.set(id, listener) - - // 如果还没有连接,现在建立连接 - if (!this.eventSource && !this.isBackground) { + + // 如果还没有连接且不在后台,现在建立连接 + if (!this.eventSource && !this.isBackground && !this.isConnecting) { this.reconnectSSE() } } @@ -138,7 +155,7 @@ export class SSEManager { */ removeMessageListener(id: string) { this.listeners.delete(id) - + // 如果没有监听器了,关闭连接 if (this.listeners.size === 0) { this.close() @@ -153,18 +170,20 @@ export class SSEManager { this.eventSource.close() this.eventSource = null } - + if (this.reconnectTimer) { clearTimeout(this.reconnectTimer) this.reconnectTimer = null } - + if (this.backgroundCloseTimer) { clearTimeout(this.backgroundCloseTimer) this.backgroundCloseTimer = null } - + this.listeners.clear() + this.isConnecting = false + this.reconnectAttempts = 0 } /** @@ -180,6 +199,37 @@ export class SSEManager { get connectionUrl(): string { return this.url } + + /** + * 强制重新连接 + */ + forceReconnect() { + this.close() + if (!this.isBackground) { + this.reconnectSSE() + } + } + + /** + * 检查是否有活跃的监听器 + */ + get hasActiveListeners(): boolean { + return this.listeners.size > 0 + } + + /** + * 获取当前重连次数 + */ + get currentReconnectAttempts(): number { + return this.reconnectAttempts + } + + /** + * 检查是否达到最大重连次数 + */ + get hasReachedMaxAttempts(): boolean { + return this.reconnectAttempts >= this.options.maxReconnectAttempts + } } /** @@ -218,4 +268,4 @@ class SSEManagerSingleton { } } -export const sseManagerSingleton = new SSEManagerSingleton() \ No newline at end of file +export const sseManagerSingleton = new SSEManagerSingleton() diff --git a/src/views/system/LoggingView.vue b/src/views/system/LoggingView.vue index ad8cfe5d..0acdc997 100644 --- a/src/views/system/LoggingView.vue +++ b/src/views/system/LoggingView.vue @@ -1,7 +1,7 @@