showMessage(`✅ ${alias} 添加成功`, 'success'); } saveKeys(keys); clearForm(); } function editKey(platform, apiKey) { const keys = loadKeys(); const key = keys.find(k => k.platform === platform && k.api_key === apiKey); if (!key) { showMessage('Key不存在', 'error'); return; } editingKey = { platform, apiKey }; document.getElementById('platform').value = key.platform; document.getElementById('alias').value = key.alias; document.getElementById('api_key').value = key.api_key; document.getElementById('base_url').value = key.base_url; document.getElementById('tags').value = key.tags || ''; document.getElementById('quota_total').value = key.quota_total || 1000000; document.getElementById('formTitle').textContent = '✏️ 编辑API Key'; showMessage(`正在编辑: ${key.alias}`, 'info'); } function deleteKey(platform, apiKey) { if (!confirm('确定要删除这个Key吗?')) return; const keys = loadKeys(); const index = keys.findIndex(k => k.platform === platform && k.api_key === apiKey); if (index === -1) { showMessage('Key不存在', 'error'); return; } const deleted = keys.splice(index, 1)[0]; saveKeys(keys); showMessage(`🗑️ ${deleted.alias} 已删除`, 'success'); } function clearForm() { editingKey = null; document.getElementById('platform').value = ''; document.getElementById('alias').value = ''; document.getElementById('api_key').value = ''; document.getElementById('base_url').value = ''; document.getElementById('tags').value = ''; document.getElementById('quota_total').value = '1000000'; document.getElementById('formTitle').textContent = '➕ 添加API Key'; } // ========== 导入导出 ========== function exportKeys() { const keys = loadKeys(); if (keys.length === 0) { showMessage('没有可导出的Key', 'warning'); return; } const data = JSON.stringify(keys, null, 2); const blob = new Blob([data], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `fu5-keys-${new Date().toISOString().split('T')[0]}.json`; a.click(); URL.revokeObjectURL(url); showMessage(`✅ 已导出 ${keys.length} 个Key`, 'success'); } function importKeys() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.onchange = (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (event) => { try { const imported = JSON.parse(event.target.result); if (!Array.isArray(imported)) throw new Error('格式不正确'); const valid = imported.filter(k => k.platform && k.api_key && k.base_url); if (valid.length === 0) throw new Error('没有有效数据'); const existing = loadKeys(); const map = new Map(); existing.forEach(k => map.set(`${k.platform}:${k.api_key}`, k)); let added = 0, updated = 0; valid.forEach(k => { const id = `${k.platform}:${k.api_key}`; if (map.has(id)) { Object.assign(map.get(id), k, { updated_at: new Date().toISOString() }); updated++; } else { existing.push({ ...k, created_at: k.created_at || new Date().toISOString(), updated_at: new Date().toISOString() }); added++; } }); saveKeys(existing); showMessage(`✅ 导入完成: 新增 ${added} 个, 更新 ${updated} 个`, 'success'); } catch (err) { showMessage(`❌ 导入失败: ${err.message}`, 'error'); } }; reader.readAsText(file); }; input.click(); } // ========== 工具函数 ========== function refreshList() { updateStats(); renderKeyTable(); showMessage('列表已刷新', 'info'); } function showMessage(text, type = 'info') { const container = document.getElementById('messageContainer'); const msg = document.createElement('div'); msg.className = `message message-${type}`; msg.textContent = text; container.appendChild(msg); setTimeout(() => msg.remove(), 3000); } // ========== 初始化 ========== document.addEventListener('DOMContentLoaded', () => { const keys = loadKeys(); if (keys.length === 0) { keys.push({ platform: 'nvidia', alias: '示例NVIDIA Key', api_key: 'nvapi-example-key-1234567890', base_url: 'https://integrate.api.nvidia.com/v1', tags: 'example,test', status: 'inactive', quota_total: 1000000, quota_used: 0, created_at: new Date().toISOString(), updated_at: new Date().toISOString() }); saveKeys(keys); showMessage('已添加示例Key,请替换为您的真实Key', 'info'); } updateStats(); renderKeyTable(); });