fix(connection): hide reconnecting notification

This commit is contained in:
jxxghp
2026-08-28 07:06:43 +08:00
parent 42db5ab5a3
commit 2475a98f2b
2 changed files with 28 additions and 43 deletions
+7 -21
View File
@@ -9,49 +9,35 @@ const { connectionStatus, connectionReason } = useGlobalOfflineStatus()
const { isRestarting } = useSystemRestartStatus()
const shownConnectionPromptKeys = new Set<string>()
const isChecking = computed(() => connectionStatus.value === 'checking')
const statusTitle = computed(() => (isChecking.value ? t('app.connectionChecking') : t('app.serviceUnavailable')))
const statusMessage = computed(() => {
if (connectionReason.value === 'browser-offline') return t('app.browserOfflineMessage')
if (connectionReason.value === 'timeout') return t('app.serviceTimeoutMessage')
if (isChecking.value) return t('app.connectionCheckingMessage')
return t('app.serviceUnavailableMessage')
})
/** 拼接离线状态提示文案,供 Toast 或 Agent 助手气泡展示。 */
function buildConnectionPromptMessage() {
return `${statusTitle.value}${statusMessage.value}`
return `${t('app.serviceUnavailable')}${statusMessage.value}`
}
/** 根据当前连接状态选择 Toast 级别,Agent 助手可用时会由全局 Toast 路由接管。 */
/** 显示连接失败 ToastAgent 助手可用时会由全局 Toast 路由接管。 */
function showConnectionPrompt() {
const message = buildConnectionPromptMessage()
const options = {
timeout: isChecking.value ? 5000 : 7000,
}
if (isChecking.value) {
toast.warning(message, options)
return
}
toast.error(message, options)
toast.error(buildConnectionPromptMessage(), { timeout: 7000 })
}
/** 在同一轮连接异常内按状态去重提示,并在恢复在线后允许下一轮提示重新出现。 */
/** 仅在确认连接失败后提示,并在恢复在线后允许下一轮提示重新出现。 */
function handleConnectionStatusChange() {
if (connectionStatus.value === 'online') {
shownConnectionPromptKeys.clear()
return
}
if (connectionStatus.value !== 'offline') return
// 重启期间由重启进度弹窗承载反馈,避免离线提示与进度提示叠加。
if (isRestarting.value) return
const promptKey =
connectionStatus.value === 'checking'
? connectionStatus.value
: `${connectionStatus.value}:${connectionReason.value || 'unknown'}`
const promptKey = `${connectionStatus.value}:${connectionReason.value || 'unknown'}`
if (shownConnectionPromptKeys.has(promptKey)) return
@@ -7,7 +7,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const mocks = vi.hoisted(() => ({
error: vi.fn(),
isRestarting: { value: false },
warning: vi.fn(),
}))
vi.mock('@/composables/useSystemRestart', () => ({
@@ -20,7 +19,7 @@ vi.mock('vue-i18n', async importOriginal => ({
}))
vi.mock('vue-toastification', () => ({
useToast: () => ({ error: mocks.error, warning: mocks.warning }),
useToast: () => ({ error: mocks.error }),
}))
describe('OfflinePage', () => {
@@ -29,7 +28,6 @@ describe('OfflinePage', () => {
beforeEach(() => {
mocks.error.mockReset()
mocks.warning.mockReset()
mocks.isRestarting.value = false
status.markServerOnline()
wrapper = mount(OfflinePage)
@@ -40,19 +38,23 @@ describe('OfflinePage', () => {
status.markServerOnline()
})
it('同一轮 checking 状态只提示一次,并使用非阻断警告', async () => {
it('连接检查期间保持静默,确认离线后才显示错误', async () => {
status.markConnectionChecking('network-error')
await nextTick()
expect(mocks.warning).toHaveBeenCalledWith('app.connectionCheckingapp.connectionCheckingMessage', {
timeout: 5000,
})
expect(mocks.error).not.toHaveBeenCalled()
status.markConnectionChecking('timeout')
await nextTick()
expect(mocks.warning).toHaveBeenCalledTimes(1)
expect(mocks.error).not.toHaveBeenCalled()
status.markServerOffline('timeout')
await nextTick()
expect(mocks.error).toHaveBeenCalledWith('app.serviceUnavailableapp.serviceTimeoutMessage', {
timeout: 7000,
})
})
it('按离线原因显示错误,并允许不同离线状态分别提示', async () => {
@@ -76,42 +78,39 @@ describe('OfflinePage', () => {
expect(mocks.error).toHaveBeenNthCalledWith(3, 'app.serviceUnavailableapp.serviceUnavailableMessage', {
timeout: 7000,
})
expect(mocks.warning).not.toHaveBeenCalled()
})
it('在线恢复后允许下一轮 checking 再次提示', async () => {
status.markConnectionChecking()
it('在线恢复后允许下一轮离线提示重新出现', async () => {
status.markServerOffline()
await nextTick()
expect(mocks.warning).toHaveBeenCalledTimes(1)
expect(mocks.error).toHaveBeenCalledTimes(1)
status.markServerOnline()
await nextTick()
status.markConnectionChecking()
status.markServerOffline()
await nextTick()
expect(mocks.warning).toHaveBeenCalledTimes(2)
expect(mocks.error).toHaveBeenCalledTimes(2)
})
it('重启期间不提示,但在线恢复仍清空上一轮去重状态', async () => {
status.markConnectionChecking()
status.markServerOffline()
await nextTick()
expect(mocks.warning).toHaveBeenCalledTimes(1)
expect(mocks.error).toHaveBeenCalledTimes(1)
mocks.isRestarting.value = true
status.markServerOffline('timeout')
await nextTick()
expect(mocks.error).not.toHaveBeenCalled()
expect(mocks.warning).toHaveBeenCalledTimes(1)
expect(mocks.error).toHaveBeenCalledTimes(1)
status.markServerOnline()
await nextTick()
expect(mocks.error).not.toHaveBeenCalled()
expect(mocks.warning).toHaveBeenCalledTimes(1)
expect(mocks.error).toHaveBeenCalledTimes(1)
mocks.isRestarting.value = false
status.markConnectionChecking()
status.markServerOffline()
await nextTick()
expect(mocks.warning).toHaveBeenCalledTimes(2)
expect(mocks.error).toHaveBeenCalledTimes(2)
})
})