// client/src/stores/pwa.js — PWA 状态:更新提示 / 安装提示 / 离线 import { defineStore } from 'pinia'; import { ref, computed } from 'vue'; export const usePwaStore = defineStore('pwa', () => { /** true = 已有新版本 SW 等激活,需要刷新 */ const needRefresh = ref(false); /** true = 资源已缓存完,可离线用 */ const offlineReady = ref(false); /** 浏览器/桌面触发安装的事件(Android/Desktop Chrome) */ const installPromptEvent = ref(null); /** 已安装(standalone 模式运行) */ const isInstalled = computed(() => { if (typeof window === 'undefined') return false; return ( window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true // iOS Safari ); }); /** iOS 设备 + Safari + 未安装 → 引导走"分享 → 添加到主屏幕" */ const isIosSafari = computed(() => { if (typeof window === 'undefined') return false; const ua = window.navigator.userAgent; return /iPad|iPhone|iPod/.test(ua) && /Safari/.test(ua) && !/CriOS|FxiOS|EdgiOS/.test(ua); }); let updateFn = null; function bindRegisterSw(registerFn) { updateFn = registerFn; } function triggerNeedRefresh() { needRefresh.value = true; } function triggerOfflineReady() { offlineReady.value = true; // 5s 后自动收起 setTimeout(() => (offlineReady.value = false), 5000); } async function applyUpdate() { if (updateFn) { await updateFn(true); needRefresh.value = false; } else { window.location.reload(); } } function dismissNeedRefresh() { needRefresh.value = false; } function dismissOfflineReady() { offlineReady.value = false; } async function promptInstall() { const e = installPromptEvent.value; if (!e) return false; e.prompt(); const choice = await e.userChoice; installPromptEvent.value = null; return choice.outcome === 'accepted'; } function captureInstallPrompt(e) { e.preventDefault(); installPromptEvent.value = e; } // 全局监听 beforeinstallprompt if (typeof window !== 'undefined') { window.addEventListener('beforeinstallprompt', captureInstallPrompt); window.addEventListener('appinstalled', () => { installPromptEvent.value = null; }); } return { needRefresh, offlineReady, installPromptEvent, isInstalled, isIosSafari, bindRegisterSw, triggerNeedRefresh, triggerOfflineReady, applyUpdate, dismissNeedRefresh, dismissOfflineReady, promptInstall, }; });