Bladeren bron

长时间未操作

Zimo 3 uur geleden
bovenliggende
commit
0fc4efcaed
2 gewijzigde bestanden met toevoegingen van 110 en 0 verwijderingen
  1. 29 0
      src/App.vue
  2. 81 0
      src/composable/useAutoLogout.ts

+ 29 - 0
src/App.vue

@@ -4,6 +4,35 @@ import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
 import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
 import routerSearch from '@/components/RouterSearch/index.vue'
+import { useAutoLogout } from './composable/useAutoLogout'
+
+const route = useRoute()
+const { addListeners, removeListeners } = useAutoLogout()
+
+const whiteList = [
+  '/login',
+  '/social-login',
+  '/auth-redirect',
+  '/bind',
+  '/register',
+  '/oauthLogin/gitee',
+  '/dingding',
+  '/deepoil'
+]
+
+watch(
+  () => route.path,
+  (newPath) => {
+    if (whiteList.includes(newPath)) {
+      console.log('进入白名单页面,移除超时检测')
+      removeListeners()
+    } else {
+      console.log('进入受控页面,开启超时检测')
+      addListeners()
+    }
+  },
+  { immediate: true } // 初始化时立即执行一次
+)
 
 defineOptions({ name: 'APP' })
 

+ 81 - 0
src/composable/useAutoLogout.ts

@@ -0,0 +1,81 @@
+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<typeof setTimeout> | 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
+  }
+}