from PySide6.QtCore import Qt, Signal, QTimer from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QStackedWidget, QGridLayout, QFileDialog from qfluentwidgets import GroupHeaderCardWidget, PushButton, FluentIcon, PrimaryPushButton, IconWidget, BodyLabel, \ SegmentedWidget, SpinBox, LargeTitleLabel, DisplayLabel, SubtitleLabel from module.picker.schema import PickerExcel, PickerStudent from ui.components.widget import RollingTextWidget from ui import MAIN_THEME_COLOR from ui.components.widget import Widget from ui.components.window import MyWindow class PSMMain(MyWindow): finishSignal = Signal() def __init__(self, student: PickerStudent, parent=None): super().__init__(parent) self.student = student self.grade_edit = SpinBox(self) self.init_layout() def init_layout(self): main_layout = QVBoxLayout() hLayout = QHBoxLayout() name_layout = QVBoxLayout() date_layout = QVBoxLayout() hLayout.addStretch() hLayout.addLayout(name_layout) hLayout.addLayout(date_layout) hLayout.addStretch() hLayout.setSpacing(20) so = LargeTitleLabel(f"{self.student.so}", self) so.setAlignment(Qt.AlignCenter) sname = DisplayLabel( f"{self.student.name[0] + ' ' + self.student.name[1] if len(self.student.name) == 2 else self.student.name}", self) sname.setAlignment(Qt.AlignCenter) name_layout.addWidget(so) name_layout.addWidget(sname) self.grade_edit.setFixedWidth(260) self.grade_edit.setRange(0, 100) grade_layout = QHBoxLayout() grade_layout.setContentsMargins(0, 0, 0, 48) grade_layout.setSpacing(20) submit_button = PrimaryPushButton("确定", self) cancel_button = PushButton("重置", self) submit_button.clicked.connect(self.close_modal) cancel_button.clicked.connect(lambda: self.grade_edit.clear()) submit_button.setFixedWidth(120) cancel_button.setFixedWidth(120) grade_layout.addWidget(submit_button) grade_layout.addWidget(cancel_button) date_layout.addWidget(self.grade_edit) date_layout.addLayout(grade_layout) main_layout.addStretch() main_layout.addLayout(hLayout) main_layout.addStretch() # 快速打分 quick_grade_layout = QVBoxLayout() quick_grade_layout.setContentsMargins(0, 0, 0, 0) quick_grade_layout.setSpacing(20) quick_grade_title = SubtitleLabel("快速打分", self) quick_grade_title.setAlignment(Qt.AlignCenter) quick_grade_layout.addWidget(quick_grade_title) grid_wrapper_layout = QHBoxLayout() grid_layout = QGridLayout() buttons = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] for i, num in enumerate(buttons): row = i // 3 col = i % 3 btn = PushButton(str(num)) btn.setFixedSize(80, 80) # 使用lambda绑定事件 btn.clicked.connect(lambda _, n=num: self.grade_edit.setValue(n)) grid_layout.addWidget(btn, row, col) grid_wrapper_layout.addStretch() grid_wrapper_layout.addLayout(grid_layout) grid_wrapper_layout.addStretch() quick_grade_layout.addLayout(grid_layout) quick_grade_layout.addLayout(grid_wrapper_layout) main_layout.addLayout(quick_grade_layout) self.widgetLayout.addLayout(main_layout) def close_modal(self): self.student.append_score(self.grade_edit.value()) self.finishSignal.emit() self.close() class PickStudentMode(QWidget): errorSignal = Signal(str) def __init__(self, parent=None): super().__init__(parent) self.card = GroupHeaderCardWidget(self) self.vbox = QVBoxLayout(self) self.vbox.setContentsMargins(0, 0, 0, 0) self.chooseBtn = PushButton("打开") self.startButton = PrimaryPushButton(FluentIcon.PLAY_SOLID, "开始") self.bottomLayout = QHBoxLayout() self.hintIcon = IconWidget(FluentIcon.INFO.icon(color=MAIN_THEME_COLOR)) self.hintLabel = BodyLabel("点击开始按钮以开始抽签 👉") self.spinbox = SpinBox() self.rollingText = RollingTextWidget(self) self.card.setTitle("输入选项") self.chooseBtn.setFixedWidth(120) self.startButton.setFixedWidth(120) self.startButton.setEnabled(False) self.spinbox.setRange(0, 6) self.spinbox.setFixedWidth(120) self.spinbox.setEnabled(False) self.hintIcon.setFixedSize(16, 16) self.hintIcon.autoFillBackground() self.bottomLayout.setSpacing(10) self.bottomLayout.setContentsMargins(24, 15, 24, 20) self.bottomLayout.addWidget(self.hintIcon, 0, Qt.AlignLeft) self.bottomLayout.addWidget(self.hintLabel, 0, Qt.AlignLeft) self.bottomLayout.addStretch(1) self.bottomLayout.addWidget(self.startButton, 0, Qt.AlignRight) self.bottomLayout.setAlignment(Qt.AlignVCenter) self.group = self.card.addGroup(FluentIcon.DOCUMENT, "提问名单", "选择提问名单", self.chooseBtn) self.spinGroup = self.card.addGroup(FluentIcon.SETTING, "提问次数", "设置提问的最大次数", self.spinbox) self.spinGroup.setSeparatorVisible(True) self.card.vBoxLayout.addLayout(self.bottomLayout) self.vbox.addWidget(self.card) self.vbox.addWidget(self.rollingText) self.vbox.addStretch(1) # ============================== self.chooseBtn.clicked.connect(self.choose_file) self.spinbox.valueChanged.connect(lambda: PickerExcel.save_total_time(value=self.spinbox.value())) self.startButton.clicked.connect(self.start_rolling) self.rollingText.finishSignal.connect(self.finish_rolling) # ============================== self.filepath = "" self.students = [] def choose_file(self): file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel 文件 (*.xlsm);") if file_path: self.group.setContent("已选择文件:" + file_path) self.filepath = file_path self.startButton.setEnabled(True) self.init_spinbox_value() def init_spinbox_value(self): if not self.filepath: return try: PickerExcel.open(self.filepath) self.spinbox.setValue(PickerExcel.read_total_time()) self.spinbox.setEnabled(True) except Exception as e: self.errorSignal.emit(str(e)) self.spinbox.setEnabled(False) self.startButton.setEnabled(False) def start_rolling(self): self.students = PickerExcel.read_student() self.rollingText.set_items(self.students) self.rollingText.start_rolling() self.startButton.setEnabled(False) def finish_rolling(self): stu = PickerStudent.pick(self.students) if not (stu.so and stu.name): self.errorSignal.emit("学生信息读取失败") self.rollingText.label.setText(stu.name) timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(lambda: self.show_screen(stu)) timer.timeout.connect(lambda: self.startButton.setEnabled(True)) timer.start(1000) def show_screen(self, stu: PickerStudent): screen = PSMMain(stu) screen.finishSignal.connect(lambda: PickerExcel.write_back(stu)) screen.finishSignal.connect(lambda: self.rollingText.label.clear()) class PickQuestionMode(QWidget): def __init__(self, parent=None): super().__init__(parent) lable = DisplayLabel('🚧', self) lable.setAlignment(Qt.AlignCenter) self.layout = QHBoxLayout(self) self.layout.addStretch() self.layout.addWidget(lable) self.layout.addStretch() class PickerWidget(Widget): errorSignal = Signal(str, str) def __init__(self, key: str, parent=None): super().__init__(key, parent) self.vbox = QVBoxLayout(self) self.menu = SegmentedWidget(self) self.stack = QStackedWidget(self) self.psm = PickStudentMode(self) self.pqm = PickQuestionMode(self) self.add_sub_interface(self.psm, "pickStudentMode", "选人模式") self.add_sub_interface(self.pqm, "pickQuestionMode", "选题模式") self.menu.setCurrentItem("pickStudentMode") self.vbox.addWidget(self.menu) self.vbox.addWidget(self.stack) self.vbox.addStretch(1) # =========================== self.stack.currentChanged.connect(self.on_stack_index_changed) self.psm.errorSignal.connect(lambda n: self.errorSignal.emit("😢 不好出错了", n)) def add_sub_interface(self, widget: QWidget, obj_name: str, text: str): widget.setObjectName(obj_name) self.stack.addWidget(widget) self.menu.addItem(routeKey=obj_name, text=text, onClick=lambda: self.stack.setCurrentWidget(widget)) def on_stack_index_changed(self, index: int): widget = self.stack.widget(index) self.stack.setCurrentWidget(widget)