diff --git a/mainPage.js b/mainPage.js new file mode 100644 index 0000000..7400867 --- /dev/null +++ b/mainPage.js @@ -0,0 +1,528 @@ +let students = JSON.parse(localStorage.getItem('students')) || []; +let selectedStudent = null; +let intervalId; +let lock = false;//自动加分锁 +let lock1 = false;//手动加分锁 +let onClassAdded = false; +let autoPointsAdded = false; +let manualPointsUsed = false; +let studentDrawn = false; +let starLock = false; + +const stars = document.querySelectorAll('.rating label'); + +stars.forEach(star => { + star.addEventListener('mouseenter', () => { + const number = star.querySelector('.star-number'); + number.classList.remove('hidden'); + }); + + star.addEventListener('mouseleave', () => { + const number = star.querySelector('.star-number'); + number.classList.add('hidden'); + }); +}); + +const particleCanvas = document.getElementById('particleCanvas'); +const particleCtx = particleCanvas.getContext('2d'); +particleCanvas.width = window.innerWidth; +particleCanvas.height = window.innerHeight; + +let particles = []; + +function createParticlesFromText(a, b) { + // 清空画布 + particleCtx.clearRect(0, 0, particleCanvas.width, particleCanvas.height); + + // 设置字体 + particleCtx.font = '150px "Long Cang"'; + particleCtx.fillStyle = '#003366'; + + // 绘制第一行文字 + const x1 = particleCanvas.width / 2 - particleCtx.measureText(selectedStudent.name).width / 2; + const y1 = particleCanvas.height / 2 - 50; // 向上移动50像素 + particleCtx.fillText(selectedStudent.name, x1, y1); + + // 绘制第二行文字 + const x2 = particleCanvas.width / 2 - particleCtx.measureText(selectedStudent.id).width / 2; + const y2 = particleCanvas.height / 2 + 70; // 向下移动70像素 + particleCtx.fillText(selectedStudent.id, x2, y2); + + // 获取整个画布的像素数据 + const imageData = particleCtx.getImageData(0, 0, particleCanvas.width, particleCanvas.height); + + // 清空粒子数组 + particles = []; + + // 创建粒子 + for (let y = 0; y < imageData.height; y += 2) { + for (let x = 0; x < imageData.width; x += 2) { + const index = (y * imageData.width + x) * 4; + const alpha = imageData.data[index + 3]; + if (alpha > 128) { // 只选择不透明的像素 + let particle = new Particle(Math.random() * particleCanvas.width, Math.random() * particleCanvas.height); + particle.targetX = x; + particle.targetY = y; + particles.push(particle); + } + } + } + + // 启动粒子动画 + animateParticles(); +} + +function Particle(x, y) { + this.x = x; + this.y = y; + this.size = 1; + this.baseX = this.x; + this.baseY = this.y; + this.density = Math.random() * 30 + 1; +} + +Particle.prototype.draw = function () { + particleCtx.fillStyle = 'black'; + particleCtx.beginPath(); + particleCtx.arc(this.x, this.y, this.size, 0, Math.PI * 2); // 绘制粒子 + particleCtx.closePath(); + particleCtx.fill(); +}; + +Particle.prototype.update = function () { + let dx = this.targetX - this.x; + let dy = this.targetY - this.y; + let distance = Math.sqrt(dx * dx + dy * dy); + let speed = distance / 20; // 移动速度,离目标越远速度越快 + this.x += dx / distance * speed; + this.y += dy / distance * speed; + + // 减少抖动,当粒子非常接近目标位置时停止移动 + if (distance < 1) { + this.x = this.targetX; + this.y = this.targetY; + } +}; + +function animateParticles() { + particleCtx.clearRect(0, 0, particleCanvas.width, particleCanvas.height); // 清除上一帧的粒子 + + particles.forEach(particle => { + particle.update(); // 更新每个粒子的状态 + particle.draw(); // 绘制每个粒子 + }); + + requestAnimationFrame(animateParticles); // 循环动画 +} + +function registerTooltipEvents() { + const buttons = document.querySelectorAll('button[data-tooltip]'); + const tooltip = document.getElementById('tooltip'); + + buttons.forEach(button => { + button.addEventListener('mouseenter', function(event) { + tooltip.textContent = button.getAttribute('data-tooltip'); + tooltip.style.display = 'block'; + tooltip.style.left = event.pageX + 'px'; + tooltip.style.top = (event.pageY + 20) + 'px'; // 鼠标下方略微偏移 + }); + + button.addEventListener('mouseleave', function() { + tooltip.style.display = 'none'; + }); + }); +} + +function showMessage(text) { + const messageDiv = document.getElementById("message"); + messageDiv.textContent = text; + messageDiv.style.display = "block"; // 显示消息 + + setTimeout(() => { + messageDiv.style.display = "none"; // 1秒后隐藏消息 + }, 1000); +} + +window.onload = function() { + // 注册工具提示事件 + registerTooltipEvents(); + resetStars(); + const storedStudent = localStorage.getItem('selectedStudent');//获取selectedStudent + if (storedStudent) { + selectedStudent = JSON.parse(storedStudent); + document.getElementById('selectedStudent').innerText = `${selectedStudent.name} (学号: ${selectedStudent.id})`; + autoPointsAdded = localStorage.getItem('autoPointsAdded') === 'true'; + manualPointsUsed = localStorage.getItem('manualPointsUsed') === 'true'; + starLock = localStorage.getItem('starLock') === 'true'; + onClassAdded = localStorage.getItem('onClassAdded') === 'true'; + } +}; + +function uploadFile() { + const input = document.getElementById('fileInput'); + const file = input.files[0]; + if (!file) { + showMessage("请选择一个文件!"); + return; + } + + const reader = new FileReader(); + reader.onload = function(e) { + const data = new Uint8Array(e.target.result); + const workbook = XLSX.read(data, { type: 'array' }); + const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; + + // 读取所有行(包括空行) + let allStudents = XLSX.utils.sheet_to_json(firstSheet, { header: 1 }); + + // 如果没有数据,则提示用户 + if (allStudents.length < 2) { + showMessage("工作表中没有有效数据!"); + return; + } + + // 去掉表头 + allStudents = allStudents.slice(1); + + // 过滤有效行,确保每行的有效性 + students = allStudents + .filter(row => row[0] !== undefined && row[0] !== null && row[0] !== '') // 确保 ID 不为空 + .map(row => ({ + id: row[0], + name: row[1], // 假设第二列为名字 + points: 0 // 默认分数为 0 + })); + + // 如果没有有效的学生数据,则提示 + if (students.length === 0) { + showMessage("工作表中没有有效学生数据!"); + return; + } + + localStorage.setItem('students', JSON.stringify(students)); + showMessage("学生名单导入成功!"); + toggleButtons(); + }; + reader.readAsArrayBuffer(file); +} + +function updateFileName() { + const input = document.getElementById('fileInput'); + const fileName = document.getElementById('fileName'); + if (input.files.length > 0) { + fileName.innerText = input.files[0].name; // 显示选择的文件名 + } else { + fileName.innerText = '未选择文件'; // 显示未选择文件的提示 + } +} + +function viewStudentList() { + window.location.href = 'studentList.html'; +} + +function startDraw() { + if (students.length === 0) { + showMessage("请先导入学生名单!"); + uploadModal.style.display = 'block'; // 显示模态框 + return; + } + // 隐藏页面元素 + document.querySelector('.container').classList.add('hidden'); + resetStars(); + + lock = false; + lock1 = false; + onClassAdded = false; + autoPointsAdded = false; + manualPointsUsed = false; + starLock = false; + + + const totalPoints = students.reduce((sum, student) => sum + (student.points > 10 ? 1 / student.points : 10 - student.points), 0); + const randomValue = Math.random() * totalPoints; + let cumulativePoints = 0; + + for (const student of students) { + cumulativePoints += Math.max(1, 10 - student.points); + if (randomValue < cumulativePoints) { + selectedStudent = student; + break; + } + } + + setTimeout(scrollStudents, 350); +} + +function onClass() { + if(!onClassAdded && selectedStudent) { + selectedStudent.points += 1; + synPoints(); + onClassAdded = true; + updateLocalStorage(); + showMessage(`${selectedStudent.name}到场,加分 1。`); + } else if (!selectedStudent) { + showMessage("请先抽取一位学生"); + } else { + showMessage("到场已加分"); + } +} + +document.addEventListener('click', async function(event) { + const drawButton = document.getElementById('drawButton'); + const scrollingNamesDiv = document.getElementById('scrollingNames'); + const selectedStudentDiv = document.getElementById('selectedStudent'); + + if(!clickEnabled){ + return; + } + + if (!drawButton.contains(event.target) && + !scrollingNamesDiv.contains(event.target) && + !selectedStudentDiv.contains(event.target)) { + + // 清空显示的被点到学生信息 + scrollingNamesDiv.innerHTML = ''; + + particles = []; + particleCtx.clearRect(0, 0, particleCanvas.width, particleCanvas.height); + + // 恢复页面元素 + document.querySelector('.container').classList.remove('hidden'); + selectedStudentDiv.style.display = 'block'; // 显示 + } +}); + +function synPoints() { + // 更新 students 数组中的相应学生积分 + const studentIndex = students.findIndex(s => s.id === selectedStudent.id); + if (studentIndex !== -1) { + students[studentIndex].points = selectedStudent.points; // 确保 students 数组中的积分也更新 + } +} + +function repeatCorrectly() { + if (!lock && selectedStudent && !autoPointsAdded) { + selectedStudent.points += 0.5; + synPoints(); + autoPointsAdded = true; + lock = true; + updateLocalStorage(); + showMessage(`已为 ${selectedStudent.name}加分 0.5。`); + } else if (!selectedStudent) { + showMessage("请先抽取一位学生"); + } else { + showMessage("已为该学生加过分"); + } +} + + +function repeatIncorrectly() { + if (!lock && selectedStudent && !autoPointsAdded) { + selectedStudent.points -= 1; + synPoints(); + autoPointsAdded = true; + lock = true; + updateLocalStorage(); + showMessage(`已为 ${selectedStudent.name} 扣分 1。`); + } else if (!selectedStudent) { + showMessage("请先抽取一位学生"); + } else { + showMessage("已为该学生加过分"); + } +} + +let clickEnabled = true; // 用于跟踪点击是否被允许 + +function scrollStudents() { + document.getElementById('selectedStudent').innerText = ''; + const scrollingNamesDiv = document.getElementById('scrollingNames'); + scrollingNamesDiv.innerHTML = ''; + let index = 0; + + clickEnabled = false; // 禁用点击 + + return new Promise((resolve) => { + intervalId = setInterval(() => { + scrollingNamesDiv.innerText = students[index].name; + index = (index + 1) % students.length; + }, 100); + + setTimeout(() => { + clearInterval(intervalId); + scrollingNamesDiv.innerHTML = ''; + if (selectedStudent) { + document.getElementById('selectedStudent').innerText = `${selectedStudent.name} (学号: ${selectedStudent.id})`; + document.getElementById('selectedStudent').style.display = 'none'; // 隐藏 + createParticlesFromText(`${selectedStudent.name} (学号:${selectedStudent.id})`); + updateLocalStorage(); + } + resolve(); // 完成滚动时解析Promise + clickEnabled = true; // 恢复点击 + }, 3000); + }); +} + +function updateLocalStorage() { + localStorage.setItem('selectedStudent', JSON.stringify(selectedStudent)); + localStorage.setItem('students', JSON.stringify(students)); + localStorage.setItem('autoPointsAdded', autoPointsAdded); + localStorage.setItem('manualPointsUsed', manualPointsUsed); + localStorage.setItem('starLock',starLock); + localStorage.setItem('onClassAdded',onClassAdded); +} + +// 初始化星级点击事件监听器 +document.querySelectorAll('.rating input').forEach(star => { + star.addEventListener('change', function() { + if (!starLock) { // 检查星星是否已经被点击过 + updatePoints(this.value); + } else { + showMessage("每次点名只能点击一次星星进行加分。"); + } + }); +}); + +// 根据选中的星级为学生加分 +function updatePoints(points) { + points = parseFloat(points); // 将点击的星星值转换为整数 + if (selectedStudent) { + if (!starLock) { // 检查星星是否已经被点击过 + selectedStudent.points += points; // 根据星星值加分 + synPoints(); + showMessage(`已为 ${selectedStudent.name} 加分 ${points}。`); + starLock = true; // 点击后锁定星星不能再加分 + updateLocalStorage(); + } else { + showMessage("每次点名只能点击一次星星进行加分。"); + } + } else { + showMessage("请先点名一个学生。"); + } +} + +//每次返回页面或者重新点名使星星恢复原始形态 +function resetStars() { + document.querySelectorAll('.rating input').forEach(star => { + star.checked = false; // 取消选中状态 + }); +} + +// 禁用所有星星选择 +function disableStars() { + document.querySelectorAll('.rating input').forEach(star => { + star.disabled = true; + }); +} + +// 启用所有星星选择 +function enableStars() { + document.querySelectorAll('.rating input').forEach(star => { + star.disabled = false; + }); +} + +function resetAllPoints() { + students.forEach(student => student.points = 0); + localStorage.setItem('students', JSON.stringify(students)); + localStorage.removeItem('selectedStudent'); + selectedStudent = null; + document.getElementById('selectedStudent').innerText = ''; + showMessage("所有积分已重置!"); +} + +//弹窗 +const fileButton = document.getElementById('fileButton'); +const uploadModal = document.getElementById('uploadModal'); +const closeButton = document.getElementById('closeButton'); + +fileButton.addEventListener('click',function() { + uploadModal.style.display = 'block'; // 显示模态框 +}); + +closeButton.addEventListener('click', function() { + resetUpload(); + uploadModal.style.display = 'none'; // 关闭模态框 +}); + +window.addEventListener('click', function(event) { + if (event.target === uploadModal) { + uploadModal.style.display = 'none'; // 点击模态框外部关闭 + } +}); + +const uploadBox = document.getElementById('uploadBox'); +const fileInput = document.getElementById('fileInput'); + +uploadBox.addEventListener('click', function() { + fileInput.click(); +}); + +uploadBox.addEventListener('dragover', function(event) { + event.preventDefault(); + uploadBox.style.borderColor = '#4CAF50'; +}); + +uploadBox.addEventListener('dragleave', function() { + uploadBox.style.borderColor = '#ccc'; +}); + +uploadBox.addEventListener('drop', function(event) { + event.preventDefault(); + uploadBox.style.borderColor = '#ccc'; + const files = event.dataTransfer.files; + if (files.length > 0) { + const fileName = files[0].name; // 获取文件名 + const uploadText = document.getElementById('uploadText'); + const excelLogo = '📊'; // Excel 图标,可以使用 emoji,也可以使用图像 URL + + // 替换内容 + uploadText.innerHTML = `${excelLogo} ${fileName}`; + document.querySelector('.pic').style.display = 'none'; // 隐藏箭头 + showMessage('已选择文件: ' + files[0].name); + + // 将文件设置到 fileInput 中,以便 OK 按钮可以获取到 + fileInput.files = files; + } +}); + +fileInput.addEventListener('change', function(event) { + const file = event.target.files[0]; + if (file) { + const fileName = file.name; // 获取文件名 + const uploadText = document.getElementById('uploadText'); + const excelLogo = '📊'; // Excel 图标,可以使用 emoji,也可以使用图像 URL + + // 替换内容 + uploadText.innerHTML = `${excelLogo} ${fileName}`; + document.querySelector('.pic').style.display = 'none'; // 隐藏箭头 + showMessage('已选择文件: ' + file.name); + } +}); + +document.getElementById('cancelButton').addEventListener('click', function() { + resetUpload(); + fileInput.value = ''; + uploadModal.style.display = 'none'; // 取消时关闭模态框 + showMessage('已取消选择'); +}); + +document.getElementById('okButton').addEventListener('click', function() { + const input = document.getElementById('fileInput'); + const file = input.files[0]; // 获取选中的文件 + + if (!file) { + showMessage('请先选择文件'); + } else { + showMessage('文件导入成功: ' + file.name); + uploadFile(); // 调用上传文件的函数 + uploadModal.style.display = 'none'; // 关闭模态框 + } + resetUpload(); +}); + +// 重置上传状态的函数 +function resetUpload() { + document.getElementById('fileInput').value = ''; // 清空文件输入 + document.getElementById('uploadText').innerHTML = '点击或拖拽文件到此处上传'; // 恢复提示文本 + document.querySelector('.pic').style.display = 'block'; // 显示箭头 +} \ No newline at end of file