import { ref } from 'vue'; import * as signalR from '@microsoft/signalr'; import { getAccessToken } from './request'; import request from './request'; // 全局未读数量(layout 徽章 与 消息页共用) export const unreadCount = ref(0); let connection = null; const messageHandlers = []; const businessChangeHandlers = []; /** 加载未读数量 */ export async function loadUnreadCount() { try { const res = await request.get('/notification/unread-count'); unreadCount.value = res.data.count; } catch (e) {} } /** * 初始化 SignalR 通知连接(幂等,重复调用返回同一连接) * @param {Function} onMessage 收到新消息时的回调 (msg) => void */ export function initNotification(onMessage) { if (connection) { if (onMessage) messageHandlers.push(onMessage); return connection; } if (onMessage) messageHandlers.push(onMessage); connection = new signalR.HubConnectionBuilder() .withUrl('/hubs/notification', { accessTokenFactory: () => getAccessToken() || '' }) .withAutomaticReconnect() .configureLogging(signalR.LogLevel.Warning) .build(); connection.on('ReceiveNotification', (msg) => { unreadCount.value++; // 全局未读 +1 messageHandlers.forEach((h) => { try { h(msg); } catch (e) {} }); }); // 业务状态变更事件(多端同步:某端操作后,其它端刷新已打开的页面) connection.on('BusinessChanged', (e) => { businessChangeHandlers.forEach((h) => { try { h(e); } catch (err) {} }); }); connection.start().catch(() => {}); return connection; } /** * 订阅业务状态变更事件(用于多端同步刷新)。 * @param {Function} handler (e) => void,e 含 businessType / businessId / action */ export function onBusinessChanged(handler) { if (handler) businessChangeHandlers.push(handler); initNotification(); // 确保连接已建立(幂等) } /** * 打开消息:标记已读 + 跳转到业务页面(消息自带 routePath 时)。 * @param {Object} msg 消息对象(含 id/readStatus/routePath/category) * @param {Object} router vue-router 实例 * @returns {boolean} 是否发生了页面跳转 */ export async function openMessage(msg, router) { // 待办消息(category=1)点击"去处理"不标记已读,保持未读提醒; // 只有真正完成待办后(后端完成待办时会标记已读)才消失 if (msg.readStatus === 0 && msg.category !== 1) { try { await request.put(`/notification/messages/${msg.id}/read`); msg.readStatus = 1; loadUnreadCount(); } catch (e) {} } if (msg.routePath) { router.push(msg.routePath); return true; } return false; } /** 停止连接(登出时调用) */ export function stopNotification() { if (connection) { connection.stop().catch(() => {}); connection = null; } messageHandlers.length = 0; unreadCount.value = 0; } export function getNotificationConnection() { return connection; }