Jelajahi Sumber

feat: 实现登录后弹窗轮播未读消息

zhouyuhao 8 bulan lalu
induk
melakukan
535098375c

+ 28 - 2
src/api/module/notificationMessage.ts

@@ -20,8 +20,9 @@ export const saveUserInfo = (params: any) => {
 }
 
 /**
- * 获取milestone消息列表
- * @param save_model profile 代表基本信息的save, no_profile 代表格式信息的save
+ * 获取notification消息列表
+ * @param rules_type 特定类型的消息,all查全部
+ * @param current_time 当前时间 轮询查询时使用
  */
 export const getNotificationList = (params: any) => {
   return HttpAxios.get(`${baseUrl}`, {
@@ -41,3 +42,28 @@ export const getNotificationDetails = (params: any) => {
     ...params
   })
 }
+
+/**
+ * 获取system message页面数据
+ */
+export const getSystemMessageData = (params: any) => {
+  return HttpAxios.get(`${baseUrl}`, {
+    action: 'notifications_rules',
+    operate: 'notifications_message_init',
+    ...params
+  })
+}
+
+/**
+ * 将notification消息标记为已读
+ * @param id 消息id Array
+ * @param read_type 如果标记全部为已读 = true. 否则其他情况为false
+ */
+export const setMessageRead = (params: any) => {
+  return HttpAxios.post(`${baseUrl}`, {
+    action: 'notifications_rules',
+    operate: 'notifications_read',
+    read_type: false,
+    ...params
+  })
+}

+ 2 - 1
src/auto-imports.d.ts

@@ -3,6 +3,7 @@
 // @ts-nocheck
 // noinspection JSUnusedGlobalSymbols
 // Generated by unplugin-auto-import
+// biome-ignore lint: disable
 export {}
 declare global {
   const $api: typeof import('@/api/index')['default']
@@ -68,6 +69,6 @@ declare global {
 // for type re-export
 declare global {
   // @ts-ignore
-  export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
+  export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
   import('vue')
 }

+ 10 - 2
src/components/NotificationMessageCard/src/NotificationMessageCard.vue

@@ -6,13 +6,21 @@ import FeatureUpdateCard from './components/FeatureUpdateCard.vue'
 const props = defineProps<{
   data: any
 }>()
-console.log(props.data, 'props.data')
+
+const emit = defineEmits<{ seeAll: [] }>()
+const handleSeeAll = () => {
+  emit('seeAll')
+}
 </script>
 
 <template>
   <div class="notification-message-card">
     <template v-for="(item, index) in data" :key="index">
-      <EventCard v-if="item.notificationType === 'event'" :data="item.info" />
+      <EventCard
+        @seeAll="handleSeeAll"
+        v-if="item.notificationType === 'event'"
+        :data="item.info"
+      />
       <PasswordCard v-else-if="item.notificationType === 'password'" :data="item.info" />
       <FeatureUpdateCard v-else-if="item.notificationType === 'feature'" :data="item.info" />
     </template>

+ 19 - 32
src/components/NotificationMessageCard/src/components/EventCard.vue

@@ -20,6 +20,9 @@ interface EventCardPropsData {
   timeLabel: string
   serial_no?: string // 单号 用来跳转到Tracking详情页
   order_from?: string // 订单来源 用来跳转到Tracking详情页
+  insert_date_format?: string // 用来跳转到System Message详情页
+  frequency_type?: string // 用来跳转到System Message详情页
+  rules_type?: string // 用来跳转到System Message详情页
   previous?: {
     date: string
     tag: string
@@ -42,16 +45,20 @@ const props = defineProps<{
   data: EventCardPropsData
 }>()
 
-const handleSeeAll = (data: any) => {
+const emit = defineEmits<{ seeAll: [] }>()
+const handleSeeAll = (data: EventCardPropsData) => {
+  emit('seeAll')
   router.push({
     name: 'System Message Detail',
     query: {
-      frequency_type: data.frequency_type
+      frequency_type: data.frequency_type,
+      insert_date_format: data.insert_date_format,
+      rules_type: data.rules_type
     }
   })
 }
 
-const jumpTracking = (data: any) => {
+const jumpTracking = (data: EventCardPropsData) => {
   router.push({
     path: '/tracking/detail',
     query: { a: data.serial_no, _schemas: data.order_from }
@@ -76,40 +83,20 @@ const jumpTracking = (data: any) => {
           <span class="font_family icon-icon_next_b"></span>
         </el-button>
       </div>
-      <div
-        class="more-tips"
-        v-if="data.type === 'delay' && (data.info.etdOrdeparturNum || data.info.etaOrarrivalNum)"
-      >
-        <div>
-          <span v-if="data.info.etdOrdeparturNum"
-            >Departure Delay ({{ data.info.etdOrdeparturNum }})</span
-          >
-          <span v-if="data.info.etdOrdeparturNum && data.info.etaOrarrivalNum">
-            &nbsp;&nbsp;|&nbsp;&nbsp;</span
-          >
-          <span v-if="data.info.etaOrarrivalNum">
-            Arrival Delay ({{ data.info.etaOrarrivalNum }})
-          </span>
-        </div>
-        <el-button @click="handleSeeAll(data)" class="see-all-icon el-button--text">
-          See All
-          <span class="font_family icon-icon_next_b"></span>
-        </el-button>
-      </div>
-
-      <div
-        class="more-tips"
-        v-if="data.type === 'change' && (data.info.etdOrdeparturNum || data.info.etaOrarrivalNum)"
-      >
+      <div class="more-tips" v-if="data.info.etdOrdeparturNum || data.info.etaOrarrivalNum">
         <div>
           <span v-if="data.info.etdOrdeparturNum"
-            >ETD Change ({{ data.info.etdOrdeparturNum }})</span
+            >{{ data.type === 'delay' ? 'Departure Delay' : 'ETD Change' }} ({{
+              data.info.etdOrdeparturNum
+            }})</span
           >
           <span v-if="data.info.etdOrdeparturNum && data.info.etaOrarrivalNum">
             &nbsp;&nbsp;|&nbsp;&nbsp;</span
           >
           <span v-if="data.info.etaOrarrivalNum">
-            ETA Change ({{ data.info.etaOrarrivalNum }})
+            {{ data.type === 'delay' ? 'Arrival Delay' : 'ETA Change' }} ({{
+              data.info.etaOrarrivalNum
+            }})
           </span>
         </div>
         <el-button @click="handleSeeAll(data)" class="see-all-icon el-button--text">
@@ -165,7 +152,7 @@ const jumpTracking = (data: any) => {
           class="font_family icon-icon_delay_b"
         ></span>
         <span v-else class="font_family icon-icon_time_b"></span>
-        <span style="margin-right: 2px">{{ data.info.timeLabel }}&nbsp;</span>
+        <span style="margin-right: 2px" v-if="data.info.timeLabel">{{ data.info.timeLabel }}:</span>
         <span style="margin-right: 3px">{{
           dayjs(data.info.time).format('MMM DD, YYYY hh:mm')
         }}</span>
@@ -177,7 +164,7 @@ const jumpTracking = (data: any) => {
       </div> -->
       <div class="time" :class="{ grey: data.type === 'delay' || data.type === 'change' }">
         <span class="font_family icon-icon_time_b"></span>
-        <span style="margin-right: 2px">{{ data.timeLabel }}</span>
+        <span style="margin-right: 3px" v-if="data.timeLabel">{{ data.timeLabel }}:</span>
         <span style="margin-right: 3px">{{ dayjs(data.time).format('MMM DD, YYYY hh:mm') }}</span>
         <span>{{ getTimezone(data.timezone) }}</span>
       </div>

+ 0 - 1
src/components/NotificationMessageCard/src/components/FeatureUpdateCard.vue

@@ -12,7 +12,6 @@ interface FeatureUpdateCardPropsData {
 const props = defineProps<{
   data: FeatureUpdateCardPropsData
 }>()
-console.log(props.data, 'props.data111')
 </script>
 
 <template>

+ 2 - 1
src/router/index.ts

@@ -97,7 +97,8 @@ const router = createRouter({
           path: '/system-message-detail',
           name: 'System Message Detail',
           meta: {
-            breadName: 'Detail'
+            breadName: 'Detail',
+            activeMenu: '/system-message'
           },
           component: () => import('../views/SystemMessage/src/components/SystemMessageDetail.vue')
         },

+ 3 - 1
src/views/Layout/src/components/Header/HeaderView.vue

@@ -17,6 +17,8 @@ const route = useRoute()
 const router = useRouter()
 const headerSearch = useHeaderSearch()
 
+const trainingCardRef = ref()
+
 // 切换系统主题颜色
 const toggleThemeMode = (theme: string) => {
   themeStore.toggleTheme(theme, true)
@@ -188,7 +190,7 @@ const notificationDrawer = ref(false)
     element-loading-background="rgb(43, 47, 54, 0.7)"
   >
     <VBreadcrumb></VBreadcrumb>
-    <TrainingCard></TrainingCard>
+    <TrainingCard ref="trainingCardRef"></TrainingCard>
     <div class="right-info">
       <el-input
         v-model="searchValue"

+ 92 - 82
src/views/Layout/src/components/Header/components/NotificationDrawer.vue

@@ -5,8 +5,6 @@ import { useRouter } from 'vue-router'
 const router = useRouter()
 const loading = ref(false)
 
-const drawerModel = defineModel('drawerModel', { type: Boolean, default: false })
-
 const notificationType = ref('all')
 const notificationTypeList = ref({
   all: 'All Notifications',
@@ -18,84 +16,84 @@ const notificationTypeList = ref({
   Feature_Update: 'Feature Update'
 })
 
-// const notificationList = ref<any[]>([])
-const notificationList = [
-  {
-    notificationType: 'feature',
-    info: {
-      isRead: true,
-      title: 'Feature Update',
-      header: 'New feature online: Quick search has been released!',
-      content:
-        'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
-    }
-  },
-  {
-    notificationType: 'event',
-    info: {
-      type: 'milestone',
-      isMultiple: true,
-      numericRecords: 3,
-      isRead: true,
-      title: 'Milestone Update',
-      mode: 'Ocean Freight',
-      no: 'HBOL: SHJN2301234',
-      tag: 'Booking Confirmed',
-      location: 'Hong Kong',
-      time: 'Jan 10, 2025 14:30 UTC+8',
-      info: {
-        route: ['Hong Kong', 'Shanghai', 'Ningbo']
-      }
-    }
-  },
-  {
-    notificationType: 'password',
-    info: {
-      title: 'Password Notifications',
-      isExpiration: true,
-      tips: 'Password Expiration in 311 Days',
-      content:
-        'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
-    }
-  },
-  {
-    notificationType: 'password',
-    info: {
-      isRead: false,
-      title: 'Password Notifications',
-      isExpiration: false,
-      tips: 'Password Expiration in 3 Days',
-      content:
-        'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
-    }
-  },
-  {
-    notificationType: 'password',
-    info: {
-      isRead: true,
-      title: 'Password Notifications',
-      isExpiration: true,
-      tips: 'Password Expiration in 31111 Days',
-      content:
-        'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
-    }
-  }
-]
+const notificationList = ref<any[]>([])
+// const notificationList = [
+//   {
+//     notificationType: 'feature',
+//     info: {
+//       isRead: true,
+//       title: 'Feature Update',
+//       header: 'New feature online: Quick search has been released!',
+//       content:
+//         'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
+//     }
+//   },
+//   {
+//     notificationType: 'event',
+//     info: {
+//       type: 'milestone',
+//       isMultiple: true,
+//       numericRecords: 3,
+//       isRead: true,
+//       title: 'Milestone Update',
+//       mode: 'Ocean Freight',
+//       no: 'HBOL: SHJN2301234',
+//       tag: 'Booking Confirmed',
+//       location: 'Hong Kong',
+//       time: 'Jan 10, 2025 14:30 UTC+8',
+//       info: {
+//         route: ['Hong Kong', 'Shanghai', 'Ningbo']
+//       }
+//     }
+//   },
+//   {
+//     notificationType: 'password',
+//     info: {
+//       title: 'Password Notifications',
+//       isExpiration: true,
+//       tips: 'Password Expiration in 311 Days',
+//       content:
+//         'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
+//     }
+//   },
+//   {
+//     notificationType: 'password',
+//     info: {
+//       isRead: false,
+//       title: 'Password Notifications',
+//       isExpiration: false,
+//       tips: 'Password Expiration in 3 Days',
+//       content:
+//         'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
+//     }
+//   },
+//   {
+//     notificationType: 'password',
+//     info: {
+//       isRead: true,
+//       title: 'Password Notifications',
+//       isExpiration: true,
+//       tips: 'Password Expiration in 31111 Days',
+//       content:
+//         'Your password will expire in 7 days. To ensure the security of your account, please change your password as soon as possible.'
+//     }
+//   }
+// ]
 
 const getNotificationList = () => {
-  // loading.value = true
-  // $api
-  //   .getNotificationList({
-  //     rules_type: notificationType.value
-  //   })
-  //   .then((res) => {
-  //     if (res.code === 200) {
-  //       notificationList.value = res.data
-  //     }
-  //   })
-  //   .finally(() => {
-  //     loading.value = false
-  //   })
+  loading.value = true
+  $api
+    .getNotificationList({
+      rules_type: notificationType.value
+    })
+    .then((res) => {
+      if (res.code === 200) {
+        notificationList.value = res.data
+      }
+    })
+    .finally(() => {
+      loading.value = false
+    })
 }
 
 const handleMarkAllRead = () => {
@@ -103,15 +101,27 @@ const handleMarkAllRead = () => {
   // notificationList.value.forEach((item) => {
   //   item.isRead = true
   // })
+  $api.setMessageRead({ read_type: true }).then((res) => {
+    if (res.code === 200) {
+      console.log('标记成功')
+    }
+  })
 }
 
+const drawerRef = ref()
 const handleViewAll = () => {
+  drawerRef.value.handleClose()
   router.push('/system-message')
 }
 
 const handleSettingMessage = () => {
-  // 跳转消息设置页面
-  // router.push('/')
+  drawerRef.value.handleClose()
+  router.push({
+    name: 'Monitoring Settings',
+    query: {
+      tab: 'Subscribe Notifications'
+    }
+  })
 }
 
 const clearData = () => {
@@ -121,10 +131,10 @@ const clearData = () => {
 
 <template>
   <el-drawer
+    ref="drawerRef"
     @open="getNotificationList"
     @closed="clearData"
     class="notice-drawer"
-    v-model="drawerModel"
     size="432px"
   >
     <template #header>
@@ -163,7 +173,7 @@ const clearData = () => {
           </div>
         </div>
         <div class="notification-content">
-          <NotificationMessageCard :data="notificationList" />
+          <NotificationMessageCard @see-all="drawerRef.handleClose()" :data="notificationList" />
         </div>
       </el-scrollbar>
     </template>

+ 33 - 12
src/views/Layout/src/components/Header/components/TrainingCard.vue

@@ -1,7 +1,10 @@
 <script setup lang="ts">
+import { onBeforeRouteUpdate } from 'vue-router'
 import NotificationMessageCard from '@/components/NotificationMessageCard/src/NotificationMessageCard.vue'
+import { useUserStore } from '@/stores/modules/user'
 
-const notificationList = []
+const userStore = useUserStore()
+const notificationList = ref([])
 // const notificationList = [
 //   {
 //     notificationType: 'feature',
@@ -104,15 +107,8 @@ const notificationList = []
 //   }
 // ]
 
-const getNotificationList = () => {
-  if (localStorage.getItem('showFeatureAfterLogin') !== 'true') return
-  // 获取数据
-
-  localStorage.removeItem('showFeatureAfterLogin')
-}
-
 const curCard = computed(() => {
-  return notificationList[curIndex.value] || null
+  return notificationList.value[curIndex.value] || null
 })
 const curIndex = ref(0)
 // 设置定时器进行自动轮播
@@ -133,7 +129,7 @@ const nextNotification = () => {
   }
 
   // 如果到达最后一个消息,设置为null以清除显示
-  if (curIndex.value >= notificationList.length) {
+  if (curIndex.value >= notificationList.value.length) {
     clearInterval(intervalId)
     // curCard.value = null
     result = false
@@ -146,7 +142,32 @@ const initTrainingCard = () => {
     intervalId = setInterval(nextNotification, 2000)
   }
 }
-initTrainingCard()
+
+onBeforeRouteUpdate((to, from, next) => {
+  if (from.name === 'Login' && userStore.userName) {
+    getNotificationList()
+  }
+  next()
+})
+
+const getNotificationList = () => {
+  // if (localStorage.getItem('showFeatureAfterLogin') !== 'true') return
+  // // 获取数据
+
+  // localStorage.removeItem('showFeatureAfterLogin')
+  $api
+    .getNotificationList({
+      rules_type: 'all',
+      info_type: true
+    })
+    .then((res) => {
+      if (res.code === 200) {
+        notificationList.value = res.data
+        console.log(curCard.value, 'curCard')
+        initTrainingCard()
+      }
+    })
+}
 
 const closeMessage = () => {
   // 如果当前消息为event类型,则需先清除定时器
@@ -179,7 +200,7 @@ const closeMessage = () => {
   position: absolute;
   top: 60px;
   right: 20px;
-  z-index: 2010;
+  z-index: 2300;
   width: 432px;
   padding: 16px;
   padding-bottom: 0;

+ 47 - 47
src/views/Layout/src/components/Menu/MenuView.vue

@@ -17,54 +17,54 @@ watch(
   }
 )
 const getMenuList = () => {
-  $api.getMenuList().then((res) => {
-    if (res.code === 200) {
-      menuList.value = res.data
-    }
-  })
-  // menuList.value = [
-  //   {
-  //     index: '1',
-  //     label: 'Dashboard',
-  //     icon: 'icon_data_fill_b',
-  //     path: '/dashboard'
-  //   },
-  //   {
-  //     index: '2',
-  //     label: 'Booking',
-  //     icon: 'icon_booking__fill_b',
-  //     path: '/booking'
-  //   },
-  //   {
-  //     index: '3',
-  //     label: 'Tracking',
-  //     icon: 'icon_tracking__fill_b',
-  //     path: '/tracking'
-  //   },
-  //   {
-  //     index: '4',
-  //     label: 'System Management',
-  //     icon: 'icon_system__management_fill_b',
-  //     type: 'list',
-  //     children: [
-  //       {
-  //         index: '4-1',
-  //         label: 'System Message',
-  //         path: '/system-message'
-  //       },
-  //       {
-  //         index: '4-2',
-  //         label: 'System Settings',
-  //         path: '/SystemSettings'
-  //       },
-  //       {
-  //         index: '4-3',
-  //         label: 'Operation Log',
-  //         path: '/Operationlog'
-  //       }
-  //     ]
+  // $api.getMenuList().then((res) => {
+  //   if (res.code === 200) {
+  //     menuList.value = res.data
   //   }
-  // ]
+  // })
+  menuList.value = [
+    {
+      index: '1',
+      label: 'Dashboard',
+      icon: 'icon_data_fill_b',
+      path: '/dashboard'
+    },
+    {
+      index: '2',
+      label: 'Booking',
+      icon: 'icon_booking__fill_b',
+      path: '/booking'
+    },
+    {
+      index: '3',
+      label: 'Tracking',
+      icon: 'icon_tracking__fill_b',
+      path: '/tracking'
+    },
+    {
+      index: '4',
+      label: 'System Management',
+      icon: 'icon_system__management_fill_b',
+      type: 'list',
+      children: [
+        {
+          index: '4-1',
+          label: 'System Message',
+          path: '/system-message'
+        },
+        {
+          index: '4-2',
+          label: 'System Settings',
+          path: '/SystemSettings'
+        },
+        {
+          index: '4-3',
+          label: 'Operation Log',
+          path: '/Operationlog'
+        }
+      ]
+    }
+  ]
 }
 getMenuList()
 //监听窗口大小

+ 111 - 288
src/views/SystemMessage/src/SystemMessage.vue

@@ -1,13 +1,9 @@
 <script setup lang="ts">
-import EventCard from '@/components/NotificationMessageCard/src/components/EventCard.vue'
 import NotificationMessageCard from '@/components/NotificationMessageCard/src/NotificationMessageCard.vue'
 
 const collapseVModel = ref<string[]>(['1'])
 
-const unreadCount = ref(33)
-const readCount = ref(22)
-const allCount = ref(135)
-const tabCountList = [2, 1, 99, 0, 23]
+const tabCountList = ref([0, 0, 0, 0, 0])
 const handleCount = (count: number) => {
   if (!count) return 0
   return count > 99 ? '99+' : count
@@ -18,304 +14,132 @@ const navList = [
   'Departure/Arrival Delay',
   'ETD/ETA Change'
 ]
-const cardList = [
-  {
-    notificationType: 'event',
-    info: {
-      type: 'milestone',
-      isMultiple: true,
-      numericRecords: 3,
-      isRead: true,
-      title: 'Milestone Update',
-      mode: 'Ocean Freight',
-      no: 'HBOL: SHJN2301234',
-      tag: 'Booking Confirmed',
-      location: 'Hong Kong',
-      time: 'Jan 10, 2025 14:30 UTC+8',
-      info: {
-        route: ['Hong Kong', 'Shanghai', 'Ningbo']
-      }
-    }
-  }
-]
-
-const result = {
-  countList: [2, 1, 99, 0, 33],
-  allCount: 135,
-  unreadCount: 33,
-  readCount: 22,
-  cardList: [
-    {
-      notificationType: 'feature',
-      info: {
-        isRead: true,
-        title: 'Feature Update',
-        header: 'New feature online: Quick search has been released!',
-        content:
-          'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
-      }
-    }
-  ]
-}
 
 const activeItem = ref('Milestone Update')
+const notificationTypeList = ref({
+  Milestone_Update: 'Milestone Update',
+  Container_Status_Update: 'Container Status Update',
+  Container_Arrival: 'Container Arrival',
+  'Departure/Arrival_Delay': 'Departure/Arrival Delay',
+  'ETD/ETA_Change': 'ETD/ETA Change',
+  Feature_Update: 'Feature Update'
+})
+
 const setActiveItem = (item: string) => {
   activeItem.value = item
-}
-
-// const getNotificationList = () => {
-//   $api
-//     .getNotificationList({
-//       rules_type: 'Milestone_Update'
-//     })
-//     .then((res) => {
-//       if (res.code === 200) {
-//         notificationList.value = res.data.info
-//         console.log(res, 'test')
-//       }
-//     })
-// }
+  activeName.value = 'All Notifications'
 
-const activeName = ref('first')
+  getNotificationList()
+}
 
-const handleClick = () => {}
+const loading = ref(false)
+const notificationList = ref<any[]>([])
+const unreadNotificationList = computed(() => {
+  return notificationList.value.filter((item) => !item.info.isRead)
+})
+const readNotificationList = computed(() => {
+  return notificationList.value.filter((item) => item.info.isRead)
+})
+const getNotificationList = () => {
+  loading.value = true
+  const rulesType = Object.entries(notificationTypeList.value).find(
+    (item) => item[1] === activeItem.value
+  )?.[0]
+  $api
+    .getSystemMessageData({
+      rules_type: rulesType
+    })
+    .then((res) => {
+      if (res.code === 200) {
+        const data = res.data
+        notificationList.value = data.cardList
+        tabCountList.value = data.countList
+      }
+    })
+    .finally(() => {
+      loading.value = false
+    })
+}
 
-// const notificationList = ref<any[]>([])
-const notificationList = [
-  {
-    type: 'milestone',
-    isMultiple: true,
-    numericRecords: 3,
-    isRead: true,
-    title: 'Milestone Update',
-    mode: 'Ocean Freight',
-    no: 'SHJN2301234',
-    tag: 'Booking Confirmed',
-    location: 'Hong Kong',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai'
-  },
-  {
-    type: 'container',
-    isRead: false,
-    mode: '',
-    no: 'SHJN2301234',
-    tag: 'Unloaded From Vessel',
-    location: 'Hong Kong',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai',
-    previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
-  },
-  {
-    type: 'delay',
-    numericRecords: 0,
-    isRead: false,
-    title: 'Delay Daily Summary (Jan 10, 2025)',
-    mode: 'Air Freight',
-    no: 'SHJN2301234',
-    tag: 'Departure Delay',
-    location: 'Hong Kong',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai',
-    info: {
-      timeLabel: 'ATA: ',
-      time: '2510-12-1 14:30 UTC+8',
-      timezone: 'Asia/Shanghai',
-      departureDelayNum: 10,
-      arrivalDelayNum: 8
-    }
-  },
-  {
-    type: 'container',
-    isRead: false,
-    mode: '',
-    no: 'SHJN2301234',
-    tag: 'Unloaded From Vessel',
-    location: 'Hong Kong',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai',
-    previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
-  },
-  {
-    type: 'delay',
-    numericRecords: 0,
-    isRead: false,
-    title: 'Delay Daily Summary (Jan 10, 2025)',
-    mode: 'Air Freight',
-    no: 'SHJN2301234',
-    tag: 'Departure Delay',
-    location: 'Hong Kong',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai',
-    info: {
-      timeLabel: 'ATA: ',
-      time: '2510-12-1 14:30 UTC+8',
-      timezone: 'Asia/Shanghai',
-      departureDelayNum: 10,
-      arrivalDelayNum: 8
-    }
-  },
-  {
-    type: 'container',
-    isRead: false,
-    mode: '',
-    no: 'SHJN2301234',
-    tag: 'Unloaded From Vessel',
-    location: 'Hong Kong',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai',
-    previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
-  },
-  {
-    type: 'delay',
-    numericRecords: 0,
-    isRead: false,
-    title: 'Delay Daily Summary (Jan 10, 2025)',
-    mode: 'Air Freight',
-    no: 'SHJN2301234',
-    tag: 'Departure Delay',
-    location: 'Hong Kong',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai',
-    info: {
-      timeLabel: 'ATA: ',
-      time: '2510-12-1 14:30 UTC+8',
-      timezone: 'Asia/Shanghai',
-      departureDelayNum: 10,
-      arrivalDelayNum: 8
-    }
-  },
-  {
-    type: 'change',
-    numericRecords: 0,
-    isRead: false,
-    title: 'ETD/ETA  Change Weekly Summary (Jan 4- 10, 2025) ',
-    mode: 'Air Freight',
-    no: 'SHJN2301234',
-    tag: 'ETD Change',
-    info: {
-      etdChangeNum: 20,
-      etaChangeNum: 10,
-      timeLabel: 'ATA: ',
-      time: '2510-12-1 14:30 UTC+8',
-      timezone: 'Asia/Shanghai'
-    },
-    location: 'Hong Kong',
-    changeTime: 'Updated ETD: Jan 17, 15:00',
-    timeLabel: 'ATA: ',
-    time: '2510-12-1 14:30 UTC+8',
-    timezone: 'Asia/Shanghai'
-  }
-]
-// onMounted(() => {
-//   getNotificationList()
-// })
+const activeName = ref('All Notifications')
 
-const featureList = [
-  {
-    notificationType: 'feature',
-    info: {
-      isRead: true,
-      title: 'Feature Update',
-      header: 'New feature online: Quick search has been released!',
-      content:
-        'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
-    }
-  },
-  {
-    notificationType: 'feature',
-    info: {
-      isRead: true,
-      title: 'Feature Update',
-      header: 'New feature online: Quick search has been released!',
-      content:
-        'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
-    }
-  },
-  {
-    notificationType: 'feature',
-    info: {
-      isRead: true,
-      title: 'Feature Update',
-      header: 'New feature online: Quick search has been released!',
-      content:
-        'We are pleased to announce that the quick search function is now officially online! You can now quickly find what you need by entering keywords, greatly improving your work efficiency. Go and experience it!'
-    }
-  }
-]
+onMounted(() => {
+  getNotificationList()
+})
 </script>
 
 <template>
-  <div class="Title">System Message</div>
-  <div class="system-message">
-    <div class="left-nav">
-      <el-collapse v-model="collapseVModel">
-        <el-collapse-item title="Event Notifications" name="1">
-          <div
-            @click="setActiveItem(item)"
-            class="collapse-item"
-            :class="{ 'is-active': item === activeItem }"
-            v-for="(item, index) in navList"
-            :key="item"
-          >
-            <div v-if="item === activeItem" class="active-sign"></div>
-            <span>{{ item }}</span>
-            <div class="count">
-              <span>{{ handleCount(tabCountList?.[index]) }}</span>
+  <div v-vloading="loading" style="height: 100%; width: 100%">
+    <div class="Title">System Message</div>
+    <div class="system-message">
+      <div class="left-nav">
+        <el-collapse v-model="collapseVModel">
+          <el-collapse-item title="Event Notifications" name="1">
+            <div
+              @click="setActiveItem(item)"
+              class="collapse-item"
+              :class="{ 'is-active': item === activeItem }"
+              v-for="(item, index) in navList"
+              :key="item"
+            >
+              <div v-if="item === activeItem" class="active-sign"></div>
+              <span>{{ item }}</span>
+              <div class="count">
+                <span>{{ handleCount(tabCountList?.[index]) }}</span>
+              </div>
             </div>
+          </el-collapse-item>
+        </el-collapse>
+        <div
+          @click="setActiveItem('Feature Update')"
+          class="collapse-item"
+          style="margin-top: 4px; font-weight: 700"
+          :class="{ 'is-active': activeItem === 'Feature Update' }"
+        >
+          <div v-if="activeItem === 'Feature Update'" class="active-sign"></div>
+          <span>Feature Update</span>
+          <div class="count">
+            <span>{{ handleCount(tabCountList?.[tabCountList.length - 1]) }}</span>
           </div>
-        </el-collapse-item>
-      </el-collapse>
-      <div
-        @click="setActiveItem('Feature Update')"
-        class="collapse-item"
-        style="margin-top: 4px; font-weight: 700"
-        :class="{ 'is-active': activeItem === 'Feature Update' }"
-      >
-        <div v-if="activeItem === 'Feature Update'" class="active-sign"></div>
-        <span>Feature Update</span>
-        <div class="count">
-          <span>{{ handleCount(tabCountList?.[tabCountList.length - 1]) }}</span>
         </div>
       </div>
-    </div>
-    <div class="right-content">
-      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
-        <el-tab-pane label="All Notifications" name="first">
-          <template #label>
-            <span style="margin-right: 4px">All Notifications</span>
-            <div class="count">
-              <span>{{ handleCount(allCount) }}</span>
+      <div class="right-content">
+        <el-tabs v-model="activeName" class="demo-tabs">
+          <el-tab-pane label="All Notifications" name="All Notifications">
+            <template #label>
+              <span style="margin-right: 4px">All Notifications</span>
+              <div class="count">
+                <span>{{ handleCount(notificationList.length) }}</span>
+              </div>
+            </template>
+            <div style="padding: 10px 140px 0px 16px">
+              <NotificationMessageCard :data="notificationList"></NotificationMessageCard>
             </div>
-          </template>
-          <div style="padding: 10px 140px 0px 16px">
-            <NotificationMessageCard :data="cardList"></NotificationMessageCard>
-          </div>
-        </el-tab-pane>
-        <el-tab-pane label="Unread" name="second">
-          <template #label>
-            <span style="margin-right: 4px">Unread</span>
-            <div class="count">
-              <span>{{ handleCount(unreadCount) }}</span>
+          </el-tab-pane>
+          <el-tab-pane label="Unread" name="Unread">
+            <template #label>
+              <span style="margin-right: 4px">Unread</span>
+              <div class="count">
+                <span>{{ handleCount(unreadNotificationList.length) }}</span>
+              </div>
+            </template>
+            <div style="padding: 10px 140px 0px 16px">
+              <NotificationMessageCard :data="unreadNotificationList"></NotificationMessageCard>
+            </div>
+          </el-tab-pane>
+          <el-tab-pane label="Read" name="Read">
+            <template #label
+              ><span style="margin-right: 4px">Read</span>
+              <div class="count">
+                <span>{{ handleCount(readNotificationList.length) }}</span>
+              </div></template
+            >
+            <div style="padding: 10px 140px 0px 16px">
+              <NotificationMessageCard :data="readNotificationList"></NotificationMessageCard>
             </div>
-          </template>
-        </el-tab-pane>
-        <el-tab-pane label="Read" name="third">
-          <template #label
-            ><span style="margin-right: 4px">Read</span>
-            <div class="count">
-              <span>{{ handleCount(readCount) }}</span>
-            </div></template
-          >
-        </el-tab-pane>
-      </el-tabs>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
     </div>
   </div>
 </template>
@@ -335,11 +159,10 @@ const featureList = [
   height: calc(100% - 68px);
   .count {
     display: inline-flex;
-    justify-content: center;
     height: 18px;
     min-width: 18px;
     padding-top: 1px;
-    padding-left: 4px;
+    padding-left: 5px;
     padding-right: 5px;
     background-color: var(--color-theme);
     border-radius: 9px;

+ 87 - 41
src/views/SystemMessage/src/components/SystemMessageDetail.vue

@@ -1,47 +1,69 @@
 <script setup lang="ts">
+import { useRoute } from 'vue-router'
 import EventCard from '@/components/NotificationMessageCard/src/components/EventCard.vue'
 
-const notificationData: any = {
-  title: 'Milestone Update Daily Summary (Jan 10, 2025)',
-  numericRecords: 3,
-  notificationList: [
-    {
-      mode: 'Ocean Freight',
-      no: 'HBOL: SHJN2301234',
-      tag: 'Booking Confirmed',
-      location: 'Hong Kong',
-      timeLabel: 'ATA: ',
-      time: '2510-12-1 14:30 UTC+8',
-      timezone: 'Asia/Shanghai'
-    },
-    {
-      mode: 'Air Freight',
-      no: 'HBOL: SHJN2301234',
-      tag: 'Booking Confirmed',
-      location: 'Hong Kong',
-      timeLabel: 'ATA: ',
-      time: '2510-12-1 14:30 UTC+8',
-      timezone: 'Asia/Shanghai'
-    },
-    {
-      mode: 'Air Freight',
-      no: 'HBOL: SHJN2301234',
-      tag: 'Booking Confirmed',
-      location: 'Hong Kong',
-      timeLabel: 'ATA: ',
-      time: '2510-12-1 14:30 UTC+8',
-      timezone: 'Asia/Shanghai',
-      previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
-    }
-  ]
-}
+const route = useRoute()
+const notificationData = ref({
+  title: '',
+  type: 'delay',
+  etdOrdeparturNum: -1,
+  etaOrarrivalNum: -1,
+  numericRecords: -1,
+  notificationList: []
+})
+// const notificationData: any = {
+//   title: 'Milestone Update Daily Summary (Jan 10, 2025)',
+//   numericRecords: 3,
+//   notificationList: [
+//     {
+//       mode: 'Ocean Freight',
+//       no: 'HBOL: SHJN2301234',
+//       tag: 'Booking Confirmed',
+//       location: 'Hong Kong',
+//       timeLabel: 'ATA: ',
+//       time: '2510-12-1 14:30 UTC+8',
+//       timezone: 'Asia/Shanghai'
+//     },
+//     {
+//       mode: 'Air Freight',
+//       no: 'HBOL: SHJN2301234',
+//       tag: 'Booking Confirmed',
+//       location: 'Hong Kong',
+//       timeLabel: 'ATA: ',
+//       time: '2510-12-1 14:30 UTC+8',
+//       timezone: 'Asia/Shanghai'
+//     },
+//     {
+//       mode: 'Air Freight',
+//       no: 'HBOL: SHJN2301234',
+//       tag: 'Booking Confirmed',
+//       location: 'Hong Kong',
+//       timeLabel: 'ATA: ',
+//       time: '2510-12-1 14:30 UTC+8',
+//       timezone: 'Asia/Shanghai',
+//       previous: 'Previous: Departure from Shanghai (08:15 UTC+8)'
+//     }
+//   ]
+// }
 
+const loading = ref(false)
 const getNotificationList = () => {
-  $api.getNotificationDetails().then((res) => {
-    if (res.code === 200) {
-      // console.log(res, 'test')
-    }
-  })
+  loading.value = true
+  $api
+    .getNotificationDetails({
+      rules_type: route.query.rules_type,
+      frequency_type: route.query.frequency_type,
+      insert_date_format: route.query.insert_date_format
+    })
+    .then((res) => {
+      if (res.code === 200) {
+        // console.log(res, 'test')
+        notificationData.value = res.data
+      }
+    })
+    .finally(() => {
+      loading.value = false
+    })
 }
 onMounted(() => {
   getNotificationList()
@@ -49,13 +71,35 @@ onMounted(() => {
 </script>
 
 <template>
-  <div class="system-message-detail">
+  <div class="system-message-detail" v-vloading="loading">
     <div class="content">
       <div class="header" v-if="notificationData.title">
         <div class="status-icon"></div>
         <div class="title">{{ notificationData.title }}</div>
       </div>
-      <div class="total-tips">Latest Status Updates ({{ notificationData.numericRecords }})</div>
+      <div class="total-tips" v-if="notificationData.numericRecords > -1">
+        Latest Status Updates ({{ notificationData.numericRecords }})
+      </div>
+      <div
+        class="total-tips"
+        v-else-if="notificationData.etdOrdeparturNum > -1 || notificationData.etaOrarrivalNum > -1"
+      >
+        <div>
+          <span v-if="notificationData.etdOrdeparturNum"
+            >{{ notificationData.type === 'delay' ? 'Departure Delay' : 'ETD Change' }} ({{
+              notificationData.etdOrdeparturNum
+            }})</span
+          >
+          <span v-if="notificationData.etdOrdeparturNum && notificationData.etaOrarrivalNum">
+            &nbsp;&nbsp;|&nbsp;&nbsp;</span
+          >
+          <span v-if="notificationData.etaOrarrivalNum">
+            {{ notificationData.type === 'delay' ? 'Arrival Delay' : 'ETA Change' }} ({{
+              notificationData.etaOrarrivalNum
+            }})
+          </span>
+        </div>
+      </div>
       <EventCard
         v-for="(item, index) in notificationData.notificationList"
         :key="index"
@@ -67,7 +111,9 @@ onMounted(() => {
 
 <style lang="scss" scoped>
 .system-message-detail {
+  height: 100%;
   padding: 16px;
+  overflow: auto;
   .content {
     margin: auto;
     width: 800px;

+ 3 - 3
src/views/SystemSettings/src/SystemSettings.vue

@@ -2,12 +2,12 @@
 import { ref, onMounted } from 'vue'
 import AddRSettingTableules from './components/SettingTable'
 import MonitoringTable from './components/MonitoringTable'
-import { useRouter } from 'vue-router'
+import { useRouter, useRoute } from 'vue-router'
 import PersonalProfile from './components/PersonalProfile.vue'
 
 const router = useRouter()
-
-const TabActive = ref('Personal Profile')
+const route = useRoute()
+const TabActive = ref(route.query.tab || 'Personal Profile')
 const isMilestoneChecked = ref(false)
 const isContainerChecked = ref(false)
 const isDepartureChecked = ref(false)