feat: 添加版本检测功能,包括构建时自动更新版本信息和运行时定期检查更新
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build": "tsx src/utils/update-version.ts && vite build --mode release",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
5
public/version.json
Normal file
5
public/version.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": "2025-10-15 09:50:32",
|
||||
"buildTime": "2025-10-15T01:50:32.937Z",
|
||||
"environment": "production"
|
||||
}
|
||||
38
src/App.vue
38
src/App.vue
@@ -1,10 +1,46 @@
|
||||
<!-- 基于rspack打包github&gitee -->
|
||||
<template>
|
||||
<router-view></router-view>
|
||||
<footer class="app-version">
|
||||
<span>版本:{{ versionText }}</span>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const versionText = ref('未知')
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const res = await fetch('/version.json', { cache: 'no-store' })
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
const v = typeof data?.version === 'string' && data.version.trim() ? data.version.trim() : ''
|
||||
versionText.value = v || '未知'
|
||||
} else {
|
||||
versionText.value = '未知'
|
||||
}
|
||||
} catch (e) {
|
||||
versionText.value = '未知'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import './assets/scss/index.scss';
|
||||
.app-version {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: saturate(180%) blur(6px);
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import { DialogPlugin } from 'tdesign-vue-next'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
// 获取浏览器中的url地址和端口号并拼接
|
||||
/* import { config } from 'public/config.js'
|
||||
const getBaseUrl = () => {
|
||||
@@ -14,7 +14,7 @@ const getBaseUrl = () => {
|
||||
// 创建一个新的axios实例
|
||||
const instance: AxiosInstance = axios.create({
|
||||
baseURL: import.meta.env.VITE_BASE_API,
|
||||
timeout: 60000,
|
||||
timeout: 30000,
|
||||
withCredentials: false,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
@@ -45,18 +45,14 @@ instance.interceptors.response.use(
|
||||
console.log(process.env.NODE_ENV, '变量')
|
||||
|
||||
const data = response.data
|
||||
|
||||
console.log('接口返回', data)
|
||||
// 判断接口返回的 Message 字段是否为 Success
|
||||
if (data && data.Message !== 'Success') {
|
||||
if (!data?.Message.includes('Success')) {
|
||||
// 如果不是 Success,则将请求视为失败
|
||||
const confirmDia = DialogPlugin({
|
||||
header: '错误',
|
||||
body: `${JSON.stringify(data)}`,
|
||||
confirmBtn: '确定',
|
||||
cancelBtn: null,
|
||||
onConfirm: ({ e }) => {
|
||||
confirmDia.hide()
|
||||
}
|
||||
ElMessageBox.alert(JSON.stringify(data), '错误', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'error',
|
||||
dangerouslyUseHTMLString: false
|
||||
})
|
||||
return Promise.reject({
|
||||
response: {
|
||||
@@ -66,7 +62,6 @@ instance.interceptors.response.use(
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 如果是 Success,则返回数据
|
||||
return data
|
||||
},
|
||||
@@ -84,15 +79,21 @@ instance.interceptors.response.use(
|
||||
// 在设置请求时发生了一些事情,触发了一个错误
|
||||
console.error('错误:', error.message)
|
||||
}
|
||||
const confirmDia = DialogPlugin({
|
||||
header: '错误',
|
||||
body: `${JSON.stringify(error)}`,
|
||||
confirmBtn: '确定',
|
||||
cancelBtn: null,
|
||||
onConfirm: ({ e }) => {
|
||||
confirmDia.hide()
|
||||
|
||||
console.error('报错', error)
|
||||
|
||||
ElMessageBox.alert(
|
||||
`接口:【${error.config.url}】报错
|
||||
${error.message}
|
||||
${JSON.stringify(error?.response?.data)}
|
||||
`,
|
||||
'报错',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
type: 'error',
|
||||
dangerouslyUseHTMLString: false
|
||||
}
|
||||
})
|
||||
)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -10,10 +10,12 @@ import { createApp } from 'vue'
|
||||
import router from './router/index' //引入vue-router
|
||||
import App from './App.vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
import { startVersionCheck } from './utils/versionCheck'
|
||||
import TDesign from 'tdesign-vue-next'
|
||||
import 'tdesign-vue-next/es/style/index.css'
|
||||
import 'normalize.css/normalize.css'
|
||||
// 启动版本检测服务 (20秒检查一次)
|
||||
startVersionCheck(1000 * 20)
|
||||
// 挂载到app上
|
||||
createApp(App)
|
||||
.use(router)
|
||||
|
||||
57
src/utils/update-version.ts
Normal file
57
src/utils/update-version.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 更新版本信息脚本
|
||||
* 在构建过程中自动更新 version.json 文件
|
||||
*/
|
||||
import fs from 'node:fs'
|
||||
import path, { dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
// 获取当前文件的目录路径
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
|
||||
// 版本信息
|
||||
const now = new Date()
|
||||
const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(
|
||||
2,
|
||||
'0'
|
||||
)}-${String(now.getDate()).padStart(2, '0')}`
|
||||
const timeStr = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(
|
||||
2,
|
||||
'0'
|
||||
)}:${String(now.getSeconds()).padStart(2, '0')}`
|
||||
|
||||
interface VersionInfo {
|
||||
version: string
|
||||
buildTime: string
|
||||
environment: string
|
||||
}
|
||||
|
||||
// 不再需要检查构建序号,直接使用时间戳作为版本号
|
||||
try {
|
||||
if (fs.existsSync(path.resolve(__dirname, '../../public/version.json'))) {
|
||||
const currentVersionInfo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../../public/version.json'), 'utf8'))
|
||||
console.log(`当前版本: ${currentVersionInfo.version}, 更新为时间格式版本`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('读取当前版本信息失败', error)
|
||||
}
|
||||
|
||||
// 设置版本格式为 YYYY-MM-DD HH:MM:SS
|
||||
const versionFormat = `${dateStr} ${timeStr}`
|
||||
|
||||
const versionInfo: VersionInfo = {
|
||||
version: versionFormat,
|
||||
buildTime: now.toISOString(),
|
||||
environment: process.env.NODE_ENV || 'production'
|
||||
}
|
||||
|
||||
// 版本文件路径
|
||||
// 确保路径正确解析到 pc-front/public/version.json
|
||||
const versionFilePath = path.resolve(__dirname, '../../public/version.json')
|
||||
|
||||
// 写入版本信息
|
||||
fs.writeFileSync(versionFilePath, JSON.stringify(versionInfo, null, 2), 'utf8')
|
||||
|
||||
console.log(`版本信息已更新: ${JSON.stringify(versionInfo)}`)
|
||||
console.log(`当前版本时间戳: ${versionFormat}`)
|
||||
154
src/utils/versionCheck.ts
Normal file
154
src/utils/versionCheck.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* 版本检测服务
|
||||
* 定期检查应用版本并提示用户更新
|
||||
*/
|
||||
|
||||
import { NotifyPlugin } from 'tdesign-vue-next'
|
||||
import { h } from 'vue'
|
||||
|
||||
interface VersionInfo {
|
||||
version: string
|
||||
buildTime: string
|
||||
environment: string
|
||||
}
|
||||
|
||||
let currentVersion: string | null = null
|
||||
let checkInterval: number | null = null
|
||||
let isUpdateNotificationShown = false
|
||||
|
||||
/**
|
||||
* 获取当前版本信息
|
||||
*/
|
||||
export const fetchVersionInfo = async (): Promise<VersionInfo> => {
|
||||
try {
|
||||
// 确保使用正确的路径访问version.json
|
||||
const response = await fetch(`/version.json?t=${new Date().getTime()}`)
|
||||
if (!response.ok) {
|
||||
throw new Error('无法获取版本信息')
|
||||
}
|
||||
return await response.json()
|
||||
} catch (error) {
|
||||
console.error('获取版本信息失败:', error)
|
||||
return {
|
||||
version: '0.0.0',
|
||||
buildTime: new Date().toISOString(),
|
||||
environment: 'unknown'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查版本更新
|
||||
*/
|
||||
export const checkVersion = async (): Promise<boolean> => {
|
||||
try {
|
||||
const versionInfo = await fetchVersionInfo()
|
||||
|
||||
// 首次加载,保存当前版本
|
||||
if (!currentVersion) {
|
||||
currentVersion = versionInfo.version
|
||||
return false
|
||||
}
|
||||
|
||||
// 版本不一致,需要更新
|
||||
if (currentVersion !== versionInfo.version) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
} catch (error) {
|
||||
console.error('检查版本更新失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示更新提示
|
||||
*/
|
||||
export const showUpdateNotification = () => {
|
||||
// 如果已经显示了更新提示,则不再重复显示
|
||||
if (isUpdateNotificationShown) {
|
||||
return
|
||||
}
|
||||
|
||||
// 标记已显示更新提示
|
||||
isUpdateNotificationShown = true
|
||||
|
||||
const notify = NotifyPlugin.warning({
|
||||
title: '有新的版本需要更新',
|
||||
content: '点击后将刷新页面获取最新版本!',
|
||||
footer: h('div', { class: 't-notification__detail' }, [
|
||||
h(
|
||||
't-button',
|
||||
{
|
||||
class: 't-notification__detail-item',
|
||||
theme: 'default',
|
||||
variant: 'text',
|
||||
onClick: () => window.location.reload()
|
||||
},
|
||||
'立即刷新'
|
||||
),
|
||||
h(
|
||||
't-button',
|
||||
{
|
||||
class: 't-notification__detail-item',
|
||||
theme: 'primary',
|
||||
variant: 'text',
|
||||
onClick: () => {
|
||||
isUpdateNotificationShown = false
|
||||
NotifyPlugin.close(notify)
|
||||
}
|
||||
},
|
||||
'稍后提醒我'
|
||||
)
|
||||
]),
|
||||
duration: 0
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动版本检测服务
|
||||
* @param intervalTime 检测间隔时间(毫秒),默认5分钟
|
||||
*/
|
||||
export const startVersionCheck = (intervalTime = 1000) => {
|
||||
// 重置通知标志
|
||||
isUpdateNotificationShown = false
|
||||
|
||||
// 初始化获取当前版本
|
||||
fetchVersionInfo().then(info => {
|
||||
currentVersion = info.version
|
||||
console.log('当前应用版本:', currentVersion)
|
||||
})
|
||||
|
||||
// 清除可能存在的旧定时器
|
||||
if (checkInterval) {
|
||||
window.clearInterval(checkInterval)
|
||||
}
|
||||
|
||||
// 设置定期检查
|
||||
checkInterval = window.setInterval(async () => {
|
||||
const needUpdate = await checkVersion()
|
||||
if (needUpdate) {
|
||||
showUpdateNotification()
|
||||
}
|
||||
}, intervalTime)
|
||||
|
||||
return () => {
|
||||
if (checkInterval) {
|
||||
window.clearInterval(checkInterval)
|
||||
checkInterval = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止版本检测服务
|
||||
*/
|
||||
export const stopVersionCheck = () => {
|
||||
if (checkInterval) {
|
||||
window.clearInterval(checkInterval)
|
||||
checkInterval = null
|
||||
}
|
||||
// 重置通知标志
|
||||
isUpdateNotificationShown = false
|
||||
}
|
||||
Reference in New Issue
Block a user