diff --git a/frontend/src/features/settings/SettingsView.vue b/frontend/src/features/settings/SettingsView.vue new file mode 100644 index 0000000..4469f19 --- /dev/null +++ b/frontend/src/features/settings/SettingsView.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/frontend/src/features/themes/ThemesView.vue b/frontend/src/features/themes/ThemesView.vue new file mode 100644 index 0000000..35ec448 --- /dev/null +++ b/frontend/src/features/themes/ThemesView.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/frontend/src/stores/provider.ts b/frontend/src/stores/provider.ts index 2c317f9..f644a45 100644 --- a/frontend/src/stores/provider.ts +++ b/frontend/src/stores/provider.ts @@ -1,13 +1,14 @@ import { defineStore } from 'pinia' import { ref, computed } from 'vue' import type { ProviderConfig, ModelInfo } from '@/contracts' -import { listModels, listProviders, mockProviders, mockModels } from '@/services/providerService' +import { createProvider, deleteProvider as deleteProviderRequest, listModels, listProviders, mockProviders, mockModels, testProvider as testProviderRequest, updateProvider as updateProviderRequest } from '@/services/providerService' export const useProviderStore = defineStore('provider', () => { const providers = ref(mockProviders) const modelsByProvider = ref>(mockModels) const defaultProviderId = ref('mock') const isLoading = ref(false) + const error = ref(null) const enabledProviders = computed(() => providers.value.filter((p) => p.enabled)) const defaultProvider = computed(() => @@ -18,6 +19,9 @@ export const useProviderStore = defineStore('provider', () => { isLoading.value = true try { providers.value = await listProviders() + error.value = null + } catch (reason) { + error.value = reason instanceof Error ? reason.message : 'Provider 加载失败' } finally { isLoading.value = false } @@ -28,32 +32,27 @@ export const useProviderStore = defineStore('provider', () => { } async function addProvider(data: Omit) { - const newProvider: ProviderConfig = { - ...data, - provider_id: `prov-${Date.now()}`, - } + const newProvider = await createProvider(data) providers.value.push(newProvider) return newProvider } async function updateProvider(providerId: string, data: Partial) { - const p = providers.value.find((p) => p.provider_id === providerId) - if (p) Object.assign(p, data) + const updated = await updateProviderRequest(providerId, data) + const index = providers.value.findIndex((provider) => provider.provider_id === providerId) + if (index >= 0) providers.value[index] = updated } async function deleteProvider(providerId: string) { + await deleteProviderRequest(providerId) const idx = providers.value.findIndex((p) => p.provider_id === providerId) if (idx > -1) providers.value.splice(idx, 1) delete modelsByProvider.value[providerId] } async function testProvider(providerId: string): Promise<{ success: boolean; latency_ms?: number; error?: string }> { - await new Promise((r) => setTimeout(r, 1000)) - const p = providers.value.find((p) => p.provider_id === providerId) - if (p?.enabled && p.has_credential) { - return { success: true, latency_ms: 230 + Math.floor(Math.random() * 200) } - } - return { success: false, error: '认证失败,请检查 API Key' } + const result = await testProviderRequest(providerId) + return { success: result.success, latency_ms: result.latency_ms, error: result.error_message } } function setDefaultProvider(providerId: string) { @@ -67,6 +66,7 @@ export const useProviderStore = defineStore('provider', () => { enabledProviders, defaultProvider, isLoading, + error, loadProviders, loadModels, addProvider, diff --git a/frontend/src/stores/settings.ts b/frontend/src/stores/settings.ts index 81743fb..5266aba 100644 --- a/frontend/src/stores/settings.ts +++ b/frontend/src/stores/settings.ts @@ -2,6 +2,8 @@ import { defineStore } from 'pinia' import { ref } from 'vue' import type { AiCoreStatus, IndexStatus } from '@/contracts' import { mockIndexStatus } from '@/services/indexService' +import * as indexService from '@/services/indexService' +import * as systemService from '@/services/systemService' export const useSettingsStore = defineStore('settings', () => { // General @@ -37,6 +39,22 @@ export const useSettingsStore = defineStore('settings', () => { 'network.request': 'confirm', 'secrets.use': 'confirm', }) + const diagnosticsError = ref(null) + + async function loadDiagnostics() { + try { + const [health, status, index] = await Promise.all([ + systemService.healthCheck(), systemService.getStatus(), indexService.getIndexStatus(), + ]) + aiCoreStatus.value = health.status === 'ok' ? 'running' : 'error' + aiCoreVersion.value = status.version + indexStatus.value = index + diagnosticsError.value = null + } catch (reason) { + aiCoreStatus.value = 'error' + diagnosticsError.value = reason instanceof Error ? reason.message : '诊断信息加载失败' + } + } function setAutoSaveInterval(ms: number) { autoSaveInterval.value = ms @@ -63,9 +81,13 @@ export const useSettingsStore = defineStore('settings', () => { async function rebuildIndex(scope: 'full' | 'fts' | 'vector' = 'full') { indexStatus.value.status = 'indexing' - setTimeout(() => { - indexStatus.value.status = 'idle' - }, 3000) + try { + await indexService.rebuildIndex(scope) + indexStatus.value = await indexService.getIndexStatus() + } catch (reason) { + indexStatus.value.status = 'error' + indexStatus.value.error = reason instanceof Error ? reason.message : '索引重建失败' + } } return { @@ -83,6 +105,8 @@ export const useSettingsStore = defineStore('settings', () => { aiCoreAddress, indexStatus, permissionPolicy, + diagnosticsError, + loadDiagnostics, setAutoSaveInterval, setDefaultEditorMode, setPermission,