This commit is contained in:
2026-08-13 19:00:37 +08:00
parent 41038e1edd
commit 0f0ae612ca
18 changed files with 175 additions and 170 deletions
+9 -18
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Bell, FileText, LogOut, Mail, Menu } from '@lucide/vue'
@@ -13,7 +13,6 @@ import { useAuthStore } from '@/core/auth/auth'
import { useUnsavedWorkStore } from '@/core/unsaved-work/unsavedWork'
import { canAccessWorkspaceRoute, workspaceRouteId, workspaceTabCandidate } from '@/core/workspace-tabs/routeWorkspace'
import { MAX_CACHED_WORKSPACE_VIEWS, useWorkspaceTabsStore } from '@/core/workspace-tabs/workspaceTabs'
import { getUnreadCount } from '@/modules/notifications/api/notificationCenter'
const route = useRoute()
const router = useRouter()
@@ -27,8 +26,10 @@ const pageTitle = computed(() => route.meta.title || '管理后台')
const pageDescription = computed(() => route.meta.description || '')
const showPageHeading = computed(() => route.meta.showPageHeading !== false)
const menuCollapsed = computed(() => collapsed.value && !mobileMenuOpen.value)
const unreadCount = ref<number | null>(null)
const unreadLoading = ref(false)
const canOpenNotificationManagement = computed(() => (
access.can('platform:notification:task:list')
|| access.can('platform:notification:template:list')
))
access.initializeAfterLogin()
workspace.initialize(auth.user?.id || auth.user?.account || '')
@@ -95,12 +96,6 @@ function handleMenuToggle() {
collapsed.value = !collapsed.value
}
async function loadUnreadCount() {
if (!access.can('platform:notification:view')) return
unreadLoading.value = true
try { unreadCount.value = await getUnreadCount() } catch { unreadCount.value = null } finally { unreadLoading.value = false }
}
function openNotificationPage(path: string) { void router.push(path) }
watch(() => route.fullPath, () => {
@@ -114,8 +109,6 @@ watch(() => auth.user?.id || auth.user?.account || '', (userId, previousUserId)
workspace.initialize(userId)
void pruneInaccessibleTabs().then(syncCurrentRoute)
})
onMounted(() => { window.addEventListener('cc-notification-unread-changed', loadUnreadCount); void loadUnreadCount() })
onBeforeUnmount(() => window.removeEventListener('cc-notification-unread-changed', loadUnreadCount))
</script>
<template>
@@ -142,14 +135,13 @@ onBeforeUnmount(() => window.removeEventListener('cc-notification-unread-changed
><Menu :size="22" /></button>
<div v-if="showPageHeading" class="page-heading"><h1>{{ pageTitle }}</h1><p v-if="pageDescription">{{ pageDescription }}</p></div>
<div class="header-user">
<el-dropdown v-if="access.can('platform:notification:view')" trigger="click" placement="bottom-end">
<button class="notification-trigger" type="button" :aria-label="`消息中心,${unreadCount ?? '未知'} 条未读`">
<Bell :size="18" /><span>消息中心</span><span class="notification-count">{{ unreadLoading ? '…' : unreadCount ?? '!' }}</span>
<el-dropdown v-if="canOpenNotificationManagement" trigger="click" placement="bottom-end">
<button class="notification-trigger" type="button" aria-label="消息中心">
<Bell :size="18" /><span>消息中心</span>
</button>
<template #dropdown><el-dropdown-menu>
<el-dropdown-item v-if="access.can('platform:notification:task:list')" @click="openNotificationPage('/notifications/messages')"><Mail :size="15" />消息管理</el-dropdown-item>
<el-dropdown-item v-if="access.can('platform:notification:template:list')" @click="openNotificationPage('/notifications/templates')"><FileText :size="15" />模板管理</el-dropdown-item>
<el-dropdown-item @click="openNotificationPage('/notifications/mine')"><Bell :size="15" />我的消息</el-dropdown-item>
</el-dropdown-menu></template>
</el-dropdown>
<div class="user-avatar">{{ auth.user?.name.slice(0, 1) }}</div>
@@ -178,6 +170,5 @@ onBeforeUnmount(() => window.removeEventListener('cc-notification-unread-changed
.app-header--without-page-heading .header-user { margin-left: auto; }
.notification-trigger { display: inline-flex; min-height: 34px; align-items: center; gap: 6px; padding: 0 9px; border: 0; border-radius: 4px; background: transparent; color: var(--cc-muted); font: inherit; }
.notification-trigger { cursor: pointer; }
.notification-count { display: inline-flex; min-width: 22px; height: 18px; align-items: center; justify-content: center; padding: 0 5px; border-radius: 9px; background: #e5e7eb; color: #64748b; font-size: 11px; font-weight: 700; }
@media (max-width: 720px) { .notification-trigger > span:not(.notification-count) { display: none; } }
@media (max-width: 720px) { .notification-trigger > span { display: none; } }
</style>