fix(chat): 阻止页面卸载后的异步初始化修改模型选择
This commit is contained in:
@@ -64,3 +64,26 @@ it('preserves the selection when provider discovery fails', async () => {
|
||||
expect(wrapper.get('.error-banner').text()).toBe('offline')
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it.each(['providers', 'skills'])('ignores initialization after unmount while %s are loading', async source => {
|
||||
const chat = useChatStore()
|
||||
let finish!: () => void
|
||||
const pending = new Promise<void>(resolve => { finish = resolve })
|
||||
if (source === 'providers') vi.mocked(useProviderStore().loadProviders).mockReturnValueOnce(pending)
|
||||
else vi.mocked(useSkillStore().loadSkills).mockReturnValueOnce(pending)
|
||||
const first = mount(ChatView)
|
||||
first.unmount()
|
||||
finish()
|
||||
await flushPromises()
|
||||
expect(chat.selectedProviderId).toBe('')
|
||||
expect(chat.selectedModel).toBe('')
|
||||
expect(useProviderStore().loadModels).not.toHaveBeenCalled()
|
||||
|
||||
const returned = mount(ChatView)
|
||||
await flushPromises()
|
||||
expect(chat.selectedProviderId).toBe('a')
|
||||
expect(chat.selectedModel).toBe('a-default')
|
||||
await returned.get('textarea').setValue('hello')
|
||||
expect(returned.get('button.button-primary').attributes('disabled')).toBeUndefined()
|
||||
returned.unmount()
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { Citation } from '@/contracts'
|
||||
import { useChatStore } from '@/stores/chat'
|
||||
@@ -16,13 +16,15 @@ const workspaceStore = useWorkspaceStore()
|
||||
const editorStore = useEditorStore()
|
||||
const router = useRouter()
|
||||
const loadError = ref('')
|
||||
let disposed = false
|
||||
onBeforeUnmount(() => { disposed = true })
|
||||
|
||||
const availableModels = computed(() => providerStore.modelsByProvider[chatStore.selectedProviderId] ?? [])
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await Promise.all([providerStore.loadProviders(), skillStore.loadSkills()])
|
||||
if (providerStore.error) return
|
||||
if (disposed || providerStore.error) return
|
||||
const selected = providerStore.enabledProviders.find(p => p.provider_id === chatStore.selectedProviderId)
|
||||
if (!selected) {
|
||||
chatStore.selectedProviderId = providerStore.defaultProviderId
|
||||
@@ -30,6 +32,7 @@ onMounted(async () => {
|
||||
await refreshModels(selected.provider_id)
|
||||
}
|
||||
} catch (error) {
|
||||
if (disposed) return
|
||||
loadError.value = error instanceof Error ? error.message : '无法加载 AI 配置,请检查后端连接。'
|
||||
}
|
||||
})
|
||||
@@ -38,7 +41,7 @@ async function refreshModels(providerId: string) {
|
||||
loadError.value = ''
|
||||
if (!providerId) return
|
||||
try { await providerStore.loadModels(providerId) }
|
||||
catch (error) { if (chatStore.selectedProviderId === providerId) loadError.value = error instanceof Error ? error.message : '模型列表加载失败,请手动填写模型 ID。' }
|
||||
catch (error) { if (!disposed && chatStore.selectedProviderId === providerId) loadError.value = error instanceof Error ? error.message : '模型列表加载失败,请手动填写模型 ID。' }
|
||||
}
|
||||
|
||||
watch(() => chatStore.selectedProviderId, async (providerId) => {
|
||||
|
||||
Reference in New Issue
Block a user