/**
* 前端版本校验工具:解决部署后文件缓存残留问题
* 核心逻辑:本地版本号 vs 后端版本号 → 不一致则清缓存、强制刷新
*/
import axios from 'axios'; // 依赖 axios,没有则安装:npm install axios
// 防止短时间内多次触发版本校验(如路由频繁切换、页面刷新)
let isChecking = false;
/**
* 1. 请求后端最新版本号(核心接口)
* @returns {Promise<string|null>} 后端最新版本号,失败则返回 null
*/
const fetchLatestVersion = async () => {
try {
// 加时间戳 + cache: 'no-store',双重保险,防止接口被缓存
const response = await axios.get('/api/system/version', {
params: {
t: Date.now() // 时间戳,避免浏览器缓存 GET 请求
},
headers: {
'Cache-Control': 'no-cache'
},
cache: 'no-store' // 禁止浏览器缓存该请求的响应
});
// 校验接口返回格式(避免后端返回异常)
if (response.data && response.data.code === 200 && response.data.data?.version) {
return response.data.data.version;
}
throw new Error('版本接口返回格式异常');
} catch (error) {
console.error('【版本校验】获取后端版本失败:', error.message);
// 接口失败时返回 null,避免阻断页面初始化(容错处理)
return null;
}
};
/**
* 2. 清理旧版本缓存(核心:只清理与业务、版本相关的缓存,不影响其他缓存)
*/
const cleanLegacyCache = () => {
console.log('【版本校验】检测到新版本,开始清理旧缓存...');
// 可根据你的项目,添加需要清理的缓存 key(以下是通用配置)
const cacheKeysToClean = [
'vuex', // Vuex 持久化缓存(如用了 vuex-persistedstate)
'templateId', // 之前项目中用到的关键参数缓存(可删除,或替换成你的缓存 key)
'lastReloadTime', // 防止无限刷新的时间戳缓存
// 可追加其他缓存 key,如:用户配置、接口缓存等与版本强相关的缓存
];
// 遍历清理缓存
cacheKeysToClean.forEach(key => {
localStorage.removeItem(key);
});
};
/**
* 3. 安全刷新页面(防止1分钟内无限刷新,避免死循环)
*/
const safeReload = () => {
const lastReloadTime = localStorage.getItem('lastReloadTime');
const now = Date.now();
// 防死循环:1分钟内只允许刷新一次
if (lastReloadTime && now - parseInt(lastReloadTime) < 60 * 1000) {
console.warn('【版本校验】短时间内已刷新过页面,跳过本次刷新');
return;
}
// 记录本次刷新时间戳
localStorage.setItem('lastReloadTime', now.toString());
// 核心:强制从服务器拉取最新资源,忽略浏览器缓存
// location.reload(true):强制刷新,绕过浏览器缓存(兼容所有主流浏览器)
window.location.reload(true);
// 兜底方案(如果 reload(true) 无效,启用下面的代码)
// const currentHref = window.location.href.split('?')[0];
// window.location.href = `${currentHref}?v=${Date.now()}`;
};
/**
* 4. 对外暴露的版本校验主方法(核心入口,供 main.js 调用)
* @returns {Promise<boolean>} 是否执行了版本更新(true:更新并刷新,false:无需更新)
*/
export const checkAppVersion = async () => {
if (isChecking) return false;
isChecking = true;
try {
// ① 获取本地版本号(由 vue.config.js / vite.config.js 注入)
const localVersion = __APP_VERSION__ || '0.0.0';
console.log('【版本校验】当前本地版本:', localVersion);
// ② 获取后端最新版本号
const remoteVersion = await fetchLatestVersion();
if (!remoteVersion) return false; // 接口失败,不执行更新,避免阻断页面
console.log('【版本校验】后端最新版本:', remoteVersion);
// ③ 对比版本号(核心逻辑:完全匹配,语义化版本可自行扩展)
if (localVersion !== remoteVersion) {
console.warn(`【版本校验】发现新版本:${localVersion} → ${remoteVersion}`);
// 清理旧缓存 + 安全刷新
cleanLegacyCache();
safeReload();
return true; // 表示执行了更新
}
// 版本一致,无需更新
console.log('【版本校验】版本一致,无需更新');
return false;
} finally {
// 无论成功失败,都重置校验状态,避免影响下次校验
isChecking = false;
}
};