chenhaozhe
4 天以前 9e825bb9263ed29897bfaf467bfd0f86da8d3e5f
消息推送 优化
5个文件已修改
331 ■■■■ 已修改文件
App.vue 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/index/login.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/index/mine.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/WebSocketServices.js 278 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
App.vue
@@ -1,17 +1,47 @@
<script>
    import WebSocketServices from "./utils/WebSocketServices";
    import {
        getOpenId,
        setUserInfo,
        setToken,
        getToken
        getToken,
        getUserInfo
    } from "./utils/auth";
    export default {
        onLaunch: function() {
            console.log('App Launch')
            // #ifdef H5
            // // 测试时,H5页面刷新会丢失WebSocket连接,需触发重连 (需要测试的时候再解除注释,否则会影响热更新)
            // if (uni.getStorageSync("userinfo")) {
            //     if (WebSocketServices.wsInstance) { // 假设你的 WebSocket 实例存在 wsInstance 中
            //         WebSocketServices.closeConnect(); // 调用你封装的“关闭连接”方法
            //     }
            //     setTimeout(() => {
            //         WebSocketServices.createConnect(
            //             getUserInfo()["Czybm"],
            //             getUserInfo()["Czymc"],
            //         )
            //     }, 500)
            // }
            // // 关键:监听热更新模块替换,销毁旧连接
            // if (module.hot) {
            //     module.hot.accept(); // 允许当前模块热更新
            //     module.hot.dispose(() => {
            //         // 热更新替换模块前,销毁 WebSocket 连接
            //         if (WebSocketServices.wsInstance) {
            //             WebSocketServices.closeConnect();
            //             WebSocketServices.wsInstance = null; // 重置实例
            //         }
            //     });
            // }
            // #endif
        },
        onShow: function() {
            console.log('App Show')
        },
        onHide: function() {
            console.log('App Hide')
@@ -30,7 +60,7 @@
    /* 用于解决picker内部设置 disabled input 时不响应的问题 */
    .picker-overlay {
        box-sizing: border-box;
        box-sizing: border-box;
        position: absolute;
        top: 0;
        left: 0;
manifest.json
@@ -2,8 +2,8 @@
    "name" : "智云LMES",
    "appid" : "__UNI__B002F49",
    "description" : "",
    "versionName" : "2.0.55",
    "versionCode" : 255,
    "versionName" : "2.0.58",
    "versionCode" : 258,
    "transformPx" : false,
    /* 5+App特有相关 */
    "app-plus" : {
@@ -21,7 +21,8 @@
            "Camera" : {},
            "Contacts" : {},
            "Bluetooth" : {},
            "Barcode" : {}
            "Barcode" : {},
            "Push" : {}
        },
        /* 应用发布信息 */
        "distribute" : {
pages/index/login.vue
@@ -335,8 +335,7 @@
                                uni.setStorageSync('HSecManagerID', res.data.data[0].HSecManagerID); //对应验收
                                uni.setStorageSync('HSecManagerName', res.data.data[0].HSecManagerName);
                                this.CommonUtils.setServerUrl(this.serverUrl)
                                // console.log('this.WebSocsketServices: ',this.WebSocsketServices);
                                // this.WebSocketServices.createConnect(res.data.data[0].Czybm,res.data.data[0].Czymc);
                                this.WebSocketServices.createConnect(res.data.data[0].Czybm,res.data.data[0].Czymc);
                                uni.reLaunch({
                                    url: '/pages/index/index'
                                })
pages/index/mine.vue
@@ -26,7 +26,8 @@
</template>
<script>
    import { getUserInfo } from "@/utils/auth.js";
    import WebSocketServices from "../../utils/WebSocketServices";
import { getUserInfo } from "@/utils/auth.js";
    import {
        CommonUtils
    } from '@/utils/common'
@@ -99,6 +100,10 @@
                    success: function (res) {
                        if (res.confirm) {
                            console.log('用户点击确定');
                            // 断开Socket连接
                            WebSocketServices.closeSocket();
                            // 销毁 userInfo 缓存
                            uni.removeStorageSync("userinfo")
                            uni.reLaunch({
                                url:'/pages/index/login'
                            })
utils/WebSocketServices.js
@@ -3,84 +3,214 @@
} from "@/utils/common.js";
class WebSocketServices {
    constructor() {
        this.wsInstance = null; // WebSocket 实例
        this.isConnecting = false; // 避免并发重连
        this.isConnected = false; // 避免并发重连
        this.wsUrl = CommonUtils.httpFormatWs()
    }
   constructor() {
       this.wsInstance = null; // WebSocket 实例
       this.isConnecting = false; // 连接中状态(避免并发重连)
       this.isConnected = false; // 已连接状态
       this.isReconnectStopped = false; // 停止重连标记
       this.wsUrl = CommonUtils.httpFormatWs(); // WebSocket 基础地址
       // 超时校验配置
       this.noMessageTimeout = 45000; // 45秒内没收到任何业务消息 → 判定连接失效(服务端30秒发一次Ping,留15秒容错)
       this.noMessageTimer = null; // 无消息超时定时器
       // 监听函数引用
       this.openListener = null;
       this.messageListener = null;
       this.closeListener = null;
       this.errorListener = null;
       // 缓存用户信息
       this.currentUserId = "";
       this.currentUserName = "";
     }
     /**
      * 建立 WebSocket 连接
      * @param {string/number} userId - 用户ID(必填)
      * @param {string} userName - 用户名(必填)
      * @param {number} count - 当前重连次数
      * @param {number} limit - 最大重连次数(默认3次)
      */
     createConnect(userId, userName, count = 0, limit = 3) {
       // 缓存用户信息(用于重连)
       this.currentUserId = userId;
       this.currentUserName = userName;
       // 前置校验:避免无效连接和并发重连
       if (this.isConnecting || this.isConnected) return;
       if (!userId && userId !== 0) { // 兼容 userId 为 0 的合法场景
         CommonUtils.showTips({ message: "用户标识不能为空,无法建立WebSocket连接" });
         return;
       }
       if (count > limit) {
         CommonUtils.showTips({
           message: `WebSocket 重连次数超出最大限制(${limit}次),已停止重连`,
         });
         this.isReconnectStopped = true;
         return;
       }
       console.log(`[WebSocket] 开始建立连接(第 ${count || 0} 次)`, {
         wsUrl: this.wsUrl,
         userId,
         userName,
       });
       // 清除历史残留:监听+定时器
       this.clearAllListeners();
       this.clearNoMessageTimer();
       // 发起连接
       this.isConnecting = true;
       this.wsInstance = uni.connectSocket({
         url: `${this.wsUrl}?userId=${encodeURIComponent(userId)}&userName=${encodeURIComponent(userName)}`,
         fail: (error) => {
           console.error("[WebSocket] 连接发起失败", error);
           this.isConnecting = false;
           this.triggerReconnect(count);
         },
       });
       // 监听连接成功:启动无消息超时校验
       this.openListener = uni.onSocketOpen((res) => {
         console.log("[WebSocket] 连接建立成功", res);
         this.isConnecting = false;
         this.isConnected = true;
         this.isReconnectStopped = false;
         this.startNoMessageCheck();
         count = 0;
       });
       this.messageListener = uni.onSocketMessage((res) => {
         try {
           const message = JSON.parse(res.data);
           console.log("[WebSocket] 收到业务消息", message);
           // 重置无消息定时器(有业务消息=连接正常)
           this.resetNoMessageTimer();
           // 处理业务消息
           if (message.Type === "Message") {
             const content = JSON.parse(message.Content);
             this.showTaskTip(`您有${content.length}条消息需要处理!`);
             // this.emit("message", content); // 支持外部监听
           }
         } catch (error) {
           console.error("[WebSocket] 消息解析失败", error, res.data);
         }
       });
       // 监听连接关闭:仅异常关闭触发重连
       this.closeListener = uni.onSocketClose((res) => {
         console.log("[WebSocket] 连接关闭", res);
         this.isConnecting = false;
         this.isConnected = false;
         this.clearNoMessageTimer();
         // 正常关闭(code=1000)或主动停止重连时,不重连
         if (!this.isReconnectStopped && res.code !== 1000) {
           this.triggerReconnect(count);
         }
       });
       // 监听连接错误:触发重连
       this.errorListener = uni.onSocketError((error) => {
         console.error("[WebSocket] 连接错误", error);
         this.isConnecting = false;
         this.clearNoMessageTimer();
         if (!this.isReconnectStopped) {
           this.triggerReconnect(count);
         }
       });
     }
     /**
      * 统一触发重连(延迟3秒)
      * @param {number} count - 当前重连次数
      */
     triggerReconnect(count) {
       console.log(`[WebSocket] 准备第 ${count + 1} 次重连`);
       setTimeout(() => {
         this.createConnect(this.currentUserId, this.currentUserName, count + 1);
       }, 3000);
     }
     /**
      * 启动“无业务消息”超时校验
      * 逻辑:45秒内没收到任何业务消息 → 判定连接失效(服务端30秒发Ping,底层已处理,此处仅校验业务通道)
      */
     startNoMessageCheck() {
       this.clearNoMessageTimer();
       this.noMessageTimer = setTimeout(() => {
         console.warn("[WebSocket] 45秒未收到业务消息,判定连接失效,主动重连");
         this.closeSocket();
         this.createConnect(this.currentUserId, this.currentUserName);
       }, this.noMessageTimeout);
     }
     /**
      * 收到业务消息后,重置无消息定时器
      */
     resetNoMessageTimer() {
       this.startNoMessageCheck();
     }
     /**
      * 清除无消息定时器
      */
     clearNoMessageTimer() {
       if (this.noMessageTimer) {
         clearTimeout(this.noMessageTimer);
         this.noMessageTimer = null;
       }
     }
     /**
      * 清除所有 Socket 监听
      */
     clearAllListeners() {
       if (this.openListener) {
         uni.offSocketOpen(this.openListener);
         this.openListener = null;
       }
       if (this.messageListener) {
         uni.offSocketMessage(this.messageListener);
         this.messageListener = null;
       }
       if (this.closeListener) {
         uni.offSocketClose(this.closeListener);
         this.closeListener = null;
       }
       if (this.errorListener) {
         uni.offSocketError(this.errorListener);
         this.errorListener = null;
       }
     }
     /**
      * 主动关闭 WebSocket 连接 (登出时关闭WebSocket连接)
      */
     closeSocket() {
       this.isReconnectStopped = true;
       this.clearAllListeners();
       this.clearNoMessageTimer();
       if (this.wsInstance) {
         uni.closeSocket({
           success: () => console.log("[WebSocket] 主动关闭连接成功"),
           fail: (error) => console.error("[WebSocket] 主动关闭连接失败", error),
         });
         this.wsInstance = null;
       }
       this.isConnected = false;
       this.isConnecting = false;
     }
    // 建立WebSocket连接
    createConnect(userId, userName) { // 使用用户标识 作为后端连接的凭据
        console.log('wsUrl: ', this.wsUrl);
        console.log('userId: ', userId);
        console.log('userName: ', userName);
        if (this.isConnecting || !userId || this.isConnected) {
            return
        }
        this.wsInstance = uni.connectSocket({
            url: this.wsUrl + `?userId=${encodeURIComponent(userId)}&userName=${encodeURIComponent(userName)}`,
            success() {
                this.isConnecting = true
            }
        })
        // 监听套接字连接建立
        uni.onSocketOpen((res) => {
            console.log('[webSocket]: 套接字连接建立成功');
            this.isConnecting = false
            this.isConnected = true
            console.log('res: ', res);
            this.wsInstance = res.socketTask
        })
        uni.onSocketMessage((res) => {
            let message = JSON.parse(res.data)
            console.log('message: ', message);
            if (message.Type == 'Message') {
                // 消息信号
                let content = JSON.parse(message.Content)
                console.log('content: ', content);
                this.showTaskTip(`您有${content.length}条消息需要处理!`)
            } else if (message.Type == 'ping') {
                // 心跳信号
                uni.sendSocketMessage({
                    data: "pong"
                })
            }
        })
    }
    // 重连
    reConnect(reCount = 1, limit = 3) {
        if (reCount > limit) {
            uni.showToast({
                icon: 'none',
                title: `超出最大重连次数。已退出连接`
            })
            this.isConnecting = false
            return
        }
        uni.showToast({
            icon: 'none',
            title: `正在尝试重连,重连次数 ${reCount}`
        })
        reConnect(reCount + 1, limit)
        uni.hideToast()
    }
    // 连接注销
    disConnect() {
    }
    showTaskTip(Content) {
        console.log('Content: ', Content);
        // #ifdef APP-PLUS || APP
        console.log('Content2: ', Content);
        let content = Content;
        let options = {
            title: "重要通知",