Преглед на файлове

feat: sport notification link

shixi преди 7 месеца
родител
ревизия
0bbb20fee0

+ 18 - 0
apps/web-antd/src/layouts/basic.vue

@@ -54,6 +54,24 @@ const notifications = ref<NotificationItem[]>([
     message: '描述信息描述信息描述信息',
     title: '代办提醒',
   },
+  {
+    id: 5,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转Workspace示例',
+    link: '/workspace',
+  },
+  {
+    id: 6,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转外部链接示例',
+    link: 'https://doc.vben.pro',
+  },
 ]);
 
 const userStore = useUserStore();

+ 18 - 0
apps/web-ele/src/layouts/basic.vue

@@ -54,6 +54,24 @@ const notifications = ref<NotificationItem[]>([
     message: '描述信息描述信息描述信息',
     title: '代办提醒',
   },
+  {
+    id: 5,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转Workspace示例',
+    link: '/workspace',
+  },
+  {
+    id: 6,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转外部链接示例',
+    link: 'https://doc.vben.pro',
+  },
 ]);
 
 const userStore = useUserStore();

+ 18 - 0
apps/web-naive/src/layouts/basic.vue

@@ -54,6 +54,24 @@ const notifications = ref<NotificationItem[]>([
     message: '描述信息描述信息描述信息',
     title: '代办提醒',
   },
+  {
+    id: 5,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转Workspace示例',
+    link: '/workspace',
+  },
+  {
+    id: 6,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转外部链接示例',
+    link: 'https://doc.vben.pro',
+  },
 ]);
 
 const userStore = useUserStore();

+ 25 - 1
packages/effects/layouts/src/widgets/notification/notification.vue

@@ -1,6 +1,8 @@
 <script lang="ts" setup>
 import type { NotificationItem } from './types';
 
+import { useRouter } from 'vue-router';
+
 import { Bell, CircleCheckBig, CircleX, MailCheck } from '@vben/icons';
 import { $t } from '@vben/locales';
 
@@ -39,6 +41,7 @@ const emit = defineEmits<{
   viewAll: [];
 }>();
 
+const router = useRouter();
 const [open, toggle] = useToggle();
 
 function close() {
@@ -59,7 +62,28 @@ function handleClear() {
 }
 
 function handleClick(item: NotificationItem) {
-  emit('read', item);
+  // 如果通知项有链接,点击时跳转
+  if (item.link) {
+    navigateTo(item.link, item.query, item.state);
+  }
+}
+
+function navigateTo(
+  link: string,
+  query?: Record<string, any>,
+  state?: Record<string, any>,
+) {
+  if (link.startsWith('http://') || link.startsWith('https://')) {
+    // 外部链接,在新标签页打开
+    window.open(link, '_blank');
+  } else {
+    // 内部路由链接,支持 query 参数和 state
+    router.push({
+      path: link,
+      query: query || {},
+      state,
+    });
+  }
 }
 </script>
 <template>

+ 7 - 0
packages/effects/layouts/src/widgets/notification/types.ts

@@ -5,6 +5,13 @@ interface NotificationItem {
   isRead?: boolean;
   message: string;
   title: string;
+  /**
+   * 跳转链接,可以是路由路径或完整 URL
+   * @example '/dashboard' 或 'https://example.com'
+   */
+  link?: string;
+  query?: Record<string, any>;
+  state?: Record<string, any>;
 }
 
 export type { NotificationItem };

+ 35 - 0
playground/src/layouts/basic.vue

@@ -36,6 +36,7 @@ setMenuList([
 
 const notifications = ref<NotificationItem[]>([
   {
+    id: 1,
     avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
     date: '3小时前',
     isRead: true,
@@ -43,6 +44,7 @@ const notifications = ref<NotificationItem[]>([
     title: '收到了 14 份新周报',
   },
   {
+    id: 2,
     avatar: 'https://avatar.vercel.sh/1',
     date: '刚刚',
     isRead: false,
@@ -50,6 +52,7 @@ const notifications = ref<NotificationItem[]>([
     title: '朱偏右 回复了你',
   },
   {
+    id: 3,
     avatar: 'https://avatar.vercel.sh/1',
     date: '2024-01-01',
     isRead: false,
@@ -57,12 +60,31 @@ const notifications = ref<NotificationItem[]>([
     title: '曲丽丽 评论了你',
   },
   {
+    id: 4,
     avatar: 'https://avatar.vercel.sh/satori',
     date: '1天前',
     isRead: false,
     message: '描述信息描述信息描述信息',
     title: '代办提醒',
   },
+  {
+    id: 5,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转Workspace示例',
+    link: '/workspace',
+  },
+  {
+    id: 6,
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1天前',
+    isRead: false,
+    message: '描述信息描述信息描述信息',
+    title: '跳转外部链接示例',
+    link: 'https://doc.vben.pro',
+  },
 ]);
 
 const userStore = useUserStore();
@@ -115,6 +137,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));
 }
@@ -170,6 +203,8 @@ onBeforeMount(() => {
         :dot="showDot"
         :notifications="notifications"
         @clear="handleNoticeClear"
+        @read="(item) => item.id && markRead(item.id)"
+        @remove="(item) => item.id && remove(item.id)"
         @make-all="handleMakeAll"
       />
     </template>