| 
					
				 | 
			
			
				@@ -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 () => {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |