feat:修复线径测量问题
This commit is contained in:
parent
268a1cc16b
commit
23823d08f8
@ -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,
|
||||
|
||||
@ -1189,4 +1189,72 @@ class InspectionDAO:
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"查询检验数据失败: {str(e)}")
|
||||
return None
|
||||
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
|
||||
}
|
||||
BIN
db/jtDB.db
BIN
db/jtDB.db
Binary file not shown.
@ -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}")
|
||||
|
||||
@ -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)
|
||||
Loading…
Reference in New Issue
Block a user