import { onMounted, onUnmounted } from 'vue' import { ElMessageBox } from 'element-plus' import { useRouter } from 'vue-router' import { useUserStore } from '@/store/modules/user' import { getAccessToken } from '@/utils/auth' import { throttle } from 'lodash-es' // --- 关键修改:将变量移到函数外部,变成全局共享变量 --- let timer: ReturnType | null = null const TIMEOUT = 30 * 60 * 1000 // 30分钟 const events = ['click', 'mousedown', 'keydown', 'scroll', 'mousemove'] export function useAutoLogout() { const userStore = useUserStore() const router = useRouter() // 处理登出逻辑 const handleLogout = () => { // 防止重复触发,先清理 removeListeners() userStore.loginOut() ElMessageBox.alert('长时间未操作,登录已超时,请重新登录!', '提示', { confirmButtonText: '确定', type: 'warning', showClose: false, callback: () => { router.push('/login') } }) } // 节流的重置计时器 const resetTimer = throttle(() => { // 这里引用的 timer 是文件顶部的全局变量 if (timer) clearTimeout(timer) // 只有有 Token 时才开启倒计时 if (getAccessToken()) { timer = setTimeout(handleLogout, TIMEOUT) } }, 1000) const addListeners = () => { // 每次添加前先移除,防止重复绑定导致事件堆积 removeListeners() events.forEach((event) => { window.addEventListener(event, resetTimer) }) resetTimer() } const removeListeners = () => { if (timer) { clearTimeout(timer) timer = null } events.forEach((event) => { window.removeEventListener(event, resetTimer) }) } // 注意:如果你要在路由守卫中手动控制, // 建议去掉这里的生命周期钩子,或者只在 App.vue 中保留 // 如果这里保留,会导致只要 import 并在组件 setup 中调用,就会自动开启监听 onMounted(() => { // 如果你想完全由路由守卫控制,注释掉下面这行 // addListeners() }) onUnmounted(() => { // 组件卸载时销毁监听 removeListeners() }) return { addListeners, removeListeners } }