add(派单任务和管片任务的刷新)

This commit is contained in:
yaj
2026-03-06 18:33:58 +08:00
parent 37d60ba63e
commit a3b6287808
9 changed files with 393 additions and 42 deletions

View File

@ -10,9 +10,9 @@ interval_days = 10
# 方量调节控件最小值
min = 0.0
# 方量调节控件最大值
max = 99.0
max = 2.4
# 方量调节控件初始值
initial = 2.5
initial = 1.9

View File

@ -14,9 +14,15 @@ sub_interval = 500
[OPC_NODE_LIST]
upper_weight = 2:upper,2:upper_weight
lower_weight = 2:lower,2:lower_weight
upper_hopper_position = 2:upper,2:upper_hopper_position
upper_clamp_status = 2:upper,2:upper_clamp_status
vibration_frequency=2:vibration_frequency
production_progress=2:production_progress
segment_tasks=2:segment_tasks
dispatch_tasks=2:dispatch_tasks
; ; upper_hopper_position = 2:upper,2:upper_hopper_position
; upper_clamp_status = 2:upper,2:upper_clamp_status
; production_progress=2:production_progress
; segment_tasks=2:segment_tasks
; dispatch_tasks=2:dispatch_tasks
segment_tasks=2:sys,2:segment_refresh
dispatch_tasks=2:sys,2:pd_refresh
mould_vibrate_status=2:mould,2:mould_vibrate_status
vibration_frequency=2:mould,2:mould_frequency
mould_finish_weight=2:mould,2:mould_finish_weight
pd_mode=2:pd,2:set_mode
pd_plan_volume=2:pd,2:set_volume

View File

