diff --git a/images/派单任务信息栏1.png b/images/派单任务信息栏1.png new file mode 100644 index 0000000..6991534 Binary files /dev/null and b/images/派单任务信息栏1.png differ diff --git a/images/派单任务信息栏2.png b/images/派单任务信息栏2.png new file mode 100644 index 0000000..5397cd4 Binary files /dev/null and b/images/派单任务信息栏2.png differ diff --git a/utils/image_paths.py b/utils/image_paths.py index a62027b..32fc454 100644 --- a/utils/image_paths.py +++ b/utils/image_paths.py @@ -107,4 +107,11 @@ class ImagePaths: SEGMENT_DETAILS_POPUP_BG = "images/详情弹出背景.png" SEGMENT_DETAILS_TITLE_BG = "images/详情标题.png" SEGMENT_DETAILS_INFO_BAR = "images/管片任务信息栏.png" - SEGMENT_DETAILS_CLOSE_ICON = "images/关闭图标.png" \ No newline at end of file + SEGMENT_DETAILS_CLOSE_ICON = "images/关闭图标.png" + + # 功能: 派单任务详情按钮弹窗 + DESPATCH_DETAILS_POPUP_BG = "images/详情弹出背景.png" + DESPATCH_DETAILS_TITLE_BG = "images/详情标题.png" + DESPATCH_DETAILS_INFO_BAR_NORMAL = "images/派单任务信息栏1.png" + DESPATCH_DETAILS_INFO_BAR_HOVER = "images/派单任务信息栏2.png" + DESPATCH_DETAILS_CLOSE_ICON = "images/关闭图标.png" \ No newline at end of file diff --git a/view/main_window.py b/view/main_window.py index e2a500a..2e6934b 100644 --- a/view/main_window.py +++ b/view/main_window.py @@ -22,6 +22,7 @@ import resources.resources_rc from utils.image_paths import ImagePaths from .widgets.segment_details_dialog import SegmentDetailsDialog +from .widgets.dispatch_details_dialog import DispatchDetailsDialog class MainWindow(QWidget): @@ -49,6 +50,9 @@ class MainWindow(QWidget): # 管片任务详情 self.segment_task_widget.task_details_signal.connect(self.handleSegmentTaskDetails) # 管片任务详情按钮 + # 派单任务详情 + self.dispatch_task_widget.task_details_signal.connect(self.handleDispatchTaskDetails) # 派单任务详情按钮 + def handleSystemStart(self): # 测试系统开启,进度条动画 @@ -239,6 +243,31 @@ class MainWindow(QWidget): # 这里可以设置对话框显示的内容 如 set_segment_id # segment_details_dialog.set_segment_id("9999999999") segment_details_dialog.show() + + def handleDispatchTaskDetails(self, dispatch_task_name:str): + # 派单任务名 task1、task2、task3 (分别对应第一条派单任务、 第二条派单任务...) + print("main_window: handleDispatchTaskDetails", dispatch_task_name) + + # 显示派单任务详情对话框 + dispatch_details_dialog = DispatchDetailsDialog(dispatch_task_name, self) + + # 这里可以设置对话框显示的内容 如 set_segment_id + # dispatch_details_dialog.set_segment_id("9999999999") + # 设置派单任务详情中的方量的值 + current_volume = self.dispatch_task_widget.get_task_volume(dispatch_task_name) + dispatch_details_dialog.set_row_value(4, str(current_volume)) # 派单方量的值的行号为4,第五行 + + # 派单任务详情页面中确定修改了派单任务的方量 + # 备注:褚工说管片任务和派单任务中的方量都只有一位小数,料斗上的方量显示两位 2025/11/8 + dispatch_details_dialog.confirm_modify_volume.connect(self.handleModifyDispatchTaskVolume) + dispatch_details_dialog.show() + + def handleModifyDispatchTaskVolume(self, dispatch_task_name:str, modifyed_volume:float): + """派单任务详情页面中, 修改了派单任务的方量""" + # 修改相应的派单任务条目显示的 派单任务方量 + self.dispatch_task_widget.set_task_volume(dispatch_task_name, modifyed_volume) + + # 其他操作,可能需要修改数据库的派单任务方量 # 更新 派单任务widget的坐标 diff --git a/view/widgets/dispatch_details_dialog.py b/view/widgets/dispatch_details_dialog.py new file mode 100644 index 0000000..7a535a4 --- /dev/null +++ b/view/widgets/dispatch_details_dialog.py @@ -0,0 +1,391 @@ +from PySide6.QtWidgets import ( + QApplication, + QDialog, + QVBoxLayout, + QHBoxLayout, + QGridLayout, + QLabel, + QWidget, + QPushButton, +) +from PySide6.QtGui import QPixmap, QFont, QPainter, QIcon +from PySide6.QtCore import Qt, QEvent, Signal +import sys + +from utils.image_paths import ImagePaths + +from view.widgets.value_adjuster import ValueAdjuster + +""" + 派单任务的详情按钮点击之后弹出, 显示派单任务的详情 +""" + +class DispatchDetailsDialog(QDialog): + # 确认修改了派单任务的方量,发送任务名(task1、task2等)和最终确认修改的方量值 + confirm_modify_volume = Signal(str, float) + + def __init__(self, dispatch_task_name:str, parent=None): + super().__init__(parent) + self.setAttribute(Qt.WA_TranslucentBackground) + + # 派单任务名 (task1、task2、 task3) + self.dispatch_task_name = dispatch_task_name + + # 初始化存储需要修改的控件 + self.id_value_label = None # 对应管片ID值标签 + self.rows = [] # 所有行的单元格列表(包含label、value) + + # 派单方量调整控件,用于修改派单方量 + self.volume_value_adjuster = None + + self._init_ui() + + def _init_ui(self): + self.setWindowFlags(Qt.FramelessWindowHint) + self._load_background() + + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(32, 20, 32, 50) + main_layout.setSpacing(0) + + # 1. 顶部区域(标题 + 关闭按钮) + self._add_top_area(main_layout) + + # 2. 对应管片ID区域 + self._add_segment_id_area(main_layout) + + # 3. 网格信息区域(单列7行) + self._add_grid_info_area(main_layout) + + # 4. 修改方量按钮 + self.modify_btn = QPushButton("修改方量", parent=self) + self.modify_btn.setFixedSize(89, 32) + self.modify_btn.setStyleSheet( + """ + QPushButton { + background-color: #001c82; + color: #9fbfd4; + border: 1px solid #017cbc; + font-size: 18px; + font-weight: Bold; + } + QPushButton:hover { + color: #2dcedb; + } + """ + ) + # modify_btn.move(860, 446) # 移动到第五行,派单方量的位置 + self.modify_btn.move(860, 442) # 移动到第五行,派单方量的位置 + self.modify_btn.clicked.connect(self.onModifyVolume) + + # 确认修改方量按钮,表示 派单方量的修改已经确定 + self.confirm_btn = QPushButton("确定", parent=self) + self.confirm_btn.setStyleSheet( + """ + QPushButton { + background-color: #001c82; + color: #9fbfd4; + border: 1px solid #017cbc; + font-size: 18px; + font-weight: Bold; + } + QPushButton:hover { + color: #2dcedb; + } + """ + ) + self.confirm_btn.move(860, 442) + self.confirm_btn.hide() # 初始隐藏 + self.confirm_btn.setFixedSize(42, 32) + self.confirm_btn.clicked.connect(self.onConfirmModifyVolume) + + # 取消修改方量按钮,表示 派单方量的修改已经取消 + self.cancel_btn = QPushButton("取消", parent=self) + self.cancel_btn.setStyleSheet( + """ + QPushButton { + background-color: #001c82; + color: #9fbfd4; + border: 1px solid #017cbc; + font-size: 18px; + font-weight: Bold; + } + QPushButton:hover { + color: #2dcedb; + } + """ + ) + self.cancel_btn.hide() + self.cancel_btn.setFixedSize(42, 32) + self.cancel_btn.move(907, 442) + self.cancel_btn.clicked.connect(self.onCancelModifyVolume) + + def _load_background(self): + self.bg_pixmap = QPixmap(ImagePaths.DESPATCH_DETAILS_POPUP_BG) + if self.bg_pixmap.isNull(): + print("错误:派单任务背景.png 加载失败,请检查路径!") + self.setFixedSize(800, 600) + else: + self.setFixedSize(self.bg_pixmap.size()) + + def _add_top_area(self, parent_layout): + top_layout = QHBoxLayout() + top_layout.setContentsMargins(0, 0, 0, 36) + + top_layout.addStretch() + + # 标题改为“任务派单” + title_label = QLabel("派单任务") + font = QFont() + font.setPixelSize(24) + font.setLetterSpacing(QFont.AbsoluteSpacing, 2) + font.setBold(True) + title_label.setFont(font) + title_label.setStyleSheet("color: #13fffc; font-weight: Bold;") + title_label.setAlignment(Qt.AlignCenter) + top_layout.addWidget(title_label) + + # 关闭按钮(保持原逻辑) + self._create_close_button(top_layout) + + parent_layout.addLayout(top_layout) + + def _create_close_button(self, parent_layout): + self.close_btn = QPushButton() + self.close_btn.setFixedSize(36, 36) + + close_icon = QPixmap(ImagePaths.DESPATCH_DETAILS_CLOSE_ICON) + if not close_icon.isNull(): + self.close_btn.setIcon(QIcon(close_icon)) + + self.close_btn.setStyleSheet( + """ + QPushButton { + background-color: transparent; + border: none; + padding: 0px; + } + QPushButton:hover { + background-color: red; + border-radius: 2px; + } + """ + ) + self.close_btn.clicked.connect(self.close) + + parent_layout.addStretch() + parent_layout.addWidget(self.close_btn) + + def _add_segment_id_area(self, parent_layout): + id_layout = QHBoxLayout() + + id_label = QLabel("对应管片ID") # 标签文字修改 + id_label.setFixedSize(318, 32) + id_font = QFont() + id_font.setPixelSize(18) + id_font.setLetterSpacing(QFont.AbsoluteSpacing, 2) + id_font.setBold(True) + id_label.setFont(id_font) + id_label.setStyleSheet( + f""" + background-image: url({ImagePaths.DESPATCH_DETAILS_TITLE_BG}); + background-repeat: no-repeat; + background-position: center; + color: #13ffff; + """ + ) + id_label.setContentsMargins(16, 0, 0, 0) + id_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + + self.id_value_label = QLabel("222232454352452") # 初始管片ID值 + value_font = QFont() + value_font.setPixelSize(18) + value_font.setBold(True) + value_font.setLetterSpacing(QFont.AbsoluteSpacing, 2) + self.id_value_label.setFont(value_font) + self.id_value_label.setStyleSheet("color: #13ffff;") + self.id_value_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) + + id_layout.addWidget(id_label) + id_layout.addStretch() + id_layout.addWidget(self.id_value_label) + id_layout.setContentsMargins(0, 0, 0, 16) + parent_layout.addLayout(id_layout) + + def _add_grid_info_area(self, parent_layout): + grid_layout = QGridLayout() + grid_layout.setSpacing(12) + + # 初始化信息条目(7行) + info_items = [ + ("创建时间", "2025年10月10日 10:10:10"), + ("派单时间", "2025年10月10日 10:10:10"), + ("任务编号", "20251010-10"), + ("配比编号", "20251010-10"), + ("派单方量", "2.0"), + ("派单状态", "未下发"), + ("派单类型", "自动派单"), + ] + + self.rows.clear() + for row, (label_text, value_text) in enumerate(info_items): + cell_widget = self._create_info_cell(label_text, value_text) + self.rows.append(cell_widget) + grid_layout.addWidget(cell_widget, row, 0) + + parent_layout.addLayout(grid_layout) + + def _create_info_cell(self, label_text, value_text): + cell_widget = QWidget() + cell_bg = QPixmap(ImagePaths.DESPATCH_DETAILS_INFO_BAR_NORMAL) # 正常背景图 + cell_widget.setObjectName("infoCell") + if not cell_bg.isNull(): + cell_widget.setFixedSize(cell_bg.size()) + cell_widget.setStyleSheet( + f""" + QWidget {{ + background-image: url({ImagePaths.DESPATCH_DETAILS_INFO_BAR_NORMAL}); + background-repeat: no-repeat; + background-position: Center; + }} + QWidget:hover {{ + background-image: url({ImagePaths.DESPATCH_DETAILS_INFO_BAR_HOVER}); + }} + QWidget QLabel#valueLabel {{ + color: #9fbfd4; + background: none; + }} + """ + ) + + cell_layout = QHBoxLayout(cell_widget) + cell_layout.setContentsMargins(0, 0, 0, 0) + + # 左侧标签 + label = QLabel(label_text) + label.setFixedSize(136, 60) + label_font = QFont() + label_font.setPixelSize(16) + label_font.setLetterSpacing(QFont.AbsoluteSpacing, 2) + label.setFont(label_font) + label.setStyleSheet("background: none;color: #fffffd; font-weight:Bold;") + label.setAlignment(Qt.AlignCenter) + cell_widget.label = label + + # 右侧值标签(设置objectName以便样式选择) + value = QLabel(value_text) + value.setObjectName("valueLabel") + value_font = QFont() + value_font.setPixelSize(20) + value.setFont(value_font) + value.setAlignment(Qt.AlignCenter) + cell_widget.value = value + + cell_layout.addWidget(label) # 左侧的标题标签 + cell_layout.addSpacing(60) + cell_layout.addWidget(value) # 右侧的值标签 + + cell_widget.installEventFilter(self) + return cell_widget + + # 实现事件过滤器,动态修改右侧值颜色 + def eventFilter(self, obj, event): + # 只处理父控件(infoCell)的事件 + if obj.objectName() == "infoCell": + # 鼠标进入父控件 → 改#13f0f3 + if event.type() == QEvent.Enter: + if hasattr(obj, "value"): # 确保存在value控件 + obj.value.setStyleSheet("background: none; color: #13f0f3;") + # 鼠标离开父控件 → 恢复默认色 + elif event.type() == QEvent.Leave: + if hasattr(obj, "value"): + obj.value.setStyleSheet("background: none; color: #9fbfd4;") + return super().eventFilter(obj, event) + + def onModifyVolume(self): + """修改派单方量的逻辑""" + volume_label = self.rows[4].value + current_value = float(volume_label.text()) + + # 1、调整派单方量,创建派单方量调整控件 + if not self.volume_value_adjuster: + self.volume_value_adjuster = ValueAdjuster(self) + self.volume_value_adjuster.move(551, 442) # 移动到当前显示派单方量的标签处 + + # 2、更新派单方量调整控件的值, 并显示 + self.volume_value_adjuster.set_value(current_value) + self.volume_value_adjuster.show() + + # 3、显示确定按钮、显示取消按钮、隐藏修改方量按钮 + self.confirm_btn.show() + self.cancel_btn.show() + self.modify_btn.hide() + + def onConfirmModifyVolume(self): + """确定 修改派单方量""" + # 显示相关的: + # 1、隐藏确认按钮、隐藏取消按钮、显示修改方量按钮 + self.confirm_btn.hide() + self.cancel_btn.hide() + self.modify_btn.show() + + # 2、修改 派单方量标签的值 + volume_label = self.rows[4].value + # modifyed_value 为float类型, 一位小数 + modifyed_value = self.volume_value_adjuster.get_value() + volume_label.setText(str(modifyed_value)) + + # 3、发送派单方量确定修改的信号 (发送派单任务名 + 确认修改之后的派单方量) + self.confirm_modify_volume.emit(self.dispatch_task_name, modifyed_value) + + # 4、关闭派单方量调整控件 + self.volume_value_adjuster.close() + + def onCancelModifyVolume(self): + # 显示相关的: + # 1、隐藏确认按钮、隐藏取消按钮、显示修改方量按钮 + self.confirm_btn.hide() + self.cancel_btn.hide() + self.modify_btn.show() + + # 2、关闭派单方量调整控件 + self.volume_value_adjuster.close() + + def paintEvent(self, event): + if not self.bg_pixmap.isNull(): + painter = QPainter(self) + painter.drawPixmap(self.rect(), self.bg_pixmap) + super().paintEvent(event) + + # ------------------- 对外修改接口 ------------------- + # row 对应行号(0-6),从0开始 + # -------------------------------------------------- + def set_segment_id(self, new_id): + """修改上方的 对应的管片ID的值""" + if self.id_value_label: + self.id_value_label.setText(str(new_id)) + + def set_row_label(self, row, new_label_text: str): + """修改左侧的显示的标签的文本,如: 创建时间、派单时间等""" + if 0 <= row < len(self.rows): + self.rows[row].label.setText(new_label_text) + + def set_row_value(self, row, new_value_text: str): + """修改右侧的显示的值, 如: 2025年9月9日 9:9:9""" + if 0 <= row < len(self.rows): + self.rows[row].value.setText(new_value_text) + + +# 测试代码 +if __name__ == "__main__": + app = QApplication(sys.argv) + dialog = DispatchDetailsDialog() + + # 测试修改接口 + dialog.set_segment_id("999999999999999") + dialog.set_row_label(0, "新创建时间") + dialog.set_row_value(0, "2025年09月09日 09:09:09") + dialog.set_row_value(4, "3.0") # 初始派单方量修改 + + dialog.show() + sys.exit(app.exec()) diff --git a/view/widgets/task_widget.py b/view/widgets/task_widget.py index e9f7556..d0ba1d0 100644 --- a/view/widgets/task_widget.py +++ b/view/widgets/task_widget.py @@ -187,6 +187,33 @@ class TaskWidget(QWidget): task_id_label = self.task_controls[task_name]["task_id_label"] task_id_label.setText(new_id) + def get_task_volume(self, task_name:str): + """ + 获取指定任务的方量, 传入任务名,如 task1、task2、task3 + return: 返回 float类型一位小数的方量值 + """ + if task_name in self.task_controls: + volume_label = self.task_controls[task_name]["volume_label"] + + # 提取 volume_label中显示的 "方量 200" 中的数字部分 + # 1. 去除前后空格,按空格分割字符串 + volume_text = volume_label.text().strip() + parts = volume_text.split() + + # 2. 取分割后的数字部分 + if len(parts) >= 2: + number_str = parts[1] # 得到 "200" + else: + # 格式异常(没有数字部分),返回None + return None + + # 褚工说任务中显示的方量只有一位小数 + try: + volume_value = round(float(number_str), 1) + return volume_value + except ValueError: + return None + if __name__ == "__main__": app = QApplication(sys.argv) widget = TaskWidget("管片任务") diff --git a/view/widgets/value_adjuster.py b/view/widgets/value_adjuster.py index a2a8393..153a294 100644 --- a/view/widgets/value_adjuster.py +++ b/view/widgets/value_adjuster.py @@ -4,13 +4,36 @@ from PySide6.QtCore import Qt from PySide6.QtGui import QDoubleValidator import sys -# 调整计划方量 +""" + 调整计划方量, 左侧减按钮, 右侧加按钮 + 这里的 最小值、最大值、初始值 需要读取配置文件来决定 +""" + +class CustomLineEdit(QLineEdit): + def __init__(self, default_text: str, parent=None): + super().__init__(parent) + self.default_text = default_text # 保存初始化时的默认文本 + self.setText(self.default_text) # 初始化为默认文本 + + def focusOutEvent(self, event): + super().focusOutEvent(event) # 先执行父类的焦点离开逻辑 + + # 检查文本是否为空(或仅含空格) + current_text = self.text().strip() + if not current_text: + self.setText(self.default_text) # 为空则恢复默认值 + else: # 不为空,显示一位小数 + value = round(float(current_text), 1) + self.setText(f"{value:.1f}") + + self.setCursorPosition(0) # 光标移到最前面 (保证数值显示完整) + class ValueAdjuster(QWidget): def __init__(self, parent=None): super().__init__(parent) - self.min_value = 0 # 最小值 - self.max_value = 99 # 最大值 - self.value = 2.5 # 初始值 + self.min_value = 0.0 # 最小值 + self.max_value = 99.0 # 最大值 + self.value = 2.5 # 初始值 (需要显示一位数字) self.setFixedSize(102, 32) @@ -21,7 +44,9 @@ class ValueAdjuster(QWidget): self.minus_btn.setCursor(Qt.PointingHandCursor) # 中间的编辑栏 - self.line_edit = QLineEdit(f"{self.value:.1f}") # 显示1位小数 + # 支持显示两位小数 + # self.line_edit = QLineEdit(f"{self.value:.1f}") # 显示1位小数 + self.line_edit = CustomLineEdit(f"{self.value:.1f}") # 显示1位小数 self.line_edit.setFixedSize(40, 26) # 加号按钮 @@ -31,8 +56,8 @@ class ValueAdjuster(QWidget): # 配置QLineEdit:支持数字输入+居中显示 self.line_edit.setAlignment(Qt.AlignCenter) # 文本居中 - # 限制输入为浮点数(支持负数,范围可自定义) - self.line_edit.setValidator(QDoubleValidator(0, 99, 1, self)) # 最多1位小数 + # 限制输入为浮点数(范围可自定义) + self.line_edit.setValidator(QDoubleValidator(self.min_value, self.max_value, 1, self)) # 最多1位小数 (必选) self.line_edit.textChanged.connect(self.on_text_changed) # 监听输入变化 # 设置样式表(保持与按钮风格统一) @@ -112,7 +137,7 @@ class ValueAdjuster(QWidget): self.line_edit.setText(f"{self.value:.1f}") def on_text_changed(self, text): - """监听输入框文本变化,更新内部value""" + """监听输入框文本变化, 更新内部value""" if not text: return try: @@ -126,7 +151,7 @@ class ValueAdjuster(QWidget): except ValueError: pass - # 获取具体的方量数值 + # 获取具体的方量数值,float类型 (一位小数) def get_value(self): return self.value