From 17ee5f456ab40c8753a24cb4cace130f6c993fdd Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sat, 14 Jun 2025 14:17:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=9C=AA=E8=AF=BB=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E7=9A=84=E5=85=A8=E5=B1=80=E4=BA=8B=E4=BB=B6=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 14 +++++ src/layouts/components/DefaultLayout.vue | 73 ++++++------------------ src/utils/badge.ts | 67 ++++++++++++---------- 3 files changed, 68 insertions(+), 86 deletions(-) diff --git a/src/App.vue b/src/App.vue index 4cb92714..8ed919d0 100644 --- a/src/App.vue +++ b/src/App.vue @@ -6,6 +6,7 @@ import api from '@/api' import { useAuthStore } from '@/stores/auth' import { getBrowserLocale, setI18nLanguage } from './plugins/i18n' import { SupportedLocale } from '@/types/i18n' +import { checkAndEmitUnreadMessages } from '@/utils/badge' // 生效主题 const { global: globalTheme } = useTheme() @@ -172,6 +173,11 @@ onMounted(async () => { setTimeout(() => { // 移除加载动画,显示页面 animateAndRemoveLoader() + + // 页面完全显示后,检查未读消息 + setTimeout(() => { + checkAndEmitUnreadMessages() + }, 1000) }, 1500) }) }) @@ -180,6 +186,10 @@ onMounted(async () => { document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { loadBackgroundImages() + // 页面恢复可见时检查未读消息 + setTimeout(() => { + checkAndEmitUnreadMessages() + }, 500) } }) @@ -188,6 +198,10 @@ onMounted(async () => { // persisted属性为true表示页面是从bfcache中恢复的 if (event.persisted) { loadBackgroundImages() + // PWA恢复时检查未读消息 + setTimeout(() => { + checkAndEmitUnreadMessages() + }, 500) } }) }) diff --git a/src/layouts/components/DefaultLayout.vue b/src/layouts/components/DefaultLayout.vue index 404562d4..43d2c78d 100644 --- a/src/layouts/components/DefaultLayout.vue +++ b/src/layouts/components/DefaultLayout.vue @@ -13,7 +13,7 @@ import { NavMenu } from '@/@layouts/types' import { useDisplay } from 'vuetify' import { useI18n } from 'vue-i18n' import { filterMenusByPermission } from '@/utils/permission' -import { checkUnreadOnStartup } from '@/utils/badge' +import { onUnreadMessage } from '@/utils/badge' const display = useDisplay() const appMode = inject('pwaMode') @@ -28,9 +28,6 @@ const superUser = computed(() => userStore.superUser) // ShortcutBar 引用 const shortcutBarRef = ref | null>(null) -// 未读消息检查状态 -const hasCheckedUnread = ref(false) - // 获取用户权限信息 const userPermissions = computed(() => ({ is_superuser: userStore.superUser, @@ -65,57 +62,18 @@ function goBack() { history.back() } -// 检查未读消息并自动打开消息弹窗 -async function checkUnreadMessages() { - if (!superUser.value || hasCheckedUnread.value) { - return // 只有超级用户才能看到消息,且每次会话只检查一次 - } - - hasCheckedUnread.value = true - - try { - const unreadCount = await checkUnreadOnStartup() - - if (unreadCount > 0) { - // 等待组件完全加载并重试打开消息弹窗 - await waitAndOpenMessageDialog() - } - } catch (error) { - // 静默处理错误 +// 处理未读消息事件 +function handleUnreadMessage(count: number) { + if (superUser.value && count > 0) { + // 延迟一点时间确保组件已渲染 + setTimeout(() => { + if (shortcutBarRef.value && typeof shortcutBarRef.value.openMessageDialog === 'function') { + shortcutBarRef.value.openMessageDialog() + } + }, 500) } } -// 等待组件准备好并打开消息弹窗 -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(() => { // 获取菜单列表 startMenus.value = getMenuList(t('menu.start')) @@ -124,11 +82,12 @@ onMounted(() => { organizeMenus.value = getMenuList(t('menu.organize')) systemMenus.value = getMenuList(t('menu.system')) - // 延迟检查未读消息,确保所有组件都已加载完成 - nextTick(() => { - setTimeout(() => { - checkUnreadMessages() - }, 2000) // 增加延迟时间到2秒 + // 监听全局未读消息事件 + const unsubscribe = onUnreadMessage(handleUnreadMessage) + + // 组件卸载时清理监听 + onBeforeUnmount(() => { + unsubscribe() }) }) diff --git a/src/utils/badge.ts b/src/utils/badge.ts index 4ae95eb6..f487d642 100644 --- a/src/utils/badge.ts +++ b/src/utils/badge.ts @@ -2,6 +2,27 @@ * 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准备就绪 export async function waitForServiceWorker(): Promise { if (!('serviceWorker' in navigator)) { @@ -50,43 +71,31 @@ export async function waitForServiceWorker(): Promise { // 应用启动时检查未读消息数量 export async function checkUnreadOnStartup(): Promise { try { - // 对于PWA应用,冷启动时需要更长的等待时间 - const isPWAColdStart = !navigator.serviceWorker.controller - const initialDelay = isPWAColdStart ? 3000 : 1000 - - // 初始延迟,等待应用完全启动 - await new Promise(resolve => setTimeout(resolve, initialDelay)) - - // 等待Service Worker准备就绪 - const sw = await waitForServiceWorker() - if (!sw) { + // 检查Service Worker是否可用 + if (!('serviceWorker' in navigator) || !navigator.serviceWorker.controller) { return 0 } - // 额外延迟确保Service Worker完全准备好 - await new Promise(resolve => setTimeout(resolve, 1000)) - - // 重试机制获取未读消息数量 - 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 + // 获取未读消息数量 + const unreadCount = await getUnreadCount() + return unreadCount } catch (error) { return 0 } } +// 应用启动检查并触发事件 +export async function checkAndEmitUnreadMessages() { + try { + const count = await checkUnreadOnStartup() + if (count > 0) { + emitUnreadMessageEvent(count) + } + } catch (error) { + // 静默处理错误 + } +} + // 清除桌面图标徽章 export async function clearAppBadge(): Promise { try {