From 584cd54d6d86b4e440f35a8cfe89611a84c6b4c9 Mon Sep 17 00:00:00 2001 From: Soybean Date: Thu, 6 Jun 2024 20:08:00 +0800 Subject: [PATCH] feat(projects): support system new version update notification. close #420 --- build/plugins/html.ts | 13 ++++++++++ build/plugins/index.ts | 6 +++-- src/locales/langs/en-us.ts | 6 ++++- src/locales/langs/zh-cn.ts | 6 ++++- src/main.ts | 4 ++- src/plugins/app.ts | 53 ++++++++++++++++++++++++++++++++++++++ src/plugins/index.ts | 1 + src/typings/app.d.ts | 4 +++ vite.config.ts | 2 +- 9 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 build/plugins/html.ts create mode 100644 src/plugins/app.ts diff --git a/build/plugins/html.ts b/build/plugins/html.ts new file mode 100644 index 00000000..b94d24fe --- /dev/null +++ b/build/plugins/html.ts @@ -0,0 +1,13 @@ +import type { Plugin } from 'vite'; + +export function setupHtmlPlugin(buildTime: string) { + const plugin: Plugin = { + name: 'html-plugin', + apply: 'build', + transformIndexHtml(html) { + return html.replace('', `\n `); + } + }; + + return plugin; +} diff --git a/build/plugins/index.ts b/build/plugins/index.ts index d437da70..debec678 100644 --- a/build/plugins/index.ts +++ b/build/plugins/index.ts @@ -6,8 +6,9 @@ import progress from 'vite-plugin-progress'; import { setupElegantRouter } from './router'; import { setupUnocss } from './unocss'; import { setupUnplugin } from './unplugin'; +import { setupHtmlPlugin } from './html'; -export function setupVitePlugins(viteEnv: Env.ImportMeta) { +export function setupVitePlugins(viteEnv: Env.ImportMeta, buildTime: string) { const plugins: PluginOption = [ vue({ script: { @@ -19,7 +20,8 @@ export function setupVitePlugins(viteEnv: Env.ImportMeta) { setupElegantRouter(), setupUnocss(viteEnv), ...setupUnplugin(viteEnv), - progress() + progress(), + setupHtmlPlugin(buildTime) ]; return plugins; diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index 81508a56..570620e9 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -1,6 +1,10 @@ const local: App.I18n.Schema = { system: { - title: 'SoybeanAdmin' + title: 'SoybeanAdmin', + updateTitle: 'System Version Update Notification', + updateContent: 'A new version of the system has been detected. Do you want to refresh the page immediately?', + updateConfirm: 'Refresh immediately', + updateCancel: 'Later' }, common: { action: 'Action', diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index f5ba30e4..fc01bb65 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -1,6 +1,10 @@ const local: App.I18n.Schema = { system: { - title: 'Soybean 管理系统' + title: 'Soybean 管理系统', + updateTitle: '系统版本更新通知', + updateContent: '检测到系统有新版本发布,是否立即刷新页面?', + updateConfirm: '立即刷新', + updateCancel: '稍后再说' }, common: { action: '操作', diff --git a/src/main.ts b/src/main.ts index efb97f89..b97a0d93 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ import { createApp } from 'vue'; import './plugins/assets'; -import { setupDayjs, setupIconifyOffline, setupLoading, setupNProgress } from './plugins'; +import { setupAppVersionNotification, setupDayjs, setupIconifyOffline, setupLoading, setupNProgress } from './plugins'; import { setupStore } from './store'; import { setupRouter } from './router'; import { setupI18n } from './locales'; @@ -23,6 +23,8 @@ async function setupApp() { setupI18n(app); + setupAppVersionNotification(); + app.mount('#app'); } diff --git a/src/plugins/app.ts b/src/plugins/app.ts new file mode 100644 index 00000000..ffe6f586 --- /dev/null +++ b/src/plugins/app.ts @@ -0,0 +1,53 @@ +import { h } from 'vue'; +import { NButton } from 'naive-ui'; +import { $t } from '../locales'; + +export function setupAppVersionNotification() { + document.addEventListener('visibilitychange', async () => { + const buildTime = await getHtmlBuildTime(); + + if (buildTime !== BUILD_TIME && document.visibilityState === 'visible') { + const n = window.$notification?.create({ + title: $t('system.updateTitle'), + content: $t('system.updateContent'), + action() { + return h('div', { style: { display: 'flex', justifyContent: 'end', gap: '12px', width: '325px' } }, [ + h( + NButton, + { + onClick() { + n?.destroy(); + } + }, + $t('system.updateCancel') + ), + h( + NButton, + { + type: 'primary', + onClick() { + location.reload(); + } + }, + $t('system.updateConfirm') + ) + ]); + } + }); + } + }); +} + +async function getHtmlBuildTime() { + const baseURL = import.meta.env.VITE_BASE_URL; + + const res = await fetch(`${baseURL}index.html`); + + const html = await res.text(); + + const match = html.match(//); + + const buildTime = match?.[1] || ''; + + return buildTime; +} diff --git a/src/plugins/index.ts b/src/plugins/index.ts index 5d10c3aa..b2c9f9b5 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -2,3 +2,4 @@ export * from './loading'; export * from './nprogress'; export * from './iconify'; export * from './dayjs'; +export * from './app'; diff --git a/src/typings/app.d.ts b/src/typings/app.d.ts index e1b4b1ee..035fd8f1 100644 --- a/src/typings/app.d.ts +++ b/src/typings/app.d.ts @@ -251,6 +251,10 @@ declare namespace App { type Schema = { system: { title: string; + updateTitle: string; + updateContent: string; + updateConfirm: string; + updateCancel: string; }; common: { action: string; diff --git a/vite.config.ts b/vite.config.ts index 1393de1e..c3ea6d06 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -25,7 +25,7 @@ export default defineConfig(configEnv => { } } }, - plugins: setupVitePlugins(viteEnv), + plugins: setupVitePlugins(viteEnv, buildTime), define: { BUILD_TIME: JSON.stringify(buildTime) },