优化:没有权限的进修默认回到登录页面
This commit is contained in:
parent
1a63d2d6e1
commit
8456ba90c8
@ -1,5 +1,36 @@
|
||||
import { i18n } from '@/plugins/i18n'
|
||||
|
||||
export type HttpUnauthorizedHandler = () => void
|
||||
|
||||
let httpUnauthorizedHandler: HttpUnauthorizedHandler | null = null
|
||||
|
||||
/**
|
||||
* 注册 HTTP 401 时的处理(如清除登录态并跳转登录页)。
|
||||
* 在 main.ts 中 app.use(pinia)、app.use(router) 之后调用,避免循环依赖。
|
||||
*/
|
||||
export function setHttpUnauthorizedHandler(handler: HttpUnauthorizedHandler | null) {
|
||||
httpUnauthorizedHandler = handler
|
||||
}
|
||||
|
||||
function notifyHttpUnauthorized() {
|
||||
try {
|
||||
httpUnauthorizedHandler?.()
|
||||
} catch (e) {
|
||||
console.error('[request] httpUnauthorizedHandler failed', e)
|
||||
}
|
||||
}
|
||||
|
||||
async function parseJsonBody<T>(res: Response): Promise<T> {
|
||||
if (res.status === 401) {
|
||||
notifyHttpUnauthorized()
|
||||
throw new Error(`HTTP 401: ${res.statusText}`)
|
||||
}
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
|
||||
}
|
||||
return res.json() as Promise<T>
|
||||
}
|
||||
|
||||
/** 请求基础 URL,默认 https://api.xtrader.vip,可通过环境变量 VITE_API_BASE_URL 覆盖 */
|
||||
export const BASE_URL =
|
||||
(import.meta as { env?: { VITE_API_BASE_URL?: string } }).env?.VITE_API_BASE_URL ??
|
||||
@ -77,10 +108,7 @@ export async function get<T = unknown>(
|
||||
...config?.headers,
|
||||
}
|
||||
const res = await fetch(url.toString(), { method: 'GET', headers })
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
|
||||
}
|
||||
return res.json() as Promise<T>
|
||||
return parseJsonBody<T>(res)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,10 +130,7 @@ export async function post<T = unknown>(
|
||||
headers,
|
||||
body: body !== undefined ? JSON.stringify(body) : undefined,
|
||||
})
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
|
||||
}
|
||||
return res.json() as Promise<T>
|
||||
return parseJsonBody<T>(res)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,10 +154,7 @@ export async function uploadFile<T = unknown>(
|
||||
headers,
|
||||
body: form,
|
||||
})
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
|
||||
}
|
||||
return res.json() as Promise<T>
|
||||
return parseJsonBody<T>(res)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,10 +176,7 @@ export async function put<T = unknown>(
|
||||
headers,
|
||||
body: body !== undefined ? JSON.stringify(body) : undefined,
|
||||
})
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
|
||||
}
|
||||
return res.json() as Promise<T>
|
||||
return parseJsonBody<T>(res)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,8 +198,5 @@ export async function httpDelete<T = unknown>(
|
||||
headers,
|
||||
body: body !== undefined ? JSON.stringify(body) : undefined,
|
||||
})
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}: ${res.statusText}`)
|
||||
}
|
||||
return res.json() as Promise<T>
|
||||
return parseJsonBody<T>(res)
|
||||
}
|
||||
|
||||
14
src/main.ts
14
src/main.ts
@ -5,11 +5,23 @@ import App from './App.vue'
|
||||
import router from './router'
|
||||
import vuetify from './plugins/vuetify'
|
||||
import { i18n } from './plugins/i18n'
|
||||
import { setHttpUnauthorizedHandler } from './api/request'
|
||||
import { useUserStore } from './stores/user'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
const pinia = createPinia()
|
||||
app.use(pinia)
|
||||
app.use(router)
|
||||
|
||||
setHttpUnauthorizedHandler(() => {
|
||||
const userStore = useUserStore(pinia)
|
||||
userStore.clearLocalSession()
|
||||
if (router.currentRoute.value.name !== 'login') {
|
||||
router.replace({ name: 'login' })
|
||||
}
|
||||
})
|
||||
|
||||
app.use(i18n)
|
||||
app.use(vuetify)
|
||||
|
||||
|
||||
@ -165,6 +165,11 @@ export const useUserStore = defineStore('user', () => {
|
||||
// 忽略失败,仍执行本地登出
|
||||
}
|
||||
}
|
||||
clearLocalSession()
|
||||
}
|
||||
|
||||
/** 仅清除本地登录态(如 HTTP 401),不请求服务端黑名单 */
|
||||
function clearLocalSession() {
|
||||
disconnectUserSocket()
|
||||
token.value = ''
|
||||
user.value = null
|
||||
@ -235,6 +240,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
balance,
|
||||
setUser,
|
||||
logout,
|
||||
clearLocalSession,
|
||||
getAuthHeaders,
|
||||
fetchUsdcBalance,
|
||||
fetchUserInfo,
|
||||
|
||||
@ -1454,8 +1454,6 @@ async function updateChartData() {
|
||||
ensureChartSeries()
|
||||
setChartData(data.value)
|
||||
nextTick(() => scheduleCryptoScrollToRealtime())
|
||||
cryptoWsUnsubscribe?.()
|
||||
cryptoWsUnsubscribe = null
|
||||
cryptoWsUnsubscribe = subscribeCryptoRealtime(sym, applyCryptoRealtimePoint)
|
||||
} finally {
|
||||
if (gen === cryptoLoadGeneration) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user