Files
PeojectTWT/UI_v3_60 copy.html
Tommmy 730a701deb unfix: add some bugs
呃这个可能有点炸了
2025-10-16 17:39:50 +08:00

1993 lines
66 KiB
HTML
Raw Permalink 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;
}
/* 鼠标跟随小圈 - 更慢更滑溜 */
.cursor-follower {
position: fixed;
width: 20px;
height: 20px;
border: 2px solid rgba(100, 255, 200, 0.7);
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
z-index: 9999;
transition: width 0.5s, height 0.5s, border 0.5s, transform 0.1s;
mix-blend-mode: difference;
}
.cursor-follower.hover {
width: 40px;
height: 40px;
border: 2px solid rgba(100, 255, 200, 0.9);
background: rgba(100, 255, 200, 0.1);
}
.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;
}
/* 模式选择按钮 */
.mode-selector {
display: flex;
justify-content: center;
gap: 30px;
margin: 40px 0;
animation: fadeInUp 1s ease-out 0.3s both;
}
.mode-btn {
padding: 20px 40px;
border-radius: 25px;
font-size: 1.2rem;
font-weight: 600;
cursor: pointer;
transition: all 0.4s ease;
position: relative;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
border: none;
color: #0a2a1a;
min-width: 180px;
}
.teacher-btn {
background: linear-gradient(45deg, #7cffcb, #00d2ff, #5de6ff);
}
.student-btn {
background: linear-gradient(45deg, #5de6ff, #00d2ff, #7cffcb);
}
.mode-btn:hover {
transform: translateY(-5px) scale(1.05);
box-shadow: 0 15px 35px rgba(100, 255, 200, 0.4);
}
.mode-btn:active {
transform: scale(0.95);
}
.mode-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;
}
.mode-btn:hover::before {
left: 100%;
}
/* 主要内容区域 */
.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; /* 或者设置一个固定高度 */
}
/* 欢迎界面 */
.welcome-screen {
padding: 40px 20px;
}
.welcome-icon {
font-size: 5rem;
margin-bottom: 30px;
background: linear-gradient(45deg, #7cffcb, #00d2ff, #5de6ff);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.welcome-title {
font-size: 2.2rem;
color: #fff;
margin-bottom: 20px;
}
.welcome-text {
color: #c0ffea;
font-size: 1.1rem;
line-height: 1.8;
max-width: 600px;
margin: 0 auto 30px;
}
/* 老师端界面 */
.teacher-screen {
display: none;
}
/* 标签页 */
.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:disabled {
opacity: 0.5;
cursor: not-allowed;
/* 移除或减弱 hover 和 active 效果 */
}
.action-btn:disabled:hover {
transform: none;
box-shadow: none;
}
.action-btn:disabled:active {
transform: none;
}
.action-btn:disabled::before {
/* 移除或减弱 hover 效果动画 */
display: none;
}
/* --- 结束禁用按钮样式 --- */
.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: 300px;
overflow-y: auto;
padding: 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;
}
/* 学生端界面 */
.student-screen {
display: none;
}
/* 文件上传区域 */
.file-upload-area {
border: 2px dashed rgba(100, 255, 200, 0.3);
border-radius: 20px;
padding: 50px 30px;
margin: 30px 0;
text-align: center;
transition: all 0.3s ease;
background: rgba(0, 0, 0, 0.2);
cursor: pointer;
}
.file-upload-area:hover {
border-color: #7cffcb;
background: rgba(124, 255, 203, 0.1);
}
.upload-icon {
font-size: 4rem;
color: #7cffcb;
margin-bottom: 20px;
}
.upload-text {
color: #c0ffea;
font-size: 1.2rem;
margin-bottom: 20px;
}
.upload-subtext {
color: #a0ffe0;
font-size: 0.9rem;
margin-bottom: 20px;
}
/* 导入信息卡片 */
.import-info {
background: linear-gradient(135deg, rgba(52, 199, 89, 0.2), rgba(124, 255, 203, 0.2));
border-radius: 20px;
padding: 30px;
margin: 30px 0;
border: 1px solid rgba(52, 199, 89, 0.3);
display: none;
}
.import-info h3 {
color: #7cffcb;
margin-bottom: 20px;
font-size: 1.5rem;
}
.import-details {
color: #c0ffea;
margin-bottom: 20px;
text-align: left;
}
.import-details p {
margin: 10px 0;
}
/* 默写区域 */
.dictation-area {
display: none;
padding: 30px 0;
}
.word-display {
font-size: 3rem;
font-weight: 300;
color: #fff;
margin: 40px 0;
text-shadow: 0 0 30px rgba(100, 255, 200, 0.5);
min-height: 150px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.word-blank {
display: inline-block;
min-width: 300px;
text-align: center;
margin: 10px 0;
font-family: 'Courier New', monospace;
letter-spacing: 5px;
font-size: 2.5rem;
}
.word-translation-student {
color: #a0ffe0;
font-size: 1.5rem;
margin-top: 15px;
}
.answer-input {
padding: 15px 20px;
border-radius: 15px;
border: 2px solid rgba(100, 255, 200, 0.3);
background: rgba(0, 0, 0, 0.2);
color: #fff;
font-size: 1.5rem;
text-align: center;
outline: none;
width: 300px;
margin: 20px 0;
}
.answer-input:focus {
border-color: #7cffcb;
box-shadow: 0 0 20px rgba(124, 255, 203, 0.5);
}
.input-indicator {
color: #7cffcb;
font-size: 1.2rem;
margin-bottom: 10px;
font-weight: 500;
}
.progress-info {
color: #c0ffea;
font-size: 1.2rem;
margin: 20px 0;
}
.progress-bar {
width: 100%;
height: 10px;
background: rgba(255, 255, 255, 0.1);
border-radius: 5px;
overflow: hidden;
margin: 20px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(45deg, #7cffcb, #00d2ff, #5de6ff);
border-radius: 5px;
width: 0%;
transition: width 0.5s ease;
}
.dictation-controls {
display: flex;
justify-content: center;
gap: 20px;
margin: 40px 0;
flex-wrap: wrap;
}
.control-btn {
padding: 15px 30px;
border-radius: 15px;
border: none;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
min-width: 150px;
}
.prev-btn {
background: linear-gradient(45deg, #5de6ff, #00d2ff);
color: #0a2a1a;
}
.next-btn {
background: linear-gradient(45deg, #7cffcb, #00d2ff);
color: #0a2a1a;
}
.end-btn {
background: linear-gradient(45deg, #FF3B30, #ff6b6b);
color: white;
}
.submit-btn {
background: linear-gradient(45deg, #34C759, #7cffcb);
color: #0a2a1a;
}
/* 成绩报告区域 */
.result-area {
display: none;
padding: 30px 0;
}
.result-header {
color: #fff;
margin-bottom: 30px;
}
.score-circle {
width: 200px;
height: 200px;
border-radius: 50%;
background: conic-gradient(#7cffcb 0% 70%, #5de6ff 70% 100%);
margin: 0 auto 30px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.score-inner {
width: 160px;
height: 160px;
border-radius: 50%;
background: rgba(10, 42, 26, 0.9);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.score-number {
font-size: 3rem;
font-weight: 700;
color: #7cffcb;
margin-bottom: 5px;
}
.score-text {
color: #c0ffea;
font-size: 1.2rem;
}
.result-stats {
display: flex;
justify-content: space-around;
margin: 30px 0;
flex-wrap: wrap;
gap: 20px;
}
.result-stat-card {
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
padding: 20px;
min-width: 150px;
border: 1px solid rgba(100, 255, 200, 0.2);
}
.result-stat-number {
font-size: 2rem;
font-weight: 700;
color: #7cffcb;
margin-bottom: 5px;
}
.result-stat-label {
color: #c0ffea;
font-size: 0.9rem;
}
.grade-badge {
padding: 10px 20px;
border-radius: 20px;
font-weight: 600;
margin: 20px 0;
display: inline-block;
}
.grade-a {
background: linear-gradient(45deg, #34C759, #7cffcb);
color: #0a2a1a;
}
.grade-b {
background: linear-gradient(45deg, #FFCC00, #ffd93d);
color: #0a2a1a;
}
.grade-c {
background: linear-gradient(45deg, #FF9500, #ffcc80);
color: #0a2a1a;
}
.grade-d {
background: linear-gradient(45deg, #FF3B30, #ff6b6b);
color: white;
}
/* 错误详情列表 */
.error-details {
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
padding: 25px;
margin: 30px 0;
border: 1px solid rgba(255, 107, 107, 0.3);
}
.error-details h3 {
color: #ff6b6b;
margin-bottom: 20px;
text-align: center;
}
.error-list {
list-style: none;
text-align: left;
}
.error-item {
display: flex;
align-items: center;
padding: 15px;
margin: 10px 0;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
border-left: 4px solid #ff6b6b;
}
.error-number {
font-weight: bold;
color: #ff6b6b;
margin-right: 15px;
min-width: 30px;
}
.error-content {
flex: 1;
}
.error-word {
font-weight: bold;
color: #fff;
margin-bottom: 5px;
}
.error-answer {
color: #ffd93d;
margin-bottom: 5px;
}
.error-correct {
color: #7cffcb;
display: flex;
align-items: center;
}
.error-arrow {
margin: 0 10px;
color: #ffd93d;
}
/* Particles background */
.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); }
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@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); }
}
/* --- 添加滚动动画相关的 CSS --- */
/* 为需要动画的容器添加基类 */
.animate-container {
position: relative;
overflow: hidden; /* 防止内容溢出 */
}
/* 定义动画类 */
.slide-transition {
transition: transform 0.5s cubic-bezier(0.25, 0.8, 0.25, 1), opacity 0.5s ease-in-out;
}
/* 水平滑入(从右到左) */
.slide-enter-from-right {
transform: translateX(100%);
opacity: 0;
}
.slide-enter-to-right, .slide-leave-from-right {
transform: translateX(0);
opacity: 1;
}
.slide-leave-to-right {
transform: translateX(-100%);
opacity: 0;
}
/* 水平滑出(从左到右) */
.slide-enter-from-left {
transform: translateX(-100%);
opacity: 0;
}
.slide-enter-to-left, .slide-leave-from-left {
transform: translateX(0);
opacity: 1;
}
.slide-leave-to-left {
transform: translateX(100%);
opacity: 0;
}
/* 垂直滑入(从下到上) - 用于标签页切换 */
.slide-v-enter-from {
transform: translateY(20px);
opacity: 0;
}
.slide-v-enter-to, .slide-v-leave-from {
transform: translateY(0);
opacity: 1;
}
.slide-v-leave-to {
transform: translateY(-20px);
opacity: 0;
}
/* --- 修改现有样式以支持动画 --- */
/* 老师端和学生端屏幕需要绝对定位来实现滚动效果 */
/* 但为了兼容性,我们使用 opacity 和 transform 来模拟 */
.teacher-screen, .student-screen {
/* 移除 display: none; */
/* display: none; */
opacity: 0;
transform: translateX(100%);
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 40px; /* 与 .main-content padding 一致 */
box-sizing: border-box;
}
.teacher-screen.active, .student-screen.active {
position: relative; /* 激活时恢复相对定位 */
opacity: 1;
transform: translateX(0);
}
/* 标签内容区域动画 */
.tab-content {
/* display: none; */ /* 移除 display: none */
opacity: 0;
transform: translateY(20px);
}
.tab-content.active {
/* display: block; */ /* 移除 display: block */
opacity: 1;
transform: translateY(0);
}
/* --- 结束添加滚动动画相关的 CSS --- */
/* 响应式设计 */
@media (max-width: 768px) {
.title {
font-size: 2.2rem;
}
.logo {
font-size: 3.5rem;
}
.mode-selector {
flex-direction: column;
align-items: center;
gap: 15px;
}
.mode-btn {
width: 100%;
max-width: 300px;
}
.main-content {
padding: 25px 20px;
}
.word-grid {
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 10px;
}
.word-item {
padding: 12px 8px;
font-size: 0.9rem;
}
.word-display {
font-size: 2rem;
}
.word-blank {
font-size: 1.8rem;
min-width: 200px;
}
.answer-input {
width: 250px;
font-size: 1.2rem;
}
.dictation-controls {
flex-direction: column;
align-items: center;
}
.control-btn {
width: 100%;
max-width: 250px;
}
.cube-container {
width: 100px;
height: 100px;
top: 25%;
}
.cube-face {
width: 100px;
height: 100px;
font-size: 1.5rem;
}
.cube-face-front { transform: rotateY(0deg) translateZ(50px); }
.cube-face-back { transform: rotateY(180deg) translateZ(50px); }
.cube-face-right { transform: rotateY(90deg) translateZ(50px); }
.cube-face-left { transform: rotateY(-90deg) translateZ(50px); }
.cube-face-top { transform: rotateX(90deg) translateZ(50px); }
.cube-face-bottom { transform: rotateX(-90deg) translateZ(50px); }
}
@media (max-width: 480px) {
.title {
font-size: 1.8rem;
}
.subtitle {
font-size: 1rem;
}
.main-content {
padding: 20px 15px;
}
.word-grid {
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
}
.word-display {
font-size: 1.5rem;
}
.word-blank {
font-size: 1.5rem;
min-width: 150px;
letter-spacing: 3px;
}
.answer-input {
width: 200px;
font-size: 1rem;
}
.stats-container {
flex-direction: column;
align-items: center;
}
.stat-card {
width: 100%;
max-width: 200px;
}
.score-circle {
width: 150px;
height: 150px;
}
.score-inner {
width: 120px;
height: 120px;
}
.score-number {
font-size: 2rem;
}
.error-item {
flex-direction: column;
align-items: flex-start;
text-align: left;
}
.error-number {
margin-bottom: 10px;
}
}
</style>
</head>
<body>
<!-- 鼠标跟随小圈 -->
<div class="cursor-follower"></div>
<!-- 背景粒子 -->
<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-book"></i>
</div>
<h1 class="title">单词默写系统</h1>
<p class="subtitle">简单易用的单词默写工具</p>
</div>
<!-- 模式选择 -->
<div class="mode-selector">
<button class="mode-btn teacher-btn" onclick="switchMode('teacher')">
<i class="fas fa-chalkboard-teacher"></i> 教师端
</button>
<button class="mode-btn student-btn" onclick="switchMode('student')">
<i class="fas fa-user-graduate"></i> 学生端
</button>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<!-- 欢迎界面 -->
<div id="welcomeScreen" class="welcome-screen">
<div class="welcome-icon">
<i class="fas fa-book-open"></i>
</div>
<h2 class="welcome-title">欢迎使用单词默写系统</h2>
<p class="welcome-text">
这是一个便捷的单词默写工具,老师可以选择单词并导出配置文件,
学生可以导入配置文件进行单词默写练习。
</p>
<p class="welcome-text">
请先选择使用模式:教师端或学生端
</p>
</div>
<!-- 老师端界面 -->
<div id="teacherScreen" class="teacher-screen animate-container">
<!-- 标签页 -->
<div class="tabs">
<button class="tab-btn active" onclick="switchTab('selection')">单词选择</button>
</div>
<!-- 单词选择标签页 -->
<div id="selectionTab">
<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-success" onclick="exportConfig()">
<i class="fas fa-download"></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>
<!-- 学生端界面 -->
<div id="studentScreen" class="student-screen animate-container">
<h3 style="color: #fff; margin: 20px 0;">导入配置文件</h3>
<div class="file-upload-area" id="fileUploadArea" onclick="document.getElementById('configFile').click()">
<div class="upload-icon">
<i class="fas fa-cloud-upload-alt"></i>
</div>
<h3 class="upload-text">点击或拖拽文件到此处上传</h3>
<p class="upload-subtext">支持 .json 格式的配置文件</p>
<button class="action-btn btn-primary">
<i class="fas fa-folder-open"></i> 选择文件
</button>
<input type="file" id="configFile" accept=".json" style="display: none;" onchange="handleFileSelect(event)">
</div>
<div id="importInfo" class="import-info">
<h3><i class="fas fa-check-circle"></i> 配置导入成功</h3>
<div class="import-details">
<p><strong>单词数量:</strong><span id="importedWordCount">0</span></p>
<p><strong>创建时间:</strong><span id="importedTime">-</span></p>
</div>
<button class="action-btn btn-success" onclick="startDictation()">
<i class="fas fa-play"></i> 开始默写
</button>
</div>
<div id="dictationArea" class="dictation-area">
<h3 style="color: #fff; margin-bottom: 30px;">单词默写</h3>
<div class="word-display" id="wordDisplay">
<div class="input-indicator">请输入单词:</div>
<div class="word-blank" id="wordBlank">_ _ _ _ _</div>
<div class="word-first-letter" id="wordFirstLetter" style="color:#ffd93d;font-size:2rem;margin-top:10px;"></div>
<div class="word-translation-student" id="wordTranslationStudent"></div> <!-- 新增翻译显示 -->
</div>
<input type="text" class="answer-input" id="answerInput" placeholder="请输入单词..." onkeypress="handleKeyPress(event)">
<div class="progress-info" id="progressInfo">进度: 0/0</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="dictation-controls">
<button class="control-btn prev-btn" onclick="showPrevWord()">
<i class="fas fa-arrow-left"></i> 上一个
</button>
<button class="control-btn submit-btn" onclick="submitAnswer()">
<i class="fas fa-check"></i> 提交答案
</button>
<button class="control-btn next-btn" onclick="showNextWord()">
下一个 <i class="fas fa-arrow-right"></i>
</button>
<button class="control-btn end-btn" onclick="endDictation()">
<i class="fas fa-stop"></i> 结束默写
</button>
</div>
</div>
<div id="resultArea" class="result-area">
<h2 class="result-header">默写成绩报告</h2>
<div class="score-circle">
<div class="score-inner">
<div class="score-number" id="finalScore">0</div>
<div class="score-text">正确率</div>
</div>
</div>
<div class="grade-badge" id="gradeBadge">等级: A</div>
<div class="result-stats">
<div class="result-stat-card">
<div class="result-stat-number" id="correctCount">0</div>
<div class="result-stat-label">正确</div>
</div>
<div class="result-stat-card">
<div class="result-stat-number" id="wrongCount">0</div>
<div class="result-stat-label">错误</div>
</div>
<div class="result-stat-card">
<div class="result-stat-number" id="totalCount">0</div>
<div class="result-stat-label">总计</div>
</div>
</div>
<div id="errorDetails" class="error-details">
<h3><i class="fas fa-times-circle"></i> 错误详情</h3>
<ul class="error-list" id="errorList">
<!-- 错误列表将通过JavaScript动态生成 -->
</ul>
</div>
<button class="action-btn btn-primary" onclick="restartDictation()">
<i class="fas fa-redo"></i> 重新开始
</button>
</div>
</div>
</div>
</div>
<script>
// 单词库 - 扩展版 (带中文翻译) - 初始为空
let toeflWords = [
];
// 全局变量
let selectedWords = []; // 存储选中的单词对象 { word, translation }
let importedWords = []; // 存储从配置文件导入的单词对象 { word, translation }
let currentWordIndex = 0;
let dictationStarted = false;
let userAnswers = []; // 存储用户答案 (字符串)
let correctAnswers = []; // 存储正确答案 (字符串) - 修复:存储英文单词字符串
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', function() {
renderWordGrid();
updateStats();
createParticles();
initCursorFollower();
});
// 创建背景粒子
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 initCursorFollower() {
const cursor = document.querySelector('.cursor-follower');
const buttons = document.querySelectorAll('button, .feature-card');
let mouseX = 0;
let mouseY = 0;
let cursorX = 0;
let cursorY = 0;
const speed = 0.1;
document.addEventListener('mousemove', e => {
mouseX = e.clientX;
mouseY = e.clientY;
});
function animateCursor() {
const distX = mouseX - cursorX;
const distY = mouseY - cursorY;
cursorX += distX * speed;
cursorY += distY * speed;
cursor.style.left = cursorX + 'px';
cursor.style.top = cursorY + 'px';
requestAnimationFrame(animateCursor);
}
animateCursor();
buttons.forEach(button => {
button.addEventListener('mouseenter', () => {
cursor.classList.add('hover');
});
button.addEventListener('mouseleave', () => {
cursor.classList.remove('hover');
});
});
}
// 模式切换 (带滑动动画)
function switchMode(mode) {
const welcomeScreen = document.getElementById('welcomeScreen');
const teacherScreen = document.getElementById('teacherScreen');
const studentScreen = document.getElementById('studentScreen');
// 添加动画类
teacherScreen.classList.add('slide-transition');
studentScreen.classList.add('slide-transition');
// 隐藏所有屏幕
welcomeScreen.style.display = 'none';
teacherScreen.classList.remove('active');
studentScreen.classList.remove('active');
// 根据目标模式显示屏幕
if (mode === 'teacher') {
// 从右侧滑入
teacherScreen.classList.add('slide-enter-from-right');
teacherScreen.style.display = 'block'; // 确保元素可见
// 强制重绘以触发动画
teacherScreen.offsetHeight;
teacherScreen.classList.remove('slide-enter-from-right');
teacherScreen.classList.add('active');
} else if (mode === 'student') {
// 从右侧滑入
studentScreen.classList.add('slide-enter-from-right');
studentScreen.style.display = 'block'; // 确保元素可见
// 强制重绘以触发动画
studentScreen.offsetHeight;
studentScreen.classList.remove('slide-enter-from-right');
studentScreen.classList.add('active');
} else {
// 默认显示欢迎界面 (如果需要从其他模式返回)
welcomeScreen.style.display = 'block';
}
}
// 标签页切换(老师端只有一个标签页)
function switchTab(tabId) {
// 移除所有标签的active状态
document.querySelectorAll('.tab-btn').forEach(tab => {
tab.classList.remove('active');
});
// 设置当前标签为active
event.target.classList.add('active');
// 切换显示内容
if (tabId === 'selection') {
document.getElementById('selectionTab').style.display = 'block';
}
}
// 渲染单词网格
function renderWordGrid(filteredWords = toeflWords) {
const wordGrid = document.getElementById('wordGrid');
wordGrid.innerHTML = '';
filteredWords.forEach(wordObj => {
const wordItem = document.createElement('div');
wordItem.className = `word-item ${selectedWords.some(w => w.word === wordObj.word) ? 'selected' : ''}`;
// 修改:显示单词和翻译
wordItem.innerHTML = `
<div class="word-text">${wordObj.word}</div>
<div class="word-translation">${wordObj.translation}</div>
`;
wordItem.onclick = () => toggleWordSelection(wordObj); // 传递整个对象
wordGrid.appendChild(wordItem);
});
}
// 切换单词选择状态
function toggleWordSelection(wordObj) {
const index = selectedWords.findIndex(w => w.word === wordObj.word);
if (index > -1) {
selectedWords.splice(index, 1);
} else {
selectedWords.push(wordObj);
}
renderWordGrid();
updateStats();
}
// 更新统计信息
function updateStats() {
const total = toeflWords.length;
const selected = selectedWords.length;
const percentage = total > 0 ? Math.round((selected / total) * 100) : 0;
document.getElementById('selectedCount').textContent = selected;
document.getElementById('totalWords').textContent = total;
document.getElementById('percentage').textContent = percentage + '%';
}
// 全选单词
function selectAllWords() {
// 确保 selectedWords 包含 toeflWords 中的所有单词对象
selectedWords = [...toeflWords];
renderWordGrid(); // 重新渲染网格以反映选择状态
updateStats(); // 更新统计信息
}
// 取消全选
function deselectAllWords() {
selectedWords = []; // 清空已选单词数组
renderWordGrid(); // 重新渲染网格
updateStats(); // 更新统计信息
}
// 随机选择60个单词
function randomSelectWords() {
selectedWords = [];
// 创建一个 toeflWords 的副本并随机打乱
const shuffled = [...toeflWords].sort(() => 0.5 - Math.random());
// 选取前60个或如果总数不足60个则全部选取
selectedWords = shuffled.slice(0, Math.min(60, shuffled.length));
renderWordGrid(); // 重新渲染网格
updateStats(); // 更新统计信息
}
// 搜索单词
function filterWords() {
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
if (searchTerm === '') {
renderWordGrid();
document.getElementById('addWordSuggestion').style.display = 'none';
} else {
// 修改:在单词和翻译中搜索
const filtered = toeflWords.filter(wordObj =>
wordObj.word.toLowerCase().includes(searchTerm) ||
wordObj.translation.toLowerCase().includes(searchTerm)
);
renderWordGrid(filtered);
// 如果没有找到匹配的单词,显示添加单词提示
if (filtered.length === 0) {
document.getElementById('addWordSuggestion').style.display = 'block';
// 不再直接设置 newWordText而是预填充输入框
document.getElementById('newWordInput').value = searchTerm;
document.getElementById('newTranslationInput').value = '';
} else {
document.getElementById('addWordSuggestion').style.display = 'none';
}
}
}
// 添加新单词 (带翻译)
function addNewWordWithTranslation() {
const newWord = document.getElementById('newWordInput').value.trim().toLowerCase();
const newTranslation = document.getElementById('newTranslationInput').value.trim();
if (newWord && newTranslation) {
// 检查是否已存在
if (!toeflWords.some(w => w.word === newWord)) {
const newWordObj = { word: newWord, translation: newTranslation };
toeflWords.push(newWordObj);
toeflWords.sort((a, b) => a.word.localeCompare(b.word)); // 按字母排序
renderWordGrid();
updateStats();
document.getElementById('addWordSuggestion').style.display = 'none';
document.getElementById('searchInput').value = '';
document.getElementById('newWordInput').value = '';
document.getElementById('newTranslationInput').value = '';
// 显示添加成功提示
alert(`单词 "${newWord}" (${newTranslation}) 已成功添加到词库中!`);
} else {
alert(`单词 "${newWord}" 已存在于词库中!`);
}
} else {
alert('请输入英文单词和中文翻译!');
}
}
// 清除搜索
function clearSearch() {
document.getElementById('searchInput').value = '';
document.getElementById('addWordSuggestion').style.display = 'none';
renderWordGrid();
}
// 导出配置文件 - 修复下载问题
function exportConfig() {
if (selectedWords.length === 0) {
alert('请先选择单词!');
return;
}
const config = {
words: selectedWords, // 导出包含 word 和 translation 的对象数组
createdTime: new Date().toISOString(),
version: '1.1' // 更新版本号
};
// 创建Blob对象
const blob = new Blob([JSON.stringify(config, null, 2)], {type: 'application/json'});
// 创建下载链接
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'toefl_words_config_with_translation.json';
document.body.appendChild(a);
a.click();
// 清理
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 100);
// 添加成功动画
const exportBtn = event.target.closest('.action-btn');
const originalText = exportBtn.innerHTML;
exportBtn.innerHTML = '<i class="fas fa-check"></i> 已导出';
exportBtn.classList.add('btn-success');
setTimeout(() => {
exportBtn.innerHTML = originalText;
exportBtn.classList.remove('btn-success');
}, 2000);
}
// 处理文件选择
function handleFileSelect(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
try {
const config = JSON.parse(e.target.result);
// 兼容旧版本 (仅包含单词字符串的数组)
if (Array.isArray(config.words) && config.words.length > 0 && typeof config.words[0] === 'string') {
// 转换旧格式到新格式 (翻译留空)
importedWords = config.words.map(word => ({ word, translation: '' }));
} else if (Array.isArray(config.words) && config.words.length > 0 && typeof config.words[0] === 'object' && config.words[0].hasOwnProperty('word')) {
// 新格式
importedWords = config.words || [];
} else {
throw new Error('Invalid word list format');
}
const createdTime = new Date(config.createdTime);
document.getElementById('importedWordCount').textContent = importedWords.length;
document.getElementById('importedTime').textContent = createdTime.toLocaleString();
document.getElementById('importInfo').style.display = 'block';
} catch (error) {
console.error(error); // 在控制台打印错误详情
alert('配置文件格式错误或版本不兼容!');
}
};
reader.readAsText(file);
}
}
// 开始默写
function startDictation() {
if (importedWords.length === 0) {
alert('请先导入配置文件!');
return;
}
document.getElementById('importInfo').style.display = 'none';
document.getElementById('dictationArea').style.display = 'block';
// 修复:初始化状态
userAnswers = new Array(importedWords.length).fill('');
// 修复correctAnswers 应该是英文单词字符串数组
correctAnswers = importedWords.map(w => w.word);
currentWordIndex = 0;
dictationStarted = true;
showCurrentWord();
// 聚焦到输入框
document.getElementById('answerInput').focus();
}
// 显示当前单词(横杠形式)和翻译,并显示首字母
function showCurrentWord() {
if (currentWordIndex >= 0 && currentWordIndex < importedWords.length) {
const currentWordObj = importedWords[currentWordIndex];
const currentWord = currentWordObj.word;
const wordTranslation = currentWordObj.translation;
const wordLength = currentWord.length;
// 横线
const blanks = '_ '.repeat(wordLength).trim();
document.getElementById('wordBlank').textContent = blanks;
// 首字母提示
document.getElementById('wordFirstLetter').textContent = `首字母提示:${currentWord[0].toUpperCase()}`;
// 翻译
document.getElementById('wordTranslationStudent').textContent = wordTranslation ? `(${wordTranslation})` : '';
// 进度
document.getElementById('progressInfo').textContent =
`进度: ${currentWordIndex + 1}/${importedWords.length}`;
const progress = importedWords.length > 0 ?
Math.round(((currentWordIndex + 1) / importedWords.length) * 100) : 0;
document.getElementById('progressFill').style.width = progress + '%';
// 回填答案
document.getElementById('answerInput').value = userAnswers[currentWordIndex] || '';
document.getElementById('answerInput').focus();
}
}
// 处理键盘按键
function handleKeyPress(event) {
if (event.key === 'Enter') {
submitAnswer();
}
}
// 提交答案
function submitAnswer() {
const answerInput = document.getElementById('answerInput');
const userAnswer = answerInput.value.trim().toLowerCase();
if (userAnswer) {
// 保存用户答案 (字符串)
userAnswers[currentWordIndex] = userAnswer;
// 如果是最后一个单词,自动结束
if (currentWordIndex === importedWords.length - 1) {
endDictation();
} else {
// 自动跳到下一个单词
showNextWord();
}
} else {
alert('请输入答案!');
}
}
// 下一个单词
function showNextWord() {
if (currentWordIndex < importedWords.length - 1) {
currentWordIndex++;
showCurrentWord();
}
}
// 上一个单词
function showPrevWord() {
if (currentWordIndex > 0) {
currentWordIndex--;
showCurrentWord();
}
}
// 结束默写并显示成绩
function endDictation() {
dictationStarted = false;
// 计算成绩
let correctCount = 0;
const errorDetails = [];
for (let i = 0; i < importedWords.length; i++) {
// 修复:比较用户答案和正确答案 (都是字符串)
if (userAnswers[i] === correctAnswers[i]) {
correctCount++;
} else {
// 记录错误详情 (包含翻译)
errorDetails.push({
number: i + 1,
word: correctAnswers[i], // 正确答案是英文单词字符串
translation: importedWords[i].translation, // 获取翻译
userAnswer: userAnswers[i] || '(未作答)'
});
}
}
const totalCount = importedWords.length;
const accuracy = totalCount > 0 ? Math.round((correctCount / totalCount) * 100) : 0;
// 显示成绩报告
document.getElementById('dictationArea').style.display = 'none';
document.getElementById('resultArea').style.display = 'block';
// 更新成绩显示
document.getElementById('finalScore').textContent = accuracy + '%';
document.getElementById('correctCount').textContent = correctCount;
document.getElementById('wrongCount').textContent = totalCount - correctCount;
document.getElementById('totalCount').textContent = totalCount;
// 根据正确率显示等级
let gradeClass = '';
let gradeText = '';
if (accuracy >= 90) {
gradeClass = 'grade-a';
gradeText = 'A (优秀)';
} else if (accuracy >= 80) {
gradeClass = 'grade-b';
gradeText = 'B (良好)';
} else if (accuracy >= 70) {
gradeClass = 'grade-c';
gradeText = 'C (及格)';
} else {
gradeClass = 'grade-d';
gradeText = 'D (需要努力)';
}
const gradeBadge = document.getElementById('gradeBadge');
gradeBadge.textContent = '等级: ' + gradeText;
gradeBadge.className = 'grade-badge ' + gradeClass;
// 更新圆形进度条
const scoreCircle = document.querySelector('.score-circle');
const gradientDegree = (accuracy / 100) * 360;
scoreCircle.style.background = `conic-gradient(#7cffcb 0deg ${gradientDegree}deg, #5de6ff ${gradientDegree}deg 360deg)`;
// 显示错误详情
const errorList = document.getElementById('errorList');
errorList.innerHTML = '';
if (errorDetails.length > 0) {
errorDetails.forEach(error => {
const li = document.createElement('li');
li.className = 'error-item';
// 修改:显示翻译
li.innerHTML = `
<div class="error-number">${error.number}.</div>
<div class="error-content">
<div class="error-word">${error.word} ${error.translation ? `(${error.translation})` : ''}</div>
<div class="error-answer">您的答案: ${error.userAnswer}</div>
<div class="error-correct">
<i class="fas fa-times" style="color: #ff6b6b;"></i>
<span class="error-arrow">→</span>
<i class="fas fa-check" style="color: #7cffcb;"></i>
<span style="margin-left: 10px;">正确答案: ${error.word}</span>
</div>
</div>
`;
errorList.appendChild(li);
});
} else {
const li = document.createElement('li');
li.innerHTML = '<div style="color: #7cffcb; text-align: center; padding: 20px;"><i class="fas fa-check-circle"></i> 恭喜!全部正确!</div>';
errorList.appendChild(li);
}
}
// 重新开始默写
function restartDictation() {
document.getElementById('resultArea').style.display = 'none';
document.getElementById('dictationArea').style.display = 'block';
// 重置状态
userAnswers = new Array(importedWords.length).fill('');
currentWordIndex = 0;
dictationStarted = true;
showCurrentWord();
}
// 拖拽上传功能
document.addEventListener('DOMContentLoaded', function() {
const uploadArea = document.getElementById('fileUploadArea');
uploadArea.addEventListener('dragover', function(e) {
e.preventDefault();
uploadArea.style.borderColor = '#7cffcb';
uploadArea.style.backgroundColor = 'rgba(124, 255, 203, 0.1)';
});
uploadArea.addEventListener('dragleave', function(e) {
e.preventDefault();
uploadArea.style.borderColor = '';
uploadArea.style.backgroundColor = '';
});
uploadArea.addEventListener('drop', function(e) {
e.preventDefault();
uploadArea.style.borderColor = '';
uploadArea.style.backgroundColor = '';
if (e.dataTransfer.files.length) {
document.getElementById('configFile').files = e.dataTransfer.files;
const event = new Event('change');
document.getElementById('configFile').dispatchEvent(event);
}
});
});
</script>
</body>
</html>