Sfoglia il codice sorgente

feat: 完成卡片未读置为已读的功能

zhouyuhao 8 mesi fa
parent
commit
bd1b8727ec

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

@@ -2,7 +2,9 @@
 import EventCard from './components/EventCard.vue'
 import PasswordCard from './components/PasswordCard.vue'
 import FeatureUpdateCard from './components/FeatureUpdateCard.vue'
+import { useNotificationMessage } from '@/stores/modules/notificationMessage'
 
+const notificationMessageStore = useNotificationMessage()
 const props = defineProps<{
   data: any
 }>()
@@ -11,19 +13,93 @@ const emit = defineEmits<{ seeAll: [] }>()
 const handleSeeAll = () => {
   emit('seeAll')
 }
+
+// 创建一个新的 IntersectionObserver 实例
+const observer = new IntersectionObserver(
+  (entries) => {
+    entries.forEach((entry) => {
+      // const index = cardsTest.value.findIndex((item) => item.id === entry.target?.dataset?.cardId)
+      const cardId = entry.target?.dataset?.cardId
+      if (entry.isIntersecting) {
+        // 将卡片设置为已经展示
+        notificationMessageStore.setReadCardMap(cardId)
+        const index = props.data.findIndex((item) => item.info.id === cardId)
+        if (index > -1) {
+          //  在1秒钟后将消息卡片设置为已读
+          setTimeout(() => {
+            props.data[index].info.isRead = true
+          }, 1000)
+        }
+      }
+    })
+  },
+  {
+    // 配置选项
+    root: null, // 使用视窗作为根元素
+    threshold: 0.1 // 当至少10%的元素进入视图时触发回调
+  }
+)
+
+// 监听元素是否在可视区域内
+const watchCards = () => {
+  const curAllCards = document?.querySelectorAll('.notification-message-card')
+  curAllCards.forEach((card: any) => {
+    const index = notificationMessageStore.notificationMsgList.indexOf(card.dataset.cardId)
+    if (index < 0 && card.dataset.cardIsread === 'false' && card.dataset.cardId) {
+      notificationMessageStore.pushNotificationMessage([card.dataset.cardId])
+
+      observer.observe(card)
+    }
+  })
+}
+
+watch(
+  () => props.data,
+  () => {
+    nextTick(() => {
+      setTimeout(() => {
+        watchCards()
+      }, 1000)
+    })
+  },
+  {
+    immediate: true,
+    deep: true
+  }
+)
+
+const clearReadData = () => {
+  const idsToRemove = new Set(props.data.map((item: any) => item.info.id))
+  const filteredId = notificationMessageStore.notificationMsgList.filter(
+    (id) => !idsToRemove.has(id)
+  )
+  notificationMessageStore.pushNotificationMessage(filteredId)
+}
+
+// 定时将消息卡片未读的置为已读
+let timer = null
+onMounted(() => {
+  timer = setInterval(() => {
+    notificationMessageStore.markMessageAsRead()
+  }, 300000)
+})
+onUnmounted(() => {
+  clearInterval(timer)
+  clearReadData()
+})
 </script>
 
 <template>
-  <div class="notification-message-card">
-    <template v-for="(item, index) in data" :key="index">
-      <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>
+  <div
+    class="notification-message-card"
+    :data-card-id="item.info.id"
+    :data-card-isread="item.info.isRead"
+    v-for="(item, index) in data"
+    :key="index"
+  >
+    <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" />
   </div>
 </template>
 

+ 6 - 6
src/components/NotificationMessageCard/src/components/EventCard.vue

