vue使用WebSocket实现实时报警弹窗

该博客详细介绍了如何使用WebSocket实现实时报警功能,当接收到报警时,系统会弹出弹窗显示报警内容并播放警告声音。内容包括WebSocket的初始化、心跳检测、错误处理、消息接收以及报警声音和弹窗的控制。此外,还展示了如何根据接收到的数据动态生成弹窗,并在点击详情后跳转到相应页面。
摘要由CSDN通过智能技术生成

使用WebSocket实现实时报警,实现当接收到报警时弹出弹窗显示报警内容和发错报警声音。

<template>
    <section class="app-main">
        <!-- 报警时的声音 controls -->
        <audio
            loop="true"
            ebkit-playsinline="true"
            playsinline="true"
            ref="myAudio"
            src="../../assets/alarm.mp3"
        ></audio>
    </section>
</template>

<script>
import { mapGetters } from 'vuex'
import { parseTime } from '@/utils/index'
import { getToken } from '@/utils/auth'
export default {
    name: 'AppMain',
    components: {
    },
    watch: {
        alarmTime(after) {
            // console.log('alarmTime', after)
            clearInterval(this.timer)
            if (after > 0) {
                this.setAudio()
            } else {
                this.myAudio.pause() // 暂停
                clearInterval(this.timer)
                this.$store.commit('user/SET_ALARMTIME', 0)
            }
        }
    },
    computed: {
        ...mapGetters(['pcAlarmVoice', 'catchComponents']),
        key() {
            return this.$route.path
        }
    },
    data() {
        return {
            websock: null,
            infoText: '',
            showInfo: false,
            lockReconnect: false,
            alarmBox: [],
            alarmBG: ['', 'bgCC6966', 'bg969696', 'bgCC6966 ', 'bg969696', 'bgCC6966', 'bgCC6966', 'bgCC6966'],
            alarmTime: 0,
            timer: null, // 声音报警定时器
            myAudio: null, // 报警声音控件
            alarmType: ['', '超限报警', '超限预警', '断电报警 ', '离线报警', '设备异常', '上线通知', '来电通知'],
            time1: null, // 连接的延时器
            timeout: 30 * 1000, // 30秒一次心跳
            timeObj: null // 心跳心跳倒计时
        }
    },
    created() {},
    mounted() {
        // http://192.168.31.240:8081/user/test?d=test02m202100001&i=1
        // console.log('进入页面')
        this.initWebSocket()
        this.myAudio = this.$refs.myAudio
    },
    methods: {
        setAudio() {
            if (this.myAudio.paused) {
                this.myAudio.play() // 播放
            }
            this.timer = setInterval(() => {
                this.alarmTime--
            }, 1000)
        },
        initWebSocket: function () {
            // WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
            // 用户token
            let bindContent = getToken()
            if (bindContent === 'undefined' || !bindContent) {
                bindContent = ''
            }
            let url = ''
            if (process.env.NODE_ENV === 'production') {
                // 生产环境
                // url = 'wss://192.168.31.46:30008/?bindType=2&bindContent=' + bindContent // 正试服
                url = 'ws://192.168.31.46:30008/?bindType=2&bindContent=' + bindContent // 正试服
            } else if (process.env.NODE_ENV === 'staging') {
                url = 'ws://ws.lenglh.cn:30008/?bindType=2&bindContent=' + bindContent // 测试服
            } else {
                // development 开发环境
                // url = 'ws://192.168.31.240:30008/?bindType=2&bindContent=' + bindContent
                url = 'ws://192.168.31.46:30008/?bindType=2&bindContent=' + bindContent
                return false
            }
            // console.log('初始化websocket', url)
            // this.websock = new WebSocket('ws://192.168.31.240:30008/?bindType=2&bindContent=' + bindContent)
            this.websock = new WebSocket(url)
            this.websock.onopen = this.websocketOnopen
            this.websock.onerror = this.websocketOnerror
            this.websock.onmessage = this.websocketOnmessage
            this.websock.onclose = this.websocketOnclose
        },
        websocketOnopen: function () {
            console.log('页面WebSocket连接成功')
            // 开启心跳检测
           	this.start()
        },
        // 正式包中连接会一分钟后断开,使用心跳监测如果断开连接则重新连接
        start() {
            //开启心跳
            let context = this
            clearInterval(context.timeObj)

            context.timeObj = setInterval(function () {
                //这里发送一个心跳,后端收到后,返回一个心跳消息
                // console.log('心跳', context.websock)
                if (context.websock.readyState === 1) {
                    //如果连接正常
                    context.websock.send(JSON.stringify({ content: 'user-bind心跳包', type: 0 }))
                } else {
                    //否则重连
                    context.reconnect()
                }
            }, context.timeout)
        },
        // 连接失败后的回调函数
        websocketOnerror: function (e) {
            console.log('WebSocket连接发生错误', e)
            this.reconnect()
        },
        // 当从服务器接受到信息时的回调函数
        websocketOnmessage: function (e) {
            // console.log('监听关闭' + e)
            console.log('-----接收消息-------')

            // 收到消息,添加报警声音(先判断声音报警是否开启)
            if (this.pcAlarmVoice) {
                this.alarmTime = 5
                // console.log('先判断声音报警是否开启');
                this.$store.commit('user/SET_ALARMTIME', this.alarmTime)
            }

            const h = this.$createElement // 创建文本节点

            let alarmData = JSON.parse(e.data).bindContent
            alarmData.alarmTime = parseTime(alarmData.alarmTime)
            if (this.$route.path === '/screen') {
                alarmData.alarmBG = this.alarmBG[alarmData.alarmType]
                alarmData.alarmBTN=this.alarmBG[alarmData.alarmType]+'btn'
            } else {
                alarmData.alarmBG = ''
                alarmData.alarmBTN = ''
            }
            alarmData.alarmType = this.alarmType[alarmData.alarmType]
            alarmData.groupName = alarmData.groupName ? alarmData.groupName : '未分配'
            let title = alarmData.deviceName + '(' + alarmData.deviceSerial + ')'

            // 当前弹窗要插入数组的下标
            let index = this.alarmBox.length

            if (index === 3) {
                this.alarmBox[0].close()
                this.alarmBox.pop()
            }

            let messageHTML = null
            // 判断是否有传感器
            if (alarmData.channelName) {
                messageHTML = h(
                    'div',
                    {
                        class: 'alarm-box'
                    },
                    [
                        h('p', this.$t('device.d409') + ':' + alarmData.alarmType),
                        h('p', this.$t('device.d746') + ':' + alarmData.channelName),
                        h('p', this.$t('monitor.m15') + ':' + alarmData.groupName),
                        h('p', this.$t('device.d497') + ':' + alarmData.alarmTime),
                        h('p', this.$t('user.u258') + ':' + alarmData.alarmContent.cn),
                        h(
                            'div',
                            {
                                class: 'btn-box'
                            },
                            [
                                h(
                                    'button',
                                    {
                                        class: 'btn el-button--primary ' + alarmData.alarmBTN,
                                        on: {
                                            click: () => this.notifyClick(alarmData) // 按钮的点击事件
                                        }
                                    },
                                    '查看详情'
                                )
                            ]
                        )
                    ]
                )
            } else {
                messageHTML = h(
                    'div',
                    {
                        class: 'alarm-box'
                    },
                    [
                        h('p', this.$t('device.d409') + ':' + alarmData.alarmType),
                        h('p', this.$t('user.u489') + ':' + alarmData.objectName),
                        h('p', this.$t('device.d497') + ':' + alarmData.alarmTime),
                        h('p', this.$t('user.u258') + ':' + alarmData.alarmContent.cn),
                        h(
                            'div',
                            {
                                class: 'btn-box'
                            },
                            [
                                h(
                                    'button',
                                    {
                                        class: 'btn el-button--primary ' + alarmData.alarmBTN,
                                        on: {
                                            click: () => this.notifyClick(alarmData) // 按钮的点击事件
                                        }
                                    },
                                    this.$t('global.detailBtn') // '查看详情'
                                )
                            ]
                        )
                    ]
                )
            }
            this.open(title, messageHTML, index, alarmData.alarmBG)
        },
        open(title, messageHTML, index, bg) {
            console.log('当前页面', this.$route, bg)
            let customClass = 'alarm-notify'
            if (this.$route.path === '/screen') {
                customClass = 'alarm-notify screen-box ' + bg
            }
            this.alarmBox[index] = this.$notify({
                title: title,
                dangerouslyUseHTMLString: true,
                duration: 5000, // 自动关闭的时间
                // duration: 0, // 不自动关闭
                customClass: customClass,
                // position: 'bottom-right',
                message: messageHTML
            })
        },
        // 查看详情
        notifyClick(alarmData) {
            this.$store.dispatch('app/setReqId', alarmData.deviceId)
            this.$router.push({ name: 'monitoringDeviceDetail' })
        },
        websocketOnclose: function (e) {
            // console.log('connection closed (' + e.code + ')')
        },
        websocketSend(text) {
            // 数据发送
            try {
                this.websock.send(text)
            } catch (err) {
                // console.log('send failed (' + err.code + ')')
            }
        },
        reconnect() {
            let context = this
            if (context.lockReconnect) return
            context.lockReconnect = true
            //没连接上会一直重连,设置延迟避免请求过多
            clearTimeout(this.time1)
            this.time1 = setTimeout(function () {
                // console.info('尝试重连...')
                context.initWebSocket()
                context.lockReconnect = false
            }, 5000)
        }
    },
    beforeDestroy() {
        // this.websock.close()
        // console.log('页面关闭websocket');
    }
}
</script>

