vue + websocket + speak-tts 实现推送的告警消息弹框显示在右下角并语音播报出内容
最近接了个项目需求,给设备配置语音加弹框告警。用户登录项目后不管在哪个页面,有告警就全局在右下角消息弹框加语音播报,下面浅介绍下我在开发中的流程以及遇到的坑!!!
1、首先项目中安装speak-tts语音播报插件。
npm install speak-tts
2、创建一个全局的 speech.js文件,文件中引入插件并初始化后导出。
因为可能会一直读多条消息,防止初始化多个Speech对象,在全局api中初始化一个对象,方便播报的时候调用。
import Speech from 'speak-tts'
const speech=new Speech()
export default speech
3、在项目点击登录按钮后调用全局的语音播报方法。
由于浏览器之间有安全限制,用户不主动触发语音播报方法, 语音播报不会主动发出声音,故在项目的登录处触发方法。
3.1、首先引入封装好的js文件
import Speech from '@/utils/speech'
3.2、在登录点击方法中调用speech方法的语言、语速等各种参数。
initSpeech(){
Speech.setLanguage('zh-CN')
Speech.init({
volume: 0.6, // 音量0-1
lang: "zh-CN", // 语言
rate: 2, // 语速1正常语速,2倍语速就写2
pitch: 1, // 音调
voice: "Microsoft Yaoyao - Chinese (Simplified, PRC)",
})
}
4、在登录后的vue页面资源的首加载项,即页面入口文件处编写弹框样式及告警信息的接收等功能(我开发的项目入口文件是AppMain.vue 文件)
4.1、首先新建一个项目右下角可放多个全局弹框的div,我此处使用的是card样式
<div class="alarmmodel" v-if=popupList.length>
<el-card class="box-card" shadow="always" v-for="(item, index) in popupList" :key="index">
<div slot="header" class="clearfix">
<span v-if="item.alertLevel == 1" style="color: rgb(221, 39, 48)">红色告警</span>
<span v-else-if="item.alertLevel == 2" style="color:rgb(255, 140, 0)">橙色告警</span>
<span v-else-if="item.alertLevel == 3" style="color: rgb(255, 215, 0)">黄色告警</span>
<el-button style="float: right; padding: 3px 0" type="text" @click='popupSubmit(item, index)'>确定</el-button>
</div>
<div class="text item">
{{ item.msg }}
</div>
</el-card>
</div>
4.2、项目中引入封装好的js文件
import Speech from '@/utils/speech'
4.3、data中定义四个对象,分别是websocket的初始化对象,websoket地址及播报的弹框数据和心跳监测对象
data() {
return {
heartbeatTimer: null, // 监测心跳
popupList: [], // 存储弹框数据
pathpopup: 'wss://www.aihs.dev.huanhuigroup.cn/dev/alert-service/websocket/voice', // websocket链接地址
socketpopup: null, // 初始化websocket对象
}
},
4.4、mounted中调用初始化的方法 this.initPopupsoket()
mounted() {
this.popupList = [];
this.initPopupsoket()
},
4.5、编写链接websocket的方法initPopupsoket,接收弹框及语音数据,并进行前后端心跳检测。
initPopupsoket() {
if (typeof (WebSocket) === "undefined") {
alert("您的浏览器不支持socket")
} else {
this.socketpopup = new WebSocket(this.pathpopup)
this.socketpopup.onopen = this.openPopup
this.socketpopup.onerror = this.errorPopup
this.socketpopup.onmessage = this.getMessagepopup
}
},
openPopup() {
console.log("socketpopup连接成功")
this.startHeartbeat() // 添加心跳监测,用来防止websocket断开
},
startHeartbeat() {// 发送心跳消息
var _this = this;
if (_this.heartbeatTimer == null) {
_this.heartbeatTimer = setInterval(function () {
console.log('监测心跳')
_this.socketpopup.send("ping");
}, 10000);
}
},
stopHeartbeat() { // 停止心跳
if (this.heartbeatTimer !== null) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
},
errorPopup() {
console.log("1连接错误")
},
getMessagepopup(msg) {
// console.log('1接受消息数据', msg.data)
this.popupList.push(JSON.parse(msg.data)) // 将推送的单条数据存起来显示多个弹框,在用户点击确定后消除此条弹框
this.startSpeech(JSON.parse(msg.data).msg) // 将数据中的告警传给播报的对象
},
closePopup() {
console.log("socketpopup已经关闭")
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
this.socketpopup.close();
}
},
4.6、语音播报弹框中的数据,每推一条播报一条(注:此处是后端单条数据推送,推送一条播报一条,只读最新的,但是弹框需要显示登录网站后的全部数据,需要用户手动点击确定后弹框消失,故在消息推送后调用语音播报,并将数据存到数组显示弹框。若考虑到数据较多,告警还没读完数据就推送过来,可考虑遍历告警数据进行播报,就不在接收到消息推送后调用此方法)
startSpeech(text) {
Speech.speak({
text: text,
listeners: {
//开始播放
onstart: () => {
console.log("Start utterance")
},
//判断播放是否完毕
onend: () => {
console.log("End utterance");
},
//恢复播放
onresume: () => {
console.log("Resume utterance")
},
},
}).then(() => {
console.log("读取成功")
})
},
4.7、点击确认后消除弹框告警
popupSubmit(item, index) {
console.log('点击告警弹框', item, index)
updateCurrentAlertsStatus(item.id, 'READ').then(() => {
this.$message.success('操作成功!');
this.popupList.splice(index, 1);
})
.catch(() => {
this.$message.error('操作失败!')
})
}
5、页面关闭后清空掉各种方法及数据
beforeDestroy() {
this.speech.cancel(); // 取消播放
this.speech = null;
console.log('离开页面', this.speech)
this.socketpopup.onclose = this.closePopup
},
遇到的坑:
1、由于浏览器安全限制,用户不主动触发语音告警不会主动出声音,故解决方法是初始化一个全局的
speech-tts方法,在点击登录的时候调用,详情见上
2、websocket链接的时候,如果域名是https的话websocket请求地址需是wss,要不会报错
以上就是我的开发流程,具体有不明白的留言给我!!
更多推荐
所有评论(0)