diff --git a/API/__pycache__/__init__.cpython-312.pyc b/API/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..1d63abf
Binary files /dev/null and b/API/__pycache__/__init__.cpython-312.pyc differ
diff --git a/API/__pycache__/client.cpython-312.pyc b/API/__pycache__/client.cpython-312.pyc
new file mode 100644
index 0000000..2a48fec
Binary files /dev/null and b/API/__pycache__/client.cpython-312.pyc differ
diff --git a/API/__pycache__/mix_weight_api.cpython-312.pyc b/API/__pycache__/mix_weight_api.cpython-312.pyc
new file mode 100644
index 0000000..b00c8db
Binary files /dev/null and b/API/__pycache__/mix_weight_api.cpython-312.pyc differ
diff --git a/config/__pycache__/__init__.cpython-312.pyc b/config/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..2e4a46d
Binary files /dev/null and b/config/__pycache__/__init__.cpython-312.pyc differ
diff --git a/config/__pycache__/settings.cpython-312.pyc b/config/__pycache__/settings.cpython-312.pyc
new file mode 100644
index 0000000..3801a47
Binary files /dev/null and b/config/__pycache__/settings.cpython-312.pyc differ
diff --git a/database/__pycache__/__init__.cpython-312.pyc b/database/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..87ebc67
Binary files /dev/null and b/database/__pycache__/__init__.cpython-312.pyc differ
diff --git a/database/__pycache__/access_db.cpython-312.pyc b/database/__pycache__/access_db.cpython-312.pyc
new file mode 100644
index 0000000..4f32551
Binary files /dev/null and b/database/__pycache__/access_db.cpython-312.pyc differ
diff --git a/database/__pycache__/sql_server.cpython-312.pyc b/database/__pycache__/sql_server.cpython-312.pyc
new file mode 100644
index 0000000..d55cedc
Binary files /dev/null and b/database/__pycache__/sql_server.cpython-312.pyc differ
diff --git a/database/__pycache__/sql_server_connection.cpython-312.pyc b/database/__pycache__/sql_server_connection.cpython-312.pyc
new file mode 100644
index 0000000..a546da8
Binary files /dev/null and b/database/__pycache__/sql_server_connection.cpython-312.pyc differ
diff --git a/services/__pycache__/__init__.cpython-312.pyc b/services/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..cb1b2e3
Binary files /dev/null and b/services/__pycache__/__init__.cpython-312.pyc differ
diff --git a/services/__pycache__/monitoring_service.cpython-312.pyc b/services/__pycache__/monitoring_service.cpython-312.pyc
new file mode 100644
index 0000000..856b1f0
Binary files /dev/null and b/services/__pycache__/monitoring_service.cpython-312.pyc differ
diff --git a/services/__pycache__/task_service.cpython-312.pyc b/services/__pycache__/task_service.cpython-312.pyc
new file mode 100644
index 0000000..144beb4
Binary files /dev/null and b/services/__pycache__/task_service.cpython-312.pyc differ
diff --git a/tcp/__pycache__/__init__.cpython-312.pyc b/tcp/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..5b8f9e1
Binary files /dev/null and b/tcp/__pycache__/__init__.cpython-312.pyc differ
diff --git a/tcp/__pycache__/server.cpython-312.pyc b/tcp/__pycache__/server.cpython-312.pyc
new file mode 100644
index 0000000..37bdc4b
Binary files /dev/null and b/tcp/__pycache__/server.cpython-312.pyc differ
diff --git a/utils/__pycache__/__init__.cpython-312.pyc b/utils/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..cfa42e7
Binary files /dev/null and b/utils/__pycache__/__init__.cpython-312.pyc differ
diff --git a/utils/__pycache__/helpers.cpython-312.pyc b/utils/__pycache__/helpers.cpython-312.pyc
new file mode 100644
index 0000000..f0a69b7
Binary files /dev/null and b/utils/__pycache__/helpers.cpython-312.pyc differ
diff --git a/zjsh_mixing_sysytem/.idea/.gitignore b/zjsh_mixing_sysytem/.idea/.gitignore
new file mode 100644
index 0000000..359bb53
--- /dev/null
+++ b/zjsh_mixing_sysytem/.idea/.gitignore
@@ -0,0 +1,3 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
diff --git a/zjsh_mixing_sysytem/.idea/inspectionProfiles/Project_Default.xml b/zjsh_mixing_sysytem/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..78dfc6d
--- /dev/null
+++ b/zjsh_mixing_sysytem/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zjsh_mixing_sysytem/.idea/inspectionProfiles/profiles_settings.xml b/zjsh_mixing_sysytem/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/zjsh_mixing_sysytem/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zjsh_mixing_sysytem/.idea/misc.xml b/zjsh_mixing_sysytem/.idea/misc.xml
new file mode 100644
index 0000000..62ef35e
--- /dev/null
+++ b/zjsh_mixing_sysytem/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zjsh_mixing_sysytem/.idea/modules.xml b/zjsh_mixing_sysytem/.idea/modules.xml
new file mode 100644
index 0000000..56ad756
--- /dev/null
+++ b/zjsh_mixing_sysytem/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zjsh_mixing_sysytem/.idea/中交三航背景界面.iml b/zjsh_mixing_sysytem/.idea/中交三航背景界面.iml
new file mode 100644
index 0000000..53e58ed
--- /dev/null
+++ b/zjsh_mixing_sysytem/.idea/中交三航背景界面.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zjsh_mixing_sysytem/__pycache__/bottom_control_widget.cpython-312.pyc b/zjsh_mixing_sysytem/__pycache__/bottom_control_widget.cpython-312.pyc
new file mode 100644
index 0000000..fb90395
Binary files /dev/null and b/zjsh_mixing_sysytem/__pycache__/bottom_control_widget.cpython-312.pyc differ
diff --git a/zjsh_mixing_sysytem/__pycache__/bottom_control_widget.cpython-39.pyc b/zjsh_mixing_sysytem/__pycache__/bottom_control_widget.cpython-39.pyc
new file mode 100644
index 0000000..cb173e4
Binary files /dev/null and b/zjsh_mixing_sysytem/__pycache__/bottom_control_widget.cpython-39.pyc differ
diff --git a/zjsh_mixing_sysytem/__pycache__/dispatch_task.cpython-312.pyc b/zjsh_mixing_sysytem/__pycache__/dispatch_task.cpython-312.pyc
new file mode 100644
index 0000000..8fa2c83
Binary files /dev/null and b/zjsh_mixing_sysytem/__pycache__/dispatch_task.cpython-312.pyc differ
diff --git a/zjsh_mixing_sysytem/__pycache__/dispatch_task.cpython-39.pyc b/zjsh_mixing_sysytem/__pycache__/dispatch_task.cpython-39.pyc
new file mode 100644
index 0000000..0d743f6
Binary files /dev/null and b/zjsh_mixing_sysytem/__pycache__/dispatch_task.cpython-39.pyc differ
diff --git a/zjsh_mixing_sysytem/__pycache__/system_nav_bar.cpython-312.pyc b/zjsh_mixing_sysytem/__pycache__/system_nav_bar.cpython-312.pyc
new file mode 100644
index 0000000..6410e16
Binary files /dev/null and b/zjsh_mixing_sysytem/__pycache__/system_nav_bar.cpython-312.pyc differ
diff --git a/zjsh_mixing_sysytem/__pycache__/system_nav_bar.cpython-39.pyc b/zjsh_mixing_sysytem/__pycache__/system_nav_bar.cpython-39.pyc
new file mode 100644
index 0000000..acbf850
Binary files /dev/null and b/zjsh_mixing_sysytem/__pycache__/system_nav_bar.cpython-39.pyc differ
diff --git a/zjsh_mixing_sysytem/bottom_control_widget.py b/zjsh_mixing_sysytem/bottom_control_widget.py
new file mode 100644
index 0000000..49b3025
--- /dev/null
+++ b/zjsh_mixing_sysytem/bottom_control_widget.py
@@ -0,0 +1,41 @@
+from PySide6.QtWidgets import (QWidget, QHBoxLayout, QLabel, QPushButton,
+ QMessageBox, QSpacerItem, QSizePolicy)
+from PySide6.QtGui import QPixmap, QPainter, QFont, QPen
+from PySide6.QtCore import Qt, QDateTime, QEvent, QSize
+
+class BottomControlWidget(QWidget):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.initUI()
+
+ def initUI(self):
+ # 1. 加载背景图并设置控件尺寸
+ bg_path = "底部背景.png"
+ self.bg_pixmap = QPixmap(bg_path)
+ if self.bg_pixmap.isNull():
+ print("警告:底部背景.png 加载失败,请检查路径!")
+ self.setFixedSize(1280, 66)
+ else:
+ self.setFixedSize(self.bg_pixmap.size())
+
+ # 2. 主布局(水平布局,组件间距6px)
+ main_layout = QHBoxLayout(self)
+ main_layout.setContentsMargins(10, 10, 10, 10) # 适当留白避免贴边
+ main_layout.setSpacing(6)
+
+ def paintEvent(self, event):
+ """绘制背景图"""
+ super().paintEvent(event)
+ if not self.bg_pixmap.isNull():
+ painter = QPainter(self)
+ painter.drawPixmap(0, 0, self.bg_pixmap)
+
+if __name__ == "__main__":
+ import sys
+ from PySide6.QtWidgets import QApplication
+
+ app = QApplication(sys.argv)
+ widget = BottomControlWidget()
+ widget.show()
+ sys.exit(app.exec())
+
\ No newline at end of file
diff --git a/zjsh_mixing_sysytem/dispatch_task.py b/zjsh_mixing_sysytem/dispatch_task.py
new file mode 100644
index 0000000..8dd5556
--- /dev/null
+++ b/zjsh_mixing_sysytem/dispatch_task.py
@@ -0,0 +1,531 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+'''
+# @Time : 2025/11/10 11:29
+# @Author : reenrr
+# @Description : 派单任务的详情按钮点击之后弹出, 显示派单任务的详情
+'''
+
+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, QSize, QTimer, Slot
+from PySide6.QtNetwork import QTcpSocket, QAbstractSocket
+import sys
+import json
+from datetime import datetime
+
+# -----------
+# 参数配置
+# -----------
+tcp_server_host = "127.0.0.1"
+tcp_server_port = 8888
+
+MAX_RECONNECT = 3 # 最大重连次数
+RECONNECT_INTERVAL = 2000 # 重连间隔(毫秒)
+
+class DispatchDetailsDialog(QDialog):
+ """
+ 派单任务的界面
+ """
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setAttribute(Qt.WA_TranslucentBackground)
+
+ self.is_running = False # 系统运行状态标记
+ self.latest_json_data = {"erp_id":None,"artifact_id":None} # 缓存服务端发送的最新JSON数据
+
+ self.statusWidgets = [] # 存储api_field + 对应的value标签
+
+ # ---------------
+ # TCP客户端核心配置
+ # ---------------
+ self.tcp_socket = QTcpSocket(self) # TCP socket实例
+ self.tcp_server_host = tcp_server_host
+ self.tcp_server_port = tcp_server_port
+ self.is_tcp_connected = False # TCP连接状态标记
+ self.has_connected_once = False # 连接至服务器至少一次标记(区别首次连接和断开后重连)
+ self.reconnect_count = 0 # 重连次数计数器
+ # 重连定时器,每隔RECONNECT_INTERVAL毫秒重连一次
+ self.reconnect_timer = QTimer(self)
+ self.reconnect_timer.setInterval(RECONNECT_INTERVAL)
+ self.reconnect_timer.timeout.connect(self._reconnect_to_server) # 绑定重连函数
+
+ # 绑定TCP信号与槽(事件驱动)
+ self._bind_tcp_signals()
+
+ # 初始化存储需要修改的控件
+ self.id_value_label = None # 对应管片ID值标签
+ self.rows = [] # 所有行的单元格列表(包含label、value)
+
+ self._init_ui()
+
+ # ----------------
+ # 客户端自动后自动连接服务端
+ # ----------------
+ print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...")
+ self._connect_to_server()
+
+ # ---------------------
+ # TCP连接相关函数
+ # ---------------------
+ def _connect_to_server(self):
+ """主动发起连接(仅在未连接状态下有效"""
+ if not self.is_tcp_connected:
+ self.tcp_socket.abort() # 终止现有连接
+ self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port)
+
+ def _reconnect_to_server(self):
+ """重连执行函数:仅在未连接且未达最大次数时触发"""
+ if not self.is_tcp_connected and self.reconnect_count < MAX_RECONNECT:
+ self.reconnect_count += 1
+ print(f"第{self.reconnect_count}次重连(共{MAX_RECONNECT}次尝试)...")
+ self._connect_to_server()
+ elif self.reconnect_count >= MAX_RECONNECT:
+ self.reconnect_timer.stop() # 停止重连定时器
+ print(f"已达最大重连次数({MAX_RECONNECT}次),停止重连,请检查服务端状态")
+
+ def _bind_tcp_signals(self):
+ """绑定TCP socket的核心信号(连接、断开、接收数据、错误)"""
+ # 连接成功信号
+ self.tcp_socket.connected.connect(self._on_tcp_connected)
+ # 断开连接信号
+ self.tcp_socket.disconnected.connect(self._on_tcp_disconnected)
+ # 接收数据信号(有新数据时触发)
+ self.tcp_socket.readyRead.connect(self._on_tcp_data_received)
+ # 错误信号(连接/通信出错时触发)
+ self.tcp_socket.errorOccurred.connect(self._on_tcp_error)
+
+ # -----------------------
+ # 界面初始化函数
+ # -----------------------
+ 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. 网格信息区域(单列6行)
+ self._add_grid_info_area(main_layout)
+ main_layout.addSpacing(30)
+
+ # 4. 操作按钮区域
+ self._init_operation_buttons(main_layout)
+
+ def _init_operation_buttons(self, parent_layout):
+ """初始化操作按钮(下料完成/生产异常/生产取消)"""
+ buttonContainer = QWidget()
+ buttonLayout = QHBoxLayout(buttonContainer)
+ buttonLayout.setSpacing(100)
+
+ self.errorButton = QPushButton("生产异常")
+ self.cancelButton = QPushButton("生产取消")
+
+ self.errorButton.setStyleSheet("""
+ QPushButton {
+ color: #1E1E1E;
+ font-size: 18px;
+ font-weight: bold;
+ padding: 15px 50px;
+ border: 1px solid;
+ background-color: #FF0000;
+ border-color: transparent;
+
+ }
+ QPushButton:hover {
+ opacity: 0.9;
+ background-color: #B71C1C;
+ }
+ QPushButton:pressed {
+ opacity: 0.8;
+ }
+
+ """)
+
+ self.cancelButton.setStyleSheet("""
+ QPushButton {
+ color: #1E1E1E;
+ font-size: 18px;
+ font-weight: bold;
+ padding: 15px 50px;
+ border: 1px solid;
+ background-color: #FFD700;
+ border-color: transparent;
+ }
+ QPushButton:hover {
+ opacity: 0.9;
+ background-color: #FFB300
+ }
+ QPushButton:pressed {
+ opacity: 0.8;
+ }
+ """)
+
+ self.errorButton.clicked.connect(self.on_error_clicked)
+ self.cancelButton.clicked.connect(self.on_cancel_clicked)
+
+ # 初始禁用“停止”和“异常”按钮(未连接时不可用)
+ self.errorButton.setDisabled(True)
+ self.cancelButton.setDisabled(True)
+
+ buttonLayout.addStretch(1)
+ buttonLayout.addWidget(self.errorButton)
+ buttonLayout.addWidget(self.cancelButton)
+ buttonLayout.addStretch(1)
+
+ parent_layout.addWidget(buttonContainer)
+
+ def _load_background(self):
+ self.bg_pixmap = QPixmap("详情弹出背景.png") # 修改为派单任务背景图
+ if self.bg_pixmap.isNull():
+ print("错误:派单任务背景.png 加载失败,请检查路径!")
+ self.setFixedSize(800, 500)
+ 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, alignment=Qt.AlignTop)
+
+ # 关闭按钮
+ top_layout.addStretch()
+
+ parent_layout.addLayout(top_layout)
+
+ 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(
+ """
+ background-image: url("详情标题.png");
+ 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("") # 初始管片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)
+ parent_layout.setAlignment(id_layout, Qt.AlignTop)
+
+ def _add_grid_info_area(self, parent_layout):
+ grid_layout = QGridLayout()
+ grid_layout.setSpacing(12)
+
+ # 初始化信息条目(6行)
+ info_items = [
+ {"name":"任务单号", "value": "", "api_field": "task_id"},
+ {"name": "工程名称", "value": "", "api_field": "project_name"},
+ {"name": "配比编号", "value": "", "api_field": "produce_mix_id"},
+ {"name": "要料状态", "value": "", "api_field": "flag"},
+ {"name": "砼强度", "value": "", "api_field": "beton_grade"},
+ {"name": "要料方量", "value": "", "api_field": "adjusted_volume"},
+ ]
+
+ self.rows.clear()
+ self.statusWidgets.clear() # 清空缓存
+
+ for row, item in enumerate(info_items):
+ cell_widget = self._create_info_cell(item["name"], item["value"])
+ self.rows.append(cell_widget)
+ grid_layout.addWidget(cell_widget, row, 0)
+
+ self.statusWidgets.append({
+ 'api_field': item["api_field"],
+ 'valueLabel': cell_widget.value # 绑定实际UI控件
+ }
+ )
+
+ parent_layout.addLayout(grid_layout)
+
+ def _create_info_cell(self, label_text, value_text):
+ cell_widget = QWidget()
+ cell_bg = QPixmap("派单任务信息栏1.png") # 正常背景图
+ cell_widget.setObjectName("infoCell")
+ if not cell_bg.isNull():
+ cell_widget.setFixedSize(cell_bg.size())
+ cell_widget.setStyleSheet(
+ """
+ QWidget {
+ background-image: url(派单任务信息栏1.png);
+ background-repeat: no-repeat;
+ background-position: Center;
+ }
+ QWidget:hover {
+ background-image: url(派单任务信息栏2.png);
+ }
+ 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 paintEvent(self, event):
+ if not self.bg_pixmap.isNull():
+ painter = QPainter(self)
+ painter.drawPixmap(self.rect(), self.bg_pixmap)
+ super().paintEvent(event)
+
+ def _update_ui_from_data(self, data):
+ """根据TCP获取的数据更新界面状态"""
+ # 1、更新顶部独立的“对应管片ID”
+ if "artifact_id" in data:
+ self.id_value_label.setText(str(data["artifact_id"]))
+
+ # 2、更新网格中的所有字段
+ for widget in self.statusWidgets:
+ api_field = widget['api_field']
+ value_label = widget['valueLabel']
+ if api_field in data:
+ new_value = str(data[api_field])
+ value_label.setText(new_value)
+
+ # ------------------- 对外修改接口 -------------------
+ # 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)
+
+ # ------------------
+ # 按钮点击事件
+ # ------------------
+ def on_error_clicked(self):
+ """点击“生产异常”:向服务端发送异常指令"""
+ print("🔘 点击「生产异常」按钮")
+ self._clear_ui_info()
+ self._send_tcp_request("production_error")
+
+ def on_cancel_clicked(self):
+ """点击“生产取消”:向服务端发送取消指令"""
+ print("🔘 点击「生产取消」按钮")
+ self._clear_ui_info()
+ self._send_tcp_request("cancel_feed")
+
+ # --------------------
+ # 清空界面信息的通用方法
+ # --------------------
+ def _clear_ui_info(self):
+ """清空管片ID和网格信息"""
+ if self.id_value_label:
+ self.id_value_label.setText("")
+ for widget in self.statusWidgets:
+ widget['valueLabel'].setText("")
+ print("ℹ️ 界面信息已清空")
+
+ # ------------------
+ # TCP客户端核心功能
+ # ------------------
+ @Slot()
+ def _on_tcp_connected(self):
+ """TCP连接成功回调"""
+ self.is_tcp_connected = True
+ self.has_connected_once = True
+ self.reconnect_timer.stop() # 停止重连定时器
+ self.reconnect_count = 0 # 重连计数器清零
+ self.is_running = True
+ print(f"TCP连接成功:{self.tcp_server_host}:{self.tcp_server_port}")
+
+ # 连接成功后,向服务器发送“请求初始数据”指令
+ self._send_tcp_request("get_initial_data")
+
+ # 更新按钮状态:启用“生产异常”“生产取消”
+ self.errorButton.setDisabled(False)
+ self.cancelButton.setDisabled(False)
+
+ @Slot()
+ def _on_tcp_disconnected(self):
+ """TCP连接断开回调"""
+ self.is_tcp_connected = False
+ self.is_running = False
+ print(f"TCP连接断开:{self.tcp_server_host}:{self.tcp_server_port}")
+
+ # 启用/禁用按钮
+ self.errorButton.setDisabled(True)
+ self.cancelButton.setDisabled(True)
+
+ # 重置状态指示灯为“未连接”状态
+ for widget in self.statusWidgets:
+ widget['indicator'].setStyleSheet("""
+ QLabel {
+ background-color: #9E9E9E;
+ border-radius: 10px;
+ border: 2px solid #555555;
+ }
+ """)
+
+ @Slot()
+ def _on_tcp_data_received(self):
+ """TCP数据接收回调(服务器发送数据时触发)"""
+ tcp_data = self.tcp_socket.readAll().data().decode("utf-8").strip()
+ print(f"TCP数据接收:{tcp_data}")
+
+ # 解析数据
+ try:
+ status_data = json.loads(tcp_data)
+ self.latest_json_data = status_data
+ self._update_ui_from_data(status_data)
+ except json.JSONDecodeError as e:
+ print(f"TCP数据解析失败(非JSON格式):{e}, 原始数据:{tcp_data}")
+ except Exception as e:
+ print(f"TCP数据处理异常:{e}")
+
+ @Slot(QAbstractSocket.SocketError)
+ def _on_tcp_error(self, error):
+ """TCP错误回调"""
+ if not self.is_tcp_connected:
+ error_str = self.tcp_socket.errorString()
+ print(f"TCP错误:{error_str}")
+ self.is_tcp_connected = False
+ self.is_running = False
+
+ # 启用/禁用按钮
+ self.errorButton.setDisabled(True)
+ self.cancelButton.setDisabled(True)
+
+ # 首次连接失败时,启动重连定时器
+ if not self.has_connected_once and self.reconnect_count == 0:
+ print(f"将在{RECONNECT_INTERVAL / 1000}秒后启动重连(最多{MAX_RECONNECT}次)")
+ self.reconnect_timer.start()
+
+ def _send_tcp_request(self, request_cmd="get_status"):
+ """向TCP服务器发送请求指令"""
+ if not self.is_tcp_connected:
+ print("TCP连接未建立,无法发送请求")
+ return
+ print(self.latest_json_data)
+ # 构造请求数据
+ request_data = json.dumps({
+ "cmd": request_cmd,
+ "erp_id": self.latest_json_data["erp_id"],
+ "artifact_id":self.latest_json_data["artifact_id"],
+ "timestamp": self.get_current_time(),
+ "client_info": "布料系统客户端"
+ }) + "\n" # 增加换行符作为数据结束标识
+
+ # 发送请求数据
+ self.tcp_socket.write(request_data.encode("utf-8"))
+ print(f"TCP请求发送:{request_data.strip()}")
+
+ # ------------------
+ # 时间相关的通用方法
+ # ------------------
+ def get_current_time(self):
+ """获取格式化的当前时间"""
+ return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+
+
+# 测试代码
+if __name__ == "__main__":
+ app = QApplication(sys.argv)
+ dialog = DispatchDetailsDialog()
+ dialog.show()
+ sys.exit(app.exec())
diff --git a/zjsh_mixing_sysytem/main_window.py b/zjsh_mixing_sysytem/main_window.py
new file mode 100644
index 0000000..038d2e3
--- /dev/null
+++ b/zjsh_mixing_sysytem/main_window.py
@@ -0,0 +1,113 @@
+# 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, QPushButton)
+
+from system_nav_bar import SystemNavBar
+from bottom_control_widget import BottomControlWidget
+from dispatch_task import DispatchDetailsDialog
+
+
+class MainWindow(QWidget):
+ def __init__(self):
+ super().__init__()
+ self.initWindow()
+ self.createSubWidgets() # 创建子部件
+ self.setupLayout() # 设置布局
+
+ def initWindow(self):
+ """初始化窗口基本属性"""
+ self.setWindowTitle("中交三航主界面") # 设置窗口标题
+ # 设置最小尺寸(可根据需求调整)
+ # 触摸屏尺寸为 1280*800
+ self.setMinimumSize(1280, 800)
+ self.setObjectName("MainWindow")
+
+ # Qt.FramelessWindowHint
+ self.setWindowFlags(Qt.FramelessWindowHint) # 无边框窗口
+
+ # 设置主界面背景图片
+ try:
+ self.background_image = QImage("主界面背景.png")
+ if self.background_image.isNull():
+ raise Exception("图片为空,可能路径错误或格式不支持")
+ # print("图片加载成功")
+ except Exception as e:
+ print(f"主界面背景图片加载失败: {e}")
+ self.background_image = None
+ return # 加载背景失败
+
+ self.update_background()
+
+ def createSubWidgets(self):
+ """创建所有子部件实例"""
+ self.system_nav_bar = SystemNavBar() # 最上方:系统导航栏
+ self.bottom_control_widget = BottomControlWidget() # 最下方: 控制的按钮 (系统诊断、系统中心等)
+
+ # 中间:任务派单
+ self.dispatch_dialog = DispatchDetailsDialog(self)
+
+ 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)
+ # 添加中间内容区
+ main_layout.addWidget(self.dispatch_dialog, alignment=Qt.AlignCenter)
+ # 添加最下方的 控制按钮控件
+ main_layout.addWidget(self.bottom_control_widget, alignment=Qt.AlignBottom)
+
+ # 关闭按钮
+ self.system_nav_bar.msg_container.close_btn.clicked.connect(self.close)
+ # 将布局应用到主窗口
+ self.setLayout(main_layout)
+
+ def show_dispatch_dialog(self):
+ """显示派单详细弹窗(居中显示在主界面)"""
+ # 计算弹窗居中位置
+ main_geometry = self.frameGeometry()
+ dialog_geometry = self.dispatch_dialog.frameGeometry()
+ dialog_geometry.moveCenter(main_geometry.center())
+ self.dispatch_dialog.move(dialog_geometry.topLeft())
+
+ # 显示弹窗
+ self.dispatch_dialog.show()
+
+ 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 resizeEvent(self, e):
+ """窗口大小变化时的回调"""
+ super().resizeEvent(e)
+ self.update_background() # 重新加载背景图片
+
+
+ def keyPressEvent(self, event):
+ if event.key() == Qt.Key_Escape: # 按下Esc键, 退出界面
+ self.close()
+ super().keyPressEvent(event)
+
+
+if __name__ == "__main__":
+ import sys
+ app = QApplication([])
+ window = MainWindow()
+ window.show() # 显示主界面
+ # window.showFullScreen() # 全屏显示主界面
+ sys.exit(app.exec())
diff --git a/zjsh_mixing_sysytem/system_nav_bar.py b/zjsh_mixing_sysytem/system_nav_bar.py
new file mode 100644
index 0000000..35ed612
--- /dev/null
+++ b/zjsh_mixing_sysytem/system_nav_bar.py
@@ -0,0 +1,141 @@
+from PySide6.QtWidgets import (QWidget, QLabel, QHBoxLayout,
+ QSpacerItem, QSizePolicy, QPushButton)
+from PySide6.QtGui import QPixmap, QFont, QPainter, QIcon
+from PySide6.QtCore import Qt, QTimer, QDateTime
+
+# 自定义消息容器, 显示系统消息
+class MsgContainer(QWidget):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setFixedSize(770, 24)
+
+ # 加载消息区域背景图
+ self.bg_pixmap = QPixmap("系统消息背景.png") # 替换为实际路径
+ if self.bg_pixmap.isNull():
+ print("警告:系统消息背景.png 加载失败")
+
+ # 消息区域内部布局(喇叭+文本)
+ msg_layout = QHBoxLayout(self)
+ msg_layout.setContentsMargins(0, 0, 0, 0) # 调整内边距,避免内容贴边
+ msg_layout.setSpacing(3) # 喇叭和文本的间距
+
+ # 消息喇叭图标
+ self.msg_icon = QLabel()
+ self.msg_icon.setFixedSize(13, 18)
+ # self.msg_icon.setStyleSheet("background-color:red;")
+ self.msg_icon.setPixmap(QPixmap("系统消息喇叭.png")) # 替换为实际路径
+ msg_layout.addWidget(self.msg_icon, alignment=Qt.AlignVCenter | Qt.AlignLeft)
+
+ # 消息文本
+ current_time = QDateTime.currentDateTime().toString("hh:mm:ss")
+ self.msg_text = QLabel(f"{current_time} 开始启动智能浇筑系统")
+ self.msg_text.setFixedWidth(740)
+ # self.msg_text.setStyleSheet("color: white; font-size: 14px;background-color:red;") # 文本样式
+ self.msg_text.setStyleSheet("color: white; font-size: 16px;font-weight:Bold;")
+ self.msg_text.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
+ msg_layout.addWidget(self.msg_text)
+
+ # 关闭按钮
+ self._create_close_button(msg_layout)
+
+ def _create_close_button(self, parent_layout):
+ self.close_btn = QPushButton()
+ self.close_btn.setFixedSize(20, 20)
+
+ close_icon = QPixmap("关闭图标.png")
+ 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;
+ }
+ """
+ )
+
+ parent_layout.addWidget(self.close_btn)
+
+ def paintEvent(self, event):
+ # 绘制消息区域背景图
+ super().paintEvent(event) # 确保子控件正常绘制
+ if self.bg_pixmap.isNull():
+ return # 图片加载失败则不绘制
+
+ painter = QPainter(self)
+ painter.setRenderHint(QPainter.SmoothPixmapTransform) # 缩放平滑
+ painter.drawPixmap(self.rect(), self.bg_pixmap)
+
+class SystemNavBar(QWidget):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ # 设置尺寸
+ self.setFixedSize(1280, 80)
+
+ # 1. 加载背景图
+ self.bg_pixmap = QPixmap("系统主界面导航栏.png") # 替换为实际图片路径
+ if self.bg_pixmap.isNull():
+ print("警告:背景图加载失败,请检查路径!")
+
+ main_layout = QHBoxLayout(self)
+ main_layout.setContentsMargins(9, 9, 9, 19)
+ main_layout.setSpacing(100) # 注意:左侧的logo+系统标题的容器 和 系统消息的间隔
+
+ # 左侧区域:logo + 系统标题
+ left_container = QWidget()
+ left_container.setFixedSize(400, 53)
+ left_layout = QHBoxLayout(left_container) # 容器内部的水平布局
+ left_layout.setContentsMargins(0, 0, 0, 0) # 容器内边距
+ left_layout.setSpacing(6) # 设置logo和标题之间的间隙为6px
+ # 系统logo
+ self.logo = QLabel()
+ self.logo.setFixedSize(53, 53)
+ self.logo.setPixmap(QPixmap("系统logo.png"))
+ left_layout.addWidget(self.logo, alignment=Qt.AlignTop)
+ # 系统总标题
+ self.title = QLabel()
+ self.title.setPixmap(QPixmap("系统总标题.png"))
+ left_layout.addWidget(self.title, alignment=Qt.AlignCenter)
+ main_layout.addWidget(left_container, alignment=Qt.AlignTop)
+
+ # 中间区域:系统消息(喇叭+文本+背景)
+ self.msg_container = MsgContainer()
+ main_layout.addWidget(self.msg_container, alignment=Qt.AlignBottom | Qt.AlignRight)
+
+ # 右侧区域:实时时间
+ self.time_label = QLabel()
+ self.time_label.setStyleSheet("color: white; font-size: 16px;font-weight:Bold;")
+ main_layout.addWidget(self.time_label, alignment= Qt.AlignTop | Qt.AlignRight)
+
+ # 启动时间更新定时器
+ self.timer = QTimer(self)
+ self.timer.timeout.connect(self.update_time)
+ self.timer.start(1000) # 每秒更新一次
+
+ def paintEvent(self, event):
+ super().paintEvent(event)
+
+ painter = QPainter(self)
+ painter.setRenderHint(QPainter.SmoothPixmapTransform) # 缩放时平滑
+
+ painter.drawPixmap(0, 0, self.bg_pixmap)
+
+ def update_time(self):
+ current_time = QDateTime.currentDateTime().toString("yyyy/MM/dd hh:mm:ss")
+ self.time_label.setText(current_time)
+
+# 测试代码
+if __name__ == "__main__":
+ import sys
+ from PySide6.QtWidgets import QApplication, QMainWindow
+
+ app = QApplication(sys.argv)
+ nav_bar = SystemNavBar()
+ nav_bar.show()
+ sys.exit(app.exec())
\ No newline at end of file
diff --git a/zjsh_mixing_sysytem/主界面背景.png b/zjsh_mixing_sysytem/主界面背景.png
new file mode 100644
index 0000000..dc65b12
Binary files /dev/null and b/zjsh_mixing_sysytem/主界面背景.png differ
diff --git a/zjsh_mixing_sysytem/关闭图标.png b/zjsh_mixing_sysytem/关闭图标.png
new file mode 100644
index 0000000..9b090d6
Binary files /dev/null and b/zjsh_mixing_sysytem/关闭图标.png differ
diff --git a/zjsh_mixing_sysytem/底部背景.png b/zjsh_mixing_sysytem/底部背景.png
new file mode 100644
index 0000000..3a66c09
Binary files /dev/null and b/zjsh_mixing_sysytem/底部背景.png differ
diff --git a/zjsh_mixing_sysytem/派单任务信息栏1.png b/zjsh_mixing_sysytem/派单任务信息栏1.png
new file mode 100644
index 0000000..6991534
Binary files /dev/null and b/zjsh_mixing_sysytem/派单任务信息栏1.png differ
diff --git a/zjsh_mixing_sysytem/派单任务信息栏2.png b/zjsh_mixing_sysytem/派单任务信息栏2.png
new file mode 100644
index 0000000..5397cd4
Binary files /dev/null and b/zjsh_mixing_sysytem/派单任务信息栏2.png differ
diff --git a/zjsh_mixing_sysytem/派单最底部.png b/zjsh_mixing_sysytem/派单最底部.png
new file mode 100644
index 0000000..92f9b55
Binary files /dev/null and b/zjsh_mixing_sysytem/派单最底部.png differ
diff --git a/zjsh_mixing_sysytem/生产取消按钮.png b/zjsh_mixing_sysytem/生产取消按钮.png
new file mode 100644
index 0000000..5ff0693
Binary files /dev/null and b/zjsh_mixing_sysytem/生产取消按钮.png differ
diff --git a/zjsh_mixing_sysytem/生产异常按钮.png b/zjsh_mixing_sysytem/生产异常按钮.png
new file mode 100644
index 0000000..4874222
Binary files /dev/null and b/zjsh_mixing_sysytem/生产异常按钮.png differ
diff --git a/zjsh_mixing_sysytem/系统logo.png b/zjsh_mixing_sysytem/系统logo.png
new file mode 100644
index 0000000..e50db73
Binary files /dev/null and b/zjsh_mixing_sysytem/系统logo.png differ
diff --git a/zjsh_mixing_sysytem/系统主界面导航栏.png b/zjsh_mixing_sysytem/系统主界面导航栏.png
new file mode 100644
index 0000000..7db6d8b
Binary files /dev/null and b/zjsh_mixing_sysytem/系统主界面导航栏.png differ
diff --git a/zjsh_mixing_sysytem/系统总标题.png b/zjsh_mixing_sysytem/系统总标题.png
new file mode 100644
index 0000000..64f34be
Binary files /dev/null and b/zjsh_mixing_sysytem/系统总标题.png differ
diff --git a/zjsh_mixing_sysytem/系统消息喇叭.png b/zjsh_mixing_sysytem/系统消息喇叭.png
new file mode 100644
index 0000000..abbc7f2
Binary files /dev/null and b/zjsh_mixing_sysytem/系统消息喇叭.png differ
diff --git a/zjsh_mixing_sysytem/系统消息背景.png b/zjsh_mixing_sysytem/系统消息背景.png
new file mode 100644
index 0000000..a436582
Binary files /dev/null and b/zjsh_mixing_sysytem/系统消息背景.png differ
diff --git a/zjsh_mixing_sysytem/详情弹出背景.png b/zjsh_mixing_sysytem/详情弹出背景.png
new file mode 100644
index 0000000..7c003c2
Binary files /dev/null and b/zjsh_mixing_sysytem/详情弹出背景.png differ
diff --git a/zjsh_mixing_sysytem/详情标题.png b/zjsh_mixing_sysytem/详情标题.png
new file mode 100644
index 0000000..edf08db
Binary files /dev/null and b/zjsh_mixing_sysytem/详情标题.png differ