fix(frontend): 修复合并审阅发现的构建与契约问题
恢复 Vue TypeScript 生产构建,补齐可运行页面壳子,并修复文件树与 SSE 状态问题。 按 FastAPI Wire Contract 统一 Service DTO 映射,同时补充前端开发说明和问题修复复盘。
This commit is contained in:
@@ -1,36 +1,67 @@
|
||||
import apiClient from './apiClient'
|
||||
import type { ProviderConfig, ModelInfo } from '@/contracts'
|
||||
import type { ApiModelInfo, ApiProviderConfig, ModelCapability, ModelInfo, OperationResponse, ProviderConfig } from '@/contracts'
|
||||
|
||||
export async function listProviders(): Promise<ProviderConfig[]> {
|
||||
try {
|
||||
return await apiClient.get('/api/providers')
|
||||
} catch {
|
||||
return mockProviders
|
||||
function capabilityMap(capabilities: string[]): Partial<ModelCapability> {
|
||||
return Object.fromEntries(capabilities.map((capability) => [capability, true])) as Partial<ModelCapability>
|
||||
}
|
||||
|
||||
function toProvider(provider: ApiProviderConfig): ProviderConfig {
|
||||
return {
|
||||
provider_id: provider.provider_id,
|
||||
provider_type: provider.provider_type,
|
||||
name: provider.name,
|
||||
base_url: provider.base_url ?? undefined,
|
||||
default_model: provider.default_model ?? '',
|
||||
enabled: provider.enabled,
|
||||
capabilities: capabilityMap(provider.capabilities),
|
||||
credential_id: provider.credential_id ?? undefined,
|
||||
has_credential: Boolean(provider.credential_id) || provider.provider_type === 'mock',
|
||||
}
|
||||
}
|
||||
|
||||
function toModel(model: ApiModelInfo): ModelInfo {
|
||||
return { model_id: model.model, name: model.display_name, capabilities: capabilityMap(model.capabilities) }
|
||||
}
|
||||
|
||||
export async function listProviders(): Promise<ProviderConfig[]> {
|
||||
const response = await apiClient.get<{ items: ApiProviderConfig[] }>('/api/providers')
|
||||
return response.items.map(toProvider)
|
||||
}
|
||||
|
||||
export async function getProvider(providerId: string): Promise<ProviderConfig> {
|
||||
return apiClient.get(`/api/providers/${providerId}`)
|
||||
return toProvider(await apiClient.get<ApiProviderConfig>(`/api/providers/${providerId}`))
|
||||
}
|
||||
|
||||
export async function createProvider(data: Omit<ProviderConfig, 'provider_id'> & { api_key?: string }): Promise<ProviderConfig> {
|
||||
return apiClient.post('/api/providers', data)
|
||||
export async function createProvider(data: Omit<ProviderConfig, 'provider_id'>): Promise<ProviderConfig> {
|
||||
const response = await apiClient.post<ApiProviderConfig>('/api/providers', {
|
||||
provider_type: data.provider_type,
|
||||
name: data.name,
|
||||
base_url: data.base_url,
|
||||
default_model: data.default_model || null,
|
||||
credential_id: data.credential_id,
|
||||
enabled: data.enabled,
|
||||
})
|
||||
return toProvider(response)
|
||||
}
|
||||
|
||||
export async function updateProvider(providerId: string, data: Partial<ProviderConfig> & { api_key?: string }): Promise<ProviderConfig> {
|
||||
return apiClient.patch(`/api/providers/${providerId}`, data)
|
||||
export async function updateProvider(providerId: string, data: Partial<ProviderConfig>): Promise<ProviderConfig> {
|
||||
const response = await apiClient.patch<ApiProviderConfig>(`/api/providers/${providerId}`, {
|
||||
name: data.name,
|
||||
base_url: data.base_url,
|
||||
default_model: data.default_model,
|
||||
credential_id: data.credential_id,
|
||||
enabled: data.enabled,
|
||||
})
|
||||
return toProvider(response)
|
||||
}
|
||||
|
||||
export async function deleteProvider(providerId: string): Promise<void> {
|
||||
export async function deleteProvider(providerId: string): Promise<OperationResponse> {
|
||||
return apiClient.delete(`/api/providers/${providerId}`)
|
||||
}
|
||||
|
||||
export async function listModels(providerId: string): Promise<ModelInfo[]> {
|
||||
try {
|
||||
return await apiClient.get(`/api/providers/${providerId}/models`)
|
||||
} catch {
|
||||
return mockModels[providerId] || []
|
||||
}
|
||||
const response = await apiClient.get<{ provider_id: string; items: ApiModelInfo[] }>(`/api/providers/${providerId}/models`)
|
||||
return response.items.map(toModel)
|
||||
}
|
||||
|
||||
export interface TestResult {
|
||||
@@ -42,8 +73,8 @@ export interface TestResult {
|
||||
|
||||
export async function testProvider(providerId: string): Promise<TestResult> {
|
||||
try {
|
||||
const result = await apiClient.post<{ success: boolean; latency_ms: number }>('/api/providers/test', { provider_id: providerId })
|
||||
return { success: result.success, latency_ms: result.latency_ms }
|
||||
const result = await apiClient.post<{ success: boolean; latency_ms?: number | null; message: string }>('/api/providers/test', { provider_id: providerId })
|
||||
return { success: result.success, latency_ms: result.latency_ms ?? undefined, error_message: result.success ? undefined : result.message }
|
||||
} catch (e: any) {
|
||||
return { success: false, error_code: e.code || 'TEST_FAILED', error_message: e.message }
|
||||
}
|
||||
@@ -51,7 +82,7 @@ export async function testProvider(providerId: string): Promise<TestResult> {
|
||||
|
||||
export const mockProviders: ProviderConfig[] = [
|
||||
{
|
||||
provider_id: 'mock-provider',
|
||||
provider_id: 'mock',
|
||||
provider_type: 'mock',
|
||||
name: 'Mock Provider (测试)',
|
||||
default_model: 'mock-1',
|
||||
@@ -69,7 +100,7 @@ export const mockProviders: ProviderConfig[] = [
|
||||
},
|
||||
{
|
||||
provider_id: 'openai-compat-1',
|
||||
provider_type: 'openai-compatible',
|
||||
provider_type: 'openai_compatible',
|
||||
name: 'OpenAI 兼容服务',
|
||||
base_url: 'https://api.openai.com/v1',
|
||||
default_model: 'gpt-4o-mini',
|
||||
@@ -106,7 +137,7 @@ export const mockProviders: ProviderConfig[] = [
|
||||
]
|
||||
|
||||
export const mockModels: Record<string, ModelInfo[]> = {
|
||||
'mock-provider': [
|
||||
mock: [
|
||||
{
|
||||
model_id: 'mock-1',
|
||||
name: 'Mock Model v1',
|
||||
|
||||
Reference in New Issue
Block a user