const API_URL = window.location.origin; let apiKey = null; let currentRole = null; let ws = null; let statsIntervalId = null; let wsPingIntervalId = null; const loginScreen = document.getElementById('login-screen'); const adminScreen = document.getElementById('admin-screen'); const userScreen = document.getElementById('user-screen'); const loginForm = document.getElementById('login-form'); const loginError = document.getElementById('login-error'); const apiKeyInput = document.getElementById('api-key-input'); const logoutButtons = document.querySelectorAll('.logout-btn'); const adminUserInfo = document.getElementById('admin-user-info'); const userInfo = document.getElementById('user-info'); const createKeyBtn = document.getElementById('create-key-btn'); const createKeyModal = document.getElementById('create-key-modal'); const createKeyForm = document.getElementById('create-key-form'); const cancelCreateBtn = document.getElementById('cancel-create-btn'); const keyDetailsModal = document.getElementById('key-details-modal'); const closeDetailsBtn = document.getElementById('close-details-btn'); const createServerKeyModal = document.getElementById('create-server-key-modal'); const createServerKeyForm = document.getElementById('create-server-key-form'); const cancelServerKeyBtn = document.getElementById('cancel-server-key-btn'); const refreshKeyModal = document.getElementById('refresh-key-modal'); const cancelRefreshBtn = document.getElementById('cancel-refresh-btn'); const confirmRefreshBtn = document.getElementById('confirm-refresh-btn'); const adminKeysList = document.getElementById('admin-keys-list'); const userKeysList = document.getElementById('user-keys-list'); const commandForm = document.getElementById('command-form'); const commandInput = document.getElementById('command-input'); const commandHistory = document.getElementById('command-history'); const userEventsList = document.getElementById('user-events-list'); const aiConfigForm = document.getElementById('ai-config-form'); const aiApiUrlInput = document.getElementById('ai-api-url'); const aiModelIdInput = document.getElementById('ai-model-id'); const aiApiKeyInput = document.getElementById('ai-api-key'); const aiApiKeyHint = document.getElementById('ai-api-key-hint'); const aiSystemPromptInput = document.getElementById('ai-system-prompt'); const aiEnabledCheckbox = document.getElementById('ai-enabled'); const aiTestBtn = document.getElementById('ai-test-btn'); const aiDeleteBtn = document.getElementById('ai-delete-btn'); const aiProviderSelect = document.getElementById('ai-provider-select'); const systemLogs = document.getElementById('system-logs'); const clearLogsBtn = document.getElementById('clear-logs-btn'); // AI Providers Configuration const AI_PROVIDERS = { openai: { url: 'https://api.openai.com/v1/chat/completions', model: 'gpt-3.5-turbo' }, siliconflow: { url: 'https://api.siliconflow.cn/v1/chat/completions', model: 'deepseek-ai/DeepSeek-R1' }, gemini: { url: 'https://generativelanguage.googleapis.com/v1beta/openai/chat/completions', model: 'gemini-2.0-flash-exp' }, deepseek: { url: 'https://api.deepseek.com/chat/completions', model: 'deepseek-chat' }, moonshot: { url: 'https://api.moonshot.cn/v1/chat/completions', model: 'moonshot-v1-8k' }, custom: { url: '', model: '' } }; if (aiProviderSelect) { aiProviderSelect.addEventListener('change', (e) => { const provider = AI_PROVIDERS[e.target.value]; if (provider && e.target.value !== 'custom') { if (aiApiUrlInput) aiApiUrlInput.value = provider.url; if (aiModelIdInput) aiModelIdInput.value = provider.model; } }); } const aiStatus = document.getElementById('ai-status'); // Theme Management const themeToggleBtns = document.querySelectorAll('.theme-toggle'); function initTheme() { const savedTheme = localStorage.getItem('theme') || 'dark'; document.documentElement.setAttribute('data-theme', savedTheme); updateThemeIcons(savedTheme); } function toggleTheme() { const currentTheme = document.documentElement.getAttribute('data-theme'); const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; document.documentElement.setAttribute('data-theme', newTheme); localStorage.setItem('theme', newTheme); updateThemeIcons(newTheme); } function updateThemeIcons(theme) { const text = theme === 'dark' ? '浅色模式' : '深色模式'; themeToggleBtns.forEach(btn => { btn.textContent = text; }); } // Initialize Theme initTheme(); themeToggleBtns.forEach(btn => { btn.addEventListener('click', toggleTheme); }); function authHeaders(key) { return { Authorization: `Bearer ${key}` }; } function resetSession() { apiKey = null; currentRole = null; if (statsIntervalId) { clearInterval(statsIntervalId); statsIntervalId = null; } if (wsPingIntervalId) { clearInterval(wsPingIntervalId); wsPingIntervalId = null; } if (ws) { ws.close(); ws = null; } if (loginScreen) { loginScreen.classList.remove('hidden'); } if (adminScreen) { adminScreen.classList.add('hidden'); } if (userScreen) { userScreen.classList.add('hidden'); } } async function detectRole(key) { const adminResponse = await fetch(`${API_URL}/manage/keys`, { headers: authHeaders(key) }); if (adminResponse.ok) { return 'admin'; } const regularResponse = await fetch(`${API_URL}/manage/keys/server-keys`, { headers: authHeaders(key) }); if (regularResponse.ok) { return 'regular'; } return null; } function showAdminPanel() { currentRole = 'admin'; loginScreen.classList.add('hidden'); userScreen.classList.add('hidden'); adminScreen.classList.remove('hidden'); if (adminUserInfo) { adminUserInfo.textContent = 'Admin Key'; } loadAdminKeys(); loadAIConfig(); } function showUserPanel() { currentRole = 'regular'; loginScreen.classList.add('hidden'); adminScreen.classList.add('hidden'); userScreen.classList.remove('hidden'); if (userInfo) { userInfo.textContent = 'Regular Key'; } loadUserServerKeys(); loadStats(); connectWebSocket(); statsIntervalId = setInterval(loadStats, 5000); } async function loadAdminKeys() { if (!adminKeysList || !apiKey) { return; } try { const response = await fetch(`${API_URL}/manage/keys`, { headers: authHeaders(apiKey) }); if (response.ok) { const keys = await response.json(); renderAdminKeys(keys); } else { adminKeysList.innerHTML = '

