Selaa lähdekoodia

feat: 版本校验刷新功能

lanceJiang 9 kuukautta sitten
vanhempi
sitoutus
7b9e050414

+ 3 - 1
src/lang/lance-element/en.ts

@@ -160,7 +160,9 @@ export default {
 				isWatermark: 'Turn On Watermark',
 				watermarkText: 'Watermark Copy',
 				reset: 'Reset The Current Configuration'
-			}
+			},
+			checkUpdatesTitle: 'New Version Available',
+			checkUpdatesDescription: 'Click to Refresh and get the latest version"'
 		}
 	}
 }

+ 3 - 1
src/lang/lance-element/zh-cn.ts

@@ -158,7 +158,9 @@ export default {
 				isWatermark: '开启水印',
 				watermarkText: '水印文案',
 				reset: '重置当前配置'
-			}
+			},
+			checkUpdatesTitle: '新版本可用',
+			checkUpdatesDescription: '点击刷新以获取最新版本'
 		}
 	}
 }

+ 124 - 0
src/layout/components/CheckUpdates.vue

@@ -0,0 +1,124 @@
+<template>
+	<slot></slot>
+</template>
+<script setup lang="tsx">
+import { onMounted, onUnmounted, ref } from 'vue'
+import {ElButton, ElNotification} from 'element-plus'
+import { t } from '@/utils'
+const props = defineProps({
+	checkUpdatesInterval: {
+		type: Number,
+		default: 5
+	}
+})
+const lastVersionTag = ref('')
+let isCheckingUpdates = false
+let timer: ReturnType<typeof setInterval>
+async function getVersionTag() {
+	try {
+		if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
+			return null
+		}
+		const response = await fetch('/', {
+			cache: 'no-cache',
+			method: 'HEAD'
+		})
+
+		return response.headers.get('etag') || response.headers.get('last-modified')
+	} catch {
+		console.error('Failed to fetch version tag')
+		return null
+	}
+}
+
+async function checkForUpdates() {
+	const versionTag = await getVersionTag()
+	if (!versionTag) {
+		return
+	}
+
+	// 首次运行时不提示更新
+	if (!lastVersionTag.value) {
+		lastVersionTag.value = versionTag
+		return
+	}
+	if (lastVersionTag.value !== versionTag && versionTag) {
+		clearInterval(timer)
+		handleNotice(versionTag)
+	}
+}
+
+const handleNotice = versionTag => {
+	const onOk = () => {
+		lastVersionTag.value = versionTag
+		window.location.reload()
+	}
+	const notify = ElNotification({
+			title: t('le.layout.checkUpdatesTitle'),
+			customClass: 'le-notification--check-app',
+			message: (
+				<div>
+					{t('le.layout.checkUpdatesDescription')}
+					<div class="text-right mt-[12px]">
+						<ElButton onClick={() => notify.close()}>{t('le.btn.cancel')}</ElButton>
+						<ElButton type="primary" onClick={onOk}>
+							{t('le.refresh')}
+						</ElButton>
+					</div>
+				</div>
+			),
+			position: 'bottom-right',
+			duration: 0
+		})
+}
+
+function start() {
+	if (props.checkUpdatesInterval <= 0) {
+		return
+	}
+
+	// 每 checkUpdatesInterval(默认值为5) 分钟检查一次
+	timer = setInterval(checkForUpdates, props.checkUpdatesInterval * 60 * 1000)
+}
+function stop() {
+	clearInterval(timer)
+}
+function handleVisibilitychange() {
+	// console.error(isCheckingUpdates, 'isCheckingUpdates')
+	if (document.hidden) {
+		stop()
+	} else {
+		if (!isCheckingUpdates) {
+			isCheckingUpdates = true
+			checkForUpdates().finally(() => {
+				isCheckingUpdates = false
+				start()
+			})
+		}
+	}
+}
+onMounted(() => {
+	start()
+	document.addEventListener('visibilitychange', handleVisibilitychange)
+})
+
+onUnmounted(() => {
+	stop()
+	document.removeEventListener('visibilitychange', handleVisibilitychange)
+})
+</script>
+
+<style lang="scss">
+//.le-notification--check-app {
+.#{$prefix}notification--check-app {
+	.el-notification {
+		&__group {
+			margin: 0;
+			width: 100%;
+		}
+		&__content {
+			margin-right: -12px;
+		}
+	}
+}
+</style>

+ 3 - 0
src/layout/index.vue

@@ -1,6 +1,8 @@
 <template>
 	<component :is="LayoutComponents[layout]" />
 	<ThemeSettings v-if="showSettings" />
+	<!-- 版本校验刷新功能 -->
+	<CheckUpdates />
 </template>
 
 <script setup lang="ts" name="layout">
@@ -12,6 +14,7 @@ import LayoutLeft from './LayoutLeft/index.vue'
 import LayoutLeftMix from './LayoutLeftMix/index.vue'
 import LayoutTop from './LayoutTop/index.vue'
 import LayoutTopMix from './LayoutTopMix/index.vue'
+import CheckUpdates from './components/CheckUpdates.vue'
 import { ThemeSettings } from '@/layout/components'
 
 const LayoutComponents: Record<LayoutType, Component> = {