Sfoglia il codice sorgente

feat: 实现消息滚动加载

zhouyuhao 5 mesi fa
parent
commit
b9434b1bed

+ 50 - 16
src/components/NotificationMessageCard/src/NotificationMessageCard.vue

@@ -27,7 +27,13 @@ const props = withDefaults(
 )
 const pageData = ref<any[]>([])
 
-const emit = defineEmits<{ seeAll: []; hasCardRead: []; viewMore: []; jumpTracking: [] }>()
+const emit = defineEmits<{
+  seeAll: []
+  hasCardRead: []
+  viewMore: []
+  jumpTracking: []
+  loading: []
+}>()
 const handleSeeAll = () => {
   emit('seeAll')
 }
@@ -166,9 +172,7 @@ const setAllMessageRead = () => {
     item.info.isRead = true
   })
 }
-defineExpose({
-  setAllMessageRead
-})
+
 // 定时将消息卡片未读的置为已读,五分钟一次
 let timer = null
 onMounted(() => {
@@ -195,21 +199,41 @@ const parentHeight = computed(() => {
 const scrollParentBoxStyle = computed(() => {
   return props.topOffset ? { height: `${parentHeight.value}px` } : {}
 })
+
+const scrollContainerRef = ref<HTMLElement | null>(null)
+const loading = ref(false)
+const finished = ref(false)
+
+const loadMore = async () => {
+  if (loading.value || finished.value) return
+  loading.value = true
+  emit('loading')
+}
+
+const onScroll = () => {
+  const el = scrollContainerRef.value
+  if (!el || loading.value || finished.value) return
+
+  const threshold = 50 // 提前50px触发
+  if (el.scrollHeight - el.scrollTop - el.clientHeight <= threshold) {
+    loadMore()
+  }
+}
+
+defineExpose({
+  loading,
+  finished,
+  scrollContainerRef,
+  setAllMessageRead
+})
 </script>
 
 <template>
-  <DynamicScroller
-    class="scroller"
-    :style="scrollParentBoxStyle"
-    :items="pageData"
-    :min-item-size="100"
-    key-field="id"
-  >
-    <template v-slot="{ item, index, active }">
-      <DynamicScrollerItem
+  <div class="scroller" :style="scrollParentBoxStyle" ref="scrollContainerRef" @scroll="onScroll">
+    <template v-for="item in pageData" :key="item.id">
+      <div
         :class="{ 'scroll-padding': props.isScrollPadding }"
         :item="item"
-        :active="active"
         :size-dependencies="[item.info.isRead]"
       >
         <div
@@ -234,9 +258,15 @@ const scrollParentBoxStyle = computed(() => {
             {{ formatTimezone(item.info.first_notifiation_date) }}
           </div>
         </div>
-      </DynamicScrollerItem>
+      </div>
     </template>
-  </DynamicScroller>
+    <div class="footer">
+      <el-divider v-if="loading"> loading... </el-divider>
+      <el-divider v-if="finished && pageData.length > 0">
+        Only display the message data within one year
+      </el-divider>
+    </div>
+  </div>
 </template>
 
 <style lang="scss" scoped>
@@ -246,6 +276,10 @@ const scrollParentBoxStyle = computed(() => {
   .scroll-padding {
     padding: 0px 140px 0px 16px;
   }
+  .footer {
+    padding: 0 16px;
+    text-align: center;
+  }
 }
 .notification-message-card {
   position: relative;

+ 8 - 8
src/stores/modules/notificationMessage.ts

@@ -49,15 +49,15 @@ export const useNotificationMessage = defineStore('notificationMessage', {
     async markMessageAsRead() {
       if (this.readCardMap.length === 0) return
 
-      await $api.setMessageRead({ id: this.readCardMap }).then((res) => {
-        if (res.code === 200) {
-          this.readCardMap = []
-          localStorage.setItem('readCardMap', JSON.stringify(this.readCardMap))
+      // await $api.setMessageRead({ id: this.readCardMap }).then((res) => {
+      //   if (res.code === 200) {
+      //     this.readCardMap = []
+      //     localStorage.setItem('readCardMap', JSON.stringify(this.readCardMap))
 
-          // 在将消息标记为已读后,再次检查是否有新消息
-          this.hasUnreadMessages()
-        }
-      })
+      //     // 在将消息标记为已读后,再次检查是否有新消息
+      //     this.hasUnreadMessages()
+      //   }
+      // })
     },
     clearData() {
       this.notificationMsgList = []

+ 16 - 5
src/views/Layout/src/components/Header/components/NotificationDrawer.vue

@@ -19,16 +19,25 @@ const notificationTypeList = ref({
 })
 
 const notificationList = ref<any[]>([])
-
+const notificationMessageCardsRef = ref()
+const pageInfo = ref({
+  cp: 1,
+  ps: 5
+})
 const getNotificationList = () => {
   loading.value = true
   $api
     .getNotificationList({
-      rules_type: notificationType.value
+      rules_type: notificationType.value,
+      cp: pageInfo.value.cp,
+      ps: pageInfo.value.ps
     })
     .then((res) => {
       if (res.code === 200) {
-        notificationList.value = res.data
+        notificationList.value = [...notificationList.value, ...res.data]
+        if (res.data.length === 0 || res.data.length < pageInfo.value.ps) {
+          notificationMessageCardsRef.value.finished = true
+        }
         // nextTick(() => {
         //   init()
         // })
@@ -36,6 +45,8 @@ const getNotificationList = () => {
     })
     .finally(() => {
       loading.value = false
+      pageInfo.value.cp += 1
+      notificationMessageCardsRef.value.loading = false
     })
 }
 
@@ -73,9 +84,8 @@ const closeDrawer = () => {
   notificationList.value = []
   notificationType.value = 'all'
   notificationMsgStore.markMessageAsRead()
+  pageInfo.value.cp = 1
 }
-
-const notificationMessageCardsRef = ref()
 </script>
 
 <template>
@@ -131,6 +141,7 @@ const notificationMessageCardsRef = ref()
             @see-all="drawerRef.handleClose()"
             @view-more="drawerRef.handleClose()"
             @jump-tracking="drawerRef.handleClose()"
+            @loading="getNotificationList"
             :data="notificationList"
             :topOffset="185"
             ref="notificationMessageCardsRef"

+ 72 - 23
src/views/SystemMessage/src/SystemMessage.vue

@@ -13,19 +13,25 @@ const tabCountList = ref([0, 0, 0, 0, 0])
 const curTabCount = ref([])
 
 const handleCount = (count: number) => {
-  if (!count) return ''
+  if (!count || count < 0) return ''
   return count > 99 ? '99+' : count
 }
+// 计算未读卡片数量
+const unreadCardCount = computed(() => {
+  const curEventNotificationIndex = navList.findIndex((navItem) => {
+    return navItem === activeCardTypeName.value
+  })
+  return tabCountList.value[curEventNotificationIndex] - notificationMsgStore.readCardMap.length
+})
 const handleShowCount = (typeName: string, index: number) => {
   // 在切换type类型时,防止点击的类型值为点击之前类型的值
   if (curTabCount.value?.[index] > -1) {
     return curTabCount.value[index]
   }
-  const count = tabCountList.value[index]
   if (typeName === activeCardTypeName.value) {
-    return handleCount(unreadNotificationList.value.length)
+    return handleCount(unreadCardCount.value)
   }
-  return handleCount(count)
+  return handleCount(tabCountList.value[index])
 }
 
 const navList = [
@@ -52,6 +58,10 @@ const setActiveItem = (item: string) => {
     tabCountList.value.length - 1
   )
 
+  // 滚动到顶部
+  if (notificationMessageCardRef.value) {
+    notificationMessageCardRef.value.scrollContainerRef.scrollTo(0, 0)
+  }
   activeCardTypeName.value = item
   sessionStorage.setItem('activeCardTypeName', item)
   activeTabName.value = 'All Notifications'
@@ -61,40 +71,72 @@ const setActiveItem = (item: string) => {
 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 unreadNotificationList = computed(() => {
+//   return notificationList.value.filter((item) => !item.info.isRead)
+// })
+const unreadNotificationList = ref<any[]>([])
+// const readNotificationList = computed(() => {
+//   return notificationList.value.filter((item) => item.info.isRead)
+// })
+const readNotificationList = ref<any[]>([])
+const pageInfo = ref({
+  cp: 1,
+  ps: 5
 })
-const getNotificationList = async () => {
+const getNotificationList = async (tabType: string = 'All Notification') => {
   loading.value = true
   const rulesType = Object.entries(notificationTypeList.value).find(
     (item) => item[1] === activeCardTypeName.value
   )?.[0]
+  let info_type: string | boolean = ''
+  if (tabType === 'All Notification') {
+    info_type = ''
+  } else if (tabType === 'Unread') {
+    info_type = true
+  } else {
+    info_type = false
+  }
   try {
     await notificationMsgStore.markMessageAsRead()
     $api
       .getSystemMessageData({
-        rules_type: rulesType
+        rules_type: rulesType,
+        cp: pageInfo.value.cp,
+        ps: pageInfo.value.ps,
+        info_type
       })
       .then((res) => {
         if (res.code === 200) {
           const data = res.data
-          notificationList.value = data.cardList
-          tabCountList.value = data.countList
+          notificationList.value = [...notificationList.value, ...data.cardList]
+          // tabCountList.value = data.countList
+          !data?.cardList?.length && (notificationMessageCardRef.value.finished = true)
+          if (tabType === 'All Notification') {
+            tabCountList.value = data.countList
+            notificationList.value = [...notificationList.value, ...data.cardList]
+          } else if (tabType === 'Unread') {
+            unreadNotificationList.value = [...unreadNotificationList.value, ...data.cardList]
+          } else {
+            readNotificationList.value = [...readNotificationList.value, ...data.cardList]
+          }
         }
       })
       .finally(() => {
         loading.value = false
         curTabCount.value = []
+        notificationMessageCardRef.value.loading = false
+        pageInfo.value.cp += 1
       })
   } catch (error) {
-    console.error(error)
     loading.value = false
     curTabCount.value = []
   }
 }
+const notificationMessageCardRef = ref()
+const handleMessageLoading = async () => {
+  pageInfo.value.cp += 1
+  await getNotificationList()
+}
 
 const changeCardRead = () => {
   const readCardMap = notificationMsgStore.readCardMap
@@ -108,12 +150,13 @@ const changeCardRead = () => {
 const activeTabName = ref('All Notifications')
 const handleTabChange = () => {
   // 当前tab页切换时,更新数据
-  const readCardMap = notificationMsgStore.readCardMap
-  notificationList.value.forEach((item) => {
-    if (readCardMap.includes(item.info.id)) {
-      item.info.isRead = true
-    }
-  })
+  // const readCardMap = notificationMsgStore.readCardMap
+  // notificationList.value.forEach((item) => {
+  //   if (readCardMap.includes(item.info.id)) {
+  //     item.info.isRead = true
+  //   }
+  // })
+  getNotificationList(activeTabName.value)
 }
 
 onMounted(() => {
@@ -174,10 +217,12 @@ onMounted(() => {
               <NotificationMessageCard
                 v-if="activeTabName === 'All Notifications'"
                 :data="notificationList"
-                @hasCardRead="changeCardRead"
                 :isScrollPadding="true"
                 :isShowInsertionTime="true"
                 :updateReadCardsOnChange="false"
+                @hasCardRead="changeCardRead"
+                @loading="getNotificationList('All Notifications')"
+                ref="notificationMessageCardRef"
               ></NotificationMessageCard>
             </div>
           </el-tab-pane>
@@ -187,9 +232,11 @@ onMounted(() => {
               <div
                 class="count"
                 :style="{ 'padding-top': isMac ? 0 : '1px' }"
-                v-if="unreadNotificationList.length"
+                v-if="unreadNotificationList.length > 0 || unreadCardCount > 0"
               >
-                <span>{{ handleCount(unreadNotificationList.length) }}</span>
+                <span>{{
+                  handleCount(unreadNotificationList.length) || handleCount(unreadCardCount)
+                }}</span>
               </div>
             </template>
             <div style="padding-bottom: 20px" v-if="activeTabName === 'Unread'">
@@ -199,6 +246,7 @@ onMounted(() => {
                 :isScrollPadding="true"
                 :isShowInsertionTime="true"
                 :updateReadCardsOnChange="false"
+                @loading="getNotificationList('Unread')"
               ></NotificationMessageCard>
             </div>
           </el-tab-pane>
@@ -211,6 +259,7 @@ onMounted(() => {
                 :isScrollPadding="true"
                 :isShowInsertionTime="true"
                 :data="readNotificationList"
+                @loading="getNotificationList('Read')"
               >
               </NotificationMessageCard>
             </div>