Failed to load keys.

'; } } catch (error) { adminKeysList.innerHTML = `

Failed to load keys: ${error.message}

`; } } async function loadUserServerKeys() { if (!userKeysList || !apiKey) { return; } try { const response = await fetch(`${API_URL}/manage/keys/server-keys`, { headers: authHeaders(apiKey) }); if (response.ok) { const keys = await response.json(); renderUserServerKeys(keys); } else { userKeysList.innerHTML = '

Failed to load server keys.

'; } } catch (error) { userKeysList.innerHTML = `

Failed to load server keys: ${error.message}

`; } } function renderAdminKeys(keys) { if (!adminKeysList) { return; } if (!keys.length) { adminKeysList.innerHTML = '

No API keys found.

'; return; } const adminKeys = keys.filter(k => k.keyType === 'admin'); const regularKeys = keys.filter(k => k.keyType === 'regular'); const serverKeys = keys.filter(k => k.keyType === 'server'); const serverKeysMap = {}; serverKeys.forEach(key => { if (key.regularKeyId) { if (!serverKeysMap[key.regularKeyId]) { serverKeysMap[key.regularKeyId] = []; } serverKeysMap[key.regularKeyId].push(key); } }); let html = ''; if (adminKeys.length > 0) { html += '

管理员密钥 (Admin Keys)

'; html += adminKeys.map(key => renderKeyCard(key)).join(''); } if (regularKeys.length > 0) { html += '

用户密钥 (Regular Keys)

'; html += regularKeys.map(regularKey => { const childServerKeys = serverKeysMap[regularKey.id] || []; return renderRegularKeyCard(regularKey, childServerKeys); }).join(''); } const linkedServerKeyIds = new Set(Object.values(serverKeysMap).flat().map(k => k.id)); const orphanServerKeys = serverKeys.filter(k => !linkedServerKeyIds.has(k.id)); if (orphanServerKeys.length > 0) { html += '

独立服务器密钥 (Orphan Server Keys)

'; html += orphanServerKeys.map(key => renderKeyCard(key)).join(''); } adminKeysList.innerHTML = html; } function toggleGroup(headerElement) { const nestedContainer = headerElement.nextElementSibling; const toggleIcon = headerElement.querySelector('.toggle-icon'); if (nestedContainer && nestedContainer.classList.contains('nested-server-keys')) { nestedContainer.classList.toggle('hidden'); if (toggleIcon) { toggleIcon.style.transform = nestedContainer.classList.contains('hidden') ? 'rotate(0deg)' : 'rotate(180deg)'; } } } function renderKeyCard(key, isNested = false) { return `

