前端热更新

This commit is contained in:
biss committed 2026-08-21 22:02:33 +08:00
1 parent af88732a07
commit 5b95fe8f40
3 files changed
+19 -16

No files matched your search

+11 -4
View File
@@ -8,6 +8,13 @@ import {
refreshIfNeeded,
} from '../auth/session'
declare module 'axios' {
export interface AxiosRequestConfig {
// Public kiosk pages must remain usable when this browser has an expired login session.
skipAuthSession?: boolean
}
}
const http = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL ?? '/api',
timeout: 15000,
@@ -20,12 +27,12 @@ http.interceptors.request.use(async (config) => {
config.url?.endsWith('/auth/logout') ||
config.url?.endsWith('/auth/sso/exchange') ||
config.url?.endsWith('/auth/sso/bind')
if (!isAuthenticationRequest) {
if (!isAuthenticationRequest && !config.skipAuthSession) {
const activeToken = await refreshIfNeeded(true)
if (activeToken) markActivity()
}
const token = localStorage.getItem(authStorageKeys.token)
if (token) config.headers.Authorization = `Bearer ${token}`
if (token && !config.skipAuthSession) config.headers.Authorization = `Bearer ${token}`
return config
})
@@ -40,7 +47,7 @@ http.interceptors.response.use(
error.config?.url?.endsWith('/auth/sso/bind')
const retryableConfig = error.config as
(typeof error.config & { _jiaowuRetried?: boolean }) | undefined
if (error.response?.status === 401 && !isAuthenticationRequest &&
if (error.response?.status === 401 && !isAuthenticationRequest && !error.config?.skipAuthSession &&
!retryableConfig?._jiaowuRetried) {
const token = await refreshAuthSession()
if (token && retryableConfig) {
@@ -49,7 +56,7 @@ http.interceptors.response.use(
return http.request(retryableConfig)
}
}
if (error.response?.status === 401 && !isAuthenticationRequest) {
if (error.response?.status === 401 && !isAuthenticationRequest && !error.config?.skipAuthSession) {
clearAuthSession()
goLogin(location.pathname + location.search + location.hash)
}
+7 -11
View File
@@ -18,10 +18,8 @@ interface AppUpdateCheckResponse {
const updateChannel =
import.meta.env.VITE_APP_UPDATE_CHANNEL?.trim() || 'production'
const foregroundCheckInterval = 5 * 60 * 1000
let checkInProgress: Promise<void> | undefined
let lastCheckedAt = 0
function absoluteApiUrl(relativePath: string) {
const configuredBase = String(http.defaults.baseURL ?? '/api')
@@ -36,9 +34,7 @@ function absoluteApiUrl(relativePath: string) {
async function checkForAppUpdate() {
if (checkInProgress) return checkInProgress
if (!navigator.onLine || Date.now() - lastCheckedAt < foregroundCheckInterval) {
return
}
if (!navigator.onLine) return
checkInProgress = (async () => {
try {
@@ -64,6 +60,9 @@ async function checkForAppUpdate() {
nativeVersion: current.native,
currentVersion,
},
// Update discovery is deliberately public. Do not delay startup for a
// token refresh or send a stale Authorization header to this endpoint.
skipAuthSession: true,
timeout: 15000,
},
)
@@ -96,7 +95,6 @@ async function checkForAppUpdate() {
// OTA failure must never stop users from entering the bundled application.
console.warn('[app-update] update check failed', error)
} finally {
lastCheckedAt = Date.now()
checkInProgress = undefined
}
})()
@@ -116,10 +114,8 @@ export async function initializeAppUpdates() {
console.warn('[app-update] bundle readiness confirmation failed', error)
}
// Every cold start checks the latest public release immediately. A bundle
// downloaded here is activated when the app is next launched.
void checkForAppUpdate()
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
void checkForAppUpdate()
}
})
window.addEventListener('online', () => void checkForAppUpdate())
}
+1 -1
View File
@@ -23,7 +23,7 @@ async function load() {
if (loading) return
loading = true
try {
data.value = (await http.get(`/venue-displays/${type.value}s/${id.value}`)).data
data.value = (await http.get(`/venue-displays/${type.value}s/${id.value}`, { skipAuthSession: true })).data
await nextTick()
fitPage()
} finally {