@@ -83,19 +83,19 @@ const jumpTracking = (data: EventCardPropsData) => {
           <span class="font_family icon-icon_next_b"></span>
         </el-button>
       </div>
-      <div class="more-tips" v-if="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"
+          <span v-if="data.info?.etdOrdeparturNum"
             >{{ data.type === 'delay' ? 'Departure Delay' : 'ETD Change' }} ({{
-              data.info.etdOrdeparturNum
+              data.info?.etdOrdeparturNum
             }})</span
           >
-          <span v-if="data.info.etdOrdeparturNum && data.info.etaOrarrivalNum">
+          <span v-if="data.info?.etdOrdeparturNum && data.info?.etaOrarrivalNum">
             &nbsp;&nbsp;|&nbsp;&nbsp;</span
           >
-          <span v-if="data.info.etaOrarrivalNum">
+          <span v-if="data.info?.etaOrarrivalNum">
             {{ data.type === 'delay' ? 'Arrival Delay' : 'ETA Change' }} ({{
-              data.info.etaOrarrivalNum
+              data.info?.etaOrarrivalNum
             }})
           </span>
         </div>

+ 19 - 3
src/components/NotificationMessageCard/src/components/FeatureUpdateCard.vue

@@ -1,5 +1,7 @@
 <script setup lang="ts">
-import featureImg from '../images/test.png'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
 
 interface FeatureUpdateCardPropsData {
   title: string
@@ -12,6 +14,16 @@ interface FeatureUpdateCardPropsData {
 const props = defineProps<{
   data: FeatureUpdateCardPropsData
 }>()
+
+const handleViewMore = () => {
+  router.push({
+    name: 'System Message Detail',
+    query: {
+      type: 'feature',
+      title: props.data.header
+    }
+  })
+}
 </script>
 
 <template>
@@ -31,11 +43,15 @@ const props = defineProps<{
           <span>{{ data.content }}</span>
         </div>
         <div class="feature-img">
-          <el-image :src="featureImg" fit="contain" alt="feature-img"></el-image>
+          <el-image :src="data.imgSrc" fit="contain" alt="feature-img"></el-image>
         </div>
 
         <div class="change-btn" style="text-align: center">
-          <el-button class="el-button--main" style="height: 40px; padding: 0 32px">
+          <el-button
+            @click="handleViewMore"
+            class="el-button--main"
+            style="height: 40px; padding: 0 32px"
+          >
             View more</el-button
           >
         </div>

BIN
src/components/NotificationMessageCard/src/images/test.png


+ 21 - 1
src/components/VSliderVerification/src/VSliderVerification.vue

@@ -34,6 +34,10 @@ const addTipsNode = () => {
   const childNode = document.createElement('div')
   childNode.className = 'tips'
   childNode.innerHTML = `
+    <div style="margin-bottom: 15px; text-align: right;">
+      <span class="font_family icon-icon_reject_b close-icon" style="margin-right: -20px;">
+      </span>
+    </div>
     <p>Please drag the slider below to complete the</p>
     <p>verification to ensure normal access</p>
   `
@@ -43,6 +47,14 @@ const addTipsNode = () => {
   } else {
     parentNode.appendChild(childNode)
   }
+  nextTick(() => {
+    const targetNode: any = document.querySelector('.font_family.icon-icon_reject_b.close-icon')
+    targetNode.onclick = closeDialog
+  })
+}
+
+const closeDialog = () => {
+  emit('close')
 }
 
 const styleMap = {
@@ -88,6 +100,7 @@ const updateSliderBackground = (state: string) => {
 
 const emit = defineEmits<{
   close: []
+  success: []
 }>()
 // 监听验证成功事件,因为这里库中的成功事件有0.8秒的延迟,所以这里手动监听验证成功事件
 const onSuccess = () => {
@@ -101,7 +114,7 @@ const onSuccess = () => {
             updateSliderBackground('success')
             addSliderBtnNode('success')
             setTimeout(() => {
-              emit('close')
+              emit('success')
               isShow.value = false
             }, 500)
           }
@@ -163,12 +176,19 @@ defineExpose({
   width: 400px;
   height: 373px;
   padding: 40px;
+  padding-top: 20px;
   background-color: var(--color-slider-bg);
   border-radius: 16px;
   box-shadow: -2px 2px 12px 0 rgba(0, 0, 0, 0.5);
   .tips {
     margin-bottom: 16px;
     text-align: center;
+    .close-icon {
+      cursor: pointer;
+      &:hover {
+        color: var(--color-theme);
+      }
+    }
   }
   .icon-border {
     display: flex;

+ 50 - 0
src/stores/modules/notificationMessage.ts

@@ -0,0 +1,50 @@
+import { defineStore } from 'pinia'
+
+interface NotificationMessageState {
+  notificationMsgList: string[] // 页面中监听的未读消息id
+  readCardMap: string[] // 已读的消息id
+  requestedReadList: string[] // 已请求置为已读的消息id
+}
+
+export const useNotificationMessage = defineStore('notificationMessage', {
+  state: (): NotificationMessageState => ({
+    notificationMsgList: JSON.parse(localStorage.getItem('notificationMsgList')) || [],
+    readCardMap: JSON.parse(localStorage.getItem('readCardMap')) || [],
+    requestedReadList: JSON.parse(localStorage.getItem('requestedReadList')) || []
+  }),
+  getters: {},
+  actions: {
+    pushNotificationMessage(array: any[]) {
+      this.notificationMsgList = [...this.notificationMsgList, ...array]
+      localStorage.setItem('notificationMsgList', JSON.stringify(this.notificationMsgList))
+    },
+    setReadCardMap(id: string) {
+      if (this.readCardMap.includes(id) || this.requestedReadList.includes(id)) return
+      this.readCardMap.push(id)
+      localStorage.setItem('readCardMap', JSON.stringify(this.readCardMap))
+    },
+    markMessageAsRead() {
+      if (this.readCardMap.length === 0) return
+      $api.setMessageRead({ id: this.readCardMap }).then((res) => {
+        if (res.code === 200) {
+          this.requestedReadList = this.readCardMap
+          localStorage.setItem('requestedReadList', JSON.stringify(this.requestedReadList))
+          this.readCardMap = []
+          localStorage.setItem('readCardMap', JSON.stringify(this.readCardMap))
+
+          this.notificationMsgList = this.notificationMsgList.filter(
+            (item) => !this.readCardMap.includes(item.id)
+          )
+        }
+      })
+    },
+    clearData() {
+      this.notificationMsgList = []
+      this.readCardMap = []
+      this.requestedReadList = []
+      localStorage.removeItem('notificationMsgList')
+      localStorage.removeItem('readCardMap')
+      localStorage.removeItem('requestedReadList')
+    }
+  }
+})

+ 2 - 0
src/stores/modules/user.ts

@@ -1,5 +1,6 @@
 import { defineStore } from 'pinia'
 import { useVisitedRowState } from './visitedRow'
+import { useNotificationMessage } from './notificationMessage'
 import dayjs from 'dayjs'
 
 interface UserInfo {
@@ -91,6 +92,7 @@ export const useUserStore = defineStore('user', {
       }
       this.isFirstLogin = false
       useVisitedRowState().clearVisitedRow()
+      useNotificationMessage().clearData()
     }
   }
 })

+ 7 - 2
src/views/Layout/src/components/Header/HeaderView.vue

@@ -179,6 +179,11 @@ const closePopover = () => {
 }
 
 const notificationDrawer = ref(false)
+
+const hasNewMessage = ref(false)
+const notifyNewMessage = () => {
+  hasNewMessage.value = true
+}
 </script>
 
 <template>
@@ -190,7 +195,7 @@ const notificationDrawer = ref(false)
     element-loading-background="rgb(43, 47, 54, 0.7)"
   >
     <VBreadcrumb></VBreadcrumb>
-    <TrainingCard ref="trainingCardRef"></TrainingCard>
+    <TrainingCard ref="trainingCardRef" @has-new-message="notifyNewMessage"></TrainingCard>
     <div class="right-info">
       <el-input
         v-model="searchValue"
@@ -203,7 +208,7 @@ const notificationDrawer = ref(false)
         </template>
       </el-input>
       <div class="notice-icon" v-if="userStore.userInfo?.uname">
-        <span class="unread-tip-icon"></span>
+        <span v-if="hasNewMessage" class="unread-tip-icon"></span>
         <el-button
           style="height: 40px; width: 40px; margin-right: 0px"
           class="el-button--text"

+ 12 - 10
src/views/Layout/src/components/Header/components/NotificationDrawer.vue

@@ -89,6 +89,9 @@ const getNotificationList = () => {
     .then((res) => {
       if (res.code === 200) {
         notificationList.value = res.data
+        // nextTick(() => {
+        //   init()
+        // })
       }
     })
     .finally(() => {
@@ -96,16 +99,13 @@ const getNotificationList = () => {
     })
 }
 
+// 标记所有为已读
 const handleMarkAllRead = () => {
-  // 标记所有为已读
-  // notificationList.value.forEach((item) => {
-  //   item.isRead = true
-  // })
-  $api.setMessageRead({ read_type: true }).then((res) => {
-    if (res.code === 200) {
-      console.log('标记成功')
-    }
-  })
+  try {
+    $api.setMessageRead({ read_type: true })
+  } catch (error) {
+    console.error(error)
+  }
 }
 
 const drawerRef = ref()
@@ -127,6 +127,8 @@ const handleSettingMessage = () => {
 const clearData = () => {
   notificationList.value = []
 }
+
+const notificationListRef = ref<HTMLElement | null>(null)
 </script>
 
 <template>
@@ -172,7 +174,7 @@ const clearData = () => {
             </el-button>
           </div>
         </div>
-        <div class="notification-content">
+        <div class="notification-content" ref="notificationListRef">
           <NotificationMessageCard @see-all="drawerRef.handleClose()" :data="notificationList" />
         </div>
       </el-scrollbar>

+ 59 - 19
src/views/Layout/src/components/Header/components/TrainingCard.vue

@@ -2,8 +2,11 @@
 import { onBeforeRouteUpdate } from 'vue-router'
 import NotificationMessageCard from '@/components/NotificationMessageCard/src/NotificationMessageCard.vue'
 import { useUserStore } from '@/stores/modules/user'
+import { useNotificationMessage } from '@/stores/modules/notificationMessage'
+import dayjs from 'dayjs'
 
 const userStore = useUserStore()
+const notificationMessageStore = useNotificationMessage()
 const notificationList = ref([])
 // const notificationList = [
 //   {
@@ -112,34 +115,53 @@ const curCard = computed(() => {
 })
 const curIndex = ref(0)
 // 设置定时器进行自动轮播
-let intervalId = null
+let trainingIntervalId = null
+
+// 轮询最新未读消息
+let newMessageIntervalId = null
+// 轮询最新未读消息
+const pollingNewMessage = () => {
+  if (newMessageIntervalId) return
+  // 每隔5分钟轮询一次
+  newMessageIntervalId = setInterval(() => {
+    getNotificationList(dayjs().format('MM/DD/YYYY HH:mm:ss'))
+  }, 300000)
+}
+
+// 登录后自动轮播消息
+const trainingCardAfterLogin = () => {
+  curIndex.value = curIndex.value + 1
+  // 如果到达最后一个消息,设置为null以清除显示
+  if (curIndex.value >= notificationList.value.length) {
+    clearInterval(trainingIntervalId)
+    pollingNewMessage()
+  }
+}
 
 const nextNotification = () => {
   let result = true
   // 更新当前索引和卡片
   curIndex.value = curIndex.value + 1
-  // curCard.value = notificationList[curIndex.value]
   // 如果消息为password或者feature类型,暂停自动轮播
   if (
     curCard.value?.notificationType === 'password' ||
     curCard.value?.notificationType === 'feature'
   ) {
-    clearInterval(intervalId)
+    clearInterval(trainingIntervalId)
     result = false
   }
-
   // 如果到达最后一个消息,设置为null以清除显示
   if (curIndex.value >= notificationList.value.length) {
-    clearInterval(intervalId)
-    // curCard.value = null
+    clearInterval(trainingIntervalId)
     result = false
   }
   return result
 }
 
+// 轮询时的轮播定时器
 const initTrainingCard = () => {
   if (curCard.value?.notificationType === 'event') {
-    intervalId = setInterval(nextNotification, 2000)
+    trainingIntervalId = setInterval(nextNotification, 2000)
   }
 }
 
@@ -147,38 +169,56 @@ onBeforeRouteUpdate((to, from, next) => {
   if (from.name === 'Login' && userStore.userName) {
     getNotificationList()
   }
+  if (to.name === 'Login') {
+    clearInterval(trainingIntervalId)
+    clearInterval(newMessageIntervalId)
+  }
   next()
 })
 
-const getNotificationList = () => {
-  // if (localStorage.getItem('showFeatureAfterLogin') !== 'true') return
-  // // 获取数据
-
-  // localStorage.removeItem('showFeatureAfterLogin')
+const emit = defineEmits<{ hasNewMessage: [] }>()
+const getNotificationList = (time?: string) => {
   $api
     .getNotificationList({
       rules_type: 'all',
-      info_type: true
+      info_type: true,
+      current_time: time
     })
     .then((res) => {
       if (res.code === 200) {
+        curIndex.value = 0
         notificationList.value = res.data
-        console.log(curCard.value, 'curCard')
-        initTrainingCard()
+
+        if (time && res.data.length > 0) {
+          emit('hasNewMessage')
+          initTrainingCard()
+        } else {
+          trainingIntervalId = setInterval(trainingCardAfterLogin, 2000)
+        }
       }
     })
 }
 
+// 关闭消息,如果是登录后自动轮播的消息,则需清除定时器,如果不是则继续轮播下一条消息
 const closeMessage = () => {
+  if (!newMessageIntervalId) {
+    clearInterval(trainingIntervalId)
+    curIndex.value = -1
+    pollingNewMessage()
+    return
+  }
+
   // 如果当前消息为event类型,则需先清除定时器
   if (curCard.value?.notificationType === 'event') {
-    clearInterval(intervalId)
+    clearInterval(trainingIntervalId)
   }
 
   const result = nextNotification()
   if (result) {
-    intervalId = setInterval(nextNotification, 2000)
+    trainingIntervalId = setInterval(nextNotification, 2000)
   }
+  // 将当前消息标记为已读
+  notificationMessageStore.setReadCardMap(curCard.value?.info?.id)
 }
 </script>
 
@@ -204,9 +244,9 @@ const closeMessage = () => {
   width: 432px;
   padding: 16px;
   padding-bottom: 0;
-  background-color: #fff;
+  background-color: var(--color-dialog-body-bg);
   border-radius: 12px;
-  box-shadow: 4px 4px 16px 0px rgba(0, 0, 0, 0.1);
+  box-shadow: 4px 4px 32px 0px rgba(0, 0, 0, 0.2);
   .close-icon {
     position: absolute;
     top: 14px;

+ 2 - 1
src/views/Login/src/loginView.vue

@@ -454,7 +454,8 @@ const firstLoginTipsRef = ref()
     </el-card>
     <VSliderVerification
       v-if="isShowSliderVerification"
-      @close="confirmVerification"
+      @success="confirmVerification"
+      @close="isShowSliderVerification = false"
       ref="sliderVerificationRef"
     ></VSliderVerification>
     <ErrorTips ref="errorTipsRef" @forget-password="status = 'reset'"></ErrorTips>

+ 26 - 16
src/views/SystemMessage/src/SystemMessage.vue

@@ -1,6 +1,8 @@
 <script setup lang="ts">
 import NotificationMessageCard from '@/components/NotificationMessageCard/src/NotificationMessageCard.vue'
+import { useNotificationMessage } from '@/stores/modules/notificationMessage'
 
+const notificationMessageStore = useNotificationMessage()
 const collapseVModel = ref<string[]>(['1'])
 
 const tabCountList = ref([0, 0, 0, 0, 0])
@@ -28,7 +30,20 @@ const notificationTypeList = ref({
 const setActiveItem = (item: string) => {
   activeItem.value = item
   activeName.value = 'All Notifications'
-
+  // if (activeItem.value === 'Feature Update') {
+  //   notificationList.value = [
+  //     {
+  //       notificationType: 'feature',
+  //       info: {
+  //         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!'
+  //       }
+  //     }
+  //   ]
+  //   return
+  // }
   getNotificationList()
 }
 
@@ -66,6 +81,9 @@ const activeName = ref('All Notifications')
 onMounted(() => {
   getNotificationList()
 })
+onUnmounted(() => {
+  notificationMessageStore.markMessageAsRead()
+})
 </script>
 
 <template>
@@ -84,7 +102,7 @@ onMounted(() => {
             >
               <div v-if="item === activeItem" class="active-sign"></div>
               <span>{{ item }}</span>
-              <div class="count">
+              <div class="count" v-if="tabCountList?.[index]">
                 <span>{{ handleCount(tabCountList?.[index]) }}</span>
               </div>
             </div>
@@ -98,7 +116,7 @@ onMounted(() => {
         >
           <div v-if="activeItem === 'Feature Update'" class="active-sign"></div>
           <span>Feature Update</span>
-          <div class="count">
+          <div class="count" v-if="tabCountList?.[tabCountList.length - 1]">
             <span>{{ handleCount(tabCountList?.[tabCountList.length - 1]) }}</span>
           </div>
         </div>
@@ -108,33 +126,25 @@ onMounted(() => {
           <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">
+            <div style="padding: 10px 140px 0px 16px" v-if="activeName === 'All Notifications'">
               <NotificationMessageCard :data="notificationList"></NotificationMessageCard>
             </div>
           </el-tab-pane>
           <el-tab-pane label="Unread" name="Unread">
             <template #label>
               <span style="margin-right: 4px">Unread</span>
-              <div class="count">
+              <div class="count" v-if="unreadNotificationList.length">
                 <span>{{ handleCount(unreadNotificationList.length) }}</span>
               </div>
             </template>
-            <div style="padding: 10px 140px 0px 16px">
+            <div style="padding: 10px 140px 0px 16px" v-if="activeName === 'Unread'">
               <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">
+            <template #label><span style="margin-right: 4px">Read</span> </template>
+            <div style="padding: 10px 140px 0px 16px" v-if="activeName === 'Read'">
               <NotificationMessageCard :data="readNotificationList"></NotificationMessageCard>
             </div>
           </el-tab-pane>

+ 28 - 3
src/views/SystemMessage/src/components/SystemMessageDetail.vue

@@ -57,7 +57,6 @@ const getNotificationList = () => {
     })
     .then((res) => {
       if (res.code === 200) {
-        // console.log(res, 'test')
         notificationData.value = res.data
       }
     })
@@ -65,14 +64,22 @@ const getNotificationList = () => {
       loading.value = false
     })
 }
+const init = () => {
+  if (route.query.type === 'feature') {
+    console.log(route.query.title)
+    notificationData.value.title = (route.query.title as string) || ''
+  } else {
+    getNotificationList()
+  }
+}
 onMounted(() => {
-  getNotificationList()
+  init()
 })
 </script>
 
 <template>
   <div class="system-message-detail" v-vloading="loading">
-    <div class="content">
+    <div class="content" v-if="route.query.type !== 'feature'">
       <div class="header" v-if="notificationData.title">
         <div class="status-icon"></div>
         <div class="title">{{ notificationData.title }}</div>
@@ -106,6 +113,20 @@ onMounted(() => {
         :data="item"
       />
     </div>
+    <div class="content" v-else>
+      <div class="header" v-if="notificationData.title">
+        <div class="status-icon"></div>
+        <div class="title">{{ notificationData.title }}</div>
+      </div>
+      <div class="feature-pdf">
+        <embed
+          src="https://juejin.cn/post/7480076971226284058?utm_source=gold_browser_extension"
+          width="100%"
+          height="100%"
+          type="application/pdf"
+        />
+      </div>
+    </div>
   </div>
 </template>
 
@@ -117,6 +138,7 @@ onMounted(() => {
   .content {
     margin: auto;
     width: 800px;
+    height: 100%;
   }
   .notification-card {
     max-width: 800px;
@@ -142,5 +164,8 @@ onMounted(() => {
     line-height: 40px;
     font-size: 12px;
   }
+  .feature-pdf {
+    height: calc(100% - 28px);
+  }
 }
 </style>

+ 2 - 1
src/views/Tracking/src/components/PublicTracking/src/PublicTrackingSearch.vue

@@ -138,7 +138,8 @@ const encryptPassword = (password) => {
     </div>
     <VSliderVerification
       v-if="isShowSliderVerification"
-      @close="confirmVerification"
+      @success="confirmVerification"
+      @close="isShowSliderVerification = false"
       ref="sliderVerificationRef"
     ></VSliderVerification>
   </div>

+ 0 - 222
src/views/Tracking/src/components/PublicTracking/src/components/SlideVerify.vue

@@ -1,222 +0,0 @@
-<script lang="ts" setup>
-const dialogVisible = ref(false)
-
-const openDialog = () => {
-  dialogVisible.value = true
-}
-
-const position = ref(0)
-const isDragging = ref(false)
-const verifyText = ref('Swipe right to verify')
-const sliderState = ref<'start' | 'success' | 'error' | 'dragging'>('start')
-const styleMap = {
-  start: {
-    thumbColor: 'var(--color-neutral-1)',
-    thumbIcon: 'icon-icon_drag__line_b',
-    trackBackground: '#87909e'
-  },
-  dragging: {
-    thumbColor: 'var(--color-neutral-1)',
-    thumbIcon: 'icon-icon_drag__line_b',
-    trackBackground: 'var(--color-success)'
-  },
-  success: {
-    thumbColor: '#fff',
-    thumbIcon: 'icon-icon_confirm_b',
-    trackBackground: 'var(--color-success)'
-  },
-  error: {
-    thumbColor: '#fff',
-    thumbIcon: 'icon-icon_reject_b',
-    trackBackground: '#c7353f'
-  }
-}
-const trackRef = ref<HTMLElement | null>(null)
-
-const getTrackBackground = () => {
-  const trackWidth = trackRef.value?.offsetWidth || 320
-  const progress = (position.value / (trackWidth - 40)) * 100 // 百分比
-  if (sliderState.value === 'start') {
-    return styleMap.start.trackBackground // 初始时灰色
-  } else if (sliderState.value === 'dragging') {
-    return `linear-gradient(90deg, ${styleMap.success.trackBackground} ${progress}%, ${styleMap.start.trackBackground} ${progress}%)`
-  } else if (sliderState.value === 'error') {
-    return `linear-gradient(90deg, ${styleMap.error.trackBackground} ${progress}%, ${styleMap.start.trackBackground} ${progress}%)`
-  }
-  return styleMap.success.trackBackground // 成功时整条绿色
-}
-
-const startDrag = () => {
-  if (sliderState.value === 'success') {
-    return
-  }
-
-  isDragging.value = true
-  document.addEventListener('mousemove', onDrag)
-  document.addEventListener('mouseup', stopDrag)
-}
-
-const onDrag = (event: MouseEvent) => {
-  if (isDragging.value) {
-    if (trackRef.value) {
-      sliderState.value = 'dragging'
-      verifyText.value = 'Swipe right to verify'
-      const rect = trackRef.value.getBoundingClientRect()
-      const offsetX = event.clientX - rect.left
-      position.value = Math.min(Math.max(offsetX, 0), rect.width - 40) // 40是滑块的宽度
-    }
-  }
-}
-
-const emit = defineEmits<{
-  verifySuccess: []
-}>()
-const stopDrag = () => {
-  isDragging.value = false
-  document.removeEventListener('mousemove', onDrag)
-  document.removeEventListener('mouseup', stopDrag)
-
-  if (trackRef.value) {
-    const trackWidth = trackRef.value.offsetWidth
-    if (position.value >= trackWidth - 40) {
-      sliderState.value = 'success'
-      verifyText.value = 'Verification successful'
-      setTimeout(() => {
-        dialogVisible.value = false
-        emit('verifySuccess')
-      }, 500)
-    } else {
-      sliderState.value = 'error'
-      verifyText.value = 'Verification failed'
-      setTimeout(() => {
-        sliderState.value = 'start'
-        verifyText.value = 'Swipe right to verify'
-        position.value = 0
-      }, 3000)
-    }
-  }
-}
-
-const moveSlider = (event: MouseEvent) => {
-  if (sliderState.value !== 'success') {
-    onDrag(event)
-  }
-}
-
-const clearData = () => {
-  sliderState.value = 'start'
-  verifyText.value = 'Swipe right to verify'
-  position.value = 0
-}
-defineExpose({
-  openDialog
-})
-</script>
-
-<template>
-  <el-dialog
-    top="30vh"
-    destroy-on-close
-    :close-on-click-modal="false"
-    :close-on-press-escape="false"
-    @closed="clearData"
-    v-model="dialogVisible"
-    width="400"
-    class="slide-verify-dialog"
-  >
-    <div class="content">
-      <p>Please drag the slider below to complete the</p>
-      <p>verification to ensure normal access</p>
-      <div class="slider-container">
-        <div
-          class="slider-track"
-          :style="{ background: getTrackBackground() }"
-          @click="moveSlider"
-          ref="trackRef"
-        >
-          {{ verifyText }}
-          <div
-            class="slider-thumb"
-            :style="{ left: `${position}px`, borderColor: styleMap[sliderState].trackBackground }"
-            @mousedown="startDrag"
-          >
-            <span
-              v-if="sliderState === 'start' || sliderState === 'dragging'"
-              class="font_family"
-              :style="{ color: styleMap[sliderState].thumbColor }"
-              :class="[styleMap[sliderState].thumbIcon]"
-            ></span>
-            <span
-              v-else
-              class="font_family other-state"
-              :style="{
-                color: styleMap[sliderState].thumbColor,
-                backgroundColor: styleMap[sliderState].trackBackground
-              }"
-              :class="[styleMap[sliderState].thumbIcon]"
-            ></span>
-          </div>
-        </div>
-      </div>
-    </div>
-  </el-dialog>
-</template>
-
-<style lang="scss" scoped>
-.content {
-  padding: 40px 0;
-  text-align: center;
-  & > p {
-    line-height: 21px;
-  }
-}
-
-.slider-container {
-  width: 320px;
-  margin: 16px auto 0;
-  text-align: center;
-  user-select: none;
-}
-.slider-track {
-  position: relative;
-  width: 100%;
-  height: 40px;
-  padding: 1px;
-  background: #868f9d;
-  border-radius: 6px;
-  line-height: 38px;
-  color: #fff;
-}
-.slider-thumb {
-  position: absolute;
-  top: 0px;
-  left: 10px;
-  width: 40px;
-  height: 40px;
-  background: #fff;
-  cursor: pointer;
-  border-radius: 6px;
-  border: 1px solid #868f9d;
-  .font_family {
-    font-size: 14px;
-    &.other-state {
-      height: 16px;
-      width: 16px;
-      padding: 1px;
-      border-radius: 50%;
-      font-size: 14px;
-    }
-  }
-}
-</style>
-
-<style lang="scss">
-.slide-verify-dialog {
-  .el-dialog__header {
-    display: none;
-  }
-  .el-dialog__body {
-    padding: 0;
-  }
-}
-</style>