// 背诵排序功能脚本 let extractedItems = []; let sortedItems = []; let currentSpinIndex = 0; let isSpinning = false; // 颜色配置 - 转盘使用不同颜色 const colors = [ '#667eea', '#764ba2', '#f093fb', '#f5576c', '#4facfe', '#00f2fe', '#43e97b', '#38f9d7', '#fa709a', '#fee140', '#30cfd0', '#330867' ]; // DOM元素 const textInput = document.getElementById('textInput'); const extractBtn = document.getElementById('extractBtn'); const extractedSection = document.getElementById('extractedSection'); const itemsList = document.getElementById('itemsList'); const itemCount = document.getElementById('itemCount'); const sortBtn = document.getElementById('sortBtn'); const wheelSection = document.getElementById('wheelSection'); const wheel = document.getElementById('wheel'); const spinBtn = document.getElementById('spinBtn'); const currentItem = document.getElementById('currentItem'); const resultSection = document.getElementById('resultSection'); const sortedList = document.getElementById('sortedList'); const resetBtn = document.getElementById('resetBtn'); const exportTxtBtn = document.getElementById('exportTxtBtn'); const exportJsonBtn = document.getElementById('exportJsonBtn'); const exportCsvBtn = document.getElementById('exportCsvBtn'); // 本地存储键名 const STORAGE_KEY_EXTRACTED = 'recitation_extracted_items'; const STORAGE_KEY_SORTED = 'recitation_sorted_items'; const STORAGE_KEY_ORIGINAL_TEXT = 'recitation_original_text'; // 页面加载时恢复数据 window.addEventListener('DOMContentLoaded', () => { restoreFromStorage(); }); // 保存到本地存储 function saveToStorage() { try { if (extractedItems.length > 0) { localStorage.setItem(STORAGE_KEY_EXTRACTED, JSON.stringify(extractedItems)); } if (sortedItems.length > 0) { localStorage.setItem(STORAGE_KEY_SORTED, JSON.stringify(sortedItems)); } if (textInput.value.trim()) { localStorage.setItem(STORAGE_KEY_ORIGINAL_TEXT, textInput.value); } } catch (e) { console.error('保存到本地存储失败:', e); } } // 从本地存储恢复 function restoreFromStorage() { try { const savedExtracted = localStorage.getItem(STORAGE_KEY_EXTRACTED); const savedSorted = localStorage.getItem(STORAGE_KEY_SORTED); const savedText = localStorage.getItem(STORAGE_KEY_ORIGINAL_TEXT); if (savedText) { textInput.value = savedText; } if (savedExtracted) { extractedItems = JSON.parse(savedExtracted); displayExtractedItems(extractedItems); extractedSection.style.display = 'block'; textInput.disabled = true; } if (savedSorted) { sortedItems = JSON.parse(savedSorted); displaySortedItems(sortedItems); createWheel(sortedItems); wheelSection.style.display = 'block'; resultSection.style.display = 'block'; } } catch (e) { console.error('从本地存储恢复失败:', e); } } // 清除本地存储 function clearStorage() { localStorage.removeItem(STORAGE_KEY_EXTRACTED); localStorage.removeItem(STORAGE_KEY_SORTED); localStorage.removeItem(STORAGE_KEY_ORIGINAL_TEXT); } // 提取知识点 extractBtn.addEventListener('click', async () => { const text = textInput.value.trim(); if (!text) { alert('请输入要处理的文本'); return; } extractBtn.disabled = true; extractBtn.textContent = '识别中...'; try { const response = await fetch('/api/extract', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text }) }); const data = await response.json(); if (data.success) { extractedItems = data.items; displayExtractedItems(extractedItems); extractedSection.style.display = 'block'; textInput.disabled = true; saveToStorage(); // 保存到本地存储 } else { alert(data.message || '提取失败'); } } catch (error) { console.error('提取失败:', error); alert('提取失败,请检查网络连接'); } finally { extractBtn.disabled = false; extractBtn.textContent = '识别知识点'; } }); // 显示提取的项目 function displayExtractedItems(items) { itemCount.textContent = items.length; itemsList.innerHTML = ''; items.forEach((item, index) => { const tag = document.createElement('span'); tag.className = 'item-tag'; tag.textContent = `${index + 1}. ${item}`; itemsList.appendChild(tag); }); } // 随机排序 sortBtn.addEventListener('click', async () => { if (extractedItems.length === 0) { alert('请先提取知识点'); return; } sortBtn.disabled = true; sortBtn.textContent = '排序中...'; try { const response = await fetch('/api/sort', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ items: extractedItems }) }); const data = await response.json(); if (data.success) { sortedItems = data.items; displaySortedItems(sortedItems); createWheel(sortedItems); wheelSection.style.display = 'block'; resultSection.style.display = 'block'; currentSpinIndex = 0; saveToStorage(); // 保存到本地存储 } else { alert(data.message || '排序失败'); } } catch (error) { console.error('排序失败:', error); alert('排序失败,请检查网络连接'); } finally { sortBtn.disabled = false; sortBtn.textContent = '开始随机排序'; } }); // 创建转盘 - 使用SVG实现更真实的转盘效果 function createWheel(items) { wheel.innerHTML = ''; if (items.length === 0) return; const anglePerItem = 360 / items.length; const radius = 190; // 转盘半径(考虑边框) const centerX = 200; const centerY = 200; // 创建SVG转盘 const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '400'); svg.setAttribute('height', '400'); svg.setAttribute('viewBox', '0 0 400 400'); svg.style.position = 'absolute'; svg.style.top = '0'; svg.style.left = '0'; svg.style.width = '100%'; svg.style.height = '100%'; items.forEach((item, index) => { const startAngle = (index * anglePerItem - 90) * Math.PI / 180; const endAngle = ((index + 1) * anglePerItem - 90) * Math.PI / 180; const x1 = centerX + radius * Math.cos(startAngle); const y1 = centerY + radius * Math.sin(startAngle); const x2 = centerX + radius * Math.cos(endAngle); const y2 = centerY + radius * Math.sin(endAngle); const largeArcFlag = anglePerItem > 180 ? 1 : 0; const pathData = [ `M ${centerX} ${centerY}`, `L ${x1} ${y1}`, `A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2}`, 'Z' ].join(' '); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', pathData); const colorIndex = index % colors.length; path.setAttribute('fill', colors[colorIndex]); path.setAttribute('stroke', '#fff'); path.setAttribute('stroke-width', '2'); svg.appendChild(path); // 添加文本 const midAngle = (startAngle + endAngle) / 2; const textRadius = radius * 0.7; const textX = centerX + textRadius * Math.cos(midAngle); const textY = centerY + textRadius * Math.sin(midAngle); const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', textX); text.setAttribute('y', textY); text.setAttribute('text-anchor', 'middle'); text.setAttribute('fill', 'white'); text.setAttribute('font-size', items.length > 8 ? '12' : '14'); text.setAttribute('font-weight', 'bold'); text.setAttribute('transform', `rotate(${(midAngle * 180 / Math.PI + 90)}, ${textX}, ${textY})`); const displayText = item.length > 12 ? item.substring(0, 12) + '...' : item; text.textContent = displayText; svg.appendChild(text); }); wheel.appendChild(svg); } // 转动转盘 spinBtn.addEventListener('click', () => { if (isSpinning || sortedItems.length === 0) return; isSpinning = true; spinBtn.disabled = true; currentItem.textContent = '转盘中...'; // 随机选择一个索引(添加多圈旋转效果) const randomIndex = Math.floor(Math.random() * sortedItems.length); const spins = 3; // 转3圈 const anglePerItem = 360 / sortedItems.length; // 计算目标角度:多转几圈 + 指向选中项 const targetAngle = spins * 360 + (360 - (randomIndex * anglePerItem) - anglePerItem / 2); // 获取当前角度 const svg = wheel.querySelector('svg'); const currentAngle = getCurrentRotation(svg); // 计算总旋转角度(考虑当前角度) const totalRotation = currentAngle + targetAngle; svg.style.transform = `rotate(${totalRotation}deg)`; // 转盘停止后显示结果 setTimeout(() => { currentItem.textContent = `${randomIndex + 1}. ${sortedItems[randomIndex]}`; currentSpinIndex = randomIndex; isSpinning = false; spinBtn.disabled = false; }, 3000); }); // 获取当前旋转角度 function getCurrentRotation(element) { const style = window.getComputedStyle(element); const transform = style.transform; if (transform === 'none') return 0; const matrix = new DOMMatrix(transform); const angle = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI); return angle; } // 显示排序结果 function displaySortedItems(items) { sortedList.innerHTML = ''; items.forEach((item, index) => { const itemDiv = document.createElement('div'); itemDiv.className = 'sorted-item'; const numberSpan = document.createElement('span'); numberSpan.className = 'sorted-item-number'; numberSpan.textContent = index + 1; const textSpan = document.createElement('span'); textSpan.className = 'sorted-item-text'; textSpan.textContent = item; itemDiv.appendChild(numberSpan); itemDiv.appendChild(textSpan); sortedList.appendChild(itemDiv); }); } // 导出功能 exportTxtBtn.addEventListener('click', () => exportData('txt')); exportJsonBtn.addEventListener('click', () => exportData('json')); exportCsvBtn.addEventListener('click', () => exportData('csv')); function exportData(format) { if (sortedItems.length === 0) { alert('没有可导出的数据'); return; } fetch('/api/export/sorted', { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8' }, body: JSON.stringify({ items: sortedItems, format: format }) }) .then(response => { if (!response.ok) { throw new Error('导出失败'); } return response.blob(); }) .then(blob => { const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, '').replace('T', '_'); a.download = `背诵排序结果_${timestamp}.${format}`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); }) .catch(error => { console.error('导出失败:', error); alert('导出失败,请重试'); }); } // 重置 resetBtn.addEventListener('click', () => { extractedItems = []; sortedItems = []; currentSpinIndex = 0; textInput.value = ''; textInput.disabled = false; extractedSection.style.display = 'none'; wheelSection.style.display = 'none'; resultSection.style.display = 'none'; wheel.innerHTML = ''; const svg = wheel.querySelector('svg'); if (svg) { svg.style.transform = 'rotate(0deg)'; } currentItem.textContent = ''; isSpinning = false; spinBtn.disabled = false; clearStorage(); // 清除本地存储 });