|
|
"""
|
|
|
点名组件
|
|
|
"""
|
|
|
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QRadioButton, QButtonGroup,
|
|
|
QGroupBox, QSpinBox, QDoubleSpinBox, QCheckBox, QMessageBox, QTextEdit)
|
|
|
from PyQt5.QtCore import Qt, QTimer
|
|
|
from PyQt5.QtGui import QFont
|
|
|
from frontend.utils.api_client import APIClient
|
|
|
|
|
|
|
|
|
class RollCallWidget(QWidget):
|
|
|
"""点名界面"""
|
|
|
|
|
|
def __init__(self, api_client: APIClient, parent=None):
|
|
|
super().__init__(parent)
|
|
|
self.api_client: APIClient = api_client
|
|
|
self.current_student = None
|
|
|
self.init_ui()
|
|
|
|
|
|
def init_ui(self):
|
|
|
"""初始化界面"""
|
|
|
layout = QVBoxLayout()
|
|
|
|
|
|
# 标题
|
|
|
title = QLabel("课堂点名")
|
|
|
title.setStyleSheet("font-size: 18px; font-weight: bold; margin: 10px;")
|
|
|
title.setAlignment(Qt.AlignCenter)
|
|
|
layout.addWidget(title)
|
|
|
|
|
|
# 点名模式选择
|
|
|
mode_group = QGroupBox("点名模式")
|
|
|
mode_layout = QHBoxLayout()
|
|
|
self.mode_group = QButtonGroup()
|
|
|
|
|
|
self.random_radio = QRadioButton("随机点名")
|
|
|
self.random_radio.setChecked(True)
|
|
|
self.mode_group.addButton(self.random_radio, 0)
|
|
|
mode_layout.addWidget(self.random_radio)
|
|
|
|
|
|
self.order_radio = QRadioButton("顺序点名")
|
|
|
self.mode_group.addButton(self.order_radio, 1)
|
|
|
mode_layout.addWidget(self.order_radio)
|
|
|
|
|
|
mode_group.setLayout(mode_layout)
|
|
|
layout.addWidget(mode_group)
|
|
|
|
|
|
# 被点学生信息显示区域
|
|
|
info_group = QGroupBox("被点学生信息")
|
|
|
info_layout = QVBoxLayout()
|
|
|
|
|
|
self.student_info = QLabel("点击'开始点名'按钮开始")
|
|
|
self.student_info.setAlignment(Qt.AlignCenter)
|
|
|
self.student_info.setStyleSheet("font-size: 24px; font-weight: bold; padding: 20px;"
|
|
|
"background-color: #f0f0f0; border-radius: 10px;")
|
|
|
self.student_info.setMinimumHeight(150)
|
|
|
info_layout.addWidget(self.student_info)
|
|
|
|
|
|
info_group.setLayout(info_layout)
|
|
|
layout.addWidget(info_group)
|
|
|
|
|
|
# 点名按钮
|
|
|
button_layout = QHBoxLayout()
|
|
|
self.start_btn = QPushButton("开始点名")
|
|
|
self.start_btn.setStyleSheet("font-size: 16px; padding: 10px; background-color: #4CAF50; color: white;")
|
|
|
self.start_btn.clicked.connect(self.start_rollcall)
|
|
|
button_layout.addWidget(self.start_btn)
|
|
|
layout.addLayout(button_layout)
|
|
|
|
|
|
# 记录点名结果
|
|
|
record_group = QGroupBox("记录点名结果")
|
|
|
record_layout = QVBoxLayout()
|
|
|
|
|
|
# 到达情况
|
|
|
self.present_check = QCheckBox("学生已到达")
|
|
|
self.present_check.setChecked(True)
|
|
|
record_layout.addWidget(self.present_check)
|
|
|
|
|
|
# 重复问题得分
|
|
|
repeat_layout = QHBoxLayout()
|
|
|
repeat_layout.addWidget(QLabel("重复问题得分:"))
|
|
|
self.repeat_score = QDoubleSpinBox()
|
|
|
self.repeat_score.setRange(-1.0, 0.5)
|
|
|
self.repeat_score.setSingleStep(0.5)
|
|
|
self.repeat_score.setValue(0.0)
|
|
|
self.repeat_score.setSuffix(" 分")
|
|
|
repeat_layout.addWidget(self.repeat_score)
|
|
|
repeat_layout.addWidget(QLabel("(-1:不能重复, 0:未测试, 0.5:准确重复)"))
|
|
|
repeat_layout.addStretch()
|
|
|
record_layout.addLayout(repeat_layout)
|
|
|
|
|
|
# 回答问题得分
|
|
|
answer_layout = QHBoxLayout()
|
|
|
answer_layout.addWidget(QLabel("回答问题得分:"))
|
|
|
self.answer_score = QDoubleSpinBox()
|
|
|
self.answer_score.setRange(0.0, 3.0)
|
|
|
self.answer_score.setSingleStep(0.5)
|
|
|
self.answer_score.setValue(0.0)
|
|
|
self.answer_score.setSuffix(" 分")
|
|
|
answer_layout.addWidget(self.answer_score)
|
|
|
answer_layout.addWidget(QLabel("(0-3分,根据回答情况)"))
|
|
|
answer_layout.addStretch()
|
|
|
record_layout.addLayout(answer_layout)
|
|
|
|
|
|
# 提交按钮
|
|
|
self.submit_btn = QPushButton("提交记录")
|
|
|
self.submit_btn.setEnabled(False)
|
|
|
self.submit_btn.clicked.connect(self.submit_record)
|
|
|
record_layout.addWidget(self.submit_btn)
|
|
|
|
|
|
record_group.setLayout(record_layout)
|
|
|
layout.addWidget(record_group)
|
|
|
|
|
|
# 最近点名记录
|
|
|
history_group = QGroupBox("最近点名记录")
|
|
|
history_layout = QVBoxLayout()
|
|
|
self.history_text = QTextEdit()
|
|
|
self.history_text.setReadOnly(True)
|
|
|
self.history_text.setMaximumHeight(150)
|
|
|
history_layout.addWidget(self.history_text)
|
|
|
history_group.setLayout(history_layout)
|
|
|
layout.addWidget(history_group)
|
|
|
|
|
|
layout.addStretch()
|
|
|
self.setLayout(layout)
|
|
|
|
|
|
def start_rollcall(self):
|
|
|
"""开始点名"""
|
|
|
try:
|
|
|
rollcall_type = "random" if self.random_radio.isChecked() else "order"
|
|
|
result = self.api_client.start_rollcall(rollcall_type)
|
|
|
|
|
|
self.current_student = result
|
|
|
self.student_info.setText(f"学号: {result['student_code']}\n"
|
|
|
f"姓名: {result['name']}\n"
|
|
|
f"专业: {result.get('major', '')}\n"
|
|
|
f"当前积分: {result['total_score']}")
|
|
|
|
|
|
self.submit_btn.setEnabled(True)
|
|
|
self.start_btn.setEnabled(False)
|
|
|
|
|
|
# 重置表单
|
|
|
self.present_check.setChecked(True)
|
|
|
self.repeat_score.setValue(0.0)
|
|
|
self.answer_score.setValue(0.0)
|
|
|
|
|
|
except Exception as e:
|
|
|
QMessageBox.critical(self, "错误", f"点名失败: {str(e)}")
|
|
|
|
|
|
def submit_record(self):
|
|
|
"""提交点名记录"""
|
|
|
if not self.current_student:
|
|
|
QMessageBox.warning(self, "提示", "请先开始点名")
|
|
|
return
|
|
|
|
|
|
try:
|
|
|
record_data = {
|
|
|
"student_id": self.current_student['student_id'],
|
|
|
"rollcall_type": "random" if self.random_radio.isChecked() else "order",
|
|
|
"is_present": self.present_check.isChecked(),
|
|
|
"question_repeat_score": self.repeat_score.value(),
|
|
|
"answer_score": self.answer_score.value()
|
|
|
}
|
|
|
|
|
|
result = self.api_client.record_rollcall(record_data)
|
|
|
|
|
|
# 更新历史记录
|
|
|
history_text = (f"[{result['created_at']}] "
|
|
|
f"{result['student_name']} ({result['student_code']}) - "
|
|
|
f"积分变化: {result['total_score_change']:+.1f}\n")
|
|
|
self.history_text.insertPlainText(history_text)
|
|
|
|
|
|
QMessageBox.information(self, "成功", "点名记录已提交")
|
|
|
|
|
|
# 重置状态
|
|
|
self.current_student = None
|
|
|
self.submit_btn.setEnabled(False)
|
|
|
self.start_btn.setEnabled(True)
|
|
|
self.student_info.setText("点击'开始点名'按钮开始")
|
|
|
|
|
|
except Exception as e:
|
|
|
QMessageBox.critical(self, "错误", f"提交记录失败: {str(e)}")
|