import { defineStore } from "pinia"; import { ref } from "vue"; /** * WebSocket Store(浏览器端) * 与商家端 @/store/websocket 消息格式一致,用于分享动态、聊天等 */ export const useWebSocketStore = defineStore("websocket", () => { const socket = ref(null); const isConnected = ref(false); const isConnecting = ref(false); const lastConnectedUrl = ref(""); // 消息订阅(用于聊天等) const messageHandlers = new Map void>>(); const connect = (url: string): Promise => { if (isConnected.value && lastConnectedUrl.value === url) { return Promise.resolve(true); } if (socket.value) { try { socket.value.close(); } catch (e) { console.warn("关闭旧连接失败:", e); } socket.value = null; isConnected.value = false; } isConnecting.value = true; lastConnectedUrl.value = url; return new Promise(resolve => { try { const ws = new WebSocket(url); socket.value = ws; ws.onopen = () => { isConnected.value = true; isConnecting.value = false; resolve(true); }; ws.onmessage = (event: MessageEvent) => { try { const message = JSON.parse(event.data); const category = message.category || "message"; // 按 category 分发 const handlers = messageHandlers.get(category); if (handlers?.length) { handlers.forEach(cb => cb(message)); } // 兼容:若后端推送的 category 不是 "message" 但明显是聊天消息,也派发给 message 订阅者(解决业主发消息不实时更新) const isChatLike = category !== "message" && (message.senderId != null || message.receiverId != null) && (message.text != null || message.content != null || message.type != null); if (isChatLike) { const messageHandlersList = messageHandlers.get("message"); if (messageHandlersList?.length) { messageHandlersList.forEach(cb => cb(message)); } } } catch (_) {} }; ws.onclose = () => { isConnected.value = false; isConnecting.value = false; socket.value = null; }; ws.onerror = () => { isConnected.value = false; isConnecting.value = false; resolve(false); }; } catch (e) { console.error("WebSocket 连接异常:", e); isConnecting.value = false; resolve(false); } }); }; /** 订阅消息(返回取消订阅函数) */ const subscribe = (type: string, callback: (msg: any) => void) => { if (!messageHandlers.has(type)) { messageHandlers.set(type, []); } messageHandlers.get(type)!.push(callback); return () => { const handlers = messageHandlers.get(type) || []; messageHandlers.set( type, handlers.filter(h => h !== callback) ); }; }; const sendMessage = (data: Record): Promise => { return new Promise(resolve => { if (!isConnected.value || !socket.value || socket.value.readyState !== WebSocket.OPEN) { console.warn("WebSocket 未连接,无法发送消息"); resolve(false); return; } try { const message = JSON.stringify(data); socket.value.send(message); resolve(true); } catch (e) { console.error("消息发送异常:", e); resolve(false); } }); }; const disconnect = () => { if (socket.value) { try { socket.value.close(); } catch (_) {} socket.value = null; } isConnected.value = false; isConnecting.value = false; lastConnectedUrl.value = ""; messageHandlers.clear(); }; return { socket, isConnected, isConnecting, lastConnectedUrl, connect, sendMessage, disconnect, subscribe }; });