diff --git a/.idea/InsertData.iml b/.idea/InsertData.iml index 29bca85..74d515a 100644 --- a/.idea/InsertData.iml +++ b/.idea/InsertData.iml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index db5199f..df3bfff 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 1326942..94a25f7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,5 @@ - \ No newline at end of file diff --git a/API/send_data_test.py b/API/send_data_test.py index 4159774..a7d031c 100644 --- a/API/send_data_test.py +++ b/API/send_data_test.py @@ -205,9 +205,10 @@ def get_not_pour_info(): "Code": 200, "Message": None, "Data": [ + { "ArtifactID": "QR1B12000151AD", - "ArtifactActionID": 346482967298117, + "ArtifactActionID": 346482967298138, "ArtifactIDVice1": "Q00001AD", "ProduceRingNumber": 1, "MouldCode": "SHR2B1-9", @@ -215,16 +216,33 @@ def get_not_pour_info(): "RingTypeCode": "R22", "SizeSpecification": "6900*1500", "BuriedDepth": "中埋", - "BlockNumber": "B1", + "BlockNumber": "F", "HoleRingMarking": "否", "GroutingPipeMarking": "否", "PolypropyleneFiberMarking": "否", - "BetonVolume": 2.0000, + "BetonVolume": 0.6, + "BetonTaskID": "20251020-01" + }, + { + "ArtifactID": "QR1B12000151AD", + "ArtifactActionID": 3464829672981339, + "ArtifactIDVice1": "Q00001AD", + "ProduceRingNumber": 1, + "MouldCode": "SHR2B1-9", + "SkeletonID": "QR1B12000046A", + "RingTypeCode": "R22", + "SizeSpecification": "6900*1500", + "BuriedDepth": "中埋", + "BlockNumber": "F", + "HoleRingMarking": "否", + "GroutingPipeMarking": "否", + "PolypropyleneFiberMarking": "否", + "BetonVolume": 0.6, "BetonTaskID": "20251020-01" }, { "ArtifactID": "QR1B32000153AD", - "ArtifactActionID": 346482967298119, + "ArtifactActionID": 346482967298140, "ArtifactIDVice1": "Q00001AD", "ProduceRingNumber": 1, "MouldCode": "SHR2B3-9", @@ -232,30 +250,14 @@ def get_not_pour_info(): "RingTypeCode": "R22", "SizeSpecification": "6900*1500", "BuriedDepth": "中埋", - "BlockNumber": "B2", + "BlockNumber": "F", "HoleRingMarking": "否", "GroutingPipeMarking": "否", "PolypropyleneFiberMarking": "否", - "BetonVolume": 2.0000, - "BetonTaskID": "20251020-01" - }, - { - "ArtifactID": "QR1B12000151AD", - "ArtifactActionID": 346482967298120, - "ArtifactIDVice1": "Q00001AD", - "ProduceRingNumber": 1, - "MouldCode": "SHR2B1-9", - "SkeletonID": "QR1B12000046A", - "RingTypeCode": "R22", - "SizeSpecification": "6900*1500", - "BuriedDepth": "中埋", - "BlockNumber": "B3", - "HoleRingMarking": "否", - "GroutingPipeMarking": "否", - "PolypropyleneFiberMarking": "否", - "BetonVolume": 2.0000, + "BetonVolume": 0.6, "BetonTaskID": "20251020-01" }, + ] } diff --git a/InsertData_list.py b/InsertData_list.py index 96566f2..60d0d6e 100644 --- a/InsertData_list.py +++ b/InsertData_list.py @@ -241,6 +241,8 @@ def _handle_two_f_blocks(f_positions, current_task, total_f_volume, artifact_lis if f_positions == [0, 1] and task_before.get("block_number") == "F": adjusted_volume = 0 block_number = "补方" + elif f_positions == [1, 2]: + adjusted_volume = artifact_list[0]["BetonVolume"] else: adjusted_volume = total_f_volume - half_volume[0] block_number = current_task["block_number"] diff --git a/main.py b/main.py index 59122bb..476ab8f 100644 --- a/main.py +++ b/main.py @@ -27,6 +27,7 @@ def start_api_service(): api.run(host='127.0.0.1', port=5001, debug=False, threaded=True) def main(): + global tcp_server api_thread = threading.Thread(target=start_api_service) api_thread.daemon = True api_thread.start() @@ -42,7 +43,7 @@ def main(): # 初始化服务 api_client = APIClient() - task_service = TaskService() + task_service = TaskService(tcp_server) monitoring_service = MonitoringService(tcp_server) # 步骤1:获取AppID @@ -101,6 +102,10 @@ def main(): # 步骤3:获取任务单信息 task_service.insert_into_produce_table(sql_db, task_info, task["beton_volume"], erp_id, task["artifact_id"], 1) + with monitoring_service.tasks_lock: + monitoring_service.monitored_tasks.add(erp_id) + monitoring_service.inserted_tasks[erp_id] = task["artifact_id"] + print(f"任务 {erp_id} (ArtifactID: {task['artifact_id']}) 已添加到监控列表") finally: sql_db.close() diff --git a/services/monitoring_service.py b/services/monitoring_service.py index c02059b..d1dcdfd 100644 --- a/services/monitoring_service.py +++ b/services/monitoring_service.py @@ -7,6 +7,7 @@ from database.access_db import AccessDB from database.sql_server import SQLServerDB from config.settings import ACCESS_DB_PATH, ACCESS_DB_PASSWORD, MONITOR_INTERVAL from tcp.server import TCPServer +from services.task_service import TaskService class MonitoringService: def __init__(self, tcp_server): @@ -15,6 +16,7 @@ class MonitoringService: self.monitored_tasks = set() self.inserted_tasks = {} self.tasks_lock = threading.Lock() + self.task_service = TaskService(tcp_server) def monitor_access_flag_changes(self): """监控Access数据库中派发任务的Flag状态""" @@ -44,8 +46,6 @@ class MonitoringService: erp_ids_str = [str(erp_id) for erp_id in tasks_to_monitor] deleted_from_sql_tasks = set(erp_ids_str) - existing_tasks_in_sql - print(f"SQL Server中仍存在的任务: {existing_tasks_in_sql}") - print(f"已从SQL Server删除的任务: {deleted_from_sql_tasks}") # 只有已从SQL Server删除的任务才需要在Access中查找 if not deleted_from_sql_tasks: @@ -75,8 +75,6 @@ class MonitoringService: current_flag = current_tasks.get(erp_id_str, "") previous_flag = self.task_flags.get(erp_id_str, "") - # 添加调试信息 - print(f"检查任务 {erp_id} - 当前Flag: '{current_flag}', 之前Flag: '{previous_flag}'") # 如果状态发生变化 if current_flag != previous_flag: @@ -98,119 +96,114 @@ class MonitoringService: def _handle_flag_status_change(self, erp_id, current_flag, artifact_id): """处理标志状态变化""" if current_flag.endswith('d'): - self._handle_status_d(erp_id, artifact_id) + self._handle_status_d(erp_id,artifact_id) elif current_flag.endswith('w'): - self._handle_status_w(erp_id, artifact_id) + self._handle_status_w(erp_id,artifact_id) elif current_flag.endswith('n'): - self._handle_status_n(erp_id, artifact_id) + self._handle_status_n(erp_id,artifact_id) elif current_flag.endswith('p'): - self._handle_status_p(erp_id, artifact_id) + self._handle_status_p(erp_id,artifact_id) elif current_flag.endswith('x'): - self._handle_status_x(erp_id, artifact_id) + self._handle_status_x(erp_id,artifact_id) - def _handle_status_d(self, erp_id, artifact_id): + def _handle_status_d(self,erp_id, artifact_id): """处理状态'd' - 未进行生产""" - print(f"派发任务 ErpID {erp_id}: 未进行生产") - # 调用同事提供的状态更新函数 + print(f"派发任务 artifact_id {artifact_id}: 未进行生产") try: print(1) - update_custom_table_status(erp_id, "未进行生产") + self.task_service.update_custom_table_status(artifact_id, "未进行生产") except Exception as e: print(f"更新状态时出错: {e}") - # 发送数据给TCP客户端(只发送erp_id和状态) try: status_data = { - "erp_id": erp_id, - "status": "未进行生产" + "erp_id":erp_id, + "artifact_id": artifact_id, + "flag": "未进行生产" } self.tcp_server.send_data(status_data) except Exception as e: print(f"发送状态数据给TCP客户端时出错: {e}") - def _handle_status_w(self, erp_id, artifact_id): + def _handle_status_w(self, erp_id,artifact_id): """处理状态'w' - 正在生产中""" - print(f"派发任务 ErpID {erp_id}: 正在生产中") - # 调用同事提供的状态更新函数 + print(f"派发任务 artifact_id {artifact_id}: 正在生产中") try: print(2) - update_custom_table_status(erp_id, "正在生产中") + self.task_service.update_custom_table_status(artifact_id, "正在生产中") except Exception as e: print(f"更新状态时出错: {e}") - # 发送数据给TCP客户端(只发送erp_id和状态) try: status_data = { - "erp_id": erp_id, - "status": "正在生产中" + "erp_id":erp_id, + "artifact_id": artifact_id, + "flag": "正在生产中" } self.tcp_server.send_data(status_data) except Exception as e: print(f"发送状态数据给TCP客户端时出错: {e}") - def _handle_status_n(self, erp_id, artifact_id): + def _handle_status_n(self,erp_id, artifact_id): """处理状态'n' - 生产完毕""" - print(f"派发任务 ErpID {erp_id}: 生产完毕") + print(f"派发任务 artifact_id {artifact_id}: 生产完毕") # 任务完成,可以从监控列表中移除 with self.tasks_lock: - self.monitored_tasks.discard(erp_id) - print(f"派发任务 ErpID {erp_id} 已完成,停止监控") - # 调用同事提供的状态更新函数 + self.monitored_tasks.discard(artifact_id) + print(f"派发任务 artifact_id {artifact_id} 已完成,停止监控") try: print(3) - update_custom_table_status(erp_id, "生产完毕") + self.task_service.update_custom_table_status(artifact_id, "生产完毕") except Exception as e: print(f"更新状态时出错: {e}") - # 发送数据给TCP客户端(只发送erp_id和状态) try: status_data = { - "erp_id": erp_id, - "status": "生产完毕" + "erp_id":erp_id, + "artifact_id": artifact_id, + "flag": "生产完毕" } self.tcp_server.send_data(status_data) except Exception as e: print(f"发送状态数据给TCP客户端时出错: {e}") - def _handle_status_p(self, erp_id, artifact_id): + def _handle_status_p(self, erp_id,artifact_id): """处理状态'p' - 生产中断""" - print(f"派发任务 ErpID {erp_id}: 生产中断") + print(f"派发任务 ErpID {artifact_id}: 生产中断") # 任务中断,可以从监控列表中移除 with self.tasks_lock: - self.monitored_tasks.discard(erp_id) - print(f"派发任务 ErpID {erp_id} 已中断,停止监控") - # 调用同事提供的状态更新函数 + self.monitored_tasks.discard(artifact_id) + print(f"派发任务 ErpID {artifact_id} 已中断,停止监控") try: print(4) - update_custom_table_status(erp_id, "生产中断") + self.task_service.update_custom_table_status(artifact_id, "生产中断") except Exception as e: print(f"更新状态时出错: {e}") - # 发送数据给TCP客户端(只发送erp_id和状态) try: status_data = { "erp_id": erp_id, - "status": "生产中断" + "artifact_id": artifact_id, + "flag": "生产中断" } self.tcp_server.send_data(status_data) except Exception as e: print(f"发送状态数据给TCP客户端时出错: {e}") - def _handle_status_x(self, erp_id, artifact_id): + def _handle_status_x(self, erp_id,artifact_id): """处理状态'x' - 数据已接收""" - print(f"派发任务 ErpID {erp_id}: 数据已接收") - # 调用同事提供的状态更新函数 + print(f"派发任务 ErpID {artifact_id}: 已插入") try: print(5) - # update_custom_table_status(erp_id, "数据已接收") + self.task_service.update_custom_table_status(artifact_id, "已插入") except Exception as e: print(f"更新状态时出错: {e}") - # 发送数据给TCP客户端(只发送erp_id和状态) try: status_data = { - "erp_id": erp_id, - "status": "数据已接收" + "erp_id":erp_id, + "artifact_id": artifact_id, + "flag": "已插入" } self.tcp_server.send_data(status_data) except Exception as e: diff --git a/services/task_service.py b/services/task_service.py index 00da6a9..0baa681 100644 --- a/services/task_service.py +++ b/services/task_service.py @@ -5,14 +5,17 @@ from database.access_db import AccessDB from database.sql_server import SQLServerDB from config.settings import ACCESS_DB_PATH, ACCESS_DB_PASSWORD from utils.helpers import get_f_block_positions +import threading +import time class TaskService: - def __init__(self): + def __init__(self, tcp_server=None): self.api_client = APIClient() self.half_volume = [0, 0] - self.task_before = None + self.task_before = {"block_number":None, "beton_volume":None, "artifact_id":None} self.artifact_timestamps = {} + self.tcp_server = tcp_server def process_not_pour_info(self): """处理未浇筑信息""" @@ -31,6 +34,11 @@ class TaskService: # 处理当前任务 current_task = self._process_current_task(artifact_list[0]) + # 根据F块情况处理任务 + task_result = self._handle_tasks_by_f_blocks( + f_block_count, f_positions, current_task, + f_blocks, total_f_volume, artifact_list + ) # 更新上一个任务信息 self.task_before = { "beton_task_id": current_task["beton_task_id"], @@ -38,13 +46,6 @@ class TaskService: "artifact_id": current_task["artifact_id"], "block_number": current_task["block_number"] } - - # 根据F块情况处理任务 - task_result = self._handle_tasks_by_f_blocks( - f_block_count, f_positions, current_task, - f_blocks, total_f_volume, artifact_list - ) - return task_result def _process_f_blocks(self, artifact_list): @@ -98,41 +99,49 @@ class TaskService: def _handle_multiple_f_blocks(self, current_task, total_f_volume, artifact_list): """处理多个F块的情况""" - adjusted_volume = total_f_volume - self.half_volume[0] + if self.task_before.get("block_number") == "F": + print("报警:,超出正常补块逻辑") + else: + adjusted_volume = total_f_volume - self.half_volume[0] - tasks = [{ - "beton_task_id": current_task["beton_task_id"], - "beton_volume": adjusted_volume, - "artifact_id": current_task["artifact_id"], - "block_number": current_task["block_number"], - }] + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + }] - send_list = [{ - "beton_task_id": current_task["beton_task_id"], - "beton_volume": adjusted_volume, - "artifact_id": current_task["artifact_id"], - "block_number": current_task["block_number"], - "beton_grade": current_task["task_data"]["BetonGrade"], - "mix_id": current_task["task_data"]["MixID"], - "time": self.artifact_timestamps.get(current_task["artifact_id"], datetime.now()) - }] + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": self.artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] - # 处理后续任务 - self._append_additional_tasks(send_list, artifact_list, [0, 0]) + # 处理后续任务 + self._append_additional_tasks(send_list, artifact_list, [0, 0]) - # 更新时间戳 - self._update_artifact_timestamps(send_list) + # 更新时间戳 + self._update_artifact_timestamps(send_list) - return tasks, artifact_list, send_list, self.half_volume + return tasks, artifact_list, send_list, self.half_volume def _handle_two_f_blocks(self, f_positions, current_task, total_f_volume, artifact_list): """处理两个F块的情况""" if f_positions == [0, 1] and self.task_before.get("block_number") == "F": adjusted_volume = 0 block_number = "补方" - else: + elif f_positions == [1, 2]: + adjusted_volume = artifact_list[0]["BetonVolume"] + block_number = current_task["block_number"] + elif f_positions == [0, 1] and self.task_before.get("block_number") != "F": adjusted_volume = total_f_volume - self.half_volume[0] block_number = current_task["block_number"] + else: + print("报警") tasks = [{ "beton_task_id": current_task["beton_task_id"], @@ -153,9 +162,7 @@ class TaskService: # 处理后续任务 volumes = [adjusted_volume, - artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0] if f_positions == [0, - 1] and self.task_before.get( - "block_number") == "F" else [0, 0] + artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0] if f_positions == [0, 1] and self.task_before.get("block_number") == "F" else [0, 0] self._append_additional_tasks(send_list, artifact_list, volumes) # 更新时间戳 @@ -305,7 +312,7 @@ class TaskService: def insert_into_produce_table(self, connection, task_info, beton_volume, erp_id, artifact_id, status): """插入数据到Produce表""" sql_db = SQLServerDB() - if status == "1": + if status == 1: # 准备插入数据 insert_data = { "ErpID": erp_id, @@ -331,14 +338,14 @@ class TaskService: try: # 假设同事提供的函数名为 save_to_custom_table # 参数包括: MISID(即erp_id), Flag, TaskID, ProduceMixID, ProjectName, BetonGrade, 调整后的方量 - save_to_custom_table( + self.save_to_custom_table( misid=erp_id, - flag="1", # 初始Flag值 + flag="已插入", # 初始Flag值 task_id=task_info["TaskID"], produce_mix_id=task_info["ProduceMixID"], project_name=task_info["ProjectName"], beton_grade=task_info["BetonGrade"], - adjusted_volume=beton_volume, + adjusted_volume=round(beton_volume,2), artifact_id=artifact_id # 已经调整后的方量 ) @@ -346,21 +353,49 @@ class TaskService: except Exception as e: print(f"调用保存函数时出错: {e}") + # 发送数据给TCP客户端 + if self.tcp_server: + try: + time.sleep(2) + task_data = { + "erp_id": erp_id, # 车号,相当于序号 + "task_id": task_info["TaskID"], # 任务单号 + "artifact_id": artifact_id, + "produce_mix_id": task_info["ProduceMixID"], # 配比号 + "project_name": task_info["ProjectName"], # 任务名 + "beton_grade": task_info["BetonGrade"], # 砼强度 + "adjusted_volume": round(beton_volume,2), # 方量 + "flag": "已插入", # 状态 + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 时间 + } + self.tcp_server.send_data(task_data) + print(f"任务 {artifact_id} 的数据已发送给TCP客户端") + except Exception as e: + print(f"发送数据给TCP客户端时出错: {e}") + return erp_id else: try: - # 假设同事提供的函数名为 save_to_custom_table # 参数包括: MISID(即erp_id), Flag, TaskID, ProduceMixID, ProjectName, BetonGrade, 调整后的方量 - save_to_custom_table( + self.save_to_custom_table( misid=erp_id, - flag="1", # 初始Flag值 + flag="已插入", # 初始Flag值 task_id=task_info["TaskID"], produce_mix_id=task_info["ProduceMixID"], project_name=task_info["ProjectName"], beton_grade=task_info["BetonGrade"], - adjusted_volume=beton_volume, + adjusted_volume=round(beton_volume,2), artifact_id=artifact_id ) print(f"任务 {erp_id} 的数据已保存到自定义数据表") except Exception as e: print(f"调用保存函数时出错: {e}") + + + return erp_id + + def save_to_custom_table(self,misid, flag, task_id, produce_mix_id, project_name, beton_grade, adjusted_volume, artifact_id): + print(f"保存到自定义数据表: MISID={misid}, Flag={flag}, TaskID={task_id}, 调整后方量={adjusted_volume}") + + def update_custom_table_status(self, erp_id, status): + print(f"更新自定义数据表状态: ERP ID={erp_id}, 状态={status}") diff --git a/tcp/server.py b/tcp/server.py index 91643ff..4461c03 100644 --- a/tcp/server.py +++ b/tcp/server.py @@ -108,7 +108,9 @@ class TCPServer: print(f"收到异常生产通知 - 时间: {timestamp}, ERP ID: {erp_id}") # 调用update_custom_table_status更新数据库状态 try: - update_custom_table_status(erp_id, "异常生产") + from services.task_service import TaskService + task_service = TaskService() + task_service.update_custom_table_status(erp_id, "异常生产") print(f"数据库状态已更新为: 异常生产 (ERP ID: {erp_id})") except Exception as e: print(f"更新数据库状态时出错: {e}") @@ -116,7 +118,9 @@ class TCPServer: print(f"收到中断生产通知 - 时间: {timestamp}, ERP ID: {erp_id}") # 调用update_custom_table_status更新数据库状态 try: - update_custom_table_status(erp_id, "取消生产") + from services.task_service import TaskService + task_service = TaskService() + task_service.update_custom_table_status(erp_id, "取消生产") print(f"数据库状态已更新为: 取消生产 (ERP ID: {erp_id})") except Exception as e: print(f"更新数据库状态时出错: {e}") diff --git a/temp.py b/temp.py index 2214966..a17eb97 100644 --- a/temp.py +++ b/temp.py @@ -415,7 +415,7 @@ def get_all_not_pour_info(app_id): # 添加这一行声明 { "ArtifactID": "QR1B32000153AD", - "ArtifactActionID": 346482967298128, + "ArtifactActionID": 346482967298140, "ArtifactIDVice1": "Q00001AD", "ProduceRingNumber": 1, "MouldCode": "SHR2B3-9", @@ -427,6 +427,6 @@ def get_all_not_pour_info(app_id): # 添加这一行声明 "HoleRingMarking": "否", "GroutingPipeMarking": "否", "PolypropyleneFiberMarking": "否", - "BetonVolume": 0.55, + "BetonVolume": 0.6, "BetonTaskID": "20251020-01" }, \ No newline at end of file diff --git a/zjsh_ui_sysytem/.idea/.gitignore b/zjsh_ui_sysytem/.idea/.gitignore deleted file mode 100644 index 359bb53..0000000 --- a/zjsh_ui_sysytem/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# 默认忽略的文件 -/shelf/ -/workspace.xml diff --git a/zjsh_ui_sysytem/.idea/inspectionProfiles/Project_Default.xml b/zjsh_ui_sysytem/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 78dfc6d..0000000 --- a/zjsh_ui_sysytem/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - \ No newline at end of file diff --git a/zjsh_ui_sysytem/.idea/inspectionProfiles/profiles_settings.xml b/zjsh_ui_sysytem/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/zjsh_ui_sysytem/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/zjsh_ui_sysytem/.idea/misc.xml b/zjsh_ui_sysytem/.idea/misc.xml deleted file mode 100644 index 62ef35e..0000000 --- a/zjsh_ui_sysytem/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/zjsh_ui_sysytem/.idea/modules.xml b/zjsh_ui_sysytem/.idea/modules.xml deleted file mode 100644 index acf6533..0000000 --- a/zjsh_ui_sysytem/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/zjsh_ui_sysytem/.idea/vcs.xml b/zjsh_ui_sysytem/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/zjsh_ui_sysytem/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/zjsh_ui_sysytem/.idea/zjsh_ui_sysytem.iml b/zjsh_ui_sysytem/.idea/zjsh_ui_sysytem.iml deleted file mode 100644 index 53e58ed..0000000 --- a/zjsh_ui_sysytem/.idea/zjsh_ui_sysytem.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/zjsh_ui_sysytem/README.md b/zjsh_ui_sysytem/README.md deleted file mode 100644 index edfe241..0000000 --- a/zjsh_ui_sysytem/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# zjsh_ui_sysytem - -中交三航精准布料浇筑要料系统 \ No newline at end of file diff --git a/zjsh_ui_sysytem/config/config.json b/zjsh_ui_sysytem/config/config.json deleted file mode 100644 index 65a36b5..0000000 --- a/zjsh_ui_sysytem/config/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后" -} diff --git a/zjsh_ui_sysytem/config/tcp_server.py b/zjsh_ui_sysytem/config/tcp_server.py deleted file mode 100644 index b46d34a..0000000 --- a/zjsh_ui_sysytem/config/tcp_server.py +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' -# @Time : 2025/9/19 09:48 -# @Author : reenrr -# @File : mock_server.py -''' -import socket -import json -import threading -import time -from datetime import datetime -import os - -class TCPServerSimulator: - def __init__(self, host='127.0.0.1', port=8888, config_file='config.json'): - self.host = host - self.port = port - self.server_socket = None - self.is_running = False - self.client_sockets = [] - self.config_file = config_file - - # 初始状态为None - self.data_template = None - - # 从配置文件中加载固定数据 - self.load_config_data() - - # 模拟数据模板 - if self.data_template is None: - self.data_template = { - "task_id": "None", - "project_name": "None", - "section": "None", - "slump": "None", - "mix_ratio_id": "None", - "request_status": "None", - "material_grade": "None", - "volume": "None", - "request_time": "None", - "car_status": "None" - } - - def load_config_data(self): - """从配置文件中加载固定数据""" - try: - if os.path.exists(self.config_file): - with open(self.config_file, 'r', encoding='utf-8') as f: - self.data_template = json.load(f) - print(f"成功从 {self.config_file} 加载配置数据") - else: - print(f"配置文件 {self.config_file} 不存在,将使用默认数据") - # 创建默认配置文件 - self.create_default_config() - except Exception as e: - print(f"加载配置文件时发生错误:{e},将使用默认数据") - self.data_template = None - - def create_default_config(self): - """创建默认配置文件""" - default_data = { - "task_id": "None", - "project_name": "None", - "section": "None", - "slump": "None", - "mix_ratio_id": "None", - "request_status": "None", - "material_grade": "None", - "volume": "None", - "request_time": "None", - "car_status": "None" - } - - try: - with open(self.config_file, 'w', encoding='utf-8') as f: - json.dump(default_data, f, ensure_ascii=False, indent=4) - print(f"已创建默认配置文件 {self.config_file}") - self.data_template = default_data - except Exception as e: - print(f"创建默认配置文件时发生错误: {e}") - self.data_template = None - - def start(self): - """启动服务器""" - self.is_running = True - self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.server_socket.bind((self.host, self.port)) - self.server_socket.listen(5) - print(f"服务器已启动,监听 {self.host}:{self.port}...") - - # 启动接受连接的线程 - accept_thread = threading.Thread(target=self.accept_connections, daemon=True) - accept_thread.start() - - try: - while self.is_running: - time.sleep(1) - except KeyboardInterrupt: - print("\n服务器正在关闭...") - self.stop() - - def accept_connections(self): - """接受客户端连接""" - while self.is_running: - try: - client_socket, client_address = self.server_socket.accept() - self.client_sockets.append(client_socket) - print(f"客户端 {client_address} 已连接") - - # 发送数据 - data = self.generate_simulated_data() - self.send_data(client_socket, data) - print(f"已向客户端 {client_address} 发送数据:{data}") - - # 启动一个线程监听客户端发送的指令 - threading.Thread( - target=self.listen_client_commands, - args=(client_socket,client_address), - daemon=True - ).start() - - except Exception as e: - if self.is_running: - print(f"接受连接时发生错误: {e}") - break - - def listen_client_commands(self, client_socket, client_address): - """监听客户端发送的指令""" - while self.is_running and client_socket in self.client_sockets: - try: - # 接收客户端发送的指令 - data = client_socket.recv(1024).decode('utf-8').strip() - if data: - print(f"客户端 {client_address} 发送指令: {data}") - else: - print(f"客户端 {client_address} 已断开连接") - self.client_sockets.remove(client_socket) - client_socket.close() - break - except Exception as e: - print(f"监听客户端 {client_address} 指令时发生错误: {e}") - self.client_sockets.remove(client_socket) - client_socket.close() - break - - def generate_simulated_data(self): - """生成模拟的状态数据""" - if self.data_template is None: - return None - - data = self.data_template.copy() - data["timestamp"] = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - - return data - - def send_data(self, client_socket, data): - """向客户端发送数据""" - try: - # 转换为JSON字符串并添加换行符作为结束标记 - if data is None: - data_str = json.dumps(None) + "\n" - else: - data_str = json.dumps(data) + "\n" - client_socket.sendall(data_str.encode('utf-8')) - except Exception as e: - print(f"向客户端 {client_socket.getpeername()} 发送数据时发生错误: {e}") - - def stop(self): - """停止服务器""" - self.is_running = False - - # 关闭所有客户端连接 - for sock in self.client_sockets: - try: - sock.close() - except Exception as e: - print(f"关闭客户端连接时发生错误: {e}") - - # 关闭服务器套接字 - if self.server_socket: - try: - self.server_socket.close() - except Exception as e: - print(f"关闭服务器套接字时发生错误: {e}") - - print("服务器已关闭") - -if __name__ == '__main__': - server = TCPServerSimulator(host='127.0.0.1', port=8888) - server.start() diff --git a/zjsh_ui_sysytem/img.png b/zjsh_ui_sysytem/img.png deleted file mode 100644 index 975dfcd..0000000 Binary files a/zjsh_ui_sysytem/img.png and /dev/null differ diff --git a/zjsh_ui_sysytem/img_1.png b/zjsh_ui_sysytem/img_1.png deleted file mode 100644 index 21a7abc..0000000 Binary files a/zjsh_ui_sysytem/img_1.png and /dev/null differ diff --git a/zjsh_ui_sysytem/img_2.png b/zjsh_ui_sysytem/img_2.png deleted file mode 100644 index 2799737..0000000 Binary files a/zjsh_ui_sysytem/img_2.png and /dev/null differ diff --git a/zjsh_ui_sysytem/main1.py b/zjsh_ui_sysytem/main1.py deleted file mode 100644 index f844033..0000000 --- a/zjsh_ui_sysytem/main1.py +++ /dev/null @@ -1,587 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' -# @Time : 2025/9/10 11:29 -# @Author : reenrr -# @File : test.py -''' -import sys -from PySide6.QtWidgets import ( - QApplication, QWidget, QVBoxLayout, QHBoxLayout, - QLabel, QFrame, QSizePolicy, QPushButton -) -from PySide6.QtCore import Qt, QTimer, QPoint, QSize, Slot -from PySide6.QtGui import QFont, QPainter, QColor, QPen, QIcon -from datetime import datetime -from PySide6.QtNetwork import QTcpSocket, QAbstractSocket -import json -import os - - -# ----------- -# 参数配置 -# ----------- -tcp_server_host = "127.0.0.1" -tcp_server_port = 8888 - -# 数据保存目录 -SAVE_DIR = "operation_records" - -class StatusMonitor(QWidget): - """ - 中交三航精准布料浇筑要料系统 - 主界面类(深色主题) - 使用TCP进行数据传输(客户端模型,与TCP服务器通信) - """ - - def __init__(self, parent=None): - """构造函数:初始化主界面的UI布局、控件和定时器""" - super().__init__(parent=parent) - self.is_running = False # 系统运行状态标记 - self.current_datetime = self.get_current_time() # 当前日期时间 - # 缓存服务端发送的最新JSON数据 - self.latest_json_data = {} - - # --------------- - # 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连接状态标记 - - # 绑定TCP信号与槽(事件驱动) - self._bind_tcp_signals() - - # 窗口基础设置 - self.setWindowTitle("中交三航精准布料浇筑要料系统") - self.setGeometry(100, 100, 850, 500) # 设置窗口位置和大小 - self.setStyleSheet("background-color: #121212;") # 窗口背景设为深黑色 - - # 初始化主布局(垂直布局) - self.mainLayout = QVBoxLayout(self) - self.mainLayout.setContentsMargins(10, 40, 10, 10) # 上边距留空用于显示日期 - self.mainLayout.setSpacing(10) # 相邻控件的间距 - - # 初始化界面组件 - self._init_title_label() - self._init_status_container() - self._init_timers() - self._init_save_dir() - - # ---------------- - # 客户端自动后自动连接服务端 - # ---------------- - print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...") - self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port) - - def _init_save_dir(self): - """初始化数据保存目录""" - if not os.path.exists(SAVE_DIR): - os.makedirs(SAVE_DIR) - print(f"已创建数据保存目录:{os.path.abspath(SAVE_DIR)}") - else: - print(f"数据保存目录已存在:{os.path.abspath(SAVE_DIR)}") - - 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_title_label(self): - """初始化系统标题标签""" - titleLabel = QLabel("中交三航精准布料浇筑要料系统") - titleLabel.setStyleSheet(""" - QLabel { - color: #00FF9D; - font-size: 20px; - font-weight: bold; - } - """) - titleLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - titleLabel.setFont(QFont("Microsoft YaHei", 24, QFont.Bold)) - self.mainLayout.addWidget(titleLabel) - - def _init_status_container(self): - """初始化核心状态监控容器(包含状态组和操作按钮)""" - self.bigContainer = QFrame() - self.bigContainer.setStyleSheet(""" - QFrame { - background-color: #1E1E1E; - border: 2px solid #333333; - border-radius: 8px; - } - """) - self.bigContainer.setSizePolicy( - QSizePolicy.Policy.Expanding, - QSizePolicy.Policy.Expanding - ) - - containerLayout = QVBoxLayout(self.bigContainer) - containerLayout.setContentsMargins(20, 20, 20, 20) - - self._init_status_groups(containerLayout) - self._init_operation_buttons(containerLayout) - - self.mainLayout.addWidget(self.bigContainer, 1) - - def _init_status_groups(self, parent_layout): - """初始化左右信息(各包含5个状态项)""" - statusWidget = QWidget() - statusLayout = QHBoxLayout(statusWidget) - statusLayout.setContentsMargins(0, 0, 0, 0) - statusLayout.setSpacing(30) # 减小中间空白间距(原30) - - leftGroup = QWidget() - leftLayout = QVBoxLayout(leftGroup) - leftLayout.setSpacing(15) - leftLayout.setContentsMargins(30, 0, 0, 0) # 左边组左内边距设为20,增加左边留白 - - rightGroup = QWidget() - rightLayout = QVBoxLayout(rightGroup) - rightLayout.setSpacing(15) - rightLayout.setContentsMargins(0, 0, 30, 0) # 右边组右内边距设为20,增加右边留白(若需左边也留白,可设左内边距) - - # 左边5个状态项及对应初始值 - leftStatusInfo = [ - {"name": "任务单号", "value": "20250706-01", "api_field": "task_id"}, - {"name": "工程名称", "value": "18号线二期工程", "api_field": "project_name"}, - {"name": "区间段", "value": "停车场工作并上行", "api_field": "section"}, - {"name": "坍落度", "value": "50~70 mm", "api_field": "slump"}, - {"name": "配合比编号", "value": "P2022=001", "api_field": "mix_ratio_id"} - ] - # 右边5个状态项及对应初始值 - rightStatusInfo = [ - {"name": "要料状态", "value": "请求中", "api_field": "request_status"}, - {"name": "要料标号", "value": "C50P12", "api_field": "material_grade"}, - {"name": "要料方量", "value": "2m³", "api_field": "volume"}, - {"name": "要料时间", "value": "2分钟后", "api_field": "request_time"}, - {"name": "小车状态", "value": "移动后", "api_field": "car_status"} - ] - self.statusWidgets = [] - - # 处理左边状态项 - for info in leftStatusInfo: - statusItem = self._create_status_item(info) - leftLayout.addWidget(statusItem) - - # 处理右边状态项 - for info in rightStatusInfo: - statusItem = self._create_status_item(info) - rightLayout.addWidget(statusItem) - - statusLayout.addWidget(leftGroup) - statusLayout.addStretch(0) # 减小中间空白比例(原1) - statusLayout.addWidget(rightGroup) - - parent_layout.addWidget(statusWidget) - - def _create_status_item(self, info): - """创建单个状态项""" - statusItem = QFrame() - statusItem.setStyleSheet(""" - QFrame { - background-color: #2D2D2D; - border: 1px solid #444444; - border-radius: 6px; - padding: 10px; - } - """) - statusItem.setFixedHeight(80) - statusItem.setFixedWidth(320) # 统一加长状态项宽度(原无固定宽度) - - itemLayout = QHBoxLayout(statusItem) - itemLayout.setContentsMargins(10, 5, 10, 5) - - # 状态指示灯 - indicator = QLabel() - indicator.setFixedSize(20, 20) - indicator.setStyleSheet(""" - QLabel { - background-color: #9E9E9E; - border-radius: 10px; - border: 2px solid #555555; - } - """) - - # 状态名称标签 - nameLabel = QLabel(info["name"]) - nameLabel.setFixedWidth(100) # 加宽名称标签(原90) - nameLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - nameLabel.setStyleSheet("font-size: 14px; color: #FFFFFF;") - nameLabel.setFont(QFont("Microsoft YaHei", 12)) - - # 状态值标签 - valueLabel = QLabel(info["value"]) - valueLabel.setStyleSheet(""" - QLabel { - font-size: 16px; - font-weight: bold; - color: #FFFFFF; - background-color: #2D2D2D; - border: none; - padding: 0px; - } - """) - valueLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - valueLabel.setMinimumWidth(150) # 加宽值标签(原80) - - itemLayout.addWidget(indicator) - itemLayout.addSpacing(10) - itemLayout.addWidget(nameLabel) - itemLayout.addStretch() - itemLayout.addWidget(valueLabel) - - self.statusWidgets.append({ - 'indicator': indicator, - 'nameLabel': nameLabel, - 'valueLabel': valueLabel, - 'status': False, - 'initial_value': info["value"], - 'api_field': info["api_field"] - }) - - return statusItem - - def _init_operation_buttons(self, parent_layout): - """初始化操作按钮(下料完成/生产异常/生产取消)""" - buttonContainer = QWidget() - buttonLayout = QHBoxLayout(buttonContainer) - buttonLayout.setContentsMargins(0, 20, 0, 0) - buttonLayout.setSpacing(30) - - # 按钮图标(需替换为实际图标路径) - start_icon_path = "img.png" - down_icon_path = "img.png" - error_icon_path = "img.png" - cancel_icon_path = "img.png" - - self.startFeedButton = QPushButton("开始下料") - self.finishButton = QPushButton("下料完成") - self.errorButton = QPushButton("生产异常") - self.cancelButton = QPushButton("生产取消") - - # 设置按钮图标 - self.startFeedButton.setIcon(QIcon(start_icon_path)) - self.finishButton.setIcon(QIcon(down_icon_path)) - self.errorButton.setIcon(QIcon(error_icon_path)) - self.cancelButton.setIcon(QIcon(cancel_icon_path)) - - # 设置图标大小 - self.startFeedButton.setIconSize(QSize(20, 20)) - self.finishButton.setIconSize(QSize(20, 20)) - self.errorButton.setIconSize(QSize(20, 20)) - self.cancelButton.setIconSize(QSize(20, 20)) - - button_base_style = """ - QPushButton { - font-size: 16px; - font-weight: bold; - padding: 10px 20px; - border-radius: 15px; - border: 1px solid; - min-width: 100px; - } - QPushButton:hover { - opacity: 0.9; - } - QPushButton:pressed { - opacity: 0.8; - } - """ - - self.startFeedButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #2196F3; - color: white; - border-color: #1976D2; - } - """) - - self.finishButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #00796B; - color: white; - border-color: #004D40; - } - """) - - self.errorButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #E65100; - color: white; - border-color: #BF360C; - } - """) - - self.cancelButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #C62828; - color: white; - border-color: #8E0000; - } - """) - - button_font = QFont("Microsoft YaHei", 12, QFont.Bold) - self.startFeedButton.setFont(button_font) - self.finishButton.setFont(button_font) - self.errorButton.setFont(button_font) - self.cancelButton.setFont(button_font) - - self.startFeedButton.clicked.connect(self.on_start_clicked) - self.finishButton.clicked.connect(self.on_finish_clicked) - self.errorButton.clicked.connect(self.on_error_clicked) - self.cancelButton.clicked.connect(self.on_cancel_clicked) - - # 初始禁用“停止”和“异常”按钮(未连接时不可用) - self.startFeedButton.setDisabled(False) - self.finishButton.setDisabled(True) - self.errorButton.setDisabled(True) - self.cancelButton.setDisabled(True) - - buttonLayout.addStretch(1) - buttonLayout.addWidget(self.startFeedButton) - buttonLayout.addWidget(self.finishButton) - buttonLayout.addWidget(self.errorButton) - buttonLayout.addWidget(self.cancelButton) - buttonLayout.addStretch(1) - - parent_layout.addWidget(buttonContainer) - - def _init_timers(self): - """初始化定时器(时间更新+状态模拟)""" - # 时间更新定时器(每秒更新一次) - self.time_timer = QTimer() - self.time_timer.timeout.connect(self.update_time) - self.time_timer.start(1000) - - def get_current_time(self): - """获取格式化的当前时间""" - return datetime.now().strftime('%Y-%m-%d %H:%M:%S') - - def get_timestamp(self): - """获取当前时间戳(秒级)""" - return datetime.now().strftime('%Y%m%d_%H%M%S_%f')[:-3] - - def update_time(self): - """更新时间显示并触发重绘""" - self.current_datetime = self.get_current_time() - self.update() # 触发paintEvent重绘 - - def paintEvent(self, event): - """重写绘画事件,在右上角绘制日期时间文本""" - super().paintEvent(event) # 调用父类方法保持原有绘制 - - # 创建QPainter对象 - painter = QPainter(self) - painter.setRenderHint(QPainter.RenderHint.TextAntialiasing) # 文本抗锯齿 - - # 设置字体 - font = QFont("Arial", 12, QFont.Bold) - painter.setFont(font) - - # 设置文本颜色 - painter.setPen(QColor("#00FF9D")) - - # 计算文本位置(右上角,留出边距) - text = f"🕒 {self.current_datetime}" - text_rect = painter.boundingRect(self.rect(), Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop, text) - x = self.width() - text_rect.width() - 15 # 右边距15px - y = 15 # 上边距15px - - # 绘制文本 - painter.drawText(x, y + text_rect.height(), text) - - def _save_data_to_file(self, button_name): - """ - 将服务端数据+按钮操作信息保存到JSON文件 - - 参数:button_name:点击的按钮名称 - """ - # 1、检查是否有服务端数据 - if not self.latest_server_data: - print(f"⚠️ 未收到服务端数据,无法保存「{button_name}」操作记录") - return - - # 2、构建完整数据(服务端数据+按钮操作信息+存档时间) - save_data = { - "opration_button": button_name, - "save_time": self.get_current_time(), - "server_data":self.latest_server_data - } - - # 3、生成唯一文件名(按时间戳命名) - file_name = f"operation_record_{self.get_timestamp()}.json" - file_path = os.path.join(SAVE_DIR, file_name) - - # 4、写入JSON文件 - try: - with open(file_path, "w", encoding="utf-8") as f: - json.dump(save_data, f, ensure_ascii=False, indent=4) - print(f"💾 保存「{button_name}」操作记录成功:{os.path.abspath(file_path)}") - except Exception as e: - print(f"💾 保存「{button_name}」操作记录失败:{str(e)}") - - # ------------------ - # TCP客户端核心功能 - # ------------------ - @Slot() - def _on_tcp_connected(self): - """TCP连接成功回调""" - self.is_tcp_connected = True - self.is_running = True - print(f"TCP连接成功:{self.tcp_server_host}:{self.tcp_server_port}") - - # 连接成功后,向服务器发送“请求初始数据”指令 - self._send_tcp_request("get_initial_data") - - # 更新按钮状态:启用“下料完成”“生产异常”“生产取消” - self.finishButton.setDisabled(False) - 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.startFeedButton.setDisabled(False) - self.finishButton.setDisabled(True) - 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_server_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错误回调""" - error_str = self.tcp_socket.errorString() - print(f"TCP错误:{error_str}") - self.is_tcp_connected = False - self.is_running = False - - # 启用/禁用按钮 - self.startFeedButton.setDisabled(False) - self.finishButton.setDisabled(True) - self.errorButton.setDisabled(True) - self.cancelButton.setDisabled(True) - - def _send_tcp_request(self, request_cmd="get_status"): - """向TCP服务器发送请求指令""" - if not self.is_tcp_connected: - print("TCP连接未建立,无法发送请求") - return - - # 构造请求数据 - request_data = json.dumps({ - "cmd": request_cmd, - "timestamp": self.get_current_time(), - "client_info": "布料系统客户端" - }) + "\n" # 增加换行符作为数据结束标识 - - # 发送请求数据 - self.tcp_socket.write(request_data.encode("utf-8")) - print(f"TCP请求发送:{request_data.strip()}") - - def _update_ui_from_data(self, data): - """根据TCP获取的数据更新界面状态""" - for widget in self.statusWidgets: - api_field = widget['api_field'] - if api_field in data: - new_value = str(data[api_field]) - widget['valueLabel'].setText(new_value) - self.set_indicator_status(widget, new_value) - - # ------------------ - # 状态指示灯逻辑 - # ------------------ - def set_indicator_status(self, widget, value): - """根据值设置状态指示灯颜色""" - if value and value != "未知" and value != "" and value != "None": - # 有效数据:绿色指示灯 - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #00E676; - border-radius: 10px; - border: 2px solid #00796B; - } - """) - else: - # 无效数据:红色指示灯 - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #FF5252; - border-radius: 10px; - border: 2px solid #C62828; - } - """) - - # ------------------ - # 按钮点击事件 - # ------------------ - def on_start_clicked(self): - """点击“开始下料”:向服务端发送开始指令""" - print("🔘 点击「开始下料」按钮") - if not self.is_tcp_connected: - print("TCP连接未建立,尝试重新连接") - self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port) - QTimer.singleShot(1000, lambda: self._send_tcp_request("start_feed")) # 等待连接成功后再发送请求 - else: - print("TCP连接已建立") - self._send_tcp_request("start_feed") - - def on_finish_clicked(self): - """点击“下料完成”:向服务端发送完成指令""" - print("🔘 点击「下料完成」按钮") - self._send_tcp_request("finish_feed") - self._save_data_to_file("finish_feed") - - def on_error_clicked(self): - """点击“生产异常”:向服务端发送异常指令""" - print("🔘 点击「生产异常」按钮") - self._send_tcp_request("production_error") - self._save_data_to_file("production_error") - - def on_cancel_clicked(self): - """点击“生产取消”:向服务端发送取消指令""" - print("🔘 点击「生产取消」按钮") - self._send_tcp_request("cancel_feed") - self._save_data_to_file("cancel_feed") - -if __name__ == "__main__": - app = QApplication(sys.argv) - window = StatusMonitor() - window.show() - sys.exit(app.exec()) diff --git a/zjsh_ui_sysytem/main2.py b/zjsh_ui_sysytem/main2.py deleted file mode 100644 index f6a5916..0000000 --- a/zjsh_ui_sysytem/main2.py +++ /dev/null @@ -1,569 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' -# @Time : 2025/10/31 14:39 -# @Author : reenrr -# @Description : 通过tcp连接获取信息,并显示在界面上(版本2) -# @File : main2.py -''' -import sys -from PySide6.QtWidgets import ( - QApplication, QWidget, QVBoxLayout, QHBoxLayout, - QLabel, QFrame, QSizePolicy, QPushButton -) -from PySide6.QtCore import Qt, QTimer, QPoint, QSize, Slot -from PySide6.QtGui import QFont, QPainter, QColor, QPen, QIcon -from datetime import datetime -from PySide6.QtNetwork import QTcpSocket, QAbstractSocket -import json -import os - - -# ----------- -# 参数配置 -# ----------- -tcp_server_host = "127.0.0.1" -tcp_server_port = 8888 - -# 数据保存目录 -SAVE_DIR = "operation_records" - -class StatusMonitor(QWidget): - """ - 中交三航精准布料浇筑要料系统 - 主界面类(深色主题) - 使用TCP进行数据传输(客户端模型,与TCP服务器通信) - """ - - def __init__(self, parent=None): - """构造函数:初始化主界面的UI布局、控件和定时器""" - super().__init__(parent=parent) - self.is_running = False # 系统运行状态标记 - self.current_datetime = self.get_current_time() # 当前日期时间 - # 缓存服务端发送的最新JSON数据(统一变量名,避免保存时出错) - self.latest_server_data = {} - - # --------------- - # 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连接状态标记 - - # 绑定TCP信号与槽(事件驱动) - self._bind_tcp_signals() - - # 窗口基础设置 - self.setWindowTitle("中交三航精准布料浇筑要料系统") - self.setGeometry(100, 100, 850, 500) # 设置窗口位置和大小 - self.setStyleSheet("background-color: #121212;") # 窗口背景设为深黑色 - - # 初始化主布局(垂直布局) - self.mainLayout = QVBoxLayout(self) - self.mainLayout.setContentsMargins(10, 40, 10, 10) # 上边距留空用于显示日期 - self.mainLayout.setSpacing(10) # 相邻控件的间距 - - # 初始化界面组件 - self._init_title_label() - self._init_status_container() - self._init_timers() - - # ---------------- - # 客户端自动连接服务端 - # ---------------- - print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...") - self.tcp_socket.connectToHost(self.tcp_server_host, self.tcp_server_port) - - 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_title_label(self): - """初始化系统标题标签""" - titleLabel = QLabel("中交三航精准布料浇筑要料系统") - titleLabel.setStyleSheet(""" - QLabel { - color: #00FF9D; - font-size: 20px; - font-weight: bold; - } - """) - titleLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - titleLabel.setFont(QFont("Microsoft YaHei", 24, QFont.Bold)) - self.mainLayout.addWidget(titleLabel) - - def _init_status_container(self): - """初始化核心状态监控容器(包含状态组和操作按钮)""" - self.bigContainer = QFrame() - self.bigContainer.setStyleSheet(""" - QFrame { - background-color: #1E1E1E; - border: 2px solid #333333; - border-radius: 8px; - } - """) - self.bigContainer.setSizePolicy( - QSizePolicy.Policy.Expanding, - QSizePolicy.Policy.Expanding - ) - - containerLayout = QVBoxLayout(self.bigContainer) - containerLayout.setContentsMargins(20, 20, 20, 20) - - self._init_status_groups(containerLayout) - self._init_operation_buttons(containerLayout) # 操作按钮包含新增的3个状态按钮 - - self.mainLayout.addWidget(self.bigContainer, 1) - - def _init_status_groups(self, parent_layout): - """初始化左右信息(各包含3个状态项)""" - statusWidget = QWidget() - statusLayout = QHBoxLayout(statusWidget) - statusLayout.setContentsMargins(0, 0, 0, 0) - statusLayout.setSpacing(30) # 减小中间空白间距 - - leftGroup = QWidget() - leftLayout = QVBoxLayout(leftGroup) - leftLayout.setSpacing(15) - leftLayout.setContentsMargins(30, 0, 0, 0) # 左边组左内边距 - - rightGroup = QWidget() - rightLayout = QVBoxLayout(rightGroup) - rightLayout.setSpacing(15) - rightLayout.setContentsMargins(0, 0, 30, 0) # 右边组右内边距 - - # 左边状态项 - leftStatusInfo = [ - {"name": "任务单号", "value": "", "api_field": "task_id"}, - {"name": "工程名称", "value": "", "api_field": "project_name"}, - {"name": "配比号", "value": "", "api_field": "produce_mix_id"} - ] - # 右边状态项 - rightStatusInfo = [ - {"name": "要料状态", "value": "", "api_field": "flag"}, - {"name": "砼强度", "value": "", "api_field": "beton_grade"}, - {"name": "要料方量", "value": "", "api_field": "adjusted_volume"}, - ] - self.statusWidgets = [] - - # 处理左边状态项 - for info in leftStatusInfo: - statusItem = self._create_status_item(info) - leftLayout.addWidget(statusItem) - - # 处理右边状态项 - for info in rightStatusInfo: - statusItem = self._create_status_item(info) - rightLayout.addWidget(statusItem) - - statusLayout.addWidget(leftGroup) - statusLayout.addStretch(0) - statusLayout.addWidget(rightGroup) - - parent_layout.addWidget(statusWidget) - - def _create_status_item(self, info): - """创建单个状态项""" - statusItem = QFrame() - statusItem.setStyleSheet(""" - QFrame { - background-color: #2D2D2D; - border: 1px solid #444444; - border-radius: 6px; - padding: 10px; - } - """) - statusItem.setFixedHeight(80) - statusItem.setFixedWidth(320) # 统一状态项宽度 - - itemLayout = QHBoxLayout(statusItem) - itemLayout.setContentsMargins(10, 5, 10, 5) - - # 状态指示灯 - indicator = QLabel() - indicator.setFixedSize(20, 20) - indicator.setStyleSheet(""" - QLabel { - background-color: #9E9E9E; - border-radius: 10px; - border: 2px solid #555555; - } - """) - - # 状态名称标签 - nameLabel = QLabel(info["name"]) - nameLabel.setFixedWidth(100) - nameLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - nameLabel.setStyleSheet("font-size: 14px; color: #FFFFFF;") - nameLabel.setFont(QFont("Microsoft YaHei", 12)) - - # 状态值标签 - valueLabel = QLabel(info["value"]) - valueLabel.setStyleSheet(""" - QLabel { - font-size: 16px; - font-weight: bold; - color: #FFFFFF; - background-color: #2D2D2D; - border: none; - padding: 0px; - } - """) - valueLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - valueLabel.setMinimumWidth(150) - - itemLayout.addWidget(indicator) - itemLayout.addSpacing(10) - itemLayout.addWidget(nameLabel) - itemLayout.addStretch() - itemLayout.addWidget(valueLabel) - - self.statusWidgets.append({ - 'indicator': indicator, - 'nameLabel': nameLabel, - 'valueLabel': valueLabel, - 'status': False, - 'initial_value': info["value"], - 'api_field': info["api_field"] - }) - - return statusItem - - def _init_operation_buttons(self, parent_layout): - """初始化操作按钮(新增未下料/下料中/下料完成 + 原有生产异常/生产取消)""" - buttonContainer = QWidget() - buttonLayout = QHBoxLayout(buttonContainer) - buttonLayout.setContentsMargins(0, 20, 0, 0) - buttonLayout.setSpacing(20) # 按钮间距(适配5个按钮,避免拥挤) - - # 按钮图标(复用现有图标路径,可根据需求替换) - status_icon_path = "img.png" # 状态类按钮(未下料/下料中/下料完成)共用图标 - error_icon_path = "img.png" - cancel_icon_path = "img.png" - - self.notFeedingBtn = QPushButton("未下料") # 未下料按钮 - self.feedingBtn = QPushButton("下料中") # 下料中按钮 - self.feedFinishBtn = QPushButton("下料完成")# 下料完成按钮 - self.errorButton = QPushButton("生产异常") - self.cancelButton = QPushButton("生产取消") - - # 设置按钮设置(图标、大小、样式) - status_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn] - for btn in status_buttons: - btn.setIcon(QIcon(status_icon_path)) - btn.setIconSize(QSize(20, 20)) - btn.setFont(QFont("Microsoft YaHei", 12, QFont.Bold)) - self.errorButton.setIcon(QIcon(error_icon_path)) - self.cancelButton.setIcon(QIcon(cancel_icon_path)) - self.errorButton.setIconSize(QSize(20, 20)) - self.cancelButton.setIconSize(QSize(20, 20)) - self.errorButton.setFont(QFont("Microsoft YaHei", 12, QFont.Bold)) - self.cancelButton.setFont(QFont("Microsoft YaHei", 12, QFont.Bold)) - - # 按钮基础样式(统一风格) - button_base_style = """ - QPushButton { - font-size: 16px; - font-weight: bold; - padding: 10px 15px; /* 缩小内边距,适配5个按钮布局 */ - border-radius: 15px; - border: 1px solid; - min-width: 90px; /* 缩小最小宽度 */ - } - QPushButton:hover { - opacity: 0.9; - } - QPushButton:pressed { - opacity: 0.8; - } - """ - - # 单个按钮样式(不同颜色区分状态) - self.notFeedingBtn.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #616161; /* 灰色:未开始状态 */ - color: white; - border-color: #424242; - } - """) - self.feedingBtn.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #2196F3; /* 蓝色:进行中状态 */ - color: white; - border-color: #1976D2; - } - """) - self.feedFinishBtn.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #4CAF50; /* 绿色:完成状态 */ - color: white; - border-color: #388E3C; - } - """) - - self.errorButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #E65100; - color: white; - border-color: #BF360C; - } - """) - self.cancelButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #C62828; - color: white; - border-color: #8E0000; - } - """) - - # ---------------- 绑定按钮点击事件 ---------------- - self.notFeedingBtn.clicked.connect(self.on_not_feeding_clicked) - self.feedingBtn.clicked.connect(self.on_feeding_clicked) - self.feedFinishBtn.clicked.connect(self.on_feed_finish_clicked) - self.errorButton.clicked.connect(self.on_error_clicked) - self.cancelButton.clicked.connect(self.on_cancel_clicked) - - # ---------------- 初始禁用所有按钮(TCP连接后启用) ---------------- - all_buttons = status_buttons + [self.errorButton, self.cancelButton] - for btn in all_buttons: - btn.setDisabled(True) - - # ---------------- 按钮布局(5个按钮横向排列) ---------------- - buttonLayout.addStretch(1) - buttonLayout.addWidget(self.notFeedingBtn) - buttonLayout.addWidget(self.feedingBtn) - buttonLayout.addWidget(self.feedFinishBtn) - buttonLayout.addWidget(self.errorButton) - buttonLayout.addWidget(self.cancelButton) - buttonLayout.addStretch(1) - - parent_layout.addWidget(buttonContainer) - - def _init_timers(self): - """初始化定时器(时间更新+状态模拟)""" - # 时间更新定时器(每秒更新一次) - self.time_timer = QTimer() - self.time_timer.timeout.connect(self.update_time) - self.time_timer.start(1000) - - def get_current_time(self): - """获取格式化的当前时间""" - return datetime.now().strftime('%Y-%m-%d %H:%M:%S') - - def get_timestamp(self): - """获取当前时间戳(秒级)""" - return datetime.now().strftime('%Y%m%d_%H%M%S_%f')[:-3] - - def update_time(self): - """更新时间显示并触发重绘""" - self.current_datetime = self.get_current_time() - self.update() # 触发paintEvent重绘 - - def paintEvent(self, event): - """重写绘画事件,在右上角绘制日期时间文本""" - super().paintEvent(event) # 调用父类方法保持原有绘制 - - # 创建QPainter对象 - painter = QPainter(self) - painter.setRenderHint(QPainter.RenderHint.TextAntialiasing) # 文本抗锯齿 - - # 设置字体 - font = QFont("Arial", 12, QFont.Bold) - painter.setFont(font) - - # 设置文本颜色 - painter.setPen(QColor("#00FF9D")) - - # 计算文本位置(右上角,留出边距) - text = f"🕒 {self.current_datetime}" - text_rect = painter.boundingRect(self.rect(), Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop, text) - x = self.width() - text_rect.width() - 15 # 右边距15px - y = 15 # 上边距15px - - # 绘制文本 - painter.drawText(x, y + text_rect.height(), text) - - # -------------------- - # 清空界面信息的通用方法 - # -------------------- - def _clear_ui_info(self): - """清空所有状态项的显示内容,并并设置指示灯颜色""" - for widget in self.statusWidgets: - widget['valueLabel'].setText("") - # 指示灯设为初始灰色(与_create_status_item中初始样式一致) - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #9E9E9E; - border-radius: 10px; - border: 2px solid #555555; - } - """) - print("ℹ️ 界面信息已清空") - - # ------------------ - # TCP客户端核心功能 - # ------------------ - @Slot() - def _on_tcp_connected(self): - """TCP连接成功回调:启用所有操作按钮""" - self.is_tcp_connected = True - self.is_running = True - print(f"TCP连接成功:{self.tcp_server_host}:{self.tcp_server_port}") - - # 连接成功后,向服务器发送“请求初始数据”指令 - self._send_tcp_request("get_initial_data") - - # 启用所有操作按钮(新增的3个状态按钮+原有2个功能按钮) - all_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn, self.errorButton, self.cancelButton] - for btn in all_buttons: - btn.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}") - - # 禁用所有操作按钮 - all_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn, self.errorButton, self.cancelButton] - for btn in all_buttons: - btn.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_server_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错误回调:禁用所有操作按钮""" - error_str = self.tcp_socket.errorString() - print(f"TCP错误:{error_str}") - self.is_tcp_connected = False - self.is_running = False - - # 禁用所有操作按钮 - all_buttons = [self.notFeedingBtn, self.feedingBtn, self.feedFinishBtn, self.errorButton, self.cancelButton] - for btn in all_buttons: - btn.setDisabled(True) - - def _send_tcp_request(self, request_cmd="get_status"): - """向TCP服务器发送请求指令""" - if not self.is_tcp_connected: - print("TCP连接未建立,无法发送请求") - return - - # 构造请求数据 - request_data = json.dumps({ - "cmd": request_cmd, - "timestamp": self.get_current_time(), - "client_info": "布料系统客户端" - }) + "\n" # 增加换行符作为数据结束标识 - - # 发送请求数据 - self.tcp_socket.write(request_data.encode("utf-8")) - print(f"TCP请求发送:{request_data.strip()}") - - def _update_ui_from_data(self, data): - """根据TCP获取的数据更新界面状态""" - for widget in self.statusWidgets: - api_field = widget['api_field'] - if api_field in data: - new_value = str(data[api_field]) - widget['valueLabel'].setText(new_value) - self.set_indicator_status(widget, new_value) - - # ------------------ - # 状态指示灯逻辑 - # ------------------ - def set_indicator_status(self, widget, value): - """根据值设置状态指示灯颜色""" - if value and value != "未知" and value != "" and value != "None": - # 有效数据:绿色指示灯 - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #00E676; - border-radius: 10px; - border: 2px solid #00796B; - } - """) - else: - # 无效数据:红色指示灯 - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #FF5252; - border-radius: 10px; - border: 2px solid #C62828; - } - """) - - # ------------------ - # 按钮点击事件 - # ------------------ - def on_not_feeding_clicked(self): - """点击“未下料”:向服务端发送“未下料”状态指令""" - print("🔘 点击「未下料」按钮") - self._clear_ui_info() - self._send_tcp_request("not_feeding") # 指令名可根据服务端需求修改 - - def on_feeding_clicked(self): - """点击“下料中”:向服务端发送“下料中”状态指令""" - print("🔘 点击「下料中」按钮") - self._clear_ui_info() - self._send_tcp_request("feeding") # 指令名可根据服务端需求修改 - - def on_feed_finish_clicked(self): - """点击“下料完成”:向服务端发送“下料完成”状态指令""" - print("🔘 点击「下料完成」按钮") - self._clear_ui_info() - self._send_tcp_request("feed_finish") # 指令名可根据服务端需求修改 - - 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") - -if __name__ == "__main__": - app = QApplication(sys.argv) - window = StatusMonitor() - window.show() - sys.exit(app.exec()) \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20250919_205501_791.json b/zjsh_ui_sysytem/operation_records/operation_record_20250919_205501_791.json deleted file mode 100644 index 6c2182f..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20250919_205501_791.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "opration_button": "finish_feed", - "save_time": "2025-09-19 20:55:01", - "server_data": { - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后", - "timestamp": "2025-09-19 20:54:55" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20250930_095113_723.json b/zjsh_ui_sysytem/operation_records/operation_record_20250930_095113_723.json deleted file mode 100644 index af1c026..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20250930_095113_723.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "opration_button": "finish_feed", - "save_time": "2025-09-30 09:51:13", - "server_data": { - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后", - "timestamp": "2025-09-30 09:50:58" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251029_110426_514.json b/zjsh_ui_sysytem/operation_records/operation_record_20251029_110426_514.json deleted file mode 100644 index d7da5cb..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251029_110426_514.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-29 11:04:26", - "server_data": { - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后", - "timestamp": "2025-10-29 11:02:19" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251029_202725_958.json b/zjsh_ui_sysytem/operation_records/operation_record_20251029_202725_958.json deleted file mode 100644 index 650d487..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251029_202725_958.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-29 20:27:25", - "server_data": { - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后", - "timestamp": "2025-10-29 20:27:12" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_105441_898.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_105441_898.json deleted file mode 100644 index 9723132..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_105441_898.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 10:54:41", - "server_data": { - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后", - "timestamp": "2025-10-30 10:54:40" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_105520_002.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_105520_002.json deleted file mode 100644 index b411941..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_105520_002.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 10:55:20", - "server_data": { - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后", - "timestamp": "2025-10-30 10:55:18" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_105523_098.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_105523_098.json deleted file mode 100644 index 6bb41c3..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_105523_098.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "opration_button": "cancel_feed", - "save_time": "2025-10-30 10:55:23", - "server_data": { - "task_id": "20250706-01", - "project_name": "18号线二期工程", - "section": "停车场工作井上行", - "slump": "50~70 mm", - "mix_ratio_id": "P2022=001", - "request_status": "请求中", - "material_grade": "C50P12", - "volume": "2m³", - "request_time": "10分钟后", - "car_status": "移动后", - "timestamp": "2025-10-30 10:55:18" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_170942_670.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_170942_670.json deleted file mode 100644 index 1cf9e4e..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_170942_670.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 17:09:42", - "server_data": { - "erp_id": 82728, - "status": "数据已接收" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171000_812.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_171000_812.json deleted file mode 100644 index 473e13e..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171000_812.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 17:10:00", - "server_data": { - "erp_id": 82728, - "status": "数据已接收" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171004_403.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_171004_403.json deleted file mode 100644 index a1c9c40..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171004_403.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 17:10:04", - "server_data": { - "erp_id": 82728, - "status": "数据已接收" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171008_419.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_171008_419.json deleted file mode 100644 index 98730f1..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171008_419.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 17:10:08", - "server_data": { - "erp_id": 82728, - "status": "数据已接收" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171022_493.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_171022_493.json deleted file mode 100644 index 57cb891..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171022_493.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 17:10:22", - "server_data": { - "erp_id": 82728, - "status": "数据已接收" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171024_108.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_171024_108.json deleted file mode 100644 index edc6cec..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_171024_108.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 17:10:24", - "server_data": { - "erp_id": 82728, - "status": "数据已接收" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/operation_records/operation_record_20251030_182057_822.json b/zjsh_ui_sysytem/operation_records/operation_record_20251030_182057_822.json deleted file mode 100644 index ac4a7d1..0000000 --- a/zjsh_ui_sysytem/operation_records/operation_record_20251030_182057_822.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "opration_button": "production_error", - "save_time": "2025-10-30 18:20:57", - "server_data": { - "erp_id": 82729, - "status": "数据已接收" - } -} \ No newline at end of file diff --git a/zjsh_ui_sysytem/test.py b/zjsh_ui_sysytem/test.py deleted file mode 100644 index aa87988..0000000 --- a/zjsh_ui_sysytem/test.py +++ /dev/null @@ -1,586 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' -# @Time : 2025/9/10 11:29 -# @Author : reenrr -# @Description : 在main函数的基础上添加了重连机制(为连接成功) -# @File : test.py -''' -import sys -from PySide6.QtWidgets import ( - QApplication, QWidget, QVBoxLayout, QHBoxLayout, - QLabel, QFrame, QSizePolicy, QPushButton -) -from PySide6.QtCore import Qt, QTimer, QPoint, QSize, Slot -from PySide6.QtGui import QFont, QPainter, QColor, QPen, QIcon -from datetime import datetime -from PySide6.QtNetwork import QTcpSocket, QAbstractSocket -import json -import os - - -# ----------- -# 参数配置 -# ----------- -tcp_server_host = "127.0.0.1" -tcp_server_port = 8888 - -# 数据保存目录 -SAVE_DIR = "operation_records" -MAX_RECONNECT = 3 # 最大重连次数 -RECONNECT_INTERVAL = 2000 # 重连间隔(毫秒) - -class StatusMonitor(QWidget): - """ - 中交三航精准布料浇筑要料系统 - 主界面类(深色主题) - 使用TCP进行数据传输(客户端模型,与TCP服务器通信) - """ - def __init__(self, parent=None): - """构造函数:初始化主界面的UI布局、控件和定时器""" - super().__init__(parent=parent) - self.is_running = False # 系统运行状态标记 - self.current_datetime = self.get_current_time() # 当前日期时间 - # 缓存服务端发送的最新JSON数据 - self.latest_json_data = {} - - # --------------- - # 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.setWindowTitle("中交三航精准布料浇筑要料系统") - self.setGeometry(100, 100, 850, 500) # 设置窗口位置和大小 - self.setStyleSheet("background-color: #121212;") # 窗口背景设为深黑色 - - # 初始化主布局(垂直布局) - self.mainLayout = QVBoxLayout(self) - self.mainLayout.setContentsMargins(10, 40, 10, 10) # 上边距留空用于显示日期 - self.mainLayout.setSpacing(10) # 相邻控件的间距 - - # 初始化界面组件 - self._init_title_label() - self._init_status_container() - self._init_timers() - self._init_save_dir() - - # ---------------- - # 客户端自动后自动连接服务端 - # ---------------- - print(f"客户端启动,自动连接服务端{self.tcp_server_host}:{self.tcp_server_port}...") - self._connect_to_server() - - 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 _init_save_dir(self): - """初始化数据保存目录""" - if not os.path.exists(SAVE_DIR): - os.makedirs(SAVE_DIR) - print(f"已创建数据保存目录:{os.path.abspath(SAVE_DIR)}") - else: - print(f"数据保存目录已存在:{os.path.abspath(SAVE_DIR)}") - - 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_title_label(self): - """初始化系统标题标签""" - titleLabel = QLabel("中交三航精准布料浇筑要料系统") - titleLabel.setStyleSheet(""" - QLabel { - color: #00FF9D; - font-size: 20px; - font-weight: bold; - } - """) - titleLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - titleLabel.setFont(QFont("Microsoft YaHei", 24, QFont.Bold)) - self.mainLayout.addWidget(titleLabel) - - def _init_status_container(self): - """初始化核心状态监控容器(包含状态组和操作按钮)""" - self.bigContainer = QFrame() - self.bigContainer.setStyleSheet(""" - QFrame { - background-color: #1E1E1E; - border: 2px solid #333333; - border-radius: 8px; - } - """) - self.bigContainer.setSizePolicy( - QSizePolicy.Policy.Expanding, - QSizePolicy.Policy.Expanding - ) - - containerLayout = QVBoxLayout(self.bigContainer) - containerLayout.setContentsMargins(20, 20, 20, 20) - - self._init_status_groups(containerLayout) - self._init_operation_buttons(containerLayout) - - self.mainLayout.addWidget(self.bigContainer, 1) - - def _init_status_groups(self, parent_layout): - """初始化左右信息(各包含3个状态项)""" - statusWidget = QWidget() - statusLayout = QHBoxLayout(statusWidget) - statusLayout.setContentsMargins(0, 0, 0, 0) - statusLayout.setSpacing(30) # 减小中间空白间距(原30) - - leftGroup = QWidget() - leftLayout = QVBoxLayout(leftGroup) - leftLayout.setSpacing(15) - leftLayout.setContentsMargins(30, 0, 0, 0) # 左边组左内边距设为20,增加左边留白 - - rightGroup = QWidget() - rightLayout = QVBoxLayout(rightGroup) - rightLayout.setSpacing(15) - rightLayout.setContentsMargins(0, 0, 30, 0) # 右边组右内边距设为20,增加右边留白(若需左边也留白,可设左内边距) - - # 左边5个状态项及对应初始值 - leftStatusInfo = [ - {"name": "任务单号", "value": "", "api_field": "task_id"}, - {"name": "工程名称", "value": "", "api_field": "project_name"}, - {"name": "配比号", "value": "", "api_field": "produce_mix_id"} - ] - # 右边5个状态项及对应初始值 - rightStatusInfo = [ - {"name": "要料状态", "value": "", "api_field": "flag"}, - {"name": "砼强度", "value": "", "api_field": "beton_grade"}, - {"name": "要料方量", "value": "", "api_field": "adjusted_volume"}, - ] - self.statusWidgets = [] - - # 处理左边状态项 - for info in leftStatusInfo: - statusItem = self._create_status_item(info) - leftLayout.addWidget(statusItem) - - # 处理右边状态项 - for info in rightStatusInfo: - statusItem = self._create_status_item(info) - rightLayout.addWidget(statusItem) - - statusLayout.addWidget(leftGroup) - statusLayout.addStretch(0) # 减小中间空白比例(原1) - statusLayout.addWidget(rightGroup) - - parent_layout.addWidget(statusWidget) - - def _create_status_item(self, info): - """创建单个状态项""" - statusItem = QFrame() - statusItem.setStyleSheet(""" - QFrame { - background-color: #2D2D2D; - border: 1px solid #444444; - border-radius: 6px; - padding: 10px; - } - """) - statusItem.setFixedHeight(80) - statusItem.setFixedWidth(320) # 统一加长状态项宽度(原无固定宽度) - - itemLayout = QHBoxLayout(statusItem) - itemLayout.setContentsMargins(10, 5, 10, 5) - - # 状态指示灯 - indicator = QLabel() - indicator.setFixedSize(20, 20) - indicator.setStyleSheet(""" - QLabel { - background-color: #9E9E9E; - border-radius: 10px; - border: 2px solid #555555; - } - """) - - # 状态名称标签 - nameLabel = QLabel(info["name"]) - nameLabel.setFixedWidth(100) # 加宽名称标签(原90) - nameLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - nameLabel.setStyleSheet("font-size: 14px; color: #FFFFFF;") - nameLabel.setFont(QFont("Microsoft YaHei", 12)) - - # 状态值标签 - valueLabel = QLabel(info["value"]) - valueLabel.setStyleSheet(""" - QLabel { - font-size: 16px; - font-weight: bold; - color: #FFFFFF; - background-color: #2D2D2D; - border: none; - padding: 0px; - } - """) - valueLabel.setAlignment(Qt.AlignmentFlag.AlignCenter) - valueLabel.setMinimumWidth(150) # 加宽值标签(原80) - - itemLayout.addWidget(indicator) - itemLayout.addSpacing(10) - itemLayout.addWidget(nameLabel) - itemLayout.addStretch() - itemLayout.addWidget(valueLabel) - - self.statusWidgets.append({ - 'indicator': indicator, - 'nameLabel': nameLabel, - 'valueLabel': valueLabel, - 'status': False, - 'initial_value': info["value"], - 'api_field': info["api_field"] - }) - - return statusItem - - def _init_operation_buttons(self, parent_layout): - """初始化操作按钮(下料完成/生产异常/生产取消)""" - buttonContainer = QWidget() - buttonLayout = QHBoxLayout(buttonContainer) - buttonLayout.setContentsMargins(0, 20, 0, 0) - buttonLayout.setSpacing(30) - - # 按钮图标(需替换为实际图标路径) - error_icon_path = "img.png" - cancel_icon_path = "img.png" - - self.errorButton = QPushButton("生产异常") - self.cancelButton = QPushButton("生产取消") - - # 设置按钮图标 - self.errorButton.setIcon(QIcon(error_icon_path)) - self.cancelButton.setIcon(QIcon(cancel_icon_path)) - - # 设置图标大小 - self.errorButton.setIconSize(QSize(20, 20)) - self.cancelButton.setIconSize(QSize(20, 20)) - - button_base_style = """ - QPushButton { - font-size: 16px; - font-weight: bold; - padding: 10px 20px; - border-radius: 15px; - border: 1px solid; - min-width: 100px; - } - QPushButton:hover { - opacity: 0.9; - } - QPushButton:pressed { - opacity: 0.8; - } - """ - self.errorButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #E65100; - color: white; - border-color: #BF360C; - } - """) - - self.cancelButton.setStyleSheet(button_base_style + """ - QPushButton { - background-color: #C62828; - color: white; - border-color: #8E0000; - } - """) - - button_font = QFont("Microsoft YaHei", 12, QFont.Bold) - self.errorButton.setFont(button_font) - self.cancelButton.setFont(button_font) - - 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 _init_timers(self): - """初始化定时器(时间更新+状态模拟)""" - # 时间更新定时器(每秒更新一次) - self.time_timer = QTimer() - self.time_timer.timeout.connect(self.update_time) - self.time_timer.start(1000) - - def get_current_time(self): - """获取格式化的当前时间""" - return datetime.now().strftime('%Y-%m-%d %H:%M:%S') - - def get_timestamp(self): - """获取当前时间戳(秒级)""" - return datetime.now().strftime('%Y%m%d_%H%M%S_%f')[:-3] - - def update_time(self): - """更新时间显示并触发重绘""" - self.current_datetime = self.get_current_time() - self.update() # 触发paintEvent重绘 - - def paintEvent(self, event): - """重写绘画事件,在右上角绘制日期时间文本""" - super().paintEvent(event) # 调用父类方法保持原有绘制 - - # 创建QPainter对象 - painter = QPainter(self) - painter.setRenderHint(QPainter.RenderHint.TextAntialiasing) # 文本抗锯齿 - - # 设置字体 - font = QFont("Arial", 12, QFont.Bold) - painter.setFont(font) - - # 设置文本颜色 - painter.setPen(QColor("#00FF9D")) - - # 计算文本位置(右上角,留出边距) - text = f"🕒 {self.current_datetime}" - text_rect = painter.boundingRect(self.rect(), Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignTop, text) - x = self.width() - text_rect.width() - 15 # 右边距15px - y = 15 # 上边距15px - - # 绘制文本 - painter.drawText(x, y + text_rect.height(), text) - - # ------------------ - # 数据保存 - # ------------------ - def _save_data_to_file(self, button_name): - """ - 将服务端数据+按钮操作信息保存到JSON文件 - - 参数:button_name:点击的按钮名称 - """ - # 1、检查是否有服务端数据 - if not self.latest_server_data: - print(f"⚠️ 未收到服务端数据,无法保存「{button_name}」操作记录") - return - - # 2、构建完整数据(服务端数据+按钮操作信息+存档时间) - save_data = { - "opration_button": button_name, - "save_time": self.get_current_time(), - "server_data":self.latest_server_data - } - - # 3、生成唯一文件名(按时间戳命名) - file_name = f"operation_record_{self.get_timestamp()}.json" - file_path = os.path.join(SAVE_DIR, file_name) - - # 4、写入JSON文件 - try: - with open(file_path, "w", encoding="utf-8") as f: - json.dump(save_data, f, ensure_ascii=False, indent=4) - print(f"💾 保存「{button_name}」操作记录成功:{os.path.abspath(file_path)}") - except Exception as e: - print(f"💾 保存「{button_name}」操作记录失败:{str(e)}") - - # -------------------- - # 清空界面信息的通用方法 - # -------------------- - def _clear_ui_info(self): - """清空所有状态项的显示内容,并并设置指示灯颜色""" - for widget in self.statusWidgets: - widget['valueLabel'].setText("") - # 指示灯设为初始灰色(与_create_status_item中初始样式一致) - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #9E9E9E; - border-radius: 10px; - border: 2px solid #555555; - } - """) - 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) - print(status_data) - self.latest_server_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 - - # 构造请求数据 - request_data = json.dumps({ - "cmd": request_cmd, - "timestamp": self.get_current_time(), - "client_info": "布料系统客户端", - "erp_id": self.latest_server_data.get('erp_id') - }) + "\n" # 增加换行符作为数据结束标识 - - # 发送请求数据 - self.tcp_socket.write(request_data.encode("utf-8")) - print(f"TCP请求发送:{request_data.strip()}") - - def _update_ui_from_data(self, data): - """根据TCP获取的数据更新界面状态""" - for widget in self.statusWidgets: - api_field = widget['api_field'] - if api_field in data: - new_value = str(data[api_field]) - widget['valueLabel'].setText(new_value) - self.set_indicator_status(widget, new_value) - - # ------------------ - # 状态指示灯逻辑 - # ------------------ - def set_indicator_status(self, widget, value): - """根据值设置状态指示灯颜色""" - if value and value != "未知" and value != "" and value != "None": - # 有效数据:绿色指示灯 - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #00E676; - border-radius: 10px; - border: 2px solid #00796B; - } - """) - else: - # 无效数据:红色指示灯 - widget['indicator'].setStyleSheet(""" - QLabel { - background-color: #FF5252; - border-radius: 10px; - border: 2px solid #C62828; - } - """) - - # ------------------ - # 按钮点击事件 - # ------------------ - 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") - -if __name__ == "__main__": - app = QApplication(sys.argv) - window = StatusMonitor() - window.show() - sys.exit(app.exec()) \ No newline at end of file