bug修复
This commit is contained in:
@@ -648,6 +648,16 @@ async function saveAnnouncement() {
|
||||
|
||||
watch(() => props.roomId, loadData, { immediate: true })
|
||||
|
||||
// 监听群通知,自动刷新成员列表
|
||||
watch(() => chatStore.lastGroupNotification, (notif) => {
|
||||
if (notif && notif.room_id === props.roomId) {
|
||||
// 延迟刷新,确保后端数据已更新
|
||||
setTimeout(() => {
|
||||
loadData()
|
||||
}, 300)
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
onMounted(() => {
|
||||
if (chatStore.contacts.length === 0) {
|
||||
contactApi.getContacts().then(res => chatStore.setContacts(res))
|
||||
|
||||
@@ -15,32 +15,49 @@
|
||||
<p class="text-gray-400 text-xs">无法在此群聊中发送消息</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 遮罩层:禁言状态 -->
|
||||
<div
|
||||
v-else-if="isMuted"
|
||||
class="absolute inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center cursor-not-allowed"
|
||||
@click.stop
|
||||
@contextmenu.prevent
|
||||
@mousedown.prevent
|
||||
@selectstart.prevent
|
||||
>
|
||||
<div class="text-center px-6">
|
||||
<i class="fas fa-volume-mute text-4xl text-orange-500 mb-3"></i>
|
||||
<p class="text-white font-semibold text-sm mb-1">您已被禁言</p>
|
||||
<p v-if="muteCountdown" class="text-orange-400 text-sm font-mono">{{ muteCountdown }}</p>
|
||||
<p v-else class="text-gray-400 text-xs">无法在此群聊中发送消息</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-6 text-gray-400 text-lg mb-3 px-2 items-center">
|
||||
<i
|
||||
class="far fa-smile hover:text-primary transition-all transform hover:scale-125 hover:rotate-12"
|
||||
:class="isBlocked ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
:class="cannotSend ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
title="表情"
|
||||
@click="!isBlocked && insertEmoji('😊')"
|
||||
@click="!cannotSend && insertEmoji('😊')"
|
||||
></i>
|
||||
<i
|
||||
class="far fa-image hover:text-green-400 transition-all transform hover:scale-125"
|
||||
:class="isBlocked ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!isBlocked && triggerFile(1)"
|
||||
:class="cannotSend ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!cannotSend && triggerFile(1)"
|
||||
title="发送图片"
|
||||
></i>
|
||||
|
||||
<!-- 新增:视频上传按钮 -->
|
||||
<i
|
||||
class="fas fa-video hover:text-purple-400 transition-all transform hover:scale-125"
|
||||
:class="isBlocked ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!isBlocked && triggerFile(3)"
|
||||
:class="cannotSend ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!cannotSend && triggerFile(3)"
|
||||
title="发送视频"
|
||||
></i>
|
||||
|
||||
<i
|
||||
class="fas fa-folder-plus hover:text-yellow-400 transition-all transform hover:scale-125"
|
||||
:class="isBlocked ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!isBlocked && triggerFile(8)"
|
||||
:class="cannotSend ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!cannotSend && triggerFile(8)"
|
||||
title="发送文件"
|
||||
></i>
|
||||
|
||||
@@ -48,20 +65,20 @@
|
||||
<i
|
||||
v-if="isGroupChat && mentionUsers.length > 0"
|
||||
class="fas fa-at hover:text-blue-400 transition-all transform hover:scale-125"
|
||||
:class="isBlocked ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!isBlocked && showMentionPickerManual()"
|
||||
:class="cannotSend ? 'text-gray-600 cursor-not-allowed' : 'text-gray-400 cursor-pointer'"
|
||||
@click="!cannotSend && showMentionPickerManual()"
|
||||
title="@群成员"
|
||||
></i>
|
||||
|
||||
<!-- 长按录音 -->
|
||||
<div
|
||||
class="relative flex items-center group select-none ml-auto mr-2"
|
||||
:class="isBlocked ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@mousedown="!isBlocked && handleRecordStart()"
|
||||
@touchstart.passive="!isBlocked && handleRecordStart()"
|
||||
@mouseup="!isBlocked && handleRecordStop()"
|
||||
@touchend.prevent="!isBlocked && handleRecordStop()"
|
||||
@mouseleave="!isBlocked && handleRecordCancel()"
|
||||
:class="cannotSend ? 'cursor-not-allowed' : 'cursor-pointer'"
|
||||
@mousedown="!cannotSend && handleRecordStart()"
|
||||
@touchstart.passive="!cannotSend && handleRecordStart()"
|
||||
@mouseup="!cannotSend && handleRecordStop()"
|
||||
@touchend.prevent="!cannotSend && handleRecordStop()"
|
||||
@mouseleave="!cannotSend && handleRecordCancel()"
|
||||
>
|
||||
<div
|
||||
class="w-8 h-8 rounded-full flex items-center justify-center transition-all shadow-md"
|
||||
@@ -83,7 +100,7 @@
|
||||
<textarea
|
||||
ref="textareaRef"
|
||||
:value="modelValue"
|
||||
:disabled="isBlocked"
|
||||
:disabled="cannotSend"
|
||||
class="w-full bg-transparent border-none text-white resize-none h-10 max-h-32 py-2 px-1 text-sm focus:outline-none scrollbar-thin placeholder-gray-500 leading-6 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
placeholder="输入消息 (Enter 发送)..."
|
||||
@input="handleInput"
|
||||
@@ -92,7 +109,7 @@
|
||||
></textarea>
|
||||
<div
|
||||
class="w-10 h-10 rounded-2xl flex items-center justify-center ml-2 transition-all duration-300 shadow-lg"
|
||||
:class="isBlocked
|
||||
:class="cannotSend
|
||||
? 'bg-gray-700 text-gray-500 scale-90 rotate-90 opacity-50 cursor-not-allowed'
|
||||
: (modelValue.trim() ? 'bg-primary hover:bg-indigo-500 text-white scale-100 rotate-0 cursor-pointer' : 'bg-gray-700 text-gray-500 scale-90 rotate-90 opacity-50 cursor-not-allowed')"
|
||||
@click="handleSend"
|
||||
@@ -142,13 +159,81 @@ const toastStore = useToastStore()
|
||||
interface Props {
|
||||
modelValue: string
|
||||
isRecording: boolean
|
||||
isBlocked?: boolean // 是否被禁言(被移除或退出群聊)
|
||||
isBlocked?: boolean // 是否被移除或退出群聊
|
||||
isMuted?: boolean // 是否被禁言
|
||||
mutedUntil?: string | null // 禁言到期时间
|
||||
isGroupChat?: boolean // 是否是群聊
|
||||
roomMembers?: Record<string, { name: string; avatar?: string }> // 群成员映射
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
// 禁言倒计时
|
||||
const muteCountdown = ref('')
|
||||
let muteTimer: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
// 计算是否可以发送消息(被移除或被禁言都不能发)
|
||||
const cannotSend = computed(() => props.isBlocked || props.isMuted)
|
||||
|
||||
// 更新禁言倒计时
|
||||
function updateMuteCountdown() {
|
||||
if (!props.mutedUntil) {
|
||||
muteCountdown.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
const now = new Date().getTime()
|
||||
const end = new Date(props.mutedUntil).getTime()
|
||||
const diff = end - now
|
||||
|
||||
if (diff <= 0) {
|
||||
muteCountdown.value = ''
|
||||
if (muteTimer) {
|
||||
clearInterval(muteTimer)
|
||||
muteTimer = null
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 计算剩余时间
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||||
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
|
||||
const seconds = Math.floor((diff % (1000 * 60)) / 1000)
|
||||
|
||||
if (days > 0) {
|
||||
muteCountdown.value = `${days}天${hours}小时后解除`
|
||||
} else if (hours > 0) {
|
||||
muteCountdown.value = `${hours}小时${minutes}分钟后解除`
|
||||
} else if (minutes > 0) {
|
||||
muteCountdown.value = `${minutes}分${seconds}秒后解除`
|
||||
} else {
|
||||
muteCountdown.value = `${seconds}秒后解除`
|
||||
}
|
||||
}
|
||||
|
||||
// 监听禁言状态变化
|
||||
watch(() => props.mutedUntil, (newVal) => {
|
||||
if (muteTimer) {
|
||||
clearInterval(muteTimer)
|
||||
muteTimer = null
|
||||
}
|
||||
|
||||
if (newVal && props.isMuted) {
|
||||
updateMuteCountdown()
|
||||
muteTimer = setInterval(updateMuteCountdown, 1000)
|
||||
} else {
|
||||
muteCountdown.value = ''
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
onUnmounted(() => {
|
||||
if (muteTimer) {
|
||||
clearInterval(muteTimer)
|
||||
muteTimer = null
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
send: [mentionUserIds?: string[]]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div
|
||||
class="flex items-center justify-center text-white font-bold shadow-md transition overflow-hidden"
|
||||
:class="[sizeClass, roundedClass, { 'cursor-pointer hover:opacity-80': $attrs.onClick }]"
|
||||
:style="isImage ? {} : { background: color || generateColor(name || avatar || '') }"
|
||||
:style="customSizeStyle"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<img
|
||||
@@ -24,7 +24,7 @@ interface Props {
|
||||
avatar?: string
|
||||
name?: string
|
||||
color?: string
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'contact'
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'contact' | number
|
||||
rounded?: 'full' | 'xl' | 'lg'
|
||||
}
|
||||
|
||||
@@ -64,16 +64,43 @@ const isImage = computed(() => {
|
||||
return false
|
||||
})
|
||||
|
||||
// 预定义尺寸映射
|
||||
const sizeMap: Record<string, string> = {
|
||||
xs: 'w-7 h-7 text-[10px]',
|
||||
sm: 'w-9 h-9 text-xs',
|
||||
md: 'w-10 h-10 text-sm',
|
||||
lg: 'w-12 h-12 text-base',
|
||||
xl: 'w-16 h-16 text-xl',
|
||||
'2xl': 'w-24 h-24 text-2xl',
|
||||
contact: 'w-11 h-11 text-lg',
|
||||
}
|
||||
|
||||
// 尺寸 class(仅用于预定义尺寸)
|
||||
const sizeClass = computed(() => {
|
||||
const sizes = {
|
||||
sm: 'w-9 h-9 text-xs',
|
||||
md: 'w-10 h-10 text-sm',
|
||||
lg: 'w-12 h-12 text-base',
|
||||
xl: 'w-16 h-16 text-xl',
|
||||
'2xl': 'w-24 h-24 text-2xl',
|
||||
contact: 'w-11 h-11 text-lg',
|
||||
if (typeof props.size === 'number') {
|
||||
return '' // 数字尺寸使用 style
|
||||
}
|
||||
return sizes[props.size]
|
||||
return sizeMap[props.size] || sizeMap.md
|
||||
})
|
||||
|
||||
// 自定义尺寸样式(用于数字尺寸和背景色)
|
||||
const customSizeStyle = computed(() => {
|
||||
const style: Record<string, string> = {}
|
||||
|
||||
// 背景色
|
||||
if (!isImage.value) {
|
||||
style.background = props.color || generateColor(props.name || props.avatar || '')
|
||||
}
|
||||
|
||||
// 数字尺寸
|
||||
if (typeof props.size === 'number') {
|
||||
style.width = `${props.size}px`
|
||||
style.height = `${props.size}px`
|
||||
// 根据尺寸计算字体大小
|
||||
style.fontSize = `${Math.max(10, props.size * 0.4)}px`
|
||||
}
|
||||
|
||||
return style
|
||||
})
|
||||
|
||||
const roundedClass = computed(() => {
|
||||
|
||||
@@ -100,11 +100,47 @@ export const useChatStore = defineStore('chat', () => {
|
||||
messages.value[roomId] = []
|
||||
}
|
||||
|
||||
// 群通知相关状态
|
||||
const lastGroupNotification = ref<{ room_id: string; type: string; data: any } | null>(null)
|
||||
const myMuteStatus = ref<Record<string, string | null>>({}) // room_id -> muted_until
|
||||
|
||||
/**
|
||||
* 设置最后的群通知(用于触发群面板刷新)
|
||||
*/
|
||||
function setLastGroupNotification(notification: { room_id: string; type: string; data: any }) {
|
||||
lastGroupNotification.value = { ...notification, _timestamp: Date.now() } as any
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置我在某个群的禁言状态
|
||||
*/
|
||||
function setMyMuteStatus(roomId: string, mutedUntil: string | null) {
|
||||
myMuteStatus.value[roomId] = mutedUntil
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我在某个群是否被禁言
|
||||
*/
|
||||
function isMyMuted(roomId: string): boolean {
|
||||
const mutedUntil = myMuteStatus.value[roomId]
|
||||
if (!mutedUntil) return false
|
||||
return new Date(mutedUntil) > new Date()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的禁言到期时间
|
||||
*/
|
||||
function getMyMutedUntil(roomId: string): string | null {
|
||||
return myMuteStatus.value[roomId] || null
|
||||
}
|
||||
|
||||
return {
|
||||
currentTarget,
|
||||
messages,
|
||||
contacts,
|
||||
totalUnread,
|
||||
lastGroupNotification,
|
||||
myMuteStatus,
|
||||
setCurrentTarget,
|
||||
addMessage,
|
||||
getRoomMessages,
|
||||
@@ -113,6 +149,10 @@ export const useChatStore = defineStore('chat', () => {
|
||||
updateContactLastMsg,
|
||||
incrementUnread,
|
||||
clearRoomMessages,
|
||||
setLastGroupNotification,
|
||||
setMyMuteStatus,
|
||||
isMyMuted,
|
||||
getMyMutedUntil,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ export const storage = {
|
||||
// Current Tab (chat/contact/moment)
|
||||
setCurrentTab(tab: 'chat' | 'contact' | 'moment') {
|
||||
localStorage.setItem(CURRENT_TAB_KEY, tab)
|
||||
// 触发自定义事件通知 UI 更新
|
||||
window.dispatchEvent(new CustomEvent('app-tab-change', { detail: { tab } }))
|
||||
},
|
||||
|
||||
getCurrentTab(): 'chat' | 'contact' | 'moment' {
|
||||
|
||||
@@ -242,6 +242,8 @@
|
||||
v-model="inputText"
|
||||
:is-recording="isRecording"
|
||||
:is-blocked="isBlockedFromGroup"
|
||||
:is-muted="isMyMutedInCurrentGroup"
|
||||
:muted-until="myMutedUntilInCurrentGroup"
|
||||
:is-group-chat="isGroupChat"
|
||||
:room-members="currentRoomMembers"
|
||||
@send="handleSendText"
|
||||
@@ -773,16 +775,32 @@ const currentRoomMembers = computed(() => {
|
||||
return roomMembers.value[chatStore.currentTarget.room_id] || {}
|
||||
})
|
||||
|
||||
// 判断当前用户是否被禁言(被移除或退出群聊)
|
||||
// 判断当前用户是否被移除(不在群成员列表中)
|
||||
const isBlockedFromGroup = computed(() => {
|
||||
if (!isGroupChat.value || !chatStore.currentTarget?.room_id || !authStore.user) {
|
||||
return false
|
||||
}
|
||||
const currentMember = roomMembers.value[chatStore.currentTarget.room_id]?.[authStore.user.id]
|
||||
// 如果当前用户不在群成员列表中,则认为被禁言
|
||||
// 如果当前用户不在群成员列表中,则认为被移除
|
||||
return !currentMember
|
||||
})
|
||||
|
||||
// 判断当前用户是否在当前群中被禁言
|
||||
const isMyMutedInCurrentGroup = computed(() => {
|
||||
if (!isGroupChat.value || !chatStore.currentTarget?.room_id) {
|
||||
return false
|
||||
}
|
||||
return chatStore.isMyMuted(chatStore.currentTarget.room_id)
|
||||
})
|
||||
|
||||
// 获取当前用户在当前群的禁言到期时间
|
||||
const myMutedUntilInCurrentGroup = computed(() => {
|
||||
if (!isGroupChat.value || !chatStore.currentTarget?.room_id) {
|
||||
return null
|
||||
}
|
||||
return chatStore.getMyMutedUntil(chatStore.currentTarget.room_id)
|
||||
})
|
||||
|
||||
// 获取当前目标名称
|
||||
function getCurrentTargetName(): string {
|
||||
if (!chatStore.currentTarget) return ''
|
||||
@@ -1099,9 +1117,34 @@ function handleWebSocketMessage(message: ChatMessage) {
|
||||
message.isSelf = message.sender_user_id === authStore.user!.id
|
||||
message.extra = typeof message.extra === 'string' ? JSON.parse(message.extra || '{}') : message.extra
|
||||
|
||||
// 处理好友申请通知
|
||||
// 处理好友通知
|
||||
if (message.message_type === 5) {
|
||||
const extra = message.extra as any
|
||||
|
||||
// 处理好友资料更新通知
|
||||
if (extra.type === 'profile_update') {
|
||||
// 更新联系人列表中的用户信息
|
||||
const contact = chatStore.contacts.find(c => c.user_id === extra.user_id || c.id === extra.user_id)
|
||||
if (contact && contact.user) {
|
||||
if (extra.name) contact.user.name = extra.name
|
||||
if (extra.avatar) contact.user.avatar = extra.avatar
|
||||
}
|
||||
|
||||
// 更新当前聊天对象(如果正在和这个人聊天)
|
||||
const currentTarget = chatStore.currentTarget
|
||||
if (currentTarget && (currentTarget.user_id === extra.user_id || currentTarget.id === extra.user_id)) {
|
||||
if (currentTarget.user) {
|
||||
if (extra.name) currentTarget.user.name = extra.name
|
||||
if (extra.avatar) currentTarget.user.avatar = extra.avatar
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新会话列表
|
||||
conversationStore.loadConversations()
|
||||
return
|
||||
}
|
||||
|
||||
// 处理好友申请通知
|
||||
toastStore.showToast(
|
||||
'收到好友申请',
|
||||
'info',
|
||||
@@ -1120,20 +1163,52 @@ function handleWebSocketMessage(message: ChatMessage) {
|
||||
|
||||
// 处理群聊通知
|
||||
if (message.message_type === 7) {
|
||||
const extra = message.extra as any
|
||||
toastStore.showToast(
|
||||
'群聊通知',
|
||||
'info',
|
||||
5000,
|
||||
extra.title || message.content || '收到群聊通知',
|
||||
{
|
||||
label: '去查看',
|
||||
handler: () => {
|
||||
currentTab.value = 'contact'
|
||||
contactStore.setLeftPanelMode('group-notify')
|
||||
const extra = typeof message.extra === 'string' ? JSON.parse(message.extra || '{}') : (message.extra || {})
|
||||
const notifRoomId = extra.room_id || message.room_id
|
||||
|
||||
// 根据通知类型进行不同处理
|
||||
switch (extra.type) {
|
||||
case 'member_mute':
|
||||
case 'member_unmute':
|
||||
// 禁言/解除禁言通知 - 保存到 chatStore 以便 MessageInput 可以响应
|
||||
if (extra.target === authStore.user?.id) {
|
||||
// 自己被禁言/解除禁言
|
||||
chatStore.setMyMuteStatus(notifRoomId, extra.type === 'member_mute' ? extra.muted_until : null)
|
||||
}
|
||||
}
|
||||
)
|
||||
// 触发群成员刷新
|
||||
chatStore.setLastGroupNotification({ room_id: notifRoomId, type: extra.type, data: extra })
|
||||
break
|
||||
|
||||
case 'role_change':
|
||||
// 角色变更通知 - 触发群成员刷新
|
||||
chatStore.setLastGroupNotification({ room_id: notifRoomId, type: extra.type, data: extra })
|
||||
break
|
||||
|
||||
case 'member_invite':
|
||||
case 'member_remove':
|
||||
case 'member_leave':
|
||||
case 'member_join':
|
||||
// 成员变动通知 - 触发群成员刷新
|
||||
chatStore.setLastGroupNotification({ room_id: notifRoomId, type: extra.type, data: extra })
|
||||
break
|
||||
}
|
||||
|
||||
// 显示 Toast 通知(不是自己被禁言时)
|
||||
if (!(extra.type === 'member_mute' && extra.target === authStore.user?.id)) {
|
||||
toastStore.showToast(
|
||||
'群聊通知',
|
||||
'info',
|
||||
5000,
|
||||
message.content || extra.title || '收到群聊通知',
|
||||
{
|
||||
label: '去查看',
|
||||
handler: () => {
|
||||
currentTab.value = 'contact'
|
||||
contactStore.setLeftPanelMode('group-notify')
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2020,7 +2095,7 @@ onMounted(async () => {
|
||||
await wsManager.connect(authStore.user.id)
|
||||
wsManager.onMessage(handleWebSocketMessage)
|
||||
wsManager.onSignal(webrtc.handleSignaling)
|
||||
wsManager.onMomentNotification(momentStore.handleWsNotification)
|
||||
// 朋友圈通知已在 App.vue 中统一注册,避免重复
|
||||
}
|
||||
await loadContacts()
|
||||
await conversationStore.loadConversations()
|
||||
@@ -2049,11 +2124,24 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => isMobile.value = window.innerWidth < 768)
|
||||
|
||||
// 监听 tab 切换事件(用于从其他地方触发 tab 切换,如朋友圈通知)
|
||||
window.addEventListener('app-tab-change', handleTabChangeEvent)
|
||||
})
|
||||
|
||||
// Tab 切换事件处理
|
||||
function handleTabChangeEvent(e: Event) {
|
||||
const customEvent = e as CustomEvent<{ tab: 'chat' | 'contact' | 'moment' }>
|
||||
if (customEvent.detail?.tab) {
|
||||
currentTab.value = customEvent.detail.tab
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
wsManager.offMessage(handleWebSocketMessage)
|
||||
wsManager.offSignal(webrtc.handleSignaling)
|
||||
wsManager.offMomentNotification(momentStore.handleWsNotification)
|
||||
window.removeEventListener('app-tab-change', handleTabChangeEvent)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user