@ -4,7 +4,7 @@ from view.widgets.system_center_dialog import SystemCenterDialog
from view.widgets.bottom_control_widget import BottomControlWidget
from view.widgets.system_diagnostics_dialog import SystemDiagnosticsDialog
from view.widgets.message_popup_widget import MessagePopupWidget
from view.main_window import MainWindow
from service.msg_recorder import MessageRecorder
from service.msg_query_thread import MsgQueryThread
@ -16,7 +16,7 @@ from service.monitor_thread import MonitorThread
"""
class BottomControlController:
def __init__(self, bottom_control_widget:BottomControlWidget, main_window):
def __init__(self, bottom_control_widget:BottomControlWidget, main_window:MainWindow):
self.bottom_control_widget = bottom_control_widget
self.main_window = main_window
@ -25,7 +25,7 @@ class BottomControlController:
self.diagnostics_device_row = 0 # 系统诊断弹窗的设备检测行号从0开始
self.diagnostics_device_col = 0 # 系统诊断弹窗的设备检测列号从0开始
self.diagnostics_service_row = 0 # 系统诊断弹窗的服务检测行号从0开始
self.diagnostics_service_col = 2 # 系统诊断弹窗的服务检测从2开始
self.diagnostics_service_col = 2 # 系统诊断弹窗的服务检测从2开始
# 系统中心弹窗
self.system_center_dialog = SystemCenterDialog(self.main_window)
@ -211,8 +211,17 @@ class BottomControlController:
self.system_diagnostics_dialog.set_ms_value(row, col, delay)
if delay <= self.device_monitor.warning_delay:
self.system_diagnostics_dialog.set_circle_status(row, col, "normal")
# 设置上料斗或者下料斗的设备状态(主界面的上料斗、下料斗控件中)
if device_name == "上料斗":
self.main_window.hopper_widget.setUpperHopperStatus(0)
elif device_name == "下料斗":
self.main_window.hopper_widget.setLowerHopperStatus(0)
else:
self.system_diagnostics_dialog.set_circle_status(row, col, "warning")
if device_name == "上料斗":
self.main_window.hopper_widget.setUpperHopperStatus(1)
elif device_name == "下料斗":
self.main_window.hopper_widget.setLowerHopperStatus(1)
# 显示检测组件
self.system_diagnostics_dialog.set_selected_show(row, col)
@ -225,6 +234,11 @@ class BottomControlController:
self.system_diagnostics_dialog.set_circle_status(row, col, "error")
# 显示检测组件
self.system_diagnostics_dialog.set_selected_show(row, col)
# 设置上料斗或者下料斗的设备状态(主界面的上料斗、下料斗控件中)
if device_name == "上料斗":
self.main_window.hopper_widget.setUpperHopperStatus(2)
elif device_name == "下料斗":
self.main_window.hopper_widget.setLowerHopperStatus(2)
def _get_diagnostics_service_row_col(self):
"""获取系统诊断弹窗中 服务检测的 行号 和 列号"""

View File

@ -80,6 +80,11 @@ class MainController:
self.opc_client.opc_signal.opc_log.connect(self.msg_recorder.normal_record, Qt.QueuedConnection) # opcua客户端日志
# 主界面的计划表单自动派单控制
self.main_window.plan_table_widget.auto_dispatch_signal.connect(self.handlePlanTableAutoDispatch) # 计划表单的自动派单切换
# 主界面的计划表单中的计划方量修改控制
self.main_window.plan_volume_modified_signal.connect(self.handleVolumeModified) # 计划方量修改
def handleMainWindowClose(self):
"""主界面关闭"""
@ -92,6 +97,19 @@ class MainController:
if hasattr(self, 'opc_client'):
self.opc_client.stop_run()
def handlePlanTableAutoDispatch(self, auto_status:bool):
"""处理计划表单的 自动派单和手动派单的切换
pd_mode: 1,自动派单 2,手动派单
"""
if auto_status: # 自动派单
self.opc_client.write_value_by_name("pd_mode", 1)
else: # 手动派单
self.opc_client.write_value_by_name("pd_mode", 2)
def handleVolumeModified(self, volume_json_str:str):
"""处理 修改方量 (计划表单中 和 派单详情中)"""
self.opc_client.write_value_by_name("pd_plan_volume", volume_json_str)
def start_msg_database_clean_task(self):
"""启动清理消息数据库(messages.db)中过期消息的定时任务"""
from PySide6.QtCore import QTimer, QDateTime, QDate, QTime
@ -239,4 +257,35 @@ class MainController:
def _update_vibration_frequency(self, val):
# 更新振捣频率
self.main_window.frequency_button_group.set_selected_frequency(val)
self.main_window.frequency_button_group.set_selected_frequency(val) # 频率选择按钮上显示的选中的频率
self.main_window.arc_progress.setFrequency(val) # 模具车上显示的振捣频率
def _update_mould_vibrate_status(self, vibrate_status:bool):
# 更新模具车上显示的振捣状态
# vibrate_status: False:未振捣、True:振捣中
if vibrate_status:
self.main_window.arc_progress.setState("振捣中")
else:
self.main_window.arc_progress.setState("未振捣")
self.opc_client.write_value_by_name("vibration_frequency", 0) # 将振捣频率设置为0
def _update_mould_finish_weight(self, finish_weight:int):
# 更新模具车中的下料重量
# finish_weight已下料重量
self.main_window.arc_progress.setWeight(finish_weight)
def _update_pd_mode(self, mode:int):
# 更新计划表单中的 派单模式(主界面下发状态的下面的切换开关),自动派单/手动派单
mode_mapping = {
1: "自动派单",
2: "手动派单",
0: None # 未知
}
mode_text = mode_mapping.get(mode)
if mode_text == "自动派单":
# 设置主界面下发状态的下面的切换开关
self.main_window.plan_table_widget.set_auto_dispatch(True) # 开启,自动派单
# 修改系统配置文件中的 派单状态为自动派单...
else:
self.main_window.plan_table_widget.set_auto_dispatch(False) # 关闭,手动派单
# 修改系统配置文件中的 派单状态为手动派单...

View File

@ -27,12 +27,16 @@ 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()
@ -45,6 +49,9 @@ class MainWindow(QWidget):
# 安装事件过滤器,处理计划方量的 QLineEdit的失去焦点事件
self.installEventFilter(self)
# 初始化派单任务控件
self.dispatch_task_widget.set_task_select_btn_selected("task2") # 派单任务控件,初始化选中第二条派单任务
# 连接槽函数
def connectSignalToSlot(self):
# 可添加信号槽连接
@ -61,6 +68,11 @@ class MainWindow(QWidget):
# 派单任务详情
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):
# 测试系统开启,进度条动画
@ -109,6 +121,8 @@ class MainWindow(QWidget):
self.dispatch_dict = {}
# 当前点击/选中的 派单任务详情对应的任务名(task1\task2\task3) (用于刷新选中的派单任务详情)
self.current_selected_dispatch_detail_name = None
# 当前点击/选中的 派单任务选择按钮对应的任务名 (用于刷新 计划表单)
self.current_dispatch_task_select_btn_name = None
def createSubWidgets(self):
"""创建所有子部件实例"""
@ -177,7 +191,21 @@ class MainWindow(QWidget):
def update_segment_tasks(self, artifact_list:List[ArtifactInfoModel]):
# 更新管片任务相关的信息
# 遍历数据并更新UI (包括左侧的管片任务 以及 管片任务详情)
for index, artifact in enumerate(artifact_list, 1):
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: # 更新浇筑方量
@ -185,6 +213,14 @@ class MainWindow(QWidget):
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):
@ -202,14 +238,60 @@ class MainWindow(QWidget):
def update_dispatch_tasks(self, pdrecord_list:List[PDRecordModel]):
# 更新派单任务相关的信息
# 遍历数据并更新UI
for index, record in enumerate(pdrecord_list, 1):
if record.MouldCode: # 更新模具号
self.dispatch_task_widget.set_task_id(f"task{index}", record.MouldCode)
if record.BetonVolume: # 更新方量(派单方量[最终计算出来的派单方量])
self.dispatch_task_widget.set_task_volume(f"task{index}", record.FBetonVolume)
if record.CreateTime: # 更新时间 (派单任务的创建时间)
self.dispatch_task_widget.set_task_time(f"task{index}", self.convert_to_ampm(record.CreateTime))
self.SetPDRecordTaskDetails(f"task{index}", record)
# 倒着查,过滤掉 搅拌生产状态不是 未知的,
# 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):
"""设置垂直布局,从上到下排列部件"""
@ -344,6 +426,7 @@ class MainWindow(QWidget):
# 显示派单任务详情对话框
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
@ -351,25 +434,28 @@ class MainWindow(QWidget):
# 设置派单任务详情中的方量的值
# 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.confirm_modify_volume.connect(self.handleModifyDispatchTaskVolume)
self.dispatch_details_dialog.set_dispatch_task_name(dispatch_task_name) # 更新派单任务名
self.dispatch_details_dialog.show()
# 更新选中的派单任务详情对应的任务名
self.current_selected_dispatch_detail_name = dispatch_task_name
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) # 创建时间 (去掉毫秒)
@ -380,13 +466,20 @@ class MainWindow(QWidget):
# 派单状态 1计划中2已下发0未知)默认1
status_mapping = {
0: None, # 未知
1: "计划中",
2: "已下发",
0: None # 未知
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: "自动派单",
@ -395,7 +488,57 @@ class MainWindow(QWidget):
}
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):
@ -480,13 +623,15 @@ class MainWindow(QWidget):
if task_name == self.current_selected_segment_detail_name:
self.updateSegmentTaskDetailsDialog(artifact_info) # 刷新管片任务详情按钮弹窗
# ======= 设置派单任务详情接口 ==========
# ======= 设置派单任务接口 ==========
# self.dispatch_dict 派单信息的字典
def SetPDRecordTaskDetails(self, task_name:str, pd_record:PDRecordModel):
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

View File

@ -278,6 +278,14 @@ class ArcProgressWidget(QWidget):
# 管片编号设置
def setSegmentNumber(self, segmentNumberStr:str):
self.segment_number_label.setText(segmentNumberStr)
# 环号设置
def setRingNumber(self, ringNumber:int):
self.ring_number_label.setText(f"环号: {ringNumber}")
# 管片尺寸(规格)设置 比如6900*1500
def setSegmentSize(self, SizeSpecification:str):
self.segment_size_label.setText(SizeSpecification)
if __name__ == "__main__":

View File

@ -337,10 +337,10 @@ class DispatchDetailsDialog(QDialog):
self.modify_btn.show()
# 2、修改 派单方量标签的值
volume_label = self.rows[4].value
# volume_label = self.rows[4].value
# modifyed_value 为float类型, 一位小数
modifyed_value = self.volume_value_adjuster.get_value()
volume_label.setText(str(modifyed_value))
# volume_label.setText(str(modifyed_value))
# 3、发送派单方量确定修改的信号 (发送派单任务名 + 确认修改之后的派单方量)
self.confirm_modify_volume.emit(self.dispatch_task_name, modifyed_value)
@ -383,6 +383,16 @@ class DispatchDetailsDialog(QDialog):
if 0 <= row < len(self.rows):
self.rows[row].value.setText(str(new_value_text) if new_value_text is not None else "")
def set_dispatch_task_name(self, task_name:str):
"""设置/刷新 派单任务名"""
self.dispatch_task_name = task_name
def set_modify_volume_status(self, status:bool):
"""设置是否能够在派单详情界面修改方量,
status为False即不能修改方量, 为True表示能够修改方量
"""
self.modify_btn.setVisible(status)
# 测试代码
if __name__ == "__main__":

View File

@ -1,6 +1,6 @@
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QApplication)
from PySide6.QtCore import Qt
from PySide6.QtCore import Qt, Signal, QTimer
from PySide6.QtGui import QPainter, QPixmap
from .value_adjuster import ValueAdjuster
from .switch_button import SwitchButton
@ -10,6 +10,14 @@ import resources.resources_rc
from utils.image_paths import ImagePaths
class PlanWidget(QWidget):
# 自动派单切换信号
# True: 自动派单 False: 手动派单
auto_dispatch_signal = Signal(bool)
# 计划表单最终的确认的修改的方量
# 对应的任务名, 最终的方量
final_modify_volume_signal = Signal(str, float)
def __init__(self, parent=None):
super().__init__(parent)
# 加载背景图
@ -25,6 +33,16 @@ class PlanWidget(QWidget):
"auto_dispatch": None # 自动派单SwitchButton
}
# ==================================================
# 用于计划表单的修改方量的最终确认
# 1、确认最终修改的方量的计时器超时代表着确认了最终的方量
self.volume_timer = QTimer(self)
self.volume_timer.setInterval(2500) # 2.5秒延迟(根据需求调整)
self.volume_timer.setSingleShot(True) # 单次触发:避免重复执行
self.volume_timer.timeout.connect(self._sync_final_volume)
# 2、该计划表单对应的任务名
self.plan_table_task_name = None
# 主垂直布局
main_layout = QVBoxLayout(self)
main_layout.setContentsMargins(13, 5, 6, 15)
@ -63,6 +81,8 @@ class PlanWidget(QWidget):
row2_layout.addWidget(label2)
self.fangliang_adjuster = ValueAdjuster() # 导入的方量调整控件
self.fangliang_adjuster.minus_btn.clicked.connect(self._reset_volume_timer)
self.fangliang_adjuster.plus_btn.clicked.connect(self._reset_volume_timer)
row2_layout.addWidget(self.fangliang_adjuster)
main_layout.addLayout(row2_layout)
self.controls["volume"] = self.fangliang_adjuster
@ -75,7 +95,7 @@ class PlanWidget(QWidget):
row3_layout.addWidget(status_icon3)
row3_layout.addSpacing(4)
label3 = QLabel("计划配比")
label3 = QLabel("")
label3.setStyleSheet("font-size: 18px; color: #03f5ff;")
row3_layout.addWidget(label3)
@ -117,11 +137,24 @@ class PlanWidget(QWidget):
row5_layout.addWidget(label5)
self.switch = SwitchButton()
self.switch.switched.connect(self.auto_dispatch_signal)
self.switch.setChecked(True)
row5_layout.addWidget(self.switch, alignment=Qt.AlignLeft)
main_layout.addLayout(row5_layout)
self.controls["auto_dispatch"] = self.switch
def _reset_volume_timer(self):
"""每次调整方量时,重置定时器(倒计时重新开始)"""
if self.volume_timer.isActive(): # 如果定时器正在运行,先停止
self.volume_timer.stop()
self.volume_timer.start() # 重启定时器
def _sync_final_volume(self):
"""同步 确认的最终的修改方量"""
final_volume = self.fangliang_adjuster.get_value()
# print("最终确认的方量为:", final_volume)
self.final_modify_volume_signal.emit(self.plan_table_task_name, final_volume)
def paintEvent(self, event):
"""绘制背景图片"""
painter = QPainter(self)
@ -150,10 +183,21 @@ class PlanWidget(QWidget):
self.controls["status"].setText(new_status)
def set_auto_dispatch(self, is_checked:bool):
"""修改自动派单开关状态, true: 开启自动派单, False: 关闭自动派单"""
"""修改自动派单开关状态, true: 自动派单, False: 动派单"""
if self.controls["auto_dispatch"]:
self.controls["auto_dispatch"].setChecked(is_checked)
def set_modify_volume_status(self, status:bool):
"""设置 计划表单中修改方量控件的状态, 是否能够修改方量
status: True, 能够修改方量
False, 不能修改方量
"""
self.fangliang_adjuster.setEnabled(status)
def set_plan_table_task_name(self, task_name:str):
"""设置 计划表单对应的选中任务名"""
self.plan_table_task_name = task_name
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = PlanWidget()

View File

@ -11,8 +11,10 @@ from utils.image_paths import ImagePaths
任务控件,如:管片任务、派单任务
"""
class TaskWidget(QWidget):
# 任务详情信号: task1表示第一条任务
# 任务详情信号: task1表示第一条任务 (用于详情对话框)
task_details_signal = Signal(str)
# 任务选择按钮选中的信号 (用于上方的计划表单)
task_selected_signal = Signal(str)
def __init__(self, taskTitle:str, parent=None):
super().__init__(parent)
@ -40,6 +42,7 @@ class TaskWidget(QWidget):
# 用字典存储每个任务的可修改控件(键:任务名,值:控件字典)
self.task_controls = {} # 结构:{"task1": {"volume_label": xxx, "time_label": xxx, ...}, ...}
self.current_selected_task = None # 选择按钮,当前选中的任务的任务名
# 三条任务条目
self._add_task("task1", "SHRB1-3", ImagePaths.TASK_RECT1)
@ -87,12 +90,17 @@ class TaskWidget(QWidget):
}}
""")
select_btn.setCheckable(True)
select_btn.clicked.connect(lambda checked, tn=task_name: self._on_select_btn_clicked(tn, checked))
controls["select_btn"] = select_btn
row1_layout.addWidget(select_btn)
# 任务编号
task_id_label = QLabel(task_id)
task_id_label.setStyleSheet("font-size: 18px; color: #16ffff;padding-left: 6px;")
# 1. 设置鼠标样式为手型,提示可点击
task_id_label.setCursor(Qt.PointingHandCursor)
# 2. 绑定点击事件点击标签时选中对应的select_btn
task_id_label.mousePressEvent = lambda event, tn=task_name: self._on_task_id_clicked(tn)
controls["task_id_label"] = task_id_label
row1_layout.addWidget(task_id_label)
@ -124,7 +132,7 @@ class TaskWidget(QWidget):
row2_layout = QHBoxLayout()
# 方量标签
volume_label = QLabel("方量 200")
volume_label.setStyleSheet("color: #a1c1d7; font-size: 14px;padding-left: 19px;")
volume_label.setStyleSheet("color: #a1c1d7; font-size: 14px;padding-left: 6px;")
controls["volume_label"] = volume_label
row2_layout.addWidget(volume_label)
@ -138,13 +146,19 @@ class TaskWidget(QWidget):
time_label.setStyleSheet("color: #a1c1d7; font-size: 14px;")
controls["time_label"] = time_label
row2_layout.addWidget(time_label)
# 状态文本标签
status_text_label = QLabel()
status_text_label.setStyleSheet("color: #16ffff; font-size: 14px;")
controls["status_text_label"] = status_text_label
row2_layout.addWidget(status_text_label)
# 状态标签
# 状态图标标签
status_icon_label = QLabel()
status_icon_label.setPixmap(QPixmap(status_icon))
controls["status_icon_label"] = status_icon_label
row2_layout.addWidget(status_icon_label, alignment=Qt.AlignRight)
# 添加水平布局2到item_layout
item_layout.addLayout(row2_layout)
# 分隔线
@ -165,6 +179,42 @@ class TaskWidget(QWidget):
# 发送任务详情信号
self.task_details_signal.emit(task_name)
def _on_select_btn_clicked(self, task_name: str, checked: bool):
"""
处理选择按钮点击事件,实现互斥选中
:param task_name: 点击的任务名task1/task2/task3
:param checked: 按钮是否被选中True/False
"""
# 1. 如果是选中操作checked=True
if checked:
# 取消之前选中的任务按钮
if self.current_selected_task and self.current_selected_task != task_name:
prev_select_btn = self.task_controls[self.current_selected_task]["select_btn"]
prev_select_btn.setChecked(False) # 取消选中
# 更新当前选中的任务
self.current_selected_task = task_name
# 通知任务选中按钮更新了选中
self.task_selected_signal.emit(task_name)
else:
# 2. 如果是取消选中操作checked=False
# 重新设为选中状态,阻止取消 (确保该按钮继续为选中状态,保证至少有一个按钮被选中)
current_select_btn = self.task_controls[task_name]["select_btn"]
current_select_btn.setChecked(True)
# 确保选中标记不丢失
self.current_selected_task = task_name
def _on_task_id_clicked(self, task_name: str):
"""
点击任务编号标签时,选中对应的选择按钮(复用互斥逻辑)
:param task_name: 点击的任务名task1/task2/task3
"""
if task_name in self.task_controls:
# 1. 获取对应select_btn
select_btn = self.task_controls[task_name]["select_btn"]
# 2. 模拟点击相应的选择按钮
if not select_btn.isChecked():
select_btn.click()
# --------------------------
# 对外接口:修改任务属性
# 三个任务条目对应的任务名task_name分别为 task1、task2、task3
@ -185,11 +235,36 @@ class TaskWidget(QWidget):
time_label = self.task_controls[task_name]["time_label"]
time_label.setText(time_str)
def set_task_status(self, task_name:str, status_str: str, icon_path:str):
"""修改指定任务的状态, 比如: 已下发、计划中等"""
ICON_COLOR_MAP = {
ImagePaths.TASK_RECT1: "#16ffff",
ImagePaths.TASK_RECT2: "#ffab11",
ImagePaths.TASK_RECT3: "#54f529",
ImagePaths.TASK_RECT4: "#ff6a5c",
ImagePaths.TASK_RECT5: "#f6f44b"
}
DEFAULT_COLOR = "#000000"
if task_name in self.task_controls:
status_label = self.task_controls[task_name]["status_text_label"] # 状态文本
status_label.setText(status_str)
icon_label = self.task_controls[task_name]["status_icon_label"] # 状态图标
icon_label.setPixmap(QPixmap(icon_path))
# 修改状态文本的颜色
status_text_color = ICON_COLOR_MAP.get(icon_path, DEFAULT_COLOR)
status_label.setStyleSheet(f"QLabel {{ color: {status_text_color}; font-size: 14px;}}")
def set_task_id(self, task_name:str, new_id: str):
"""修改指定任务的编号, 如: SHRB2-3"""
if task_name in self.task_controls:
task_id_label = self.task_controls[task_name]["task_id_label"]
task_id_label.setText(new_id)
task_id_label.setText(new_id)
def set_task_select_btn_selected(self, task_name:str):
"""设置 任务选择按钮选中 (主要用于刷新计划表单)"""
if task_name in self.task_controls:
task_select_btn = self.task_controls[task_name]["select_btn"]
task_select_btn.click()
def get_task_volume(self, task_name:str):
"""