642 lines
33 KiB
Python
642 lines
33 KiB
Python
# coding: utf-8
|
||
from typing import List
|
||
from PySide6.QtCore import Qt, Signal, QEasingCurve, QUrl, QSize, QTimer, QEvent
|
||
from PySide6.QtGui import QIcon, QDesktopServices, QColor, QPalette, QBrush, QImage
|
||
from PySide6.QtWidgets import (QApplication, QHBoxLayout, QVBoxLayout,
|
||
QFrame, QWidget, QSpacerItem, QSizePolicy, QMainWindow, QLineEdit)
|
||
|
||
# from .widgets.status_monitor_widget import StatusMonitorWidget
|
||
from .widgets.system_nav_bar import SystemNavBar
|
||
from .widgets.mixer_widget import MixerWidget
|
||
from .widgets.conveyor_system_widget import ConveyorSystemWidget
|
||
from .widgets.task_widget import TaskWidget
|
||
from .widgets.plan_widget import PlanWidget
|
||
from .widgets.frequency_button_group import FrequencyButtonGroup
|
||
from .widgets.hopper_widget import HopperWidget
|
||
from .widgets.arc_progress_widget import ArcProgressWidget
|
||
from .widgets.production_progress_widget import ProductionProgressWidget
|
||
# from .widgets.system_button_widget import SystemButtonWidget
|
||
from .widgets.vibration_video_widget import VibrationVideoWidget
|
||
from .widgets.bottom_control_widget import BottomControlWidget
|
||
|
||
import resources.resources_rc
|
||
from utils.image_paths import ImagePaths
|
||
|
||
from .widgets.segment_details_dialog import SegmentDetailsDialog
|
||
from .widgets.dispatch_details_dialog import DispatchDetailsDialog
|
||
|
||
from busisness.models import ArtifactInfoModel
|
||
from busisness.models import PDRecordModel
|
||
import json
|
||
|
||
|
||
class MainWindow(QWidget):
|
||
# 定义“即将关闭”的信号
|
||
about_to_close = Signal()
|
||
|
||
# 计划方量修改信号
|
||
plan_volume_modified_signal = Signal(str)
|
||
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.initWindow()
|
||
self.init_business_attributes() # 初始化业务属性
|
||
self.createSubWidgets() # 创建子部件
|
||
self.initSubWidgets() # 初始化子部件
|
||
self.setupLayout() # 设置布局
|
||
self.connectSignalToSlot()
|
||
|
||
# 安装事件过滤器,处理计划方量的 QLineEdit的失去焦点事件
|
||
self.installEventFilter(self)
|
||
|
||
# 初始化派单任务控件
|
||
self.dispatch_task_widget.set_task_select_btn_selected("task2") # 派单任务控件,初始化选中第二条派单任务
|
||
|
||
# 连接槽函数
|
||
def connectSignalToSlot(self):
|
||
# 可添加信号槽连接
|
||
# self.system_button_widget.buttons["系统启动"].clicked.connect(self.handleSystemStart)
|
||
# self.system_button_widget.buttons["系统停止"].clicked.connect(self.handleSystemStop)
|
||
|
||
# 传送带部分的按钮
|
||
self.conveyor_system_widget.left_btn.clicked.connect(self.handleHopperMoveLeft) # 传送带下的左移按钮
|
||
self.conveyor_system_widget.right_btn.clicked.connect(self.handleHopperMoveRight) # 传送带下的右移按钮
|
||
|
||
# 管片任务详情
|
||
self.segment_task_widget.task_details_signal.connect(self.handleSegmentTaskDetails) # 管片任务详情按钮
|
||
|
||
# 派单任务详情
|
||
self.dispatch_task_widget.task_details_signal.connect(self.handleDispatchTaskDetails) # 派单任务详情按钮
|
||
|
||
# 派单任务选择 (用于更新计划表单)
|
||
self.dispatch_task_widget.task_selected_signal.connect(self.handleDispatchTaskSelected) # 派单任务选择按钮
|
||
|
||
# 计划表单方量修改
|
||
self.plan_table_widget.final_modify_volume_signal.connect(self.handleDispatchTaskVolumeModified) # 计划方量修改
|
||
|
||
def handleSystemStart(self):
|
||
# 测试系统开启,进度条动画
|
||
self.production_progress.testProgress(60)
|
||
self.arc_progress.testProgress(60)
|
||
|
||
def handleSystemStop(self):
|
||
# 测试系统停止,进度条动画
|
||
self.production_progress.animation.stop()
|
||
self.arc_progress.animation.stop()
|
||
|
||
def initWindow(self):
|
||
"""初始化窗口基本属性"""
|
||
self.setWindowTitle("中交三航主界面") # 设置窗口标题
|
||
# 设置最小尺寸(可根据需求调整)
|
||
# 工控机尺寸为 1280*1024
|
||
self.setMinimumSize(1280, 1024)
|
||
self.setObjectName("MainWindow")
|
||
# 设置主界面窗口背景色
|
||
# self.setStyleSheet("background-color: #ffffff;") # #001558
|
||
|
||
# Qt.FramelessWindowHint
|
||
# 没有顶部的白色边框
|
||
self.setWindowFlags(Qt.FramelessWindowHint) # 无边框
|
||
|
||
# 设置主界面背景图片
|
||
try:
|
||
self.background_image = QImage(ImagePaths.MAIN_INTERFACE_BACKGROUND)
|
||
if self.background_image.isNull():
|
||
raise Exception("图片为空,可能路径错误或格式不支持")
|
||
# print("图片加载成功")
|
||
except Exception as e:
|
||
print(f"主界面背景图片加载失败: {e}")
|
||
self.background_image = None
|
||
return # 加载背景失败
|
||
|
||
self.update_background()
|
||
|
||
def init_business_attributes(self):
|
||
# 保存管片任务信息的字典 task1: ArtifactInfoModel1.... (用于显示管片任务详情)
|
||
self.artifact_dict = {}
|
||
# 当前点击/选中的 管片任务详情对应的任务名(task1\task2\task3) (用于刷新选中的管片任务详情)
|
||
self.current_selected_segment_detail_name = None
|
||
|
||
# 保存派单任务信息的字典 task1: PDRecordModel1.... (用于显示派单任务详情)
|
||
self.dispatch_dict = {}
|
||
# 当前点击/选中的 派单任务详情对应的任务名(task1\task2\task3) (用于刷新选中的派单任务详情)
|
||
self.current_selected_dispatch_detail_name = None
|
||
# 当前点击/选中的 派单任务选择按钮对应的任务名 (用于刷新 计划表单)
|
||
self.current_dispatch_task_select_btn_name = None
|
||
|
||
def createSubWidgets(self):
|
||
"""创建所有子部件实例"""
|
||
self.system_nav_bar = SystemNavBar() # 最上方:系统导航栏
|
||
self.mixer_widget = MixerWidget(self) # 左侧: 搅拌机
|
||
self.conveyor_system_widget = ConveyorSystemWidget(self) # 左侧: 传送带系统
|
||
self.segment_task_widget = TaskWidget("管片任务", self) # 左侧:管片任务
|
||
self.dispatch_task_widget = TaskWidget("派单任务", self) # 右侧:派单任务
|
||
self.frequency_button_group = FrequencyButtonGroup(self) # 右侧:振捣频率按钮组(220hz/230hz/240hz)
|
||
self.plan_table_widget = PlanWidget(self) # 右侧: 计划表单
|
||
# self.status_monitor = StatusMonitorWidget() # 状态监控部件
|
||
self.hopper_widget = HopperWidget() # 中间1:料斗部件
|
||
self.arc_progress = ArcProgressWidget() # 中间2:弧形进度部件 (模具车)
|
||
self.production_progress = ProductionProgressWidget() # 中间3: 生产进度部件
|
||
# self.system_button_widget = SystemButtonWidget() # 系统控制按钮
|
||
self.vibration_video = VibrationVideoWidget() # 振捣视频控件 (右侧)
|
||
self.bottom_control_widget = BottomControlWidget() # 最下方: 控制的按钮 (系统诊断、系统中心等)
|
||
|
||
def initSubWidgets(self):
|
||
# 初始化派单任务的 任务id
|
||
# self.dispatch_task_widget.set_task_id("task1", "PD0001")
|
||
# self.dispatch_task_widget.set_task_id("task2", "PD0002")
|
||
# self.dispatch_task_widget.set_task_id("task3", "PD0003")
|
||
|
||
# 初始化 管片任务 和 派单任务显示的数据
|
||
self._init_segment_tasks()
|
||
self._init_dispatch_tasks()
|
||
|
||
def convert_to_ampm(self, time_str: str) -> str:
|
||
"""
|
||
将时间转换为"hh:mmAM/PM"形式(如03:22PM)
|
||
Args:
|
||
time_str: 原始时间字符串"
|
||
Returns:
|
||
转换后的时间字符串(如"03:22PM")
|
||
"""
|
||
from datetime import datetime
|
||
# 可能的时间格式(优先尝试带微秒的格式)
|
||
time_formats = [
|
||
"%Y-%m-%d %H:%M:%S", # 不带微秒
|
||
"%Y-%m-%d %H:%M:%S.%f" # 带微秒(如.528453)
|
||
]
|
||
|
||
for fmt in time_formats:
|
||
try:
|
||
dt = datetime.strptime(time_str, fmt)
|
||
return dt.strftime("%I:%M%p") # 转换为12小时制时分+AM/PM
|
||
except ValueError:
|
||
continue # 格式不匹配,尝试下一种格式
|
||
|
||
# 所有格式都不匹配时,返回占位符
|
||
return "--:--"
|
||
|
||
def _init_segment_tasks(self):
|
||
"""初始化管片任务, 从数据库中读取管片任务数据并更新到UI"""
|
||
try:
|
||
from busisness.blls import ArtifactBll
|
||
artifact_dal = ArtifactBll()
|
||
artifacts = artifact_dal.get_artifact_task() # 获取管片任务数据
|
||
|
||
# 更新管片任务
|
||
self.update_segment_tasks(artifacts)
|
||
except Exception as e:
|
||
print(f"更新管片任务数据失败: {e}")
|
||
|
||
def update_segment_tasks(self, artifact_list:List[ArtifactInfoModel]):
|
||
# 更新管片任务相关的信息
|
||
# 遍历数据并更新UI (包括左侧的管片任务 以及 管片任务详情)
|
||
SEGMENT_STATUS_MAP = {
|
||
1: "待生产",
|
||
2: "正生产",
|
||
3: "已生产" # 完成生产
|
||
}
|
||
SEGMENT_STATUS_IMAGE = {
|
||
1: ImagePaths.TASK_RECT5,
|
||
2: ImagePaths.TASK_RECT4,
|
||
3: ImagePaths.TASK_RECT3
|
||
}
|
||
for index, artifact in enumerate(reversed(artifact_list), 1):
|
||
# 提取管片生产状态
|
||
segment_status_text = SEGMENT_STATUS_MAP.get(artifact.Status, "未知") # 管片状态文本
|
||
segment_status_icon = SEGMENT_STATUS_IMAGE.get(artifact.Status, ImagePaths.TASK_RECT1) # 管片状态图标
|
||
|
||
if artifact.MouldCode: # 更新模具号
|
||
self.segment_task_widget.set_task_id(f"task{index}", artifact.MouldCode)
|
||
if artifact.BetonVolume: # 更新浇筑方量
|
||
self.segment_task_widget.set_task_volume(f"task{index}", artifact.BetonVolume)
|
||
if artifact.BeginTime: # 更新时间 (管片任务的开始时间)
|
||
# print("artifact.BeginTime: ", artifact.BeginTime)
|
||
self.segment_task_widget.set_task_time(f"task{index}", self.convert_to_ampm(artifact.BeginTime))
|
||
if segment_status_text: # 更新管片状态
|
||
self.segment_task_widget.set_task_status(f"task{index}", segment_status_text, segment_status_icon)
|
||
# 更新模具车上的管片信息
|
||
if segment_status_text == "正生产": # 模具车上只显示 正生产的管片信息
|
||
self.arc_progress.setRingNumber(artifact.ProduceRingNumber) # 设置模具车上的环号
|
||
self.arc_progress.setSegmentModel(artifact.BuriedDepth+": "+artifact.RingTypeCode) # 管片类型(如:中埋: R12)
|
||
self.arc_progress.setSegmentSize(artifact.SizeSpecification) # 管片规格(尺寸)
|
||
self.arc_progress.setSegmentNumber(artifact.MouldCode) # 管片号(如:SHRB1-3)[模具编号]
|
||
self.SetSegmentTaskDetails(f"task{index}", artifact) # 设置管片任务详情信息
|
||
|
||
def _init_dispatch_tasks(self):
|
||
"""初始化派单任务, 从数据库中读取派单任务数据并更新到UI"""
|
||
try:
|
||
from busisness.blls import PDRecordBll
|
||
pdrecord_dal = PDRecordBll()
|
||
pdrecords = pdrecord_dal.get_PD_record() # 获取派单任务数据
|
||
|
||
# 更新派单任务
|
||
self.update_dispatch_tasks(pdrecords)
|
||
except Exception as e:
|
||
print(f"更新派单任务数据失败: {e}")
|
||
|
||
def update_dispatch_tasks(self, pdrecord_list:List[PDRecordModel]):
|
||
# 更新派单任务相关的信息
|
||
# 遍历数据并更新UI
|
||
# 倒着查,过滤掉 搅拌生产状态不是 未知的,
|
||
# 1、查到的第一个 派单状态为 已下发或者已超时 作为task1
|
||
# 2、查到的第一个 派单状态为 计划中的作为 task2,第二个派单状态为 计划中作为 task3
|
||
# 初始化标记:控制只取第一条Status=2/3、前两条Status=1的记录
|
||
# 派单状态映射(1计划中 2已下发 0未知 3已超时)
|
||
DISPATCH_STATUS_MAP = {
|
||
0: "未知",
|
||
1: "计划中",
|
||
2: "派单中", # 已下发
|
||
3: "已超时",
|
||
4: "未扫码"
|
||
}
|
||
# 派单状态图标映射
|
||
DISPATCH_STATUS_IMAGE = {
|
||
0: ImagePaths.TASK_RECT1,
|
||
1: ImagePaths.TASK_RECT2,
|
||
2: ImagePaths.TASK_RECT3,
|
||
3: ImagePaths.TASK_RECT4,
|
||
4: ImagePaths.TASK_RECT5,
|
||
}
|
||
# 搅拌生产状态映射
|
||
PRODUCE_STATUS_MAP = {
|
||
0: "未知",
|
||
1: "已取消",
|
||
2: "已完成",
|
||
3: "异常"
|
||
}
|
||
task_count = 0 # 有效的派单任务数量(需要显示的, task1,task2,task3)
|
||
|
||
# 倒序遍历pdrecord_list
|
||
for record in reversed(pdrecord_list):
|
||
# 提取状态文字
|
||
dispatch_status_text = DISPATCH_STATUS_MAP.get(record.Status, "未知") # 派单状态
|
||
dispatch_status_icon = DISPATCH_STATUS_IMAGE.get(record.Status, ImagePaths.TASK_RECT1) # 派单状态图标
|
||
produce_status_text = PRODUCE_STATUS_MAP.get(record.GStatus, "未知") # 搅拌生产状态
|
||
|
||
# 过滤掉GStatus不为0的记录,搅拌生产状态为未知(0)才需要显示
|
||
if produce_status_text != "未知":
|
||
continue
|
||
|
||
task_count += 1 # 有效任务数量加一
|
||
self._set_dispatch_tasks_info(f"task{task_count}", record, dispatch_status_text, dispatch_status_icon)
|
||
|
||
def _set_dispatch_tasks_info(self, task_name, record:PDRecordModel, status_text:str, status_icon:str):
|
||
# 设置派单任务的tasks信息
|
||
if record.MouldCode:
|
||
self.dispatch_task_widget.set_task_id(task_name, record.MouldCode)
|
||
if record.FBetonVolume:
|
||
self.dispatch_task_widget.set_task_volume(task_name, record.FBetonVolume)
|
||
if record.CreateTime:
|
||
self.dispatch_task_widget.set_task_time(task_name, self.convert_to_ampm(record.CreateTime))
|
||
if status_text:
|
||
self.dispatch_task_widget.set_task_status(task_name, status_text, status_icon)
|
||
self.SetPDRecordTask(task_name, record)
|
||
|
||
def setupLayout(self):
|
||
"""设置垂直布局,从上到下排列部件"""
|
||
main_layout = QVBoxLayout(self) # 主布局:垂直布局
|
||
# 设置布局间距(部件之间的距离)和边距(布局与窗口边缘的距离)
|
||
main_layout.setSpacing(0) # 部件间距0px
|
||
main_layout.setContentsMargins(0, 0, 0, 0) # 左上右下边距0px
|
||
|
||
# 添加最上方的 系统导航栏(包括系统标题、中交三航的logo等)
|
||
main_layout.addWidget(self.system_nav_bar, alignment=Qt.AlignTop)
|
||
|
||
# 相应控件的坐标设置
|
||
self.mixer_widget.move(0, 70) # 搅拌楼坐标
|
||
# self.conveyor_system_widget.move(0, 191)
|
||
self.conveyor_system_widget.move(0, 171) # 传送带系统坐标
|
||
# self.segment_task_widget.move(54, 406)
|
||
self.segment_task_widget.move(54, 382) # 管片任务坐标
|
||
# self.dispatch_task_widget.move(629, 384)
|
||
self.update_dispatch_task_position() # 更新派单任务坐标
|
||
self.update_plan_table_position() # 更新计划表单坐标
|
||
self.update_frequency_button_group_position() # 更新振捣频率选择按钮坐标
|
||
|
||
# 中间的垂直子布局
|
||
sub_v_layout = QVBoxLayout()
|
||
sub_v_layout.setSpacing(0)
|
||
# 依次添加部件到布局(从上到下)
|
||
# sub_v_layout.addWidget(self.status_monitor, alignment=Qt.AlignHCenter)
|
||
sub_v_layout.addSpacerItem(QSpacerItem(
|
||
20, 40, # 最小宽高
|
||
QSizePolicy.Minimum,
|
||
QSizePolicy.Expanding # 垂直方向伸缩,占据剩余空间
|
||
))
|
||
sub_v_layout.addWidget(self.hopper_widget, alignment=Qt.AlignHCenter) # 料斗
|
||
sub_v_layout.addWidget(self.arc_progress, alignment=Qt.AlignHCenter) # 拱形进度条(模具车)
|
||
sub_v_layout.addWidget(self.production_progress, alignment=Qt.AlignHCenter) # 生产进度条
|
||
sub_v_layout.addSpacerItem(QSpacerItem(
|
||
20, 40, # 最小宽高
|
||
QSizePolicy.Minimum,
|
||
QSizePolicy.Expanding # 垂直方向伸缩,占据剩余空间
|
||
))
|
||
# sub_v_layout.addWidget(self.system_button_widget, alignment=Qt.AlignHCenter)
|
||
|
||
# 中间的水平布局
|
||
middle_h_layout = QHBoxLayout()
|
||
# middle_h_layout.setSpacing(20)
|
||
middle_h_layout.setSpacing(0)
|
||
# 1、加入垂直子布局(设置拉伸因子1,让其占满水平剩余空间)
|
||
middle_h_layout.addLayout(sub_v_layout, stretch=1)
|
||
# 2、加入振捣视频控件
|
||
middle_h_layout.addWidget(self.vibration_video, alignment=Qt.AlignCenter)
|
||
|
||
# === 中间子布局 添加到主布局 ===
|
||
main_layout.addLayout(middle_h_layout)
|
||
|
||
# 添加最下方的 控制按钮控件
|
||
main_layout.addWidget(self.bottom_control_widget, alignment=Qt.AlignBottom)
|
||
|
||
# 将布局应用到主窗口
|
||
self.setLayout(main_layout)
|
||
|
||
# 上料斗左移
|
||
def handleHopperMoveLeft(self):
|
||
# 演示效果
|
||
self.hopper_widget.hideUpperHopper()
|
||
self.conveyor_system_widget.showHopper() # 开始向左移动,显示料斗 (此时,料斗一定在传送带上的过渡位置)
|
||
# 按钮状态:点击料斗左移按钮后,禁用料斗右移按钮
|
||
self.conveyor_system_widget.right_btn.setEnabled(False)
|
||
# 以下为模拟:
|
||
# 假设两秒种之后,移动到了搅拌机下 (这里需要根据实际情况修改)
|
||
QTimer.singleShot(2000, self.conveyor_system_widget.moveHopperBelowMixer)
|
||
# 移动到搅拌楼下,搅拌桨就开始旋转
|
||
QTimer.singleShot(2100, self.mixer_widget.startBladeMix)
|
||
# 料斗左移完成,恢复料斗右移按钮
|
||
QTimer.singleShot(2100, lambda: self.conveyor_system_widget.right_btn.setEnabled(True))
|
||
|
||
# 上料斗右移
|
||
def handleHopperMoveRight(self):
|
||
# 演示效果
|
||
self.conveyor_system_widget.moveHopperToTransition() # 移动到过渡的位置
|
||
self.hopper_widget.upper_clamp_widget.set_angle(0) # 上料斗向右移动到目的地时,夹爪的角度一定是0
|
||
# 按钮状态:点击料斗右移按钮后,禁用料斗左移按钮
|
||
self.conveyor_system_widget.left_btn.setEnabled(False)
|
||
|
||
# 开始右移,搅拌桨就停止转动
|
||
self.mixer_widget.stopBladeMix()
|
||
|
||
# 以下为模拟:
|
||
# 假设两秒后,传送带中 料斗向右移动完成 (这里需要根据实际情况修改)
|
||
QTimer.singleShot(1900, self.conveyor_system_widget.hideHopper) # 料斗向右移动完成,隐藏料斗
|
||
QTimer.singleShot(2000, self.hopper_widget.showUpperHopper)
|
||
# 料斗右移完成,恢复料斗左移按钮
|
||
QTimer.singleShot(2100, lambda: self.conveyor_system_widget.left_btn.setEnabled(True))
|
||
|
||
def handleSegmentTaskDetails(self, segment_task_name:str):
|
||
# 管片任务名 task1、task2、task3 (分别对应第一条管片任务、 第二条管片任务...)
|
||
# print("main_window: handleSegmentTaskDetails", segment_task_name)
|
||
if not hasattr(self, "segment_details_dialog"):
|
||
self.segment_details_dialog = SegmentDetailsDialog(self)
|
||
artifact_info:ArtifactInfoModel = self.artifact_dict.get(segment_task_name)
|
||
# 更新管片任务详情按钮弹窗的显示
|
||
self.updateSegmentTaskDetailsDialog(artifact_info)
|
||
# 显示管片任务详情对话框
|
||
self.segment_details_dialog.show()
|
||
# 更新选中的管片任务详情对应的任务名
|
||
self.current_selected_segment_detail_name = segment_task_name
|
||
|
||
def updateSegmentTaskDetailsDialog(self, artifact_info:ArtifactInfoModel):
|
||
if artifact_info and hasattr(self, "segment_details_dialog"):
|
||
# 这里设置管片详情对话框显示的内容 如 set_segment_id
|
||
self.segment_details_dialog.set_segment_id(artifact_info.ArtifactActionID) # 管片ID
|
||
# 设置管片详情界面的左边一列
|
||
self.segment_details_dialog.set_left_value(0, artifact_info.ArtifactID) # 管片编号
|
||
self.segment_details_dialog.set_left_value(1, artifact_info.ArtifactIDVice1) # 管片副标识
|
||
self.segment_details_dialog.set_left_value(2, artifact_info.ProduceRingNumber) # 生产环号
|
||
self.segment_details_dialog.set_left_value(3, artifact_info.MouldCode) # 模具编号
|
||
self.segment_details_dialog.set_left_value(4, artifact_info.SkeletonID) # 骨架编号
|
||
self.segment_details_dialog.set_left_value(5, artifact_info.RingTypeCode) # 环类型编号
|
||
self.segment_details_dialog.set_left_value(6, artifact_info.SizeSpecification) # 尺寸规格
|
||
# 设置管片详情界面的右边一列
|
||
self.segment_details_dialog.set_right_value(0, artifact_info.BlockNumber) # 分块号
|
||
self.segment_details_dialog.set_right_value(1, artifact_info.HoleRingMarking) # 出洞环标记
|
||
self.segment_details_dialog.set_right_value(2, artifact_info.GroutingPipeMarking) # 注浆管标记
|
||
self.segment_details_dialog.set_right_value(3, artifact_info.PolypropyleneFiberMarking) # 聚丙烯纤维标记
|
||
self.segment_details_dialog.set_right_value(4, artifact_info.BetonVolume) # 浇筑方量
|
||
self.segment_details_dialog.set_right_value(5, artifact_info.BetonTaskID) # 任务单号
|
||
self.segment_details_dialog.set_right_value(6, artifact_info.BuriedDepth) # 埋深
|
||
|
||
def handleDispatchTaskDetails(self, dispatch_task_name:str):
|
||
# 派单任务名 task1、task2、task3 (分别对应第一条派单任务、 第二条派单任务...)
|
||
# print("main_window: handleDispatchTaskDetails", dispatch_task_name)
|
||
|
||
# 显示派单任务详情对话框
|
||
if not hasattr(self, "dispatch_details_dialog"):
|
||
self.dispatch_details_dialog = DispatchDetailsDialog(dispatch_task_name, self)
|
||
self.dispatch_details_dialog.confirm_modify_volume.connect(self.handleModifyDispatchTaskVolume)
|
||
pd_record:PDRecordModel = self.dispatch_dict.get(dispatch_task_name)
|
||
|
||
# 这里可以设置对话框显示的内容 如 set_segment_id
|
||
# dispatch_details_dialog.set_segment_id("9999999999")
|
||
# 设置派单任务详情中的方量的值
|
||
# current_volume = self.dispatch_task_widget.get_task_volume(dispatch_task_name)
|
||
# self.dispatch_details_dialog.set_row_value(4, str(current_volume)) # 派单方量的值的行号为4,第五行
|
||
|
||
# 更新选中的派单任务详情对应的任务名
|
||
self.current_selected_dispatch_detail_name = dispatch_task_name
|
||
|
||
# 更新派单任务详情按钮弹窗的显示
|
||
self.updateDispatchTaskDetailsDialog(pd_record)
|
||
|
||
# 派单任务详情页面中确定修改了派单任务的方量
|
||
# 备注:褚工说管片任务和派单任务中的方量都只有一位小数,料斗上的方量显示两位 2025/11/8
|
||
self.dispatch_details_dialog.set_dispatch_task_name(dispatch_task_name) # 更新派单任务名
|
||
self.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)
|
||
|
||
# 其他操作,可能需要修改数据库的派单任务方量
|
||
self.handleDispatchTaskVolumeModified(dispatch_task_name, modifyed_volume)
|
||
|
||
def updateDispatchTaskDetailsDialog(self, pd_record:PDRecordModel):
|
||
"""更新派单详情对话框"""
|
||
if pd_record and hasattr(self, "dispatch_details_dialog"):
|
||
self.dispatch_details_dialog.set_segment_id(pd_record.ArtifactActionID) # 管片ID
|
||
self.dispatch_details_dialog.set_row_value(0, pd_record.CreateTime.split('.')[0] if pd_record.CreateTime else None) # 创建时间 (去掉毫秒)
|
||
self.dispatch_details_dialog.set_row_value(1, pd_record.OptTime.split('.')[0] if pd_record.OptTime else None) # 派单时间 (去掉毫秒)
|
||
self.dispatch_details_dialog.set_row_value(2, pd_record.TaskID) # 任务编号
|
||
self.dispatch_details_dialog.set_row_value(3, pd_record.ProduceMixID) # 生产配合比编号(配比编号)
|
||
self.dispatch_details_dialog.set_row_value(4, pd_record.FBetonVolume) # 派单方量(最终计算出来的实际派单方量)
|
||
|
||
# 派单状态 (1计划中2已下发0未知),默认1
|
||
status_mapping = {
|
||
0: None, # 未知
|
||
1: "计划中",
|
||
2: "派单中", # 已下发 # 付工说改为派单中更好
|
||
3: "已超时",
|
||
4: "未扫码"
|
||
}
|
||
status_text = status_mapping.get(pd_record.Status)
|
||
self.dispatch_details_dialog.set_row_value(5, status_text)
|
||
|
||
if status_text == "计划中": # 只有派单状态为计划中,详情界面才能够修改方量
|
||
self.dispatch_details_dialog.set_modify_volume_status(True)
|
||
else:
|
||
self.dispatch_details_dialog.set_modify_volume_status(False)
|
||
|
||
# 派单模式(1自动派单 2手动派单 0未知 )Mode: int = 0
|
||
mode_mapping = {
|
||
1: "自动派单",
|
||
2: "手动派单",
|
||
0: None # 未知
|
||
}
|
||
mode_text = mode_mapping.get(pd_record.Mode)
|
||
self.dispatch_details_dialog.set_row_value(6, mode_text)
|
||
|
||
def handleDispatchTaskSelected(self, dispatch_task_name:str):
|
||
"""处理派单任务按钮选中, 更新计划表单相关的(计划单号、计划方量等)"""
|
||
pd_record:PDRecordModel = self.dispatch_dict.get(dispatch_task_name) # 根据派单任务名获取派单记录
|
||
self.current_dispatch_task_select_btn_name = dispatch_task_name # 更新派单任务选择按钮对应的任务名
|
||
self.updatePlanTableWidget(pd_record) # 更新计划表单
|
||
|
||
def handleDispatchTaskVolumeModified(self, dispatch_task_name:str, final_volume:float):
|
||
"""处理派单任务方量修改"""
|
||
pd_record:PDRecordModel = self.dispatch_dict.get(dispatch_task_name)
|
||
if pd_record:
|
||
volume_dict = {
|
||
"ID": pd_record.ID,
|
||
"ArtifactActionID": pd_record.ArtifactActionID,
|
||
"Volume": final_volume
|
||
}
|
||
volume_json_str = json.dumps(volume_dict, ensure_ascii=False)
|
||
# print("volume_json_str: ", volume_json_str)
|
||
self.plan_volume_modified_signal.emit(volume_json_str)
|
||
|
||
def updatePlanTableWidget(self, pd_record:PDRecordModel):
|
||
"""更新计划表单"""
|
||
def format_plan_number(num):
|
||
# 格式化计划单号
|
||
# 保留最后5位,再补零
|
||
remainder = num % 100000
|
||
return f"{remainder:05d}"
|
||
|
||
if pd_record and hasattr(self, "plan_table_widget"):
|
||
plan_number = format_plan_number(pd_record.ID) # 计划单号
|
||
self.plan_table_widget.set_plan_no(f"PD{plan_number}") # 更新计划表单的计划单号 (PD+表单ID)
|
||
self.plan_table_widget.set_plan_volume(pd_record.FBetonVolume) # 更新计划表单的计划方量
|
||
self.plan_table_widget.set_plan_ratio(pd_record.ProduceMixID) # 更新计划表单的计划配比
|
||
# 派单模式(1自动派单 2手动派单 0未知 )Mode: int = 0
|
||
status_mapping = {
|
||
0: "", # 未知
|
||
1: "计划中",
|
||
2: "派单中", # 已下发 # 付工说改为派单中更好
|
||
3: "已超时",
|
||
4: "未扫码"
|
||
}
|
||
status_text = status_mapping.get(pd_record.Status)
|
||
self.plan_table_widget.set_status(status_text)
|
||
|
||
if status_text == "计划中": # 计划表单只有派单状态为计划中,才能够修改方量
|
||
self.plan_table_widget.set_modify_volume_status(True)
|
||
else:
|
||
self.plan_table_widget.set_modify_volume_status(False)
|
||
|
||
# 更新计划表单对应的任务名
|
||
self.plan_table_widget.set_plan_table_task_name(self.current_dispatch_task_select_btn_name)
|
||
|
||
# 更新 派单任务widget的坐标
|
||
def update_dispatch_task_position(self):
|
||
# 方法1:获取模具车控件左上角坐标(相对于父控件)
|
||
arc_pos = self.arc_progress.pos()
|
||
# print(f"料斗控件左上角坐标(相对父控件):x={arc_pos.x()}, y={arc_pos.y()}")
|
||
|
||
# x+462, y-249
|
||
self.dispatch_task_widget.move(arc_pos.x()+462, arc_pos.y()-249)
|
||
# print("update_dispatch_task_position", arc_pos.x()+462, arc_pos.y()-241)
|
||
|
||
# 更新 计划表单widget的坐标
|
||
def update_plan_table_position(self):
|
||
# 方法1:获取料斗控件左上角坐标(相对于父控件)
|
||
hopper_pos = self.hopper_widget.pos()
|
||
# print(f"料斗控件左上角坐标(相对父控件):x={arc_pos.x()}, y={arc_pos.y()}")
|
||
|
||
# x+462, y-249
|
||
self.plan_table_widget.move(hopper_pos.x()+362, hopper_pos.y()+40)
|
||
|
||
def update_frequency_button_group_position(self):
|
||
# 方法1:获取模具车控件左上角坐标(相对于父控件)
|
||
arc_pos = self.arc_progress.pos()
|
||
|
||
self.frequency_button_group.move(arc_pos.x()+572, arc_pos.y() + 125)
|
||
|
||
def update_background(self):
|
||
"""更新主界面背景图片"""
|
||
if self.background_image and not self.background_image.isNull():
|
||
palette = self.palette()
|
||
# 按当前窗口尺寸缩放图片
|
||
scaled_image = self.background_image.scaled(
|
||
self.size(),
|
||
Qt.IgnoreAspectRatio,
|
||
Qt.SmoothTransformation
|
||
)
|
||
palette.setBrush(QPalette.Window, QBrush(scaled_image))
|
||
self.setPalette(palette)
|
||
self.setAutoFillBackground(True)
|
||
|
||
def eventFilter(self, watched, event):
|
||
"""过滤鼠标点击事件, 让计划方量的QLineEdit在鼠标点击外部时失去焦点"""
|
||
# 只处理鼠标左键点击事件
|
||
if event.type() == QEvent.MouseButtonPress and event.button() == Qt.LeftButton:
|
||
# 获取当前拥有焦点的控件
|
||
focus_widget = QApplication.focusWidget()
|
||
# 判断焦点是否在QLineEdit上
|
||
if isinstance(focus_widget, QLineEdit):
|
||
# 将全局鼠标位置转换为焦点控件(QLineEdit)的局部坐标
|
||
local_pos = focus_widget.mapFromGlobal(event.globalPos())
|
||
# 若点击位置不在QLineEdit内部,则清除焦点
|
||
if not focus_widget.rect().contains(local_pos):
|
||
focus_widget.clearFocus()
|
||
# 将焦点转移到主窗口,避免无焦点状态
|
||
self.setFocus()
|
||
return super().eventFilter(watched, event)
|
||
|
||
def resizeEvent(self, e):
|
||
"""窗口大小变化时的回调"""
|
||
super().resizeEvent(e)
|
||
self.update_background() # 重新加载背景图片
|
||
self.update_dispatch_task_position() # 更新 派单任务的坐标
|
||
self.update_plan_table_position() # 更新计划表单坐标
|
||
self.update_frequency_button_group_position() # 更新振捣频率按钮坐标
|
||
|
||
def closeEvent(self, e):
|
||
"""窗口关闭时的回调"""
|
||
self.hide() # 隐藏界面
|
||
self.about_to_close.emit()
|
||
super().closeEvent(e)
|
||
|
||
def keyPressEvent(self, event):
|
||
if event.key() == Qt.Key_Escape: # 按下Esc键, 退出界面
|
||
self.close()
|
||
super().keyPressEvent(event)
|
||
|
||
# ======= 设置管片任务详情接口 ==========
|
||
# self.artifact_dict 管片信息的字典
|
||
def SetSegmentTaskDetails(self, task_name:str, artifact_info:ArtifactInfoModel):
|
||
self.artifact_dict[task_name] = artifact_info
|
||
if hasattr(self, "segment_details_dialog") and self.segment_details_dialog and self.segment_details_dialog.isVisible():
|
||
if task_name == self.current_selected_segment_detail_name:
|
||
self.updateSegmentTaskDetailsDialog(artifact_info) # 刷新管片任务详情按钮弹窗
|
||
|
||
# ======= 设置派单任务接口 ==========
|
||
# self.dispatch_dict 派单信息的字典
|
||
def SetPDRecordTask(self, task_name:str, pd_record:PDRecordModel):
|
||
self.dispatch_dict[task_name] = pd_record
|
||
if hasattr(self, "dispatch_details_dialog") and self.dispatch_details_dialog and self.dispatch_details_dialog.isVisible():
|
||
if task_name == self.current_selected_dispatch_detail_name:
|
||
self.updateDispatchTaskDetailsDialog(pd_record) # 刷新派单任务详情按钮弹窗
|
||
if hasattr(self, "plan_table_widget") and task_name == self.current_dispatch_task_select_btn_name:
|
||
self.updatePlanTableWidget(pd_record) # 刷新计划表单
|
||
|
||
if __name__ == "__main__":
|
||
import sys
|
||
app = QApplication([])
|
||
window = MainWindow()
|
||
window.show()
|
||
sys.exit(app.exec())
|