0.0.7 #11
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import LeftArrowIcon from './assets/icons/leftarrow.vue'
 | 
			
		|||
import CorgIcon from './assets/icons/corg.vue'
 | 
			
		||||
import { watch } from 'vue'
 | 
			
		||||
 | 
			
		||||
import Updated from './components/updated.vue'
 | 
			
		||||
import UpdatePopup from './components/UpdatePopup.vue'
 | 
			
		||||
 | 
			
		||||
const presentPreferencePanel = ref(false)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ watch(() => presentPreferencePanel, (value) => {
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
	<Updated />
 | 
			
		||||
	<UpdatePopup />
 | 
			
		||||
 | 
			
		||||
	<div class="w-screen h-screen overflow-hidden bg-[#191919]">
 | 
			
		||||
		<div class="flex flex-col w-full h-full overflow-y-auto">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,26 +1,42 @@
 | 
			
		|||
<script lang="ts" setup>
 | 
			
		||||
import XIcon from '../assets/icons/x.vue'
 | 
			
		||||
import { computed } from 'vue'
 | 
			
		||||
import { ref, onMounted } from 'vue'
 | 
			
		||||
import { useUpdatePopup } from '../stores/useUpdatePopup'
 | 
			
		||||
 | 
			
		||||
const version = computed(() => {
 | 
			
		||||
	try {
 | 
			
		||||
		// 如果你的构建工具支持,可以直接导入
 | 
			
		||||
		return chrome?.runtime?.getManifest?.()?.version || 'unknown'
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
		return 'unknown'
 | 
			
		||||
const updatePopupStore = useUpdatePopup()
 | 
			
		||||
const showPopup = ref(false)
 | 
			
		||||
 | 
			
		||||
const version = updatePopupStore.getCurrentVersion()
 | 
			
		||||
 | 
			
		||||
// 关闭弹窗的处理函数
 | 
			
		||||
const handleDismiss = async () => {
 | 
			
		||||
	showPopup.value = false
 | 
			
		||||
	// 标记弹窗已显示,避免再次显示
 | 
			
		||||
	await updatePopupStore.markUpdatePopupShown()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 组件挂载时检查是否需要显示弹窗
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
	// 等待 store 初始化完成
 | 
			
		||||
	if (!updatePopupStore.isLoaded) {
 | 
			
		||||
		await updatePopupStore.initializeUpdatePopup()
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// 检查是否需要显示更新弹窗
 | 
			
		||||
	const shouldShow = await updatePopupStore.shouldShowUpdatePopup()
 | 
			
		||||
	showPopup.value = shouldShow
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="absolute top-0 left-0 w-screen h-screen bg-neutral-700/30 flex justify-center items-center select-none">
 | 
			
		||||
	<div v-if="showPopup" class="absolute top-0 left-0 w-screen h-screen bg-neutral-700/30 flex justify-center items-center select-none z-50">
 | 
			
		||||
		<div class="bg-neutral-900/80 shadow-[0_0_16px_0_rgba(0,0,0,0.5)] backdrop-blur-2xl border border-[#ffffff39] rounded-lg w-[60rem] h-3/4 relative overflow-y-auto text-white">
 | 
			
		||||
			<div
 | 
			
		||||
				class="flex justify-between items-center p-8 sticky top-0 bg-gradient-to-b from-neutral-900 to-neutral-900/0 z-10">
 | 
			
		||||
				<div class="text-white text-2xl font-semibold">MSR Mod 已更新至 {{version}}</div>
 | 
			
		||||
				<button
 | 
			
		||||
					class="text-white w-9 h-9 bg-neutral-800/80 border border-[#ffffff39] rounded-full text-center backdrop-blur-3xl flex justify-center items-center transition-all duration-200 hover:bg-neutral-700/80"
 | 
			
		||||
					@click="$emit('dismiss')">
 | 
			
		||||
					@click="handleDismiss">
 | 
			
		||||
					<XIcon :size="4" />
 | 
			
		||||
				</button>
 | 
			
		||||
			</div>
 | 
			
		||||
							
								
								
									
										204
									
								
								src/stores/useUpdatePopup.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								src/stores/useUpdatePopup.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,204 @@
 | 
			
		|||
import { defineStore } from "pinia"
 | 
			
		||||
import { ref } from "vue"
 | 
			
		||||
 | 
			
		||||
// 声明全局类型
 | 
			
		||||
declare global {
 | 
			
		||||
	interface Window {
 | 
			
		||||
		browser?: any
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useUpdatePopup = defineStore('updatePopup', () => {
 | 
			
		||||
	const isLoaded = ref(false)
 | 
			
		||||
	const storageType = ref<'chrome' | 'localStorage' | 'memory'>('chrome')
 | 
			
		||||
 | 
			
		||||
	// 获取当前版本号
 | 
			
		||||
	const getCurrentVersion = (): string => {
 | 
			
		||||
		try {
 | 
			
		||||
			// 尝试从 Chrome 扩展 API 获取版本号
 | 
			
		||||
			return chrome?.runtime?.getManifest?.()?.version || 'unknown'
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			return 'unknown'
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 检测可用的 API
 | 
			
		||||
	const detectAvailableAPIs = () => {
 | 
			
		||||
		// 检查原生 chrome API
 | 
			
		||||
		try {
 | 
			
		||||
			if (typeof chrome !== 'undefined' && chrome.storage && chrome.storage.sync) {
 | 
			
		||||
				storageType.value = 'chrome'
 | 
			
		||||
				return 'chrome'
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			// Silent fail
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 检查 window.chrome
 | 
			
		||||
		try {
 | 
			
		||||
			if (window.chrome && window.chrome.storage && window.chrome.storage.sync) {
 | 
			
		||||
				storageType.value = 'chrome'
 | 
			
		||||
				return 'chrome'
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			// Silent fail
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 检查 localStorage
 | 
			
		||||
		try {
 | 
			
		||||
			if (typeof localStorage !== 'undefined') {
 | 
			
		||||
				localStorage.setItem('msr_test', 'test')
 | 
			
		||||
				localStorage.removeItem('msr_test')
 | 
			
		||||
				storageType.value = 'localStorage'
 | 
			
		||||
				return 'localStorage'
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			// Silent fail
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 都不可用,使用内存存储
 | 
			
		||||
		storageType.value = 'memory'
 | 
			
		||||
		return 'memory'
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 通用的获取存储值函数
 | 
			
		||||
	const getStoredValue = async (key: string, defaultValue: any) => {
 | 
			
		||||
		const type = detectAvailableAPIs()
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			switch (type) {
 | 
			
		||||
				case 'chrome':
 | 
			
		||||
					return await new Promise((resolve) => {
 | 
			
		||||
						const api = chrome?.storage?.sync || window.chrome?.storage?.sync
 | 
			
		||||
						if (api) {
 | 
			
		||||
							api.get({ [key]: defaultValue }, (result) => {
 | 
			
		||||
								if (chrome.runtime.lastError) {
 | 
			
		||||
									resolve(defaultValue)
 | 
			
		||||
								} else {
 | 
			
		||||
									resolve(result[key])
 | 
			
		||||
								}
 | 
			
		||||
							})
 | 
			
		||||
						} else {
 | 
			
		||||
							resolve(defaultValue)
 | 
			
		||||
						}
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
				case 'localStorage':
 | 
			
		||||
					const stored = localStorage.getItem(`msr_${key}`)
 | 
			
		||||
					const value = stored ? JSON.parse(stored) : defaultValue
 | 
			
		||||
					return value
 | 
			
		||||
 | 
			
		||||
				case 'memory':
 | 
			
		||||
				default:
 | 
			
		||||
					return defaultValue
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			return defaultValue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 通用的设置存储值函数
 | 
			
		||||
	const setStoredValue = async (key: string, value: any) => {
 | 
			
		||||
		const type = storageType.value
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			switch (type) {
 | 
			
		||||
				case 'chrome':
 | 
			
		||||
					return await new Promise<void>((resolve, reject) => {
 | 
			
		||||
						const api = chrome?.storage?.sync || window.chrome?.storage?.sync
 | 
			
		||||
						if (api) {
 | 
			
		||||
							api.set({ [key]: value }, () => {
 | 
			
		||||
								if (chrome.runtime.lastError) {
 | 
			
		||||
									reject(new Error(chrome.runtime.lastError.message))
 | 
			
		||||
								} else {
 | 
			
		||||
									resolve()
 | 
			
		||||
								}
 | 
			
		||||
							})
 | 
			
		||||
						} else {
 | 
			
		||||
							reject(new Error('Chrome storage API 不可用'))
 | 
			
		||||
						}
 | 
			
		||||
					})
 | 
			
		||||
 | 
			
		||||
				case 'localStorage':
 | 
			
		||||
					localStorage.setItem(`msr_${key}`, JSON.stringify(value))
 | 
			
		||||
					break
 | 
			
		||||
 | 
			
		||||
				case 'memory':
 | 
			
		||||
					// 内存存储(不持久化)
 | 
			
		||||
					break
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			throw error
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 检查是否需要显示更新弹窗
 | 
			
		||||
	const shouldShowUpdatePopup = async (): Promise<boolean> => {
 | 
			
		||||
		try {
 | 
			
		||||
			const currentVersion = getCurrentVersion()
 | 
			
		||||
			
 | 
			
		||||
			// 如果无法获取当前版本,不显示弹窗
 | 
			
		||||
			if (currentVersion === 'unknown') {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 获取上次显示弹窗的版本号
 | 
			
		||||
			const lastShownVersion = await getStoredValue('lastUpdatePopupVersion', '')
 | 
			
		||||
 | 
			
		||||
			// 如果版本号不同,需要显示弹窗并更新存储的版本号
 | 
			
		||||
			if (lastShownVersion !== currentVersion) {
 | 
			
		||||
				await setStoredValue('lastUpdatePopupVersion', currentVersion)
 | 
			
		||||
				return true
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error('检查更新弹窗状态失败:', error)
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 标记已显示过更新弹窗(手动关闭时调用)
 | 
			
		||||
	const markUpdatePopupShown = async () => {
 | 
			
		||||
		try {
 | 
			
		||||
			const currentVersion = getCurrentVersion()
 | 
			
		||||
			if (currentVersion !== 'unknown') {
 | 
			
		||||
				await setStoredValue('lastUpdatePopupVersion', currentVersion)
 | 
			
		||||
			}
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error('标记更新弹窗已显示失败:', error)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 获取当前存储的版本号
 | 
			
		||||
	const getLastShownVersion = async (): Promise<string> => {
 | 
			
		||||
		return await getStoredValue('lastUpdatePopupVersion', '')
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 异步初始化函数
 | 
			
		||||
	const initializeUpdatePopup = async () => {
 | 
			
		||||
		try {
 | 
			
		||||
			// 初始化存储类型检测
 | 
			
		||||
			detectAvailableAPIs()
 | 
			
		||||
			isLoaded.value = true
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error('初始化更新弹窗 store 失败:', error)
 | 
			
		||||
			isLoaded.value = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 立即初始化
 | 
			
		||||
	initializeUpdatePopup()
 | 
			
		||||
 | 
			
		||||
	return {
 | 
			
		||||
		isLoaded,
 | 
			
		||||
		storageType,
 | 
			
		||||
		getCurrentVersion,
 | 
			
		||||
		shouldShowUpdatePopup,
 | 
			
		||||
		markUpdatePopupShown,
 | 
			
		||||
		getLastShownVersion,
 | 
			
		||||
		initializeUpdatePopup,
 | 
			
		||||
		getStoredValue,
 | 
			
		||||
		setStoredValue
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user