<style scoped lang="scss">
.app-main {
    /*50 = navbar  */
    min-height: calc(100vh - 60px);
    width: 100%;
    position: relative;
}
.fixed-header + .app-main {
    padding-top: 50px;
}

.info {
    position: relative;
    width: 100%;
    padding: 10px;
}

::v-deep .el-notification__group {
    width: 100% !important;
}
</style>

<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
    .fixed-header {
        padding-right: 15px;
    }
}

.alarm-notify {
    width: 400px;
    .el-notification__group {
        width: 100%;

        .alarm-box {
            > p {
                line-height: 1.4;
                margin-top: 10px;
            }
        }
    }
}

.screen-box {
    // background-color: #103064;
    // border: 1px solid #2154b2;
    opacity: 95%;
    .el-notification__title {
        color: #fff !important;
    }
    p {
        color: #fff !important;
    }
}

.bgCC6966 {
    background-color: #cc6966;
    border: 1px solid #cc2e29;
}

.bgCC6966btn {
    background-color: #ffffff !important;
    color: #cc6966 !important;
}

.bg969696 {
    background-color: #969696;
    border: 1px solid #ffffff;
}

.bg969696btn {
    background-color: #ffffff !important;
    color: #323232 !important;
}

.btn {
    box-sizing: border-box;
    height: 35px;
    border-radius: 4px;
    border: none;
}

.btn-box {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    margin-top: 20px;
}
// -----------------------
.isOn {
    width: 28px;
    height: 28px;
    -webkit-animation: rotating 1.2s linear infinite;
    animation: rotating 1.2s linear infinite;
}
@keyframes rotating {
    from {
        -webkit-transform: rotate(0);
    }
    to {
        -webkit-transform: rotate(360deg);
    }
}
@-webkit-keyframes rotating {
    from {
        -webkit-transform: rotate(0);
    }
    to {
        -webkit-transform: rotate(360deg);
    }
}
.isOff {
    width: 28px;
    height: 28px;
}
</style>

注:

  • 使用this.$t('')是项目做了中英文翻译
  • 使用this.$createElement创建弹窗的html片段是因为要求使用返回的数据的值做显示,使用原始html片段不能实现,而使用模板字符串的html片段时不能执行方法,最终使用vue的this.$createElement实现项目需求。

最终弹窗效果:
在这里插入图片描述
点击详情即可跳转页面

  • 4
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值