fix(web): suppress duplicate toasts when auth session expires
Desktop Client Build / Resolve Build Metadata (push) Successful in 32s
Frontend CI / Frontend (push) Successful in 4m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Has been cancelled
Desktop Client Build / Build Desktop Client (push) Has been cancelled

Mark 401/refresh-failure errors as handled so per-view catch blocks fall
through silently while a single global "登录已过期" warning is shown.
Centralize ops-web error rendering via showOpsError.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 00:12:29 +08:00
parent 558646b166
commit ff2bb77cdd
22 changed files with 161 additions and 78 deletions
+10
View File
@@ -26,6 +26,7 @@ export class ApiClientError extends Error {
code: number
detail?: string
requestId?: string
handled?: boolean
constructor(input: {
message: string
@@ -33,6 +34,7 @@ export class ApiClientError extends Error {
status?: number
detail?: string
requestId?: string
handled?: boolean
}) {
super(input.message)
this.name = 'ApiClientError'
@@ -40,6 +42,7 @@ export class ApiClientError extends Error {
this.status = input.status
this.detail = input.detail
this.requestId = input.requestId
this.handled = input.handled
}
}
@@ -78,6 +81,11 @@ function unwrapEnvelope<T>(response: { data: ApiEnvelope<T> }): T {
return response.data.data
}
function markHandled(error: ApiClientError): ApiClientError {
error.handled = true
return error
}
export function createApiClient(options: CreateApiClientOptions = {}): ApiClient {
const client = axios.create({
baseURL: options.baseURL ?? '',
@@ -136,12 +144,14 @@ export function createApiClient(options: CreateApiClientOptions = {}): ApiClient
const normalizedRefreshError = normalizeError(refreshError)
if (normalizedRefreshError.status === 401) {
auth.clearTokens()
throw markHandled(normalizedRefreshError)
}
throw normalizedRefreshError
}
}
auth.clearTokens()
throw markHandled(normalizeError(error))
}
throw normalizeError(error)