// DOM Elements const apiKeyInput = document.getElementById('apiKey'); const scriptUrlInput = document.getElementById('scriptUrl'); const modelInput = document.getElementById('modelInput'); const saveConfigBtn = document.getElementById('saveConfig'); const statusBadge = document.getElementById('statusBadge'); const resultsArea = document.getElementById('results'); // Preset Management Elements const newPresetName = document.getElementById('newPresetName'); const newPresetSheet = document.getElementById('newPresetSheet'); const newPresetFields = document.getElementById('newPresetFields'); const addPresetBtn = document.getElementById('addPreset'); const cancelEditBtn = document.getElementById('cancelEdit'); const presetList = document.getElementById('presetList'); const presetSelect = document.getElementById('presetSelect'); const runPresetBtn = document.getElementById('runPreset'); // Import/Export Elements const exportBtn = document.getElementById('exportPresets'); const importBtn = document.getElementById('importPresets'); const importInput = document.getElementById('importInput'); // Collapsible logic const toggleConfig = document.getElementById('toggleConfig'); const configContent = document.getElementById('configContent'); const configChevron = document.getElementById('configChevron'); const DEFAULT_PRESETS = [ { id: 'p1', name: '提取笔记本', sheetName: '笔记本', fields: '品牌, CPU, 内存, 存储, 价格, URL' }, { id: 'p2', name: '提取外设', sheetName: '外设', fields: '品牌, 型号, 连接方式, 电池寿命, 价格, URL' } ]; let currentPresets = []; let editingPresetId = null; toggleConfig.addEventListener('click', () => { const isHidden = configContent.classList.toggle('hidden'); configChevron.classList.toggle('rotate-180', !isHidden); }); // Load settings and presets on startup chrome.storage.local.get(['geminiApiKey', 'googleScriptUrl', 'geminiModel', 'userPresets'], (data) => { if (data.geminiApiKey) { apiKeyInput.value = data.geminiApiKey; configContent.classList.add('hidden'); configChevron.classList.remove('rotate-180'); } else { configContent.classList.remove('hidden'); configChevron.classList.add('rotate-180'); } if (data.googleScriptUrl) scriptUrlInput.value = data.googleScriptUrl; if (data.geminiModel) modelInput.value = data.geminiModel; currentPresets = data.userPresets || DEFAULT_PRESETS; renderPresets(currentPresets); }); // Save global settings saveConfigBtn.addEventListener('click', () => { const apiKey = apiKeyInput.value.trim(); const scriptUrl = scriptUrlInput.value.trim(); const model = modelInput.value.trim(); chrome.storage.local.set({ geminiApiKey: apiKey, googleScriptUrl: scriptUrl, geminiModel: model }, () => { updateStatus('已保存', 'bg-green-500 text-white'); setTimeout(() => updateStatus('待机', 'bg-gray-200 text-gray-600'), 2000); }); }); // Preset Management Logic addPresetBtn.addEventListener('click', async () => { const name = newPresetName.value.trim(); const sheetName = newPresetSheet.value.trim(); const rawFields = newPresetFields.value.trim(); if (!name || !rawFields) return alert('请输入名称和字段'); const normalizedFields = rawFields .split(/[,,]/) .map(f => f.trim()) .filter(f => f !== "") .join(', '); const { userPresets = DEFAULT_PRESETS } = await chrome.storage.local.get('userPresets'); if (editingPresetId) { // Update existing currentPresets = userPresets.map(p => p.id === editingPresetId ? { ...p, name, sheetName, fields: normalizedFields } : p ); stopEditing(); } else { // Add new const newPreset = { id: Date.now().toString(), name, sheetName, fields: normalizedFields }; currentPresets = [...userPresets, newPreset]; } await chrome.storage.local.set({ userPresets: currentPresets }); clearPresetInputs(); renderPresets(currentPresets); }); cancelEditBtn.addEventListener('click', stopEditing); // Export/Import Logic exportBtn.addEventListener('click', async () => { const { userPresets = DEFAULT_PRESETS } = await chrome.storage.local.get('userPresets'); const blob = new Blob([JSON.stringify(userPresets, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `hardware-presets-${new Date().toISOString().split('T')[0]}.json`; a.click(); URL.revokeObjectURL(url); }); importBtn.addEventListener('click', () => importInput.click()); importInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = async (event) => { try { const importedPresets = JSON.parse(event.target.result); if (!Array.isArray(importedPresets)) throw new Error('无效的预设文件格式'); const { userPresets = DEFAULT_PRESETS } = await chrome.storage.local.get('userPresets'); const choice = confirm('导入成功!\n点击 [确定] 将导入的预设合并到当前列表。\n点击 [取消] 将替换整个预设列表。'); let finalPresets; if (choice) { // Merge: Append with new IDs to prevent conflicts const newItems = importedPresets.map(p => ({ ...p, id: Date.now().toString() + Math.random().toString(36).substr(2, 5) })); finalPresets = [...userPresets, ...newItems]; } else { finalPresets = importedPresets; } await chrome.storage.local.set({ userPresets: finalPresets }); currentPresets = finalPresets; renderPresets(currentPresets); alert('预设导入完成!'); } catch (err) { alert('导入失败: ' + err.message); } importInput.value = ''; // Reset input }; reader.readAsText(file); }); function startEditing(preset) { editingPresetId = preset.id; newPresetName.value = preset.name; newPresetSheet.value = preset.sheetName || ''; newPresetFields.value = preset.fields; addPresetBtn.textContent = '更新预设'; addPresetBtn.classList.replace('bg-indigo-50', 'bg-indigo-600'); addPresetBtn.classList.replace('text-indigo-700', 'text-white'); cancelEditBtn.classList.remove('hidden'); configContent.classList.remove('hidden'); configChevron.classList.add('rotate-180'); } function stopEditing() { editingPresetId = null; clearPresetInputs(); addPresetBtn.textContent = '添加新预设'; addPresetBtn.classList.replace('bg-indigo-600', 'bg-indigo-50'); addPresetBtn.classList.replace('text-white', 'text-indigo-700'); cancelEditBtn.classList.add('hidden'); } function clearPresetInputs() { newPresetName.value = ''; newPresetSheet.value = ''; newPresetFields.value = ''; } async function deletePreset(id) { if (editingPresetId === id) stopEditing(); const { userPresets = DEFAULT_PRESETS } = await chrome.storage.local.get('userPresets'); currentPresets = userPresets.filter(p => p.id !== id); await chrome.storage.local.set({ userPresets: currentPresets }); renderPresets(currentPresets); } function renderPresets(presets) { presetList.innerHTML = ''; presetSelect.innerHTML = ''; presets.forEach(preset => { // 1. Settings List Item const item = document.createElement('div'); item.className = 'flex items-center justify-between bg-white p-3 mb-2 rounded-lg border border-gray-200 shadow-sm transition-all hover:border-indigo-200'; item.innerHTML = `