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.

366 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>课堂随机点名系统</title>
<link rel="icon" href="static/logo.ico" type="image/x-icon">
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
background-image: url('/static/background.png'); /* 背景图片路径 */
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.card {
background-color: rgba(255, 255, 255, 0.8); /* 卡片背景色 */
border-radius: 10px; /* 圆角 */
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* 阴影 */
margin: 20px auto; /* 上下间距和自动水平居中 */
padding: 20px; /* 内边距 */
width: 300px; /* 卡片宽度 */
}
h1 {
color: whitesmoke;
font-size: 36px;
margin-bottom: 20px;
}
/* 按钮样式 */
.button {
display: block; /* 改为块级元素以实现纵向排列 */
width: 100%; /* 设置按钮宽度为 100% */
margin: 15px 0; /* 上下间距 */
padding: 15px; /* 增加上边距和下边距 */
font-size: 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #45a049;
}
.button:active {
transform: scale(0.95);
}
.modal {
display: none;
position: fixed;
z-index: 2;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.8);
opacity: 0;
transition: opacity 0.3s ease;
}
.modal.show {
opacity: 1;
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
transition: transform 0.3s ease;
}
.modal-content.show {
transform: scale(1);
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
}
.disabled {
opacity: 0.5; /* 设置透明度为 0.5 以表示禁用状态 */
pointer-events: none; /* 禁用事件 */
}
</style>
</head>
<body>
<h1>课堂随机点名系统</h1>
<img src="/static/kfc_cat.jpg" alt="Logo" style="width: 88px; height: auto;">
<div class="card">
<div class="card-body">
<button class="button" data-action="upload">上传学生名单</button>
<button class="button" data-action="roll-call">随机点名</button>
<button class="button" data-action="view-rank">查看积分排行</button>
</div>
</div>
<div id="myModal" class="modal">
<div class="modal-content">
<span id="closeModal" class="close">&times;</span>
<p id="rollResult"></p>
<form id="rollCallForm">
<p>是否来上课了?
<label><input type="radio" name="isCome" value="yes" onclick="toggleQuestionOptions()"> 来了</label>
<label><input type="radio" name="isCome" value="no" onclick="toggleQuestionOptions()"> 没来</label>
</p>
<div id="questionOptions">
<p>是否能够重复问题?
<label><input type="radio" name="canRepeat" value="yes"></label>
<label><input type="radio" name="canRepeat" value="no"> 不能</label>
</p>
<p>是否能够正确回答问题?
<label><input type="radio" name="answerCorrect" value="correct"> 完全正确</label>
<label><input type="radio" name="answerCorrect" value="partial"> 部分正确</label>
<label><input type="radio" name="answerCorrect" value="incorrect"> 错误</label>
</p>
</div>
<button type="button" id="submitRollCall">提交</button>
</form>
</div>
</div>
<script>
const apiBaseUrl = "http://127.0.0.1:8000"; /* 部署到服务器需要修改为http://8.130.115.98:8080 */
var modal = document.getElementById("myModal");
var rollResultElement = document.getElementById("rollResult");
var span = document.getElementById("closeModal");
// 关闭模态框的函数
function closeModal() {
modal.classList.remove('show');
setTimeout(() => {
modal.style.display = "none";
}, 300);
}
span.onclick = closeModal;
window.onclick = function (event) {
if (event.target == modal) {
closeModal();
}
};
let studentData = [];
// 处理上传学生名单的函数
function uploadList() {
let fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.xlsx';
fileInput.onchange = function () {
let formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch(apiBaseUrl + '/upload', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
alert(data.message);
if (data.message === "名单上传成功!") {
studentData = data.students;
}
})
.catch(error => {
console.error('Error:', error);
alert('上传失败,请检查网络连接或文件格式。');
});
};
fileInput.click();
}
// 处理随机点名的函数
function rollCall() {
fetch(apiBaseUrl + '/roll?enable_random_events=true')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(responseData => {
if (responseData.message) {
alert(responseData.message);
} else {
sessionStorage.setItem('lastCalledStudentId', responseData.学号);
rollResultElement.innerText = `被点名的学生是:${responseData.学号}--${responseData.姓名}`;
modal.classList.add('show');
modal.style.display = "block";
if (responseData.转移权) {
showTransferOptions(responseData.学号);
}
if (responseData.随机事件) {
alert(`随机事件触发:${responseData.随机事件}`);
}
}
})
.catch(error => {
console.error('Error:', error);
alert(`无法完成点名,请检查网络连接或服务器状态。详细信息:${error.message}`);
});
}
// 切换问题选项的可用性
function toggleQuestionOptions() {
const form = document.getElementById("rollCallForm");
const isCome = form.elements["isCome"].value;
const questionOptions = document.getElementById("questionOptions");
if (isCome === "no") {
questionOptions.classList.add("disabled");
Array.from(questionOptions.querySelectorAll('input[type="radio"]')).forEach(input => {
input.checked = false;
input.disabled = true;
});
} else {
questionOptions.classList.remove("disabled");
Array.from(questionOptions.querySelectorAll('input[type="radio"]')).forEach(input => {
input.disabled = false;
});
}
}
// 显示转移选项的函数
function showTransferOptions(currentStudentId) {
const transferModal = document.createElement('div');
transferModal.className = 'modal transfer-modal';
const transferContent = document.createElement('div');
transferContent.className = 'modal-content';
transferContent.innerHTML = `<p>请选择转移的学生:</p>`;
studentData.forEach(student => {
if (student.学号 !== currentStudentId) {
const button = document.createElement('button');
button.innerText = `${student.姓名} (${student.学号})`;
button.onclick = function () {
alert(`转移到学生:${student.姓名} (${student.学号})`);
transferModal.style.display = "none";
modal.style.display = "none";
sessionStorage.setItem('lastCalledStudentId', student.学号);
rollCall();
};
transferContent.appendChild(button);
}
});
transferModal.appendChild(transferContent);
document.body.appendChild(transferModal);
transferModal.classList.add('show');
transferModal.style.display = "block";
const closeButton = document.createElement('span');
closeButton.className = 'close';
closeButton.innerHTML = '&times;';
closeButton.onclick = function () {
transferModal.style.display = "none";
};
transferContent.appendChild(closeButton);
}
// 提交点名评估的函数
document.getElementById("submitRollCall").onclick = function () {
const form = document.getElementById("rollCallForm");
const isCome = form.elements["isCome"].value === "yes";
const canRepeat = form.elements["canRepeat"].value === "yes";
const answerCorrect = form.elements["answerCorrect"].value === "correct" ? "完全正确" :
(form.elements["answerCorrect"].value === "partial" ? "部分正确" : "错误");
const studentId = sessionStorage.getItem('lastCalledStudentId');
if (!studentId) {
alert('没有找到被点名的学生 ID请重新点名。');
return;
}
const dataToSend = {
student_id: studentId,
is_come: isCome,
can_repeat: canRepeat,
answer_correct: answerCorrect
};
fetch(apiBaseUrl + '/evaluate-answer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(dataToSend),
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(updatedData => {
if (updatedData.success) {
alert('回答已评估!');
} else {
alert('回答评估失败!');
}
})
.catch(error => {
console.error('Error:', error);
alert('无法完成评估,请检查网络连接或服务器状态。');
});
closeModal();
};
// 处理查看积分排行的函数
function viewRank() {
fetch(apiBaseUrl + '/rank')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data.message) {
alert(data.message);
} else {
let rankList = "积分排行:\n";
data.forEach((student, index) => {
rankList += `${index + 1}. 学号:${student.学号} 姓名:${student.姓名} 积分:${student.积分}\n`;
});
alert(rankList);
}
})
.catch(error => {
console.error('Error:', error);
alert('无法完成操作,请检查网络连接或服务器状态。');
});
}
// 为按钮添加点击事件处理
document.querySelectorAll('.button').forEach(button => {
button.addEventListener('click', function () {
const action = this.dataset.action;
if (action === 'upload') {
uploadList();
} else if (action === 'roll-call') {
rollCall();
} else if (action === 'view-rank') {
viewRank();
}
});
});
</script>
</body>
</html>