|
@@ -1,5 +1,86 @@
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
|
|
+import { onBeforeUnmount, onMounted, watch } from "vue";
|
|
|
|
|
+import { useRoute } from "vue-router";
|
|
|
import { motion } from "motion-v";
|
|
import { motion } from "motion-v";
|
|
|
|
|
+import { deleteUserCache } from "@hooks/useCache";
|
|
|
|
|
+import { manualLogoutKey, reloginCancelKey } from "@/config/axios/service";
|
|
|
|
|
+import { removeToken, getAccessToken } from "@/utils/auth";
|
|
|
|
|
+import { useUserStore } from "@/stores/useUserStore";
|
|
|
|
|
+
|
|
|
|
|
+const route = useRoute();
|
|
|
|
|
+const userStore = useUserStore();
|
|
|
|
|
+
|
|
|
|
|
+const IDLE_TIMEOUT = 30 * 60 * 1000;
|
|
|
|
|
+const activityEvents = [
|
|
|
|
|
+ "click",
|
|
|
|
|
+ "mousemove",
|
|
|
|
|
+ "keydown",
|
|
|
|
|
+ "scroll",
|
|
|
|
|
+ "touchstart",
|
|
|
|
|
+];
|
|
|
|
|
+
|
|
|
|
|
+let idleTimer: number | null = null;
|
|
|
|
|
+
|
|
|
|
|
+const isLoginPage = () => route.path === "/login";
|
|
|
|
|
+
|
|
|
|
|
+const clearIdleTimer = () => {
|
|
|
|
|
+ if (idleTimer) {
|
|
|
|
|
+ window.clearTimeout(idleTimer);
|
|
|
|
|
+ idleTimer = null;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const logoutByIdle = () => {
|
|
|
|
|
+ clearIdleTimer();
|
|
|
|
|
+
|
|
|
|
|
+ if (!getAccessToken() || isLoginPage()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ deleteUserCache();
|
|
|
|
|
+ userStore.resetState();
|
|
|
|
|
+ sessionStorage.setItem(manualLogoutKey, "true");
|
|
|
|
|
+ sessionStorage.removeItem(reloginCancelKey);
|
|
|
|
|
+ removeToken();
|
|
|
|
|
+ window.location.href = "/login";
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const resetIdleTimer = () => {
|
|
|
|
|
+ clearIdleTimer();
|
|
|
|
|
+
|
|
|
|
|
+ if (!getAccessToken() || isLoginPage()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ idleTimer = window.setTimeout(() => {
|
|
|
|
|
+ logoutByIdle();
|
|
|
|
|
+ }, IDLE_TIMEOUT);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleUserActivity = () => {
|
|
|
|
|
+ resetIdleTimer();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ activityEvents.forEach((eventName) => {
|
|
|
|
|
+ window.addEventListener(eventName, handleUserActivity, true);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ watch(
|
|
|
|
|
+ () => route.path,
|
|
|
|
|
+ () => {
|
|
|
|
|
+ resetIdleTimer();
|
|
|
|
|
+ },
|
|
|
|
|
+ { immediate: true },
|
|
|
|
|
+ );
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
|
+ clearIdleTimer();
|
|
|
|
|
+ activityEvents.forEach((eventName) => {
|
|
|
|
|
+ window.removeEventListener(eventName, handleUserActivity, true);
|
|
|
|
|
+ });
|
|
|
|
|
+});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
<template>
|