fix(frontend): 提示模型凭据缺失与鉴权失败

This commit is contained in:
2026-08-30 10:48:25 +08:00
parent dc5ee76bed
commit 31e29f25bb
4 changed files with 34 additions and 3 deletions
+15
View File
@@ -17,6 +17,7 @@ vi.mock('@/services/providerService', () => ({
import { useProviderStore } from './provider'
import { listModels, listProviderPresets, listProviders } from '@/services/providerService'
import { ApiErrorClass } from '@/services/apiClient'
const providers: ProviderConfig[] = [
{
@@ -27,6 +28,7 @@ const providers: ProviderConfig[] = [
default_model: '',
enabled: true,
capabilities: { chat: true },
credential_id: 'deepseek',
has_credential: true,
},
]
@@ -37,6 +39,7 @@ const presets: ProviderPreset[] = [
name: 'DeepSeek',
provider_type: 'openai_compatible',
base_url: 'https://api.deepseek.com',
default_credential_id: 'deepseek',
requires_credential: true,
},
]
@@ -76,4 +79,16 @@ describe('provider store model discovery', () => {
expect(store.modelLoadingByProvider.openai).toBe(false)
expect(store.modelErrorsByProvider.openai).toBe('认证失败')
})
it('explains how to inject a missing DeepSeek credential', async () => {
vi.mocked(listModels).mockRejectedValue(
new ApiErrorClass('PROVIDER_CREDENTIAL_MISSING', 'Credential is unavailable')
)
const store = useProviderStore()
await store.loadProviders()
await expect(store.loadModels('openai')).rejects.toThrow('Credential is unavailable')
expect(store.modelErrorsByProvider.openai).toContain('DEEPSEEK_API_KEY')
})
})
+12 -1
View File
@@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { ProviderConfig, ModelInfo, ProviderPreset } from '@/contracts'
import { createProvider, deleteProvider as deleteProviderRequest, listModels, listProviderPresets, listProviders, mockProviders, mockModels, testProvider as testProviderRequest, updateProvider as updateProviderRequest } from '@/services/providerService'
import { ApiErrorClass } from '@/services/apiClient'
export const useProviderStore = defineStore('provider', () => {
const providers = ref<ProviderConfig[]>(mockProviders)
@@ -48,7 +49,17 @@ export const useProviderStore = defineStore('provider', () => {
modelsByProvider.value[providerId] = uniqueModels
return uniqueModels
} catch (reason) {
const message = reason instanceof Error ? reason.message : '模型列表获取失败'
const provider = providers.value.find((item) => item.provider_id === providerId)
const credentialId = provider?.credential_id
let message = reason instanceof Error ? reason.message : '模型列表获取失败'
if (reason instanceof ApiErrorClass && reason.code === 'PROVIDER_CREDENTIAL_MISSING') {
const environmentName = credentialId === 'deepseek'
? 'DEEPSEEK_API_KEY'
: `AINOTE_CREDENTIAL_${credentialId?.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() || '<ID>'}`
message = `未找到凭据“${credentialId || '未设置'}”,请在启动 AI Core 前设置 ${environmentName}`
} else if (reason instanceof ApiErrorClass && reason.code === 'PROVIDER_AUTH_FAILED') {
message = `鉴权失败,请检查凭据“${credentialId || '未设置'}”对应的 API Key 是否有效。`
}
modelErrorsByProvider.value[providerId] = message
throw reason
} finally {