Files
PeojectTWT/base64_gen.html

805 lines
29 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>