| class APIPanel { |
| constructor() { |
| |
| if (window.apiPanelInstance) { |
| console.warn('APIPanel: Instance already exists, returning existing one.'); |
| return window.apiPanelInstance; |
| } |
| console.log('APIPanel: Creating new instance.'); |
|
|
| |
| this.providerSelect = document.getElementById('api-provider'); |
| this.modelSelect = document.getElementById('api-model'); |
| this.apiKeyInput = document.getElementById('api-key'); |
| |
| this.submitButton = document.querySelector('#api-panel .api-submit-btn'); |
|
|
| |
| if (!this.providerSelect || !this.modelSelect || !this.apiKeyInput || !this.submitButton) { |
| console.error("APIPanel: One or more required DOM elements not found during construction."); |
| } |
|
|
| this.initialized = false; |
|
|
| this.handleSubmit = this.handleSubmit.bind(this); |
| this.updateModelOptions = this.updateModelOptions.bind(this); |
| if (this.providerSelect && this.modelSelect) { |
| this.updateModelOptions(); |
| } |
|
|
| window.apiPanelInstance = this; |
| console.log('APIPanel: New instance created.'); |
| } |
|
|
| init() { |
| if (this.initialized) { |
| console.log('APIPanel: Listeners already initialized, skipping.'); |
| return; |
| } |
| |
| if (!this.providerSelect || !this.modelSelect || !this.apiKeyInput || !this.submitButton) { |
| console.error("APIPanel: Cannot init listeners, required DOM elements missing."); |
| return; |
| } |
|
|
| console.log('APIPanel: Initializing event listeners.'); |
| this.setupEventListeners(); |
| this.initialized = true; |
| console.log('APIPanel: Event listeners initialized successfully.'); |
| } |
|
|
| setupEventListeners() { |
| |
| if (this.submitButton) { |
| this.submitButton.removeEventListener('click', this.handleSubmit); |
| |
| this.submitButton.addEventListener('click', this.handleSubmit); |
| console.log('APIPanel: Submit button listener attached.'); |
| } |
|
|
| |
| if (this.providerSelect) { |
| this.providerSelect.removeEventListener('change', this.updateModelOptions); |
| this.providerSelect.addEventListener('change', this.updateModelOptions); |
| console.log('APIPanel: Provider select listener attached.'); |
| } |
| } |
|
|
| updateModelOptions() { |
| if (!this.providerSelect || !this.modelSelect) { |
| console.warn('APIPanel: DOM elements missing for updateModelOptions.'); |
| return; |
| } |
|
|
| const provider = this.providerSelect.value; |
| const models = { |
| openai: ['gpt-4o-mini', 'gpt-4o', 'gpt-4'], |
| anthropic: ['claude-3.5-sonnet', 'claude-3.7-sonnet', 'claude-3.5-haiku'], |
| alibaba: ['qwen-turbo', 'qwen-max','qwen-plus'], |
| openrouter: ['gpt-4o-mini','gpt-4o','gemini-2.0-flash','claude-3.5-sonnet','deepseek-r1'] |
| }; |
|
|
| const currentModelValue = this.modelSelect.value; |
| this.modelSelect.innerHTML = ''; |
|
|
| if (models[provider] && models[provider].length > 0) { |
| models[provider].forEach(model => { |
| const option = document.createElement('option'); |
| option.value = model; |
| option.textContent = model; |
| this.modelSelect.appendChild(option); |
| }); |
| |
| if (models[provider].includes(currentModelValue)) { |
| this.modelSelect.value = currentModelValue; |
| } |
| } else { |
| |
| const option = document.createElement('option'); |
| option.textContent = 'No models available'; |
| option.disabled = true; |
| this.modelSelect.appendChild(option); |
| } |
| } |
|
|
| handleSubmit(event) { |
| |
| event.preventDefault(); |
| event.stopPropagation(); |
|
|
| if (APIPanel.isSubmitting) { |
| console.log('APIPanel: Submission in progress, ignoring duplicate click.'); |
| return; |
| } |
|
|
| |
| if (!this.providerSelect || !this.modelSelect || !this.apiKeyInput || !this.submitButton) { |
| console.error("APIPanel: Cannot handle submit, critical elements missing."); |
| alert(window.i18n?.get('internalError') ?? '内部错误,无法提交。'); |
| return; |
| } |
|
|
|
|
| |
| APIPanel.isSubmitting = true; |
| this.submitButton.disabled = true; |
| |
| const resetButton = () => { |
| APIPanel.isSubmitting = false; |
| if (this.submitButton) { |
| this.submitButton.disabled = false; |
| } |
| console.log('APIPanel: Submit button re-enabled.'); |
| }; |
|
|
|
|
| |
| const provider = this.providerSelect.value; |
| const model = this.modelSelect.value; |
| const apiKey = this.apiKeyInput.value.trim(); |
|
|
| |
| if (!provider || !model || !apiKey) { |
| const message = window.i18n?.get('fillAllFields') ?? '请填写所有字段!'; |
| alert(message); |
| resetButton(); |
| return; |
| } |
|
|
| const requestData = { |
| provider: provider, |
| model: model, |
| apiKey: apiKey |
| }; |
|
|
| console.log('APIPanel: Sending config data (key hidden):', { provider, model, apiKey: '***' }); |
|
|
| |
| fetch('/api/save-config', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(requestData) |
| }) |
| .then(response => { |
| if (response.ok) { |
| const message = window.i18n?.get('configSubmitted') ?? '配置已提交到服务器!'; |
| alert(message); |
| } else { |
| |
| response.text().then(text => { |
| console.error('APIPanel: Submit failed.', response.status, text); |
| const message = (window.i18n?.get('submitFailed') ?? '提交失败,请检查服务器状态。') + ` (Status: ${response.status})`; |
| alert(message); |
| }).catch(() => { |
| console.error('APIPanel: Submit failed.', response.status); |
| const message = (window.i18n?.get('submitFailed') ?? '提交失败,请检查服务器状态。') + ` (Status: ${response.status})`; |
| alert(message); |
| }); |
| } |
| }) |
| .catch(error => { |
| console.error('APIPanel: HTTP request failed:', error); |
| const message = window.i18n?.get('networkError') ?? '提交失败,请检查网络连接。'; |
| alert(message); |
| }) |
| .finally(() => { |
| |
| resetButton(); |
| }); |
| } |
| } |
|
|
| APIPanel.isSubmitting = false; |
| window.APIPanel = APIPanel; |
|
|