mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
refactor: 优化通知组件的样式和逻辑,移除不必要的状态,改善用户体验
This commit is contained in:
@@ -19,7 +19,6 @@ const hasNewMessage = ref(false)
|
|||||||
const notificationList = ref<SystemNotification[]>([])
|
const notificationList = ref<SystemNotification[]>([])
|
||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const loadedOnce = ref(false)
|
|
||||||
const hasMore = ref(true)
|
const hasMore = ref(true)
|
||||||
const notificationKeys = new Set<string>()
|
const notificationKeys = new Set<string>()
|
||||||
|
|
||||||
@@ -37,7 +36,9 @@ function getNotificationTime(item: SystemNotification) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeText(value: unknown) {
|
function normalizeText(value: unknown) {
|
||||||
return String(value ?? '').replace(/\s+/g, ' ').trim()
|
return String(value ?? '')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNotificationKind(item: SystemNotification) {
|
function getNotificationKind(item: SystemNotification) {
|
||||||
@@ -152,8 +153,6 @@ async function loadNotifications({ done }: { done: (status: 'ok' | 'empty' | 'er
|
|||||||
},
|
},
|
||||||
})) as SystemNotification[]
|
})) as SystemNotification[]
|
||||||
|
|
||||||
loadedOnce.value = true
|
|
||||||
|
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
hasMore.value = false
|
hasMore.value = false
|
||||||
done('empty')
|
done('empty')
|
||||||
@@ -185,12 +184,13 @@ function handleMessage(event: MessageEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 将通知列表标记为已读,并同步清理应用角标和未读红点。 */
|
/** 将通知列表标记为已读,并同步清理应用角标、未读红点和通知弹窗。 */
|
||||||
function markAllAsRead() {
|
function markAllAsRead() {
|
||||||
hasNewMessage.value = false
|
hasNewMessage.value = false
|
||||||
notificationList.value.forEach(item => {
|
notificationList.value.forEach(item => {
|
||||||
item.read = true
|
item.read = true
|
||||||
})
|
})
|
||||||
|
appsMenu.value = false
|
||||||
void clearUnreadMessages()
|
void clearUnreadMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +289,10 @@ useDelayedSSE(
|
|||||||
<div v-if="notificationList.length > 0" class="py-3 text-center text-caption text-medium-emphasis">
|
<div v-if="notificationList.length > 0" class="py-3 text-center text-caption text-medium-emphasis">
|
||||||
{{ t('message.noMoreData') }}
|
{{ t('message.noMoreData') }}
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="notification-empty">
|
||||||
|
<VIcon icon="mdi-bell-sleep-outline" size="40" class="mb-3" />
|
||||||
|
<div>{{ t('notification.empty') }}</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<VVirtualScroll
|
<VVirtualScroll
|
||||||
@@ -339,11 +343,6 @@ useDelayedSSE(
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VVirtualScroll>
|
</VVirtualScroll>
|
||||||
|
|
||||||
<div v-if="notificationList.length === 0 && loadedOnce && !loading" class="notification-empty">
|
|
||||||
<VIcon icon="mdi-bell-sleep-outline" size="40" class="mb-3" />
|
|
||||||
<div>{{ t('notification.empty') }}</div>
|
|
||||||
</div>
|
|
||||||
</VInfiniteScroll>
|
</VInfiniteScroll>
|
||||||
</div>
|
</div>
|
||||||
</VCard>
|
</VCard>
|
||||||
@@ -356,8 +355,8 @@ useDelayedSSE(
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notification-list-container {
|
.notification-list-container {
|
||||||
max-block-size: min(560px, 62vh);
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
max-block-size: min(560px, 62vh);
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +366,7 @@ useDelayedSSE(
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notification-virtual-item {
|
.notification-virtual-item {
|
||||||
block-size: 104px;
|
block-size: 110px;
|
||||||
padding-block: 4px;
|
padding-block: 4px;
|
||||||
padding-inline: 8px;
|
padding-inline: 8px;
|
||||||
}
|
}
|
||||||
@@ -376,15 +375,15 @@ useDelayedSSE(
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
inline-size: 100%;
|
padding: 10px;
|
||||||
block-size: 100%;
|
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
block-size: 100%;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
padding: 10px;
|
inline-size: 100%;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
transition:
|
transition:
|
||||||
background-color 0.2s ease,
|
background-color 0.2s ease,
|
||||||
@@ -406,15 +405,15 @@ useDelayedSSE(
|
|||||||
.notification-media {
|
.notification-media {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex: 0 0 56px;
|
flex: 0 0 56px;
|
||||||
block-size: 76px;
|
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: rgba(var(--v-theme-on-surface), 0.06);
|
background: rgba(var(--v-theme-on-surface), 0.06);
|
||||||
|
block-size: 84px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-media__image,
|
.notification-media__image,
|
||||||
.notification-media__fallback {
|
.notification-media__fallback {
|
||||||
inline-size: 100%;
|
|
||||||
block-size: 100%;
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-media__fallback,
|
.notification-media__fallback,
|
||||||
@@ -425,14 +424,14 @@ useDelayedSSE(
|
|||||||
|
|
||||||
.notification-icon {
|
.notification-icon {
|
||||||
flex: 0 0 40px;
|
flex: 0 0 40px;
|
||||||
block-size: 40px;
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: rgba(var(--v-theme-on-surface), 0.06);
|
background: rgba(var(--v-theme-on-surface), 0.06);
|
||||||
|
block-size: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-content {
|
.notification-content {
|
||||||
min-inline-size: 0;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-inline-size: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-title-row {
|
.notification-title-row {
|
||||||
@@ -453,33 +452,33 @@ useDelayedSSE(
|
|||||||
|
|
||||||
.notification-unread-dot {
|
.notification-unread-dot {
|
||||||
flex: 0 0 7px;
|
flex: 0 0 7px;
|
||||||
inline-size: 7px;
|
|
||||||
block-size: 7px;
|
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: rgb(var(--v-theme-error));
|
background: rgb(var(--v-theme-error));
|
||||||
|
block-size: 7px;
|
||||||
|
inline-size: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-text {
|
.notification-text {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-block-start: 4px;
|
-webkit-box-orient: vertical;
|
||||||
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
line-height: 1.45;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
|
line-height: 1.45;
|
||||||
|
margin-block-start: 4px;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-meta {
|
.notification-meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 6px;
|
align-items: center;
|
||||||
margin-block-start: 6px;
|
|
||||||
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
color: rgba(var(--v-theme-on-surface), var(--v-disabled-opacity));
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
|
gap: 6px;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
margin-block-start: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-type {
|
.notification-type {
|
||||||
@@ -491,8 +490,9 @@ useDelayedSSE(
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notification-empty {
|
.notification-empty {
|
||||||
padding: 32px 16px;
|
|
||||||
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
||||||
|
padding-block: 32px;
|
||||||
|
padding-inline: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user