api文档:cn.rx.js.org/
封装一个类,新建js文件
import { EMPTY, merge, Observable, Subject, ReplaySubject, timer, throwError, of } from 'rxjs'
import {
catchError,
delayWhen,
filter,
retryWhen,
switchAll,
tap,
mergeMap,
finalize,
} from 'rxjs/operators'
import { webSocket, WebSocketSubject } from 'rxjs/webSocket'
let index = 0
const RECONNECT_INTERVAL = 3000
const RECONNECT_ATTEMPTS = 3
class WebsocketChannel {
constructor() {
this.channelCollection = {}
}
addChannel(key, channel) {
this.channelCollection[key] = channel
}
deleteChannel(key) {
delete this.channelCollection[key]
}
clearChannel() {
this.channelCollection = {}
}
hasChannel(key) {
return this.channelCollection.hasOwnProperty(key)
}
forEach(fn) {
for (let key in this.channelCollection) {
fn(this.channelCollection[key])
}
}
}
export class WebsocketService {
socket$
reconnectCount = 0
constructor(url, stopConnect) {
this.url = url
if (!this.stopConnect && stopConnect) {
this.stopConnect = stopConnect
} else {
this.stopConnect = this.defaultStopConnect
}
this.channels = new WebsocketChannel()
this.connect()
this.subject = new Subject()
}
defaultStopConnect() {}
connect() {
let _this = this
this.socket$ = webSocket({
url: this.url,
openObserver: {
next: () => {
_this.reconnectCount = 0
_this.socket$.subscribe(message => {
_this.subject.next(message)
})
//重连订阅消息
_this.channels.forEach(item => {
_this.next(item.subMsg())
})
},
},
})
this.socket$.subscribe({
next: () => {},
error: () => {
this.reconnect()
},
compelte: () => {
console.log('compelte')
},
})
}
// 断线重连
reconnect() {
timer(RECONNECT_INTERVAL).subscribe(() => {
this.reconnectCount++
if (this.reconnectCount > RECONNECT_ATTEMPTS) {
console.error('重连结束!!')
this.stopConnect()
} else {
console.info(`第${this.reconnectCount}次websocket重连`)
this.socket$ = undefined
this.connect()
}
})
}
multiplex(subMsg, unsubMsg, messageFilter) {
let id = ++index
if (!this.channels.hasChannel(id)) {
this.channels.addChannel(id, {
subMsg,
unsubMsg,
messageFilter,
})
}
const self = this
return new Observable(observer => {
try {
self.next(subMsg())
} catch (err) {
observer.error(err)
}
const subscription = self.subject.subscribe(
x => {
try {
if (messageFilter(x)) {
observer.next(x)
}
} catch (err) {
observer.error(err)
}
},
err => observer.error(err),
() => observer.complete()
)
return () => {
try {
self.next(unsubMsg())
self.channels.deleteChannel(id)
} catch (err) {
observer.error(err)
}
subscription.unsubscribe()
}
})
}
//发送消息
next(msg) {
this.socket$.next(msg)
}
}
挂载websocket在vue上
<template>
<div style="display: none" class="notice-log"></div>
</template>
<script>
import { WebsocketService } from '@/api/WebsocketService.js'
import { getBaseUrl } from '@/utils/api'
export default {
name: 'noticeLog',
data() {
return {
noticeId: '',
notification: null
}
},
created() {
//刷新创建websocket
let vm = this
if (vm.$store.state.account.token != '') {
vm.mountWebsockt().then(() => {
if (vm.$root.$wsmaintenance) {
//全局通知消息
const observable = this.$root.$wsmaintenance.multiplex(
() => ({ op : "snapshot"}),
() => ({ op : "update", update: { id : null}}),
data => true
)
const subscription = observable.subscribe(data => {
const res = data.data
if (data.code === 0 && res.title) {
if (res.id && res.startTime) {
if (this.notificatio) this.notificatio.close()
const h = this.$createElement
this.notificatio = this.$notify.info({
dangerouslyUseHTMLString: true,
message: h('strong', null, [
h('div', { class: 'noticelog-bottom'}, `标题:${res.title}`),
h('div', { class: 'noticelog-bottom'}, `开始时间:${res.startTime}`),
h('div', { class: 'noticelog-bottom'}, `结束时间:${res.endTime}`),
h('div', { class: 'noticelog-bottom'}, `内容:${res.content}`),
h('a', {
on:{
click:()=>{
this.closeTips(res.id)
}
},
class: 'noticelog-btn',
href: 'javascript:;'
}, "不再提示")
]),
position: 'bottom-right',
duration: 0
})
this.noticeId = res.id
} else {
this.$notify.info({
dangerouslyUseHTMLString: true,
message: `<strong><div class="noticelog-bottom">标题:${res.title}</div><div>内容:${res.content}</div></strong>`,
position: 'bottom-right',
duration: 0
})
}
}
})
vm.$once('hook:beforeDestroy', () => {
if (this.notificatio) this.notificatio.close()
// subscription.unsubscribe()
})
}
})
}
},
mounted() {
//监听鼠标点击事件
// document.addEventListener('mouseup', (e) => {
// let _track = document.getElementById('notips');
// if (_track) {
// if (_track.contains(e.target)) {
// this.closeTips();//事件
// }
// }
// })
},
methods: {
//挂载websocket在vue上
async mountWebsockt() {
let vm = this
try {
const token = 'Bearer ' + vm.$store.state.account.token
const apiUrl = getBaseUrl().replace(/^https?\:\/\//i, "")
const wsHeader = getBaseUrl().slice(0, 5) === 'https' ? 'wss' : 'ws'
vm.$root.$wsmaintenance = new WebsocketService(
`${wsHeader}://${apiUrl}/oauth/websocket/maintenance?token=${token}`
)
} catch (error) {
console.error('websocket创建失败')
}
},
closeTips(id) {
this.$root.$wsmaintenance.next({ op : "update", update: { id : id}})
this.notificatio.close()
}
},
}
</script>
<style lang='scss'>
.noticelog-bottom {
margin-bottom: 5px;
word-break: break-all;
}
.noticelog-btn {
color: #409eff;
float: right;
}
</style>
组件中调用
<template>
<div style="display: none"></div>
</template>
<script>
import { WebsocketService } from '@/api/WebsocketService.js'
import realTimeMonitorApi from '@/api/gasLeakMonitor/realTimeMonitor.js'
import { Notification } from 'element-ui'
import { map } from 'rxjs'
import routerMixin from '@/mixins/router.js'
import messageManageApi from '@/api/customerServiceManage/messageManage'
import { notifications } from '@/views/gmis/customerServiceManage/messageManage/constant.js'
export default {
name: 'NotifictionMessage',
mixins: [routerMixin],
data() {
return {
notifications: [],
currentSystemTypeId: null,
}
},
created() {
//刷新创建websocket
let vm = this
if (vm.$store.state.account.token != '') {
vm.mountWebsockt().then(() => {
if (vm.$root.$websocket) {
//全局通知消息
const observable = this.$root.$websocket.multiplex(
() => ({ topic: 'PUSH_ALARM_SYSTEM_PUSH_POP_UP_WINDOW', operation: 'open' }),
() => ({ topic: 'PUSH_ALARM_SYSTEM_PUSH_POP_UP_WINDOW', operation: 'close' }),
data => data.module == 'PUSH_ALARM_SYSTEM' && data.type == 'PUSH_POP_UP_WINDOW'
)
const subscription = observable.pipe(map(item => item.data)).subscribe(data => {
this.$store.commit(
'account/setMessageCount',
this.$store.state.account.messageCount + 1
)
vm.notifications.push(data)
if (vm.notifications.length > 6) {
Notification.closeAll()
vm.$notify({
message: `您收到了${vm.notifications.length}条新消息`,
position: 'bottom-right',
onClick() {
vm.currentSystemTypeId = '4'
vm.getRouter(vm.currentSystemTypeId, {
path: '/customerServiceManage/messageManage/Index',
params: JSON.parse(data.jsonParam),
})
},
})
} else {
const notification = vm.$notify({
message: data.content,
position: 'bottom-right',
onClick() {
const redirectUrl = notifications[data.type].value[data.module].redirectUrl
if (redirectUrl) {
vm.currentSystemTypeId = redirectUrl['systemTypeId']
if (data.module == 'NOTIFY_ALARM_SYSTEM') {
vm.markReadedStatus(data)
let jsonParam = JSON.parse(data.jsonParam)
if (jsonParam.customerTypeName == 'RESIDENT') {
vm.getRouter('21', {
path: '/householdLeakMonitor/inhabitantGasLeakEvent',
query: { eventId: JSON.parse(data.jsonParam).eventId },
})
} else {
vm.getRouter('21', {
path: '/householdLeakMonitor/businessGasLeakEvent',
query: { eventId: JSON.parse(data.jsonParam).eventId },
})
}
} else {
vm.getRouter(vm.currentSystemTypeId, {
path: redirectUrl['path'],
query: JSON.parse(data.jsonParam),
})
}
vm.$store.commit(
'account/setMessageCount',
vm.$store.state.account.messageCount - 1
)
}
notification.close()
},
})
}
})
vm.$once('hook:beforeDestroy', () => {
subscription.unsubscribe()
})
}
})
} else {
this.$emit('ws-ready')
}
},
methods: {
//挂载websocket在vue上
async mountWebsockt() {
let vm = this
try {
const {
data: { isSuccess, data },
} = await realTimeMonitorApi.getWebsocketUrl()
if (isSuccess) {
const user = vm.$store.state.account.user
const token = 'Bearer ' + vm.$store.state.account.token
vm.$root.$websocket = new WebsocketService(
`ws://${data.ip + ':' + data.port + data.path}?token=${token}&tenant=${
user.tenantId
}&account=${user.account}`
)
}
} catch (error) {
console.error('websocket创建失败')
}
this.$emit('ws-ready')
},
//标记已读
async markReadedStatus(data) {
const {
data: { isSuccess },
} = await messageManageApi.updateReadStatus({
id: data.receiveId,
isRead: true,
})
},
},
}
</script>
updateFeaturebyWebsocket() {
let vm = this
const alarmObservable = vm.$root.$websocket.multiplex(
() => ({ topic: 'PUSH_ALARM_SYSTEM_PUSH_WARN', operation: 'open' }),
() => ({ topic: 'PUSH_ALARM_SYSTEM_PUSH_WARN', operation: 'close' }),
data => data.module == 'PUSH_ALARM_SYSTEM' && data.type == 'PUSH_WARN'
)
const subscription = alarmObservable.pipe(map(item => item.data)).subscribe(data => {
if (vm.vectorSource) {
const feature = vm.vectorSource.getFeatureById(data.pointId)
if (feature) {
vm.vectorSource.removeFeature(feature)
const newFeature = new Feature({
geometry: new Point([parseFloat(data.longitude), parseFloat(data.latitude)]),
properties: {
...data,
},
})
newFeature.setId(data.pointId)
vm.vectorSource.addFeature(newFeature)
}
}
})
vm.$once('hook:beforeDestroy', () => {
subscription.unsubscribe()
})
},
第二次链接
<template>
<div style="display: none"></div>
</template>
<script>
import { WebsocketService } from '@/api/WebsocketService.js'
import realTimeMonitorApi from '@/api/gasLeakMonitor/realTimeMonitor.js'
import { Notification } from 'element-ui'
import { map } from 'rxjs'
import routerMixin from '@/mixins/router.js'
import messageManageApi from '@/api/customerServiceManage/messageManage'
import { notifications } from '@/views/gmis/customerServiceManage/messageManage/constant.js'
export default {
name: 'NotifictionMessage',
mixins: [routerMixin],
data() {
return {
notifications: [],
currentSystemTypeId: null,
}
},
created() {
//刷新创建websocket
let vm = this
if (vm.$store.state.account.token != '') {
vm.mountWebsockt().then(() => {
if (vm.$root.$websocket) {
//全局通知消息
const observable = this.$root.$websocket.multiplex(
() => ({ topic: 'PUSH_ALARM_SYSTEM_PUSH_POP_UP_WINDOW', operation: 'open' }),
() => ({ topic: 'PUSH_ALARM_SYSTEM_PUSH_POP_UP_WINDOW', operation: 'close' }),
data => data.module == 'PUSH_ALARM_SYSTEM' && data.type == 'PUSH_POP_UP_WINDOW'
)
const subscription = observable.pipe(map(item => item.data)).subscribe(data => {
this.$store.commit(
'account/setMessageCount',
this.$store.state.account.messageCount + 1
)
vm.notifications.push(data)
if (vm.notifications.length > 6) {
Notification.closeAll()
vm.$notify({
message: `您收到了${vm.notifications.length}条新消息`,
position: 'bottom-right',
onClick() {
vm.currentSystemTypeId = '4'
vm.getRouter(vm.currentSystemTypeId, {
path: '/customerServiceManage/messageManage/Index',
params: JSON.parse(data.jsonParam),
})
},
})
} else {
const notification = vm.$notify({
message: data.content,
position: 'bottom-right',
onClick() {
const redirectUrl = notifications[data.type].value[data.module].redirectUrl
if (redirectUrl) {
vm.currentSystemTypeId = redirectUrl['systemTypeId']
if (data.module == 'NOTIFY_ALARM_SYSTEM') {
vm.markReadedStatus(data)
let jsonParam = JSON.parse(data.jsonParam)
if (jsonParam.customerTypeName == 'RESIDENT') {
vm.getRouter('21', {
path: '/householdLeakMonitor/inhabitantGasLeakEvent',
query: { eventId: JSON.parse(data.jsonParam).eventId },
})
} else {
vm.getRouter('21', {
path: '/householdLeakMonitor/businessGasLeakEvent',
query: { eventId: JSON.parse(data.jsonParam).eventId },
})
}
} else {
vm.getRouter(vm.currentSystemTypeId, {
path: redirectUrl['path'],
query: JSON.parse(data.jsonParam),
})
}
vm.$store.commit(
'account/setMessageCount',
vm.$store.state.account.messageCount - 1
)
}
notification.close()
},
})
}
})
vm.$once('hook:beforeDestroy', () => {
subscription.unsubscribe()
})
}
})
} else {
this.$emit('ws-ready')
}
},
methods: {
//挂载websocket在vue上
async mountWebsockt() {
let vm = this
try {
const {
data: { isSuccess, data },
} = await realTimeMonitorApi.getWebsocketUrl()
if (isSuccess) {
const user = vm.$store.state.account.user
const token = 'Bearer ' + vm.$store.state.account.token
vm.$root.$websocket = new WebsocketService(
`ws://${data.ip + ':' + data.port + data.path}?token=${token}&tenant=${
user.tenantId
}&account=${user.account}`
)
}
} catch (error) {
console.error('websocket创建失败')
}
this.$emit('ws-ready')
},
//标记已读
async markReadedStatus(data) {
const {
data: { isSuccess },
} = await messageManageApi.updateReadStatus({
id: data.receiveId,
isRead: true,
})
},
},
}
</script>