252 lines
11 KiB
Python
252 lines
11 KiB
Python
import sys
|
|
from PySide6 import QtCore, QtWidgets, QtGui
|
|
from PySide6.QtGui import QFont
|
|
from utils import read_excel, save_to_excel
|
|
from solve import solve_program
|
|
from datetime import datetime
|
|
|
|
class MyWidget(QtWidgets.QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.main_layout = QtWidgets.QVBoxLayout()
|
|
self.setLayout(self.main_layout)
|
|
|
|
bold_font = QFont()
|
|
bold_font.setBold(True) # 设置字体加粗
|
|
|
|
thin_font = QFont()
|
|
thin_font.setBold(False) # 设置字体不加粗
|
|
|
|
# 选择文件部分
|
|
self._excel_dir = None
|
|
self.group_box_1 = QtWidgets.QGroupBox("Step 1. 选择问卷星导出的表格文件")
|
|
self.group_box_1.setFont(bold_font)
|
|
|
|
self.openfile_layout = QtWidgets.QVBoxLayout()
|
|
self.button_openfile = QtWidgets.QPushButton("选择文件")
|
|
self.button_openfile.setFont(thin_font)
|
|
self.button_openfile.clicked.connect(self.open_file)
|
|
self.label_openfile = QtWidgets.QLabel("未选择文件")
|
|
self.label_openfile.setFont(thin_font)
|
|
|
|
self.openfile_layout.addWidget(self.button_openfile)
|
|
self.openfile_layout.addWidget(self.label_openfile)
|
|
self.group_box_1.setLayout(self.openfile_layout)
|
|
self.main_layout.addWidget(self.group_box_1)
|
|
|
|
|
|
# 限制条件部分
|
|
self.group_box_2 = QtWidgets.QGroupBox("Step 2. 输入限制条件")
|
|
self.group_box_2.setFont(bold_font)
|
|
self.cond_layout_overall = QtWidgets.QVBoxLayout()
|
|
self.group_box_2.setLayout(self.cond_layout_overall)
|
|
|
|
# 限制条件1
|
|
self.cond_layout_1 = QtWidgets.QHBoxLayout()
|
|
# 文字1
|
|
self.label_cond_1_1 = QtWidgets.QLabel("每班次人数:", self)
|
|
self.label_cond_1_1.setFont(thin_font)
|
|
# 数字输入框1
|
|
self.line_edit_1_1 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_1_1.setFont(thin_font)
|
|
self.line_edit_1_1.setValidator(QtGui.QIntValidator()) # 设置只接受整数
|
|
self.line_edit_1_1.setPlaceholderText("无限制")
|
|
self.line_edit_1_1.setText("4")
|
|
# 文字2
|
|
self.label_cond_1_2 = QtWidgets.QLabel("到", self)
|
|
self.label_cond_1_2.setFont(thin_font)
|
|
# 数字输入框2
|
|
self.line_edit_1_2 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_1_2.setFont(thin_font)
|
|
self.line_edit_1_2.setValidator(QtGui.QIntValidator()) # 设置只接受整数
|
|
self.line_edit_1_2.setPlaceholderText("无限制")
|
|
self.line_edit_1_2.setText("8")
|
|
|
|
self.cond_layout_1.addWidget(self.label_cond_1_1)
|
|
self.cond_layout_1.addWidget(self.line_edit_1_1)
|
|
self.cond_layout_1.addWidget(self.label_cond_1_2)
|
|
self.cond_layout_1.addWidget(self.line_edit_1_2)
|
|
self.cond_layout_overall.addLayout(self.cond_layout_1)
|
|
|
|
# 限制条件2
|
|
self.cond_layout_2 = QtWidgets.QHBoxLayout()
|
|
# 文字1
|
|
self.label_cond_2_1 = QtWidgets.QLabel("每班次电脑或电器的老人数:", self)
|
|
self.label_cond_2_1.setFont(thin_font)
|
|
# 数字输入框1
|
|
self.line_edit_2_1 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_2_1.setFont(thin_font)
|
|
self.line_edit_2_1.setValidator(QtGui.QIntValidator()) # 设置只接受整数
|
|
self.line_edit_2_1.setPlaceholderText("无限制")
|
|
# 文字2
|
|
self.label_cond_2_2 = QtWidgets.QLabel("到", self)
|
|
self.label_cond_2_2.setFont(thin_font)
|
|
# 数字输入框2
|
|
self.line_edit_2_2 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_2_2.setFont(thin_font)
|
|
self.line_edit_2_2.setValidator(QtGui.QIntValidator()) # 设置只接受整数
|
|
self.line_edit_2_2.setPlaceholderText("无限制")
|
|
self.line_edit_2_2.setText("1")
|
|
|
|
self.cond_layout_2.addWidget(self.label_cond_2_1)
|
|
self.cond_layout_2.addWidget(self.line_edit_2_1)
|
|
self.cond_layout_2.addWidget(self.label_cond_2_2)
|
|
self.cond_layout_2.addWidget(self.line_edit_2_2)
|
|
self.cond_layout_overall.addLayout(self.cond_layout_2)
|
|
|
|
# 限制条件3
|
|
self.cond_layout_3 = QtWidgets.QHBoxLayout()
|
|
# 文字1
|
|
self.label_cond_3_1 = QtWidgets.QLabel("每班次老人数:", self)
|
|
self.label_cond_3_1.setFont(thin_font)
|
|
# 数字输入框1
|
|
self.line_edit_3_1 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_3_1.setFont(thin_font)
|
|
self.line_edit_3_1.setValidator(QtGui.QIntValidator())
|
|
self.line_edit_3_1.setPlaceholderText("无限制")
|
|
self.line_edit_3_1.setText("1")
|
|
# 文字2
|
|
self.label_cond_3_2 = QtWidgets.QLabel("到", self)
|
|
self.label_cond_3_2.setFont(thin_font)
|
|
# 数字输入框2
|
|
self.line_edit_3_2 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_3_2.setFont(thin_font)
|
|
self.line_edit_3_2.setValidator(QtGui.QIntValidator())
|
|
self.line_edit_3_2.setPlaceholderText("无限制")
|
|
|
|
self.cond_layout_3.addWidget(self.label_cond_3_1)
|
|
self.cond_layout_3.addWidget(self.line_edit_3_1)
|
|
self.cond_layout_3.addWidget(self.label_cond_3_2)
|
|
self.cond_layout_3.addWidget(self.line_edit_3_2)
|
|
self.cond_layout_overall.addLayout(self.cond_layout_3)
|
|
|
|
# 限制条件4
|
|
self.cond_layout_4 = QtWidgets.QHBoxLayout()
|
|
# 文字1
|
|
self.label_cond_4_1 = QtWidgets.QLabel("每班次小朋友数:", self)
|
|
self.label_cond_4_1.setFont(thin_font)
|
|
# 数字输入框1
|
|
self.line_edit_4_1 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_4_1.setFont(thin_font)
|
|
self.line_edit_4_1.setValidator(QtGui.QIntValidator())
|
|
self.line_edit_4_1.setPlaceholderText("无限制")
|
|
self.line_edit_4_1.setText("2")
|
|
# 文字2
|
|
self.label_cond_4_2 = QtWidgets.QLabel("到", self)
|
|
self.label_cond_4_2.setFont(thin_font)
|
|
# 数字输入框2
|
|
self.line_edit_4_2 = QtWidgets.QLineEdit(self)
|
|
self.line_edit_4_2.setFont(thin_font)
|
|
self.line_edit_4_2.setValidator(QtGui.QIntValidator())
|
|
self.line_edit_4_2.setPlaceholderText("无限制")
|
|
|
|
self.cond_layout_4.addWidget(self.label_cond_4_1)
|
|
self.cond_layout_4.addWidget(self.line_edit_4_1)
|
|
self.cond_layout_4.addWidget(self.label_cond_4_2)
|
|
self.cond_layout_4.addWidget(self.line_edit_4_2)
|
|
self.cond_layout_overall.addLayout(self.cond_layout_4)
|
|
|
|
|
|
self.main_layout.addWidget(self.group_box_2)
|
|
|
|
|
|
# 处理文件部分
|
|
self.group_box_3 = QtWidgets.QGroupBox("Step 3. 获取最优结果")
|
|
self.group_box_3.setFont(bold_font)
|
|
|
|
self.button_solve = QtWidgets.QPushButton("开始排班!")
|
|
self.button_solve.setFont(thin_font)
|
|
self.text_solve = QtWidgets.QTextEdit(self)
|
|
self.text_solve.setFont(thin_font)
|
|
self.text_solve.setReadOnly(True) # 设置为只读模式
|
|
|
|
# 创建 QScrollArea 并将 QTextEdit 添加进去
|
|
self.scroll_area = QtWidgets.QScrollArea(self)
|
|
self.scroll_area.setWidget(self.text_solve) # 将 QTextEdit 设置为 QScrollArea 的内容
|
|
self.scroll_area.setWidgetResizable(True) # 允许 QTextEdit 根据 QScrollArea 的大小自动调整
|
|
|
|
self.button_solve.clicked.connect(self.magic)
|
|
|
|
self.solve_layout = QtWidgets.QVBoxLayout()
|
|
self.solve_layout.addWidget(self.scroll_area)
|
|
self.solve_layout.addWidget(self.button_solve)
|
|
self.group_box_3.setLayout(self.solve_layout)
|
|
self.main_layout.addWidget(self.group_box_3)
|
|
|
|
def open_file(self):
|
|
# 弹出文件选择对话框
|
|
file_path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "打开文件", "", "所有文件 (*.*);;文本文件 (*.txt)")
|
|
|
|
# 如果用户选择了文件,则更新标签显示文件路径
|
|
if file_path:
|
|
self.label_openfile.setText(f"选中文件: {file_path}")
|
|
self._excel_dir = file_path
|
|
|
|
@QtCore.Slot()
|
|
def magic(self):
|
|
self.text_solve.append("*******************")
|
|
|
|
# 读取文件
|
|
if self._excel_dir is None:
|
|
self.text_solve.append("请先选择文件!")
|
|
return
|
|
|
|
self.text_solve.append("开始排班...")
|
|
self.text_solve.append("读取文件中...")
|
|
all_data, index_to_name_dict, preference_mat, want_num_array, is_new_array, is_tech_array = read_excel(self._excel_dir)
|
|
self.text_solve.append("读取文件成功!")
|
|
|
|
self.text_solve.append("信息统计:")
|
|
stu_num = len(index_to_name_dict)
|
|
self.text_solve.append(f"\t学生总人数:{stu_num}")
|
|
|
|
class_num = len(preference_mat[0])
|
|
self.text_solve.append(f"\t班次总数:{class_num}")
|
|
|
|
tech_sum = 0
|
|
for i in range(len(preference_mat)):
|
|
if not is_new_array[i] and is_tech_array[i]:
|
|
tech_sum += want_num_array[i]
|
|
self.text_solve.append(f"\t电脑部或电气部的所有老人的意愿班次之和:{tech_sum}")
|
|
|
|
all_sum = sum(want_num_array)
|
|
self.text_solve.append(f"\t所有人的意愿班次之和:{all_sum}")
|
|
|
|
# 读取限制条件
|
|
num_min = int(self.line_edit_1_1.text()) if self.line_edit_1_1.text() else None
|
|
num_max = int(self.line_edit_1_2.text()) if self.line_edit_1_2.text() else None
|
|
num_tech_min = int(self.line_edit_2_1.text()) if self.line_edit_2_1.text() else None
|
|
num_tech_max = int(self.line_edit_2_2.text()) if self.line_edit_2_2.text() else None
|
|
num_old_min = int(self.line_edit_3_1.text()) if self.line_edit_3_1.text() else None
|
|
num_old_max = int(self.line_edit_3_2.text()) if self.line_edit_3_2.text() else None
|
|
num_new_min = int(self.line_edit_4_1.text()) if self.line_edit_4_1.text() else None
|
|
num_new_max = int(self.line_edit_4_2.text()) if self.line_edit_4_2.text() else None
|
|
|
|
self.text_solve.append("计算最优解中...")
|
|
vars = solve_program(preference_mat=preference_mat, want_num_array=want_num_array, is_new_array=is_new_array, is_tech_array=is_tech_array,
|
|
num_min=num_min, num_max=num_max, num_tech_min=num_tech_min, num_tech_max=num_tech_max,
|
|
num_old_min=num_old_min, num_old_max=num_old_max, num_new_min=num_new_min, num_new_max=num_new_max)
|
|
if vars is None:
|
|
self.text_solve.append("在目前限制条件下无解!请尝试更改限制条件!")
|
|
return
|
|
else:
|
|
self.text_solve.append("计算最优解成功!")
|
|
|
|
# 保存结果到 excel
|
|
self.text_solve.append("保存结果中...")
|
|
time_str = datetime.now().strftime('%Y%m%d_%H%M%S')
|
|
save_dir = f"result_{time_str}.xlsx"
|
|
if vars is not None:
|
|
save_to_excel(vars, all_data, index_to_name_dict, preference_mat, save_dir)
|
|
self.text_solve.append(f"保存结果成功!保存路径:{save_dir}")
|
|
|
|
if __name__ == "__main__":
|
|
app = QtWidgets.QApplication([])
|
|
|
|
widget = MyWidget()
|
|
widget.setWindowTitle("EVA 值班排班软件")
|
|
widget.resize(600, 600)
|
|
widget.show()
|
|
|
|
sys.exit(app.exec()) |