This commit is contained in:
Zy
2026-09-20 08:57:53 +08:00
parent 292ee1a6dd
commit f6a7eb1b4e
41 changed files with 864 additions and 608 deletions

View File

@@ -1,15 +1,40 @@
import { getToken } from '@/utils/auth';
import { ElNotification } from 'element-plus';
import { useNoticeStore } from '@/store/modules/notice';
import { useEventSource } from '@vueuse/core';
import { watch } from 'vue';
// 初始化
export const initSSE = (url: any) => {
// 全局单例保存SSE实例,防止多次创建
let eventSourceInstance: ReturnType<typeof useEventSource> | null = null;
let stopWatchError: (() => void) | null = null;
let stopWatchData: (() => void) | null = null;
// 关闭SSE、清理监听
export const closeSSE = () => {
if (eventSourceInstance) {
eventSourceInstance.close();
eventSourceInstance = null;
}
// 销毁watch
stopWatchError?.();
stopWatchData?.();
stopWatchError = null;
stopWatchData = null;
};
// 初始化SSE
export const initSSE = (url: string) => {
if (import.meta.env.VITE_APP_SSE === 'false') {
return;
}
// 关键:新建之前先关闭旧连接!
closeSSE();
url = url + '?Authorization=Bearer ' + getToken() + '&clientid=' + import.meta.env.VITE_APP_CLIENT_ID;
const { data, error } = useEventSource(url, [], {
const token = getToken();
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
const sseUrl = url + '?Authorization=Bearer ' + token + '&clientid=' + clientId;
eventSourceInstance = useEventSource(sseUrl, [], {
autoReconnect: {
retries: 5,
delay: 5000,
@@ -19,14 +44,16 @@ export const initSSE = (url: any) => {
}
});
watch(error, () => {
const { data, error } = eventSourceInstance;
stopWatchError = watch(error, () => {
console.log('SSE connection error:', error.value);
error.value = null;
// error.value = null; // 不要手动覆盖,会干扰useEventSource内部状态
});
watch(data, () => {
stopWatchData = watch(data, () => {
if (!data.value) return;
const notice = tryParseJson(data.value);
const notice = tryParseJson(data.value as string);
if (typeof notice === 'string') {
useNoticeStore().addNotice({
message: notice,
@@ -42,7 +69,6 @@ export const initSSE = (url: any) => {
data.value = null;
return;
} else {
// 此处 notice 类型为 Record<string, unknown>,安全取出属性
const title = typeof notice.title === 'string' ? notice.title : '消息';
const message = typeof notice.message === 'string' ? notice.message : '';
const type = typeof notice.type === 'string' ? notice.type : 'info';
@@ -75,7 +101,7 @@ function tryParseJson(str: string): string | Record<string, unknown> {
if (trimStr === '') return str;
try {
const parsed = JSON.parse(trimStr);
// 只有"纯对象"才返回对象,数组/null/基础值等统一当作字符串处理
// 只有纯对象才返回对象,数组/null/基础值等统一当作字符串处理
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
return parsed as Record<string, unknown>;
}