fix(auth): 长任务活跃期间续期会话
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { touchSessionActivity } from '@/utils/sessionActivity'
|
||||
|
||||
/**
|
||||
* 后端统一响应格式
|
||||
@@ -29,9 +30,12 @@ service.interceptors.response.use(
|
||||
const res = response.data as ApiResult
|
||||
// 二进制流等非 JSON 响应直接返回
|
||||
if (response.config.responseType === 'blob' || response.config.responseType === 'arraybuffer') {
|
||||
touchSessionActivity()
|
||||
return response
|
||||
}
|
||||
if (res.code === 0) {
|
||||
// 生成进度轮询也属于用户正在使用系统,避免长任务结束后被误判为会话过期。
|
||||
touchSessionActivity()
|
||||
return res.data
|
||||
}
|
||||
// 业务错误
|
||||
|
||||
@@ -298,6 +298,7 @@ function requiredPermission(path: string, explicit?: unknown) {
|
||||
// 全局守卫:登录校验 + 会话超时
|
||||
router.beforeEach((to, _from, next) => {
|
||||
const auth = useAuthStore()
|
||||
auth.syncSession()
|
||||
document.title = to.meta.title ? `${to.meta.title} - 远光软件微调平台` : '远光软件微调平台'
|
||||
|
||||
if (to.meta.public) {
|
||||
|
||||
@@ -3,6 +3,13 @@ import { ref, computed } from 'vue'
|
||||
import { login as loginApi } from '@/api/modules/system'
|
||||
import { SESSION_TIMEOUT } from '@/constants'
|
||||
import type { PermissionCode, SystemUser } from '@/types'
|
||||
import {
|
||||
clearSessionActivity,
|
||||
sessionActivityTime,
|
||||
startSessionActivity,
|
||||
syncSessionActivity,
|
||||
touchSessionActivity,
|
||||
} from '@/utils/sessionActivity'
|
||||
|
||||
const USER_STORAGE_KEY = 'currentUser'
|
||||
|
||||
@@ -60,7 +67,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
if (currentUser.value?.role === 'operator') return '操作员'
|
||||
return '观察员'
|
||||
})
|
||||
const loginTime = ref<number>(parseInt(localStorage.getItem('loginTime') || '0', 10) || 0)
|
||||
const loginTime = sessionActivityTime
|
||||
|
||||
const isLoggedIn = computed(() => {
|
||||
if (!loginTime.value) return false
|
||||
@@ -71,10 +78,9 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
async function login(user: string, password: string) {
|
||||
const response = await loginApi(user, password)
|
||||
currentUser.value = response.user
|
||||
loginTime.value = Date.now()
|
||||
startSessionActivity()
|
||||
localStorage.setItem('username', response.user.username)
|
||||
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(response.user))
|
||||
localStorage.setItem('loginTime', String(loginTime.value))
|
||||
}
|
||||
|
||||
/** 检查当前账号是否拥有指定模块权限。 */
|
||||
@@ -85,19 +91,20 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
|
||||
/** 续期会话(活跃时刷新) */
|
||||
function refresh() {
|
||||
if (isLoggedIn.value) {
|
||||
loginTime.value = Date.now()
|
||||
localStorage.setItem('loginTime', String(loginTime.value))
|
||||
}
|
||||
if (currentUser.value) touchSessionActivity()
|
||||
}
|
||||
|
||||
/** 在路由判断前吸收其他标签页写入的最后活跃时间。 */
|
||||
function syncSession() {
|
||||
syncSessionActivity()
|
||||
}
|
||||
|
||||
/** 退出 */
|
||||
function logout() {
|
||||
currentUser.value = null
|
||||
loginTime.value = 0
|
||||
clearSessionActivity()
|
||||
localStorage.removeItem('username')
|
||||
localStorage.removeItem(USER_STORAGE_KEY)
|
||||
localStorage.removeItem('loginTime')
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -110,6 +117,7 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
hasPermission,
|
||||
login,
|
||||
refresh,
|
||||
syncSession,
|
||||
logout,
|
||||
}
|
||||
})
|
||||
|
||||
32
frontend/src/utils/sessionActivity.ts
Normal file
32
frontend/src/utils/sessionActivity.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
const LOGIN_TIME_STORAGE_KEY = 'loginTime'
|
||||
|
||||
function storedActivityTime() {
|
||||
return Number.parseInt(localStorage.getItem(LOGIN_TIME_STORAGE_KEY) || '0', 10) || 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话按“最后活跃时间”计算,而不是从首次登录起固定倒计时。
|
||||
* 该 ref 被认证 store 与请求层共享,确保 API 活动可以立即影响路由守卫。
|
||||
*/
|
||||
export const sessionActivityTime = ref(storedActivityTime())
|
||||
|
||||
export function startSessionActivity() {
|
||||
sessionActivityTime.value = Date.now()
|
||||
localStorage.setItem(LOGIN_TIME_STORAGE_KEY, String(sessionActivityTime.value))
|
||||
}
|
||||
|
||||
export function touchSessionActivity() {
|
||||
if (!sessionActivityTime.value) return
|
||||
startSessionActivity()
|
||||
}
|
||||
|
||||
export function syncSessionActivity() {
|
||||
sessionActivityTime.value = storedActivityTime()
|
||||
}
|
||||
|
||||
export function clearSessionActivity() {
|
||||
sessionActivityTime.value = 0
|
||||
localStorage.removeItem(LOGIN_TIME_STORAGE_KEY)
|
||||
}
|
||||
Reference in New Issue
Block a user