Files
f9-web-ai-test/web/src/utils/notification.js
T
2026-10-08 10:43:59 +08:00

100 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}