uniapp中webscoket 针对客服进行的再次封装

灯火 Lv3

参考

uniapp封装websokcet并全局使用

介绍

最近开发unapp客服系统,针对系统功能将websokcet进行了再次封装

ws-socket.js 对websocket的封装 连接、心跳、关闭
socket-instance.js 引入ws-socket.js的再次封装,上线、下线、接收消息、发送消息,并抛出给外部

封装

  • ws-socket.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118

    class WebSocketManager {
    /**
    * 创建 WsSocket 的实例
    *
    * @param {Object} events 原生 WebSocket 绑定事件
    */
    constructor(events) {
    // this.socketUrl = `你的ws地址`;
    this.socketTask = null;
    // 是否连接上ws
    this.isOpenSocket = false;
    // 心跳间隔 毫秒
    this.heartBeatDelay = 3000;
    this.heartBeatInterval = null;
    // 连接次数
    this.reconnectTimes = 10;
    this.reconnectInterval = null;
    // 重连间隔 毫秒
    this.reconnectDelay = 3000;
    //这个参数是防止重连失败之后onClose方法会重复执行reconnect方法,导致重连定时器出问题
    //连接并打开之后可重连,且只执行重连方法一次
    this.canReconnect = false;

    // 定义 WebSocket 原生方法
    this.events = Object.assign(
    {
    onError: (evt) => {},
    onOpen: (evt) => {},
    onClose: (evt) => {},
    onMessage: (evt) => {}
    },
    events
    );
    }

    init() {
    this.socketTask = uni.connectSocket({
    url: `你的ws地址`,
    complete: () => {}
    });

    this.socketTask.onOpen((evt) => {
    this.events.onOpen(evt);
    console.log("WebSocket connection successful");
    this.isOpenSocket = true;
    this.canReconnect = true;
    this.startHeartbeat();
    this.clearReconnectInterval();
    });

    this.socketTask.onMessage((evt) => {
    this.events.onMessage(evt);
    });

    this.socketTask.onClose((evt) => {
    this.events.onClose(evt);
    console.log("WebSocket disconnected");
    this.isOpenSocket = false;
    // 关闭重连 因为是客服系统排他登录,当被挤下下时,不能进行重连,不然会出现反复上下线的问题
    // if (this.canReconnect) {
    // this.reconnect();
    // this.canReconnect = false;
    // }
    });
    this.socketTask.onError((evt) => {
    this.events.onError(evt);
    })
    }
    // 心跳
    startHeartbeat() {
    this.heartBeatInterval = setInterval(() => {
    const params = { intent: "PING" };
    this.send(JSON.stringify(params));
    }, this.heartBeatDelay);
    }

    send(value) {
    if (this.socketTask) {
    this.socketTask.send({
    data: value,
    success: () => {
    console.log("Message sent successfully");
    }
    });
    }
    }

    reconnect() {
    clearInterval(this.heartBeatInterval);
    if (!this.isOpenSocket) {
    let attempts = 0;
    this.reconnectInterval = setInterval(() => {
    console.log("Attempting to reconnect");
    this.init();
    attempts++;
    if (attempts >= this.reconnectTimes) {
    clearInterval(this.reconnectInterval);
    console.log("Unable to reconnect - network or server error");
    }
    }, this.reconnectDelay);
    }
    }

    clearReconnectInterval() {
    clearInterval(this.reconnectInterval);
    }
    completeClose() {
    clearInterval(this.heartBeatInterval);
    clearInterval(this.reconnectInterval);
    this.canReconnect = false;
    if (this.socketTask) {
    this.socketTask.close();
    }
    }
    }

    export default WebSocketManager;
  • socket-instance.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import ws from '@/plugin/ws-socket.js'
import { ref } from 'vue'
// 是否在线,在线socket连接成功,离线未连接或者已经掉线
const isOnline = ref(false)
// 全局使用
// const isOnline = computed(() => serverStore.getIsOnline)
class SocketInstance {
/**
* WsSocket 实例
*/
socket;
eventHandlers;

/**
* SocketInstance 初始化实例
*/
constructor() {
this.socket = new ws({
onError: (evt) => {
console.log("Websocket 连接失败回调方法");
},
// Websocket 连接成功回调方法
onOpen: (evt) => {
},
// Websocket 断开连接回调方法
onClose: (evt) => {
},
onMessage: async (evt) => {
const result = JSON.parse(evt.data);
// 后台报错
if (result.code === -1) {
console.error(result);
return;
// 401
} else if (result.code === 401) {
// 重新获取token...
return;
}
// 无实体跳出
if (!result.data) return;
this.handleMessage(result.data)
}
})
// 事件处理函数映射
this.resetEvent();
// 连接
this.connect();
}

// 连接 WebSocket 服务
connect() {
console.log("🔗连接 WebSocket");
if (!this.socket.socketTask || !isOnline.value) {
this.socket.init();
}
}
// 处理message事件
handleMessage(data) {
console.log(data,data.type, 'handleMessage data')
// 上线
if (data.type === 'ONLINE') {
return this.handleOnline(data)
}
// 下线
if (data.type === 'OFFLINE') {
return this.handleOffline(data)
}
// 接收消息
if (data.type === 'MESSAGE') {
return this.handleTalk(data)
}
}
handleOnline(data) {
uni.showToast({
title: '您已上线',
icon: 'none',
duration: 2000
});
// serverStore.setIsOnline(true)
isOnline.value = true
this.eventHandlers['event_online_status'](data);
}
handleOffline(data) {
uni.showModal({
title: '提示',
content: '您已在其他页面发起咨询,当前咨询口已失效,点击确认进行重新咨询',
success: (res) => {
if (res.confirm) {
// 重新连接
this.connect()
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
// serverStore.setIsOnline(false)
isOnline.value = false
return this.eventHandlers['event_offline_status'](data);
}
handleTalk(data) {
console.log('handleTalk---')
let info = data.result
// ws 对话消息的逻辑
// ...

// 抛出给外部
this.eventHandlers["event_dialogue"](info);
}
// 允许外部设置事件处理函数
on(eventName, handler) {
this.eventHandlers[eventName] = handler;
}
/**
* 聊天发送数据
*
* @param {Object} info
*/
send(info) {
// 当前掉线
if (!isOnline.value) {
uni.showToast({
title: '当前掉线,无法发送消息',
duration: 2000,
icon:'none'
});
return
}
this.socket.send(info)
// 发送消息的相关逻辑
// ...

// 抛出
this.eventHandlers["event_dialogue"](params);
}
resetEvent() {
this.eventHandlers = {
// 上线
event_online_status: (data) => {},
// 下线
event_offline_status: (data) => {},
// 接收对话消息
event_dialogue: (data) => {},
// 聊天列表数量出现变化,新增聊天
event_update_talks: (data) => {}
};
}
}

export default new SocketInstance();

使用

vue3 + setup 环境上的使用

1
2
3
4
5
6
7
8
9
10
11
// 一引入自动连接,多次引入也只会有一个ws连接
import SocketInstance from "@/im-server/socket-instance";
import { onMounted } from 'vue'

const eventDialogue = (data) => {
console.log('-------------接收消息', data)
}

onMounted(() => {
SocketInstance.on('event_dialogue', eventDialogue)
})
  • 标题: uniapp中webscoket 针对客服进行的再次封装
  • 作者: 灯火
  • 创建于 : 2023-11-10 01:14:37
  • 更新于 : 2023-11-15 02:44:50
  • 链接: https://blog.juniverse.top/2023/11/10/uniapp-webscoket/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
此页目录
uniapp中webscoket 针对客服进行的再次封装