import { getMessageBox } from '@/api/system/message'; import type { MessageVO } from '@/api/system/message/types'; import { useUserStore } from '@/store/modules/user'; import { getToken } from '@/utils/auth'; import { ElNotification } from 'element-plus'; import { useNoticeStore } from '@/store/modules/notice'; import { isMessageRead } from '@/utils/message-read'; import { parsePushMessage, resolveNoticeGroup, resolveNoticeTitle, shouldAppendNotice } from '@/utils/push-message'; let closePushConnection: (() => void) | undefined; const formatNoticeTime = (timestamp?: number | string) => { const time = timestamp ? new Date(timestamp) : new Date(); return time.toLocaleString(); }; const appendNotice = (raw: string) => { const payload = parsePushMessage(raw); if (!shouldAppendNotice(payload)) { return; } const userId = useUserStore().userId; const title = resolveNoticeTitle(payload); useNoticeStore().addNotice({ messageId: payload.messageId, title, category: resolveNoticeGroup(payload), type: payload.type, source: payload.source, message: payload.message ?? '', content: payload.data?.noticeContent, data: payload.data, path: payload.path, read: isMessageRead(userId, payload.messageId), timestamp: payload.timestamp ?? Date.now(), time: formatNoticeTime(payload.timestamp) }); ElNotification({ title, message: payload.message ?? '', type: 'success', duration: 3000 }); }; const toNoticeItem = (item: MessageVO) => { const userId = useUserStore().userId; const timestamp = item.createTime ? new Date(item.createTime).getTime() : Date.now(); return { messageId: item.messageId, title: item.title, category: resolveNoticeGroup(item), type: item.type, source: item.source, message: item.message ?? '', content: item.content, data: item.data ?? null, path: item.path, read: isMessageRead(userId, item.messageId), timestamp, time: formatNoticeTime(timestamp) }; }; const buildSseUrl = (path: string) => { return `${import.meta.env.VITE_APP_BASE_API}${path}?Authorization=Bearer ${getToken()}&clientid=${import.meta.env.VITE_APP_CLIENT_ID}`; }; const buildWsUrl = (path: string) => { const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; return `${protocol}${window.location.host}${buildSseUrl(path)}`; }; const initSsePush = (url: string) => { const { data, error, close } = useEventSource(url, [], { autoReconnect: { retries: 5, delay: 5000, onFailed() { console.log('Failed to connect after 5 retries'); } } }); closePushConnection = close; watch(error, () => { console.log('SSE connection error:', error.value); error.value = null; }); watch(data, () => { if (!data.value) return; appendNotice(data.value); data.value = null; }); }; const initWsPush = (url: string) => { const { close } = useWebSocket(url, { autoReconnect: { retries: 3, delay: 1000, onFailed() { console.log('websocket重连失败'); } }, heartbeat: { message: 'ping', interval: 10000, pongTimeout: 2000 }, onConnected() { console.log('websocket已经连接'); }, onDisconnected() { console.log('websocket已经断开'); }, onMessage: (_, e) => { if (String(e.data) === 'pong') { return; } appendNotice(String(e.data)); } }); closePushConnection = close; }; export const initPush = () => { closePush(); if (import.meta.env.VITE_APP_MESSAGE_ENABLED === 'false') { return; } const path = import.meta.env.VITE_APP_MESSAGE_PATH || '/resource/message'; const transport = import.meta.env.VITE_APP_MESSAGE_TRANSPORT || 'sse'; if (transport.toLowerCase() === 'websocket') { initWsPush(buildWsUrl(path)); return; } initSsePush(buildSseUrl(path)); }; export const initMessageBox = async () => { if (import.meta.env.VITE_APP_MESSAGE_ENABLED === 'false') { useNoticeStore().clearNotice(); return; } const { data } = await getMessageBox(); const notices = [...(data?.systemList ?? []), ...(data?.noticeList ?? []), ...(data?.workflowList ?? [])].map( toNoticeItem ); useNoticeStore().setNotices(notices); }; export const closePush = () => { closePushConnection?.(); closePushConnection = undefined; };