实现未读消息的全局事件处理

This commit is contained in:
jxxghp
2025-06-14 14:17:26 +08:00
parent 6cefdb5d37
commit 17ee5f456a
3 changed files with 68 additions and 86 deletions
+14
View File
@@ -6,6 +6,7 @@ import api from '@/api'
import { useAuthStore } from '@/stores/auth' import { useAuthStore } from '@/stores/auth'
import { getBrowserLocale, setI18nLanguage } from './plugins/i18n' import { getBrowserLocale, setI18nLanguage } from './plugins/i18n'
import { SupportedLocale } from '@/types/i18n' import { SupportedLocale } from '@/types/i18n'
import { checkAndEmitUnreadMessages } from '@/utils/badge'
// 生效主题 // 生效主题
const { global: globalTheme } = useTheme() const { global: globalTheme } = useTheme()
@@ -172,6 +173,11 @@ onMounted(async () => {
setTimeout(() => { setTimeout(() => {
// 移除加载动画,显示页面 // 移除加载动画,显示页面
animateAndRemoveLoader() animateAndRemoveLoader()
// 页面完全显示后,检查未读消息
setTimeout(() => {
checkAndEmitUnreadMessages()
}, 1000)
}, 1500) }, 1500)
}) })
}) })
@@ -180,6 +186,10 @@ onMounted(async () => {
document.addEventListener('visibilitychange', () => { document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') { if (document.visibilityState === 'visible') {
loadBackgroundImages() loadBackgroundImages()
// 页面恢复可见时检查未读消息
setTimeout(() => {
checkAndEmitUnreadMessages()
}, 500)
} }
}) })
@@ -188,6 +198,10 @@ onMounted(async () => {
// persisted属性为true表示页面是从bfcache中恢复的 // persisted属性为true表示页面是从bfcache中恢复的
if (event.persisted) { if (event.persisted) {
loadBackgroundImages() loadBackgroundImages()
// PWA恢复时检查未读消息
setTimeout(() => {
checkAndEmitUnreadMessages()
}, 500)
} }
}) })
}) })
+16 -57
View File
@@ -13,7 +13,7 @@ import { NavMenu } from '@/@layouts/types'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { filterMenusByPermission } from '@/utils/permission' import { filterMenusByPermission } from '@/utils/permission'
import { checkUnreadOnStartup } from '@/utils/badge' import { onUnreadMessage } from '@/utils/badge'
const display = useDisplay() const display = useDisplay()
const appMode = inject('pwaMode') const appMode = inject('pwaMode')
@@ -28,9 +28,6 @@ const superUser = computed(() => userStore.superUser)
// ShortcutBar 引用 // ShortcutBar 引用
const shortcutBarRef = ref<InstanceType<typeof ShortcutBar> | null>(null) const shortcutBarRef = ref<InstanceType<typeof ShortcutBar> | null>(null)
// 未读消息检查状态
const hasCheckedUnread = ref(false)
// 获取用户权限信息 // 获取用户权限信息
const userPermissions = computed(() => ({ const userPermissions = computed(() => ({
is_superuser: userStore.superUser, is_superuser: userStore.superUser,
@@ -65,57 +62,18 @@ function goBack() {
history.back() history.back()
} }
// 检查未读消息并自动打开消息弹窗 // 处理未读消息事件
async function checkUnreadMessages() { function handleUnreadMessage(count: number) {
if (!superUser.value || hasCheckedUnread.value) { if (superUser.value && count > 0) {
return // 只有超级用户才能看到消息,且每次会话只检查一次 // 延迟一点时间确保组件已渲染
} setTimeout(() => {
if (shortcutBarRef.value && typeof shortcutBarRef.value.openMessageDialog === 'function') {
hasCheckedUnread.value = true shortcutBarRef.value.openMessageDialog()
}
try { }, 500)
const unreadCount = await checkUnreadOnStartup()
if (unreadCount > 0) {
// 等待组件完全加载并重试打开消息弹窗
await waitAndOpenMessageDialog()
}
} catch (error) {
// 静默处理错误
} }
} }
// 等待组件准备好并打开消息弹窗
async function waitAndOpenMessageDialog() {
const maxRetries = 5
const retryDelay = 1000 // 1秒
for (let i = 0; i < maxRetries; i++) {
// 等待一段时间确保组件加载完成
await new Promise(resolve => setTimeout(resolve, retryDelay * (i + 1)))
// 检查ShortcutBar组件是否已经准备好
if (shortcutBarRef.value && typeof shortcutBarRef.value.openMessageDialog === 'function') {
shortcutBarRef.value.openMessageDialog()
return // 成功打开,退出重试循环
}
}
}
// 监听用户状态变化
watch(
superUser,
newValue => {
if (newValue && !hasCheckedUnread.value) {
// 用户状态变为超级用户且还没检查过未读消息时,延迟检查
setTimeout(() => {
checkUnreadMessages()
}, 1000)
}
},
{ immediate: true },
)
onMounted(() => { onMounted(() => {
// 获取菜单列表 // 获取菜单列表
startMenus.value = getMenuList(t('menu.start')) startMenus.value = getMenuList(t('menu.start'))
@@ -124,11 +82,12 @@ onMounted(() => {
organizeMenus.value = getMenuList(t('menu.organize')) organizeMenus.value = getMenuList(t('menu.organize'))
systemMenus.value = getMenuList(t('menu.system')) systemMenus.value = getMenuList(t('menu.system'))
// 延迟检查未读消息,确保所有组件都已加载完成 // 监听全局未读消息事件
nextTick(() => { const unsubscribe = onUnreadMessage(handleUnreadMessage)
setTimeout(() => {
checkUnreadMessages() // 组件卸载时清理监听
}, 2000) // 增加延迟时间到2秒 onBeforeUnmount(() => {
unsubscribe()
}) })
}) })
</script> </script>
+38 -29
View File
@@ -2,6 +2,27 @@
* PWA 徽章管理工具 * PWA 徽章管理工具
*/ */
// 全局事件类型
interface UnreadMessageEvent extends CustomEvent {
detail: { count: number }
}
// 发送全局未读消息事件
export function emitUnreadMessageEvent(count: number) {
const event = new CustomEvent('unreadMessage', { detail: { count } }) as UnreadMessageEvent
window.dispatchEvent(event)
}
// 监听全局未读消息事件
export function onUnreadMessage(callback: (count: number) => void) {
const handler = (event: Event) => {
const unreadEvent = event as UnreadMessageEvent
callback(unreadEvent.detail.count)
}
window.addEventListener('unreadMessage', handler)
return () => window.removeEventListener('unreadMessage', handler)
}
// 等待Service Worker准备就绪 // 等待Service Worker准备就绪
export async function waitForServiceWorker(): Promise<ServiceWorker | null> { export async function waitForServiceWorker(): Promise<ServiceWorker | null> {
if (!('serviceWorker' in navigator)) { if (!('serviceWorker' in navigator)) {
@@ -50,43 +71,31 @@ export async function waitForServiceWorker(): Promise<ServiceWorker | null> {
// 应用启动时检查未读消息数量 // 应用启动时检查未读消息数量
export async function checkUnreadOnStartup(): Promise<number> { export async function checkUnreadOnStartup(): Promise<number> {
try { try {
// 对于PWA应用,冷启动时需要更长的等待时间 // 检查Service Worker是否可用
const isPWAColdStart = !navigator.serviceWorker.controller if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) {
const initialDelay = isPWAColdStart ? 3000 : 1000
// 初始延迟,等待应用完全启动
await new Promise(resolve => setTimeout(resolve, initialDelay))
// 等待Service Worker准备就绪
const sw = await waitForServiceWorker()
if (!sw) {
return 0 return 0
} }
// 额外延迟确保Service Worker完全准备好 // 获取未读消息数量
await new Promise(resolve => setTimeout(resolve, 1000)) const unreadCount = await getUnreadCount()
return unreadCount
// 重试机制获取未读消息数量
for (let i = 0; i < 5; i++) {
// 增加重试次数
try {
const unreadCount = await getUnreadCount()
if (unreadCount >= 0) {
// 确保返回有效数字
return unreadCount
}
} catch (error) {
if (i === 4) throw error // 最后一次重试失败则抛出错误
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))) // 递增等待时间
}
}
return 0
} catch (error) { } catch (error) {
return 0 return 0
} }
} }
// 应用启动检查并触发事件
export async function checkAndEmitUnreadMessages() {
try {
const count = await checkUnreadOnStartup()
if (count > 0) {
emitUnreadMessageEvent(count)
}
} catch (error) {
// 静默处理错误
}
}
// 清除桌面图标徽章 // 清除桌面图标徽章
export async function clearAppBadge(): Promise<boolean> { export async function clearAppBadge(): Promise<boolean> {
try { try {