feat: add read and delete for each notification

This commit is contained in:
shixi 2025-11-11 23:41:52 +08:00
parent a4aa133db5
commit dbc5ea32ae
5 changed files with 79 additions and 3 deletions

View File

@ -23,6 +23,7 @@ import LoginForm from '#/views/_core/authentication/login.vue';
const notifications = ref<NotificationItem[]>([
{
id: 1,
avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
date: '3小时前',
isRead: true,
@ -30,6 +31,7 @@ const notifications = ref<NotificationItem[]>([
title: '收到了 14 份新周报',
},
{
id: 2,
avatar: 'https://avatar.vercel.sh/1',
date: '刚刚',
isRead: false,
@ -37,6 +39,7 @@ const notifications = ref<NotificationItem[]>([
title: '朱偏右 回复了你',
},
{
id: 3,
avatar: 'https://avatar.vercel.sh/1',
date: '2024-01-01',
isRead: false,
@ -44,6 +47,7 @@ const notifications = ref<NotificationItem[]>([
title: '曲丽丽 评论了你',
},
{
id: 4,
avatar: 'https://avatar.vercel.sh/satori',
date: '1天前',
isRead: false,
@ -102,6 +106,17 @@ function handleNoticeClear() {
notifications.value = [];
}
function markRead(id: number | string) {
const item = notifications.value.find((item) => item.id === id);
if (item) {
item.isRead = true;
}
}
function remove(id: number | string) {
notifications.value = notifications.value.filter((item) => item.id !== id);
}
function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
@ -144,6 +159,8 @@ watch(
:dot="showDot"
:notifications="notifications"
@clear="handleNoticeClear"
@read="(item) => item.id && markRead(item.id)"
@remove="(item) => item.id && remove(item.id)"
@make-all="handleMakeAll"
/>
</template>

View File

@ -23,6 +23,7 @@ import LoginForm from '#/views/_core/authentication/login.vue';
const notifications = ref<NotificationItem[]>([
{
id: 1,
avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
date: '3小时前',
isRead: true,
@ -30,6 +31,7 @@ const notifications = ref<NotificationItem[]>([
title: '收到了 14 份新周报',
},
{
id: 2,
avatar: 'https://avatar.vercel.sh/1',
date: '刚刚',
isRead: false,
@ -37,6 +39,7 @@ const notifications = ref<NotificationItem[]>([
title: '朱偏右 回复了你',
},
{
id: 3,
avatar: 'https://avatar.vercel.sh/1',
date: '2024-01-01',
isRead: false,
@ -44,6 +47,7 @@ const notifications = ref<NotificationItem[]>([
title: '曲丽丽 评论了你',
},
{
id: 4,
avatar: 'https://avatar.vercel.sh/satori',
date: '1天前',
isRead: false,
@ -102,6 +106,17 @@ function handleNoticeClear() {
notifications.value = [];
}
function markRead(id: number | string) {
const item = notifications.value.find((item) => item.id === id);
if (item) {
item.isRead = true;
}
}
function remove(id: number | string) {
notifications.value = notifications.value.filter((item) => item.id !== id);
}
function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
@ -144,6 +159,8 @@ watch(
:dot="showDot"
:notifications="notifications"
@clear="handleNoticeClear"
@read="(item) => item.id && markRead(item.id)"
@remove="(item) => item.id && remove(item.id)"
@make-all="handleMakeAll"
/>
</template>

View File

@ -23,6 +23,7 @@ import LoginForm from '#/views/_core/authentication/login.vue';
const notifications = ref<NotificationItem[]>([
{
id: 1,
avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
date: '3小时前',
isRead: true,
@ -30,6 +31,7 @@ const notifications = ref<NotificationItem[]>([
title: '收到了 14 份新周报',
},
{
id: 2,
avatar: 'https://avatar.vercel.sh/1',
date: '刚刚',
isRead: false,
@ -37,6 +39,7 @@ const notifications = ref<NotificationItem[]>([
title: '朱偏右 回复了你',
},
{
id: 3,
avatar: 'https://avatar.vercel.sh/1',
date: '2024-01-01',
isRead: false,
@ -44,6 +47,7 @@ const notifications = ref<NotificationItem[]>([
title: '曲丽丽 评论了你',
},
{
id: 4,
avatar: 'https://avatar.vercel.sh/satori',
date: '1天前',
isRead: false,
@ -102,6 +106,17 @@ function handleNoticeClear() {
notifications.value = [];
}
function markRead(id: number | string) {
const item = notifications.value.find((item) => item.id === id);
if (item) {
item.isRead = true;
}
}
function remove(id: number | string) {
notifications.value = notifications.value.filter((item) => item.id !== id);
}
function handleMakeAll() {
notifications.value.forEach((item) => (item.isRead = true));
}
@ -145,6 +160,8 @@ watch(
:dot="showDot"
:notifications="notifications"
@clear="handleNoticeClear"
@read="(item) => item.id && markRead(item.id)"
@remove="(item) => item.id && remove(item.id)"
@make-all="handleMakeAll"
/>
</template>

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import type { NotificationItem } from './types';
import { Bell, MailCheck } from '@vben/icons';
import { Bell, CircleCheckBig, CircleX, MailCheck } from '@vben/icons';
import { $t } from '@vben/locales';
import {
@ -35,6 +35,7 @@ const emit = defineEmits<{
clear: [];
makeAll: [];
read: [NotificationItem];
remove: [NotificationItem];
viewAll: [];
}>();
@ -91,7 +92,7 @@ function handleClick(item: NotificationItem) {
</div>
<VbenScrollbar v-if="notifications.length > 0">
<ul class="!flex max-h-[360px] w-full flex-col">
<template v-for="item in notifications" :key="item.title">
<template v-for="item in notifications" :key="item.id ?? item.title">
<li
class="hover:bg-accent border-border relative flex w-full cursor-pointer items-start gap-5 border-t px-3 py-3"
@click="handleClick(item)"
@ -107,7 +108,6 @@ function handleClick(item: NotificationItem) {
<img
:src="item.avatar"
class="aspect-square h-full w-full object-cover"
role="img"
/>
</span>
<div class="flex flex-col gap-1 leading-none">
@ -119,6 +119,30 @@ function handleClick(item: NotificationItem) {
{{ item.date }}
</p>
</div>
<div
class="absolute right-3 top-1/2 flex -translate-y-1/2 flex-col gap-2"
>
<VbenIconButton
v-if="!item.isRead"
size="xs"
variant="ghost"
class="h-6 px-2"
:tooltip="$t('common.confirm')"
@click.stop="emit('read', item)"
>
<CircleCheckBig class="size-4" />
</VbenIconButton>
<VbenIconButton
v-if="item.isRead"
size="xs"
variant="ghost"
class="text-destructive h-6 px-2"
:tooltip="$t('common.delete')"
@click.stop="emit('remove', item)"
>
<CircleX class="size-4" />
</VbenIconButton>
</div>
</li>
</template>
</ul>

View File

@ -1,4 +1,5 @@
interface NotificationItem {
id: number | string;
avatar: string;
date: string;
isRead?: boolean;