2019-06-17 12:29:25 +08:00
|
|
|
|
<template>
|
2019-06-22 16:15:40 +08:00
|
|
|
|
<chat-renderer :paidMessages="paidMessages" :messages="messages" :css="config.css"></chat-renderer>
|
2019-06-17 12:29:25 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import config from '@/api/config'
|
|
|
|
|
import ChatRenderer from '@/components/ChatRenderer'
|
2019-06-22 16:15:40 +08:00
|
|
|
|
import * as constants from '@/components/ChatRenderer/constants'
|
2019-06-17 12:29:25 +08:00
|
|
|
|
|
2019-10-06 16:20:48 +08:00
|
|
|
|
const COMMAND_HEARTBEAT = 0
|
2019-09-23 22:22:27 +08:00
|
|
|
|
const COMMAND_JOIN_ROOM = 1
|
|
|
|
|
const COMMAND_ADD_TEXT = 2
|
|
|
|
|
const COMMAND_ADD_GIFT = 3
|
|
|
|
|
const COMMAND_ADD_MEMBER = 4
|
|
|
|
|
const COMMAND_ADD_SUPER_CHAT = 5
|
|
|
|
|
const COMMAND_DEL_SUPER_CHAT = 6
|
2019-06-17 12:29:25 +08:00
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
name: 'Room',
|
|
|
|
|
components: {
|
|
|
|
|
ChatRenderer
|
|
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
let cfg = {...config.DEFAULT_CONFIG}
|
|
|
|
|
cfg.blockKeywords = cfg.blockKeywords.split('\n').filter(val => val)
|
|
|
|
|
cfg.blockUsers = cfg.blockUsers.split('\n').filter(val => val)
|
2019-06-20 23:53:34 +08:00
|
|
|
|
cfg.maxSpeed = 0
|
2019-06-17 12:29:25 +08:00
|
|
|
|
return {
|
|
|
|
|
config: cfg,
|
2019-10-06 16:20:48 +08:00
|
|
|
|
|
2019-06-17 12:29:25 +08:00
|
|
|
|
websocket: null,
|
2019-10-06 16:20:48 +08:00
|
|
|
|
retryCount: 0,
|
|
|
|
|
isDestroying: false,
|
|
|
|
|
heartbeatTimerId: null,
|
|
|
|
|
|
2019-06-20 23:53:34 +08:00
|
|
|
|
messagesBufferTimerId: null,
|
|
|
|
|
nextId: 0,
|
|
|
|
|
messagesBuffer: [], // 暂时不显示的消息,可能会丢弃
|
2019-06-22 16:15:40 +08:00
|
|
|
|
messages: [], // 正在显示的消息
|
|
|
|
|
paidMessages: []
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
2019-10-06 16:20:48 +08:00
|
|
|
|
created() {
|
|
|
|
|
this.wsConnect()
|
2019-06-17 12:29:25 +08:00
|
|
|
|
if (this.$route.query.config_id) {
|
2019-10-06 16:20:48 +08:00
|
|
|
|
this.updateConfig(this.$route.query.config_id)
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
beforeDestroy() {
|
2019-06-20 23:53:34 +08:00
|
|
|
|
if (this.messagesBufferTimerId) {
|
|
|
|
|
window.clearInterval(this.messagesBufferTimerId)
|
|
|
|
|
}
|
2019-10-06 16:20:48 +08:00
|
|
|
|
this.isDestroying = true
|
2019-06-17 12:29:25 +08:00
|
|
|
|
this.websocket.close()
|
|
|
|
|
},
|
2019-06-20 23:53:34 +08:00
|
|
|
|
watch: {
|
|
|
|
|
config(val) {
|
|
|
|
|
if (this.messagesBufferTimerId) {
|
|
|
|
|
window.clearInterval(this.messagesBufferTimerId)
|
|
|
|
|
this.messagesBufferTimerId = null
|
|
|
|
|
}
|
|
|
|
|
if (val.maxSpeed > 0) {
|
2019-10-06 16:20:48 +08:00
|
|
|
|
this.messagesBufferTimerId = window.setInterval(this.handleMessagesBuffer, 1000 / val.maxSpeed)
|
2019-06-20 23:53:34 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
2019-06-17 12:29:25 +08:00
|
|
|
|
methods: {
|
2019-10-06 16:20:48 +08:00
|
|
|
|
async updateConfig(configId) {
|
|
|
|
|
try {
|
|
|
|
|
let cfg = await config.getRemoteConfig(configId)
|
|
|
|
|
cfg.blockKeywords = cfg.blockKeywords.split('\n').filter(val => val)
|
|
|
|
|
cfg.blockUsers = cfg.blockUsers.split('\n').filter(val => val)
|
|
|
|
|
this.config = cfg
|
|
|
|
|
} catch (e) {
|
|
|
|
|
this.$message.error('获取配置失败:' + e)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
wsConnect() {
|
2019-10-13 17:02:54 +08:00
|
|
|
|
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'
|
2019-10-06 16:20:48 +08:00
|
|
|
|
// 开发时使用localhost:12450
|
2019-10-13 17:02:54 +08:00
|
|
|
|
const host = process.env.NODE_ENV === 'development' ? 'localhost:12450' : window.location.host
|
|
|
|
|
const url = `${protocol}://${host}/chat`
|
2019-10-06 16:20:48 +08:00
|
|
|
|
this.websocket = new WebSocket(url)
|
|
|
|
|
this.websocket.onopen = this.onWsOpen
|
|
|
|
|
this.websocket.onclose = this.onWsClose
|
|
|
|
|
this.websocket.onmessage = this.onWsMessage
|
|
|
|
|
this.heartbeatTimerId = window.setInterval(this.sendHeartbeat, 10 * 1000)
|
|
|
|
|
},
|
|
|
|
|
sendHeartbeat() {
|
|
|
|
|
this.websocket.send(JSON.stringify({
|
|
|
|
|
cmd: COMMAND_HEARTBEAT
|
|
|
|
|
}))
|
|
|
|
|
},
|
2019-06-17 12:29:25 +08:00
|
|
|
|
onWsOpen() {
|
2019-10-06 16:20:48 +08:00
|
|
|
|
this.retryCount = 0
|
2019-06-17 12:29:25 +08:00
|
|
|
|
this.websocket.send(JSON.stringify({
|
|
|
|
|
cmd: COMMAND_JOIN_ROOM,
|
|
|
|
|
data: {
|
|
|
|
|
roomId: parseInt(this.$route.params.roomId)
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
},
|
2019-10-06 16:20:48 +08:00
|
|
|
|
onWsClose() {
|
|
|
|
|
if (this.heartbeatTimerId) {
|
|
|
|
|
window.clearInterval(this.heartbeatTimerId)
|
|
|
|
|
this.heartbeatTimerId = null
|
|
|
|
|
}
|
|
|
|
|
if (this.isDestroying) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
window.console.log(`掉线重连中${++this.retryCount}`)
|
|
|
|
|
this.wsConnect()
|
|
|
|
|
},
|
2019-06-17 12:29:25 +08:00
|
|
|
|
onWsMessage(event) {
|
|
|
|
|
let {cmd, data} = JSON.parse(event.data)
|
|
|
|
|
let message = null
|
|
|
|
|
let time = data.timestamp ? new Date(data.timestamp * 1000) : new Date()
|
2019-10-06 12:23:47 +08:00
|
|
|
|
switch (cmd) {
|
2019-06-17 12:29:25 +08:00
|
|
|
|
case COMMAND_ADD_TEXT:
|
2019-06-20 23:53:34 +08:00
|
|
|
|
if (!this.config.showDanmaku || !this.filterTextMessage(data) || this.mergeSimilar(data.content)) {
|
2019-06-17 12:29:25 +08:00
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
message = {
|
2019-10-06 12:23:47 +08:00
|
|
|
|
id: `text_${this.nextId++}`,
|
2019-06-22 16:15:40 +08:00
|
|
|
|
type: constants.MESSAGE_TYPE_TEXT,
|
2019-06-17 12:29:25 +08:00
|
|
|
|
avatarUrl: data.avatarUrl,
|
2019-07-18 08:31:58 +08:00
|
|
|
|
time: time,
|
2019-06-17 12:29:25 +08:00
|
|
|
|
authorName: data.authorName,
|
|
|
|
|
authorType: data.authorType,
|
|
|
|
|
content: data.content,
|
2019-06-20 20:03:07 +08:00
|
|
|
|
privilegeType: data.privilegeType,
|
2019-06-17 12:29:25 +08:00
|
|
|
|
repeated: 1
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
case COMMAND_ADD_GIFT: {
|
2019-06-20 23:53:34 +08:00
|
|
|
|
if (!this.config.showGift) {
|
|
|
|
|
break
|
|
|
|
|
}
|
2019-06-17 12:29:25 +08:00
|
|
|
|
let price = data.totalCoin / 1000
|
2019-09-23 22:22:27 +08:00
|
|
|
|
if (price < this.config.minGiftPrice) { // 丢人
|
2019-06-17 12:29:25 +08:00
|
|
|
|
break
|
2019-09-23 22:22:27 +08:00
|
|
|
|
}
|
2019-06-17 12:29:25 +08:00
|
|
|
|
message = {
|
2019-10-06 12:23:47 +08:00
|
|
|
|
id: `gift_${this.nextId++}`,
|
2019-09-23 22:22:27 +08:00
|
|
|
|
type: constants.MESSAGE_TYPE_SUPER_CHAT,
|
2019-06-17 12:29:25 +08:00
|
|
|
|
avatarUrl: data.avatarUrl,
|
|
|
|
|
authorName: data.authorName,
|
|
|
|
|
price: price,
|
2019-07-18 08:31:58 +08:00
|
|
|
|
time: time,
|
2019-09-23 22:22:27 +08:00
|
|
|
|
content: '' // 有了SC,礼物不需要内容了
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
2019-06-20 20:03:07 +08:00
|
|
|
|
case COMMAND_ADD_MEMBER:
|
2019-09-23 22:22:27 +08:00
|
|
|
|
if (!this.config.showGift || !this.filterSuperChatMessage(data)) {
|
2019-06-20 23:53:34 +08:00
|
|
|
|
break
|
|
|
|
|
}
|
2019-06-17 12:29:25 +08:00
|
|
|
|
message = {
|
2019-10-06 12:23:47 +08:00
|
|
|
|
id: `member_${this.nextId++}`,
|
2019-06-22 16:15:40 +08:00
|
|
|
|
type: constants.MESSAGE_TYPE_MEMBER,
|
2019-06-17 12:29:25 +08:00
|
|
|
|
avatarUrl: data.avatarUrl,
|
2019-07-18 08:31:58 +08:00
|
|
|
|
time: time,
|
2019-06-17 12:29:25 +08:00
|
|
|
|
authorName: data.authorName,
|
|
|
|
|
title: 'NEW MEMBER!',
|
2019-07-15 21:30:52 +08:00
|
|
|
|
content: `Welcome ${data.authorName}!`
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
|
|
|
|
break
|
2019-09-23 22:22:27 +08:00
|
|
|
|
case COMMAND_ADD_SUPER_CHAT:
|
|
|
|
|
if (!this.config.showGift) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if (data.price < this.config.minGiftPrice) { // 丢人
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
message = {
|
2019-10-06 12:23:47 +08:00
|
|
|
|
id: `sc_${data.id}`,
|
2019-09-23 22:22:27 +08:00
|
|
|
|
type: constants.MESSAGE_TYPE_SUPER_CHAT,
|
|
|
|
|
avatarUrl: data.avatarUrl,
|
|
|
|
|
authorName: data.authorName,
|
|
|
|
|
price: data.price,
|
|
|
|
|
time: time,
|
|
|
|
|
content: data.content
|
|
|
|
|
}
|
|
|
|
|
break
|
2019-10-06 12:23:47 +08:00
|
|
|
|
case COMMAND_DEL_SUPER_CHAT: {
|
|
|
|
|
let arrays = [this.messages, this.messagesBuffer, this.paidMessages]
|
|
|
|
|
for (let id of data.ids) {
|
|
|
|
|
id = `sc_${id}`
|
|
|
|
|
for (let arr of arrays) {
|
|
|
|
|
for (let i = 0; i < arr.length; i++) {
|
|
|
|
|
if (arr[i].id === id) {
|
|
|
|
|
arr.splice(i, 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-23 22:22:27 +08:00
|
|
|
|
break
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
2019-10-06 12:23:47 +08:00
|
|
|
|
}
|
2019-06-17 12:29:25 +08:00
|
|
|
|
if (message) {
|
2019-06-20 23:53:34 +08:00
|
|
|
|
this.addMessageBuffer(message)
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
filterTextMessage(data) {
|
|
|
|
|
if (this.config.blockGiftDanmaku && data.isGiftDanmaku) {
|
|
|
|
|
return false
|
|
|
|
|
} else if (this.config.blockLevel > 0 && data.authorLevel < this.config.blockLevel) {
|
|
|
|
|
return false
|
|
|
|
|
} else if (this.config.blockNewbie && data.isNewbie) {
|
|
|
|
|
return false
|
|
|
|
|
} else if (this.config.blockNotMobileVerified && !data.isMobileVerified) {
|
|
|
|
|
return false
|
2019-06-21 17:38:22 +08:00
|
|
|
|
} else if (this.config.blockMedalLevel > 0 && data.medalLevel < this.config.blockMedalLevel) {
|
|
|
|
|
return false
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
|
|
|
|
for (let keyword of this.config.blockKeywords) {
|
|
|
|
|
if (data.content.indexOf(keyword) !== -1) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (let user of this.config.blockUsers) {
|
|
|
|
|
if (data.authorName === user) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
},
|
2019-09-23 22:22:27 +08:00
|
|
|
|
filterSuperChatMessage(data) {
|
|
|
|
|
for (let keyword of this.config.blockKeywords) {
|
|
|
|
|
if (data.content.indexOf(keyword) !== -1) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (let user of this.config.blockUsers) {
|
|
|
|
|
if (data.authorName === user) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
},
|
2019-06-17 12:29:25 +08:00
|
|
|
|
mergeSimilar(content) {
|
|
|
|
|
if (!this.config.mergeSimilarDanmaku) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
for (let i = this.messages.length - 1; i >= 0 && i >= this.messages.length - 5; i--) {
|
|
|
|
|
let message = this.messages[i]
|
|
|
|
|
if (
|
|
|
|
|
(message.content.indexOf(content) !== -1 || content.indexOf(message.content) !== -1) // 包含对方
|
|
|
|
|
&& Math.abs(message.content.length - content.length) < Math.min(message.content.length, content.length) // 长度差比两者长度都小
|
|
|
|
|
) {
|
|
|
|
|
message.repeated++
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
2019-06-20 23:53:34 +08:00
|
|
|
|
},
|
|
|
|
|
addMessageBuffer(message) {
|
2019-10-06 12:23:47 +08:00
|
|
|
|
if (this.config.maxSpeed > 0 && message.type === constants.MESSAGE_TYPE_TEXT) {
|
2019-06-20 23:53:34 +08:00
|
|
|
|
message.addTime = new Date()
|
|
|
|
|
this.messagesBuffer.push(message)
|
|
|
|
|
} else {
|
|
|
|
|
// 无速度限制或者是礼物
|
|
|
|
|
this.addMessageShow(message)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
addMessageShow(message) {
|
2019-06-22 16:15:40 +08:00
|
|
|
|
message.addTime = new Date()
|
2019-06-20 23:53:34 +08:00
|
|
|
|
this.messages.push(message)
|
2019-06-22 16:15:40 +08:00
|
|
|
|
if (message.type !== constants.MESSAGE_TYPE_TEXT) {
|
|
|
|
|
this.paidMessages.unshift(message)
|
|
|
|
|
}
|
2019-06-21 16:50:18 +08:00
|
|
|
|
// 防止同时添加和删除项目时所有的项目重新渲染 https://github.com/vuejs/vue/issues/6857
|
|
|
|
|
this.$nextTick(() => {
|
2019-09-16 22:15:32 +08:00
|
|
|
|
if (this.messages.length > this.config.maxNumber) {
|
|
|
|
|
this.messages.splice(0, this.messages.length - this.config.maxNumber)
|
2019-06-21 16:50:18 +08:00
|
|
|
|
}
|
|
|
|
|
})
|
2019-06-20 23:53:34 +08:00
|
|
|
|
},
|
|
|
|
|
handleMessagesBuffer() {
|
|
|
|
|
// 3秒内未发出则丢弃
|
2019-06-22 16:15:40 +08:00
|
|
|
|
let i
|
2019-06-20 23:53:34 +08:00
|
|
|
|
let curTime = new Date()
|
2019-06-22 16:15:40 +08:00
|
|
|
|
for (i = 0; i < this.messagesBuffer.length; i++) {
|
|
|
|
|
if (curTime - this.messagesBuffer[i].addTime <= 3 * 1000) {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-03 00:12:40 +08:00
|
|
|
|
this.messagesBuffer.splice(0, i)
|
2019-06-20 23:53:34 +08:00
|
|
|
|
if (this.messagesBuffer.length <= 0) {
|
|
|
|
|
return
|
|
|
|
|
}
|
2019-07-03 00:12:40 +08:00
|
|
|
|
let message = this.messagesBuffer.shift()
|
|
|
|
|
// 防止短时间发送多条时不能合并
|
|
|
|
|
if (this.mergeSimilar(message.content)) {
|
|
|
|
|
this.handleMessagesBuffer()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
this.addMessageShow(message)
|
2019-06-17 12:29:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|