feat(frontend): 完成主题与设置页面
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user