feat: 更新电力监控配置,禁用自动启动功能;优化主窗口和串口设置界面,增强用户交互体验;修复部分代码格式和逻辑问题。

This commit is contained in:
zhu-mengmeng 2025-06-30 15:52:10 +08:00
parent 145a350fb8
commit 7a2351cbe6
6 changed files with 188 additions and 129 deletions

View File

@ -90,6 +90,6 @@
}
},
"electricity": {
"auto_start": true
"auto_start": false
}
}

Binary file not shown.

View File

@ -58,12 +58,22 @@ class MainWindow(MainWindowUI):
def __init__(self, user_id=None, user_name=None, corp_name=None, corp_id=None):
"""初始化主窗口"""
super().__init__(username=user_name) # 将 user_name 作为 username 参数传递给父类
super().__init__(user_id)
# 初始化用户信息
self.user_id = user_id
self.user_name = user_name
self.corp_name = corp_name
self.corp_id = corp_id
# 初始化系统变量
self._current_weight = 0.0 # 当前重量
self._last_weight_time = 0 # 上次称重时间
self._stability_check_timer = None # 稳定性检查定时器
self._weight_stable_threshold = 2 # 重量稳定阈值(秒)
self._weight_processed = False # 新增:标记当前重量是否已处理,避免重复处理
self._last_processed_weight = 0.0 # 新增:记录上次处理的重量
# 初始化数据加载状态标志
self._loading_data_in_progress = False # 数据加载状态标志,防止循环调用
self._current_order_code = None # 存储当前订单号
@ -421,7 +431,7 @@ class MainWindow(MainWindowUI):
from widgets.loading_dialog_widget import LoadingDialog
dialog = LoadingDialog(parent=self,user_id=self.user_id,user_name=self.user_name,corp_id=self.corp_id)
# 如果已有上料信息,则填充到对话框
# 如果已有上料信息,作为参考显示在对话框中,但允许用户修改
if self._loading_info and self._current_stow_num > 0:
dialog.order_input.setText(self._loading_info.get('order_code', ''))
dialog.tray_input.setText(self._loading_info.get('tray_code', ''))
@ -429,11 +439,7 @@ class MainWindow(MainWindowUI):
dialog.quantity_value.setText(self._loading_info.get('quantity_value', '--'))
dialog.weight_value.setText(self._loading_info.get('weight_value', '--'))
dialog.pallet_tier_value.setText(str(self._current_stow_num))
# 只有当上料任务正在进行时才禁用输入框
if self._is_loading_active:
# 禁用输入框,防止修改
dialog.order_input.setEnabled(False)
dialog.tray_input.setEnabled(False)
# 不禁用输入框,允许用户修改
# 连接订单号信号
dialog.order_code_signal.connect(self.handle_order_code_received)
@ -455,8 +461,7 @@ class MainWindow(MainWindowUI):
QMessageBox.warning(self, "错误", "未获取到托盘料信息,请重试")
return
# 如果是新的上料操作没有存储的信息或层数为0
if not self._loading_info or self._current_stow_num == 0:
# 始终使用用户最新输入的信息
self._current_stow_num = int(stow_num)
# 保存上料信息
self._loading_info = {
@ -495,23 +500,20 @@ class MainWindow(MainWindowUI):
dialog = UnloadingDialog(self, self.user_id)
# 如果是同一下料任务_current_unload_info不为空则回显信息
# 如果有之前的下料信息,作为参考显示在对话框中,但允许用户修改
if self._current_unload_info:
# 关键:确保回显到对话框的是固定的总层数
self._current_unload_info['tier'] = str(self._total_unload_num)
dialog.set_unloading_info(self._current_unload_info)
logging.info(f"回显下料信息:当前层数={self._current_unload_num}, 总层数={self._total_unload_num}")
logging.info(f"显示之前的下料信息作为参考")
if dialog.exec_() == QDialog.Accepted:
# 获取用户最新输入的下料信息
unloading_info = dialog.get_unloading_info()
# 仅当开始一次全新的下料时(没有进行中的任务),才设置总层数
is_new_task = not self._current_unload_info or self._current_unload_num == 0
if is_new_task:
# 始终使用用户最新输入的信息
self._total_unload_num = int(unloading_info.get('tier', '3'))
self._current_unload_num = 1
self._current_unload_num = 1 # 从第一层开始
self._current_unload_info = unloading_info
logging.info(f"新的下料任务开始:总层数={self._total_unload_num}, 当前层数={self._current_unload_num}")
logging.info(f"下料任务设置:总层数={self._total_unload_num}, 当前层数={self._current_unload_num}")
# 将初始层数(1)写入寄存器
modbus = ModbusUtils()
@ -521,8 +523,6 @@ class MainWindow(MainWindowUI):
logging.info(f"下料初始化成功:层数 {self._current_unload_num} 已写入寄存器4")
finally:
modbus.close_client(client)
else:
logging.info(f"继续下料任务:总层数={self._total_unload_num}, 当前层数={self._current_unload_num}")
# 统一更新UI显示
tray_code = self._current_unload_info.get('tray_code', '')
@ -536,42 +536,42 @@ class MainWindow(MainWindowUI):
def restore_start_button_style(self):
"""恢复开始按钮的原始样式"""
try:
self.start_button.setStyleSheet("""
# 使用与main_window_ui.py中初始化时相同的样式只恢复背景色
button_style = """
QPushButton {
background-color: transparent;
color: black;
border: 1px solid #4caf50;
padding: 8px 16px;
font-weight: bold;
border-radius: 4px;
padding: 2px 10px;
min-height: 29px;
max-height: 29px;
border: 1px solid #4caf50;
}
QPushButton:hover {
background-color: #f0f0f0;
background-color: #d7eeda;
}
""")
"""
self.start_button.setStyleSheet(button_style)
logging.info("已恢复开始按钮原始样式")
except Exception as e:
logging.error(f"{str(e)}")
logging.error(f"恢复开始按钮样式失败: {str(e)}")
def fill_start_button_style(self):
"""填充开始按钮样式 - 绿色背景,白色字体"""
try:
# 填充按钮样式 - 绿色背景,白色字体,高度与下料按钮一致
self.start_button.setStyleSheet("""
# 使用与main_window_ui.py中初始化时相同的样式只改变背景色和文字颜色
button_style = """
QPushButton {
padding: 8px 16px;
font-weight: bold;
border-radius: 4px;
background-color: #4caf50;
color: white;
border: 1px solid #4caf50;
border-radius: 4px;
padding: 2px 10px;
min-height: 29px;
max-height: 29px;
}
QPushButton:hover {
background-color: #4caf50;
background-color: #45a049;
color: white;
}
""")
"""
self.start_button.setStyleSheet(button_style)
logging.info("已填充开始按钮样式")
except Exception as e:
logging.error(f"填充开始按钮样式失败: {str(e)}")
@ -1723,6 +1723,11 @@ class MainWindow(MainWindowUI):
logging.info(f"[显示] 称重数据: {weight_in_kg}kg (原始值: {weight_in_g}g)")
self.weight_label.setText(f"重量: {weight_in_kg}kg")
# 检测重量从接近0到较大值的变化判断为新产品
if self._current_weight is not None and self._current_weight < 0.1 and weight_in_kg > 0.5:
logging.info(f"检测到新产品放上,重量从 {self._current_weight}kg 变为 {weight_in_kg}kg")
self._weight_processed = False # 重置处理标记,允许处理新产品
# 更新当前重量和时间
self._current_weight = weight_in_kg
self._last_weight_time = current_time
@ -1737,25 +1742,25 @@ class MainWindow(MainWindowUI):
self._stability_check_timer.setSingleShot(True) # 单次触发
self._stability_check_timer.timeout.connect(lambda: self._check_weight_stability(weight_in_kg))
self._stability_check_timer.start(self._weight_stable_threshold * 1000) # 转换为毫秒
# 获取当前选中的行或第一个数据行
# 尝试获取表格行数据,用于日志记录
current_row = self.process_table.currentRow()
data_row = current_row if current_row >= 2 else 2 # 使用第一个数据行索引为2
tray_id = self.tray_edit.currentText()
# 确保行存在
# 记录表格行状态,仅用于日志记录,不影响后续处理
if data_row >= self.process_table.rowCount():
logging.warning(f"选中的行 {data_row} 超出了表格范围")
return
# 获取工程号
gc_note = self.process_table.item(data_row, 1)
if not gc_note:
logging.warning("无法获取工程号")
return
gc_note = gc_note.text().strip()
if not gc_note:
else:
# 获取工程号,仅用于日志记录
gc_note_item = self.process_table.item(data_row, 1)
if gc_note_item:
gc_note = gc_note_item.text().strip()
if gc_note:
logging.info(f"当前处理的工程号: {gc_note}, 行: {data_row}")
else:
logging.warning("工程号为空")
return
else:
logging.warning("无法获取工程号")
except Exception as e:
logging.error(f"处理称重数据时发生错误: {str(e)}")
# 确保重新连接信号
@ -1774,9 +1779,27 @@ class MainWindow(MainWindowUI):
# 如果当前重量与定时器启动时的重量相同,说明这段时间内没有新的重量数据
if self._current_weight == original_weight_kg:
logging.info(f"重量 {original_weight_kg}kg 在{self._weight_stable_threshold}秒内保持稳定")
# 如果这个重量与上一次处理的重量接近±0.1kg),且标记已处理,则跳过
if self._weight_processed and abs(original_weight_kg - self._last_processed_weight) < 0.1:
logging.info(f"跳过处理:重量 {original_weight_kg}kg 与上次处理的重量 {self._last_processed_weight}kg 接近且已处理")
return
# 称重稳定后,给寄存器 D10 为 1 表示已经称重完成
modbus = ModbusUtils()
client = modbus.get_client()
modbus.write_register_until_success(client, 10, 1)
modbus.close_client(client)
# 处理稳定重量
self._process_stable_weight(original_weight_kg)
# 调用打印方法
self._print_weight_label(original_weight_kg)
# 设置已处理标记和上次处理的重量
self._weight_processed = True
self._last_processed_weight = original_weight_kg
logging.info(f"已标记重量 {original_weight_kg}kg 为已处理")
else:
logging.info(f"重量在{self._weight_stable_threshold}秒内发生变化,从 {original_weight_kg}kg 变为 {self._current_weight}kg")
except Exception as e:
@ -1794,6 +1817,11 @@ class MainWindow(MainWindowUI):
weight_kg: 稳定的重量值千克
"""
try:
# 忽略接近0的重量值这可能表示产品已被移除
if weight_kg < 0.1: # 小于100g的重量视为无效
logging.info(f"忽略接近零的重量值: {weight_kg}kg可能表示产品已被移除")
return
# 获取数据行数
if self.process_table.rowCount() <= 2: # 没有数据行
logging.warning("没有可用的数据行来写入称重数据")
@ -1807,14 +1835,21 @@ class MainWindow(MainWindowUI):
# 计算净重列索引 - 净重位置在检验列之后的第三列(称重后面)
net_weight_col = 2 + len(enabled_configs) + 2
# 获取当前选中的行或第一个数据行
# 查找第一个没有称重数据的行
data_row = None
for row in range(2, self.process_table.rowCount()):
weight_item = self.process_table.item(row, weight_col)
if not weight_item or not weight_item.text().strip():
data_row = row
break
# 如果没有找到没有称重数据的行,使用当前选中行或第一个数据行
if data_row is None:
current_row = self.process_table.currentRow()
data_row = current_row if current_row >= 2 else 2 # 使用第一个数据行索引为2
# 确保行存在
if data_row >= self.process_table.rowCount():
logging.warning(f"选中的行 {data_row} 超出了表格范围")
return
logging.info(f"未找到没有称重数据的行,使用当前选中行或第一个数据行: {data_row}")
else:
logging.info(f"找到没有称重数据的行: {data_row}")
# 获取工程号
gc_note = self.process_table.item(data_row, 1)
@ -1868,7 +1903,7 @@ class MainWindow(MainWindowUI):
inspection_dao = InspectionDAO()
# 调用接口
gc_api = GcApi()
axios_num = self.get_axios_num_by_order_id(self._current_order_code)+1
axios_num = self.get_axios_num_by_order_id(self._current_order_code) + 1
# 获取订单信息和其他信息,两者都已经是字典格式
info = {}
order_info = inspection_dao.get_order_info(self._current_order_code)
@ -1986,7 +2021,7 @@ class MainWindow(MainWindowUI):
pass
# 创建并设置贴标单元格
label_item = QTableWidgetItem(axios_num)
label_item = QTableWidgetItem(str(axios_num))
label_item.setTextAlignment(Qt.AlignCenter)
# 写入单元格
@ -2221,11 +2256,18 @@ class MainWindow(MainWindowUI):
self.error_1 = error_code
self._update_error_status()
# 如果有故障,显示提示
if error_code in (2, 3):
# 如果有故障,显示提示(对任何错误码都弹框)
if error_code > 0:
QMessageBox.warning(self, "机器人视觉报警", f"机器人视觉报警: {detailed_desc}")
# 移除在下料区域显示异常信息的代码
# 获取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)
def handle_error_2(self, error_code, error_desc):
@ -2238,8 +2280,18 @@ class MainWindow(MainWindowUI):
self.error_2 = error_code
self._update_error_status()
# 如果有故障,显示提示
# 移除在下料区域显示异常信息的代码
# 如果有故障,显示提示(对任何错误码都弹框)
if error_code > 0:
QMessageBox.warning(self, "滚筒线报警", f"滚筒线报警: {detailed_desc}")
# 获取Modbus连接
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)
def handle_error_3(self, error_code, error_desc):
@ -2263,7 +2315,7 @@ class MainWindow(MainWindowUI):
elif error_code == 2:
QMessageBox.warning(self, "异常", f"异常: {detailed_desc}")
modbus.write_register_until_success(client, 3, 0)
modbus.write_register_until_success(client, 0, 0)
modbus.write_register_until_success(client, 4, 0)
modbus.close_client(client)
@Slot(int)
@ -2558,36 +2610,6 @@ class MainWindow(MainWindowUI):
value: 检验值
"""
try:
# 获取当前选中的行或第一个数据行
current_row = self.process_table.currentRow()
data_row = current_row if current_row >= 2 else 2 # 使用第一个数据行索引为2
# 确保行存在
if data_row >= self.process_table.rowCount():
logging.warning(f"选中的行 {data_row} 超出了表格范围")
# 可能需要添加新行
if self.process_table.rowCount() <= 2: # 只有表头行
order_id = self.order_edit.text().strip()
if order_id:
self.add_new_inspection_row(order_id)
data_row = 2 # 新添加的行
else:
logging.warning("无法添加新行,订单号为空")
return
else:
return
# 获取工程号
order_id_item = self.process_table.item(data_row, 1)
if not order_id_item:
logging.warning("无法获取工程号")
return
order_id = order_id_item.text().strip()
if not order_id:
logging.warning("工程号为空")
return
# 获取检验项的列索引
config_id = config.get('id')
config_position = config.get('position')
@ -2606,6 +2628,43 @@ class MainWindow(MainWindowUI):
logging.warning(f"未找到{data_type}对应的列索引")
return
# 检查表格是否有数据行
if self.process_table.rowCount() <= 2: # 只有表头行
order_id = self.order_edit.text().strip()
if order_id:
self.add_new_inspection_row(order_id)
data_row = 2 # 新添加的行
else:
logging.warning("无法添加新行,订单号为空")
return
# 查找第一个没有该检测数据的行
data_row = 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():
data_row = row
break
# 如果没有找到没有该检测数据的行,使用当前选中行或第一个数据行
if data_row is None:
current_row = self.process_table.currentRow()
data_row = current_row if current_row >= 2 else 2 # 使用第一个数据行索引为2
logging.info(f"未找到没有{data_type}数据的行,使用当前选中行或第一个数据行: {data_row}")
else:
logging.info(f"找到没有{data_type}数据的行: {data_row}")
# 获取工程号
order_id_item = self.process_table.item(data_row, 1)
if not order_id_item:
logging.warning("无法获取工程号")
return
order_id = order_id_item.text().strip()
if not order_id:
logging.warning("工程号为空")
return
# 暂时断开信号连接避免触发cellChanged信号
try:
self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed)