mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 11:51:45 +08:00
feat: Regular monitoring page update [deploy]
This commit is contained in:
@@ -12,9 +12,9 @@ import { useCoreAccessStore, useCoreLockStore } from '@vben/stores';
|
||||
import { MenuRecordRaw } from '@vben/types';
|
||||
import { mapTree } from '@vben/utils';
|
||||
import { VbenAdminLayout } from '@vben-core/layout-ui';
|
||||
import { VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';
|
||||
import { Toaster, VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';
|
||||
|
||||
import { Breadcrumb, Preferences } from '../widgets';
|
||||
import { Breadcrumb, CheckUpdates, Preferences } from '../widgets';
|
||||
import { LayoutContent } from './content';
|
||||
import { Copyright } from './copyright';
|
||||
import { LayoutFooter } from './footer';
|
||||
@@ -310,6 +310,12 @@ watch(
|
||||
|
||||
<template #extra>
|
||||
<slot name="extra"></slot>
|
||||
<Toaster />
|
||||
<CheckUpdates
|
||||
v-if="preferences.app.enableCheckUpdates"
|
||||
:polling-time="preferences.app.checkUpdatesPollingTime"
|
||||
/>
|
||||
|
||||
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
|
||||
<slot v-if="coreLockStore.isLockScreen" name="lock-screen"></slot>
|
||||
</Transition>
|
||||
|
@@ -0,0 +1,126 @@
|
||||
<script setup lang="ts">
|
||||
import { h, onMounted, onUnmounted, ref } from 'vue';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
import { ToastAction, useToast } from '@vben-core/shadcn-ui';
|
||||
|
||||
interface Props {
|
||||
// 轮训时间,分钟
|
||||
pollingTime?: number;
|
||||
}
|
||||
|
||||
defineOptions({ name: 'CheckUpdates' });
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
pollingTime: 1,
|
||||
});
|
||||
|
||||
const lastVersionTag = ref('');
|
||||
let isCheckingUpdates = false;
|
||||
const timer = ref<ReturnType<typeof setInterval>>();
|
||||
const { toast } = useToast();
|
||||
|
||||
async function getVersionTag() {
|
||||
try {
|
||||
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) {
|
||||
lastVersionTag.value = versionTag;
|
||||
clearInterval(timer.value);
|
||||
handleNotice();
|
||||
}
|
||||
}
|
||||
function handleNotice() {
|
||||
const { dismiss } = toast({
|
||||
action: h('div', [
|
||||
h(
|
||||
ToastAction,
|
||||
{
|
||||
altText: $t('common.cancel'),
|
||||
onClick: () => dismiss(),
|
||||
},
|
||||
{
|
||||
default: () => $t('common.cancel'),
|
||||
},
|
||||
),
|
||||
h(
|
||||
ToastAction,
|
||||
{
|
||||
altText: $t('common.refresh'),
|
||||
class: 'bg-primary hover:bg-primary-hover mx-1',
|
||||
onClick: () => {
|
||||
window.location.reload();
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => $t('common.refresh'),
|
||||
},
|
||||
),
|
||||
]),
|
||||
description: $t('widgets.checkUpdatesDescription'),
|
||||
duration: 0,
|
||||
title: $t('widgets.checkUpdatesTitle'),
|
||||
});
|
||||
}
|
||||
|
||||
function start() {
|
||||
// 每5分钟检查一次
|
||||
timer.value = setInterval(checkForUpdates, props.pollingTime * 60 * 1000);
|
||||
}
|
||||
|
||||
function handleVisibilitychange() {
|
||||
if (document.hidden) {
|
||||
stop();
|
||||
} else {
|
||||
if (!isCheckingUpdates) {
|
||||
isCheckingUpdates = true;
|
||||
checkForUpdates().finally(() => {
|
||||
isCheckingUpdates = false;
|
||||
start();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
start();
|
||||
document.addEventListener('visibilitychange', handleVisibilitychange);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
stop();
|
||||
document.removeEventListener('visibilitychange', handleVisibilitychange);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<slot></slot>
|
||||
</template>
|
@@ -0,0 +1 @@
|
||||
export { default as CheckUpdates } from './check-updates.vue';
|
@@ -1,4 +1,5 @@
|
||||
export { default as Breadcrumb } from './breadcrumb.vue';
|
||||
export * from './check-updates';
|
||||
export { default as AuthenticationColorToggle } from './color-toggle.vue';
|
||||
export * from './global-search';
|
||||
export { default as LanguageToggle } from './language-toggle.vue';
|
||||
|
@@ -12,6 +12,7 @@ defineOptions({
|
||||
const appLocale = defineModel<string>('appLocale');
|
||||
const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
|
||||
const appWatermark = defineModel<boolean>('appWatermark');
|
||||
const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -24,4 +25,7 @@ const appWatermark = defineModel<boolean>('appWatermark');
|
||||
<SwitchItem v-model="appWatermark">
|
||||
{{ $t('preferences.watermark') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="appEnableCheckUpdates">
|
||||
{{ $t('preferences.checkUpdates') }}
|
||||
</SwitchItem>
|
||||
</template>
|
||||
|
@@ -62,6 +62,7 @@ const appColorGrayMode = defineModel<boolean>('appColorGrayMode');
|
||||
const appColorWeakMode = defineModel<boolean>('appColorWeakMode');
|
||||
const appContentCompact = defineModel<ContentCompactType>('appContentCompact');
|
||||
const appWatermark = defineModel<boolean>('appWatermark');
|
||||
const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
|
||||
|
||||
const transitionProgress = defineModel<boolean>('transitionProgress');
|
||||
const transitionName = defineModel<string>('transitionName');
|
||||
@@ -254,6 +255,7 @@ async function handleReset() {
|
||||
<Block :title="$t('preferences.general')">
|
||||
<General
|
||||
v-model:app-dynamic-title="appDynamicTitle"
|
||||
v-model:app-enable-check-updates="appEnableCheckUpdates"
|
||||
v-model:app-locale="appLocale"
|
||||
v-model:app-watermark="appWatermark"
|
||||
/>
|
||||
|
Reference in New Issue
Block a user