f
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
<router-view />
|
||||
<van-popup v-model:show="showPopup" round @click-overlay="onClickOverlay">
|
||||
<div class="popup-content text-center p-8">
|
||||
<div v-if="currentNotify?.title" class="text-lg font-bold mb-4">{{ currentNotify.title }}</div>
|
||||
<div v-html="currentNotify?.content"></div>
|
||||
<div class="flex justify-center">
|
||||
<van-button type="primary" @click="showPopup = false" class="w-24">关闭</van-button>
|
||||
<van-button type="primary" @click="onClosePopup" class="w-24">关闭</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
@@ -18,12 +19,16 @@ import { useRoute } from 'vue-router'
|
||||
const showPopup = ref(false)
|
||||
const notify = ref([])
|
||||
const currentNotify = ref(null)
|
||||
const pendingNotifyQueue = ref([])
|
||||
const shownNotificationKeys = ref(new Set())
|
||||
const SESSION_KEY = 'qnc_webview_shown_notifications'
|
||||
|
||||
// 获取当前页面路径
|
||||
const route = useRoute()
|
||||
|
||||
// 获取通知数据
|
||||
onMounted(() => {
|
||||
loadShownNotificationKeys()
|
||||
getGlobalNotify()
|
||||
})
|
||||
|
||||
@@ -33,60 +38,128 @@ const getGlobalNotify = async () => {
|
||||
.get()
|
||||
.json()
|
||||
|
||||
if (data.value && !error.value) {
|
||||
if (data.value !== 200) {
|
||||
notify.value = data.value.data.notifications
|
||||
checkNotification() // 在获取数据后检查通知
|
||||
}
|
||||
if (data.value && !error.value && data.value.code === 200 && data.value.data) {
|
||||
notify.value = data.value.data.notifications ?? []
|
||||
checkNotification()
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前时间是否在通知的时间范围内
|
||||
/** 与后台「展示时间」一致:未配置或起止相同视为「全天」,任意时刻都算在范围内 */
|
||||
const isWithinTimeRange = (startTime, endTime) => {
|
||||
const s = (startTime || '').trim()
|
||||
const e = (endTime || '').trim()
|
||||
if (!s && !e) return true
|
||||
if (s === e) return true
|
||||
|
||||
const now = new Date()
|
||||
|
||||
// 获取当前时间的小时和分钟
|
||||
const currentMinutes = now.getHours() * 60 + now.getMinutes()
|
||||
|
||||
// 将 startTime 和 endTime 转换为分钟数
|
||||
const startParts = startTime.split(':').map(Number)
|
||||
const endParts = endTime.split(':').map(Number)
|
||||
const startMinutes = startParts[0] * 60 + startParts[1]
|
||||
const endMinutes = endParts[0] * 60 + endParts[1]
|
||||
|
||||
// 如果 endTime 小于 startTime,表示跨越了午夜
|
||||
if (endMinutes < startMinutes) {
|
||||
// 判断当前时间是否在 [startTime, 23:59:59] 或 [00:00:00, endTime] 之间
|
||||
return currentMinutes >= startMinutes || currentMinutes < endMinutes
|
||||
const toMinutes = (t) => {
|
||||
const parts = t.split(':').map(Number)
|
||||
const h = parts[0] ?? 0
|
||||
const m = parts[1] ?? 0
|
||||
return h * 60 + m
|
||||
}
|
||||
const startMinutes = toMinutes(s)
|
||||
const endMinutes = toMinutes(e)
|
||||
|
||||
// 普通情况,直接判断时间是否在范围内
|
||||
if (endMinutes < startMinutes) {
|
||||
return currentMinutes >= startMinutes || currentMinutes <= endMinutes
|
||||
}
|
||||
return currentMinutes >= startMinutes && currentMinutes <= endMinutes
|
||||
}
|
||||
|
||||
/** 当前路由是否与通知配置的页面一致 */
|
||||
const matchesNotificationPage = (page) => {
|
||||
const p = (page || '').trim()
|
||||
const cur = route.path || ''
|
||||
if (p === cur) return true
|
||||
if (p === '/' && (cur === '/' || cur === '')) return true
|
||||
if (cur.startsWith('/app/') && p === cur.replace('/app/', '/')) return true
|
||||
if (p.startsWith('/app/') && cur === p.replace('/app/', '/')) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const buildNotificationKey = (notification) => {
|
||||
return [
|
||||
notification.title ?? '',
|
||||
notification.content ?? '',
|
||||
notification.notificationPage ?? '',
|
||||
notification.startDate ?? '',
|
||||
notification.endDate ?? '',
|
||||
notification.startTime ?? '',
|
||||
notification.endTime ?? ''
|
||||
].join('|')
|
||||
}
|
||||
|
||||
const loadShownNotificationKeys = () => {
|
||||
const raw = sessionStorage.getItem(SESSION_KEY)
|
||||
if (!raw) return
|
||||
try {
|
||||
const parsed = JSON.parse(raw)
|
||||
if (Array.isArray(parsed)) {
|
||||
shownNotificationKeys.value = new Set(parsed)
|
||||
}
|
||||
} catch {
|
||||
shownNotificationKeys.value = new Set()
|
||||
}
|
||||
}
|
||||
|
||||
const saveShownNotificationKeys = () => {
|
||||
sessionStorage.setItem(SESSION_KEY, JSON.stringify([...shownNotificationKeys.value]))
|
||||
}
|
||||
|
||||
const hasShownNotification = (notification) => {
|
||||
return shownNotificationKeys.value.has(buildNotificationKey(notification))
|
||||
}
|
||||
|
||||
const markNotificationShown = (notification) => {
|
||||
shownNotificationKeys.value.add(buildNotificationKey(notification))
|
||||
saveShownNotificationKeys()
|
||||
}
|
||||
|
||||
const showNextNotification = () => {
|
||||
const next = pendingNotifyQueue.value.shift()
|
||||
if (!next) {
|
||||
currentNotify.value = null
|
||||
showPopup.value = false
|
||||
return
|
||||
}
|
||||
currentNotify.value = next
|
||||
showPopup.value = true
|
||||
markNotificationShown(next)
|
||||
}
|
||||
|
||||
// 检查通知并更新showPopup
|
||||
const checkNotification = () => {
|
||||
// 遍历通知数组,找到第一个符合条件的通知
|
||||
for (let notification of notify.value) {
|
||||
// 判断时间是否符合当前时间
|
||||
const isTimeValid = isWithinTimeRange(notification.startTime, notification.endTime)
|
||||
// 判断页面是否符合
|
||||
if (showPopup.value) return
|
||||
|
||||
if (isTimeValid && notification.notificationPage === route.path) {
|
||||
currentNotify.value = notification
|
||||
showPopup.value = true
|
||||
break // 只显示第一个符合的通知
|
||||
const matchedNotifications = []
|
||||
for (let notification of notify.value) {
|
||||
const isTimeValid = isWithinTimeRange(notification.startTime, notification.endTime)
|
||||
const isPageValid = matchesNotificationPage(notification.notificationPage)
|
||||
const isShown = hasShownNotification(notification)
|
||||
|
||||
if (isTimeValid && isPageValid && !isShown) {
|
||||
matchedNotifications.push(notification)
|
||||
}
|
||||
}
|
||||
|
||||
pendingNotifyQueue.value = matchedNotifications
|
||||
showNextNotification()
|
||||
}
|
||||
|
||||
// 监听路由变化
|
||||
watch(() => route.path, () => {
|
||||
checkNotification() // 每次路由变化时重新判断通知
|
||||
checkNotification()
|
||||
})
|
||||
|
||||
// 关闭弹窗
|
||||
const onClosePopup = () => {
|
||||
showNextNotification()
|
||||
}
|
||||
|
||||
const onClickOverlay = () => {
|
||||
showPopup.value = false
|
||||
onClosePopup()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user