mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-31 19:08:13 +08:00
重构PWA状态管理
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { ComputedRef, Ref } from 'vue'
|
||||
import { useTabStateRestore } from '@/composables/useStateRestore'
|
||||
|
||||
// 动态标签页相关类型
|
||||
interface DynamicHeaderTabButton {
|
||||
@@ -38,7 +39,17 @@ export function useDynamicHeaderTab() {
|
||||
items: DynamicHeaderTabItem[] | ComputedRef<DynamicHeaderTabItem[]> | Ref<DynamicHeaderTabItem[]>
|
||||
modelValue: Ref<string>
|
||||
appendButtons?: DynamicHeaderTabButton[]
|
||||
enableStateRestore?: boolean
|
||||
}) => {
|
||||
// 集成PWA状态恢复功能
|
||||
const enablePWARestore = config.enableStateRestore !== false // 默认启用
|
||||
const pwaTabState = enablePWARestore ? useTabStateRestore(config.modelValue.value) : null
|
||||
|
||||
// 如果启用了PWA状态恢复,先尝试恢复状态
|
||||
if (pwaTabState && pwaTabState.activeTab.value) {
|
||||
config.modelValue.value = pwaTabState.activeTab.value
|
||||
}
|
||||
|
||||
const tabConfig: DynamicHeaderTabConfig = {
|
||||
items: Array.isArray(config.items) ? config.items : config.items.value,
|
||||
modelValue: config.modelValue.value,
|
||||
@@ -46,12 +57,34 @@ export function useDynamicHeaderTab() {
|
||||
routePath: route.path,
|
||||
onUpdateModelValue: (value: string) => {
|
||||
config.modelValue.value = value
|
||||
// 同步到PWA状态
|
||||
if (pwaTabState && value) {
|
||||
pwaTabState.activeTab.value = value
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// 如果启用了PWA状态恢复,监听PWA状态变化并同步到modelValue
|
||||
if (pwaTabState) {
|
||||
watch(pwaTabState.activeTab, newTab => {
|
||||
if (newTab && newTab !== config.modelValue.value) {
|
||||
config.modelValue.value = newTab
|
||||
// 更新tabConfig并重新注册
|
||||
tabConfig.modelValue = newTab
|
||||
if (registerDynamicHeaderTab) {
|
||||
registerDynamicHeaderTab(tabConfig)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 监听modelValue变化并更新配置
|
||||
watch(config.modelValue, newValue => {
|
||||
tabConfig.modelValue = newValue
|
||||
// 同步到PWA状态
|
||||
if (pwaTabState && newValue) {
|
||||
pwaTabState.activeTab.value = newValue
|
||||
}
|
||||
// 重新注册以更新值
|
||||
if (registerDynamicHeaderTab) {
|
||||
registerDynamicHeaderTab(tabConfig)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import { checkPWAStatus, isPWADisplayMode } from '@/@core/utils/navigator'
|
||||
import type { PWAState } from '@/utils/pwaStateManager'
|
||||
|
||||
// 全局PWA状态,确保只初始化一次
|
||||
const globalPwaStatus = ref<{
|
||||
@@ -72,142 +71,6 @@ export function usePWA() {
|
||||
appMode,
|
||||
pwaStatus,
|
||||
loading: globalLoading,
|
||||
// 保留手动初始化方法以防需要
|
||||
initializePWA: initializePWAGlobally,
|
||||
}
|
||||
}
|
||||
|
||||
// PWA状态管理 composable
|
||||
export function usePWAState() {
|
||||
const isStateRestored = ref(false)
|
||||
const stateRestoreCount = ref(0)
|
||||
const lastRestoredState = ref<PWAState | null>(null)
|
||||
const isPWAMode = ref(false)
|
||||
|
||||
// 检查PWA模式 - 使用统一的检测方式
|
||||
const checkPWAMode = async () => {
|
||||
// 确保全局PWA状态已初始化
|
||||
if (globalPwaStatus.value === null) {
|
||||
await initializePWAGlobally()
|
||||
}
|
||||
|
||||
// 获取PWA状态
|
||||
const status = globalPwaStatus.value
|
||||
if (status) {
|
||||
isPWAMode.value = status.isPWAEnvironment
|
||||
} else {
|
||||
// 如果状态获取失败,使用同步检测作为后备
|
||||
isPWAMode.value = isPWADisplayMode()
|
||||
}
|
||||
}
|
||||
|
||||
// 保存当前状态
|
||||
const saveCurrentState = async () => {
|
||||
if (window.pwaStateController) {
|
||||
await window.pwaStateController.saveCurrentState()
|
||||
}
|
||||
}
|
||||
|
||||
// 手动触发状态恢复检查
|
||||
const checkStateRestore = async () => {
|
||||
if (window.pwaStateController) {
|
||||
// 静默检查
|
||||
}
|
||||
}
|
||||
|
||||
// 监听状态恢复事件
|
||||
const handleStateRestored = (event: Event) => {
|
||||
const customEvent = event as CustomEvent<{ state: PWAState }>
|
||||
isStateRestored.value = true
|
||||
stateRestoreCount.value++
|
||||
lastRestoredState.value = customEvent.detail.state
|
||||
}
|
||||
|
||||
// 重置状态恢复标志
|
||||
const resetStateRestored = () => {
|
||||
isStateRestored.value = false
|
||||
lastRestoredState.value = null
|
||||
}
|
||||
|
||||
// 检查状态管理器是否可用
|
||||
const isStateManagerAvailable = () => {
|
||||
return !!window.pwaStateController
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkPWAMode()
|
||||
|
||||
// 监听状态恢复事件
|
||||
window.addEventListener('pwaStateRestored', handleStateRestored)
|
||||
|
||||
// 监听PWA模式变化
|
||||
const mediaQuery = window.matchMedia('(display-mode: standalone)')
|
||||
const handleDisplayModeChange = (e: MediaQueryListEvent) => {
|
||||
isPWAMode.value = e.matches
|
||||
// 同步更新全局PWA状态
|
||||
if (globalPwaStatus.value) {
|
||||
globalPwaStatus.value.isStandaloneMode = e.matches
|
||||
globalPwaStatus.value.isPWAEnvironment = globalPwaStatus.value.hasPWAFeatures || e.matches
|
||||
globalPwaStatus.value.isFullPWA = globalPwaStatus.value.hasPWAFeatures && e.matches
|
||||
}
|
||||
}
|
||||
|
||||
if (mediaQuery.addEventListener) {
|
||||
mediaQuery.addEventListener('change', handleDisplayModeChange)
|
||||
} else {
|
||||
mediaQuery.addListener(handleDisplayModeChange)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (mediaQuery.removeEventListener) {
|
||||
mediaQuery.removeEventListener('change', handleDisplayModeChange)
|
||||
} else {
|
||||
mediaQuery.removeListener(handleDisplayModeChange)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('pwaStateRestored', handleStateRestored)
|
||||
})
|
||||
|
||||
return {
|
||||
// 响应式状态
|
||||
isPWAMode,
|
||||
isStateRestored,
|
||||
stateRestoreCount,
|
||||
lastRestoredState,
|
||||
|
||||
// 方法
|
||||
saveCurrentState,
|
||||
checkStateRestore,
|
||||
resetStateRestored,
|
||||
isStateManagerAvailable,
|
||||
checkPWAMode,
|
||||
}
|
||||
}
|
||||
|
||||
// 全局PWA状态管理器
|
||||
export function useGlobalPWAState() {
|
||||
// 检查是否在PWA环境中 - 使用统一的检测方式
|
||||
const isPWAEnvironment = () => {
|
||||
return globalPwaStatus.value?.isPWAEnvironment ?? isPWADisplayMode()
|
||||
}
|
||||
|
||||
// 获取存储的状态
|
||||
const getStoredState = () => {
|
||||
return localStorage.getItem('mp-pwa-app-state')
|
||||
}
|
||||
|
||||
// 清除存储的状态
|
||||
const clearStoredState = () => {
|
||||
localStorage.removeItem('mp-pwa-app-state')
|
||||
sessionStorage.removeItem('mp-pwa-session-state')
|
||||
}
|
||||
|
||||
return {
|
||||
isPWAEnvironment,
|
||||
getStoredState,
|
||||
clearStoredState,
|
||||
}
|
||||
}
|
||||
|
||||
192
src/composables/useStateRestore.ts
Normal file
192
src/composables/useStateRestore.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* PWA状态恢复组合式API
|
||||
* 提供2个专门的hooks:路由、标签页
|
||||
*/
|
||||
|
||||
import { ref, onMounted, onUnmounted, watch, inject } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { StateRestore } from '@/plugins/stateRestore'
|
||||
|
||||
// =============================================================================
|
||||
// 1. 动态标签页状态恢复
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* 动态标签页状态恢复Hook
|
||||
* 自动保存和恢复v-tabs的当前激活标签
|
||||
*/
|
||||
export function useTabStateRestore(defaultTab?: string) {
|
||||
const route = useRoute()
|
||||
const stateRestore = inject<StateRestore>('stateRestore')
|
||||
|
||||
const activeTab = ref<string>(defaultTab || '')
|
||||
|
||||
// 保存标签页状态
|
||||
const saveTabState = (tab: string) => {
|
||||
if (stateRestore && tab) {
|
||||
stateRestore.tab.saveTabState(route.path, tab)
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复标签页状态
|
||||
const restoreTabState = () => {
|
||||
if (stateRestore) {
|
||||
const savedTab = stateRestore.tab.getTabState(route.path)
|
||||
if (savedTab) {
|
||||
activeTab.value = savedTab
|
||||
console.log(`恢复标签页状态: ${route.path} -> ${savedTab}`)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 监听activeTab变化,自动保存
|
||||
watch(activeTab, newTab => {
|
||||
if (newTab) {
|
||||
saveTabState(newTab)
|
||||
}
|
||||
})
|
||||
|
||||
// 组件挂载时恢复状态
|
||||
onMounted(() => {
|
||||
// 先尝试恢复,如果没有保存的状态则使用默认值
|
||||
if (!restoreTabState() && defaultTab) {
|
||||
activeTab.value = defaultTab
|
||||
}
|
||||
})
|
||||
|
||||
// 监听全局恢复事件
|
||||
const handleRestore = () => {
|
||||
restoreTabState()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('pwa-state-restore', handleRestore)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('pwa-state-restore', handleRestore)
|
||||
})
|
||||
|
||||
return {
|
||||
activeTab,
|
||||
saveTabState,
|
||||
restoreTabState,
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 2. 路由状态恢复
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* 路由状态恢复Hook
|
||||
* 获取路由恢复信息,主要用于调试和监控
|
||||
*/
|
||||
export function useRouteStateRestore() {
|
||||
const stateRestore = inject<StateRestore>('stateRestore')
|
||||
|
||||
const lastRestoredRoute = ref<any>(null)
|
||||
|
||||
// 获取上次保存的路由
|
||||
const getLastSavedRoute = () => {
|
||||
if (stateRestore) {
|
||||
return stateRestore.route.restoreRoute()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 手动保存当前路由
|
||||
const saveCurrentRoute = () => {
|
||||
if (stateRestore) {
|
||||
stateRestore.route.saveCurrentRoute()
|
||||
}
|
||||
}
|
||||
|
||||
// 清除路由状态
|
||||
const clearRouteState = () => {
|
||||
if (stateRestore) {
|
||||
stateRestore.route.clearRoute()
|
||||
}
|
||||
}
|
||||
|
||||
// 监听全局恢复事件
|
||||
const handleRestore = (event: Event) => {
|
||||
const customEvent = event as CustomEvent
|
||||
if (customEvent.detail?.route) {
|
||||
lastRestoredRoute.value = customEvent.detail.route
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('pwa-state-restore', handleRestore)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('pwa-state-restore', handleRestore)
|
||||
})
|
||||
|
||||
return {
|
||||
lastRestoredRoute,
|
||||
getLastSavedRoute,
|
||||
saveCurrentRoute,
|
||||
clearRouteState,
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 3. 全量状态恢复Hook
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* 全量状态恢复Hook
|
||||
* 用于清理所有状态或获取统计信息
|
||||
*/
|
||||
export function useStateRestore() {
|
||||
const stateRestore = inject<StateRestore>('stateRestore')
|
||||
|
||||
// 清除所有状态
|
||||
const clearAllStates = () => {
|
||||
if (stateRestore) {
|
||||
stateRestore.clearAllStates()
|
||||
console.log('已清除所有PWA状态')
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态统计
|
||||
const getStateStats = () => {
|
||||
if (!stateRestore) return null
|
||||
|
||||
return {
|
||||
hasRoute: !!stateRestore.route.restoreRoute(),
|
||||
// 可以扩展更多统计信息
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
clearAllStates,
|
||||
getStateStats,
|
||||
stateRestore,
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 4. 快捷Hook组合
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* 页面级状态恢复Hook
|
||||
* 组合路由和标签页状态恢复功能,适用于有标签页的页面
|
||||
*/
|
||||
export function usePageStateRestore(defaultTab?: string) {
|
||||
const tabs = defaultTab ? useTabStateRestore(defaultTab) : null
|
||||
const route = useRouteStateRestore()
|
||||
const global = useStateRestore()
|
||||
|
||||
return {
|
||||
tabs,
|
||||
route,
|
||||
global,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user