feat(frontend): 搭建桌面端基础界面与 Workspace

- App Shell 壳层:主导航、次导航、Title Bar、状态栏
- Vault 入口页:最近 Vault、打开/创建 Vault、AI Core 状态
- Workspace 与文件树:浏览、打开、创建笔记/文件夹
- Design Token:浅色/深色主题 CSS Variables
- Contracts / Service / Store / Router 基础架构
- 统一 ApiClient 与 SseClient,对接后端 API 契约
This commit is contained in:
2026-08-29 10:36:16 +08:00
parent 694c1b27c1
commit f9efc4f4a2
42 changed files with 8044 additions and 167 deletions
+80
View File
@@ -0,0 +1,80 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { ProviderConfig, ModelInfo } from '@/contracts'
import { mockProviders, mockModels } from '@/services/providerService'
export const useProviderStore = defineStore('provider', () => {
const providers = ref<ProviderConfig[]>(mockProviders)
const modelsByProvider = ref<Record<string, ModelInfo[]>>(mockModels)
const defaultProviderId = ref('mock-provider')
const isLoading = ref(false)
const enabledProviders = computed(() => providers.value.filter((p) => p.enabled))
const defaultProvider = computed(() =>
providers.value.find((p) => p.provider_id === defaultProviderId.value) || null
)
async function loadProviders() {
isLoading.value = true
try {
const { listProviders } = await import('@/services/providerService')
providers.value = await listProviders()
} finally {
isLoading.value = false
}
}
async function loadModels(providerId: string) {
const { listModels } = await import('@/services/providerService')
modelsByProvider.value[providerId] = await listModels(providerId)
}
async function addProvider(data: Omit<ProviderConfig, 'provider_id'> & { api_key?: string }) {
const newProvider: ProviderConfig = {
...data,
provider_id: `prov-${Date.now()}`,
}
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)
}
async function deleteProvider(providerId: string) {
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' }
}
function setDefaultProvider(providerId: string) {
defaultProviderId.value = providerId
}
return {
providers,
modelsByProvider,
defaultProviderId,
enabledProviders,
defaultProvider,
isLoading,
loadProviders,
loadModels,
addProvider,
updateProvider,
deleteProvider,
testProvider,
setDefaultProvider,
}
})