import { ref } from 'vue' import { getConfig, updateConfig, testConnection, type Config } from '../api' /** * 服务商表单管理 Composable * * 提供服务商配置的完整管理功能: * - 加载/保存配置 * - 添加/编辑/删除服务商 * - 测试连接 * - 激活服务商 */ // 服务商数据类型 export interface Provider { type: string model: string base_url?: string api_key?: string api_key_masked?: string endpoint_type?: string high_concurrency?: boolean short_prompt?: boolean } // 服务商配置类型 export interface ProviderConfig { active_provider: string providers: Record } // 文本服务商表单类型 export interface TextProviderForm { name: string type: string api_key: string api_key_masked: string base_url: string model: string endpoint_type: string _has_api_key: boolean } // 图片服务商表单类型 export interface ImageProviderForm { name: string type: string api_key: string api_key_masked: string base_url: string model: string high_concurrency: boolean short_prompt: boolean endpoint_type: string _has_api_key: boolean } // 文本服务商类型选项 export const textTypeOptions = [ { value: 'google_gemini', label: 'Google Gemini' }, { value: 'openai_compatible', label: 'OpenAI 兼容接口' } ] // 图片服务商类型选项 export const imageTypeOptions = [ { value: 'google_genai', label: 'Google GenAI' }, { value: 'image_api', label: 'OpenAI 兼容接口' } ] /** * 服务商表单管理 Hook */ export function useProviderForm() { // 加载状态 const loading = ref(true) const saving = ref(false) const testingText = ref(false) const testingImage = ref(false) // 配置数据 const textConfig = ref({ active_provider: '', providers: {} }) const imageConfig = ref({ active_provider: '', providers: {} }) // 文本服务商弹窗状态 const showTextModal = ref(false) const editingTextProvider = ref(null) const textForm = ref(createEmptyTextForm()) // 图片服务商弹窗状态 const showImageModal = ref(false) const editingImageProvider = ref(null) const imageForm = ref(createEmptyImageForm()) /** * 创建空的文本服务商表单 */ function createEmptyTextForm(): TextProviderForm { return { name: '', type: 'openai_compatible', api_key: '', api_key_masked: '', base_url: '', model: '', endpoint_type: '/v1/chat/completions', _has_api_key: false } } /** * 创建空的图片服务商表单 */ function createEmptyImageForm(): ImageProviderForm { return { name: '', type: 'image_api', api_key: '', api_key_masked: '', base_url: '', model: '', high_concurrency: false, short_prompt: false, endpoint_type: '/v1/images/generations', _has_api_key: false } } /** * 加载配置 */ async function loadConfig() { loading.value = true try { const result = await getConfig() if (result.success && result.config) { textConfig.value = { active_provider: result.config.text_generation.active_provider, providers: result.config.text_generation.providers } imageConfig.value = result.config.image_generation } else { alert('加载配置失败: ' + (result.error || '未知错误')) } } catch (e) { alert('加载配置失败: ' + String(e)) } finally { loading.value = false } } /** * 自动保存配置 */ async function autoSaveConfig() { try { const config: Partial = { text_generation: { active_provider: textConfig.value.active_provider, providers: textConfig.value.providers }, image_generation: imageConfig.value } const result = await updateConfig(config) if (result.success) { // 重新加载配置以获取最新的脱敏 API Key await loadConfig() } } catch (e) { console.error('自动保存失败:', e) } } // ==================== 文本服务商操作 ==================== /** * 激活文本服务商 */ async function activateTextProvider(name: string) { textConfig.value.active_provider = name await autoSaveConfig() } /** * 打开添加文本服务商弹窗 */ function openAddTextModal() { editingTextProvider.value = null textForm.value = createEmptyTextForm() showTextModal.value = true } /** * 打开编辑文本服务商弹窗 */ function openEditTextModal(name: string, provider: Provider) { editingTextProvider.value = name textForm.value = { name: name, type: provider.type || 'openai_compatible', api_key: '', api_key_masked: provider.api_key_masked || '', base_url: provider.base_url || '', model: provider.model || '', endpoint_type: provider.endpoint_type || '/v1/chat/completions', _has_api_key: !!provider.api_key_masked } showTextModal.value = true } /** * 关闭文本服务商弹窗 */ function closeTextModal() { showTextModal.value = false editingTextProvider.value = null } /** * 保存文本服务商 */ async function saveTextProvider() { const name = editingTextProvider.value || textForm.value.name if (!name) { alert('请填写服务商名称') return } if (!textForm.value.type) { alert('请选择服务商类型') return } // 新增时必须填写 API Key if (!editingTextProvider.value && !textForm.value.api_key) { alert('请填写 API Key') return } const existingProvider = textConfig.value.providers[name] || {} const providerData: any = { type: textForm.value.type, model: textForm.value.model } // 如果填写了新的 API Key,使用新的;否则保留原有的 if (textForm.value.api_key) { providerData.api_key = textForm.value.api_key } else if (existingProvider.api_key) { providerData.api_key = existingProvider.api_key } if (textForm.value.base_url) { providerData.base_url = textForm.value.base_url } // 如果是 OpenAI 兼容接口,保存 endpoint_type if (textForm.value.type === 'openai_compatible') { providerData.endpoint_type = textForm.value.endpoint_type } textConfig.value.providers[name] = providerData closeTextModal() await autoSaveConfig() } /** * 删除文本服务商 */ async function deleteTextProvider(name: string) { if (confirm(`确定要删除服务商 "${name}" 吗?`)) { delete textConfig.value.providers[name] if (textConfig.value.active_provider === name) { textConfig.value.active_provider = '' } await autoSaveConfig() } } /** * 测试文本服务商连接(弹窗中) */ async function testTextConnection() { testingText.value = true try { const result = await testConnection({ type: textForm.value.type, provider_name: editingTextProvider.value || undefined, api_key: textForm.value.api_key || undefined, base_url: textForm.value.base_url, model: textForm.value.model }) if (result.success) { alert('✅ ' + result.message) } } catch (e: any) { alert('❌ 连接失败:' + (e.response?.data?.error || e.message)) } finally { testingText.value = false } } /** * 测试列表中的文本服务商 */ async function testTextProviderInList(name: string, provider: Provider) { try { const result = await testConnection({ type: provider.type, provider_name: name, api_key: undefined, base_url: provider.base_url, model: provider.model }) if (result.success) { alert('✅ ' + result.message) } } catch (e: any) { alert('❌ 连接失败:' + (e.response?.data?.error || e.message)) } } // ==================== 图片服务商操作 ==================== /** * 激活图片服务商 */ async function activateImageProvider(name: string) { imageConfig.value.active_provider = name await autoSaveConfig() } /** * 打开添加图片服务商弹窗 */ function openAddImageModal() { editingImageProvider.value = null imageForm.value = createEmptyImageForm() showImageModal.value = true } /** * 打开编辑图片服务商弹窗 */ function openEditImageModal(name: string, provider: Provider) { editingImageProvider.value = name imageForm.value = { name: name, type: provider.type || '', api_key: '', api_key_masked: provider.api_key_masked || '', base_url: provider.base_url || '', model: provider.model || '', high_concurrency: provider.high_concurrency || false, short_prompt: provider.short_prompt || false, endpoint_type: provider.endpoint_type || '/v1/images/generations', _has_api_key: !!provider.api_key_masked } showImageModal.value = true } /** * 关闭图片服务商弹窗 */ function closeImageModal() { showImageModal.value = false editingImageProvider.value = null } /** * 保存图片服务商 */ async function saveImageProvider() { const name = editingImageProvider.value || imageForm.value.name if (!name) { alert('请填写服务商名称') return } if (!imageForm.value.type) { alert('请填写服务商类型') return } // 新增时必须填写 API Key if (!editingImageProvider.value && !imageForm.value.api_key) { alert('请填写 API Key') return } const existingProvider = imageConfig.value.providers[name] || {} const providerData: any = { type: imageForm.value.type, model: imageForm.value.model, high_concurrency: imageForm.value.high_concurrency, short_prompt: imageForm.value.short_prompt } // 如果是 OpenAI 兼容接口,保存 endpoint_type if (imageForm.value.type === 'image_api') { providerData.endpoint_type = imageForm.value.endpoint_type } // 如果填写了新的 API Key,使用新的;否则保留原有的 if (imageForm.value.api_key) { providerData.api_key = imageForm.value.api_key } else if (existingProvider.api_key) { providerData.api_key = existingProvider.api_key } if (imageForm.value.base_url) { providerData.base_url = imageForm.value.base_url } imageConfig.value.providers[name] = providerData closeImageModal() await autoSaveConfig() } /** * 删除图片服务商 */ async function deleteImageProvider(name: string) { if (confirm(`确定要删除服务商 "${name}" 吗?`)) { delete imageConfig.value.providers[name] if (imageConfig.value.active_provider === name) { imageConfig.value.active_provider = '' } await autoSaveConfig() } } /** * 测试图片服务商连接(弹窗中) */ async function testImageConnection() { testingImage.value = true try { const result = await testConnection({ type: imageForm.value.type, provider_name: editingImageProvider.value || undefined, api_key: imageForm.value.api_key || undefined, base_url: imageForm.value.base_url, model: imageForm.value.model }) if (result.success) { alert('✅ ' + result.message) } } catch (e: any) { alert('❌ 连接失败:' + (e.response?.data?.error || e.message)) } finally { testingImage.value = false } } /** * 测试列表中的图片服务商 */ async function testImageProviderInList(name: string, provider: Provider) { try { const result = await testConnection({ type: provider.type, provider_name: name, api_key: undefined, base_url: provider.base_url, model: provider.model }) if (result.success) { alert('✅ ' + result.message) } } catch (e: any) { alert('❌ 连接失败:' + (e.response?.data?.error || e.message)) } } /** * 更新文本表单数据 */ function updateTextForm(data: TextProviderForm) { textForm.value = data } /** * 更新图片表单数据 */ function updateImageForm(data: ImageProviderForm) { imageForm.value = data } return { // 状态 loading, saving, testingText, testingImage, // 配置数据 textConfig, imageConfig, // 文本服务商弹窗 showTextModal, editingTextProvider, textForm, // 图片服务商弹窗 showImageModal, editingImageProvider, imageForm, // 方法 loadConfig, // 文本服务商方法 activateTextProvider, openAddTextModal, openEditTextModal, closeTextModal, saveTextProvider, deleteTextProvider, testTextConnection, testTextProviderInList, updateTextForm, // 图片服务商方法 activateImageProvider, openAddImageModal, openEditImageModal, closeImageModal, saveImageProvider, deleteImageProvider, testImageConnection, testImageProviderInList, updateImageForm } }