up. ws update.
This commit is contained in:
parent
9afa5e5583
commit
98cb8ee0aa
@ -16,18 +16,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, inject} from 'vue';
|
import { computed } from 'vue';
|
||||||
import {useUserStore} from "@/store/modules/user";
|
import { useUserStore } from '@/store/modules/user';
|
||||||
import { ConnectionStatus} from "@/plugins/websocket/type";
|
import { WsConnectionStatus, wsInstance } from '@/plugins/websocket';
|
||||||
import { websocketInstance } from "@/plugins/websocket/instance";
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
// const visible = ref(false);
|
// const visible = ref(false);
|
||||||
const visible = computed<boolean>(() => {
|
const visible = computed<boolean>(() => {
|
||||||
return (
|
return (
|
||||||
websocketInstance.connectionStatus.value != ConnectionStatus.CONNECTED &&
|
wsInstance.connectionStatus.value != WsConnectionStatus.CONNECTED &&
|
||||||
userStore.info
|
userStore.info
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -7,8 +7,7 @@ import DictData from '@/components/DictData/index.vue';
|
|||||||
import i18n from './i18n';
|
import i18n from './i18n';
|
||||||
import installer from './as-needed';
|
import installer from './as-needed';
|
||||||
import { iconsInstaller } from '@/components/IconSelect/util';
|
import { iconsInstaller } from '@/components/IconSelect/util';
|
||||||
import WebSocketPlugin from '@/plugins/websocket';
|
import { WsConfig, WsPlugin } from '@/plugins/websocket';
|
||||||
import type { WebSocketConfig } from '@/plugins/websocket/type';
|
|
||||||
import 'element-plus/theme-chalk/display.css';
|
import 'element-plus/theme-chalk/display.css';
|
||||||
import 'ele-admin-plus/es/style/nprogress.scss';
|
import 'ele-admin-plus/es/style/nprogress.scss';
|
||||||
import './styles/themes/rounded.scss';
|
import './styles/themes/rounded.scss';
|
||||||
@ -19,14 +18,14 @@ import './styles/index.scss';
|
|||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
// WebSocket配置
|
// WebSocket配置
|
||||||
const websocketConfig: Partial<WebSocketConfig> = {
|
const websocketConfig: Partial<WsConfig> = {
|
||||||
url: 'ws://139.155.146.146:19980', // 你的WebSocket服务器地址
|
url: 'ws://139.155.146.146:19980', // 你的WebSocket服务器地址
|
||||||
reconnectAttempts: 10,
|
reconnectAttempts: 10,
|
||||||
reconnectDelay: 5000,
|
reconnectDelay: 5000,
|
||||||
autoConnect: true // 应用启动时自动连接
|
autoConnect: true // 应用启动时自动连接
|
||||||
};
|
};
|
||||||
// 安装WebSocket插件
|
// 安装WebSocket插件
|
||||||
app.use(WebSocketPlugin, {
|
app.use(WsPlugin, {
|
||||||
globalConfig: websocketConfig
|
globalConfig: websocketConfig
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
57
z_ele/src/plugins/websocket/core/event-manager.ts
Normal file
57
z_ele/src/plugins/websocket/core/event-manager.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { WsEvent, WsEventContext, WsEventListener } from '../types';
|
||||||
|
import { generateGUID } from '@/utils/common';
|
||||||
|
import { wsInstance } from './instance';
|
||||||
|
|
||||||
|
export interface WsEventManager {
|
||||||
|
listeners: Record<string, WsEventListener[]>;
|
||||||
|
subscribe(event: WsEvent, handler: Function): WsEventContext;
|
||||||
|
unsubscribe(event: WsEvent, listenerId: string): void;
|
||||||
|
emit(event: WsEvent, data?: any): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WsEventManagerImpl implements WsEventManager {
|
||||||
|
listeners: Record<string, WsEventListener[]> = {};
|
||||||
|
|
||||||
|
subscribe(event: WsEvent, handler: Function): WsEventContext {
|
||||||
|
if (!this.listeners[event]) this.listeners[event] = [];
|
||||||
|
|
||||||
|
const listenerId = generateGUID();
|
||||||
|
const listener: WsEventListener = { handler, id: listenerId };
|
||||||
|
this.listeners[event].push(listener);
|
||||||
|
|
||||||
|
// 立即触发已连接事件
|
||||||
|
if (event === WsEvent.CONNECTED && wsInstance?.isConnected.value) {
|
||||||
|
handler({
|
||||||
|
id: listenerId,
|
||||||
|
remove: () => this.unsubscribe(event, listenerId)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: listenerId,
|
||||||
|
remove: () => this.unsubscribe(event, listenerId)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe(event: WsEvent, listenerId: string): void {
|
||||||
|
if (!this.listeners[event]) return;
|
||||||
|
this.listeners[event] = this.listeners[event].filter(l => l.id !== listenerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(event: WsEvent, data?: any): void {
|
||||||
|
console.debug(`[WS Event] Emitting: ${event}`);
|
||||||
|
const listeners = this.listeners[event] || [];
|
||||||
|
|
||||||
|
// 安全遍历
|
||||||
|
listeners.forEach((listener) => {
|
||||||
|
const context: WsEventContext = {
|
||||||
|
id: listener.id,
|
||||||
|
remove: () => this.unsubscribe(event, listener.id)
|
||||||
|
};
|
||||||
|
listener.handler(context, wsInstance, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单例事件管理器
|
||||||
|
export const wsEventManager = new WsEventManagerImpl();
|
||||||
146
z_ele/src/plugins/websocket/core/instance.ts
Normal file
146
z_ele/src/plugins/websocket/core/instance.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
import {
|
||||||
|
WsConfig,
|
||||||
|
WsInstance,
|
||||||
|
WsConnectionStatus,
|
||||||
|
WsMessageType,
|
||||||
|
WsMessage,
|
||||||
|
WsEvent,
|
||||||
|
WsSendEventType
|
||||||
|
} from '../types';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { wsEventManager } from './event-manager';
|
||||||
|
|
||||||
|
// 创建WebSocket实例
|
||||||
|
export function createWsInstance(config: WsConfig): WsInstance {
|
||||||
|
// 响应式状态
|
||||||
|
const socket = ref<WebSocket | null>(null);
|
||||||
|
const isConnected = ref(false);
|
||||||
|
const isConnecting = ref(false);
|
||||||
|
const reconnectCount = ref(0);
|
||||||
|
const connectionStatus = ref<WsConnectionStatus>(
|
||||||
|
WsConnectionStatus.DISCONNECTED
|
||||||
|
);
|
||||||
|
const messages = ref<WsMessage[]>([]);
|
||||||
|
|
||||||
|
// 计算状态类
|
||||||
|
const statusClass = computed(
|
||||||
|
() => `status-${connectionStatus.value.toLowerCase()}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// 内部方法
|
||||||
|
const addMessage = (content: string, type: WsMessageType) => {
|
||||||
|
messages.value.push({ content, type, timestamp: new Date() });
|
||||||
|
};
|
||||||
|
|
||||||
|
const addSystemMessage = (content: string) =>
|
||||||
|
addMessage(content, WsMessageType.SYSTEM);
|
||||||
|
|
||||||
|
// 事件处理器
|
||||||
|
const handleOpen = (e: Event) => {
|
||||||
|
isConnected.value = true;
|
||||||
|
isConnecting.value = false;
|
||||||
|
connectionStatus.value = WsConnectionStatus.CONNECTED;
|
||||||
|
reconnectCount.value = 0;
|
||||||
|
addSystemMessage('Connection established');
|
||||||
|
wsEventManager.emit(WsEvent.CONNECTED, e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMessage = (e: MessageEvent) =>
|
||||||
|
addMessage(e.data, WsMessageType.INCOMING);
|
||||||
|
|
||||||
|
const handleError = (e: Event) => {
|
||||||
|
isConnecting.value = false;
|
||||||
|
connectionStatus.value = WsConnectionStatus.ERROR;
|
||||||
|
addSystemMessage(`Error: ${e.type}`);
|
||||||
|
!isConnected.value && attemptReconnect();
|
||||||
|
console.log(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = (e: CloseEvent) => {
|
||||||
|
isConnected.value = false;
|
||||||
|
isConnecting.value = false;
|
||||||
|
connectionStatus.value = WsConnectionStatus.DISCONNECTED;
|
||||||
|
addSystemMessage(`Connection closed: ${e.code} ${e.reason || ''}`);
|
||||||
|
e.code !== 1000 && attemptReconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重连逻辑
|
||||||
|
const attemptReconnect = () => {
|
||||||
|
if (reconnectCount.value >= config.reconnectAttempts) {
|
||||||
|
return addSystemMessage('Max reconnect attempts reached');
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnectCount.value++;
|
||||||
|
addSystemMessage(
|
||||||
|
`Reconnecting (${reconnectCount.value}/${config.reconnectAttempts})...`
|
||||||
|
);
|
||||||
|
setTimeout(connectSocket, config.reconnectDelay);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 公开方法
|
||||||
|
const connectSocket = () => {
|
||||||
|
if (isConnected.value || isConnecting.value) return;
|
||||||
|
|
||||||
|
isConnecting.value = true;
|
||||||
|
connectionStatus.value = WsConnectionStatus.CONNECTING;
|
||||||
|
addSystemMessage('Connecting...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.value = new WebSocket(config.url);
|
||||||
|
|
||||||
|
socket.value.onopen = handleOpen;
|
||||||
|
socket.value.onmessage = handleMessage;
|
||||||
|
socket.value.onerror = handleError;
|
||||||
|
socket.value.onclose = handleClose;
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error as Event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const disconnectSocket = () => {
|
||||||
|
socket.value?.close();
|
||||||
|
socket.value = null;
|
||||||
|
isConnected.value = false;
|
||||||
|
isConnecting.value = false;
|
||||||
|
connectionStatus.value = WsConnectionStatus.DISCONNECTED;
|
||||||
|
reconnectCount.value = 0;
|
||||||
|
addSystemMessage('Connection closed');
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendMessage = (event: WsSendEventType, data: any) => {
|
||||||
|
if (!socket.value || !isConnected.value || !data) return;
|
||||||
|
|
||||||
|
const payload = JSON.stringify({ event, data });
|
||||||
|
socket.value.send(payload);
|
||||||
|
addMessage(payload, WsMessageType.OUTGOING);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearMessages = () => (messages.value = []);
|
||||||
|
|
||||||
|
// 自动连接
|
||||||
|
console.log('autoConnect->');
|
||||||
|
config.autoConnect && connectSocket();
|
||||||
|
|
||||||
|
return {
|
||||||
|
isConnected,
|
||||||
|
isConnecting,
|
||||||
|
connectionStatus,
|
||||||
|
messages,
|
||||||
|
statusClass,
|
||||||
|
events: wsEventManager,
|
||||||
|
|
||||||
|
connectSocket,
|
||||||
|
disconnectSocket,
|
||||||
|
sendMessage,
|
||||||
|
clearMessages
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全局实例
|
||||||
|
export let wsInstance: WsInstance | null = null;
|
||||||
|
|
||||||
|
// 初始化方法
|
||||||
|
export function initWs(config: WsConfig): WsInstance {
|
||||||
|
return (wsInstance = wsInstance || createWsInstance(config));
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
// plugins/websocket
|
|
||||||
import { App, Plugin } from 'vue';
|
|
||||||
import {
|
|
||||||
WebSocketConfig,
|
|
||||||
WebSocketPluginOptions
|
|
||||||
} from '@/plugins/websocket/type';
|
|
||||||
import { initWebSocket } from '@/plugins/websocket/instance';
|
|
||||||
|
|
||||||
// 插件安装函数
|
|
||||||
const WebSocketPlugin: Plugin = {
|
|
||||||
install(app: App, options: WebSocketPluginOptions = {}) {
|
|
||||||
const { globalConfig = {} } = options;
|
|
||||||
|
|
||||||
// 合并默认配置和全局配置
|
|
||||||
const defaultConfig: WebSocketConfig = {
|
|
||||||
url: 'wss://echo.websocket.org',
|
|
||||||
protocols: '',
|
|
||||||
reconnectAttempts: 5,
|
|
||||||
reconnectDelay: 3000,
|
|
||||||
autoConnect: false,
|
|
||||||
...globalConfig
|
|
||||||
};
|
|
||||||
// 创建WebSocket实例
|
|
||||||
initWebSocket(defaultConfig);
|
|
||||||
console.debug('initWebSocket.', defaultConfig);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default WebSocketPlugin;
|
|
||||||
@ -1,171 +0,0 @@
|
|||||||
import {
|
|
||||||
ConnectionStatus, MessageType,
|
|
||||||
PaWebSocket,
|
|
||||||
SendEventType,
|
|
||||||
WebSocketConfig,
|
|
||||||
WebSocketMessage,
|
|
||||||
WsEvent
|
|
||||||
} from '@/plugins/websocket/type';
|
|
||||||
import { subscriptionManager } from '@/plugins/websocket/subscriber';
|
|
||||||
import { computed, ref } from 'vue';
|
|
||||||
|
|
||||||
// 创建WebSocket实例的函数
|
|
||||||
function createWebSocket(config: WebSocketConfig) {
|
|
||||||
// 响应式数据
|
|
||||||
const socket = ref<WebSocket | null>(null);
|
|
||||||
const isConnected = ref(false);
|
|
||||||
const isConnecting = ref(false);
|
|
||||||
const reconnectCount = ref(0);
|
|
||||||
const connectionStatus = ref(ConnectionStatus.DISCONNECTED);
|
|
||||||
const messages = ref<WebSocketMessage[]>([]);
|
|
||||||
|
|
||||||
// 计算属性
|
|
||||||
const statusClass = computed(() => {
|
|
||||||
switch (connectionStatus.value) {
|
|
||||||
case ConnectionStatus.CONNECTED:
|
|
||||||
return 'status-connected';
|
|
||||||
case ConnectionStatus.CONNECTING:
|
|
||||||
return 'status-connecting';
|
|
||||||
default:
|
|
||||||
return 'status-disconnected';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 方法
|
|
||||||
const connect = () => {
|
|
||||||
if (isConnected.value || isConnecting.value) return;
|
|
||||||
|
|
||||||
isConnecting.value = true;
|
|
||||||
connectionStatus.value = ConnectionStatus.CONNECTING;
|
|
||||||
addSystemMessage('正在连接...');
|
|
||||||
|
|
||||||
try {
|
|
||||||
socket.value = new WebSocket(
|
|
||||||
config.url,
|
|
||||||
config.protocols ? config.protocols.split(',') : undefined
|
|
||||||
);
|
|
||||||
|
|
||||||
socket.value.onopen = onOpen;
|
|
||||||
socket.value.onmessage = onMessage;
|
|
||||||
socket.value.onerror = onError;
|
|
||||||
socket.value.onclose = onClose;
|
|
||||||
} catch (error) {
|
|
||||||
onError(error as Event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const disconnect = () => {
|
|
||||||
if (socket.value) {
|
|
||||||
socket.value.close();
|
|
||||||
socket.value = null;
|
|
||||||
}
|
|
||||||
isConnected.value = false;
|
|
||||||
isConnecting.value = false;
|
|
||||||
connectionStatus.value = ConnectionStatus.DISCONNECTED;
|
|
||||||
reconnectCount.value = 0;
|
|
||||||
addSystemMessage('连接已关闭');
|
|
||||||
};
|
|
||||||
|
|
||||||
const reconnect = () => {
|
|
||||||
if (reconnectCount.value < config.reconnectAttempts) {
|
|
||||||
reconnectCount.value++;
|
|
||||||
addSystemMessage(
|
|
||||||
`尝试重新连接 (${reconnectCount.value}/${config.reconnectAttempts})...`
|
|
||||||
);
|
|
||||||
setTimeout(() => connect(), config.reconnectDelay);
|
|
||||||
} else {
|
|
||||||
addSystemMessage('已达到最大重连次数,连接终止');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const sendMessage = (event: SendEventType, data: any) => {
|
|
||||||
if (socket.value && isConnected.value && data) {
|
|
||||||
const message: string = JSON.stringify({ event, data });
|
|
||||||
socket.value.send(message);
|
|
||||||
/*
|
|
||||||
* 扔进最近的消息记录
|
|
||||||
*/
|
|
||||||
addMessage(message, MessageType.OUTGOING);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const clearMessages = () => {
|
|
||||||
messages.value = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const addMessage = (content: string, type: MessageType) => {
|
|
||||||
messages.value.push({
|
|
||||||
content,
|
|
||||||
type,
|
|
||||||
timestamp: new Date()
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const addSystemMessage = (content: string) => {
|
|
||||||
addMessage(content, MessageType.SYSTEM);
|
|
||||||
};
|
|
||||||
|
|
||||||
// WebSocket事件处理
|
|
||||||
const onOpen = (e: Event) => {
|
|
||||||
isConnected.value = true;
|
|
||||||
isConnecting.value = false;
|
|
||||||
connectionStatus.value = ConnectionStatus.CONNECTED;
|
|
||||||
reconnectCount.value = 0;
|
|
||||||
addSystemMessage('连接已建立');
|
|
||||||
// 触发连接成功事件
|
|
||||||
subscriptionManager.trigger(WsEvent.CONNECTED, e);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMessage = (event: MessageEvent) => {
|
|
||||||
addMessage(event.data, MessageType.INCOMING);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onError = (error: Event) => {
|
|
||||||
isConnecting.value = false;
|
|
||||||
connectionStatus.value = ConnectionStatus.ERROR;
|
|
||||||
addSystemMessage(`错误: ${error.type}`);
|
|
||||||
|
|
||||||
if (!isConnected.value) {
|
|
||||||
reconnect();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClose = (event: CloseEvent) => {
|
|
||||||
isConnected.value = false;
|
|
||||||
isConnecting.value = false;
|
|
||||||
connectionStatus.value = ConnectionStatus.DISCONNECTED;
|
|
||||||
addSystemMessage(`连接关闭: ${event.code} ${event.reason || ''}`);
|
|
||||||
|
|
||||||
if (event.code !== 1000) {
|
|
||||||
reconnect();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 自动连接(如果配置了)
|
|
||||||
if (config.autoConnect) {
|
|
||||||
connect();
|
|
||||||
}
|
|
||||||
return <PaWebSocket>{
|
|
||||||
// 状态
|
|
||||||
isConnected,
|
|
||||||
isConnecting,
|
|
||||||
connectionStatus,
|
|
||||||
messages,
|
|
||||||
statusClass,
|
|
||||||
// 方法
|
|
||||||
connect,
|
|
||||||
disconnect,
|
|
||||||
sendMessage,
|
|
||||||
clearMessages,
|
|
||||||
subscription: subscriptionManager
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export let websocketInstance: PaWebSocket | null = null;
|
|
||||||
|
|
||||||
export function initWebSocket(config: WebSocketConfig): PaWebSocket {
|
|
||||||
if (!websocketInstance) {
|
|
||||||
websocketInstance = createWebSocket(config);
|
|
||||||
}
|
|
||||||
return websocketInstance;
|
|
||||||
}
|
|
||||||
21
z_ele/src/plugins/websocket/plugin.ts
Normal file
21
z_ele/src/plugins/websocket/plugin.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { App, Plugin } from 'vue';
|
||||||
|
import { WsPluginOptions, WsConfig } from './types';
|
||||||
|
import { initWs } from './core/instance';
|
||||||
|
|
||||||
|
const WsPlugin: Plugin = {
|
||||||
|
install(app: App, options: WsPluginOptions = {}) {
|
||||||
|
const mergedConfig: WsConfig = {
|
||||||
|
url: 'wss://echo.websocket.org',
|
||||||
|
protocols: 'chat',
|
||||||
|
reconnectAttempts: 5,
|
||||||
|
reconnectDelay: 3000,
|
||||||
|
autoConnect: false,
|
||||||
|
...options.globalConfig
|
||||||
|
};
|
||||||
|
// 初始化并挂载到app
|
||||||
|
console.log('初始化ws', mergedConfig);
|
||||||
|
app.config.globalProperties.$ws = initWs(mergedConfig);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WsPlugin;
|
||||||
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* 事件订阅管理器
|
|
||||||
* 用于统一管理WebSocket事件订阅与触发
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { WsEvent } from '@/plugins/websocket/type';
|
|
||||||
import { generateGUID } from '@/utils/common';
|
|
||||||
import { websocketInstance } from '@/plugins/websocket/instance';
|
|
||||||
|
|
||||||
// 重命名接口,使用更具描述性的名称
|
|
||||||
export interface EventListener {
|
|
||||||
handler: Function;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SubscriptionContext {
|
|
||||||
id: string;
|
|
||||||
destroy(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SubscriptionManager {
|
|
||||||
events: Record<string, EventListener[]>;
|
|
||||||
addListener(event: WsEvent, listener: Function): void;
|
|
||||||
removeListener(event: WsEvent, listenerId: string): void;
|
|
||||||
trigger(event: WsEvent, data: any): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubscriptionManagerImpl implements SubscriptionManager {
|
|
||||||
events: Record<string, EventListener[]> = {
|
|
||||||
// 全局事件名称定义
|
|
||||||
[WsEvent.CONNECTED]: []
|
|
||||||
};
|
|
||||||
addListener(event: WsEvent, listener: Function): void {
|
|
||||||
// 确保事件数组已初始化
|
|
||||||
if (!this.events[event]) {
|
|
||||||
this.events[event] = [];
|
|
||||||
}
|
|
||||||
const listenerId = generateGUID();
|
|
||||||
this.events[event].push({
|
|
||||||
handler: listener,
|
|
||||||
id: listenerId
|
|
||||||
});
|
|
||||||
// 部分一次性的事件(如果处于此事件,则直接触发)
|
|
||||||
if (event == WsEvent.CONNECTED) {
|
|
||||||
if (websocketInstance?.isConnected) {
|
|
||||||
this.trigger(event, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeListener(event: WsEvent, listenerId: string): void {
|
|
||||||
if (!this.events[event]) return;
|
|
||||||
|
|
||||||
this.events[event] = this.events[event].filter(
|
|
||||||
(listener) => listener.id !== listenerId
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger(event: WsEvent, data: any): void {
|
|
||||||
console.log('触发事件', event);
|
|
||||||
|
|
||||||
if (!this.events[event] || this.events[event].length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建副本以避免在迭代过程中修改原数组
|
|
||||||
const listeners = [...this.events[event]];
|
|
||||||
|
|
||||||
listeners.forEach((listener) => {
|
|
||||||
const context: SubscriptionContext = {
|
|
||||||
id: listener.id,
|
|
||||||
destroy: () => this.removeListener(event, listener.id)
|
|
||||||
};
|
|
||||||
|
|
||||||
listener.handler(context, websocketInstance, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建单例实例
|
|
||||||
export const subscriptionManager = new SubscriptionManagerImpl();
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
import type { Ref } from 'vue';
|
|
||||||
import { SubscriptionManager } from '@/plugins/websocket/subscriber';
|
|
||||||
|
|
||||||
export enum WsEvent {
|
|
||||||
CONNECTED = 'CONNECTED' // websocket连接成功
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaWebSocket {
|
|
||||||
isConnected: Ref<boolean>;
|
|
||||||
connectionStatus: Ref<string>;
|
|
||||||
sendMessage: Function;
|
|
||||||
subscription: SubscriptionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SendEventType {
|
|
||||||
BIND_CONNECT_ID = 'bind_connect_id'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export enum ConnectionStatus {
|
|
||||||
CONNECTING = 'connecting',
|
|
||||||
CONNECTED = 'connected',
|
|
||||||
DISCONNECTED = 'disconnected',
|
|
||||||
ERROR = 'error'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum MessageType {
|
|
||||||
INCOMING = 'incoming',
|
|
||||||
OUTGOING = 'outgoing',
|
|
||||||
SYSTEM = 'system'
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebSocketMessage {
|
|
||||||
content: string;
|
|
||||||
type: MessageType;
|
|
||||||
timestamp: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebSocketConfig {
|
|
||||||
url: string;
|
|
||||||
protocols?: string;
|
|
||||||
reconnectAttempts: number;
|
|
||||||
reconnectDelay: number;
|
|
||||||
autoConnect?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插件选项接口
|
|
||||||
export interface WebSocketPluginOptions {
|
|
||||||
// 全局配置
|
|
||||||
globalConfig?: Partial<WebSocketConfig>;
|
|
||||||
}
|
|
||||||
65
z_ele/src/plugins/websocket/types.ts
Normal file
65
z_ele/src/plugins/websocket/types.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import type { Ref } from 'vue';
|
||||||
|
import { WsEventManager } from '@/plugins/websocket/core/event-manager';
|
||||||
|
|
||||||
|
export enum WsEvent {
|
||||||
|
CONNECTED = 'CONNECTED'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WsSendEventType {
|
||||||
|
BIND_CONNECT_ID = 'bind_connect_id'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WsConnectionStatus {
|
||||||
|
CONNECTING = 'connecting',
|
||||||
|
CONNECTED = 'connected',
|
||||||
|
DISCONNECTED = 'disconnected',
|
||||||
|
ERROR = 'error'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WsMessageType {
|
||||||
|
INCOMING = 'incoming',
|
||||||
|
OUTGOING = 'outgoing',
|
||||||
|
SYSTEM = 'system'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WsMessage {
|
||||||
|
content: string;
|
||||||
|
type: WsMessageType;
|
||||||
|
timestamp: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WsConfig {
|
||||||
|
url: string;
|
||||||
|
protocols?: string;
|
||||||
|
reconnectAttempts: number;
|
||||||
|
reconnectDelay: number;
|
||||||
|
autoConnect?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WsPluginOptions {
|
||||||
|
globalConfig?: Partial<WsConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WsEventListener {
|
||||||
|
handler: Function;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WsEventContext {
|
||||||
|
id: string;
|
||||||
|
remove(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WsInstance {
|
||||||
|
isConnected: Ref<boolean>;
|
||||||
|
isConnecting: Ref<boolean>;
|
||||||
|
connectionStatus: Ref<WsConnectionStatus>;
|
||||||
|
messages: Ref<WsMessage[]>;
|
||||||
|
statusClass: Ref<string>;
|
||||||
|
|
||||||
|
connectSocket: () => void;
|
||||||
|
disconnectSocket: () => void;
|
||||||
|
sendMessage: (event: WsSendEventType, data: any) => void;
|
||||||
|
clearMessages: () => void;
|
||||||
|
events: WsEventManager; // 重命名为更清晰的events
|
||||||
|
}
|
||||||
@ -9,10 +9,16 @@ import type { User } from '@/api/system/user/model';
|
|||||||
import type { Menu } from '@/api/system/menu/model';
|
import type { Menu } from '@/api/system/menu/model';
|
||||||
import type { DictionaryData } from '@/api/system/dictionary-data/model';
|
import type { DictionaryData } from '@/api/system/dictionary-data/model';
|
||||||
import { getUserInfo } from '@/api/layout';
|
import { getUserInfo } from '@/api/layout';
|
||||||
import { inject } from 'vue';
|
|
||||||
import { PaWebSocket, SendEventType, WsEvent } from '@/plugins/websocket/type';
|
|
||||||
import { getToken } from '@/utils/token-util';
|
import { getToken } from '@/utils/token-util';
|
||||||
import {getSubscriptionManager, SubscriptionContext, subscriptionManager} from "@/plugins/websocket/subscriber";
|
import {
|
||||||
|
WsEventContext,
|
||||||
|
wsEventManager,
|
||||||
|
WsEvent,
|
||||||
|
WsInstance,
|
||||||
|
WsSendEventType,
|
||||||
|
wsInstance
|
||||||
|
} from '@/plugins/websocket';
|
||||||
|
|
||||||
/** 直接指定菜单数据 */
|
/** 直接指定菜单数据 */
|
||||||
const USER_MENUS: Menu[] | null = null;
|
const USER_MENUS: Menu[] | null = null;
|
||||||
|
|
||||||
@ -69,19 +75,15 @@ export const useUserStore = defineStore('user', {
|
|||||||
);
|
);
|
||||||
this.setMenus(menus);
|
this.setMenus(menus);
|
||||||
|
|
||||||
console.log('管理器塞事件进去', inject('websocket'));
|
console.log('管理器塞事件进去');
|
||||||
subscriptionManager.addListener(
|
wsEventManager.subscribe(WsEvent.CONNECTED, (sub: WsEventContext) => {
|
||||||
WsEvent.CONNECTED,
|
console.log('事件执行, 绑定连接和用户关系');
|
||||||
(sub: SubscriptionContext, ws: PaWebSocket) => {
|
|
||||||
console.log('事件执行');
|
|
||||||
// 绑定用户到websocket的connect_id中
|
// 绑定用户到websocket的connect_id中
|
||||||
ws.sendMessage(SendEventType.BIND_CONNECT_ID, {
|
wsInstance.sendMessage(WsSendEventType.BIND_CONNECT_ID, {
|
||||||
token: getToken(),
|
token: getToken(),
|
||||||
userId: result.userId
|
userId: result.userId
|
||||||
});
|
});
|
||||||
// sub.destroy();
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
return { menus, homePath };
|
return { menus, homePath };
|
||||||
},
|
},
|
||||||
setClientState(value: any) {
|
setClientState(value: any) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user