From 9eaaba2d0a811b1bb3fac1195d406fc380a6c0c4 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 25 Jan 2024 11:06:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ws=20=E5=B0=81=E8=A3=85=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/ws-websocket.ts | 126 +++++++++++++++++++++--------- src/views/dashboard/cdr/index.vue | 23 +++++- vite.config.ts | 7 ++ 3 files changed, 118 insertions(+), 38 deletions(-) diff --git a/src/plugins/ws-websocket.ts b/src/plugins/ws-websocket.ts index 6c5b34a7..c956f20d 100644 --- a/src/plugins/ws-websocket.ts +++ b/src/plugins/ws-websocket.ts @@ -1,13 +1,19 @@ -import { sessionGet } from "@/utils/cache-session-utils"; +import { sessionGet } from '@/utils/cache-session-utils'; +import { getToken } from './auth-token'; +import { localGet } from '@/utils/cache-local-utils'; +import { CACHE_LOCAL_I18N } from '@/constants/cache-keys-constants'; +import { TOKEN_RESPONSE_FIELD } from '@/constants/token-constants'; /**连接参数类型 */ -export type TypeParams = { +export type OptionsType = { /**WebSocket服务器将响应的URL */ url?: string; + /**地址栏参数 */ + params?: Record; /**onopen事件的回调函数 */ onopen?: Function; /**message事件的回调函数 */ - onmessage: Function; + onmessage: (data: Record) => void; /**error事件的回调函数 */ onerror: Function; /**close事件的回调函数 */ @@ -41,7 +47,7 @@ export class WS { /**ws 实例 */ private ws: WebSocket | null = null; /**ws 连接参数 */ - private params: TypeParams | null = null; + private options: OptionsType | null = null; /**心跳调度器 */ private heartInterval: number = 0; /**重连定时器 */ @@ -51,87 +57,135 @@ export class WS { * 构造函数 * @param {object} params 构造函数参数 */ - constructor(params: TypeParams) { + constructor(options: OptionsType) { if (!window.WebSocket) { // 检测浏览器支持 console.error('抱歉! 浏览器不支持websocket'); return; } - this.params = params; - this.create(params); + this.options = options; + this.create(options); } /** * 创建链接 - * @param {object} params 连接参数 + * @param {object} options 连接参数 */ - public create(params: TypeParams) { + public create(options: OptionsType) { try { - if (!params.url) { + if (!options.url) { // 兼容旧前端可改配置文件 - const baseUrl = import.meta.env.PROD + const wsUrl = import.meta.env.PROD ? sessionGet('wsUrl') || import.meta.env.VITE_API_BASE_URL - : import.meta.env.VITE_API_BASE_URL; - params.url = `ws://${baseUrl}/ws`; + : '/socket'; + if (wsUrl.startsWith('ws')) { + options.url = `${wsUrl}/ws`; + } else if (wsUrl.startsWith('https')) { + options.url = `${wsUrl.replace('https', 'wss')}/ws`; + } else if (wsUrl.startsWith('http')) { + options.url = `${wsUrl.replace('http', 'ws')}/ws`; + } else { + const protocol = + window.location.protocol === 'https:' ? 'wss://' : 'ws://'; + options.url = `${protocol}${location.host}${wsUrl}/ws`; + } + + // 地址栏参数 + let params = options.params || {}; + // 设置 token + const token = getToken(); + if (token) { + params[TOKEN_RESPONSE_FIELD] = token; + } + // 多语言处理 + params['language'] = localGet(CACHE_LOCAL_I18N) || 'en_US'; + let paramStr = ''; + for (const key in params) { + const value = params[key]; + // 空字符或未定义的值不作为参数发送 + if (value === '' || value === undefined) continue; + paramStr += `&${encodeURIComponent(key)}=${encodeURIComponent( + value + )}`; + } + if (paramStr && paramStr.startsWith('&')) { + options.url = `${options.url}?${paramStr.substring(1)}`; + } } - const ws = new WebSocket(params.url); + const ws = new WebSocket(options.url, 'omc-ws'); // 用于指定连接成功后的回调函数。 ws.onopen = ev => { - if (params.heartTimer && params.heartTimer > 0) { - this.heartCheck(params.heartTimer); + if (options.heartTimer && options.heartTimer > 0) { + this.heartCheck(options.heartTimer); } - if (typeof params.onopen === 'function') { - params.onopen(ev); + if (typeof options.onopen === 'function') { + options.onopen(ev); } }; // 用于指定当从服务器接受到信息时的回调函数。 ws.onmessage = ev => { - if (typeof params.onmessage === 'function') { - params.onmessage(ev); + const data = ev.data; + // 解析文本消息 + if (ev.type === 'message') { + try { + const jsonData = JSON.parse(data); + if (typeof options.onmessage === 'function') { + options.onmessage(jsonData); + } + } catch (error) { + console.error('websocket 消息格式错误', error); + } } }; // 用于指定连接关闭后的回调函数。 ws.onclose = ev => { - if (typeof params.onclose === 'function') { - params.onclose(ev); + if (typeof options.onclose === 'function') { + options.onclose(ev); } }; // 用于指定连接失败后的回调函数。 ws.onerror = ev => { console.error('websocket 连接异常', ev); - if (typeof params.onerror === 'function') { - params.onerror(ev); + if (typeof options.onerror === 'function') { + options.onerror(ev); } - if (params.reconnectTimer && params.reconnectTimer > 0) { - this.reconnect(params.reconnectTimer); + if (options.reconnectTimer && options.reconnectTimer > 0) { + this.reconnect(options.reconnectTimer); } }; this.ws = ws; } catch (error) { - if (typeof params.onerror === 'function') { - params.onerror(error); + if (typeof options.onerror === 'function') { + options.onerror(error); } - if (params.reconnectTimer && params.reconnectTimer > 0) { - this.reconnect(params.reconnectTimer); + if (options.reconnectTimer && options.reconnectTimer > 0) { + this.reconnect(options.reconnectTimer); } } } // 发送消息 - send(data: Record) { + public send(data: Record) { if (!this.ws) { console.warn('websocket 不可用'); return; } console.log(' readyState', this.ws.readyState); + if ( + this.ws.readyState === WebSocket.CLOSED || + this.ws.readyState === WebSocket.CLOSING + ) { + this.close(); + return; + } this.ws.send(JSON.stringify(data)); } // 手动关闭socket - close() { + public close() { this.heartInterval && clearInterval(this.heartInterval); this.reconnectTimeout && clearTimeout(this.reconnectTimeout); if (!this.ws) { @@ -142,7 +196,7 @@ export class WS { } // 周期性发送ping 保活 - heartCheck(heartTimer: number) { + private heartCheck(heartTimer: number) { this.heartInterval = window.setInterval(() => { this.send({ type: 'ping', @@ -151,12 +205,12 @@ export class WS { } // 断线重连 - reconnect(reconnectTimer: number) { + private reconnect(reconnectTimer: number) { if (this.reconnectTimeout > 0) return; clearTimeout(this.reconnectTimeout); this.reconnectTimeout = window.setTimeout(() => { - if (this.params) { - this.create(this.params); + if (this.options) { + this.create(this.options); this.reconnectTimeout = 0; } }, reconnectTimer); diff --git a/src/views/dashboard/cdr/index.vue b/src/views/dashboard/cdr/index.vue index 48592a07..1991c14f 100644 --- a/src/views/dashboard/cdr/index.vue +++ b/src/views/dashboard/cdr/index.vue @@ -13,10 +13,29 @@ import { ColumnsType } from 'ant-design-vue/lib/table/Table'; import { message } from 'ant-design-vue/lib'; import { hasPermissions } from '@/plugins/auth-user'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; +import { WS, OptionsType } from '@/plugins/ws-websocket'; import useI18n from '@/hooks/useI18n'; const { t } = useI18n(); - -onMounted(() => {}); +onMounted(() => { + const options: OptionsType = { + params: { + subGroupID: '1005', + }, + onmessage: ev => { + // 接收数据后回调 + console.log(ev); + }, + onerror: (ev: any) => { + // 接收数据后回调 + console.log(ev); + }, + // 保活周期 10s + heartTimer: 0, + // 断线重连 + reconnectTimer: 0, + }; + const ws = new WS(options); +});