浏览代码

江苏工伤结算单的日期

LIJU 1 月之前
父节点
当前提交
8020f5052c
共有 2 个文件被更改,包括 77 次插入0 次删除
  1. 7 0
      src/App.vue
  2. 70 0
      src/utils/auto-logout-on-close.ts

+ 7 - 0
src/App.vue

@@ -23,6 +23,7 @@ import useChangeToken from "@/utils/cy-use/useChangeToken";
 import CyDialogV2 from "@/components/cy/CyDialog/index.vue";
 import BackgroundTask from "@/layout/HeaderV2/BackgroundTask.vue";
 import { useYfGroupStore } from "@/pinia/use-yf-group";
+import { setupAutoLogoutOnClose } from "@/utils/auto-logout-on-close";
 
 const progressBarStore = useProgressBarStore();
 const systemStore = useSystemStore();
@@ -202,6 +203,12 @@ onMounted(() => {
   setCallback("systemNotification", systemNotification);
   setCallback("checkTheCallbacks", checkTheCallbacks);
   setCallback("avatarNotification", avatarNotification);
+
+  // 设置浏览器关闭时自动退出账号
+  const cleanupAutoLogout = setupAutoLogoutOnClose();
+  
+  // 组件卸载时清理事件监听器
+  onUnmounted(cleanupAutoLogout);
 });
 </script>
 

+ 70 - 0
src/utils/auto-logout-on-close.ts

@@ -0,0 +1,70 @@
+/**
+ * 浏览器关闭时自动退出账号(sessionStorage 哨兵方案)
+ * 思路:
+ * - 每次页面加载:
+ *   1) 若检测到已登录且不存在“会话哨兵”,说明是上一次浏览器被关闭 → 先执行一次安全登出
+ *   2) 设置“会话哨兵”,标记本标签页生命周期内为存活状态
+ * - 刷新/同域SPA导航:不会丢失 sessionStorage 的哨兵,不会触发登出
+ * - 关闭浏览器/关闭所有同域标签:sessionStorage 被清空,哨兵丢失;下次打开时检测到无哨兵且此前已登录,则自动登出
+ *
+ * 优点:
+ * - 绝不影响刷新/导航等正常流程
+ * - 仅在浏览器真正关闭后、下次进入时执行一次安全登出
+ */
+
+import { useUserStore } from '@/pinia/user-store'
+import { changeToken } from '@/utils/cy-use/useChangeToken'
+
+/**
+ * 设置浏览器关闭时自动退出账号
+ * @returns 清理函数,用于移除事件监听器
+ */
+export function setupAutoLogoutOnClose() {
+  const SESSION_SENTINEL_KEY = '_browserSessionAlive'
+
+  /**
+   * 执行退出登录的逻辑
+   * 使用项目现有的退出逻辑,确保与手动退出保持一致
+   */
+  const performLogout = () => {
+    try {
+      if (localStorage.token) {
+        localStorage.clear()
+        changeToken()
+        // 不做路由跳转,避免影响正常加载/关闭流程
+      }
+    } catch (error) {
+      console.warn('自动退出时出错:', error)
+    }
+  }
+
+  /**
+   * 初始化:处理上一次是否为浏览器关闭
+   * 规则:
+   * - 若检测到已登录且不存在会话哨兵,说明上一次关闭了浏览器(而非刷新/导航)→ 先执行降级登出,确保安全
+   */
+  const handleInit = () => {
+    const hasToken = !!localStorage.token
+    const hasSentinel = sessionStorage.getItem(SESSION_SENTINEL_KEY) === '1'
+
+    if (hasToken && !hasSentinel) {
+      performLogout()
+    }
+
+    // 设置当前会话存活哨兵
+    sessionStorage.setItem(SESSION_SENTINEL_KEY, '1')
+  }
+
+  if (document.readyState === 'complete' || document.readyState === 'interactive') {
+    handleInit()
+  } else {
+    const onLoad = () => {
+      handleInit()
+      window.removeEventListener('load', onLoad)
+    }
+    window.addEventListener('load', onLoad)
+  }
+
+  // 哨兵方案无需事件监听,这里返回空清理函数以保持API一致
+  return () => {}
+}