From 6c33eeb3bfc7c27f9d53d3837608fca60cae6bcb Mon Sep 17 00:00:00 2001 From: zhu-mengmeng <15588200382@163.com> Date: Sat, 26 Jul 2025 13:31:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E6=89=98=E7=9B=98?= =?UTF-8?q?=E5=8C=85=E8=A3=85=E7=BB=9F=E8=AE=A1=E6=95=B0=E6=8D=AE=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E9=80=BB=E8=BE=91=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=B8=85?= =?UTF-8?q?=E9=99=A4=E7=BC=93=E5=AD=98=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=B8=BB=E7=AA=97=E5=8F=A3=E5=92=8CAPI=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apis/gc_api.py | 72 +++++++++++++++++++++++++++++++++++++---- db/jtDB.db | Bin 1421312 -> 1433600 bytes from pymodbus.py | 2 +- widgets/main_window.py | 53 +++++++++++++++++++++--------- 4 files changed, 103 insertions(+), 24 deletions(-) diff --git a/apis/gc_api.py b/apis/gc_api.py index 10ca510..609fe8c 100644 --- a/apis/gc_api.py +++ b/apis/gc_api.py @@ -1,6 +1,7 @@ import requests import json import logging +import time from utils.config_loader import ConfigLoader from utils.api_utils import ApiUtils @@ -10,6 +11,11 @@ class GcApi: def __init__(self): """初始化API接口""" self.api_utils = ApiUtils() + + # 添加缓存相关属性 + self._tray_stats_cache = {} # 缓存数据 + self._tray_stats_cache_time = {} # 缓存时间 + self._cache_ttl = 5 # 缓存有效期(秒) def ismt_option(self, params): @@ -398,8 +404,7 @@ class GcApi: return {"status": False, "message": str(e)} def get_tray_package_statistics(self, order_id, tray_id, corp_id): - """ - 获取托盘包装统计数据 + """获取托盘包装统计信息 Args: order_id: 订单号 @@ -407,8 +412,20 @@ class GcApi: corp_id: 公司ID Returns: - dict: 包含托盘完成轴数和托盘完成数量的字典 + dict: 托盘包装统计信息 """ + # 生成缓存键 + cache_key = f"{order_id}_{tray_id}_{corp_id}" + + # 检查缓存是否有效 + current_time = time.time() + if (cache_key in self._tray_stats_cache and + current_time - self._tray_stats_cache_time.get(cache_key, 0) < self._cache_ttl): + logging.info(f"使用缓存数据: getBzNumByTrayWszb.do, 参数={order_id}, {tray_id}") + return self._tray_stats_cache[cache_key] + + # 原有API调用逻辑 + logging.info(f"调用API: getBzNumByTrayWszb.do, 参数={order_id}, {tray_id}") try: # API 配置中的键名 api_key = "get_tray_package_statistics" @@ -419,6 +436,12 @@ class GcApi: "data_corp": corp_id } response = self.api_utils.get(api_key, params=params) + + if response and response.get('status', False): + # 更新缓存 + self._tray_stats_cache[cache_key] = response + self._tray_stats_cache_time[cache_key] = current_time + return response except Exception as e: logging.error(f"获取托盘包装统计数据失败: {str(e)}") @@ -426,7 +449,7 @@ class GcApi: def get_spack_info(self, order_id, tray_id, corp_id): """ - 获取托盘包装统计数据 + 获取spack信息 Args: order_id: 订单号 @@ -434,7 +457,7 @@ class GcApi: corp_id: 公司ID Returns: - dict: 包含托盘完成轴数和托盘完成数量的字典 + dict: 包含spack信息的字典 """ try: # API 配置中的键名 @@ -448,5 +471,40 @@ class GcApi: response = self.api_utils.get(api_key, params=params) return response except Exception as e: - logging.error(f"获取托盘包装统计数据失败: {str(e)}") - return {"status": False, "message": str(e)} \ No newline at end of file + logging.error(f"获取spack信息失败: {str(e)}") + return {"status": False, "message": str(e)} + + def clear_tray_stats_cache(self, order_id=None, tray_id=None, corp_id=None): + """清除托盘统计数据缓存 + + Args: + order_id: 订单号,如果为None则清除所有缓存 + tray_id: 托盘号,如果为None则清除该订单的所有缓存 + corp_id: 公司ID,如果为None则清除该订单和托盘的所有缓存 + """ + if order_id is None: + # 清除所有缓存 + self._tray_stats_cache = {} + self._tray_stats_cache_time = {} + logging.info("已清除所有托盘统计数据缓存") + return + + # 清除特定缓存 + keys_to_remove = [] + prefix = f"{order_id}_" + if tray_id: + prefix += f"{tray_id}_" + if corp_id: + prefix += f"{corp_id}" + + for key in list(self._tray_stats_cache.keys()): + if key.startswith(prefix): + keys_to_remove.append(key) + + for key in keys_to_remove: + if key in self._tray_stats_cache: + del self._tray_stats_cache[key] + if key in self._tray_stats_cache_time: + del self._tray_stats_cache_time[key] + + logging.info(f"已清除托盘统计数据缓存: 前缀={prefix}, 清除数量={len(keys_to_remove)}") \ No newline at end of file diff --git a/db/jtDB.db b/db/jtDB.db index 1a99e2084b9c17952b15a6a2dcd27f75080f1f82..ea75ffd59cabefc82d1410ea30472c692fd987e9 100644 GIT binary patch delta 6612 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 diff --git a/from pymodbus.py b/from pymodbus.py index 464498d..37c95f2 100644 --- a/from pymodbus.py +++ b/from pymodbus.py @@ -2,7 +2,7 @@ from pymodbus.client import ModbusTcpClient import time client = ModbusTcpClient('localhost', port=5020) client.connect() -client.write_registers(address=11, values=[5062]) +client.write_registers(address=11, values=[12900]) # client.write_registers(address=3, values=[0]) # time.sleep(2) # client.write_registers(address=0, values=[0]) diff --git a/widgets/main_window.py b/widgets/main_window.py index 8f6ed04..2a1c393 100644 --- a/widgets/main_window.py +++ b/widgets/main_window.py @@ -1391,6 +1391,13 @@ class MainWindow(MainWindowUI): # 保存到数据库 inspection_dao.save_inspection_data(order_id, gc_note, data) + + # 如果状态为已完成,清除缓存,强制下次更新从API获取最新数据 + if status == 'COMPLETED': + from apis.gc_api import GcApi + gc_api = GcApi() + gc_api.clear_tray_stats_cache(order_id=order_id, tray_id=tray_id) + logging.info(f"已清除托盘统计数据缓存: 订单号={order_id}, 托盘号={tray_id}") except Exception as e: logging.error(f"保存检验数据失败: {str(e)}") @@ -1461,18 +1468,18 @@ class MainWindow(MainWindowUI): self.load_finished_inspection_data() logging.info(f"数据加载完成,托盘号: {tray_id}") - # 加载完成后显示包装记录 + # 加载完成后显示包装记录,但不更新统计数据 try: - self.show_pack_item() - logging.info(f"在_do_safe_load中调用show_pack_item, 托盘号: {tray_id}") + self.show_pack_item(update_stats=False) + logging.info(f"在_do_safe_load中调用show_pack_item(update_stats=False), 托盘号: {tray_id}") except Exception as e: logging.error(f"在_do_safe_load中调用show_pack_item失败: {str(e)}") except Exception as e: logging.error(f"安全加载数据失败: {str(e)}, 托盘号: {tray_id}") - # 即使加载失败,也尝试显示包装记录 + # 即使加载失败,也尝试显示包装记录,但不更新统计数据 try: - self.show_pack_item() - logging.info(f"加载失败后尝试显示包装记录, 托盘号: {tray_id}") + self.show_pack_item(update_stats=False) + logging.info(f"加载失败后尝试显示包装记录(update_stats=False), 托盘号: {tray_id}") except Exception as ex: logging.error(f"加载失败后显示包装记录失败: {str(ex)}, 托盘号: {tray_id}") finally: @@ -1757,15 +1764,19 @@ class MainWindow(MainWindowUI): logging.error(f"加载已完成检验数据到包装记录失败: {str(e)}") QMessageBox.warning(self, "加载失败", f"加载已完成检验数据到包装记录失败: {str(e)}") - def show_pack_item(self): - """显示包装记录""" + def show_pack_item(self, update_stats=True): + """显示包装记录 + + Args: + update_stats: 是否更新统计数据,默认为True + """ try: from dao.inspection_dao import InspectionDAO inspection_dao = InspectionDAO() # 获取托盘号 tray_id = self.tray_edit.text() - logging.info(f"显示包装记录,当前托盘号: {tray_id}") + logging.info(f"显示包装记录,当前托盘号: {tray_id}, 更新统计={update_stats}") if not tray_id: logging.warning("托盘号为空,无法显示包装记录") @@ -1798,7 +1809,8 @@ class MainWindow(MainWindowUI): # 如果没有包装记录,直接返回 if not package_record: logging.info(f"托盘号 {tray_id} 没有包装记录数据") - self.update_package_statistics() + if update_stats: + self.update_package_statistics() self.record_table.blockSignals(False) # 恢复信号 return @@ -1836,8 +1848,9 @@ class MainWindow(MainWindowUI): # 恢复信号 self.record_table.blockSignals(False) - # 更新包装记录统计数据 - self.update_package_statistics() + # 更新包装记录统计数据(如果需要) + if update_stats: + self.update_package_statistics() logging.info(f"包装记录显示完成,托盘号={tray_id},总记录数={self.record_table.rowCount()}") except Exception as e: @@ -2701,6 +2714,7 @@ class MainWindow(MainWindowUI): info['mzl'] = weight_kg info['printsl'] = 1 logging.info(f"使用的xpack: {xpack}, spack: {info['spack']}") + info['pono'] = info.get("pono") or order_info.get('ddmo') info["dycz"] = info.get("cz") info['qd'] = self._current_gc_qd info['sc_gch'] = gc_note @@ -3996,14 +4010,14 @@ class MainWindow(MainWindowUI): try: # 设置加载状态为True,避免无限循环调用 self._loading_data_in_progress = True - # 强制显示包装记录 - self.show_pack_item() - logging.info(f"托盘号变更:直接调用显示包装记录, 托盘号={tray_id}") + # 强制显示包装记录,但不更新统计数据 + self.show_pack_item(update_stats=False) + logging.info(f"托盘号变更:直接调用显示包装记录(update_stats=False), 托盘号={tray_id}") finally: # 恢复之前的加载状态 self._loading_data_in_progress = prev_loading_state - # 更新包装统计数据 + # 只在托盘号变更时更新一次包装统计数据 self.update_package_statistics() logging.info(f"托盘号变更:更新包装统计数据, 托盘号={tray_id}") @@ -4498,6 +4512,9 @@ class MainWindow(MainWindowUI): try: # 获取托盘号 tray_id = self.tray_edit.text() + # 获取订单号(用于清除缓存) + order_id = self.order_edit.text().strip() + if not tray_id: QMessageBox.warning(self, "提示", "请先选择托盘号") return @@ -4517,6 +4534,10 @@ class MainWindow(MainWindowUI): # 调用接口 from apis.gc_api import GcApi gc_api = GcApi() + + # 清除缓存,强制下次更新从API获取最新数据 + if order_id: + gc_api.clear_tray_stats_cache(order_id=order_id, tray_id=tray_id) import socket try: