feat: 新增检验数据查询接口,优化主窗口防抖机制及数据处理逻辑
This commit is contained in:
parent
95ba01e152
commit
268a1cc16b
@ -1139,3 +1139,54 @@ class InspectionDAO:
|
||||
except Exception as e:
|
||||
logging.error(f"删除包装记录失败: {str(e)}")
|
||||
return False
|
||||
def get_inspection_data_by_config(self, order_id, gc_note, tray_id, position, config_id):
|
||||
"""根据工程号、托盘号、位置和配置ID查询检验数据
|
||||
|
||||
Args:
|
||||
order_id: 订单号
|
||||
gc_note: 工程号
|
||||
tray_id: 托盘号
|
||||
position: 位置序号
|
||||
config_id: 配置ID
|
||||
|
||||
Returns:
|
||||
dict: 检验数据记录,如果不存在则返回None
|
||||
"""
|
||||
try:
|
||||
# 使用SQLUtils获取数据库连接
|
||||
sql = """
|
||||
SELECT id, order_id, gc_note, position, config_id, value, status, remark, tray_id, create_time, update_time
|
||||
FROM wsbz_inspection_data
|
||||
WHERE order_id = ? AND gc_note = ? AND tray_id = ? AND position = ? AND config_id = ?
|
||||
ORDER BY update_time DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
|
||||
with SQLUtils('sqlite', database='db/jtDB.db') as db:
|
||||
# 执行查询
|
||||
db.cursor.execute(sql, (order_id, gc_note, tray_id, position, config_id))
|
||||
|
||||
# 获取结果
|
||||
row = db.cursor.fetchone()
|
||||
|
||||
# 如果有结果,转换为字典
|
||||
if row:
|
||||
return {
|
||||
'id': row[0],
|
||||
'order_id': row[1],
|
||||
'gc_note': row[2],
|
||||
'position': row[3],
|
||||
'config_id': row[4],
|
||||
'value': row[5],
|
||||
'status': row[6],
|
||||
'remark': row[7],
|
||||
'tray_id': row[8],
|
||||
'create_time': row[9],
|
||||
'update_time': row[10]
|
||||
}
|
||||
else:
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"查询检验数据失败: {str(e)}")
|
||||
return None
|
||||
@ -48,7 +48,7 @@ class ModbusMonitor(QObject):
|
||||
register_error = Signal(int, str)
|
||||
monitor_status_changed = Signal(bool, str)
|
||||
|
||||
def __init__(self, polling_interval=1.0, max_errors=3, retry_interval=5.0):
|
||||
def __init__(self, polling_interval=0.5, max_errors=3, retry_interval=5.0):
|
||||
"""
|
||||
初始化Modbus监控器
|
||||
|
||||
|
||||
@ -911,6 +911,20 @@ class MainWindow(MainWindowUI):
|
||||
# 获取当前输入的工程号
|
||||
gc_note = self.order_edit.text().strip()
|
||||
if gc_note:
|
||||
# 防抖机制:记录上次处理的工程号和时间
|
||||
current_time = time.time()
|
||||
last_order_time = getattr(self, '_last_order_time', 0)
|
||||
last_order_gc = getattr(self, '_last_order_gc', '')
|
||||
|
||||
# 如果是相同的工程号且间隔小于1秒,则忽略此次处理
|
||||
if last_order_gc == gc_note and current_time - last_order_time < 1.0:
|
||||
logging.info(f"忽略重复处理工程号: {gc_note},间隔太短")
|
||||
return
|
||||
|
||||
# 更新最后处理的工程号和时间
|
||||
self._last_order_gc = gc_note
|
||||
self._last_order_time = current_time
|
||||
|
||||
logging.info(f"输入的工程号: {gc_note}")
|
||||
#判断是否是接口,如果不是接口直接添加如果是则走接口
|
||||
# 如果开启接口模式,则需要调用接口同步到业务库
|
||||
@ -974,11 +988,19 @@ class MainWindow(MainWindowUI):
|
||||
self.update_info_table(order_info)
|
||||
self.add_new_inspection_row(gc_note, self._current_order_code)
|
||||
else:
|
||||
# 直接添加新行
|
||||
self.add_new_inspection_row(gc_note, self._current_order_code)
|
||||
|
||||
# 清空工程号输入框
|
||||
self.order_edit.clear()
|
||||
|
||||
# 将光标重新定位到工程号输入框
|
||||
self.order_edit.setFocus()
|
||||
|
||||
# 更新订单数量和产量统计数据
|
||||
self.update_order_statistics()
|
||||
else:
|
||||
logging.warning("工程号为空")
|
||||
QMessageBox.warning(self, "输入提示", "请输入有效的工程号")
|
||||
logging.warning("工程号为空,忽略处理")
|
||||
|
||||
def handle_virtual_order(self):
|
||||
"""处理虚拟工程号按钮点击事件"""
|
||||
@ -1009,26 +1031,6 @@ class MainWindow(MainWindowUI):
|
||||
logging.error(f"生成虚拟工程号失败: {str(e)}")
|
||||
QMessageBox.critical(self, "错误", f"生成虚拟工程号失败: {str(e)}")
|
||||
|
||||
def test_rapid_scanning(self):
|
||||
"""测试快速连续扫码的场景,确保最新扫码的工程号始终在最后"""
|
||||
logging.info("开始测试快速连续扫码场景")
|
||||
|
||||
# 模拟扫码工程号A
|
||||
logging.info("模拟扫码工程号A")
|
||||
self.order_edit.setText("A")
|
||||
self.handle_order_enter()
|
||||
|
||||
# 等待一小段时间
|
||||
QTimer.singleShot(100, lambda: self._test_scan_b())
|
||||
|
||||
def _test_scan_b(self):
|
||||
"""测试扫码工程号B"""
|
||||
logging.info("模拟扫码工程号B")
|
||||
self.order_edit.setText("B")
|
||||
self.handle_order_enter()
|
||||
|
||||
# 等待一小段时间后检查结果
|
||||
QTimer.singleShot(200, self._check_test_result)
|
||||
|
||||
def _check_test_result(self):
|
||||
"""检查测试结果"""
|
||||
@ -1108,32 +1110,6 @@ class MainWindow(MainWindowUI):
|
||||
item = QTableWidgetItem("")
|
||||
item.setTextAlignment(Qt.AlignCenter)
|
||||
|
||||
# 如果有order_info数据,尝试匹配字段并设置值
|
||||
# if order_info:
|
||||
# config_name = config.get('name')
|
||||
# # 检查order_info中是否有与config_name匹配的键
|
||||
# if config_name in order_info:
|
||||
# value = str(order_info[config_name])
|
||||
# item = QTableWidgetItem(value)
|
||||
# item.setTextAlignment(Qt.AlignCenter)
|
||||
# # 设置单元格背景为浅绿色,表示自动填充
|
||||
# item.setBackground(QBrush(QColor("#c8e6c9")))
|
||||
|
||||
# # 保存到数据库
|
||||
# from dao.inspection_dao import InspectionDAO
|
||||
# inspection_dao = InspectionDAO()
|
||||
# tray_id = self.tray_edit.currentText()
|
||||
# data = [{
|
||||
# 'position': config.get('position'),
|
||||
# 'config_id': config.get('id'),
|
||||
# 'value': value,
|
||||
# 'status': 'init', # 设置初始状态
|
||||
# 'remark': '',
|
||||
# 'tray_id': tray_id
|
||||
# }]
|
||||
# inspection_dao.save_inspection_data(self._current_order_code,gc_note, data)
|
||||
# logging.info(f"自动填充字段 {config_name} 值为 {value}")
|
||||
|
||||
# 设置单元格属性以标识其关联的检验项
|
||||
item.setData(Qt.UserRole, config.get('id'))
|
||||
self.process_table.setItem(data_start_row, col_index, item)
|
||||
@ -1236,21 +1212,30 @@ class MainWindow(MainWindowUI):
|
||||
row: 行索引
|
||||
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', '')
|
||||
# 创建唯一键,包含行、列、工程号
|
||||
try:
|
||||
# 获取工程号,用于创建更精确的唯一键
|
||||
order_item = self.process_table.item(row, 1)
|
||||
gc_note = order_item.text().strip() if order_item else ""
|
||||
|
||||
# 如果是同一单元格且间隔小于0.5秒,则忽略此次调用
|
||||
if last_cell == last_cell_key and current_time - last_process_time < 0.5:
|
||||
# 创建包含行、列、工程号的唯一键
|
||||
cell_key = f"{row}_{column}_{gc_note}"
|
||||
current_time = time.time()
|
||||
|
||||
# 获取上次处理时间
|
||||
last_process_times = getattr(self, '_last_cell_process_times', {})
|
||||
last_process_time = last_process_times.get(cell_key, 0)
|
||||
|
||||
# 如果同一单元格在1秒内被处理过,则忽略
|
||||
if current_time - last_process_time < 1.0:
|
||||
logging.info(f"防抖:跳过重复处理单元格 [{row}, {column}], 工程号={gc_note},间隔小于1秒")
|
||||
return
|
||||
|
||||
# 更新最后处理的单元格和时间
|
||||
self._last_cell_changed = last_cell_key
|
||||
self._last_cell_change_time = current_time
|
||||
# 更新处理时间
|
||||
if not hasattr(self, '_last_cell_process_times'):
|
||||
self._last_cell_process_times = {}
|
||||
self._last_cell_process_times[cell_key] = current_time
|
||||
|
||||
try:
|
||||
# 只处理数据行的检验列变更
|
||||
if row < 2: # 忽略表头行
|
||||
return
|
||||
@ -1260,11 +1245,6 @@ class MainWindow(MainWindowUI):
|
||||
return
|
||||
|
||||
# 获取工程号
|
||||
order_item = self.process_table.item(row, 1)
|
||||
if not order_item:
|
||||
return
|
||||
|
||||
gc_note = order_item.text().strip()
|
||||
if not gc_note:
|
||||
return
|
||||
|
||||
@ -1300,6 +1280,7 @@ class MainWindow(MainWindowUI):
|
||||
# 显示临时状态消息
|
||||
self.statusBar().showMessage(f"正在保存检验数据: {data_type}={value}", 1000)
|
||||
|
||||
# 验证数据有效性
|
||||
# 设置单元格颜色为浅绿色,表示已填写
|
||||
cell_item.setBackground(QBrush(QColor("#c8e6c9")))
|
||||
|
||||
@ -1307,8 +1288,6 @@ class MainWindow(MainWindowUI):
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
inspection_dao = InspectionDAO()
|
||||
status = inspection_dao.get_product_status(self._current_order_code, gc_note, tray_id)
|
||||
|
||||
# 保存到数据库
|
||||
self.save_inspection_data(self._current_order_code, gc_note, tray_id, config['position'], config['id'], value, status)
|
||||
|
||||
# 判断是否是包装列
|
||||
@ -1351,7 +1330,14 @@ class MainWindow(MainWindowUI):
|
||||
# 延迟一段时间后再触发查询,避免频繁刷新UI
|
||||
# 但要避免在加载过程中触发新的加载
|
||||
if not self._loading_data_in_progress:
|
||||
QTimer.singleShot(1000, self._safe_load_data)
|
||||
# 使用类变量保存定时器,避免创建多个定时器
|
||||
if hasattr(self, '_load_data_timer') and self._load_data_timer is not None:
|
||||
self._load_data_timer.stop()
|
||||
|
||||
self._load_data_timer = QTimer()
|
||||
self._load_data_timer.setSingleShot(True)
|
||||
self._load_data_timer.timeout.connect(self._safe_load_data)
|
||||
self._load_data_timer.start(1000)
|
||||
|
||||
|
||||
|
||||
@ -1374,12 +1360,21 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 如果是相同的数据且间隔小于0.5秒,则忽略此次保存
|
||||
if last_save_key == save_key and current_time - last_save_time < 0.5:
|
||||
logging.info(f"防抖机制:跳过保存相同数据 {save_key},间隔小于0.5秒")
|
||||
return
|
||||
|
||||
# 更新最后保存的数据和时间
|
||||
self._last_save_key = save_key
|
||||
self._last_save_time = current_time
|
||||
|
||||
# 检查是否已存在相同记录
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
inspection_dao = InspectionDAO()
|
||||
existing_data = inspection_dao.get_inspection_data_by_config(order_id, gc_note, tray_id, position, config_id)
|
||||
if existing_data and str(existing_data.get('value')) == str(value):
|
||||
logging.info(f"幂等处理:跳过保存已存在的检验数据 {gc_note}_{position}_{config_id}={value}")
|
||||
return
|
||||
|
||||
try:
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
inspection_dao = InspectionDAO()
|
||||
@ -1432,6 +1427,23 @@ class MainWindow(MainWindowUI):
|
||||
# 更新最后加载的时间
|
||||
self._last_safe_load_time = current_time
|
||||
|
||||
# 检查是否已有定时器在运行
|
||||
if hasattr(self, '_safe_load_timer') and self._safe_load_timer is not None:
|
||||
self._safe_load_timer.stop()
|
||||
self._safe_load_timer = None
|
||||
logging.debug("已停止之前的加载定时器")
|
||||
|
||||
# 创建新的定时器,延迟执行实际加载操作
|
||||
self._safe_load_timer = QTimer()
|
||||
self._safe_load_timer.setSingleShot(True)
|
||||
self._safe_load_timer.timeout.connect(self._do_safe_load)
|
||||
self._safe_load_timer.start(500) # 500毫秒后执行
|
||||
|
||||
def _do_safe_load(self):
|
||||
"""实际执行数据加载的方法,由定时器触发"""
|
||||
# 获取当前托盘号,用于日志记录
|
||||
tray_id = self.tray_edit.currentText()
|
||||
|
||||
if self._loading_data_in_progress:
|
||||
# 如果已经在加载数据,不要再次触发
|
||||
logging.debug(f"已有数据加载正在进行,忽略此次请求 (托盘号: {tray_id})")
|
||||
@ -1441,6 +1453,13 @@ class MainWindow(MainWindowUI):
|
||||
self._loading_data_in_progress = True
|
||||
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}")
|
||||
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}")
|
||||
# 即使加载失败,也尝试显示包装记录
|
||||
@ -1451,10 +1470,23 @@ class MainWindow(MainWindowUI):
|
||||
logging.error(f"加载失败后显示包装记录失败: {str(ex)}, 托盘号: {tray_id}")
|
||||
finally:
|
||||
self._loading_data_in_progress = False
|
||||
# 清理定时器引用
|
||||
self._safe_load_timer = None
|
||||
|
||||
def load_finished_inspection_data(self):
|
||||
"""加载未完成的检验数据并显示在表格中"""
|
||||
# 注意:此方法通常应通过_safe_load_data调用,以防止循环
|
||||
|
||||
# 添加表格更新锁,避免并发更新
|
||||
if hasattr(self, '_table_updating') and self._table_updating:
|
||||
logging.info("表格正在更新中,忽略此次加载请求")
|
||||
return
|
||||
|
||||
self._table_updating = True
|
||||
|
||||
# 记录信号连接状态
|
||||
signal_was_connected = False
|
||||
|
||||
try:
|
||||
# 获取托盘号
|
||||
tray_id = self.tray_edit.currentText()
|
||||
@ -1480,11 +1512,15 @@ class MainWindow(MainWindowUI):
|
||||
# 使用get_inspection_data_unfinished获取未完成的数据
|
||||
unfinished_data = inspection_dao.get_inspection_data_unfinished(tray_id)
|
||||
|
||||
# 断开单元格变更信号,避免加载过程中触发保存
|
||||
# 检查信号是否已连接,并断开单元格变更信号
|
||||
try:
|
||||
signal_was_connected = self.process_table.receivers(self.process_table.cellChanged) > 0
|
||||
if signal_was_connected:
|
||||
self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed)
|
||||
except:
|
||||
pass
|
||||
logging.debug("已断开单元格变更信号")
|
||||
except Exception as e:
|
||||
logging.debug(f"断开单元格变更信号失败: {str(e)}")
|
||||
signal_was_connected = False
|
||||
|
||||
# 清空表格现有数据行,只保留表头
|
||||
while self.process_table.rowCount() > 2:
|
||||
@ -1495,11 +1531,13 @@ class MainWindow(MainWindowUI):
|
||||
# 确保表格完全清空,只保留表头行
|
||||
self.process_table.setRowCount(2) # 只保留表头的两行
|
||||
|
||||
# 重新连接单元格变更信号
|
||||
# 只有在之前信号已连接的情况下才重新连接
|
||||
if signal_was_connected:
|
||||
try:
|
||||
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
|
||||
except:
|
||||
pass
|
||||
logging.debug("已重新连接单元格变更信号")
|
||||
except Exception as e:
|
||||
logging.warning(f"重新连接单元格变更信号失败: {str(e)}")
|
||||
|
||||
# 加载包装记录
|
||||
return
|
||||
@ -1531,59 +1569,60 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 按创建时间排序,但确保新添加的工程号在最后
|
||||
sorted_gc_notes = inspection_dao.get_orders_by_create_time(list(orders_data.keys()))
|
||||
logging.info(f"按创建时间排序后的工程号列表: {sorted_gc_notes}")
|
||||
|
||||
# 如果当前有正在处理的工程号,确保它在最后
|
||||
if current_gc_note and current_gc_note in sorted_gc_notes:
|
||||
# 将当前工程号移到列表末尾
|
||||
# 如果有当前正在处理的工程号,将其移到最后
|
||||
if current_gc_note and current_gc_note in sorted_gc_notes and current_timestamp:
|
||||
logging.info(f"将当前处理的工程号 {current_gc_note} 移到最后")
|
||||
sorted_gc_notes.remove(current_gc_note)
|
||||
sorted_gc_notes.append(current_gc_note)
|
||||
logging.info(f"将最新扫码的工程号 {current_gc_note} (时间戳: {current_timestamp}) 移到列表末尾,确保显示在最后")
|
||||
logging.info(f"调整后的工程号列表: {sorted_gc_notes}")
|
||||
elif current_gc_note:
|
||||
logging.info(f"当前正在处理的工程号 {current_gc_note} 不在数据库记录中,可能是新添加的")
|
||||
else:
|
||||
|
||||
logging.info(f"按创建时间排序后的工程号列表: {sorted_gc_notes}")
|
||||
|
||||
# 如果没有当前正在处理的工程号,记录日志
|
||||
if not current_gc_note:
|
||||
logging.info("没有当前正在处理的工程号")
|
||||
|
||||
# 收集所有要设置的单元格,批量设置
|
||||
cells_to_set = []
|
||||
|
||||
# 按排序后的工程号顺序添加数据
|
||||
for gc_note in sorted_gc_notes:
|
||||
items = orders_data[gc_note]
|
||||
|
||||
# 添加新行
|
||||
# 添加工程号到表格的第二列
|
||||
item = QTableWidgetItem(gc_note)
|
||||
item.setTextAlignment(Qt.AlignCenter)
|
||||
self.process_table.insertRow(row_idx)
|
||||
self.process_table.setItem(row_idx, 1, item)
|
||||
|
||||
# 添加序号到第一列
|
||||
seq_item = QTableWidgetItem(str(row_idx - 1))
|
||||
seq_item.setTextAlignment(Qt.AlignCenter)
|
||||
self.process_table.setItem(row_idx, 0, seq_item)
|
||||
# 添加序号到表格的第一列
|
||||
item = QTableWidgetItem(str(row_idx - 1)) # 序号从1开始
|
||||
item.setTextAlignment(Qt.AlignCenter)
|
||||
self.process_table.setItem(row_idx, 0, item)
|
||||
|
||||
# 添加工程号到第二列
|
||||
order_item = QTableWidgetItem(gc_note)
|
||||
order_item.setTextAlignment(Qt.AlignCenter)
|
||||
self.process_table.setItem(row_idx, 1, order_item)
|
||||
# 获取该工程号的所有数据
|
||||
data_list = orders_data[gc_note]
|
||||
|
||||
# 添加检验数据
|
||||
for item in items:
|
||||
position = item['position']
|
||||
value = item['value'] if item['value'] else ""
|
||||
status = item['status']
|
||||
config_id = item['config_id']
|
||||
# 按位置分组,确保每个位置只有一条数据(取最新的)
|
||||
position_data = {}
|
||||
for data in data_list:
|
||||
position = data['position']
|
||||
if position not in position_data or data['update_time'] > position_data[position]['update_time']:
|
||||
position_data[position] = data
|
||||
|
||||
# 添加检验数据到表格
|
||||
for position, data in position_data.items():
|
||||
value = data['value']
|
||||
config_id = data['config_id']
|
||||
|
||||
# 找到对应的列索引
|
||||
col_index = None
|
||||
col_idx = None
|
||||
|
||||
# 处理检验列(position 1-10)
|
||||
if 1 <= position <= 10:
|
||||
for i, config in enumerate(enabled_configs):
|
||||
if config.get('position') == position:
|
||||
col_index = 2 + i # 检验列从第3列开始
|
||||
if config['id'] == config_id:
|
||||
col_idx = 2 + i
|
||||
break
|
||||
|
||||
if col_index is not None:
|
||||
# 创建单元格并设置值
|
||||
cell_item = QTableWidgetItem(str(value))
|
||||
cell_item.setTextAlignment(Qt.AlignCenter)
|
||||
# 存储配置ID,用于保存时确定是哪个检验项
|
||||
cell_item.setData(Qt.UserRole, config_id)
|
||||
# 设置单元格
|
||||
self.process_table.setItem(row_idx, col_index, cell_item)
|
||||
# 添加贴标(11)和称重数据(12)
|
||||
if position == 11: # 贴标
|
||||
# 贴标列索引 = 2(序号和工程号) + 检验列数
|
||||
@ -1602,37 +1641,20 @@ class MainWindow(MainWindowUI):
|
||||
# 设置表格为可编辑状态
|
||||
self.process_table.setEditTriggers(QTableWidget.DoubleClicked | QTableWidget.EditKeyPressed)
|
||||
|
||||
# 重新连接单元格变更信号
|
||||
# 只有在之前信号已连接的情况下才重新连接
|
||||
if signal_was_connected:
|
||||
try:
|
||||
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
|
||||
|
||||
logging.debug("已重新连接单元格变更信号")
|
||||
except Exception as e:
|
||||
logging.warning(f"重新连接单元格变更信号失败: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"加载未完成的检验数据失败: {str(e)}")
|
||||
QMessageBox.warning(self, "加载失败", f"加载未完成的检验数据失败: {str(e)}")
|
||||
|
||||
finally:
|
||||
# 加载包装记录,但要避免循环调用
|
||||
# 设置一个标志,防止 show_pack_item 触发更多的数据加载
|
||||
# 只有在_safe_load_data调用此方法,且没有明确设置加载状态的情况下才调用
|
||||
has_loading_flag = hasattr(self, '_loading_data_in_progress')
|
||||
is_loading = getattr(self, '_loading_data_in_progress', False)
|
||||
|
||||
# 如果是被_safe_load_data调用(即已经设置了_loading_data_in_progress),则无需额外设置
|
||||
if has_loading_flag and is_loading:
|
||||
# 直接调用show_pack_item,不改变加载状态
|
||||
try:
|
||||
self.show_pack_item()
|
||||
logging.info("在load_finished_inspection_data中调用show_pack_item")
|
||||
except Exception as e:
|
||||
logging.error(f"在load_finished_inspection_data中调用show_pack_item失败: {str(e)}")
|
||||
# 否则,这是直接调用此方法(非_safe_load_data),需要设置加载状态
|
||||
elif not is_loading:
|
||||
self._loading_data_in_progress = True
|
||||
try:
|
||||
self.show_pack_item()
|
||||
logging.info("在load_finished_inspection_data中直接调用show_pack_item")
|
||||
finally:
|
||||
self._loading_data_in_progress = False
|
||||
# 释放表格更新锁
|
||||
self._table_updating = False
|
||||
|
||||
def load_finished_record_to_package_record(self, order_id, gc_note, tray_id, axios_num=None):
|
||||
"""加载已完成检验数据到包装记录
|
||||
@ -2017,22 +2039,57 @@ class MainWindow(MainWindowUI):
|
||||
# 连接电力数据变化信号
|
||||
self.electricity_handler.electricity_data_changed.connect(self.update_electricity_statistics)
|
||||
|
||||
# 连接贴标信号
|
||||
# 连接贴标信号 - 先断开再连接,避免重复连接
|
||||
try:
|
||||
self.machine_handlers.label_signal_changed.disconnect(self.handle_label_signal)
|
||||
except Exception:
|
||||
logging.debug("贴标信号未连接,无需断开")
|
||||
self.machine_handlers.label_signal_changed.connect(self.handle_label_signal)
|
||||
|
||||
# 连接称重数据变化信号
|
||||
# 连接称重数据变化信号 - 先断开再连接,避免重复连接
|
||||
try:
|
||||
self.machine_handlers.weight_changed.disconnect(self.handle_weight_data)
|
||||
except Exception:
|
||||
logging.debug("称重信号未连接,无需断开")
|
||||
self.machine_handlers.weight_changed.connect(self.handle_weight_data)
|
||||
|
||||
# 连接NG信号
|
||||
# 连接NG信号 - 先断开再连接,避免重复连接
|
||||
try:
|
||||
self.machine_handlers.ng_changed.disconnect(self.handle_ng)
|
||||
except Exception:
|
||||
logging.debug("NG信号未连接,无需断开")
|
||||
self.machine_handlers.ng_changed.connect(self.handle_ng)
|
||||
|
||||
# 连接故障信号
|
||||
# 连接故障信号 - 先断开再连接,避免重复连接
|
||||
try:
|
||||
self.machine_handlers.error_1_changed.disconnect(self.handle_error_1)
|
||||
except Exception:
|
||||
logging.debug("故障1信号未连接,无需断开")
|
||||
self.machine_handlers.error_1_changed.connect(self.handle_error_1)
|
||||
|
||||
try:
|
||||
self.machine_handlers.error_2_changed.disconnect(self.handle_error_2)
|
||||
except Exception:
|
||||
logging.debug("故障2信号未连接,无需断开")
|
||||
self.machine_handlers.error_2_changed.connect(self.handle_error_2)
|
||||
|
||||
try:
|
||||
self.machine_handlers.error_3_changed.disconnect(self.handle_error_3)
|
||||
except Exception:
|
||||
logging.debug("故障3信号未连接,无需断开")
|
||||
self.machine_handlers.error_3_changed.connect(self.handle_error_3)
|
||||
|
||||
# 连接上下料反馈信号
|
||||
# 连接上下料反馈信号 - 先断开再连接,避免重复连接
|
||||
try:
|
||||
self.machine_handlers.loading_feedback_changed.disconnect(self.handle_loading_feedback)
|
||||
except Exception:
|
||||
logging.debug("上料反馈信号未连接,无需断开")
|
||||
self.machine_handlers.loading_feedback_changed.connect(self.handle_loading_feedback)
|
||||
|
||||
try:
|
||||
self.machine_handlers.unloading_feedback_changed.disconnect(self.handle_unloading_feedback)
|
||||
except Exception:
|
||||
logging.debug("下料反馈信号未连接,无需断开")
|
||||
self.machine_handlers.unloading_feedback_changed.connect(self.handle_unloading_feedback)
|
||||
|
||||
# 连接急停信号
|
||||
@ -2041,9 +2098,6 @@ class MainWindow(MainWindowUI):
|
||||
# 立即更新一次用电量数据
|
||||
self.update_electricity_statistics()
|
||||
|
||||
# 立即更新一次订单数量和产量统计数据
|
||||
self.update_order_statistics()
|
||||
|
||||
logging.info("已连接所有Modbus信号")
|
||||
|
||||
def update_electricity_statistics(self, value=None):
|
||||
@ -2103,7 +2157,18 @@ class MainWindow(MainWindowUI):
|
||||
def handle_weight_data(self, weight_in_g):
|
||||
"""处理称重数据变化"""
|
||||
try:
|
||||
# 添加防抖机制,避免短时间内重复处理相同重量
|
||||
current_time = time.time()
|
||||
last_weight_time = getattr(self, '_last_weight_data_time', 0)
|
||||
last_weight_value = getattr(self, '_last_weight_data_value', 0)
|
||||
|
||||
# 如果是相同的重量且间隔小于0.2秒,则忽略此次调用
|
||||
if abs(weight_in_g - last_weight_value) < 10 and current_time - last_weight_time < 0.2:
|
||||
return
|
||||
|
||||
# 更新最后处理的重量和时间
|
||||
self._last_weight_data_time = current_time
|
||||
self._last_weight_data_value = weight_in_g
|
||||
|
||||
# 转换重量单位并立即更新UI显示
|
||||
weight_in_kg = self._convert_to_kg(weight_in_g)
|
||||
@ -2115,6 +2180,12 @@ class MainWindow(MainWindowUI):
|
||||
logging.info(f"检测到新产品放上,重量从 {self._current_weight}kg 变为 {weight_in_kg}kg")
|
||||
self._weight_processed = False # 重置处理标记,允许处理新产品
|
||||
|
||||
# 检测重量从较大值变为接近0,判断为产品移除
|
||||
elif self._current_weight is not None and self._current_weight > 0.5 and weight_in_kg < 0.1:
|
||||
logging.info(f"检测到产品被移除,重量从 {self._current_weight}kg 变为 {weight_in_kg}kg")
|
||||
self._weight_processed = False # 重置处理标记,为下一个产品做准备
|
||||
self._last_processed_weight = 0 # 重置上次处理的重量
|
||||
|
||||
# 更新当前重量和时间
|
||||
self._current_weight = weight_in_kg
|
||||
self._last_weight_time = current_time
|
||||
@ -2163,8 +2234,16 @@ class MainWindow(MainWindowUI):
|
||||
original_weight_kg: 开始检查时的重量(千克)
|
||||
"""
|
||||
try:
|
||||
# 设置最小有效重量阈值,低于此值的重量不会被处理
|
||||
MIN_VALID_WEIGHT = 0.5 # 0.5kg
|
||||
|
||||
# 如果当前重量低于最小有效重量阈值,则直接跳过
|
||||
if self._current_weight < MIN_VALID_WEIGHT:
|
||||
logging.info(f"当前重量 {self._current_weight}kg 低于最小有效重量阈值 {MIN_VALID_WEIGHT}kg,跳过处理")
|
||||
return
|
||||
|
||||
# 如果当前重量与定时器启动时的重量相同,说明这段时间内没有新的重量数据
|
||||
if self._current_weight == original_weight_kg and self._current_weight > 0.5:
|
||||
if self._current_weight == original_weight_kg and self._current_weight > MIN_VALID_WEIGHT:
|
||||
logging.info(f"重量 {original_weight_kg}kg 在{self._weight_stable_threshold}秒内保持稳定")
|
||||
|
||||
# 如果这个重量与上一次处理的重量接近(±0.1kg),且标记已处理,则跳过
|
||||
@ -2191,6 +2270,20 @@ class MainWindow(MainWindowUI):
|
||||
weight_kg: 稳定的重量值(千克)
|
||||
max_retries: 最大重试次数
|
||||
"""
|
||||
# 添加防抖机制,避免短时间内重复处理相同重量
|
||||
current_time = time.time()
|
||||
last_stable_time = getattr(self, '_last_stable_weight_time', 0)
|
||||
last_stable_value = getattr(self, '_last_stable_weight_value', 0)
|
||||
|
||||
# 如果是相同的重量且间隔小于1秒,则忽略此次调用
|
||||
if abs(weight_kg - last_stable_value) < 0.1 and current_time - last_stable_time < 1.0:
|
||||
logging.info(f"防抖机制:跳过处理相同的稳定重量 {weight_kg}kg,间隔小于1秒")
|
||||
return
|
||||
|
||||
# 更新最后处理的稳定重量和时间
|
||||
self._last_stable_weight_time = current_time
|
||||
self._last_stable_weight_value = weight_kg
|
||||
|
||||
retry_count = 0
|
||||
last_error = None
|
||||
modbus = ModbusUtils()
|
||||
@ -2201,6 +2294,8 @@ class MainWindow(MainWindowUI):
|
||||
if not client:
|
||||
logging.error("无法获取Modbus客户端连接")
|
||||
return
|
||||
|
||||
logging.info(f"开始处理稳定重量: {weight_kg}kg")
|
||||
# 这里不再写入D10=1,全部交由_process_stable_weight处理
|
||||
self._process_stable_weight(weight_kg)
|
||||
# 调用打印方法
|
||||
@ -2209,6 +2304,11 @@ class MainWindow(MainWindowUI):
|
||||
self._weight_processed = True
|
||||
self._last_processed_weight = weight_kg
|
||||
logging.info(f"已标记重量 {weight_kg}kg 为已处理")
|
||||
|
||||
# 重置当前重量为0,避免两个产品之间的重量判断问题
|
||||
# 这样可以确保下一个产品必须从接近0的值开始测量
|
||||
logging.info(f"已重置当前重量为0,等待下一个产品")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"处理稳定重量时发生错误: {str(e)}")
|
||||
finally:
|
||||
@ -2222,6 +2322,14 @@ class MainWindow(MainWindowUI):
|
||||
Args:
|
||||
weight_kg: 稳定的重量值(千克)
|
||||
"""
|
||||
# 添加处理锁,避免并发处理
|
||||
if hasattr(self, '_processing_weight_lock') and self._processing_weight_lock:
|
||||
logging.warning(f"已有称重处理进行中,忽略本次请求: {weight_kg}kg")
|
||||
return
|
||||
|
||||
# 设置处理锁
|
||||
self._processing_weight_lock = True
|
||||
|
||||
try:
|
||||
# 忽略接近0的重量值,这可能表示产品已被移除
|
||||
if weight_kg < 0.1: # 小于100g的重量视为无效
|
||||
@ -2267,15 +2375,29 @@ class MainWindow(MainWindowUI):
|
||||
self._current_processing_row = data_row
|
||||
|
||||
# 获取工程号
|
||||
gc_note = self.process_table.item(data_row, 1)
|
||||
if not gc_note:
|
||||
gc_note_item = self.process_table.item(data_row, 1)
|
||||
if not gc_note_item:
|
||||
logging.warning("无法获取工程号")
|
||||
return
|
||||
|
||||
gc_note = gc_note.text().strip()
|
||||
gc_note = gc_note_item.text().strip()
|
||||
if not gc_note:
|
||||
logging.warning("工程号为空")
|
||||
return
|
||||
|
||||
# 创建唯一键,包含工程号、重量值和时间戳
|
||||
current_time = time.time()
|
||||
process_key = f"{gc_note}_{weight_kg}_{int(current_time/60)}" # 按分钟级别去重
|
||||
|
||||
# 检查是否已处理过相同的键
|
||||
last_process_key = getattr(self, '_last_weight_process_key', '')
|
||||
if process_key == last_process_key:
|
||||
logging.info(f"跳过重复处理:工程号 {gc_note} 的重量 {weight_kg}kg 在短时间内已处理")
|
||||
return
|
||||
|
||||
# 更新处理键
|
||||
self._last_weight_process_key = process_key
|
||||
|
||||
# 保存净重到数据库(毛重-工字轮重量,单位都是千克)
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
inspection_dao = InspectionDAO()
|
||||
@ -2312,10 +2434,13 @@ class MainWindow(MainWindowUI):
|
||||
self.warning_msg.setIcon(QMessageBox.Warning)
|
||||
self.warning_msg.setWindowTitle('重量超出范围')
|
||||
self.warning_msg.setText(f"称重值 {net_weight_kg:.2f}kg 不在轴重要求范围内 ({min_weight:.1f} - {max_weight:.1f}kg)")
|
||||
self.warning_msg.setStandardButtons(QMessageBox.NoButton)
|
||||
self.warning_msg.setStandardButtons(QMessageBox.Ok) # 添加确定按钮
|
||||
self.warning_msg.setModal(False) # 确保非模态
|
||||
self.warning_msg.setWindowFlags(self.warning_msg.windowFlags() | Qt.WindowStaysOnTopHint) # 置顶显示
|
||||
|
||||
# 连接按钮点击信号
|
||||
self.warning_msg.buttonClicked.connect(lambda btn: self.warning_msg.close())
|
||||
|
||||
# 使用 show 而非 exec_ 保持非阻塞
|
||||
self.warning_msg.show()
|
||||
|
||||
@ -2377,12 +2502,24 @@ class MainWindow(MainWindowUI):
|
||||
weight_item.setTextAlignment(Qt.AlignCenter)
|
||||
self.process_table.setItem(data_row, weight_col, weight_item)
|
||||
|
||||
# 保存到数据库(使用千克)
|
||||
# 检查是否已存在相同记录
|
||||
tray_id = self.tray_edit.currentText()
|
||||
existing_data = inspection_dao.get_inspection_data_by_config(self._current_order_code, gc_note, tray_id, 12, 12)
|
||||
if existing_data and str(existing_data.get('value')) == str(weight_kg):
|
||||
logging.info(f"跳过保存:工程号 {gc_note} 的称重数据 {weight_kg} 已存在")
|
||||
else:
|
||||
# 保存到数据库(使用千克)
|
||||
self.save_inspection_data(self._current_order_code, gc_note, tray_id, 12, 12, str(weight_kg), "pass")
|
||||
logging.info(f"已保存称重数据: {weight_kg}kg 到工程号 {gc_note}")
|
||||
|
||||
|
||||
# 检查是否已存在相同净重记录
|
||||
existing_net_data = inspection_dao.get_inspection_data_by_config(self._current_order_code, gc_note, tray_id, 13, 13)
|
||||
if existing_net_data and str(existing_net_data.get('value')) == str(net_weight_kg):
|
||||
logging.info(f"跳过保存:工程号 {gc_note} 的净重数据 {net_weight_kg} 已存在")
|
||||
else:
|
||||
# 保存净重数据
|
||||
self.save_inspection_data(self._current_order_code, gc_note, tray_id, 13, 13, str(net_weight_kg), "pass")
|
||||
logging.info(f"已保存净重数据: {net_weight_kg}kg 到工程号 {gc_note}")
|
||||
|
||||
# 设置净重单元格(显示千克)
|
||||
net_weight_item = QTableWidgetItem(str(net_weight_kg))
|
||||
@ -2514,6 +2651,7 @@ class MainWindow(MainWindowUI):
|
||||
logging.info(f"添加订单信息成功: {response.get('data',{})}")
|
||||
else:
|
||||
QMessageBox.warning(self, f"提示", response.get("message",{}))
|
||||
|
||||
# 新增:如果勾选了圆形标签checkbox,则向寄存器D15写入1
|
||||
if hasattr(self, "round_label_checkbox") and self.round_label_checkbox.isChecked():
|
||||
modbus = ModbusUtils()
|
||||
@ -2525,15 +2663,15 @@ class MainWindow(MainWindowUI):
|
||||
# 保存贴标数据到数据库
|
||||
self.save_inspection_data(self._current_order_code, gc_note, tray_id, 11, 11, str(axios_num), "pass")
|
||||
|
||||
# 更新产品状态为weighed
|
||||
inspection_dao.update_product_status(self._current_order_code, gc_note, tray_id, 'weighed')
|
||||
logging.info(f"工程号 {gc_note} 的称重已完成,状态更新为weighed")
|
||||
|
||||
# 重新连接信号
|
||||
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
|
||||
|
||||
logging.info(f"已将稳定的称重数据 {weight_kg}kg 写入行 {data_row}, 列 {weight_col}")
|
||||
|
||||
# 更新产品状态为weighed
|
||||
inspection_dao.update_product_status(self._current_order_code, gc_note, tray_id, 'weighed')
|
||||
logging.info(f"工程号 {gc_note} 的称重已完成,状态更新为weighed")
|
||||
|
||||
# 清除当前处理行的跟踪,因为称重完成后需要等待贴标
|
||||
self._current_processing_row = None
|
||||
|
||||
@ -2544,6 +2682,9 @@ class MainWindow(MainWindowUI):
|
||||
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
# 释放处理锁
|
||||
self._processing_weight_lock = False
|
||||
|
||||
def _print_weight_label(self, weight_kg):
|
||||
"""
|
||||
@ -2574,7 +2715,7 @@ class MainWindow(MainWindowUI):
|
||||
try:
|
||||
# 获取Modbus客户端(现在使用连接池,不会每次都创建新连接)
|
||||
client = modbus.get_client()
|
||||
time.sleep(0.5)
|
||||
time.sleep(0.1)
|
||||
if not client:
|
||||
logging.error("无法获取Modbus客户端连接")
|
||||
return
|
||||
@ -2935,14 +3076,6 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 显示事件消息
|
||||
if "全部完成" in desc:
|
||||
QMessageBox.information(self, "下料完成", desc)
|
||||
# 任务完成,清除状态显示
|
||||
self.clear_operation_status("output")
|
||||
if hasattr(self, 'unload_level_label'):
|
||||
self.unload_level_label.setText("下料层数:--")
|
||||
if hasattr(self, 'unload_position_label'):
|
||||
self.unload_position_label.setText("下料位置:--")
|
||||
# 下料任务完成,恢复下料按钮样式
|
||||
self.restore_output_button_style()
|
||||
logging.info("下料任务完成,恢复下料按钮样式")
|
||||
elif "请启动" in desc:
|
||||
@ -3005,11 +3138,6 @@ class MainWindow(MainWindowUI):
|
||||
# 获取Modbus连接
|
||||
modbus = ModbusUtils()
|
||||
client = modbus.get_client()
|
||||
|
||||
# 根据错误码可以添加不同的处理逻辑
|
||||
# 这里先简单处理,对所有错误都复位相关寄存器
|
||||
modbus.write_register_until_success(client, 2, 0)
|
||||
modbus.write_register_until_success(client, 0, 0)
|
||||
modbus.close_client(client)
|
||||
|
||||
@Slot(int, str)
|
||||
@ -3030,10 +3158,6 @@ class MainWindow(MainWindowUI):
|
||||
modbus = ModbusUtils()
|
||||
client = modbus.get_client()
|
||||
|
||||
# 根据错误码可以添加不同的处理逻辑
|
||||
# 这里先简单处理,对所有错误都复位相关寄存器
|
||||
modbus.write_register_until_success(client, 3, 0)
|
||||
modbus.write_register_until_success(client, 4, 0)
|
||||
modbus.close_client(client)
|
||||
|
||||
@Slot(int, str)
|
||||
@ -3265,6 +3389,7 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
def on_diameter_data_received(self, port_name, data):
|
||||
"""线径数据接收回调函数 - 采用类似称重的逻辑,不使用会话机制"""
|
||||
modbus_client = None
|
||||
try:
|
||||
data_str = data.decode('utf-8') if isinstance(data, bytes) else str(data)
|
||||
logging.info(f"收到线径数据: {data_str} 来自 {port_name}")
|
||||
@ -3274,6 +3399,23 @@ class MainWindow(MainWindowUI):
|
||||
value_str = data_str.split("线径数据:")[1].strip()
|
||||
try:
|
||||
xj_value = round(float(value_str)/10000, 3)
|
||||
|
||||
# 防抖机制:记录上次处理的线径数据和时间
|
||||
current_time = time.time()
|
||||
last_diameter_time = getattr(self, '_last_diameter_time', 0)
|
||||
last_diameter_value = getattr(self, '_last_diameter_value', None)
|
||||
|
||||
# 如果是相同的线径值(精确到0.001)且间隔小于1秒,则忽略此次处理
|
||||
if (last_diameter_value is not None and
|
||||
abs(last_diameter_value - xj_value) < 0.001 and
|
||||
current_time - last_diameter_time < 1.0):
|
||||
logging.info(f"忽略重复线径数据: {xj_value:.3f},间隔太短")
|
||||
return
|
||||
|
||||
# 更新最后处理的线径数据和时间
|
||||
self._last_diameter_value = xj_value
|
||||
self._last_diameter_time = current_time
|
||||
|
||||
self.statusBar().showMessage(f"线径数据: {xj_value:.3f}", 2000)
|
||||
|
||||
# 查找线径对应的检验项配置和列
|
||||
@ -3363,18 +3505,21 @@ class MainWindow(MainWindowUI):
|
||||
if final_value < min_diameter or final_value > max_diameter:
|
||||
# 写入寄存器D10 给值 3 表示线径超出范围
|
||||
modbus = ModbusUtils()
|
||||
client = modbus.get_client()
|
||||
modbus.write_register_until_success(client, 10, 3)
|
||||
modbus.close_client(client)
|
||||
modbus_client = modbus.get_client()
|
||||
modbus.write_register_until_success(modbus_client, 10, 3)
|
||||
|
||||
# 显示自动关闭的警告提示框
|
||||
self.diameter_warning_msg = QMessageBox(self)
|
||||
self.diameter_warning_msg.setIcon(QMessageBox.Warning)
|
||||
self.diameter_warning_msg.setWindowTitle('线径超出范围')
|
||||
self.diameter_warning_msg.setText(f"线径值 {final_value:.3f}mm 不在线径公差范围内 ({min_diameter:.3f} - {max_diameter:.3f}mm)")
|
||||
self.diameter_warning_msg.setStandardButtons(QMessageBox.NoButton)
|
||||
self.diameter_warning_msg.setStandardButtons(QMessageBox.Ok) # 添加确定按钮
|
||||
self.diameter_warning_msg.setModal(False) # 确保非模态
|
||||
self.diameter_warning_msg.setWindowFlags(self.diameter_warning_msg.windowFlags() | Qt.WindowStaysOnTopHint) # 置顶显示
|
||||
|
||||
# 连接按钮点击信号
|
||||
self.diameter_warning_msg.buttonClicked.connect(lambda btn: self.diameter_warning_msg.close())
|
||||
|
||||
# 使用 show 而非 exec_ 保持非阻塞
|
||||
self.diameter_warning_msg.show()
|
||||
|
||||
@ -3416,30 +3561,13 @@ class MainWindow(MainWindowUI):
|
||||
else:
|
||||
logging.debug("线径公差字段不存在或为空,跳过范围检查")
|
||||
|
||||
# 原有的数据库公差校验(保留作为备用)
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
inspection_dao = InspectionDAO()
|
||||
bccd, tccd = inspection_dao.get_xj_range(self._current_order_code)
|
||||
|
||||
if bccd is not None and tccd is not None:
|
||||
if float(bccd) - 0.02 <= final_value <= float(tccd) + 0.02:
|
||||
# 保存线径数据到表格
|
||||
try:
|
||||
# 使用set_inspection_value保存数据
|
||||
self.set_inspection_value('xj', xj_config, final_value)
|
||||
logging.info(f"已将稳定的线径值 {final_value:.3f} 保存到工程号 {gc_note} (行 {data_row})")
|
||||
else:
|
||||
# 使用信号槽机制确保在主线程中显示弹框
|
||||
self.diameter_warning_signal.emit(final_value, bccd, tccd)
|
||||
|
||||
# 重置测量列表,防止重复触发
|
||||
self._diameter_measurements = []
|
||||
|
||||
# 阻止继续执行,等待用户处理
|
||||
logging.warning(f"线径值 {final_value:.3f} 超出公差范围,已阻止保存,等待用户处理")
|
||||
return
|
||||
else:
|
||||
# 无公差范围,直接保存
|
||||
self.set_inspection_value('xj', xj_config, final_value)
|
||||
logging.info(f"已将线径值 {final_value:.3f} 保存到工程号 {gc_note} (行 {data_row})")
|
||||
except Exception as e:
|
||||
logging.error(f"保存线径数据到表格失败: {str(e)}")
|
||||
|
||||
# 重置测量列表,准备下一次测量
|
||||
self._diameter_measurements = []
|
||||
@ -3455,6 +3583,19 @@ class MainWindow(MainWindowUI):
|
||||
logging.warning(f"收到的数据不包含线径数据标记: {data_str}")
|
||||
except Exception as e:
|
||||
logging.error(f"处理线径数据失败: {str(e)}")
|
||||
import traceback
|
||||
logging.error(f"错误详情: {traceback.format_exc()}")
|
||||
finally:
|
||||
# 确保关闭Modbus客户端连接
|
||||
if modbus_client:
|
||||
try:
|
||||
ModbusUtils().close_client(modbus_client)
|
||||
except Exception as e:
|
||||
logging.error(f"关闭Modbus客户端连接失败: {str(e)}")
|
||||
|
||||
# 确保清理测量列表
|
||||
if hasattr(self, '_diameter_measurements') and len(self._diameter_measurements) >= 5:
|
||||
self._diameter_measurements = []
|
||||
|
||||
def _save_diameter_to_order(self, order_id, config, value):
|
||||
"""基于工程号保存线径值,确保即使行号变化也能保存到正确的产品"""
|
||||
@ -3493,10 +3634,13 @@ class MainWindow(MainWindowUI):
|
||||
self.diameter_warning_msg.setIcon(QMessageBox.Warning)
|
||||
self.diameter_warning_msg.setWindowTitle('线径超出范围')
|
||||
self.diameter_warning_msg.setText(f"线径 {final_value:.3f} 不在公差范围内 ({bccd} - {tccd})")
|
||||
self.diameter_warning_msg.setStandardButtons(QMessageBox.NoButton) # 不显示按钮
|
||||
self.diameter_warning_msg.setStandardButtons(QMessageBox.Ok) # 添加确定按钮
|
||||
self.diameter_warning_msg.setModal(False) # 确保非模态
|
||||
self.diameter_warning_msg.setWindowFlags(self.diameter_warning_msg.windowFlags() | Qt.WindowStaysOnTopHint) # 置顶显示
|
||||
|
||||
# 连接按钮点击信号
|
||||
self.diameter_warning_msg.buttonClicked.connect(lambda btn: self.diameter_warning_msg.close())
|
||||
|
||||
# 显示提示框(非模态)
|
||||
self.diameter_warning_msg.show()
|
||||
|
||||
@ -3551,6 +3695,20 @@ class MainWindow(MainWindowUI):
|
||||
scan_data = data_str.split("扫码数据:")[1].strip()
|
||||
logging.info(f"提取到扫码数据: {scan_data}")
|
||||
|
||||
# 防抖机制:记录上次扫码的数据和时间
|
||||
current_time = time.time()
|
||||
last_scan_time = getattr(self, '_last_scan_time', 0)
|
||||
last_scan_data = getattr(self, '_last_scan_data', '')
|
||||
|
||||
# 如果是相同的数据且间隔小于1秒,则忽略此次扫码
|
||||
if last_scan_data == scan_data and current_time - last_scan_time < 1.0:
|
||||
logging.info(f"忽略重复扫码数据: {scan_data},间隔太短")
|
||||
return
|
||||
|
||||
# 更新最后扫码的数据和时间
|
||||
self._last_scan_data = scan_data
|
||||
self._last_scan_time = current_time
|
||||
|
||||
# 使用焦点跟踪器设置文本并触发回车事件
|
||||
from utils.focus_tracker import FocusTracker
|
||||
focus_tracker = FocusTracker.get_instance()
|
||||
@ -4643,7 +4801,30 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
def handle_inspection_cell_changed(self, row, column):
|
||||
"""处理检验表格单元格内容变更事件"""
|
||||
# 创建唯一键,包含行、列、工程号
|
||||
try:
|
||||
# 获取工程号,用于创建更精确的唯一键
|
||||
order_item = self.process_table.item(row, 1)
|
||||
gc_note = order_item.text().strip() if order_item else ""
|
||||
|
||||
# 创建包含行、列、工程号的唯一键
|
||||
cell_key = f"{row}_{column}_{gc_note}"
|
||||
current_time = time.time()
|
||||
|
||||
# 获取上次处理时间
|
||||
last_process_times = getattr(self, '_last_cell_process_times', {})
|
||||
last_process_time = last_process_times.get(cell_key, 0)
|
||||
|
||||
# 如果同一单元格在1秒内被处理过,则忽略
|
||||
if current_time - last_process_time < 1.0:
|
||||
logging.info(f"防抖:跳过重复处理单元格 [{row}, {column}], 工程号={gc_note},间隔小于1秒")
|
||||
return
|
||||
|
||||
# 更新处理时间
|
||||
if not hasattr(self, '_last_cell_process_times'):
|
||||
self._last_cell_process_times = {}
|
||||
self._last_cell_process_times[cell_key] = current_time
|
||||
|
||||
# 只处理数据行的检验列变更
|
||||
if row < 2: # 忽略表头行
|
||||
return
|
||||
@ -4653,11 +4834,6 @@ class MainWindow(MainWindowUI):
|
||||
return
|
||||
|
||||
# 获取工程号
|
||||
order_item = self.process_table.item(row, 1)
|
||||
if not order_item:
|
||||
return
|
||||
|
||||
gc_note = order_item.text().strip()
|
||||
if not gc_note:
|
||||
return
|
||||
|
||||
@ -4743,7 +4919,14 @@ class MainWindow(MainWindowUI):
|
||||
# 延迟一段时间后再触发查询,避免频繁刷新UI
|
||||
# 但要避免在加载过程中触发新的加载
|
||||
if not self._loading_data_in_progress:
|
||||
QTimer.singleShot(1000, self._safe_load_data)
|
||||
# 使用类变量保存定时器,避免创建多个定时器
|
||||
if hasattr(self, '_load_data_timer') and self._load_data_timer is not None:
|
||||
self._load_data_timer.stop()
|
||||
|
||||
self._load_data_timer = QTimer()
|
||||
self._load_data_timer.setSingleShot(True)
|
||||
self._load_data_timer.timeout.connect(self._safe_load_data)
|
||||
self._load_data_timer.start(1000)
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user