You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

528 lines
18 KiB

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'; // 显示箭头
}