From 0d03699fcf3a922e296e9144402c9dc510abf3f6 Mon Sep 17 00:00:00 2001 From: i548450 Date: Tue, 9 Jun 2026 11:27:39 +0800 Subject: [PATCH] =?UTF-8?q?refactor(sse):=20=E6=94=B9=E7=94=A8=E5=8E=9F?= =?UTF-8?q?=E7=94=9F=20EventSource=20+=20=E4=BA=8B=E4=BB=B6=E6=80=BB?= =?UTF-8?q?=E7=BA=BF,=E6=94=AF=E6=8C=81=E5=A4=9A=20event=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 utils/sseEventBus.ts mitt 单例 - sse.ts 从 useEventSource 改为原生 EventSource,显式 addEventListener - 'message' event 沿用旧通知行为(noticeStore + ElNotification) - FORWARD_EVENTS(目前 customerservice)转发到事件总线供业务模块订阅 --- src/utils/sse.ts | 69 +++++++++++++++++++++++++++------------- src/utils/sseEventBus.ts | 21 ++++++++++++ 2 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 src/utils/sseEventBus.ts diff --git a/src/utils/sse.ts b/src/utils/sse.ts index 059c8f82..5669c477 100644 --- a/src/utils/sse.ts +++ b/src/utils/sse.ts @@ -1,42 +1,67 @@ import { getToken } from '@/utils/auth'; import { ElNotification } from 'element-plus'; import { useNoticeStore } from '@/store/modules/notice'; +import { getSseEventBus } from '@/utils/sseEventBus'; + +// Business-level SSE event names forwarded to the global event bus. +// Feature modules subscribe via getSseEventBus().on('xxx', handler). +const FORWARD_EVENTS = ['customerservice']; + +const MAX_RETRIES = 5; +const RETRY_DELAY = 5000; + +let eventSource: EventSource | null = null; +let retries = 0; -// 初始化 export const initSSE = (url: any) => { if (import.meta.env.VITE_APP_SSE === 'false') { return; } + connect(url); +}; - url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID; - const { data, error } = useEventSource(url, [], { - autoReconnect: { - retries: 5, - delay: 5000, - onFailed() { - console.log('Failed to connect after 5 retries'); - } - } - }); +function connect(url: string) { + const fullUrl = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID; + eventSource = new EventSource(fullUrl); - watch(error, () => { - console.log('SSE connection error:', error.value); - error.value = null; - }); - - watch(data, () => { - if (!data.value) return; + // Legacy "message" event: keep existing notification behavior + eventSource.addEventListener('message', (e: MessageEvent) => { + if (!e.data) return; useNoticeStore().addNotice({ - message: data.value, + message: e.data, read: false, time: new Date().toLocaleString() }); ElNotification({ title: '消息', - message: data.value, + message: e.data, type: 'success', duration: 3000 }); - data.value = null; }); -}; + + // Business events: forward to global bus, feature modules subscribe themselves + const bus = getSseEventBus(); + FORWARD_EVENTS.forEach((name) => { + eventSource!.addEventListener(name, (e: MessageEvent) => { + bus.emit(name, e.data); + }); + }); + + eventSource.onopen = () => { + retries = 0; + console.log('SSE connected'); + }; + + eventSource.onerror = (err) => { + console.log('SSE connection error:', err); + eventSource?.close(); + eventSource = null; + if (retries < MAX_RETRIES) { + retries += 1; + setTimeout(() => connect(url), RETRY_DELAY); + } else { + console.log('SSE failed after', MAX_RETRIES, 'retries'); + } + }; +} diff --git a/src/utils/sseEventBus.ts b/src/utils/sseEventBus.ts new file mode 100644 index 00000000..9fea3314 --- /dev/null +++ b/src/utils/sseEventBus.ts @@ -0,0 +1,21 @@ +import mitt, { Emitter } from 'mitt'; + +/** + * SSE event bus events shape: protocol-level event name -> raw data string + * Consumers JSON.parse the payload themselves + */ +export type SseBusEvents = Record; + +let bus: Emitter | null = null; + +/** + * Lazily-initialized singleton event bus + * Used by sse.ts to forward business event names (e.g. "customerservice") + * to feature modules without creating a second EventSource + */ +export function getSseEventBus(): Emitter { + if (!bus) { + bus = mitt(); + } + return bus; +}