805 lines
29 KiB
HTML
805 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>单词默写系统 - 教师端生成器</title>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
}
|
||
body {
|
||
background: linear-gradient(135deg, #0a2a1a, #0c3a4a, #0d4b66);
|
||
min-height: 100vh;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 20px;
|
||
overflow-x: hidden;
|
||
position: relative;
|
||
}
|
||
.container {
|
||
width: 100%;
|
||
max-width: 1000px;
|
||
text-align: center;
|
||
position: relative;
|
||
z-index: 10;
|
||
}
|
||
.header {
|
||
margin-bottom: 40px;
|
||
animation: fadeInDown 1s ease-out;
|
||
position: relative;
|
||
}
|
||
.logo {
|
||
font-size: 4.5rem;
|
||
margin-bottom: 20px;
|
||
background: linear-gradient(45deg, #7cffcb, #00d2ff, #5de6ff);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
text-shadow: 0 0 20px rgba(100, 255, 200, 0.3);
|
||
animation: pulse 3s infinite;
|
||
}
|
||
.title {
|
||
font-size: 2.8rem;
|
||
font-weight: 700;
|
||
margin-bottom: 15px;
|
||
color: #fff;
|
||
text-shadow: 0 0 15px rgba(100, 255, 200, 0.5);
|
||
position: relative;
|
||
z-index: 20;
|
||
}
|
||
.subtitle {
|
||
font-size: 1.2rem;
|
||
color: #c0ffea;
|
||
max-width: 600px;
|
||
margin: 0 auto;
|
||
line-height: 1.6;
|
||
position: relative;
|
||
z-index: 20;
|
||
}
|
||
.main-content {
|
||
background: rgba(10, 42, 26, 0.7);
|
||
border-radius: 30px;
|
||
padding: 40px;
|
||
margin: 30px 0;
|
||
backdrop-filter: blur(15px);
|
||
border: 1px solid rgba(100, 255, 200, 0.3);
|
||
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4);
|
||
animation: fadeInUp 1s ease-out 0.6s both;
|
||
position: relative;
|
||
overflow: hidden;
|
||
height: auto;
|
||
}
|
||
.tabs {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 15px;
|
||
margin-bottom: 30px;
|
||
}
|
||
.tab-btn {
|
||
padding: 12px 25px;
|
||
border-radius: 20px;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border: 1px solid rgba(100, 255, 200, 0.3);
|
||
color: #c0ffea;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
font-weight: 500;
|
||
}
|
||
.tab-btn.active {
|
||
background: linear-gradient(45deg, #7cffcb, #00d2ff, #5de6ff);
|
||
color: #0a2a1a;
|
||
font-weight: 600;
|
||
}
|
||
.tab-btn:hover:not(.active) {
|
||
background: rgba(255, 255, 255, 0.2);
|
||
}
|
||
.search-container {
|
||
display: flex;
|
||
gap: 15px;
|
||
margin: 25px 0;
|
||
max-width: 600px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
}
|
||
.search-input {
|
||
flex: 1;
|
||
padding: 15px 20px;
|
||
border-radius: 15px;
|
||
border: 1px solid rgba(100, 255, 200, 0.3);
|
||
background: rgba(0, 0, 0, 0.2);
|
||
color: #fff;
|
||
font-size: 1rem;
|
||
outline: none;
|
||
}
|
||
.search-input::placeholder {
|
||
color: #a0ffe0;
|
||
}
|
||
.search-input:focus {
|
||
border-color: #7cffcb;
|
||
box-shadow: 0 0 15px rgba(124, 255, 203, 0.3);
|
||
}
|
||
.button-group {
|
||
display: flex;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
gap: 15px;
|
||
margin: 25px 0;
|
||
}
|
||
.action-btn {
|
||
padding: 12px 25px;
|
||
border-radius: 15px;
|
||
border: none;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.btn-primary {
|
||
background: linear-gradient(45deg, #7cffcb, #00d2ff, #5de6ff);
|
||
color: #0a2a1a;
|
||
}
|
||
.btn-secondary {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
color: #c0ffea;
|
||
border: 1px solid rgba(100, 255, 200, 0.3);
|
||
}
|
||
.btn-success {
|
||
background: linear-gradient(45deg, #34C759, #7cffcb);
|
||
color: #0a2a1a;
|
||
}
|
||
.btn-warning {
|
||
background: linear-gradient(45deg, #FFCC00, #ffd93d);
|
||
color: #0a2a1a;
|
||
}
|
||
.btn-danger {
|
||
background: linear-gradient(45deg, #FF3B30, #ff6b6b);
|
||
color: white;
|
||
}
|
||
.action-btn:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 8px 20px rgba(100, 255, 200, 0.3);
|
||
}
|
||
.action-btn:active {
|
||
transform: translateY(-1px);
|
||
}
|
||
.action-btn::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: -100%;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
||
transition: 0.5s;
|
||
}
|
||
.action-btn:hover::before {
|
||
left: 100%;
|
||
}
|
||
.stats-container {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
margin: 30px 0;
|
||
flex-wrap: wrap;
|
||
gap: 20px;
|
||
}
|
||
.stat-card {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border-radius: 15px;
|
||
padding: 20px;
|
||
min-width: 120px;
|
||
border: 1px solid rgba(100, 255, 200, 0.2);
|
||
}
|
||
.stat-number {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
color: #7cffcb;
|
||
margin-bottom: 5px;
|
||
}
|
||
.stat-label {
|
||
color: #c0ffea;
|
||
font-size: 0.9rem;
|
||
}
|
||
.word-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||
gap: 15px;
|
||
margin: 30px 0;
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
padding: 10px;
|
||
background: rgba(0, 0, 0, 0.1);
|
||
border-radius: 10px;
|
||
}
|
||
.word-grid::-webkit-scrollbar {
|
||
width: 8px;
|
||
}
|
||
.word-grid::-webkit-scrollbar-track {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border-radius: 4px;
|
||
}
|
||
.word-grid::-webkit-scrollbar-thumb {
|
||
background: linear-gradient(45deg, #7cffcb, #00d2ff);
|
||
border-radius: 4px;
|
||
}
|
||
.word-item {
|
||
padding: 15px 10px;
|
||
border-radius: 10px;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
color: #c0ffea;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
border: 1px solid transparent;
|
||
font-weight: 500;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
.word-item:hover {
|
||
background: rgba(255, 255, 255, 0.2);
|
||
transform: translateY(-2px);
|
||
}
|
||
.word-item.selected {
|
||
background: linear-gradient(45deg, #7cffcb, #00d2ff, #5de6ff);
|
||
color: #0a2a1a;
|
||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||
font-weight: 600;
|
||
}
|
||
.word-text {
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
}
|
||
.word-translation {
|
||
font-size: 0.8em;
|
||
opacity: 0.8;
|
||
}
|
||
.add-word-suggestion {
|
||
background: linear-gradient(135deg, rgba(255, 204, 0, 0.2), rgba(255, 107, 107, 0.2));
|
||
border-radius: 15px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
border: 1px solid rgba(255, 204, 0, 0.3);
|
||
display: none;
|
||
}
|
||
.add-word-suggestion p {
|
||
color: #ffd93d;
|
||
margin-bottom: 15px;
|
||
}
|
||
.add-word-inputs {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
margin-top: 10px;
|
||
}
|
||
.add-word-input {
|
||
padding: 10px;
|
||
border-radius: 8px;
|
||
border: 1px solid rgba(100, 255, 200, 0.3);
|
||
background: rgba(0, 0, 0, 0.2);
|
||
color: #fff;
|
||
}
|
||
.particles {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: -1;
|
||
overflow: hidden;
|
||
}
|
||
.particle {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
background: rgba(100, 255, 200, 0.2);
|
||
animation: float 15s infinite linear;
|
||
}
|
||
@keyframes float {
|
||
0% {
|
||
transform: translateY(0) translateX(0) rotate(0deg);
|
||
opacity: 0;
|
||
}
|
||
10% {
|
||
opacity: 1;
|
||
}
|
||
90% {
|
||
opacity: 0.5;
|
||
}
|
||
100% {
|
||
transform: translateY(-100vh) translateX(100px) rotate(360deg);
|
||
opacity: 0;
|
||
}
|
||
}
|
||
.cube-container {
|
||
position: absolute;
|
||
top: 20%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 150px;
|
||
height: 150px;
|
||
perspective: 1000px;
|
||
z-index: 5;
|
||
opacity: 0.7;
|
||
}
|
||
.cube {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
transform-style: preserve-3d;
|
||
animation: rotate 20s infinite linear;
|
||
}
|
||
.cube-face {
|
||
position: absolute;
|
||
width: 150px;
|
||
height: 150px;
|
||
background: rgba(100, 255, 200, 0.1);
|
||
border: 2px solid rgba(100, 255, 200, 0.3);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
font-size: 2rem;
|
||
font-weight: bold;
|
||
color: rgba(100, 255, 200, 0.7);
|
||
backdrop-filter: blur(2px);
|
||
}
|
||
.cube-face-front { transform: rotateY(0deg) translateZ(75px); }
|
||
.cube-face-back { transform: rotateY(180deg) translateZ(75px); }
|
||
.cube-face-right { transform: rotateY(90deg) translateZ(75px); }
|
||
.cube-face-left { transform: rotateY(-90deg) translateZ(75px); }
|
||
.cube-face-top { transform: rotateX(90deg) translateZ(75px); }
|
||
.cube-face-bottom { transform: rotateX(-90deg) translateZ(75px); }
|
||
@keyframes rotate {
|
||
0% { transform: rotateX(0) rotateY(0) rotateZ(0); }
|
||
100% { transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg); }
|
||
}
|
||
@keyframes fadeInDown {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-30px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
@keyframes fadeInUp {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(30px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
@keyframes pulse {
|
||
0% { text-shadow: 0 0 10px rgba(100, 255, 200, 0.3); }
|
||
50% { text-shadow: 0 0 30px rgba(100, 255, 200, 0.6); }
|
||
100% { text-shadow: 0 0 10px rgba(100, 255, 200, 0.3); }
|
||
}
|
||
.export-info {
|
||
background: rgba(0, 0, 0, 0.2);
|
||
border-radius: 15px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
text-align: left;
|
||
}
|
||
.export-info h3 {
|
||
color: #7cffcb;
|
||
margin-bottom: 15px;
|
||
}
|
||
.export-info ul {
|
||
color: #c0ffea;
|
||
padding-left: 20px;
|
||
}
|
||
.export-info li {
|
||
margin-bottom: 10px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="particles" id="particles"></div>
|
||
<div class="cube-container">
|
||
<div class="cube">
|
||
<div class="cube-face cube-face-front">教</div>
|
||
<div class="cube-face cube-face-back">师</div>
|
||
<div class="cube-face cube-face-right">端</div>
|
||
<div class="cube-face cube-face-left">生</div>
|
||
<div class="cube-face cube-face-top">成</div>
|
||
<div class="cube-face cube-face-bottom">器</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<div class="header">
|
||
<div class="logo">
|
||
<i class="fas fa-chalkboard-teacher"></i>
|
||
</div>
|
||
<h1 class="title">单词默写系统 - 教师端生成器</h1>
|
||
<p class="subtitle">创建和管理单词词库,生成加密配置文件</p>
|
||
</div>
|
||
|
||
<div class="main-content">
|
||
<div class="tabs">
|
||
<button class="tab-btn active" onclick="switchTab('manage')">词库管理</button>
|
||
<button class="tab-btn" onclick="switchTab('export')">导出配置</button>
|
||
</div>
|
||
|
||
<div id="manageTab" class="tab-content active">
|
||
<h3 style="color: #fff; margin: 20px 0;">管理单词词库</h3>
|
||
<div class="search-container">
|
||
<input type="text" class="search-input" id="searchInput" placeholder="搜索单词..." oninput="filterWords()">
|
||
<button class="action-btn btn-secondary" onclick="clearSearch()">
|
||
<i class="fas fa-times"></i> 清除
|
||
</button>
|
||
</div>
|
||
|
||
<div id="addWordSuggestion" class="add-word-suggestion">
|
||
<p><i class="fas fa-lightbulb"></i> 没有找到您要的单词?可以添加到词库中!</p>
|
||
<div class="add-word-inputs">
|
||
<input type="text" class="add-word-input" id="newWordInput" placeholder="英文单词">
|
||
<input type="text" class="add-word-input" id="newTranslationInput" placeholder="中文翻译">
|
||
<button class="action-btn btn-warning" onclick="addNewWordWithTranslation()">
|
||
<i class="fas fa-plus"></i> 添加单词
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="button-group">
|
||
<button class="action-btn btn-primary" onclick="selectAllWords()">
|
||
<i class="fas fa-check-square"></i> 全选
|
||
</button>
|
||
<button class="action-btn btn-secondary" onclick="deselectAllWords()">
|
||
<i class="fas fa-square"></i> 取消全选
|
||
</button>
|
||
<button class="action-btn btn-warning" onclick="randomSelectWords()">
|
||
<i class="fas fa-dice"></i> 随机60个
|
||
</button>
|
||
<button class="action-btn btn-danger" onclick="deleteSelectedWords()">
|
||
<i class="fas fa-trash"></i> 删除选中
|
||
</button>
|
||
</div>
|
||
|
||
<div class="stats-container">
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="totalWords">0</div>
|
||
<div class="stat-label">总单词</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="selectedCount">0</div>
|
||
<div class="stat-label">已选择</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="percentage">0%</div>
|
||
<div class="stat-label">完成度</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="word-grid" id="wordGrid">
|
||
<!-- 单词项将通过JavaScript动态生成 -->
|
||
</div>
|
||
</div>
|
||
|
||
<div id="exportTab" class="tab-content">
|
||
<h3 style="color: #fff; margin: 20px 0;">导出配置文件</h3>
|
||
<div class="button-group">
|
||
<button class="action-btn btn-success" onclick="exportConfig()">
|
||
<i class="fas fa-download"></i> 导出加密配置文件
|
||
</button>
|
||
</div>
|
||
<div class="stats-container">
|
||
<div class="stat-card">
|
||
<div class="stat-number" id="exportWordCount">0</div>
|
||
<div class="stat-label">待导出单词</div>
|
||
</div>
|
||
</div>
|
||
<div class="export-info">
|
||
<h3><i class="fas fa-info-circle"></i> 导出说明</h3>
|
||
<ul>
|
||
<li>导出的配置文件将包含完整的JSON结构</li>
|
||
<li>英文单词部分使用Base64加密</li>
|
||
<li>中文翻译保持明文</li>
|
||
<li>学生端可直接导入使用</li>
|
||
<li>无需修改应用程序即可更换单词列表</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 词库数据
|
||
let wordLibrary = [
|
||
{ "word": "instrument", "translation": "n. 工具、手段" },
|
||
{ "word": "therefore", "translation": "adv. 因此" },
|
||
{ "word": "tradition", "translation": "n. 传统" },
|
||
{ "word": "represent", "translation": "v. 代表、描绘" },
|
||
{ "word": "iceberg", "translation": "n. 冰山" },
|
||
{ "word": "store", "translation": "v. 储存" },
|
||
{ "word": "depend", "translation": "v. 依赖" },
|
||
{ "word": "general", "translation": "adj. 整体的、普遍的、大体的" },
|
||
{ "word": "contrast", "translation": "n. 对比、差别" },
|
||
{ "word": "predator", "translation": "n. 捕食者" },
|
||
{ "word": "against", "translation": "prep. 与……相反、违背、对比、以…为背景" },
|
||
{ "word": "survive", "translation": "v. 存活、挺过、比……活的长" },
|
||
{ "word": "nature", "translation": "n. 自然、本质" },
|
||
{ "word": "solar", "translation": "adj. 太阳的" },
|
||
{ "word": "architecture", "translation": "n. 建筑" },
|
||
{ "word": "primarily", "translation": "adv. 主要地" },
|
||
{ "word": "observe", "translation": "v. 观察(到)、遵从(法律等)" },
|
||
{ "word": "canal", "translation": "n. 运河" },
|
||
{ "word": "craft", "translation": "n. 手艺" },
|
||
{ "word": "reflect", "translation": "v. 反映、反射、反思" },
|
||
{ "word": "argue", "translation": "v. 论证" },
|
||
{ "word": "draw", "translation": "v. 画、得出、提取、轻拉" },
|
||
{ "word": "theater", "translation": "n. 剧院、戏剧表演" },
|
||
{ "word": "especially", "translation": "adv. 特别是、尤其" },
|
||
{ "word": "aggressive", "translation": "adj. 攻击性的" },
|
||
{ "word": "extreme", "translation": "adj.&n. 极度、极端、极大(的)" },
|
||
{ "word": "sense", "translation": "n. 意识" },
|
||
{ "word": "single", "translation": "adj. 单一的、单身的 v. 选中" },
|
||
{ "word": "previous", "translation": "adj. 先前的" },
|
||
{ "word": "obtain", "translation": "v. 获得" }
|
||
];
|
||
|
||
// 选中的单词索引
|
||
let selectedIndices = new Set();
|
||
|
||
// 页面加载时初始化
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
createParticles();
|
||
updateStats();
|
||
renderWordGrid();
|
||
});
|
||
|
||
// 创建背景粒子
|
||
function createParticles() {
|
||
const particlesContainer = document.getElementById('particles');
|
||
const particleCount = 30;
|
||
for (let i = 0; i < particleCount; i++) {
|
||
const particle = document.createElement('div');
|
||
particle.classList.add('particle');
|
||
const size = Math.random() * 20 + 5;
|
||
particle.style.width = `${size}px`;
|
||
particle.style.height = `${size}px`;
|
||
particle.style.left = `${Math.random() * 100}%`;
|
||
particle.style.top = `${Math.random() * 100}%`;
|
||
const delay = Math.random() * 15;
|
||
const duration = 15 + Math.random() * 10;
|
||
particle.style.animationDelay = `${delay}s`;
|
||
particle.style.animationDuration = `${duration}s`;
|
||
const colors = ['rgba(100, 255, 200, 0.2)', 'rgba(0, 210, 255, 0.2)', 'rgba(93, 230, 255, 0.2)'];
|
||
particle.style.background = colors[Math.floor(Math.random() * colors.length)];
|
||
particlesContainer.appendChild(particle);
|
||
}
|
||
}
|
||
|
||
// 标签页切换
|
||
function switchTab(tabId) {
|
||
// 移除所有标签的active状态
|
||
document.querySelectorAll('.tab-btn').forEach(tab => {
|
||
tab.classList.remove('active');
|
||
});
|
||
// 移除所有内容区域的active状态
|
||
document.querySelectorAll('.tab-content').forEach(content => {
|
||
content.classList.remove('active');
|
||
});
|
||
|
||
// 设置当前标签为active
|
||
event.target.classList.add('active');
|
||
// 显示对应的内容区域
|
||
document.getElementById(tabId + 'Tab').classList.add('active');
|
||
|
||
// 如果是导出标签,更新导出统计
|
||
if (tabId === 'export') {
|
||
document.getElementById('exportWordCount').textContent = selectedIndices.size;
|
||
}
|
||
}
|
||
|
||
// 更新统计信息
|
||
function updateStats() {
|
||
document.getElementById('totalWords').textContent = wordLibrary.length;
|
||
document.getElementById('selectedCount').textContent = selectedIndices.size;
|
||
const percentage = wordLibrary.length > 0 ? Math.round((selectedIndices.size / wordLibrary.length) * 100) : 0;
|
||
document.getElementById('percentage').textContent = percentage + '%';
|
||
}
|
||
|
||
// 渲染单词网格
|
||
function renderWordGrid(filteredWords = wordLibrary, filteredIndices = null) {
|
||
const wordGrid = document.getElementById('wordGrid');
|
||
wordGrid.innerHTML = '';
|
||
|
||
filteredWords.forEach((wordObj, index) => {
|
||
// 如果是过滤后的数组,需要找到原始索引
|
||
const actualIndex = filteredIndices ? filteredIndices[index] : index;
|
||
|
||
const wordItem = document.createElement('div');
|
||
wordItem.className = `word-item ${selectedIndices.has(actualIndex) ? 'selected' : ''}`;
|
||
wordItem.innerHTML = `
|
||
<div class="word-text">${wordObj.word}</div>
|
||
<div class="word-translation">${wordObj.translation}</div>
|
||
`;
|
||
wordItem.addEventListener('click', () => toggleWordSelection(actualIndex));
|
||
wordGrid.appendChild(wordItem);
|
||
});
|
||
}
|
||
|
||
// 切换单词选择状态
|
||
function toggleWordSelection(index) {
|
||
if (selectedIndices.has(index)) {
|
||
selectedIndices.delete(index);
|
||
} else {
|
||
selectedIndices.add(index);
|
||
}
|
||
updateStats();
|
||
renderWordGrid(); // 重新渲染以更新选中状态
|
||
}
|
||
|
||
// 全选单词
|
||
function selectAllWords() {
|
||
for (let i = 0; i < wordLibrary.length; i++) {
|
||
selectedIndices.add(i);
|
||
}
|
||
updateStats();
|
||
renderWordGrid();
|
||
}
|
||
|
||
// 取消全选
|
||
function deselectAllWords() {
|
||
selectedIndices.clear();
|
||
updateStats();
|
||
renderWordGrid();
|
||
}
|
||
|
||
// 随机选择60个单词
|
||
function randomSelectWords() {
|
||
selectedIndices.clear();
|
||
const totalWords = wordLibrary.length;
|
||
const count = Math.min(60, totalWords);
|
||
|
||
// 创建索引数组并随机打乱
|
||
const indices = Array.from({length: totalWords}, (_, i) => i);
|
||
for (let i = indices.length - 1; i > 0; i--) {
|
||
const j = Math.floor(Math.random() * (i + 1));
|
||
[indices[i], indices[j]] = [indices[j], indices[i]];
|
||
}
|
||
|
||
// 选择前count个
|
||
for (let i = 0; i < count; i++) {
|
||
selectedIndices.add(indices[i]);
|
||
}
|
||
|
||
updateStats();
|
||
renderWordGrid();
|
||
}
|
||
|
||
// 搜索单词
|
||
function filterWords() {
|
||
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
|
||
if (!searchTerm) {
|
||
renderWordGrid();
|
||
return;
|
||
}
|
||
|
||
const filteredIndices = [];
|
||
const filteredWords = wordLibrary.filter((wordObj, index) => {
|
||
const match = wordObj.word.toLowerCase().includes(searchTerm) ||
|
||
wordObj.translation.toLowerCase().includes(searchTerm);
|
||
if (match) filteredIndices.push(index);
|
||
return match;
|
||
});
|
||
|
||
renderWordGrid(filteredWords, filteredIndices);
|
||
}
|
||
|
||
// 清除搜索
|
||
function clearSearch() {
|
||
document.getElementById('searchInput').value = '';
|
||
renderWordGrid();
|
||
}
|
||
|
||
// 添加新单词
|
||
function addNewWordWithTranslation() {
|
||
const wordInput = document.getElementById('newWordInput');
|
||
const translationInput = document.getElementById('newTranslationInput');
|
||
const word = wordInput.value.trim();
|
||
const translation = translationInput.value.trim();
|
||
|
||
if (!word || !translation) {
|
||
alert('请输入完整的单词和翻译!');
|
||
return;
|
||
}
|
||
|
||
// 检查是否已存在
|
||
const exists = wordLibrary.some(item => item.word.toLowerCase() === word.toLowerCase());
|
||
if (exists) {
|
||
alert('该单词已存在于词库中!');
|
||
return;
|
||
}
|
||
|
||
// 添加到词库
|
||
wordLibrary.push({ word, translation });
|
||
|
||
// 清空输入框
|
||
wordInput.value = '';
|
||
translationInput.value = '';
|
||
|
||
// 更新显示
|
||
updateStats();
|
||
renderWordGrid();
|
||
|
||
// 隐藏添加提示
|
||
document.getElementById('addWordSuggestion').style.display = 'none';
|
||
}
|
||
|
||
// 删除选中的单词
|
||
function deleteSelectedWords() {
|
||
if (selectedIndices.size === 0) {
|
||
alert('请先选择要删除的单词!');
|
||
return;
|
||
}
|
||
|
||
if (!confirm(`确定要删除选中的 ${selectedIndices.size} 个单词吗?`)) {
|
||
return;
|
||
}
|
||
|
||
// 按索引从大到小排序,避免删除时索引变化的问题
|
||
const sortedIndices = Array.from(selectedIndices).sort((a, b) => b - a);
|
||
|
||
// 删除单词
|
||
for (const index of sortedIndices) {
|
||
wordLibrary.splice(index, 1);
|
||
}
|
||
|
||
// 清空选中状态
|
||
selectedIndices.clear();
|
||
|
||
// 更新显示
|
||
updateStats();
|
||
renderWordGrid();
|
||
}
|
||
|
||
// 导出配置文件(Base64加密英文单词,中文翻译保持明文)
|
||
function exportConfig() {
|
||
if (selectedIndices.size === 0) {
|
||
alert('请先选择要导出的单词!');
|
||
return;
|
||
}
|
||
|
||
// 获取选中的单词对象
|
||
const selectedWords = Array.from(selectedIndices).map(index => wordLibrary[index]);
|
||
|
||
// 创建包含加密英文单词和明文翻译的JSON结构
|
||
const exportData = {
|
||
words: selectedWords.map(item => ({
|
||
word: btoa(item.word), // 加密英文单词
|
||
translation: item.translation // 保持明文翻译
|
||
})),
|
||
created: new Date().toISOString(),
|
||
count: selectedWords.length
|
||
};
|
||
|
||
// 生成JavaScript文件内容
|
||
const jsContent = `var configData = ${JSON.stringify(exportData, null, 2)};\n`;
|
||
|
||
// 创建下载链接
|
||
const blob = new Blob([jsContent], { type: 'application/javascript' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `word_dictation_config_${new Date().getTime()}.js`;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
URL.revokeObjectURL(url);
|
||
|
||
alert(`成功导出包含 ${selectedWords.length} 个单词的配置文件!`);
|
||
}
|
||
</script>
|
||
</body>
|
||
</html> |