check-updates.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <script setup lang="ts">
  2. import { onMounted, onUnmounted, ref } from 'vue';
  3. import { $t } from '@vben/locales';
  4. import { useVbenModal } from '@vben-core/popup-ui';
  5. interface Props {
  6. // 轮训时间,分钟
  7. checkUpdatesInterval?: number;
  8. // 检查更新的地址
  9. checkUpdateUrl?: string;
  10. }
  11. defineOptions({ name: 'CheckUpdates' });
  12. const props = withDefaults(defineProps<Props>(), {
  13. checkUpdatesInterval: 1,
  14. checkUpdateUrl: import.meta.env.BASE_URL || '/',
  15. });
  16. let isCheckingUpdates = false;
  17. const currentVersionTag = ref('');
  18. const lastVersionTag = ref('');
  19. const timer = ref<ReturnType<typeof setInterval>>();
  20. const [UpdateNoticeModal, modalApi] = useVbenModal({
  21. closable: false,
  22. closeOnPressEscape: false,
  23. closeOnClickModal: false,
  24. onConfirm() {
  25. lastVersionTag.value = currentVersionTag.value;
  26. window.location.reload();
  27. // handleSubmitLogout();
  28. },
  29. });
  30. async function getVersionTag() {
  31. try {
  32. if (
  33. location.hostname === 'localhost' ||
  34. location.hostname === '127.0.0.1'
  35. ) {
  36. return null;
  37. }
  38. const response = await fetch(props.checkUpdateUrl, {
  39. cache: 'no-cache',
  40. method: 'HEAD',
  41. });
  42. return (
  43. response.headers.get('etag') || response.headers.get('last-modified')
  44. );
  45. } catch {
  46. console.error('Failed to fetch version tag');
  47. return null;
  48. }
  49. }
  50. async function checkForUpdates() {
  51. const versionTag = await getVersionTag();
  52. if (!versionTag) {
  53. return;
  54. }
  55. // 首次运行时不提示更新
  56. if (!lastVersionTag.value) {
  57. lastVersionTag.value = versionTag;
  58. return;
  59. }
  60. if (lastVersionTag.value !== versionTag && versionTag) {
  61. clearInterval(timer.value);
  62. handleNotice(versionTag);
  63. }
  64. }
  65. function handleNotice(versionTag: string) {
  66. currentVersionTag.value = versionTag;
  67. modalApi.open();
  68. }
  69. function start() {
  70. if (props.checkUpdatesInterval <= 0) {
  71. return;
  72. }
  73. // 每 checkUpdatesInterval(默认值为1) 分钟检查一次
  74. timer.value = setInterval(
  75. checkForUpdates,
  76. props.checkUpdatesInterval * 60 * 1000,
  77. );
  78. }
  79. function handleVisibilitychange() {
  80. if (document.hidden) {
  81. stop();
  82. } else {
  83. if (!isCheckingUpdates) {
  84. isCheckingUpdates = true;
  85. checkForUpdates().finally(() => {
  86. isCheckingUpdates = false;
  87. start();
  88. });
  89. }
  90. }
  91. }
  92. function stop() {
  93. clearInterval(timer.value);
  94. }
  95. onMounted(() => {
  96. start();
  97. document.addEventListener('visibilitychange', handleVisibilitychange);
  98. });
  99. onUnmounted(() => {
  100. stop();
  101. document.removeEventListener('visibilitychange', handleVisibilitychange);
  102. });
  103. </script>
  104. <template>
  105. <UpdateNoticeModal
  106. :cancel-text="$t('common.cancel')"
  107. :confirm-text="$t('common.refresh')"
  108. :fullscreen-button="false"
  109. :title="$t('ui.widgets.checkUpdatesTitle')"
  110. centered
  111. content-class="px-8 min-h-10"
  112. footer-class="border-none mb-3 mr-3"
  113. header-class="border-none"
  114. >
  115. {{ $t('ui.widgets.checkUpdatesDescription') }}
  116. </UpdateNoticeModal>
  117. </template>