优化登录状态错误时跳转页面到admin/login

This commit is contained in:
2026-05-11 15:19:33 +08:00
parent 2f8c4f4ced
commit 8c5b1d212a
2 changed files with 144 additions and 0 deletions

View File

@@ -34,6 +34,7 @@ function resolveAdminThinkLang(): string {
window.requests = []
window.tokenRefreshing = false
window.authRedirecting = false
const pendingMap = new Map()
const loadingInstance: LoadingInstance = {
target: null,
@@ -245,20 +246,119 @@ export default createAxios
* 处理异常
* @param {*} error
*/
/** 解析 axios 错误响应体(可能已是对象或 JSON 字符串) */
function normalizeAxiosErrorBody(data: unknown): anyObj | null {
if (data === undefined || data === null) {
return null
}
if (typeof data === 'string') {
try {
return JSON.parse(data) as anyObj
} catch {
return null
}
}
if (typeof data === 'object') {
return data as anyObj
}
return null
}
/**
* 后端未登录时通过 HTTP 303 + body.data.type === 'need login' 提示登录(见 Auth::LOGIN_RESPONSE_CODE
* Axios 将 303 视为失败,不会进入成功拦截器里对 code==303 的分支,需在此与之一致:清 token 并跳登录页。
*/
function redirectToLoginIfNeedLoginFromHttp303(error: any): boolean {
if (!error?.response || error.response.status !== 303) {
return false
}
const body = normalizeAxiosErrorBody(error.response.data)
if (!body || typeof body.data !== 'object' || body.data === null) {
return false
}
const needType = (body.data as anyObj).type
if (needType !== 'need login') {
return false
}
if (window.authRedirecting) {
return true
}
const isAdminAppFlag = isAdminApp()
const loginRouteName = isAdminAppFlag ? 'adminLogin' : 'userLogin'
if (router.currentRoute.value.name === loginRouteName) {
return true
}
window.authRedirecting = true
const adminInfo = useAdminInfo()
const userInfo = useUserInfo()
if (isAdminAppFlag) {
adminInfo.removeToken()
router.replace({ name: loginRouteName }).finally(() => {
window.authRedirecting = false
})
} else {
userInfo.removeToken()
const to = router.currentRoute.value.fullPath
router.replace({ name: loginRouteName, query: to ? { to } : {} }).finally(() => {
window.authRedirecting = false
})
}
return true
}
function httpErrorStatusHandle(error: any) {
// 处理被取消的请求
if (axios.isCancel(error)) return console.error(i18n.global.t('axios.Automatic cancellation due to duplicate request:') + error.message)
if (redirectToLoginIfNeedLoginFromHttp303(error)) {
return
}
let message = ''
if (error && error.response) {
switch (error.response.status) {
case 302:
message = i18n.global.t('axios.Interface redirected!')
break
case 303: {
const body303 = normalizeAxiosErrorBody(error.response.data)
const serverMsg303 = body303 && typeof body303.msg === 'string' ? body303.msg : ''
message = serverMsg303 !== '' ? serverMsg303 : i18n.global.t('axios.Interface redirected!')
break
}
case 400:
message = i18n.global.t('axios.Incorrect parameter!')
break
case 401:
message = i18n.global.t('axios.You do not have permission to operate!')
{
const data = error.response.data
const serverMsg = data && typeof data.msg === 'string' ? data.msg : ''
if (serverMsg) {
message = serverMsg
}
const isAdminAppFlag = isAdminApp()
const loginRouteName = isAdminAppFlag ? 'adminLogin' : 'userLogin'
if (!window.authRedirecting && router.currentRoute.value.name !== loginRouteName) {
window.authRedirecting = true
const adminInfo = useAdminInfo()
const userInfo = useUserInfo()
if (isAdminAppFlag) {
adminInfo.removeToken()
router.replace({ name: loginRouteName }).finally(() => {
window.authRedirecting = false
})
} else {
userInfo.removeToken()
const to = router.currentRoute.value.fullPath
router
.replace({ name: loginRouteName, query: to ? { to } : {} })
.finally(() => {
window.authRedirecting = false
})
}
}
}
break
case 403:
message = i18n.global.t('axios.You do not have permission to operate!')
@@ -271,6 +371,49 @@ function httpErrorStatusHandle(error: any) {
break
case 409:
message = i18n.global.t('axios.The same data already exists in the system!')
{
const data = error.response.data
const serverMsg = data && typeof data.msg === 'string' ? data.msg : ''
const authExpiredHints = [
'Token expiration',
'token expiration',
'登录态过期',
'请重新登录',
'Session expired',
'session expired',
'please login again',
'sila log masuk semula',
]
const looksLikeAuthExpired =
serverMsg !== '' && authExpiredHints.some((hint) => serverMsg.toLowerCase().includes(hint.toLowerCase()))
if (looksLikeAuthExpired) {
message = serverMsg
const isAdminAppFlag = isAdminApp()
const loginRouteName = isAdminAppFlag ? 'adminLogin' : 'userLogin'
if (!window.authRedirecting && router.currentRoute.value.name !== loginRouteName) {
window.authRedirecting = true
const adminInfo = useAdminInfo()
const userInfo = useUserInfo()
if (isAdminAppFlag) {
adminInfo.removeToken()
router.replace({ name: loginRouteName }).finally(() => {
window.authRedirecting = false
})
} else {
userInfo.removeToken()
const to = router.currentRoute.value.fullPath
router
.replace({ name: loginRouteName, query: to ? { to } : {} })
.finally(() => {
window.authRedirecting = false
})
}
}
}
}
break
case 500:
message = i18n.global.t('axios.Server internal error!')

View File

@@ -3,6 +3,7 @@ interface Window {
lazy: number
unique: number
tokenRefreshing: boolean
authRedirecting: boolean
requests: Function[]
eventSource: EventSource
loadLangHandle: Record<string, any>