feat(frontend): 完成主题与设置页面

This commit is contained in:
2026-08-29 22:49:44 +08:00
parent 3239bab696
commit 5192a8b4e8
4 changed files with 143 additions and 16 deletions
+13 -13
View File
@@ -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<ProviderConfig[]>(mockProviders)
const modelsByProvider = ref<Record<string, ModelInfo[]>>(mockModels)
const defaultProviderId = ref('mock')
const isLoading = ref(false)
const error = ref<string | null>(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<ProviderConfig, 'provider_id'>) {
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<ProviderConfig>) {
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,
+27 -3
View File
@@ -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<string | null>(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,