diff --git a/gofaster/app/dist/renderer/js/index.js b/gofaster/app/dist/renderer/js/index.js index 1f509fb..ab78779 100644 --- a/gofaster/app/dist/renderer/js/index.js +++ b/gofaster/app/dist/renderer/js/index.js @@ -3004,18 +3004,23 @@ __webpack_require__.r(__webpack_exports__); // 登录状态 const isLoggedIn = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(false) - // 应用设置 - const appSettings = (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)({ - appName: 'GoFaster' - }) - - // Toast 配置 - const toastConfig = (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)({ - type: 'info', - title: '', - content: '', - duration: 3000 - }) + // 应用设置 + const appSettings = (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)({ + appName: 'GoFaster' + }) + + // Toast 配置 + const toastConfig = (0,vue__WEBPACK_IMPORTED_MODULE_0__.reactive)({ + type: 'info', + title: '', + content: '', + duration: 3000 + }) + + // 会话超时相关 + let sessionTimeoutTimer = null + let lastActivityTime = Date.now() + const sessionTimeoutMinutes = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)(30) // 默认30分钟 const messages = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)([ { @@ -3352,6 +3357,12 @@ __webpack_require__.r(__webpack_exports__); const userName = currentUser.name || userData.username || '用户' showToastMessage('success', '登录成功', `欢迎回来,${userName}!`) + // 启动会话超时检测 + startSessionTimeoutCheck() + + // 更新用户活动时间 + updateUserActivity() + // 跳转到首页 router.push('/') } @@ -3427,6 +3438,139 @@ __webpack_require__.r(__webpack_exports__); toastConfig.duration = duration showToast.value = true } + + // 更新用户活动时间 + const updateUserActivity = () => { + lastActivityTime = Date.now() + } + + // 启动会话超时检测 + const startSessionTimeoutCheck = () => { + // 清除之前的定时器 + if (sessionTimeoutTimer) { + clearInterval(sessionTimeoutTimer) + } + + // 获取用户设置的会话超时时间 + try { + const userSettings = localStorage.getItem('gofaster-settings') + if (userSettings) { + const settings = JSON.parse(userSettings) + if (settings.sessionTimeout) { + sessionTimeoutMinutes.value = settings.sessionTimeout + } + } + } catch (error) { + console.error('获取会话超时设置失败:', error) + } + + // 每分钟检查一次会话状态 + sessionTimeoutTimer = setInterval(() => { + const currentTime = Date.now() + const inactiveTime = (currentTime - lastActivityTime) / 1000 / 60 // 转换为分钟 + + if (inactiveTime >= sessionTimeoutMinutes.value) { + console.log('会话超时,自动退出登录') + showToastMessage('warning', '会话超时', '您的会话已超时,将自动退出登录') + + // 延迟2秒后执行退出登录,让用户看到提示 + setTimeout(() => { + logout() + }, 2000) + } + }, 60000) // 每分钟检查一次 + } + + // 停止会话超时检测 + const stopSessionTimeoutCheck = () => { + if (sessionTimeoutTimer) { + clearInterval(sessionTimeoutTimer) + sessionTimeoutTimer = null + } + } + + // 处理应用关闭事件 + const handleAppWillClose = () => { + if (isLoggedIn.value) { + // 同步执行退出登录,不等待异步操作 + try { + const token = localStorage.getItem('token') + + if (token) { + // 这里可以发送一个同步的退出登录请求,但考虑到应用即将关闭,主要是清除本地状态 + _services_userService__WEBPACK_IMPORTED_MODULE_3__.userService.logout(token).catch(error => { + console.error('应用关闭时调用登出接口失败:', error) + }) + } + } catch (error) { + console.error('应用关闭时退出登录失败:', error) + } finally { + // 清除本地状态 + localStorage.removeItem('user') + localStorage.removeItem('isLoggedIn') + localStorage.removeItem('token') + + // 清除用户对象状态 + currentUser.id = null + currentUser.name = '' + currentUser.email = '' + currentUser.avatar = null + currentUser.role = '' + currentUser.lastLogin = null + currentUser.lastLoginIP = '' + currentUser.status = 1 + currentUser.roles = [] + + // 更新登录状态 + isLoggedIn.value = false + + // 停止会话超时检测 + stopSessionTimeoutCheck() + } + } + } + + // 自动退出登录(不显示提示) + const autoLogout = async () => { + try { + // 获取当前token + const token = localStorage.getItem('token') + if (token) { + // 调用后端登出接口 + await _services_userService__WEBPACK_IMPORTED_MODULE_3__.userService.logout(token) + } + } catch (error) { + console.error('调用登出接口失败:', error) + } finally { + // 清除用户信息 + currentUser.id = null + currentUser.name = '' + currentUser.email = '' + currentUser.avatar = null + currentUser.role = '' + currentUser.lastLogin = null + currentUser.lastLoginIP = '' + currentUser.status = 1 + currentUser.roles = [] + isLoggedIn.value = false + + // 清除本地存储 + localStorage.removeItem('user') + localStorage.removeItem('isLoggedIn') + localStorage.removeItem('token') + + // 关闭用户菜单 + showUserMenu.value = false + + // 触发全局事件,通知其他组件用户已登出 + window.dispatchEvent(new CustomEvent('user-logout', { + detail: { user: currentUser } + })) + + // 跳转到首页 + router.push('/') + } + } const logout = async () => { try { @@ -3440,7 +3584,10 @@ __webpack_require__.r(__webpack_exports__); console.error('调用登出接口失败:', error) // 即使后端调用失败,也要清除本地状态 } finally { - // 清除用户信息 + // 停止会话超时检测 + stopSessionTimeoutCheck() + + // 清除用户信息 currentUser.id = null currentUser.name = '' currentUser.email = '' @@ -3530,14 +3677,39 @@ __webpack_require__.r(__webpack_exports__); // 初始化收藏菜单 updateFavoriteMenu() - // 检查登录状态 - const savedIsLoggedIn = localStorage.getItem('isLoggedIn') - const savedUser = localStorage.getItem('user') - - if (savedIsLoggedIn === 'true' && savedUser) { - try { - const userData = JSON.parse(savedUser) - console.log('从localStorage恢复的用户数据:', userData) + // 添加用户活动监听器 + const userActivityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'] + userActivityEvents.forEach(event => { + document.addEventListener(event, updateUserActivity, { passive: true }) + }) + + // 监听应用关闭事件 + if (window.electronAPI && window.electronAPI.onAppWillClose) { + window.electronAPI.onAppWillClose(handleAppWillClose) + } else { + // 兼容性处理:如果electronAPI不可用,使用备用方案 + console.warn('electronAPI不可用,无法注册应用关闭事件监听器') + // 可以在这里添加其他备用方案,比如使用localStorage或其他方式 + } + + // 添加页面卸载事件监听器作为备用方案 + window.addEventListener('beforeunload', () => { + if (isLoggedIn.value) { + // 同步清除本地状态 + localStorage.removeItem('user') + localStorage.removeItem('isLoggedIn') + localStorage.removeItem('token') + stopSessionTimeoutCheck() + } + }) + + // 检查登录状态 + const savedIsLoggedIn = localStorage.getItem('isLoggedIn') + const savedUser = localStorage.getItem('user') + + if (savedIsLoggedIn === 'true' && savedUser) { + try { + const userData = JSON.parse(savedUser) // 先设置默认值,然后用localStorage的数据覆盖 const defaultUser = { @@ -3568,7 +3740,6 @@ __webpack_require__.r(__webpack_exports__); Object.assign(currentUser, defaultUser, mappedUserData) isLoggedIn.value = true - console.log('恢复后的用户信息:', currentUser) } catch (error) { console.warn('解析用户信息失败:', error) // 清除无效的用户信息 @@ -3607,6 +3778,15 @@ __webpack_require__.r(__webpack_exports__); // 组件卸载时清理事件监听器 ;(0,vue__WEBPACK_IMPORTED_MODULE_0__.onUnmounted)(() => { document.removeEventListener('click', handleGlobalClick) + + // 移除用户活动监听器 + const userActivityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'] + userActivityEvents.forEach(event => { + document.removeEventListener(event, updateUserActivity) + }) + + // 停止会话超时检测 + stopSessionTimeoutCheck() }) // 提供响应式数据给子组件 @@ -3614,11 +3794,7 @@ __webpack_require__.r(__webpack_exports__); ;(0,vue__WEBPACK_IMPORTED_MODULE_0__.provide)('currentUser', safeCurrentUser) ;(0,vue__WEBPACK_IMPORTED_MODULE_0__.provide)('showLoginModal', showLoginModal) - // 添加调试信息 - console.log('MainLayout setup completed') - console.log('isLoggedIn:', isLoggedIn) - console.log('safeCurrentUser:', safeCurrentUser) - console.log('showLoginModal:', showLoginModal) + return { showMessagePanel, @@ -4637,7 +4813,6 @@ __webpack_require__.r(__webpack_exports__); this.$router.push('/history'); }, openSettings() { - console.log('打开用户设置'); // 通过事件通知父组件添加标签页 this.$emit('add-tab', { @@ -4726,39 +4901,31 @@ __webpack_require__.r(__webpack_exports__); // 监听登录状态变化 - 使用计算属性确保响应式 this.$watch('computedIsLoggedIn', (newVal) => { - console.log('Home.vue - 登录状态变化:', newVal); if (newVal && this.computedCurrentUser) { - console.log('Home.vue - 当前用户信息:', this.computedCurrentUser); this.userInfo.name = this.computedCurrentUser.name || this.userInfo.name; this.userInfo.email = this.computedCurrentUser.email || this.userInfo.email; - console.log('Home.vue - 更新后的用户信息:', this.userInfo); } }, { immediate: true }); // 监听用户信息变化 - 使用计算属性确保响应式 this.$watch('computedCurrentUser', (newUser) => { - console.log('Home.vue - 用户信息变化:', newUser); if (newUser && newUser.name) { this.userInfo.name = newUser.name; this.userInfo.email = newUser.email || this.userInfo.email; - console.log('Home.vue - 用户信息更新后:', this.userInfo); } }, { immediate: true, deep: true }); // 监听全局登录成功事件 window.addEventListener('user-login-success', (event) => { - console.log('Home.vue - 收到登录成功事件:', event.detail); const { user } = event.detail; if (user) { this.userInfo.name = user.name || this.userInfo.name; this.userInfo.email = user.email || this.userInfo.email; - console.log('Home.vue - 事件更新后的用户信息:', this.userInfo); } }); // 监听全局登出事件 window.addEventListener('user-logout', () => { - console.log('Home.vue - 收到登出事件'); this.userInfo.name = '用户'; this.userInfo.email = 'user@example.com'; }); @@ -8856,7 +9023,7 @@ __webpack_require__.r(__webpack_exports__); /******/ /******/ /* webpack/runtime/getFullHash */ /******/ (() => { -/******/ __webpack_require__.h = () => ("861ac4d425d88faa") +/******/ __webpack_require__.h = () => ("4a166f955d2fe42e") /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ diff --git a/gofaster/app/src/main/index.js b/gofaster/app/src/main/index.js index a323269..0d5f3d3 100644 --- a/gofaster/app/src/main/index.js +++ b/gofaster/app/src/main/index.js @@ -4,8 +4,8 @@ const fs = require('fs') const os = require('os') const WindowStateManager = require('./windowState') -// 创建窗口状态管理器 -const windowStateManager = new WindowStateManager('main') +// 窗口状态管理器(延迟初始化) +let windowStateManager = null // 设置进程编码,确保中文正常显示 process.env.LANG = 'zh_CN.UTF-8' @@ -48,9 +48,19 @@ let mainWindow let errorLogCount = 0 let logFilePath -// 检查是否为开发环境 -const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged -console.log('Development environment:', isDev) +// 检查是否为开发环境(延迟初始化) +let isDev = null +function getIsDev() { + if (isDev === null) { + try { + isDev = process.env.NODE_ENV === 'development' || !app.isPackaged + } catch (error) { + // 如果app对象还没有准备好,默认使用开发环境 + isDev = process.env.NODE_ENV === 'development' || true + } + } + return isDev +} // 初始化日志系统 function initLogging() { @@ -120,7 +130,7 @@ function initLogging() { } // 开发环境热重载 - 只在非watch模式下启用 -if (isDev && !process.argv.includes('--watch')) { +if (getIsDev() && !process.argv.includes('--watch')) { try { // 修复热重载配置 require('electron-reload')(appRoot, { @@ -141,7 +151,7 @@ if (isDev && !process.argv.includes('--watch')) { } // 监听文件变化(用于watch模式) -if (isDev && process.argv.includes('--watch')) { +if (getIsDev() && process.argv.includes('--watch')) { console.log('Watch mode enabled, monitoring file changes...'); // 监听dist目录变化 @@ -172,7 +182,20 @@ if (isDev && process.argv.includes('--watch')) { function createWindow() { try { // 加载保存的窗口状态 - const windowState = windowStateManager.loadState() + let windowState + if (!windowStateManager) { + console.warn('窗口状态管理器未初始化,使用默认状态') + windowState = { + width: 1200, + height: 800, + x: undefined, + y: undefined, + isMaximized: false, + isFullScreen: false + } + } else { + windowState = windowStateManager.loadState() + } mainWindow = new BrowserWindow({ width: windowState.width, @@ -212,8 +235,8 @@ function createWindow() { console.log('Main window created'); - // 开发环境下抑制安全警告 - if (isDev) { + // 开发环境下抑制安全警告 + if (getIsDev()) { mainWindow.webContents.on('did-frame-finish-load', () => { // 移除有问题的JavaScript执行,避免IPC通信错误 console.log('Page loaded, DevTools ready'); @@ -289,8 +312,8 @@ function createWindow() { // 检查文件是否存在 if (!fs.existsSync(loadPath)) { console.log('File not found, waiting for build completion...'); - // 在watch模式下等待文件构建完成 - if (isDev && process.argv.includes('--watch')) { + // 在watch模式下等待文件构建完成 + if (getIsDev() && process.argv.includes('--watch')) { const checkFile = () => { if (fs.existsSync(loadPath)) { console.log('Build completed, starting to load...'); @@ -315,8 +338,8 @@ function createWindow() { function loadMainWindow() { mainWindow.loadFile(loadPath).then(() => { console.log('Page loaded successfully'); - // 开发环境下打开开发者工具 - if (isDev) { + // 开发环境下打开开发者工具 + if (getIsDev()) { mainWindow.webContents.openDevTools() } // 页面加载完成后显示窗口 @@ -330,50 +353,60 @@ function createWindow() { } // 添加窗口状态监听器 - // 窗口大小改变时保存状态(防抖) + // 窗口大小改变时保存状态(防抖) let resizeTimeout mainWindow.on('resize', () => { clearTimeout(resizeTimeout) resizeTimeout = setTimeout(() => { - if (!mainWindow.isMaximized() && !mainWindow.isFullScreen()) { + if (!mainWindow.isMaximized() && !mainWindow.isFullScreen() && windowStateManager) { windowStateManager.saveState(mainWindow) } }, 500) // 500ms防抖 }) - + // 窗口移动时保存状态(防抖) let moveTimeout mainWindow.on('move', () => { clearTimeout(moveTimeout) moveTimeout = setTimeout(() => { - if (!mainWindow.isMaximized() && !mainWindow.isFullScreen()) { + if (!mainWindow.isMaximized() && !mainWindow.isFullScreen() && windowStateManager) { windowStateManager.saveState(mainWindow) } }, 500) // 500ms防抖 }) - + // 窗口最大化状态变化时保存状态 mainWindow.on('maximize', () => { - windowStateManager.saveState(mainWindow) + if (windowStateManager) { + windowStateManager.saveState(mainWindow) + } }) - + mainWindow.on('unmaximize', () => { - windowStateManager.saveState(mainWindow) + if (windowStateManager) { + windowStateManager.saveState(mainWindow) + } }) - + // 窗口全屏状态变化时保存状态 mainWindow.on('enter-full-screen', () => { - windowStateManager.saveState(mainWindow) + if (windowStateManager) { + windowStateManager.saveState(mainWindow) + } }) - + mainWindow.on('leave-full-screen', () => { - windowStateManager.saveState(mainWindow) + if (windowStateManager) { + windowStateManager.saveState(mainWindow) + } }) - + // 窗口关闭事件 mainWindow.on('closed', () => { // 保存窗口状态 - windowStateManager.saveState(mainWindow) + if (windowStateManager) { + windowStateManager.saveState(mainWindow) + } mainWindow = null }) @@ -385,6 +418,12 @@ function createWindow() { app.whenReady().then(() => { console.log('Electron app ready'); + // 输出开发环境状态 + console.log('Development environment:', getIsDev()); + + // 初始化窗口状态管理器 + windowStateManager = new WindowStateManager('main') + // 初始化日志系统 initLogging() @@ -518,6 +557,12 @@ ipcMain.handle('get-local-ip', async () => { // 窗口状态管理相关的IPC处理器 ipcMain.handle('reset-window-state', async () => { try { + if (!windowStateManager) { + return { + success: false, + message: '窗口状态管理器未初始化' + } + } const result = windowStateManager.resetState() return { success: result, @@ -527,13 +572,19 @@ ipcMain.handle('reset-window-state', async () => { console.error('重置窗口状态失败:', error) return { success: false, - message: '重置窗口状态失败: ' + error.message + message: '重置窗口状态失败: ' + error.message } } }) ipcMain.handle('get-window-state-info', async () => { try { + if (!windowStateManager) { + return { + success: false, + message: '窗口状态管理器未初始化' + } + } const hasState = windowStateManager.hasSavedState() const statePath = windowStateManager.getStatePath() let currentState = null @@ -556,7 +607,7 @@ ipcMain.handle('get-window-state-info', async () => { console.error('获取窗口状态信息失败:', error) return { success: false, - message: '获取窗口状态信息失败: ' + error.message + message: '获取窗口状态信息失败: ' + error.message } } }) @@ -564,7 +615,37 @@ ipcMain.handle('get-window-state-info', async () => { }); // 闭合 app.whenReady().then() 的回调函数 app.on('window-all-closed', () => { - if (process.platform !== 'darwin') app.quit() + // 通知渲染进程应用即将关闭,执行退出登录 + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send('app-will-close') + // 延迟退出,给渲染进程时间处理退出登录 + setTimeout(() => { + if (process.platform !== 'darwin') { + app.quit() + } + }, 1000) // 延迟1秒退出 + } else { + if (process.platform !== 'darwin') app.quit() + } +}) + +// 应用即将退出时的处理 +app.on('before-quit', () => { + // 通知渲染进程应用即将退出,执行退出登录 + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send('app-will-close') + // 延迟退出,给渲染进程时间处理退出登录 + setTimeout(() => { + app.quit() + }, 1000) // 延迟1秒退出 + } else { + app.quit() + } +}) + +// 应用退出时的处理 +app.on('quit', () => { + console.log('应用退出,已通知渲染进程执行退出登录') }) app.on('activate', () => { @@ -581,7 +662,7 @@ process.on('unhandledRejection', (reason, promise) => { }) // 测试日志系统 - 在开发环境下生成一些测试错误 -if (isDev) { +if (getIsDev()) { setTimeout(() => { console.error('测试错误日志 1: 这是一个模拟的错误信息') }, 5000) diff --git a/gofaster/app/src/main/windowState.js b/gofaster/app/src/main/windowState.js index 1e6ce8f..4a5181a 100644 --- a/gofaster/app/src/main/windowState.js +++ b/gofaster/app/src/main/windowState.js @@ -5,7 +5,29 @@ const fs = require('fs') class WindowStateManager { constructor(windowName = 'main') { this.windowName = windowName - this.statePath = path.join(app.getPath('userData'), `${windowName}-window-state.json`) + this._statePath = null // 延迟初始化状态路径 + } + + // 获取状态文件路径(延迟初始化) + get statePath() { + if (!this._statePath) { + try { + // 确保app对象已经准备好 + if (app && typeof app.getPath === 'function') { + this._statePath = path.join(app.getPath('userData'), `${this.windowName}-window-state.json`) + } else { + // 如果app还没有准备好,使用临时路径 + const os = require('os') + this._statePath = path.join(os.tmpdir(), `${this.windowName}-window-state.json`) + } + } catch (error) { + console.error('初始化状态路径失败:', error) + // 使用临时路径作为后备 + const os = require('os') + this._statePath = path.join(os.tmpdir(), `${this.windowName}-window-state.json`) + } + } + return this._statePath } // 加载窗口状态 diff --git a/gofaster/app/src/preload.js b/gofaster/app/src/preload.js index f11399c..d886b0f 100644 --- a/gofaster/app/src/preload.js +++ b/gofaster/app/src/preload.js @@ -10,5 +10,7 @@ contextBridge.exposeInMainWorld('electronAPI', { getLogFilePath: () => ipcRenderer.invoke('get-log-file-path'), onErrorLogUpdated: (callback) => ipcRenderer.on('error-log-updated', callback), openLogFolder: () => ipcRenderer.invoke('open-log-folder'), - getLocalIP: () => ipcRenderer.invoke('get-local-ip') + getLocalIP: () => ipcRenderer.invoke('get-local-ip'), + // 添加应用关闭事件监听 + onAppWillClose: (callback) => ipcRenderer.on('app-will-close', callback) }) \ No newline at end of file diff --git a/gofaster/app/src/renderer/components/MainLayout.vue b/gofaster/app/src/renderer/components/MainLayout.vue index b330f19..d4f5338 100644 --- a/gofaster/app/src/renderer/components/MainLayout.vue +++ b/gofaster/app/src/renderer/components/MainLayout.vue @@ -265,18 +265,23 @@ export default { // 登录状态 const isLoggedIn = ref(false) - // 应用设置 - const appSettings = reactive({ - appName: 'GoFaster' - }) - - // Toast 配置 - const toastConfig = reactive({ - type: 'info', - title: '', - content: '', - duration: 3000 - }) + // 应用设置 + const appSettings = reactive({ + appName: 'GoFaster' + }) + + // Toast 配置 + const toastConfig = reactive({ + type: 'info', + title: '', + content: '', + duration: 3000 + }) + + // 会话超时相关 + let sessionTimeoutTimer = null + let lastActivityTime = Date.now() + const sessionTimeoutMinutes = ref(30) // 默认30分钟 const messages = ref([ { @@ -613,6 +618,12 @@ export default { const userName = currentUser.name || userData.username || '用户' showToastMessage('success', '登录成功', `欢迎回来,${userName}!`) + // 启动会话超时检测 + startSessionTimeoutCheck() + + // 更新用户活动时间 + updateUserActivity() + // 跳转到首页 router.push('/') } @@ -688,6 +699,139 @@ export default { toastConfig.duration = duration showToast.value = true } + + // 更新用户活动时间 + const updateUserActivity = () => { + lastActivityTime = Date.now() + } + + // 启动会话超时检测 + const startSessionTimeoutCheck = () => { + // 清除之前的定时器 + if (sessionTimeoutTimer) { + clearInterval(sessionTimeoutTimer) + } + + // 获取用户设置的会话超时时间 + try { + const userSettings = localStorage.getItem('gofaster-settings') + if (userSettings) { + const settings = JSON.parse(userSettings) + if (settings.sessionTimeout) { + sessionTimeoutMinutes.value = settings.sessionTimeout + } + } + } catch (error) { + console.error('获取会话超时设置失败:', error) + } + + // 每分钟检查一次会话状态 + sessionTimeoutTimer = setInterval(() => { + const currentTime = Date.now() + const inactiveTime = (currentTime - lastActivityTime) / 1000 / 60 // 转换为分钟 + + if (inactiveTime >= sessionTimeoutMinutes.value) { + console.log('会话超时,自动退出登录') + showToastMessage('warning', '会话超时', '您的会话已超时,将自动退出登录') + + // 延迟2秒后执行退出登录,让用户看到提示 + setTimeout(() => { + logout() + }, 2000) + } + }, 60000) // 每分钟检查一次 + } + + // 停止会话超时检测 + const stopSessionTimeoutCheck = () => { + if (sessionTimeoutTimer) { + clearInterval(sessionTimeoutTimer) + sessionTimeoutTimer = null + } + } + + // 处理应用关闭事件 + const handleAppWillClose = () => { + if (isLoggedIn.value) { + // 同步执行退出登录,不等待异步操作 + try { + const token = localStorage.getItem('token') + + if (token) { + // 这里可以发送一个同步的退出登录请求,但考虑到应用即将关闭,主要是清除本地状态 + userService.logout(token).catch(error => { + console.error('应用关闭时调用登出接口失败:', error) + }) + } + } catch (error) { + console.error('应用关闭时退出登录失败:', error) + } finally { + // 清除本地状态 + localStorage.removeItem('user') + localStorage.removeItem('isLoggedIn') + localStorage.removeItem('token') + + // 清除用户对象状态 + currentUser.id = null + currentUser.name = '' + currentUser.email = '' + currentUser.avatar = null + currentUser.role = '' + currentUser.lastLogin = null + currentUser.lastLoginIP = '' + currentUser.status = 1 + currentUser.roles = [] + + // 更新登录状态 + isLoggedIn.value = false + + // 停止会话超时检测 + stopSessionTimeoutCheck() + } + } + } + + // 自动退出登录(不显示提示) + const autoLogout = async () => { + try { + // 获取当前token + const token = localStorage.getItem('token') + if (token) { + // 调用后端登出接口 + await userService.logout(token) + } + } catch (error) { + console.error('调用登出接口失败:', error) + } finally { + // 清除用户信息 + currentUser.id = null + currentUser.name = '' + currentUser.email = '' + currentUser.avatar = null + currentUser.role = '' + currentUser.lastLogin = null + currentUser.lastLoginIP = '' + currentUser.status = 1 + currentUser.roles = [] + isLoggedIn.value = false + + // 清除本地存储 + localStorage.removeItem('user') + localStorage.removeItem('isLoggedIn') + localStorage.removeItem('token') + + // 关闭用户菜单 + showUserMenu.value = false + + // 触发全局事件,通知其他组件用户已登出 + window.dispatchEvent(new CustomEvent('user-logout', { + detail: { user: currentUser } + })) + + // 跳转到首页 + router.push('/') + } + } const logout = async () => { try { @@ -701,7 +845,10 @@ export default { console.error('调用登出接口失败:', error) // 即使后端调用失败,也要清除本地状态 } finally { - // 清除用户信息 + // 停止会话超时检测 + stopSessionTimeoutCheck() + + // 清除用户信息 currentUser.id = null currentUser.name = '' currentUser.email = '' @@ -791,14 +938,39 @@ export default { // 初始化收藏菜单 updateFavoriteMenu() - // 检查登录状态 - const savedIsLoggedIn = localStorage.getItem('isLoggedIn') - const savedUser = localStorage.getItem('user') - - if (savedIsLoggedIn === 'true' && savedUser) { - try { - const userData = JSON.parse(savedUser) - console.log('从localStorage恢复的用户数据:', userData) + // 添加用户活动监听器 + const userActivityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'] + userActivityEvents.forEach(event => { + document.addEventListener(event, updateUserActivity, { passive: true }) + }) + + // 监听应用关闭事件 + if (window.electronAPI && window.electronAPI.onAppWillClose) { + window.electronAPI.onAppWillClose(handleAppWillClose) + } else { + // 兼容性处理:如果electronAPI不可用,使用备用方案 + console.warn('electronAPI不可用,无法注册应用关闭事件监听器') + // 可以在这里添加其他备用方案,比如使用localStorage或其他方式 + } + + // 添加页面卸载事件监听器作为备用方案 + window.addEventListener('beforeunload', () => { + if (isLoggedIn.value) { + // 同步清除本地状态 + localStorage.removeItem('user') + localStorage.removeItem('isLoggedIn') + localStorage.removeItem('token') + stopSessionTimeoutCheck() + } + }) + + // 检查登录状态 + const savedIsLoggedIn = localStorage.getItem('isLoggedIn') + const savedUser = localStorage.getItem('user') + + if (savedIsLoggedIn === 'true' && savedUser) { + try { + const userData = JSON.parse(savedUser) // 先设置默认值,然后用localStorage的数据覆盖 const defaultUser = { @@ -829,7 +1001,6 @@ export default { Object.assign(currentUser, defaultUser, mappedUserData) isLoggedIn.value = true - console.log('恢复后的用户信息:', currentUser) } catch (error) { console.warn('解析用户信息失败:', error) // 清除无效的用户信息 @@ -868,6 +1039,15 @@ export default { // 组件卸载时清理事件监听器 onUnmounted(() => { document.removeEventListener('click', handleGlobalClick) + + // 移除用户活动监听器 + const userActivityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'] + userActivityEvents.forEach(event => { + document.removeEventListener(event, updateUserActivity) + }) + + // 停止会话超时检测 + stopSessionTimeoutCheck() }) // 提供响应式数据给子组件 @@ -875,11 +1055,7 @@ export default { provide('currentUser', safeCurrentUser) provide('showLoginModal', showLoginModal) - // 添加调试信息 - console.log('MainLayout setup completed') - console.log('isLoggedIn:', isLoggedIn) - console.log('safeCurrentUser:', safeCurrentUser) - console.log('showLoginModal:', showLoginModal) + return { showMessagePanel, diff --git a/gofaster/app/src/renderer/views/Home.vue b/gofaster/app/src/renderer/views/Home.vue index 96bc65b..3590c78 100644 --- a/gofaster/app/src/renderer/views/Home.vue +++ b/gofaster/app/src/renderer/views/Home.vue @@ -192,7 +192,6 @@ export default { this.$router.push('/history'); }, openSettings() { - console.log('打开用户设置'); // 通过事件通知父组件添加标签页 this.$emit('add-tab', { @@ -281,39 +280,31 @@ export default { // 监听登录状态变化 - 使用计算属性确保响应式 this.$watch('computedIsLoggedIn', (newVal) => { - console.log('Home.vue - 登录状态变化:', newVal); if (newVal && this.computedCurrentUser) { - console.log('Home.vue - 当前用户信息:', this.computedCurrentUser); this.userInfo.name = this.computedCurrentUser.name || this.userInfo.name; this.userInfo.email = this.computedCurrentUser.email || this.userInfo.email; - console.log('Home.vue - 更新后的用户信息:', this.userInfo); } }, { immediate: true }); // 监听用户信息变化 - 使用计算属性确保响应式 this.$watch('computedCurrentUser', (newUser) => { - console.log('Home.vue - 用户信息变化:', newUser); if (newUser && newUser.name) { this.userInfo.name = newUser.name; this.userInfo.email = newUser.email || this.userInfo.email; - console.log('Home.vue - 用户信息更新后:', this.userInfo); } }, { immediate: true, deep: true }); // 监听全局登录成功事件 window.addEventListener('user-login-success', (event) => { - console.log('Home.vue - 收到登录成功事件:', event.detail); const { user } = event.detail; if (user) { this.userInfo.name = user.name || this.userInfo.name; this.userInfo.email = user.email || this.userInfo.email; - console.log('Home.vue - 事件更新后的用户信息:', this.userInfo); } }); // 监听全局登出事件 window.addEventListener('user-logout', () => { - console.log('Home.vue - 收到登出事件'); this.userInfo.name = '用户'; this.userInfo.email = 'user@example.com'; });