feat: 新增防抖机制以提升用户体验

This commit is contained in:
zhu-mengmeng 2025-07-22 14:30:18 +08:00
parent b61f2cc70b
commit 95ba01e152
2 changed files with 65 additions and 27 deletions

View File

@ -120,7 +120,7 @@
} }
}, },
"electricity": { "electricity": {
"auto_start": false, "auto_start": true,
"interval_minutes": 30 "interval_minutes": 30
} }
} }

View File

@ -1236,6 +1236,20 @@ class MainWindow(MainWindowUI):
row: 行索引 row: 行索引
column: 列索引 column: 列索引
""" """
# 防抖机制:记录上次处理的单元格位置和时间
current_time = time.time()
last_cell_key = f"{row}_{column}"
last_process_time = getattr(self, '_last_cell_change_time', 0)
last_cell = getattr(self, '_last_cell_changed', '')
# 如果是同一单元格且间隔小于0.5秒,则忽略此次调用
if last_cell == last_cell_key and current_time - last_process_time < 0.5:
return
# 更新最后处理的单元格和时间
self._last_cell_changed = last_cell_key
self._last_cell_change_time = current_time
try: try:
# 只处理数据行的检验列变更 # 只处理数据行的检验列变更
if row < 2: # 忽略表头行 if row < 2: # 忽略表头行
@ -1352,6 +1366,20 @@ class MainWindow(MainWindowUI):
value: 检验值 value: 检验值
status: 状态 status: 状态
""" """
# 防抖机制:记录上次保存的数据和时间
current_time = time.time()
save_key = f"{gc_note}_{position}_{config_id}_{value}"
last_save_time = getattr(self, '_last_save_time', 0)
last_save_key = getattr(self, '_last_save_key', '')
# 如果是相同的数据且间隔小于0.5秒,则忽略此次保存
if last_save_key == save_key and current_time - last_save_time < 0.5:
return
# 更新最后保存的数据和时间
self._last_save_key = save_key
self._last_save_time = current_time
try: try:
from dao.inspection_dao import InspectionDAO from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO() inspection_dao = InspectionDAO()
@ -1392,6 +1420,18 @@ class MainWindow(MainWindowUI):
# 获取当前托盘号,用于日志记录 # 获取当前托盘号,用于日志记录
tray_id = self.tray_edit.currentText() tray_id = self.tray_edit.currentText()
# 防抖机制:记录上次加载的时间
current_time = time.time()
last_safe_load_time = getattr(self, '_last_safe_load_time', 0)
# 如果间隔小于0.5秒,则忽略此次加载
if current_time - last_safe_load_time < 0.5:
logging.debug(f"_safe_load_data 被频繁调用,忽略此次请求 (托盘号: {tray_id})")
return
# 更新最后加载的时间
self._last_safe_load_time = current_time
if self._loading_data_in_progress: if self._loading_data_in_progress:
# 如果已经在加载数据,不要再次触发 # 如果已经在加载数据,不要再次触发
logging.debug(f"已有数据加载正在进行,忽略此次请求 (托盘号: {tray_id})") logging.debug(f"已有数据加载正在进行,忽略此次请求 (托盘号: {tray_id})")
@ -1416,13 +1456,27 @@ class MainWindow(MainWindowUI):
"""加载未完成的检验数据并显示在表格中""" """加载未完成的检验数据并显示在表格中"""
# 注意此方法通常应通过_safe_load_data调用以防止循环 # 注意此方法通常应通过_safe_load_data调用以防止循环
try: try:
# 获取托盘号
tray_id = self.tray_edit.currentText()
# 防止短时间内重复加载相同数据
current_time = time.time()
last_load_time = getattr(self, '_last_load_time', 0)
last_load_tray = getattr(self, '_last_load_tray', '')
# 如果是同一托盘且间隔小于1秒则忽略此次加载
if last_load_tray == tray_id and current_time - last_load_time < 1.0:
logging.debug(f"忽略重复加载托盘 {tray_id} 的数据,间隔太短")
return
# 更新最后加载的托盘和时间
self._last_load_tray = tray_id
self._last_load_time = current_time
# 使用InspectionDAO获取未完成的检验数据 # 使用InspectionDAO获取未完成的检验数据
from dao.inspection_dao import InspectionDAO from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO() inspection_dao = InspectionDAO()
# 获取托盘号
tray_id = self.tray_edit.currentText()
# 使用get_inspection_data_unfinished获取未完成的数据 # 使用get_inspection_data_unfinished获取未完成的数据
unfinished_data = inspection_dao.get_inspection_data_unfinished(tray_id) unfinished_data = inspection_dao.get_inspection_data_unfinished(tray_id)
@ -1641,6 +1695,7 @@ class MainWindow(MainWindowUI):
except Exception as e: except Exception as e:
logging.error(f"加载已完成检验数据到包装记录失败: {str(e)}") logging.error(f"加载已完成检验数据到包装记录失败: {str(e)}")
QMessageBox.warning(self, "加载失败", f"加载已完成检验数据到包装记录失败: {str(e)}") QMessageBox.warning(self, "加载失败", f"加载已完成检验数据到包装记录失败: {str(e)}")
def show_pack_item(self): def show_pack_item(self):
"""显示包装记录""" """显示包装记录"""
try: try:
@ -1725,6 +1780,7 @@ class MainWindow(MainWindowUI):
logging.error(f"显示包装记录失败: {str(e)}") logging.error(f"显示包装记录失败: {str(e)}")
self.record_table.blockSignals(False) # 确保信号被恢复 self.record_table.blockSignals(False) # 确保信号被恢复
QMessageBox.warning(self, "显示失败", f"显示包装记录失败: {str(e)}") QMessageBox.warning(self, "显示失败", f"显示包装记录失败: {str(e)}")
def update_package_statistics(self): def update_package_statistics(self):
"""更新包装记录统计数据""" """更新包装记录统计数据"""
try: try:
@ -2518,6 +2574,7 @@ class MainWindow(MainWindowUI):
try: try:
# 获取Modbus客户端现在使用连接池不会每次都创建新连接 # 获取Modbus客户端现在使用连接池不会每次都创建新连接
client = modbus.get_client() client = modbus.get_client()
time.sleep(0.5)
if not client: if not client:
logging.error("无法获取Modbus客户端连接") logging.error("无法获取Modbus客户端连接")
return return
@ -2742,25 +2799,6 @@ class MainWindow(MainWindowUI):
"""处理寄存器变化""" """处理寄存器变化"""
logging.info(f"[处理] 寄存器D{address}变化: {value}") logging.info(f"[处理] 寄存器D{address}变化: {value}")
# # 当D0寄存器有值时填充上料按钮样式
# if address == 0 and value > 0:
# self.fill_input_button_style()
# logging.info(f"D0寄存器有值({value}),填充上料按钮样式")
# # 当D4寄存器有值时填充下料按钮样式
# elif address == 4 and value > 0:
# self.fill_output_button_style()
# logging.info(f"D4寄存器有值({value}),填充下料按钮样式")
# # 当D0寄存器为 0 时,恢复上料按钮样式
# if address == 0 and value == 0:
# self.restore_input_button_style()
# logging.info(f"D0寄存器为 0 ,恢复上料按钮样式")
# # 当D4寄存器为 0 时,恢复下料按钮样式
# elif address == 4 and value == 0:
# self.restore_output_button_style()
# logging.info(f"D4寄存器为 0 ,恢复下料按钮样式")
# D2寄存器控制上料按钮样式 # D2寄存器控制上料按钮样式
if address == 2 and value == 0: if address == 2 and value == 0:
self.restore_input_button_style() self.restore_input_button_style()
@ -4581,7 +4619,7 @@ class MainWindow(MainWindowUI):
status = inspection_dao.get_product_status(self._current_order_code, row_gc_note, tray_id) status = inspection_dao.get_product_status(self._current_order_code, row_gc_note, tray_id)
if status == target_status: if status == target_status:
logging.info(f"找到状态为{target_status}的行: {row}, 工程号: {row_gc_note}") logging.info(f"找到状态为{target_status}的行: {row}, 工程号: {row_gc_note}")
return row return row # 找到第一个匹配的行就立即返回
# 如果从当前处理行开始没找到,从头开始搜索 # 如果从当前处理行开始没找到,从头开始搜索
if self._current_processing_row is not None and self._current_processing_row > 2: if self._current_processing_row is not None and self._current_processing_row > 2:
@ -4594,7 +4632,7 @@ class MainWindow(MainWindowUI):
status = inspection_dao.get_product_status(self._current_order_code, row_gc_note, tray_id) status = inspection_dao.get_product_status(self._current_order_code, row_gc_note, tray_id)
if status == target_status: if status == target_status:
logging.info(f"从头开始找到状态为{target_status}的行: {row}, 工程号: {row_gc_note}") logging.info(f"从头开始找到状态为{target_status}的行: {row}, 工程号: {row_gc_note}")
return row return row # 找到第一个匹配的行就立即返回
logging.warning(f"未找到状态为{target_status}的行") logging.warning(f"未找到状态为{target_status}的行")
return None return None