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
+11 -10
View File
@@ -302,7 +302,8 @@ import { message } from 'ant-design-vue'
import dayjs from 'dayjs'
import { computed, onMounted, reactive, ref } from 'vue'
import { OpsApiError, http } from '@/lib/http'
import { showOpsError } from '@/lib/errors'
import { http } from '@/lib/http'
interface AdminUserRow {
id: number
@@ -447,7 +448,7 @@ async function reload() {
rows.value = result.items
total.value = result.total
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
} finally {
loading.value = false
}
@@ -462,7 +463,7 @@ async function loadMeta() {
plans.value = planResult
roles.value = roleResult
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
}
}
@@ -526,7 +527,7 @@ async function submitCreate() {
resetCreate()
void reload()
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
} finally {
createLoading.value = false
}
@@ -608,7 +609,7 @@ async function submitEdit() {
editOpen.value = false
void reload()
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
} finally {
editLoading.value = false
}
@@ -624,7 +625,7 @@ async function resetPlanUsage(row: AdminUserRow) {
rows.value = rows.value.map((item) => (item.id === row.id ? result.user : item))
void reload()
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
} finally {
resetUsageLoadingId.value = null
}
@@ -644,7 +645,7 @@ async function resetLoginLock(row: AdminUserRow) {
message.warning('未发现登录锁 Redis key,请检查 ops-api 与 admin-web 使用的 Redis 地址和 DB 是否一致')
}
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
} finally {
resetLoginLockLoadingId.value = null
}
@@ -675,7 +676,7 @@ async function submitResetPassword() {
message.success('密码已重置')
resetOpen.value = false
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
} finally {
resetLoading.value = false
}
@@ -711,7 +712,7 @@ async function submitKol() {
kolOpen.value = false
void reload()
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
} finally {
kolLoading.value = false
}
@@ -724,7 +725,7 @@ async function toggleStatus(row: AdminUserRow) {
message.success(next === 'active' ? '已启用' : '已停用')
void reload()
} catch (error) {
if (error instanceof OpsApiError) message.error(error.detail || error.message)
showOpsError(error)
}
}