diff --git a/config/app_config.json b/config/app_config.json index 66d41c5..ce0c39a 100644 --- a/config/app_config.json +++ b/config/app_config.json @@ -103,7 +103,7 @@ "parity": "N", "port": "19200", "query_cmd": "01 41 0d", - "query_interval": 5, + "query_interval": 1, "auto_query": true, "ser": "COM3", "stop_bits": 1, diff --git a/dao/inspection_dao.py b/dao/inspection_dao.py index 436f000..e14dab2 100644 --- a/dao/inspection_dao.py +++ b/dao/inspection_dao.py @@ -1189,4 +1189,72 @@ class InspectionDAO: except Exception as e: logging.error(f"查询检验数据失败: {str(e)}") - return None \ No newline at end of file + return None + def get_package_statistics(self, order_id=None): + """获取包装记录的统计数据 + + Args: + order_id: 订单号,如果为None则获取所有订单的统计 + + Returns: + dict: 包含当前订单和所有订单的统计数据 + { + 'count': 当前订单的记录数量, + 'weight': 当前订单的总重量, + 'count_all': 所有订单的记录数量, + 'weight_all': 所有订单的总重量 + } + """ + try: + # 构建SQL查询 + sql = """ + SELECT SUM(weight) weight, + SUM(count) count, + SUM(count_all) count_all, + SUM(weight_all) weight_all + FROM ( + SELECT COUNT(gc_note) AS count, + SUM(weight) AS weight, + '' AS count_all, + '' AS weight_all + FROM wsbz_inspection_pack_data + WHERE order_id = ? + UNION ALL + SELECT '', '', + COUNT(gc_note) AS count_all, + SUM(weight) AS weight_all + FROM wsbz_inspection_pack_data + ) a + """ + + with SQLUtils('sqlite', database='db/jtDB.db') as db: + # 执行查询 + db.cursor.execute(sql, (order_id or '',)) + + # 获取结果 + row = db.cursor.fetchone() + + # 如果有结果,转换为字典 + if row: + return { + 'weight': float(row[0] or 0), + 'count': int(row[1] or 0), + 'count_all': int(row[2] or 0), + 'weight_all': float(row[3] or 0) + } + else: + return { + 'weight': 0, + 'count': 0, + 'count_all': 0, + 'weight_all': 0 + } + + except Exception as e: + logging.error(f"获取包装记录统计数据失败: {str(e)}") + return { + 'weight': 0, + 'count': 0, + 'count_all': 0, + 'weight_all': 0 + } \ No newline at end of file diff --git a/db/jtDB.db b/db/jtDB.db index d03a1e0..4433962 100644 Binary files a/db/jtDB.db and b/db/jtDB.db differ diff --git a/utils/serial_manager.py b/utils/serial_manager.py index 1c3ca5b..b44f8bb 100644 --- a/utils/serial_manager.py +++ b/utils/serial_manager.py @@ -1117,8 +1117,8 @@ class SerialManager: byte_data = bytes.fromhex(query_cmd.replace(' ', '')) self.serial_ports[port_name].write(byte_data) - # 等待响应 - time.sleep(0.5) + # 等待响应 - 减少等待时间以加快数据获取 + time.sleep(0.2) if self.serial_ports[port_name].in_waiting > 0: response = self.serial_ports[port_name].read(self.serial_ports[port_name].in_waiting) @@ -1128,14 +1128,14 @@ class SerialManager: logging.error(f"线径数据处理异常: {e}") # 查询间隔,从配置中获取或使用默认值 - query_interval = self.xj_config.get('query_interval', 5) if self.xj_config else 5 - wait_cycles = int(query_interval * 10) # 转换为0.1秒的周期数 + query_interval = self.xj_config.get('query_interval', 1) if self.xj_config else 1 - # 每隔query_interval秒查询一次 - for i in range(wait_cycles): - if not self.running_flags.get(port_name, False): - break - time.sleep(0.1) + # 确保查询间隔不小于0.2秒 + if query_interval < 0.2: + query_interval = 0.2 + + # 每隔query_interval秒查询一次,使用更简单的等待方式 + time.sleep(query_interval) except Exception as e: logging.error(f"线径串口 {port_name} 读取线程异常: {e}") diff --git a/widgets/main_window.py b/widgets/main_window.py index 13e0cd0..f97a925 100644 --- a/widgets/main_window.py +++ b/widgets/main_window.py @@ -158,6 +158,9 @@ class MainWindow(MainWindowUI): # 加载已完成检验数据 self.show_pack_item() + + # 更新包装记录统计数据 + self.update_package_statistics() # 创建状态处理器实例 self.machine_handlers = MachineStatusHandlers() @@ -925,6 +928,11 @@ class MainWindow(MainWindowUI): self._last_order_gc = gc_note self._last_order_time = current_time + # 清除最近处理的线径工程号,确保新扫码的工程号不会使用之前的线径数据 + if hasattr(self, '_last_processed_gc_note'): + logging.info(f"清除最近处理线径数据的工程号: {self._last_processed_gc_note}") + self._last_processed_gc_note = None + logging.info(f"输入的工程号: {gc_note}") #判断是否是接口,如果不是接口直接添加如果是则走接口 # 如果开启接口模式,则需要调用接口同步到业务库 @@ -999,6 +1007,9 @@ class MainWindow(MainWindowUI): # 更新订单数量和产量统计数据 self.update_order_statistics() + + # 确保完整加载所有检验数据,包括线径数据 + self._safe_load_data() else: logging.warning("工程号为空,忽略处理") @@ -1027,28 +1038,14 @@ class MainWindow(MainWindowUI): logging.info(f"已生成虚拟工程号并直接添加: {virtual_gc_note}") + # 确保完整加载所有检验数据,包括线径数据 + self._safe_load_data() + except Exception as e: logging.error(f"生成虚拟工程号失败: {str(e)}") QMessageBox.critical(self, "错误", f"生成虚拟工程号失败: {str(e)}") - def _check_test_result(self): - """检查测试结果""" - logging.info("检查快速连续扫码测试结果") - total_rows = self.process_table.rowCount() - if total_rows > 2: - last_gc_note = self.process_table.item(total_rows - 1, 1) - if last_gc_note: - logging.info(f"最后一行的工程号: {last_gc_note.text()}") - if last_gc_note.text() == "B": - logging.info("✅ 测试通过:最新扫码的工程号B正确显示在最后") - else: - logging.error("❌ 测试失败:最新扫码的工程号B没有显示在最后") - else: - logging.error("❌ 测试失败:无法获取最后一行的工程号") - else: - logging.error("❌ 测试失败:表格中没有数据行") - def add_new_inspection_row(self, gc_note, order_code): """在微丝产线表格中添加一条新记录,添加到表格末尾 @@ -1131,9 +1128,6 @@ class MainWindow(MainWindowUI): # 选中新添加的行 self.process_table.selectRow(data_start_row) - # 移除行数限制,允许显示更多数据 - # self.limit_table_rows(10) # 最多保留10行数据 - # 将工程号和托盘号保存到数据库,确保能够正确关联 from dao.inspection_dao import InspectionDAO inspection_dao = InspectionDAO() @@ -1181,29 +1175,6 @@ class MainWindow(MainWindowUI): self._current_gc_note = None self._current_gc_note_timestamp = None - def limit_table_rows(self, max_rows): - """限制表格最大行数 - - Args: - max_rows: 最大行数(不包括表头行) - """ - try: - # 计算数据总行数 - data_rows = self.process_table.rowCount() - 2 # 减去表头行 - - # 如果超过最大行数,删除多余的行 - if data_rows > max_rows: - # 要删除的行数 - rows_to_remove = data_rows - max_rows - - # 从最后一行开始删除 - for i in range(rows_to_remove): - self.process_table.removeRow(self.process_table.rowCount() - 1) - - logging.info(f"已限制表格最大行数为 {max_rows} 行数据,删除了 {rows_to_remove} 行") - - except Exception as e: - logging.error(f"限制表格行数失败: {str(e)}") def handle_inspection_cell_changed(self, row, column): """处理微丝包装单元格内容变更 @@ -1415,29 +1386,48 @@ class MainWindow(MainWindowUI): # 获取当前托盘号,用于日志记录 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})") + # 检查是否有加载操作正在进行 + if getattr(self, '_loading_data_in_progress', False): + logging.warning(f"已有数据加载操作正在进行,忽略此次请求 (托盘号: {tray_id})") return - # 更新最后加载的时间 - self._last_safe_load_time = current_time + # 检查是否有递归调用 + call_stack_depth = getattr(self, '_safe_load_call_depth', 0) + 1 + self._safe_load_call_depth = call_stack_depth - # 检查是否已有定时器在运行 - 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("已停止之前的加载定时器") + # 如果调用栈深度超过3,可能存在递归调用 + if call_stack_depth > 3: + logging.warning(f"检测到可能的递归调用 _safe_load_data,调用栈深度: {call_stack_depth},忽略此次请求") + self._safe_load_call_depth -= 1 + return - # 创建新的定时器,延迟执行实际加载操作 - 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毫秒后执行 + try: + # 防抖机制:记录上次加载的时间 + 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 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毫秒后执行 + finally: + # 减少调用栈深度计数 + self._safe_load_call_depth -= 1 def _do_safe_load(self): """实际执行数据加载的方法,由定时器触发""" @@ -1605,7 +1595,7 @@ class MainWindow(MainWindowUI): 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']: + if position not in position_data or data.get('update_time', 0) > position_data[position].get('update_time', 0): position_data[position] = data # 添加检验数据到表格 @@ -1636,6 +1626,26 @@ class MainWindow(MainWindowUI): # 净重列索引 = 2(序号和工程号) + 检验列数 + 2(贴标和称重) net_weight_col = 2 + len(enabled_configs) + 2 self.process_table.setItem(row_idx, net_weight_col, QTableWidgetItem(str(value))) + + # 额外加载该工程号的线径数据(即使产品已完成) + for i, config in enumerate(enabled_configs): + if config.get('name') == 'xj' or config.get('display_name') == '线径': + xj_col = 2 + i + # 检查表格中是否已有线径数据 + xj_item = self.process_table.item(row_idx, xj_col) + if not xj_item or not xj_item.text().strip(): + # 如果表格中没有线径数据,尝试从数据库加载 + xj_data = inspection_dao.get_inspection_data_by_config( + self._current_order_code, gc_note, tray_id, position=config.get('position'), config_id=config.get('id') + ) + if xj_data and xj_data.get('value'): + # 设置线径数据到表格 + xj_item = QTableWidgetItem(str(xj_data.get('value'))) + xj_item.setTextAlignment(Qt.AlignCenter) + self.process_table.setItem(row_idx, xj_col, xj_item) + logging.info(f"从数据库加载线径数据: {xj_data.get('value')} 到工程号 {gc_note}") + break + row_idx += 1 # 设置表格为可编辑状态 @@ -1806,30 +1816,32 @@ class MainWindow(MainWindowUI): def update_package_statistics(self): """更新包装记录统计数据""" try: - # 获取包装记录表的行数 - package_count = self.record_table.rowCount() + # 使用DAO获取包装记录统计数据 + from dao.inspection_dao import InspectionDAO + inspection_dao = InspectionDAO() + stats = inspection_dao.get_package_statistics(self._current_order_code) - # 更新任务表格中的已完成数量 - completed_item = QTableWidgetItem(str(package_count)) + # 更新任务表格中的总生产数量(总数量) + total_count_item = QTableWidgetItem(str(stats['count_all'])) + total_count_item.setTextAlignment(Qt.AlignCenter) + self.task_table.setItem(2, 0, total_count_item) + + # 更新任务表格中的总生产公斤(总重量) + total_kg_item = QTableWidgetItem(f"{stats['weight_all']:.2f}") + total_kg_item.setTextAlignment(Qt.AlignCenter) + self.task_table.setItem(2, 1, total_kg_item) + + # 更新任务表格中的已完成数量(当前订单数量) + completed_item = QTableWidgetItem(str(stats['count'])) completed_item.setTextAlignment(Qt.AlignCenter) self.task_table.setItem(2, 2, completed_item) - # 计算已完成公斤数(如果称重列有数值) - completed_kg = 0 - for row in range(self.record_table.rowCount()): - weight_item = self.record_table.item(row, 6) # 称重列 - if weight_item and weight_item.text(): - try: - completed_kg += float(weight_item.text()) - except ValueError: - pass - - # 更新任务表格中的已完成公斤 - completed_kg_item = QTableWidgetItem(str(completed_kg)) + # 更新任务表格中的已完成公斤(当前订单重量) + completed_kg_item = QTableWidgetItem(f"{stats['weight']:.2f}") completed_kg_item.setTextAlignment(Qt.AlignCenter) self.task_table.setItem(2, 3, completed_kg_item) - logging.info(f"已更新包装记录统计数据: 完成数量={package_count}, 完成公斤={completed_kg}") + logging.info(f"已更新包装记录统计数据: 总生产数量={stats['count_all']}, 总生产公斤={stats['weight_all']:.2f}, 已完成数量={stats['count']}, 已完成公斤={stats['weight']:.2f}") except Exception as e: logging.error(f"更新包装记录统计数据失败: {str(e)}") @@ -2820,6 +2832,9 @@ class MainWindow(MainWindowUI): # 更新订单数量和产量统计数据 self.update_order_statistics() + # 更新包装记录统计数据 + self.update_package_statistics() + # 重新连接单元格变更信号 self.process_table.cellChanged.connect(self.handle_inspection_cell_changed) @@ -3318,6 +3333,9 @@ class MainWindow(MainWindowUI): # 更新订单数量和产量统计数据 self.update_order_statistics() + # 更新包装记录统计数据 + self.update_package_statistics() + logging.info(f"NG信号处理完成: 工程号={order_id}, 托盘号={tray_id}, 贴标值={label_value}") except Exception as e: logging.error(f"处理NG信号时发生错误: {str(e)}") @@ -3389,6 +3407,24 @@ class MainWindow(MainWindowUI): def on_diameter_data_received(self, port_name, data): """线径数据接收回调函数 - 采用类似称重的逻辑,不使用会话机制""" + # 添加处理锁,避免并发处理导致卡死 + if hasattr(self, '_processing_diameter_lock') and self._processing_diameter_lock: + logging.warning(f"已有线径数据处理进行中,忽略本次请求") + return + + # 设置处理锁,并添加超时保护 + self._processing_diameter_lock = True + self._diameter_processing_start_time = time.time() + + # 添加超时检测定时器 + if hasattr(self, '_diameter_timeout_timer') and self._diameter_timeout_timer is not None: + self._diameter_timeout_timer.stop() + + self._diameter_timeout_timer = QTimer() + self._diameter_timeout_timer.setSingleShot(True) + self._diameter_timeout_timer.timeout.connect(self._reset_diameter_processing_lock) + self._diameter_timeout_timer.start(5000) # 5秒超时保护 + modbus_client = None try: data_str = data.decode('utf-8') if isinstance(data, bytes) else str(data) @@ -3400,19 +3436,8 @@ class MainWindow(MainWindowUI): 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 @@ -3440,8 +3465,12 @@ class MainWindow(MainWindowUI): # 使用类属性存储最近的测量值,用于稳定性检测 if not hasattr(self, '_diameter_measurements'): self._diameter_measurements = [] + + # 添加当前测量值到列表 self._diameter_measurements.append(xj_value) - if len(self._diameter_measurements) > 5: + + # 保留最近的10个测量值,增加缓冲区大小以便更快收集足够的数据 + if len(self._diameter_measurements) > 10: self._diameter_measurements.pop(0) # 显示临时值到状态栏 @@ -3449,12 +3478,12 @@ class MainWindow(MainWindowUI): self.statusBar().showMessage(f"线径数据收集中: {xj_value:.3f} ({len(self._diameter_measurements)}/5)", 2000) return - # 检查稳定性 + # 检查稳定性 - 使用最近的5个测量值 measurements = self._diameter_measurements[-5:] min_value = min(measurements) max_value = max(measurements) avg_value = sum(measurements) / len(measurements) - error_range = avg_value * 0.04 # 允许4%误差 + error_range = avg_value * 0.05 # 允许5%误差,增加容错范围 if max_value - min_value <= error_range: # 数据稳定,可以保存 @@ -3462,11 +3491,26 @@ class MainWindow(MainWindowUI): # 查找第一个没有线径数据的行 data_row = None - for row in range(2, self.process_table.rowCount()): - cell_item = self.process_table.item(row, xj_column) - if not cell_item or not cell_item.text().strip() or cell_item.text().strip() == '0': - data_row = row - break + + # 如果有最近处理的线径工程号,优先查找该工程号对应的行 + if hasattr(self, '_last_processed_gc_note') and self._last_processed_gc_note: + for row in range(2, self.process_table.rowCount()): + order_id_item = self.process_table.item(row, 1) + if order_id_item and order_id_item.text().strip() == self._last_processed_gc_note: + # 检查该行的线径单元格是否为空 + cell_item = self.process_table.item(row, xj_column) + if not cell_item or not cell_item.text().strip() or cell_item.text().strip() == '0': + data_row = row + logging.info(f"找到最近处理的线径工程号 {self._last_processed_gc_note} 对应的行: {data_row}") + break + + # 如果没有找到最近处理的工程号对应的行,再查找第一个没有线径数据的行 + if data_row is None: + for row in range(2, self.process_table.rowCount()): + cell_item = self.process_table.item(row, xj_column) + if not cell_item or not cell_item.text().strip() or cell_item.text().strip() == '0': + data_row = row + break # 如果没找到空行,使用当前选中行或第一个数据行 if data_row is None: @@ -3486,6 +3530,10 @@ class MainWindow(MainWindowUI): if not gc_note: logging.warning("工程号为空") return + + # 记录最近处理的线径工程号,用于后续线径数据处理 + self._last_processed_gc_note = gc_note + logging.info(f"记录最近处理线径数据的工程号: {gc_note}") # 获取托盘号 tray_id = self.tray_edit.currentText() @@ -3566,12 +3614,11 @@ class MainWindow(MainWindowUI): # 使用set_inspection_value保存数据 self.set_inspection_value('xj', xj_config, final_value) logging.info(f"已将稳定的线径值 {final_value:.3f} 保存到工程号 {gc_note} (行 {data_row})") + + # 重置测量列表,准备下一次测量 + self._diameter_measurements = [] except Exception as e: logging.error(f"保存线径数据到表格失败: {str(e)}") - - # 重置测量列表,准备下一次测量 - self._diameter_measurements = [] - self.statusBar().showMessage(f"线径数据已保存: {final_value:.3f}", 2000) else: # 数据不稳定,继续收集 self.statusBar().showMessage(f"线径数据不稳定: {min_value:.3f} - {max_value:.3f}, 继续测量", 2000) @@ -3592,10 +3639,14 @@ class MainWindow(MainWindowUI): 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 = [] + + # 释放处理锁 + if hasattr(self, '_processing_diameter_lock'): + self._processing_diameter_lock = False + + # 停止超时定时器 + if hasattr(self, '_diameter_timeout_timer') and self._diameter_timeout_timer is not None: + self._diameter_timeout_timer.stop() def _save_diameter_to_order(self, order_id, config, value): """基于工程号保存线径值,确保即使行号变化也能保存到正确的产品""" @@ -3751,6 +3802,13 @@ class MainWindow(MainWindowUI): config: 检验项配置 value: 检验值 """ + # 添加防递归锁,避免死循环 + if hasattr(self, '_set_inspection_value_lock') and self._set_inspection_value_lock: + logging.warning(f"检测到递归调用set_inspection_value,忽略本次调用: {data_type}={value}") + return + + self._set_inspection_value_lock = True + try: # 获取检验项的列索引 config_id = config.get('id') @@ -3806,11 +3864,26 @@ class MainWindow(MainWindowUI): # 如果没有找到特定行,使用默认逻辑查找第一个没有该检测数据的行 if data_row is None: - for row in range(2, self.process_table.rowCount()): - cell_item = self.process_table.item(row, col_index) - if not cell_item or not cell_item.text().strip() or (data_type == 'xj' and cell_item.text().strip() == '0'): - data_row = row - break + # 新增:检查是否有最近添加的工程号,如果有,优先保存到之前的行 + if data_type == 'xj' and hasattr(self, '_last_processed_gc_note') and self._last_processed_gc_note: + # 查找最近处理的工程号对应的行 + for row in range(2, self.process_table.rowCount()): + order_id_item = self.process_table.item(row, 1) + if order_id_item and order_id_item.text().strip() == self._last_processed_gc_note: + # 检查该行的线径单元格是否为空 + cell_item = self.process_table.item(row, col_index) + if not cell_item or not cell_item.text().strip() or cell_item.text().strip() == '0': + data_row = row + logging.info(f"找到最近处理的工程号 {self._last_processed_gc_note} 对应的空线径单元格,行: {data_row}") + break + + # 如果没有找到最近处理的工程号对应的行,或者该行已有线径数据,再查找第一个没有该检测数据的行 + if data_row is None: + for row in range(2, self.process_table.rowCount()): + cell_item = self.process_table.item(row, col_index) + if not cell_item or not cell_item.text().strip() or (data_type == 'xj' and cell_item.text().strip() == '0'): + data_row = row + break # 如果没有找到没有该检测数据的行,使用当前选中行或第一个数据行 if data_row is None: @@ -3831,6 +3904,11 @@ class MainWindow(MainWindowUI): logging.warning("工程号为空") return + # 记录最近处理的工程号,用于后续线径数据处理 + if data_type == 'xj': + self._last_processed_gc_note = order_id + logging.info(f"记录最近处理线径数据的工程号: {order_id}") + # 暂时断开信号连接,避免触发cellChanged信号 try: self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed) @@ -3870,17 +3948,18 @@ class MainWindow(MainWindowUI): # 不需要在这里主动触发数据重新加载,因为handle_inspection_cell_changed会处理 # 重新连接信号 - self.process_table.cellChanged.connect(self.handle_inspection_cell_changed) - - logging.info(f"已将{data_type}数据 {formatted_value} 写入工程号 {order_id} (行 {data_row}, 列 {col_index})") - - except Exception as e: - logging.error(f"设置检验项值失败: {str(e)}") - # 确保重新连接信号 try: self.process_table.cellChanged.connect(self.handle_inspection_cell_changed) - except: - pass + except Exception as e: + logging.warning(f"重新连接cellChanged信号失败: {str(e)}") + + logging.info(f"成功设置{data_type}值 {formatted_value} 到工程号 {order_id} 的行 {data_row}") + + except Exception as e: + logging.error(f"设置检验值失败: {str(e)}") + finally: + # 释放锁 + self._set_inspection_value_lock = False def handle_tray_changed(self): """处理托盘号变更事件,启动监听并加载数据""" @@ -5025,5 +5104,14 @@ class MainWindow(MainWindowUI): from PySide6.QtWidgets import QMessageBox QMessageBox.critical(self, "错误", f"处理炉号选择失败: {str(e)}") + def _reset_diameter_processing_lock(self): + """重置线径处理锁,用于超时保护""" + if hasattr(self, '_processing_diameter_lock') and self._processing_diameter_lock: + processing_time = time.time() - getattr(self, '_diameter_processing_start_time', time.time()) + logging.warning(f"线径数据处理超时,强制释放锁。处理时间: {processing_time:.2f}秒") + self._processing_diameter_lock = False + + + def safe_str(val): return "" if val is None else str(val) \ No newline at end of file