refactor: update PWA registration and StatsCorner component for improved functionality

- Changed PWA registration type to 'autoUpdate' for immediate updates upon new version availability.
- Removed obsolete busuanzi elements and replaced the data fetching method with a new API call for site statistics.
- Simplified the UpdateToast component to trigger immediate updates without countdown, enhancing user experience.
This commit is contained in:
AdingApkgg
2026-02-01 13:58:23 +08:00
parent 201afc1493
commit 92e0be566f
3 changed files with 25 additions and 138 deletions

View File

@@ -27,12 +27,6 @@
</a> </a>
</div> </div>
<!-- 隐藏的 busuanzi 元素 busuanzi 脚本更新 -->
<div id="busuanzi_container_site_pv" style="display: none !important; visibility: hidden !important; position: absolute; left: -9999px;">
<span id="busuanzi_value_site_pv" />
<span id="busuanzi_value_site_uv" />
</div>
<!-- 左下角统计Vue 控制显示 --> <!-- 左下角统计Vue 控制显示 -->
<div <div
class="fixed bottom-4 left-4 z-40 transition-all duration-300" class="fixed bottom-4 left-4 z-40 transition-all duration-300"
@@ -62,8 +56,6 @@ import { useStatsStore } from '@/stores/stats'
const statsStore = useStatsStore() const statsStore = useStatsStore()
const showStats = ref(false) const showStats = ref(false)
let checkInterval: number | null = null
let observer: MutationObserver | null = null
// 计算属性 - 从 statsStore 获取状态 // 计算属性 - 从 statsStore 获取状态
const apiService = computed(() => statsStore.serviceStatuses.get('api')) const apiService = computed(() => statsStore.serviceStatuses.get('api'))
@@ -100,48 +92,28 @@ const statusIconClass = computed(() => {
return 'text-red-500' return 'text-red-500'
}) })
// 检查不蒜子数据是否加载 // 使用新的 busuanzi API 获取统计
function checkBusuanziData() { async function fetchBusuanziStats() {
const pvElement = document.getElementById('busuanzi_value_site_pv') try {
const uvElement = document.getElementById('busuanzi_value_site_uv') const res = await fetch('https://bsz.saop.cc/api', {
method: 'POST',
credentials: 'include',
headers: { 'x-bsz-referer': window.location.href },
})
if (pvElement && uvElement) { if (!res.ok) {return}
const pvValue = parseInt(pvElement.textContent || '0', 10)
const uvValue = parseInt(uvElement.textContent || '0', 10)
if (pvValue > 0 && uvValue > 0) { const { success, data } = await res.json()
// 更新 statsStore
statsStore.updateVisitorStats(pvValue, uvValue) if (success && data) {
statsStore.updateVisitorStats(data.site_pv, data.site_uv)
showStats.value = true showStats.value = true
if (checkInterval !== null) {
clearInterval(checkInterval)
checkInterval = null
}
if (observer) {
observer.disconnect()
observer = null
}
} }
} catch (error) {
console.warn('[Busuanzi] Failed to fetch stats:', error)
} }
} }
// 使用 MutationObserver 监听不蒜子元素的变化
function setupObserver() {
const pvElement = document.getElementById('busuanzi_value_site_pv')
const uvElement = document.getElementById('busuanzi_value_site_uv')
if (!pvElement || !uvElement) {return}
observer = new MutationObserver(() => {
checkBusuanziData()
})
observer.observe(pvElement, { childList: true, characterData: true, subtree: true })
observer.observe(uvElement, { childList: true, characterData: true, subtree: true })
}
// 监听 visitorStats 变化,自动显示统计 // 监听 visitorStats 变化,自动显示统计
watch(() => statsStore.visitorStats.pv, (pv) => { watch(() => statsStore.visitorStats.pv, (pv) => {
if (pv > 0) { if (pv > 0) {
@@ -153,39 +125,13 @@ onMounted(() => {
// 使用 statsStore 进行状态检测 // 使用 statsStore 进行状态检测
statsStore.startStatusCheck(30000) statsStore.startStatusCheck(30000)
// 不蒜子统计 // 获取不蒜子统计
setupObserver() void fetchBusuanziStats()
checkBusuanziData()
let attempts = 0
const maxAttempts = 40
checkInterval = window.setInterval(() => {
attempts++
checkBusuanziData()
if (showStats.value || attempts >= maxAttempts) {
if (checkInterval !== null) {
clearInterval(checkInterval)
checkInterval = null
}
}
}, 500)
}) })
onUnmounted(() => { onUnmounted(() => {
// 停止状态检测 // 停止状态检测
statsStore.stopStatusCheck() statsStore.stopStatusCheck()
if (checkInterval !== null) {
clearInterval(checkInterval)
checkInterval = null
}
if (observer) {
observer.disconnect()
observer = null
}
}) })
</script> </script>

View File

@@ -13,49 +13,24 @@
> >
<!-- 图标 --> <!-- 图标 -->
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center"> <div class="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center">
<RefreshCw :size="18" :class="{ 'animate-spin': isUpdating }" /> <RefreshCw :size="18" class="animate-spin" />
</div> </div>
<!-- 文字内容 --> <!-- 文字内容 -->
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<p class="font-semibold text-sm">发现新版本</p> <p class="font-semibold text-sm">发现新版本</p>
<p class="text-xs text-white/80 truncate"> <p class="text-xs text-white/80 truncate">正在更新...</p>
<template v-if="isUpdating">
正在更新...
</template>
<template v-else-if="countdown > 0">
{{ countdown }} 秒后自动更新...
</template>
<template v-else>
准备更新...
</template>
</p>
</div> </div>
<!-- 立即更新按钮 -->
<button
v-if="!isUpdating && countdown > 0"
class="flex-shrink-0 px-3 py-1.5 rounded-full bg-white/20 hover:bg-white/30 text-xs font-medium transition-colors"
@click="handleUpdate"
>
立即更新
</button>
</div> </div>
</Transition> </Transition>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch, onUnmounted } from 'vue' import { watch } from 'vue'
import { RefreshCw } from 'lucide-vue-next' import { RefreshCw } from 'lucide-vue-next'
import { useRegisterSW } from 'virtual:pwa-register/vue' import { useRegisterSW } from 'virtual:pwa-register/vue'
import { playNotification } from '@/composables/useSound' import { playNotification } from '@/composables/useSound'
const UPDATE_COUNTDOWN = 5 // 秒
const countdown = ref(0)
const isUpdating = ref(false)
let countdownTimer: number | null = null
const { const {
needRefresh, needRefresh,
updateServiceWorker, updateServiceWorker,
@@ -75,46 +50,12 @@ const {
}, },
}) })
// 当有更新时启动倒计时 // 当有更新时立即更新
watch(needRefresh, (need) => { watch(needRefresh, (need) => {
if (need) { if (need) {
playNotification() playNotification()
startCountdown() // 立即更新 SW 并刷新页面
} void updateServiceWorker(true)
})
function startCountdown() {
countdown.value = UPDATE_COUNTDOWN
if (countdownTimer) {
clearInterval(countdownTimer)
}
countdownTimer = window.setInterval(() => {
countdown.value--
if (countdown.value <= 0) {
if (countdownTimer) {
clearInterval(countdownTimer)
countdownTimer = null
}
handleUpdate()
}
}, 1000)
}
function handleUpdate() {
if (countdownTimer) {
clearInterval(countdownTimer)
countdownTimer = null
}
isUpdating.value = true
// 更新 SW 并刷新页面
void updateServiceWorker(true)
}
onUnmounted(() => {
if (countdownTimer) {
clearInterval(countdownTimer)
} }
}) })
</script> </script>

View File

@@ -28,7 +28,7 @@ export default defineConfig({
tailwindcss(), tailwindcss(),
// PWA 配置 // PWA 配置
VitePWA({ VitePWA({
registerType: 'prompt', // 提示用户更新 registerType: 'autoUpdate', // 收到新版本立即更新
includeAssets: ['logo.svg', 'robots.txt'], includeAssets: ['logo.svg', 'robots.txt'],
manifest: { manifest: {
name: 'SearchGal - Galgame 聚合搜索', name: 'SearchGal - Galgame 聚合搜索',