import { WS_BASE_URL } from 'config/api'; import { mapGetters, mapMutations } from 'vuex'; let connected = false; // socket 是否连接 let socket = null; // websocket 实例 let lockSocket = false; let socketMsgQueue = []; // socket消息队列 let prevTimestamp = 0; // 上次收到消息的时间戳 let sendHeartTimer = null; // 💓的timer计时器 const mixin = { // computed: mapGetters('home', ['projectId']), mounted() { socket ? socket.close() : this.initSocket(); }, methods: { ...mapMutations('messages', [ 'messagesAdd', 'messagesAddWeight', 'messagesAddRfid', 'messagesAddWeighSensor1', 'messagesAddWeighSensor2', 'messagesAddWeighSensor3', 'messagesAddWeighSensor4', 'messagesAddVibrationSensor', 'messagesAddThrombolyticDose', 'messagesAddBolusDose', 'messagesAddMaintenanceDose', ]), // ...mapMutations('home', ['increaseProjectsRingNum']), // 初始化websocket initSocket() { if (lockSocket) return; lockSocket = true; // const token = sessionStorage.getItem('anyringToken'); // if (!token) return; if ('WebSocket' in window) { socket = new WebSocket(WS_BASE_URL); socket.onopen = this.websocketOpen; socket.onmessage = this.websocketOnMessage; socket.onclose = this.websocketClose; socket.onerror = this.websocketError; } else { this.$message.error('当前浏览器不支持 websocket'); } lockSocket = false; }, /** * 处理收到的消息内容 * @param {object} item 单个消息体对象 */ handleMessagesData(item) { const data = JSON.parse(item.data); console.log('data: ', data); switch (data.type) { case 'ChannelStatus': // 认证消息 this.handleAuthMessage(data); break; case 1: // 体重 // 收到同步消息 // 把消息添加到store 的消息栈中 this.messagesAddWeight(data.data); break; case 2: // RFID this.messagesAddRfid(data.data); break; case 3: // 称重传感器一 this.messagesAddWeighSensor1(data.data); break; case 4: // 称重传感器二 this.messagesAddWeighSensor2(data.data); break; case 5: // 称重传感器三 this.messagesAddWeighSensor3(data.data); break; case 6: // 称重传感器四 this.messagesAddWeighSensor4(data.data); break; case 7: // 震动传感器 this.messagesAddVibrationSensor(data.data); break; case 8: // 溶栓剂量(总量) this.messagesAddThrombolyticDose(data.data); break; case 9: // 团注剂量 this.messagesAddBolusDose(data.data); break; case 10: // 维持剂量 this.messagesAddMaintenanceDose(data.data); break; default: break; } }, /** * 收到ws 消息 * @param {object} res 收到的消息数据 */ async websocketOnMessage(res) { try { prevTimestamp = Date.now(); // console.warn('message: ', res, new Date().toLocaleString()); if (res && res.data && JSON.parse(res.data)) { const resData = JSON.parse(res.data); const { messageSet, ackId } = resData; // 处理消息体对象 messageSet.forEach(item => this.handleMessagesData(item)); // console.log('ackId', ackId); // 有ackId 发送ack ackId && this.sendSocketMessage({ type: 'Ack', data: { ackId } }); } } catch (error) { console.error('error: ', error); } }, // 打开socket websocketOpen() { // console.warn('socket 打开成功', new Date().toLocaleString()); connected = true; prevTimestamp = Date.now(); this.auth(); for (let i = 0; i < socketMsgQueue.length; i += 1) { this.sendSocketMessage(socketMsgQueue[i]); } socketMsgQueue = []; }, // 发送消息 sendSocketMessage(data) { // console.warn('send:', data, new Date().toLocaleString()); if (connected) { if (socket.readyState === 1) { socket.send(JSON.stringify({ toDomain: 'Server', data: JSON.stringify(data) })); } } else { socketMsgQueue.push(data); } }, // 关闭socket websocketClose(e) { // console.warn(e); connected = false; if (sendHeartTimer) clearInterval(sendHeartTimer); // console.warn('close:', connected, new Date().toLocaleString()); if (!e || e.code !== 1005) { socket.close(); } setTimeout(() => { // connected 在这里的作用是: // 在发生重连 但是还没连上之前 不要再次重连 this.initSocket(); }, 300); }, // 连接失败 websocketError() { console.warn('error = ', connected); }, // websocket发送token进行认证 auth() { // const token = sessionStorage.getItem('anyringToken'); // if (!token) return; const userId = '1338747522436435968'; const data = { type: 'Auth', data: { userId }, major: 1, minor: 1 }; this.sendSocketMessage(data); }, // 心跳检测 sendHeart() { if (sendHeartTimer) clearInterval(sendHeartTimer); sendHeartTimer = setInterval(() => { if (Date.now() - prevTimestamp >= 15000) { this.sendSocketMessage({ type: 'Ping' }); if (Date.now() - prevTimestamp > 20000) { // console.warn('手动断开'); socket.close(); } } }, 5000); }, /** * 处理auth认证返回的ChannelStatus消息 * @param {object} data 消息内容对象 */ handleAuthMessage(data) { if (data.data.authed) { // 认证成功 this.sendHeart(); } else { this.$message.error('消息系统认证失败, 请重新登录'); // 清除掉本地无用的token sessionStorage.removeItem('anyringToken'); socket = null; setTimeout(() => { this.$router.push('/user/login'); }, 1000); } }, }, }; export default mixin;