${key.keyType === 'admin' ? 'Admin' : key.keyType === 'server' ? 'Server' : 'Regular'} ${key.isActive ? '已启用' : '已停用'} ${key.name}

ID: ${key.id}

Prefix: ${key.keyPrefix}

${key.serverId ? `

Server ID: ${key.serverId}

` : ''}

创建时间: ${new Date(key.createdAt).toLocaleString()}

最后使用: ${key.lastUsed ? new Date(key.lastUsed).toLocaleString() : '从未'}

${key.isActive ? `` : `` }
`; } function renderRegularKeyCard(regularKey, childServerKeys = []) { return `

Regular ${regularKey.isActive ? '已启用' : '已停用'} ${regularKey.name}

ID: ${regularKey.id}

Prefix: ${regularKey.keyPrefix}

${regularKey.serverId ? `

Server ID: ${regularKey.serverId}

` : ''}

创建时间: ${new Date(regularKey.createdAt).toLocaleString()}

最后使用: ${regularKey.lastUsed ? new Date(regularKey.lastUsed).toLocaleString() : '从未'}

${regularKey.isActive ? `` : `` }
${childServerKeys.length > 0 ? `` : ''}
${childServerKeys.length > 0 ? ` ` : ''}
`; } function renderUserServerKeys(keys) { if (!userKeysList) { return; } if (!keys.length) { userKeysList.innerHTML = '

No server keys available.

'; return; } userKeysList.innerHTML = keys.map((key) => `

Server ${key.isActive ? '已启用' : '已停用'} ${key.name}

ID: ${key.id}

Prefix: ${key.keyPrefix}

${key.serverId ? `

Server ID: ${key.serverId}

` : ''}

创建时间: ${new Date(key.createdAt).toLocaleString()}

最后使用: ${key.lastUsed ? new Date(key.lastUsed).toLocaleString() : '从未'}

${key.isActive ? `` : `` }
`).join(''); } async function activateKey(keyId) { if (!apiKey) { return; } try { const response = await fetch(`${API_URL}/manage/keys/${keyId}/activate`, { method: 'PATCH', headers: authHeaders(apiKey) }); if (!response.ok) { const error = await response.json(); alert(`Failed to activate key: ${error.detail}`); return; } if (currentRole === 'admin') { loadAdminKeys(); } else if (currentRole === 'regular') { loadUserServerKeys(); } } catch (error) { alert(`Failed to activate key: ${error.message}`); } } async function deactivateKey(keyId) { if (!apiKey) { return; } try { const response = await fetch(`${API_URL}/manage/keys/${keyId}/deactivate`, { method: 'PATCH', headers: authHeaders(apiKey) }); if (!response.ok) { const error = await response.json(); alert(`Failed to deactivate key: ${error.detail}`); return; } if (currentRole === 'admin') { loadAdminKeys(); } else if (currentRole === 'regular') { loadUserServerKeys(); } } catch (error) { alert(`Failed to deactivate key: ${error.message}`); } } async function deleteKey(keyId, keyName) { if (currentRole !== 'admin') { return; } if (!confirm(`确定要删除密钥 "${keyName}" 吗? 此操作无法撤销。`)) { return; } try { const response = await fetch(`${API_URL}/manage/keys/${keyId}`, { method: 'DELETE', headers: authHeaders(apiKey) }); if (!response.ok) { const error = await response.json(); alert(`Failed to delete key: ${error.detail}`); return; } loadAdminKeys(); } catch (error) { alert(`Failed to delete key: ${error.message}`); } } function showKeyCreatedModal(payload) { if (!keyDetailsModal) { return; } let content = ''; if (payload.regularKey && payload.serverKey) { content = `

Regular Key

Name: ${payload.regularKey.name}

Type: ${payload.regularKey.keyType}

ID: ${payload.regularKey.id}

Key: ${payload.regularKey.key}


Server Key

Name: ${payload.serverKey.name}

Type: ${payload.serverKey.keyType}

ID: ${payload.serverKey.id}

Key: ${payload.serverKey.key}

`; } else { content = `

Key Created

Name: ${payload.name}

Type: ${payload.keyType}

ID: ${payload.id}

Key: ${payload.key}

