diff --git a/frontend/src/components/account/AccountTestModal.vue b/frontend/src/components/account/AccountTestModal.vue index b0e534d6..67409a7c 100644 --- a/frontend/src/components/account/AccountTestModal.vue +++ b/frontend/src/components/account/AccountTestModal.vue @@ -165,7 +165,6 @@ @@ -249,7 +248,7 @@ const availableModels = ref([]) const selectedModelId = ref('') const testPrompt = ref('') const loadingModels = ref(false) -let eventSource: EventSource | null = null +let abortController: AbortController | null = null const generatedImages = ref([]) const prioritizedGeminiModels = ['gemini-3.1-flash-image', 'gemini-2.5-flash-image', 'gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-3-flash-preview', 'gemini-3-pro-preview', 'gemini-2.0-flash'] const supportsGeminiImageTest = computed(() => { @@ -279,7 +278,7 @@ watch( resetState() await loadAvailableModels() } else { - closeEventSource() + abortStream() } } ) @@ -329,18 +328,14 @@ const resetState = () => { } const handleClose = () => { - // 防止在连接测试进行中关闭对话框 - if (status.value === 'connecting') { - return - } - closeEventSource() + abortStream() emit('close') } -const closeEventSource = () => { - if (eventSource) { - eventSource.close() - eventSource = null +const abortStream = () => { + if (abortController) { + abortController.abort() + abortController = null } } @@ -365,7 +360,9 @@ const startTest = async () => { addLine(t('admin.accounts.testAccountTypeLabel', { type: props.account.type }), 'text-gray-400') addLine('', 'text-gray-300') - closeEventSource() + abortStream() + + abortController = new AbortController() try { // Create EventSource for SSE @@ -381,7 +378,8 @@ const startTest = async () => { body: JSON.stringify({ model_id: selectedModelId.value, prompt: supportsGeminiImageTest.value ? testPrompt.value.trim() : '' - }) + }), + signal: abortController.signal }) if (!response.ok) { @@ -418,10 +416,15 @@ const startTest = async () => { } } } - } catch (error: any) { + } catch (error: unknown) { + if (error instanceof DOMException && error.name === 'AbortError') { + status.value = 'idle' + return + } status.value = 'error' - errorMessage.value = error.message || 'Unknown error' - addLine(`Error: ${errorMessage.value}`, 'text-red-400') + const msg = error instanceof Error ? error.message : 'Unknown error' + errorMessage.value = msg + addLine(`Error: ${msg}`, 'text-red-400') } } diff --git a/frontend/src/components/admin/account/AccountTestModal.vue b/frontend/src/components/admin/account/AccountTestModal.vue index b0e534d6..67409a7c 100644 --- a/frontend/src/components/admin/account/AccountTestModal.vue +++ b/frontend/src/components/admin/account/AccountTestModal.vue @@ -165,7 +165,6 @@ @@ -249,7 +248,7 @@ const availableModels = ref([]) const selectedModelId = ref('') const testPrompt = ref('') const loadingModels = ref(false) -let eventSource: EventSource | null = null +let abortController: AbortController | null = null const generatedImages = ref([]) const prioritizedGeminiModels = ['gemini-3.1-flash-image', 'gemini-2.5-flash-image', 'gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-3-flash-preview', 'gemini-3-pro-preview', 'gemini-2.0-flash'] const supportsGeminiImageTest = computed(() => { @@ -279,7 +278,7 @@ watch( resetState() await loadAvailableModels() } else { - closeEventSource() + abortStream() } } ) @@ -329,18 +328,14 @@ const resetState = () => { } const handleClose = () => { - // 防止在连接测试进行中关闭对话框 - if (status.value === 'connecting') { - return - } - closeEventSource() + abortStream() emit('close') } -const closeEventSource = () => { - if (eventSource) { - eventSource.close() - eventSource = null +const abortStream = () => { + if (abortController) { + abortController.abort() + abortController = null } } @@ -365,7 +360,9 @@ const startTest = async () => { addLine(t('admin.accounts.testAccountTypeLabel', { type: props.account.type }), 'text-gray-400') addLine('', 'text-gray-300') - closeEventSource() + abortStream() + + abortController = new AbortController() try { // Create EventSource for SSE @@ -381,7 +378,8 @@ const startTest = async () => { body: JSON.stringify({ model_id: selectedModelId.value, prompt: supportsGeminiImageTest.value ? testPrompt.value.trim() : '' - }) + }), + signal: abortController.signal }) if (!response.ok) { @@ -418,10 +416,15 @@ const startTest = async () => { } } } - } catch (error: any) { + } catch (error: unknown) { + if (error instanceof DOMException && error.name === 'AbortError') { + status.value = 'idle' + return + } status.value = 'error' - errorMessage.value = error.message || 'Unknown error' - addLine(`Error: ${errorMessage.value}`, 'text-red-400') + const msg = error instanceof Error ? error.message : 'Unknown error' + errorMessage.value = msg + addLine(`Error: ${msg}`, 'text-red-400') } }