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