`; } const detailsContent = document.getElementById('key-details-content'); if (detailsContent) { detailsContent.innerHTML = content; } keyDetailsModal.classList.remove('hidden'); } async function loadStats() { try { const response = await fetch(`${API_URL}/health`); if (!response.ok) { return; } const data = await response.json(); const connections = document.getElementById('user-stat-connections'); if (connections) { connections.textContent = data.active_ws || 0; } const serverKeys = document.getElementById('user-stat-server-keys'); if (serverKeys) { serverKeys.textContent = data.server_active || 0; } } catch (error) { console.error('Failed to load stats:', error); } } function connectWebSocket() { if (!apiKey) { return; } const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; const wsUrl = `${protocol}://${window.location.host}/ws?api_key=${apiKey}`; ws = new WebSocket(wsUrl); ws.onopen = () => { console.log('WebSocket connected'); }; ws.onmessage = (event) => { try { const message = JSON.parse(event.data); if (message.type === 'minecraft_event') { addEventToList(message.event); } } catch (error) { console.error('Failed to parse WebSocket message:', error); } }; ws.onerror = (error) => { console.error('WebSocket error:', error); }; ws.onclose = () => { console.log('WebSocket disconnected'); if (wsPingIntervalId) { clearInterval(wsPingIntervalId); wsPingIntervalId = null; } if (apiKey && currentRole === 'regular') { setTimeout(() => connectWebSocket(), 5000); } }; wsPingIntervalId = setInterval(() => { if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'ping' })); } }, 30000); } function addEventToList(event) { if (!userEventsList) { return; } const eventItem = document.createElement('div'); eventItem.className = 'event-item'; eventItem.innerHTML = ` ${event.event_type} - ${event.server_name}
${new Date(event.timestamp).toLocaleString()}
${JSON.stringify(event.data, null, 2)}
`; userEventsList.insertBefore(eventItem, userEventsList.firstChild); while (userEventsList.children.length > 50) { userEventsList.removeChild(userEventsList.lastChild); } } function appendCommandHistory(command, status, detail) { if (!commandHistory) { return; } const entry = document.createElement('div'); entry.className = 'command-item'; entry.innerHTML = `
${status}: ${command}
${detail ? `
${detail}
` : ''} `; commandHistory.insertBefore(entry, commandHistory.firstChild); while (commandHistory.children.length > 20) { commandHistory.removeChild(commandHistory.lastChild); } } if (loginForm) { loginForm.addEventListener('submit', async (event) => { event.preventDefault(); const key = apiKeyInput.value.trim(); loginError.textContent = ''; if (!key) { loginError.textContent = 'API key is required.'; return; } try { const role = await detectRole(key); if (!role) { loginError.textContent = 'Invalid key or insufficient permissions.'; return; } apiKey = key; if (role === 'admin') { showAdminPanel(); } else if (role === 'regular') { showUserPanel(); } } catch (error) { loginError.textContent = error.message || 'Unable to connect to server.'; } }); } logoutButtons.forEach((button) => { button.addEventListener('click', () => { resetSession(); }); }); if (createKeyBtn) { createKeyBtn.addEventListener('click', () => { createKeyModal.classList.remove('hidden'); }); } if (cancelCreateBtn) { cancelCreateBtn.addEventListener('click', () => { createKeyModal.classList.add('hidden'); createKeyForm.reset(); }); } if (closeDetailsBtn) { closeDetailsBtn.addEventListener('click', () => { keyDetailsModal.classList.add('hidden'); }); } function showCreateServerKeyModal(regularKeyId, regularKeyName) { if (!createServerKeyModal) { return; } const parentNameEl = document.getElementById('create-server-key-parent-name'); if (parentNameEl) { parentNameEl.textContent = `父级 Regular Key: ${regularKeyName}`; } const regularIdInput = document.getElementById('server-key-regular-id'); if (regularIdInput) { regularIdInput.value = regularKeyId; } createServerKeyModal.classList.remove('hidden'); } function hideCreateServerKeyModal() { if (!createServerKeyModal) { return; } createServerKeyModal.classList.add('hidden'); const nameInput = document.getElementById('server-key-name'); const descInput = document.getElementById('server-key-description'); const serverIdInput = document.getElementById('server-key-server-id'); if (nameInput) nameInput.value = ''; if (descInput) descInput.value = ''; if (serverIdInput) serverIdInput.value = ''; } async function createServerKey(event) { event.preventDefault(); const regularKeyId = document.getElementById('server-key-regular-id')?.value; const name = document.getElementById('server-key-name')?.value.trim(); const description = document.getElementById('server-key-description')?.value.trim(); const serverId = document.getElementById('server-key-server-id')?.value.trim(); if (!regularKeyId || !name) { alert('Regular Key ID and name are required.'); return; } try { const payload = { name, description, regular_key_id: regularKeyId }; if (serverId) { payload.server_id = serverId; } const response = await fetch(`${API_URL}/manage/keys/server-keys`, { method: 'POST', headers: { ...authHeaders(apiKey), 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { const error = await response.json(); alert(`Failed to create server key: ${error.detail}`); return; } const result = await response.json(); hideCreateServerKeyModal(); showKeyCreatedModal(result); loadAdminKeys(); } catch (error) { alert(`Failed to create server key: ${error.message}`); } } if (cancelServerKeyBtn) { cancelServerKeyBtn.addEventListener('click', hideCreateServerKeyModal); } if (createServerKeyForm) { createServerKeyForm.addEventListener('submit', createServerKey); } window.showCreateServerKeyModal = showCreateServerKeyModal; window.hideCreateServerKeyModal = hideCreateServerKeyModal; window.createServerKey = createServerKey; function showRefreshKeyModal(keyId, keyName) { if (!refreshKeyModal) { return; } const keyNameEl = document.getElementById('refresh-key-name'); const keyIdInput = document.getElementById('refresh-key-id'); if (keyNameEl) keyNameEl.textContent = keyName; if (keyIdInput) keyIdInput.value = keyId; refreshKeyModal.classList.remove('hidden'); } function hideRefreshKeyModal() { if (!refreshKeyModal) { return; } refreshKeyModal.classList.add('hidden'); } async function refreshKey() { const keyId = document.getElementById('refresh-key-id')?.value; if (!keyId || !apiKey) { return; } try { const response = await fetch(`${API_URL}/manage/keys/${keyId}/refresh`, { method: 'POST', headers: authHeaders(apiKey) }); if (!response.ok) { const error = await response.json(); alert(`刷新失败: ${error.detail}`); return; } const result = await response.json(); hideRefreshKeyModal(); showKeyCreatedModal(result); if (currentRole === 'admin') { loadAdminKeys(); } else if (currentRole === 'regular') { loadUserServerKeys(); } } catch (error) { alert(`刷新失败: ${error.message}`); } } if (cancelRefreshBtn) { cancelRefreshBtn.addEventListener('click', hideRefreshKeyModal); } if (confirmRefreshBtn) { confirmRefreshBtn.addEventListener('click', refreshKey); } window.showRefreshKeyModal = showRefreshKeyModal; window.hideRefreshKeyModal = hideRefreshKeyModal; window.refreshKey = refreshKey; if (createKeyForm) { createKeyForm.addEventListener('submit', async (event) => { event.preventDefault(); const name = document.getElementById('key-name').value.trim(); const description = document.getElementById('key-description').value.trim(); const keyType = document.getElementById('key-type').value; const serverId = document.getElementById('key-server-id').value.trim(); if (!name) { alert('Name is required.'); return; } try { const payload = { name, description, key_type: keyType }; if (serverId) { payload.server_id = serverId; } const response = await fetch(`${API_URL}/manage/keys`, { method: 'POST', headers: { ...authHeaders(apiKey), 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) { const error = await response.json(); alert(`Failed to create key: ${error.detail}`); return; } const result = await response.json(); createKeyModal.classList.add('hidden'); createKeyForm.reset(); showKeyCreatedModal(result); loadAdminKeys(); } catch (error) { alert(`Failed to create key: ${error.message}`); } }); } if (commandForm) { commandForm.addEventListener('submit', async (event) => { event.preventDefault(); const command = commandInput.value.trim(); if (!command) { return; } try { const response = await fetch(`${API_URL}/api/server/command`, { method: 'POST', headers: { ...authHeaders(apiKey), 'Content-Type': 'application/json' }, body: JSON.stringify({ command }) }); if (!response.ok) { const error = await response.json(); appendCommandHistory(command, 'Rejected', error.detail); return; } appendCommandHistory(command, 'Sent', new Date().toLocaleString()); commandInput.value = ''; } catch (error) { appendCommandHistory(command, 'Error', error.message); } }); } window.activateKey = activateKey; window.deactivateKey = deactivateKey; window.deleteKey = deleteKey; async function loadAIConfig() { if (!apiKey) { return; } try { const response = await fetch(`${API_URL}/api/ai/config`, { headers: authHeaders(apiKey) }); if (response.ok) { const config = await response.json(); if (aiApiUrlInput) aiApiUrlInput.value = config.apiUrl || ''; if (aiModelIdInput) aiModelIdInput.value = config.modelId || ''; if (aiApiKeyInput) aiApiKeyInput.value = ''; if (aiApiKeyHint) aiApiKeyHint.textContent = config.apiKey ? `Current: ${config.apiKey}` : ''; if (aiSystemPromptInput) aiSystemPromptInput.value = config.systemPrompt || ''; if (aiEnabledCheckbox) aiEnabledCheckbox.checked = config.enabled; showAIStatus('Configuration loaded', 'success'); } else if (response.status === 404) { if (aiApiUrlInput) aiApiUrlInput.value = ''; if (aiModelIdInput) aiModelIdInput.value = ''; if (aiApiKeyInput) aiApiKeyInput.value = ''; if (aiApiKeyHint) aiApiKeyHint.textContent = ''; if (aiSystemPromptInput) aiSystemPromptInput.value = ''; if (aiEnabledCheckbox) aiEnabledCheckbox.checked = true; showAIStatus('No configuration found. Please set up AI configuration.', 'info'); } } catch (error) { showAIStatus(`Failed to load AI config: ${error.message}`, 'error'); } } async function saveAIConfig(event) { event.preventDefault(); if (!apiKey) { return; } const apiUrl = aiApiUrlInput?.value?.trim(); const modelId = aiModelIdInput?.value?.trim(); const apiKeyValue = aiApiKeyInput?.value?.trim(); const systemPrompt = aiSystemPromptInput?.value?.trim() || null; const enabled = aiEnabledCheckbox?.checked ?? true; if (!apiUrl || !modelId) { showAIStatus('API URL and Model ID are required', 'error'); return; } try { const existingResponse = await fetch(`${API_URL}/api/ai/config`, { headers: authHeaders(apiKey) }); const isUpdate = existingResponse.ok; const payload = { api_url: apiUrl, model_id: modelId, enabled: enabled, system_prompt: systemPrompt }; if (apiKeyValue) { payload.api_key = apiKeyValue; } else if (!isUpdate) { showAIStatus('API Key is required for new configuration', 'error'); return; } const method = isUpdate ? 'PATCH' : 'POST'; const response = await fetch(`${API_URL}/api/ai/config`, { method: method, headers: { ...authHeaders(apiKey), 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (response.ok) { const config = await response.json(); if (aiApiKeyInput) aiApiKeyInput.value = ''; if (aiApiKeyHint) aiApiKeyHint.textContent = config.apiKey ? `Current: ${config.apiKey}` : ''; showAIStatus('Configuration saved successfully', 'success'); } else { const error = await response.json(); showAIStatus(`Failed to save: ${error.detail}`, 'error'); } } catch (error) { showAIStatus(`Failed to save AI config: ${error.message}`, 'error'); } } async function testAIConnection() { if (!apiKey) { return; } showAIStatus('Testing connection...', 'info'); try { const response = await fetch(`${API_URL}/api/ai/config/test`, { method: 'POST', headers: authHeaders(apiKey) }); const result = await response.json(); if (result.success) { showAIStatus(`Connection successful! Model: ${result.model}, Response: ${result.response}`, 'success'); } else { showAIStatus(`Connection failed: ${result.error}`, 'error'); } } catch (error) { showAIStatus(`Test failed: ${error.message}`, 'error'); } } async function deleteAIConfig() { if (!apiKey) { return; } if (!confirm('确定要删除 AI 配置吗?')) { return; } try { const response = await fetch(`${API_URL}/api/ai/config`, { method: 'DELETE', headers: authHeaders(apiKey) }); if (response.ok || response.status === 204) { if (aiApiUrlInput) aiApiUrlInput.value = ''; if (aiModelIdInput) aiModelIdInput.value = ''; if (aiApiKeyInput) aiApiKeyInput.value = ''; if (aiApiKeyHint) aiApiKeyHint.textContent = ''; if (aiSystemPromptInput) aiSystemPromptInput.value = ''; if (aiEnabledCheckbox) aiEnabledCheckbox.checked = true; showAIStatus('Configuration deleted', 'success'); } else { const error = await response.json(); showAIStatus(`Failed to delete: ${error.detail}`, 'error'); } } catch (error) { showAIStatus(`Failed to delete AI config: ${error.message}`, 'error'); } } function showAIStatus(message, type) { if (!aiStatus) { return; } aiStatus.textContent = message; aiStatus.className = `ai-status ${type}`; } if (aiConfigForm) { aiConfigForm.addEventListener('submit', saveAIConfig); } if (aiTestBtn) { aiTestBtn.addEventListener('click', testAIConnection); } if (aiDeleteBtn) { aiDeleteBtn.addEventListener('click', deleteAIConfig); }