Compare commits
6 Commits
bacd7e84ab
...
c091a55cb0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c091a55cb0 | ||
|
|
507a345d43 | ||
|
|
1a5fa1a95b | ||
|
|
428df1d388 | ||
|
|
dfa09ea585 | ||
|
|
acb8e2f854 |
86
apis/tary_api.py
Normal file
86
apis/tary_api.py
Normal file
@ -0,0 +1,86 @@
|
||||
from utils.api_utils import ApiUtils
|
||||
import logging
|
||||
|
||||
class TaryApi:
|
||||
def __init__(self):
|
||||
"""初始化托盘API工具类"""
|
||||
self.api_utils = ApiUtils()
|
||||
|
||||
def get_tary_info(self, tary_code):
|
||||
"""
|
||||
获取托盘信息
|
||||
|
||||
Args:
|
||||
tary_code: 托盘编号
|
||||
|
||||
Returns:
|
||||
dict: 托盘信息
|
||||
"""
|
||||
try:
|
||||
# API 配置中的键名
|
||||
api_key = "get_tray_info"
|
||||
|
||||
# 将托盘号作为参数传递
|
||||
response = self.api_utils.get(api_key, params={"tp_note": tary_code})
|
||||
|
||||
# 记录API响应
|
||||
logging.info(f"托盘API响应: {response}")
|
||||
|
||||
# 请求失败时返回空数据
|
||||
if not response.get("status", False):
|
||||
return {
|
||||
"success": False,
|
||||
"message": "获取托盘信息失败",
|
||||
"data": None
|
||||
}
|
||||
|
||||
# 成功时格式化数据
|
||||
if response.get("data"):
|
||||
# 记录data的类型
|
||||
logging.info(f"数据类型: {type(response['data'])}, 数据内容: {response['data']}")
|
||||
|
||||
# 如果data直接是对象,则使用该对象
|
||||
if isinstance(response["data"], dict):
|
||||
logging.info("处理data为字典的情况")
|
||||
tray_info = response["data"]
|
||||
# 如果data是数组,并且有元素,则使用第一个元素
|
||||
elif isinstance(response["data"], list) and len(response["data"]) > 0:
|
||||
logging.info("处理data为数组的情况")
|
||||
tray_info = response["data"][0]
|
||||
else:
|
||||
logging.warning(f"数据格式不支持: {response['data']}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "托盘数据格式不正确",
|
||||
"data": None
|
||||
}
|
||||
|
||||
# 构建返回数据
|
||||
formatted_data = {
|
||||
"tp_note": tray_info.get("tp_note", ""), # 托盘号
|
||||
"product_name": tray_info.get("zx_name", ""), # 产品名称
|
||||
"axis_type": tray_info.get("zx", ""), # 轴型
|
||||
"tier": str(tray_info.get("cs", "")), # 托盘料
|
||||
"weight": str(tray_info.get("zl", "")), # 重量
|
||||
"quantity": "" # 数量先空下
|
||||
}
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": "获取托盘信息成功",
|
||||
"data": formatted_data
|
||||
}
|
||||
|
||||
# 数据为空
|
||||
return {
|
||||
"success": False,
|
||||
"message": "未找到托盘信息",
|
||||
"data": None
|
||||
}
|
||||
except Exception as e:
|
||||
logging.error(f"获取托盘信息异常: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"获取托盘信息异常: {str(e)}",
|
||||
"data": None
|
||||
}
|
||||
@ -6,7 +6,12 @@
|
||||
"enable_serial_ports": false,
|
||||
"enable_keyboard_listener": false,
|
||||
"enable_camera": false
|
||||
}
|
||||
},
|
||||
"base_url": "http://localhost:8084",
|
||||
"mode": "standalone"
|
||||
},
|
||||
"apis": {
|
||||
"get_tray_info": "/apjt/xcsc/tpda/getByTp_note/"
|
||||
},
|
||||
"database": {
|
||||
"default": "sqlite",
|
||||
@ -43,10 +48,11 @@
|
||||
"host": "localhost",
|
||||
"port": "5020"
|
||||
},
|
||||
"serial":{
|
||||
"keyboard":{
|
||||
"trigger_key":"Key.page_up"
|
||||
},"mdz":{
|
||||
"serial": {
|
||||
"keyboard": {
|
||||
"trigger_key": "Key.page_up"
|
||||
},
|
||||
"mdz": {
|
||||
"bit": 10,
|
||||
"code": "mdz",
|
||||
"data_bits": 8,
|
||||
@ -57,7 +63,8 @@
|
||||
"ser": "COM5",
|
||||
"stop_bits": 1,
|
||||
"timeout": 1
|
||||
},"cz":{
|
||||
},
|
||||
"cz": {
|
||||
"bit": 10,
|
||||
"code": "cz",
|
||||
"data_bits": 8,
|
||||
|
||||
@ -430,7 +430,7 @@ class InspectionDAO:
|
||||
# TODO:调用接口,获取到工程号对应的其他信息,比如材质,规格,后续完成
|
||||
try:
|
||||
sql = """
|
||||
INSERT INTO inspection_pack_data (order_id, tray_id, axis_package_id, weight, net_weight, pack_time, create_time, create_by, update_time, update_by, is_deleted)
|
||||
INSERT INTO wsbz_inspection_pack_data (order_id, tray_id, axis_package_id, weight, net_weight, pack_time, create_time, create_by, update_time, update_by, is_deleted)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
params = (order_id, tray_id, label_value, weight_value, net_weight_value, finish_time, datetime.now(), 'system', datetime.now(), 'system', False)
|
||||
|
||||
@ -14,70 +14,36 @@ class PalletTypeDAO:
|
||||
if hasattr(self, 'db'):
|
||||
self.db.close()
|
||||
|
||||
def get_all_pallet_types(self, include_disabled=False):
|
||||
"""获取所有托盘类型
|
||||
|
||||
Args:
|
||||
include_disabled: 是否包含禁用的类型
|
||||
|
||||
Returns:
|
||||
list: 托盘类型列表
|
||||
"""
|
||||
def get_pallet_code(self):
|
||||
"""获取托盘号"""
|
||||
try:
|
||||
if include_disabled:
|
||||
sql = """
|
||||
SELECT id, type_name, operation_type, description, enabled, sort_order
|
||||
FROM wsbz_pallet_types
|
||||
sql = """
|
||||
SELECT DISTINCT pallet_code
|
||||
FROM wsbz_pallet_archives
|
||||
WHERE is_deleted = FALSE
|
||||
ORDER BY sort_order
|
||||
"""
|
||||
params = ()
|
||||
else:
|
||||
sql = """
|
||||
SELECT id, type_name, operation_type, description, enabled, sort_order
|
||||
FROM wsbz_pallet_types
|
||||
WHERE is_deleted = FALSE AND enabled = TRUE
|
||||
ORDER BY sort_order
|
||||
"""
|
||||
params = ()
|
||||
|
||||
self.db.cursor.execute(sql, params)
|
||||
"""
|
||||
self.db.cursor.execute(sql)
|
||||
results = self.db.cursor.fetchall()
|
||||
|
||||
pallet_types = []
|
||||
for row in results:
|
||||
pallet_type = {
|
||||
'id': row[0],
|
||||
'type_name': row[1],
|
||||
'operation_type': row[2],
|
||||
'description': row[3],
|
||||
'enabled': bool(row[4]),
|
||||
'sort_order': row[5]
|
||||
}
|
||||
pallet_types.append(pallet_type)
|
||||
|
||||
return pallet_types
|
||||
return [row[0] for row in results]
|
||||
except Exception as e:
|
||||
logging.error(f"获取托盘类型失败: {str(e)}")
|
||||
logging.error(f"获取托盘号失败: {str(e)}")
|
||||
return []
|
||||
|
||||
def get_pallet_type_by_pallet_id(self, pallet_id):
|
||||
def get_pallet_type_by_pallet_id(self, pallet_code):
|
||||
"""根据托盘号获取托盘类型
|
||||
|
||||
Args:
|
||||
pallet_id: 托盘号
|
||||
pallet_code: 托盘号
|
||||
|
||||
Returns:
|
||||
dict: 托盘类型信息,未找到则返回None
|
||||
"""
|
||||
try:
|
||||
sql = """
|
||||
SELECT DISTINCT sort_order
|
||||
SELECT DISTINCT tier
|
||||
FROM wsbz_pallet_archives t1
|
||||
LEFT JOIN wsbz_pallet_types t2 ON t1.type_id = t2.id
|
||||
WHERE pallet_id = ? AND t1.is_deleted = FALSE
|
||||
WHERE pallet_code = ? AND t1.is_deleted = FALSE
|
||||
"""
|
||||
params = (pallet_id,)
|
||||
params = (pallet_code,)
|
||||
self.db.cursor.execute(sql, params)
|
||||
row = self.db.cursor.fetchone()
|
||||
if row:
|
||||
@ -85,7 +51,37 @@ class PalletTypeDAO:
|
||||
except Exception as e:
|
||||
logging.error(f"获取托盘类型失败: {str(e)}")
|
||||
return None
|
||||
|
||||
def get_pallet_info_by_pallet_id(self, pallet_code):
|
||||
"""根据托盘号获取托盘信息
|
||||
|
||||
Args:
|
||||
pallet_code: 托盘号
|
||||
|
||||
Returns:
|
||||
dict: 托盘信息,未找到则返回None
|
||||
"""
|
||||
try:
|
||||
sql = """
|
||||
SELECT pallet_code,
|
||||
pallet_name,
|
||||
description,
|
||||
axios_name,
|
||||
axios_type,
|
||||
tier,
|
||||
size,
|
||||
amount,
|
||||
weight
|
||||
FROM wsbz_pallet_archives t1
|
||||
WHERE pallet_code = ? AND t1.is_deleted = FALSE
|
||||
"""
|
||||
params = (pallet_code,)
|
||||
self.db.cursor.execute(sql, params)
|
||||
row = self.db.cursor.fetchone()
|
||||
if row:
|
||||
return row
|
||||
except Exception as e:
|
||||
logging.error(f"获取托盘类型失败: {str(e)}")
|
||||
return None
|
||||
def get_pallet_types_by_operation(self, operation_type, include_disabled=False):
|
||||
"""根据操作类型获取托盘类型
|
||||
|
||||
|
||||
BIN
db/jtDB.db
BIN
db/jtDB.db
Binary file not shown.
@ -55,8 +55,8 @@ SET enum_values = '["A区", "B区", "C区", "D区"]'
|
||||
WHERE name = 'fzd' AND is_deleted = FALSE;
|
||||
|
||||
-- 包装记录表
|
||||
drop table if exists inspection_pack_data;
|
||||
create table if not exists inspection_pack_data
|
||||
drop table if exists wsbz_inspection_pack_data;
|
||||
create table if not exists wsbz_inspection_pack_data
|
||||
(
|
||||
--订单号
|
||||
order_id VARCHAR(50),
|
||||
|
||||
@ -2,13 +2,14 @@ from pymodbus.client import ModbusTcpClient
|
||||
|
||||
client = ModbusTcpClient('localhost', port=5020)
|
||||
client.connect()
|
||||
# client.write_registers(address=11, values=[110])
|
||||
# client.write_registers(address=11, values=[114])
|
||||
# client.write_registers(address=6, values=[1])
|
||||
# client.write_registers(address=5, values=[16])
|
||||
# 贴标完成
|
||||
# client.write_registers(address=13, values=[1])
|
||||
client.write_registers(address=24, values=[1])
|
||||
# client.write_registers(address=24, values=[1])
|
||||
|
||||
|
||||
result = client.read_holding_registers(address=24, count=1)
|
||||
result = client.read_holding_registers(address=4, count=1)
|
||||
print(result.registers[0],"123===")
|
||||
client.close()
|
||||
248
ui/loading_dialog_ui.py
Normal file
248
ui/loading_dialog_ui.py
Normal file
@ -0,0 +1,248 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QDialog, QLabel, QLineEdit, QComboBox, QPushButton,
|
||||
QVBoxLayout, QHBoxLayout, QFrame
|
||||
)
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QFont
|
||||
|
||||
class LoadingDialogUI(QDialog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("上料操作")
|
||||
self.setFixedSize(600, 250)
|
||||
|
||||
# 设置字体
|
||||
self.normal_font = QFont("微软雅黑", 12)
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化UI"""
|
||||
# 主布局
|
||||
self.main_layout = QVBoxLayout(self)
|
||||
self.main_layout.setContentsMargins(20, 20, 20, 20)
|
||||
self.main_layout.setSpacing(0) # 移除布局间距
|
||||
|
||||
# 创建内容区域
|
||||
self.create_content_frame()
|
||||
|
||||
# 创建按钮
|
||||
self.create_buttons()
|
||||
|
||||
def create_content_frame(self):
|
||||
"""创建内容区域"""
|
||||
# 创建一个带边框的容器
|
||||
container = QFrame()
|
||||
container.setStyleSheet("""
|
||||
QFrame {
|
||||
border: 1px solid #e0e0e0;
|
||||
background-color: white;
|
||||
}
|
||||
""")
|
||||
|
||||
# 容器的垂直布局
|
||||
container_layout = QVBoxLayout(container)
|
||||
container_layout.setContentsMargins(0, 0, 0, 0)
|
||||
container_layout.setSpacing(0)
|
||||
|
||||
# 通用样式
|
||||
label_style = """
|
||||
QLabel {
|
||||
background-color: #f5f5f5;
|
||||
color: #333333;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: 0 8px;
|
||||
}
|
||||
"""
|
||||
|
||||
input_style = """
|
||||
QLineEdit {
|
||||
border: none;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
background-color: white;
|
||||
selection-background-color: #0078d4;
|
||||
padding: 0 8px;
|
||||
}
|
||||
QLineEdit:focus {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
"""
|
||||
|
||||
value_style = """
|
||||
QLabel {
|
||||
background-color: white;
|
||||
border: none;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: 0 8px;
|
||||
}
|
||||
"""
|
||||
|
||||
# 第一行:订单号和产品
|
||||
row1 = QHBoxLayout()
|
||||
row1.setSpacing(0)
|
||||
|
||||
# 第二行:托盘号
|
||||
row2 = QHBoxLayout()
|
||||
row2.setSpacing(0)
|
||||
|
||||
self.tray_label = QLabel("托盘号")
|
||||
self.tray_label.setFont(self.normal_font)
|
||||
self.tray_label.setStyleSheet(label_style)
|
||||
self.tray_label.setFixedWidth(100)
|
||||
self.tray_label.setFixedHeight(45)
|
||||
|
||||
self.tray_input = QLineEdit()
|
||||
self.tray_input.setFont(self.normal_font)
|
||||
self.tray_input.setPlaceholderText("请扫描托盘号")
|
||||
self.tray_input.setStyleSheet(input_style)
|
||||
self.tray_input.setFixedHeight(45)
|
||||
|
||||
row2.addWidget(self.tray_label)
|
||||
row2.addWidget(self.tray_input, 1)
|
||||
container_layout.addLayout(row2)
|
||||
|
||||
# 第三行:轴型和托盘料
|
||||
row3 = QHBoxLayout()
|
||||
row3.setSpacing(0)
|
||||
|
||||
axis_layout = QHBoxLayout()
|
||||
axis_layout.setSpacing(0)
|
||||
self.axis_label = QLabel("轴型")
|
||||
self.axis_label.setFont(self.normal_font)
|
||||
self.axis_label.setStyleSheet(label_style)
|
||||
self.axis_label.setFixedWidth(100)
|
||||
self.axis_label.setFixedHeight(40)
|
||||
|
||||
self.axis_value = QLabel("--")
|
||||
self.axis_value.setFont(self.normal_font)
|
||||
self.axis_value.setStyleSheet(value_style)
|
||||
self.axis_value.setFixedHeight(40)
|
||||
|
||||
axis_layout.addWidget(self.axis_label)
|
||||
axis_layout.addWidget(self.axis_value, 1)
|
||||
|
||||
tier_layout = QHBoxLayout()
|
||||
tier_layout.setSpacing(0)
|
||||
self.pallet_tier_label = QLabel("托盘料")
|
||||
self.pallet_tier_label.setFont(self.normal_font)
|
||||
self.pallet_tier_label.setStyleSheet(label_style)
|
||||
self.pallet_tier_label.setFixedWidth(100)
|
||||
self.pallet_tier_label.setFixedHeight(40)
|
||||
|
||||
self.pallet_tier_value = QLabel("--")
|
||||
self.pallet_tier_value.setFont(self.normal_font)
|
||||
self.pallet_tier_value.setStyleSheet(value_style)
|
||||
self.pallet_tier_value.setFixedHeight(40)
|
||||
|
||||
tier_layout.addWidget(self.pallet_tier_label)
|
||||
tier_layout.addWidget(self.pallet_tier_value, 1)
|
||||
|
||||
row3.addLayout(axis_layout, 1)
|
||||
row3.addLayout(tier_layout, 1)
|
||||
container_layout.addLayout(row3)
|
||||
|
||||
# 第四行:数量和重量
|
||||
row4 = QHBoxLayout()
|
||||
row4.setSpacing(0)
|
||||
|
||||
quantity_layout = QHBoxLayout()
|
||||
quantity_layout.setSpacing(0)
|
||||
self.quantity_label = QLabel("数量")
|
||||
self.quantity_label.setFont(self.normal_font)
|
||||
self.quantity_label.setStyleSheet(label_style)
|
||||
self.quantity_label.setFixedWidth(100)
|
||||
self.quantity_label.setFixedHeight(40)
|
||||
|
||||
self.quantity_value = QLabel("--")
|
||||
self.quantity_value.setFont(self.normal_font)
|
||||
self.quantity_value.setStyleSheet(value_style)
|
||||
self.quantity_value.setFixedHeight(40)
|
||||
|
||||
quantity_layout.addWidget(self.quantity_label)
|
||||
quantity_layout.addWidget(self.quantity_value, 1)
|
||||
|
||||
weight_layout = QHBoxLayout()
|
||||
weight_layout.setSpacing(0)
|
||||
self.weight_label = QLabel("重量")
|
||||
self.weight_label.setFont(self.normal_font)
|
||||
self.weight_label.setStyleSheet(label_style)
|
||||
self.weight_label.setFixedWidth(100)
|
||||
self.weight_label.setFixedHeight(40)
|
||||
|
||||
self.weight_value = QLabel("--")
|
||||
self.weight_value.setFont(self.normal_font)
|
||||
self.weight_value.setStyleSheet(value_style)
|
||||
self.weight_value.setFixedHeight(40)
|
||||
|
||||
weight_layout.addWidget(self.weight_label)
|
||||
weight_layout.addWidget(self.weight_value, 1)
|
||||
|
||||
row4.addLayout(quantity_layout, 1)
|
||||
row4.addLayout(weight_layout, 1)
|
||||
container_layout.addLayout(row4)
|
||||
|
||||
# 添加弹性空间
|
||||
container_layout.addStretch()
|
||||
|
||||
# 将容器添加到主布局
|
||||
self.main_layout.addWidget(container)
|
||||
|
||||
def create_buttons(self):
|
||||
"""创建按钮"""
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.setContentsMargins(0, 10, 0, 0)
|
||||
|
||||
self.confirm_button = QPushButton("确认")
|
||||
self.confirm_button.setFont(self.normal_font)
|
||||
self.confirm_button.setFixedSize(100, 35)
|
||||
self.confirm_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #0078d4;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 8px 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #106ebe;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #005a9e;
|
||||
}
|
||||
""")
|
||||
|
||||
self.cancel_button = QPushButton("取消")
|
||||
self.cancel_button.setFont(self.normal_font)
|
||||
self.cancel_button.setFixedSize(100, 35)
|
||||
self.cancel_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: white;
|
||||
color: #333333;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
padding: 8px 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #f5f5f5;
|
||||
border-color: #bdbdbd;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #e0e0e0;
|
||||
border-color: #bdbdbd;
|
||||
}
|
||||
""")
|
||||
|
||||
button_layout.addStretch()
|
||||
button_layout.addWidget(self.confirm_button)
|
||||
button_layout.addSpacing(30) # 添加30px的间距
|
||||
button_layout.addWidget(self.cancel_button)
|
||||
|
||||
self.main_layout.addLayout(button_layout)
|
||||
@ -108,6 +108,29 @@ class MainWindowUI(QMainWindow):
|
||||
self.task_label.setAlignment(Qt.AlignLeft)
|
||||
self.task_label.setStyleSheet("font-weight: bold; color: #333333;")
|
||||
self.task_layout.addWidget(self.task_label)
|
||||
|
||||
|
||||
# 订单行
|
||||
self.order_layout = QHBoxLayout()
|
||||
self.order_layout.setAlignment(Qt.AlignLeft) # 设置整个布局左对齐
|
||||
|
||||
self.order_label = QLabel("工程号")
|
||||
self.order_label.setFont(QFont("微软雅黑", 12, QFont.Bold))
|
||||
self.order_label.setFixedHeight(30)
|
||||
self.order_label.setStyleSheet("padding: 0 5px; color: #333333;")
|
||||
|
||||
self.order_edit = QLineEdit()
|
||||
self.order_edit.setFixedHeight(30)
|
||||
self.order_edit.setFixedWidth(150)
|
||||
self.order_edit.setReadOnly(False)
|
||||
self.order_edit.setFont(QFont("微软雅黑", 12))
|
||||
self.order_edit.setText("") # 设置默认订单号
|
||||
self.order_edit.setStyleSheet("background-color: #f9f9f9; border: 1px solid #cccccc; border-radius: 3px; padding: 2px 5px;")
|
||||
|
||||
self.order_layout.addWidget(self.order_label)
|
||||
self.order_layout.addWidget(self.order_edit)
|
||||
self.order_layout.addStretch() # 添加弹性空间,将组件推到左侧
|
||||
self.task_layout.addLayout(self.order_layout)
|
||||
|
||||
# 任务表格 - 使用合并单元格实现一级二级标题
|
||||
self.task_table = QTableWidget(3, 4) # 3行4列:一级标题行、二级标题行、数据行
|
||||
@ -148,24 +171,6 @@ class MainWindowUI(QMainWindow):
|
||||
self.task_table.setRowHeight(2, 30) # 数据行高
|
||||
self.task_layout.addWidget(self.task_table)
|
||||
|
||||
# 订单行
|
||||
self.order_layout = QHBoxLayout()
|
||||
self.order_label = QLabel("工程号")
|
||||
self.order_label.setFont(QFont("微软雅黑", 12, QFont.Bold))
|
||||
self.order_label.setFixedHeight(35)
|
||||
self.order_label.setStyleSheet("padding: 0 5px; color: #333333;")
|
||||
|
||||
self.order_edit = QLineEdit()
|
||||
self.order_edit.setFixedHeight(35)
|
||||
self.order_edit.setReadOnly(False)
|
||||
self.order_edit.setFont(QFont("微软雅黑", 12))
|
||||
self.order_edit.setText("ORD-2025-001") # 设置默认订单号
|
||||
self.order_edit.setStyleSheet("background-color: #f9f9f9; border: 1px solid #cccccc; border-radius: 3px; padding: 2px 5px;")
|
||||
|
||||
self.order_layout.addWidget(self.order_label)
|
||||
self.order_layout.addWidget(self.order_edit)
|
||||
self.task_layout.addLayout(self.order_layout)
|
||||
|
||||
self.left_layout.addWidget(self.task_frame)
|
||||
|
||||
# 上料区 - 使用QFrame包裹,添加边框
|
||||
@ -218,12 +223,9 @@ class MainWindowUI(QMainWindow):
|
||||
self.tray_edit.setMaxVisibleItems(10) # 设置下拉框最多显示10个项目
|
||||
self.tray_edit.completer().setCaseSensitivity(Qt.CaseInsensitive) # 设置补全不区分大小写
|
||||
self.tray_edit.completer().setFilterMode(Qt.MatchContains) # 设置模糊匹配模式
|
||||
self.tray_edit.addItem("托盘1")
|
||||
self.tray_edit.addItem("托盘2")
|
||||
self.tray_edit.addItem("托盘3")
|
||||
self.tray_edit.addItem("托盘4")
|
||||
self.tray_edit.addItem("托盘5")
|
||||
self.tray_edit.addItem("托盘6")
|
||||
# 允许清空选择
|
||||
self.tray_edit.setCurrentText("")
|
||||
|
||||
self.tray_layout.addWidget(self.tray_edit)
|
||||
|
||||
self.left_layout.addWidget(self.tray_frame)
|
||||
@ -501,28 +503,37 @@ class MainWindowUI(QMainWindow):
|
||||
self.record_layout.addWidget(self.record_title)
|
||||
|
||||
# 创建表格
|
||||
self.record_table = QTableWidget(14, 9) # 14行9列:序号、订单、品名、规格、托号、轴包装号、重量、净重、完成时间
|
||||
self.record_table = QTableWidget(13, 9) # 13行9列:序号、订单、品名、规格、托号、轴包装号、重量、净重、完成时间
|
||||
|
||||
# 应用通用表格设置
|
||||
self.setup_table_common(self.record_table)
|
||||
# 应用通用表格设置但保留表头
|
||||
self.setup_table_common(self.record_table, hide_headers=False)
|
||||
|
||||
# 设置列标题
|
||||
record_headers = ["序号", "订单", "品名", "规格", "托号", "轴包装号", "毛重", "净重", "完成时间"]
|
||||
for col, header in enumerate(record_headers):
|
||||
self.record_table.setItem(0, col, self.create_header_item(header))
|
||||
self.record_table.setHorizontalHeaderLabels(record_headers)
|
||||
|
||||
# 设置表头样式
|
||||
self.record_table.horizontalHeader().setStyleSheet("""
|
||||
QHeaderView::section {
|
||||
background-color: #f8f8f8;
|
||||
padding: 4px;
|
||||
border: 1px solid #dddddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
|
||||
# 设置行高
|
||||
self.record_table.setRowHeight(0, 35) # 列标题行高
|
||||
self.record_table.setRowHeight(13, 35) # 合计行高
|
||||
self.record_table.setRowHeight(12, 35) # 合计行高
|
||||
|
||||
# 设置数据行的行高
|
||||
for row in range(1, 13): # 记录行
|
||||
for row in range(0, 12): # 记录行
|
||||
self.record_table.setRowHeight(row, 35)
|
||||
|
||||
# 设置列宽
|
||||
column_widths = [70, 200, 130, 130, 160, 120, 120, 120, 160] # 各列的默认宽度
|
||||
column_widths = [70, 200, 130, 130, 160, 120, 120, 120, 160]
|
||||
for col, width in enumerate(column_widths):
|
||||
self.record_table.setColumnWidth(col, width)
|
||||
self.record_table.horizontalHeader().resizeSection(col, width)
|
||||
|
||||
# 添加表格到布局
|
||||
self.record_layout.addWidget(self.record_table)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QWidget, QLabel, QLineEdit, QPushButton, QComboBox, QGridLayout, QHBoxLayout, QVBoxLayout,
|
||||
QTabWidget, QFrame, QFormLayout, QGroupBox, QRadioButton, QSpacerItem, QSizePolicy,
|
||||
QTableWidget, QTableWidgetItem, QHeaderView, QSlider, QCheckBox
|
||||
QTableWidget, QTableWidgetItem, QHeaderView, QSlider, QCheckBox, QButtonGroup
|
||||
)
|
||||
from PySide6.QtGui import QFont, QBrush, QColor
|
||||
from PySide6.QtCore import Qt, Signal, QSize
|
||||
@ -233,6 +233,34 @@ class SettingsUI(QWidget):
|
||||
self.db_type_group.setLayout(self.db_type_layout)
|
||||
self.database_layout.addWidget(self.db_type_group)
|
||||
|
||||
# 添加运行模式选择组
|
||||
self.mode_group = QGroupBox("运行模式")
|
||||
self.mode_group.setFont(self.normal_font)
|
||||
self.mode_layout = QHBoxLayout()
|
||||
|
||||
# 创建单选按钮组
|
||||
self.mode_button_group = QButtonGroup(self)
|
||||
|
||||
# 创建单机模式单选按钮
|
||||
self.standalone_mode_radio = QRadioButton("单机模式")
|
||||
self.standalone_mode_radio.setFont(self.normal_font)
|
||||
self.standalone_mode_radio.setChecked(True) # 默认选中单机模式
|
||||
self.mode_button_group.addButton(self.standalone_mode_radio, 1)
|
||||
|
||||
# 创建接口模式单选按钮
|
||||
self.api_mode_radio = QRadioButton("接口模式")
|
||||
self.api_mode_radio.setFont(self.normal_font)
|
||||
self.mode_button_group.addButton(self.api_mode_radio, 2)
|
||||
|
||||
# 添加单选按钮到布局
|
||||
self.mode_layout.addWidget(QLabel("选择运行模式:"))
|
||||
self.mode_layout.addWidget(self.standalone_mode_radio)
|
||||
self.mode_layout.addWidget(self.api_mode_radio)
|
||||
self.mode_layout.addStretch(1)
|
||||
|
||||
self.mode_group.setLayout(self.mode_layout)
|
||||
self.database_layout.addWidget(self.mode_group)
|
||||
|
||||
# 数据库连接设置
|
||||
self.db_conn_group = QGroupBox("连接设置")
|
||||
self.db_conn_group.setFont(self.normal_font)
|
||||
|
||||
237
ui/unloading_dialog_ui.py
Normal file
237
ui/unloading_dialog_ui.py
Normal file
@ -0,0 +1,237 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QDialog, QLabel, QLineEdit, QComboBox, QPushButton,
|
||||
QVBoxLayout, QHBoxLayout, QFrame
|
||||
)
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QFont
|
||||
|
||||
class UnloadingDialogUI(QDialog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("下料操作")
|
||||
self.setFixedSize(600, 250) # 减小高度,因为移除了第一行
|
||||
|
||||
# 设置字体
|
||||
self.normal_font = QFont("微软雅黑", 12)
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化UI"""
|
||||
# 主布局
|
||||
self.main_layout = QVBoxLayout(self)
|
||||
self.main_layout.setContentsMargins(20, 20, 20, 20)
|
||||
self.main_layout.setSpacing(0) # 移除布局间距
|
||||
|
||||
# 创建内容区域
|
||||
self.create_content_frame()
|
||||
|
||||
# 创建按钮
|
||||
self.create_buttons()
|
||||
|
||||
def create_content_frame(self):
|
||||
"""创建内容区域"""
|
||||
# 创建一个带边框的容器
|
||||
container = QFrame()
|
||||
container.setStyleSheet("""
|
||||
QFrame {
|
||||
border: 1px solid #e0e0e0;
|
||||
background-color: white;
|
||||
}
|
||||
""")
|
||||
|
||||
# 容器的垂直布局
|
||||
container_layout = QVBoxLayout(container)
|
||||
container_layout.setContentsMargins(0, 0, 0, 0)
|
||||
container_layout.setSpacing(0)
|
||||
|
||||
# 通用样式
|
||||
label_style = """
|
||||
QLabel {
|
||||
background-color: #f5f5f5;
|
||||
color: #333333;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: 0 8px;
|
||||
}
|
||||
"""
|
||||
|
||||
input_style = """
|
||||
QLineEdit {
|
||||
border: none;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
background-color: white;
|
||||
selection-background-color: #0078d4;
|
||||
padding: 0 8px;
|
||||
}
|
||||
QLineEdit:focus {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
"""
|
||||
|
||||
value_style = """
|
||||
QLabel {
|
||||
background-color: white;
|
||||
border: none;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding: 0 8px;
|
||||
}
|
||||
"""
|
||||
|
||||
# 第一行:托盘号
|
||||
row1 = QHBoxLayout()
|
||||
row1.setSpacing(0)
|
||||
|
||||
self.tray_label = QLabel("托盘号")
|
||||
self.tray_label.setFont(self.normal_font)
|
||||
self.tray_label.setStyleSheet(label_style)
|
||||
self.tray_label.setFixedWidth(100)
|
||||
self.tray_label.setFixedHeight(45)
|
||||
|
||||
self.tray_input = QLineEdit()
|
||||
self.tray_input.setFont(self.normal_font)
|
||||
self.tray_input.setPlaceholderText("请扫描托盘号")
|
||||
self.tray_input.setStyleSheet(input_style)
|
||||
self.tray_input.setFixedHeight(45)
|
||||
|
||||
row1.addWidget(self.tray_label)
|
||||
row1.addWidget(self.tray_input, 1)
|
||||
container_layout.addLayout(row1)
|
||||
|
||||
# 第二行:轴型和托盘料
|
||||
row2 = QHBoxLayout()
|
||||
row2.setSpacing(0)
|
||||
|
||||
axis_layout = QHBoxLayout()
|
||||
axis_layout.setSpacing(0)
|
||||
self.axis_label = QLabel("轴型")
|
||||
self.axis_label.setFont(self.normal_font)
|
||||
self.axis_label.setStyleSheet(label_style)
|
||||
self.axis_label.setFixedWidth(100)
|
||||
self.axis_label.setFixedHeight(40)
|
||||
|
||||
self.axis_value = QLabel("--")
|
||||
self.axis_value.setFont(self.normal_font)
|
||||
self.axis_value.setStyleSheet(value_style)
|
||||
self.axis_value.setFixedHeight(40)
|
||||
|
||||
axis_layout.addWidget(self.axis_label)
|
||||
axis_layout.addWidget(self.axis_value, 1)
|
||||
|
||||
tier_layout = QHBoxLayout()
|
||||
tier_layout.setSpacing(0)
|
||||
self.pallet_tier_label = QLabel("托盘料")
|
||||
self.pallet_tier_label.setFont(self.normal_font)
|
||||
self.pallet_tier_label.setStyleSheet(label_style)
|
||||
self.pallet_tier_label.setFixedWidth(100)
|
||||
self.pallet_tier_label.setFixedHeight(40)
|
||||
|
||||
self.pallet_tier_value = QLabel("--")
|
||||
self.pallet_tier_value.setFont(self.normal_font)
|
||||
self.pallet_tier_value.setStyleSheet(value_style)
|
||||
self.pallet_tier_value.setFixedHeight(40)
|
||||
|
||||
tier_layout.addWidget(self.pallet_tier_label)
|
||||
tier_layout.addWidget(self.pallet_tier_value, 1)
|
||||
|
||||
row2.addLayout(axis_layout, 1)
|
||||
row2.addLayout(tier_layout, 1)
|
||||
container_layout.addLayout(row2)
|
||||
|
||||
# 第三行:数量和重量
|
||||
row3 = QHBoxLayout()
|
||||
row3.setSpacing(0)
|
||||
|
||||
quantity_layout = QHBoxLayout()
|
||||
quantity_layout.setSpacing(0)
|
||||
self.quantity_label = QLabel("数量")
|
||||
self.quantity_label.setFont(self.normal_font)
|
||||
self.quantity_label.setStyleSheet(label_style)
|
||||
self.quantity_label.setFixedWidth(100)
|
||||
self.quantity_label.setFixedHeight(40)
|
||||
|
||||
self.quantity_value = QLabel("--")
|
||||
self.quantity_value.setFont(self.normal_font)
|
||||
self.quantity_value.setStyleSheet(value_style)
|
||||
self.quantity_value.setFixedHeight(40)
|
||||
|
||||
quantity_layout.addWidget(self.quantity_label)
|
||||
quantity_layout.addWidget(self.quantity_value, 1)
|
||||
|
||||
weight_layout = QHBoxLayout()
|
||||
weight_layout.setSpacing(0)
|
||||
self.weight_label = QLabel("重量")
|
||||
self.weight_label.setFont(self.normal_font)
|
||||
self.weight_label.setStyleSheet(label_style)
|
||||
self.weight_label.setFixedWidth(100)
|
||||
self.weight_label.setFixedHeight(40)
|
||||
|
||||
self.weight_value = QLabel("--")
|
||||
self.weight_value.setFont(self.normal_font)
|
||||
self.weight_value.setStyleSheet(value_style)
|
||||
self.weight_value.setFixedHeight(40)
|
||||
|
||||
weight_layout.addWidget(self.weight_label)
|
||||
weight_layout.addWidget(self.weight_value, 1)
|
||||
|
||||
row3.addLayout(quantity_layout, 1)
|
||||
row3.addLayout(weight_layout, 1)
|
||||
container_layout.addLayout(row3)
|
||||
|
||||
# 添加弹性空间
|
||||
container_layout.addStretch()
|
||||
|
||||
# 将容器添加到主布局
|
||||
self.main_layout.addWidget(container)
|
||||
|
||||
def create_buttons(self):
|
||||
"""创建按钮"""
|
||||
# 按钮布局
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.setContentsMargins(0, 20, 0, 0)
|
||||
button_layout.setSpacing(10)
|
||||
|
||||
# 确认按钮
|
||||
self.confirm_button = QPushButton("确认")
|
||||
self.confirm_button.setFont(self.normal_font)
|
||||
self.confirm_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #fff8e1;
|
||||
border: 1px solid #ffc107;
|
||||
padding: 8px 16px;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #fff3e0;
|
||||
}
|
||||
""")
|
||||
|
||||
# 取消按钮
|
||||
self.cancel_button = QPushButton("取消")
|
||||
self.cancel_button.setFont(self.normal_font)
|
||||
self.cancel_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #e0e0e0;
|
||||
padding: 8px 16px;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
""")
|
||||
|
||||
# 添加按钮到布局
|
||||
button_layout.addStretch()
|
||||
button_layout.addWidget(self.confirm_button)
|
||||
button_layout.addWidget(self.cancel_button)
|
||||
|
||||
# 将按钮布局添加到主布局
|
||||
self.main_layout.addLayout(button_layout)
|
||||
134
utils/api_utils.py
Normal file
134
utils/api_utils.py
Normal file
@ -0,0 +1,134 @@
|
||||
import requests
|
||||
import json
|
||||
from .config_loader import ConfigLoader
|
||||
|
||||
class ApiUtils:
|
||||
def __init__(self):
|
||||
"""初始化 API 工具类"""
|
||||
self.config_loader = ConfigLoader.get_instance()
|
||||
self.base_url = self.config_loader.get_value("app.base_url", "")
|
||||
self.apis = self.config_loader.get_value("apis", {})
|
||||
|
||||
def get_full_url(self, url):
|
||||
"""
|
||||
根据 API 键获取完整 URL
|
||||
|
||||
Args:
|
||||
url: API 配置中的键名
|
||||
|
||||
Returns:
|
||||
str: 完整的 URL
|
||||
"""
|
||||
if url not in self.apis:
|
||||
return None
|
||||
|
||||
return f"{self.base_url}{self.apis[url]}"
|
||||
|
||||
def request(self, method, url, params=None, data=None, json_data=None, headers=None):
|
||||
"""
|
||||
发送 HTTP 请求
|
||||
|
||||
Args:
|
||||
method: 请求方法,如 'GET', 'POST' 等
|
||||
url: API 配置中的键名
|
||||
params: URL 参数
|
||||
data: 表单数据
|
||||
json_data: JSON 数据
|
||||
headers: 请求头
|
||||
|
||||
Returns:
|
||||
dict: 响应数据
|
||||
"""
|
||||
full_url = self.get_full_url(url)
|
||||
if not full_url:
|
||||
return {"success": False, "message": f"未找到 API 配置: {url}"}
|
||||
|
||||
# 处理托盘号参数
|
||||
# 如果是托盘查询接口,并且有tp_note参数,将其附加到URL末尾
|
||||
if url == "get_tray_info" and params and "tp_note" in params:
|
||||
full_url = f"{full_url}{params['tp_note']}"
|
||||
# 从params中移除tp_note,因为已经添加到URL中
|
||||
params = {k: v for k, v in params.items() if k != "tp_note"}
|
||||
|
||||
default_headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
if headers:
|
||||
default_headers.update(headers)
|
||||
|
||||
try:
|
||||
response = requests.request(
|
||||
method=method,
|
||||
url=full_url,
|
||||
params=params,
|
||||
data=data,
|
||||
json=json_data,
|
||||
headers=default_headers
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
return {"success": False, "message": f"请求异常: {str(e)}"}
|
||||
except json.JSONDecodeError:
|
||||
return {"success": False, "message": "响应数据不是有效的 JSON 格式"}
|
||||
|
||||
def get(self, url, params=None, headers=None):
|
||||
"""
|
||||
发送 GET 请求
|
||||
|
||||
Args:
|
||||
url: API 配置中的键名
|
||||
params: URL 参数
|
||||
headers: 请求头
|
||||
|
||||
Returns:
|
||||
dict: 响应数据
|
||||
"""
|
||||
return self.request("GET", url, params=params, headers=headers)
|
||||
|
||||
def post(self, url, json_data=None, data=None, headers=None):
|
||||
"""
|
||||
发送 POST 请求
|
||||
|
||||
Args:
|
||||
url: API 配置中的键名
|
||||
json_data: JSON 数据
|
||||
data: 表单数据
|
||||
headers: 请求头
|
||||
|
||||
Returns:
|
||||
dict: 响应数据
|
||||
"""
|
||||
return self.request("POST", url, data=data, json_data=json_data, headers=headers)
|
||||
|
||||
def put(self, url, json_data=None, data=None, headers=None):
|
||||
"""
|
||||
发送 PUT 请求
|
||||
|
||||
Args:
|
||||
url: API 配置中的键名
|
||||
json_data: JSON 数据
|
||||
data: 表单数据
|
||||
headers: 请求头
|
||||
|
||||
Returns:
|
||||
dict: 响应数据
|
||||
"""
|
||||
return self.request("PUT", url, data=data, json_data=json_data, headers=headers)
|
||||
|
||||
def delete(self, url, params=None, headers=None):
|
||||
"""
|
||||
发送 DELETE 请求
|
||||
|
||||
Args:
|
||||
url: API 配置中的键名
|
||||
params: URL 参数
|
||||
headers: 请求头
|
||||
|
||||
Returns:
|
||||
dict: 响应数据
|
||||
"""
|
||||
return self.request("DELETE", url, params=params, headers=headers)
|
||||
|
||||
56
utils/app_mode.py
Normal file
56
utils/app_mode.py
Normal file
@ -0,0 +1,56 @@
|
||||
import logging
|
||||
from utils.config_loader import ConfigLoader
|
||||
|
||||
class AppMode:
|
||||
"""
|
||||
应用运行模式工具类,用于判断当前系统是单机模式还是接口模式
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_mode():
|
||||
"""
|
||||
获取当前应用运行模式
|
||||
|
||||
Returns:
|
||||
str: 'standalone'(单机模式) 或 'api'(接口模式)
|
||||
"""
|
||||
config_loader = ConfigLoader.get_instance()
|
||||
return config_loader.get_app_mode()
|
||||
|
||||
@staticmethod
|
||||
def set_mode(mode):
|
||||
"""
|
||||
设置应用运行模式
|
||||
|
||||
Args:
|
||||
mode: 'standalone'(单机模式) 或 'api'(接口模式)
|
||||
|
||||
Returns:
|
||||
bool: 是否设置成功
|
||||
"""
|
||||
config_loader = ConfigLoader.get_instance()
|
||||
result = config_loader.set_app_mode(mode)
|
||||
logging.info(f"应用运行模式已设置为: {mode}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def is_standalone():
|
||||
"""
|
||||
检查是否为单机模式
|
||||
|
||||
Returns:
|
||||
bool: True表示单机模式,False表示接口模式
|
||||
"""
|
||||
config_loader = ConfigLoader.get_instance()
|
||||
return config_loader.is_standalone_mode()
|
||||
|
||||
@staticmethod
|
||||
def is_api():
|
||||
"""
|
||||
检查是否为接口模式
|
||||
|
||||
Returns:
|
||||
bool: True表示接口模式,False表示单机模式
|
||||
"""
|
||||
config_loader = ConfigLoader.get_instance()
|
||||
return config_loader.is_api_mode()
|
||||
@ -45,7 +45,8 @@ class ConfigLoader:
|
||||
"enable_serial_ports": False,
|
||||
"enable_keyboard_listener": False,
|
||||
"enable_camera": False
|
||||
}
|
||||
},
|
||||
"mode": "standalone" # 默认为单机模式
|
||||
},
|
||||
"database": {
|
||||
"current": "sqlite",
|
||||
@ -104,7 +105,8 @@ class ConfigLoader:
|
||||
"enable_serial_ports": False,
|
||||
"enable_keyboard_listener": False,
|
||||
"enable_camera": False
|
||||
}
|
||||
},
|
||||
"mode": "standalone" # 默认为单机模式
|
||||
},
|
||||
"database": {
|
||||
"current": "sqlite",
|
||||
@ -179,6 +181,12 @@ class ConfigLoader:
|
||||
if db_config.get('default') == 'pgsql':
|
||||
db_config['default'] = 'postgresql'
|
||||
self.save_config()
|
||||
|
||||
# 检查并添加运行模式配置
|
||||
if 'app' in self.config and 'mode' not in self.config['app']:
|
||||
logging.info("添加运行模式配置...")
|
||||
self.config['app']['mode'] = 'standalone'
|
||||
self.save_config()
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"升级配置文件结构失败: {e}")
|
||||
@ -240,6 +248,49 @@ class ConfigLoader:
|
||||
|
||||
# 保存配置
|
||||
return self.save_config()
|
||||
|
||||
def get_app_mode(self):
|
||||
"""
|
||||
获取应用运行模式
|
||||
|
||||
Returns:
|
||||
str: 'standalone'(单机模式) 或 'api'(接口模式)
|
||||
"""
|
||||
return self.get_value('app.mode', 'standalone')
|
||||
|
||||
def set_app_mode(self, mode):
|
||||
"""
|
||||
设置应用运行模式
|
||||
|
||||
Args:
|
||||
mode: 'standalone'(单机模式) 或 'api'(接口模式)
|
||||
|
||||
Returns:
|
||||
bool: 是否设置成功
|
||||
"""
|
||||
if mode not in ['standalone', 'api']:
|
||||
logging.error(f"无效的运行模式: {mode},必须是 'standalone' 或 'api'")
|
||||
return False
|
||||
|
||||
return self.set_value('app.mode', mode)
|
||||
|
||||
def is_standalone_mode(self):
|
||||
"""
|
||||
检查是否为单机模式
|
||||
|
||||
Returns:
|
||||
bool: True表示单机模式,False表示接口模式
|
||||
"""
|
||||
return self.get_app_mode() == 'standalone'
|
||||
|
||||
def is_api_mode(self):
|
||||
"""
|
||||
检查是否为接口模式
|
||||
|
||||
Returns:
|
||||
bool: True表示接口模式,False表示单机模式
|
||||
"""
|
||||
return self.get_app_mode() == 'api'
|
||||
|
||||
def get_config(self, key):
|
||||
"""
|
||||
@ -249,51 +300,44 @@ class ConfigLoader:
|
||||
key: 配置键,例如'mdz', 'cz'等
|
||||
|
||||
Returns:
|
||||
dict: 配置值,未找到则返回None
|
||||
dict: 配置数据
|
||||
"""
|
||||
if 'serial' not in self.config:
|
||||
self.config['serial'] = {}
|
||||
|
||||
if key not in self.config['serial']:
|
||||
return None
|
||||
|
||||
return self.config['serial'][key]
|
||||
|
||||
serial_config = self.config.get('serial', {})
|
||||
return serial_config.get(key, {})
|
||||
|
||||
def set_config(self, key, config_data):
|
||||
"""
|
||||
设置serial配置下的指定配置
|
||||
|
||||
Args:
|
||||
key: 配置键,例如'mdz', 'cz'等
|
||||
config_data: 要设置的配置数据
|
||||
config_data: 配置数据
|
||||
|
||||
Returns:
|
||||
bool: 是否设置成功
|
||||
"""
|
||||
if 'serial' not in self.config:
|
||||
self.config['serial'] = {}
|
||||
|
||||
self.config['serial'][key] = config_data
|
||||
# 这里不保存配置,等待调用save_config方法时一并保存
|
||||
return True
|
||||
|
||||
self.config['serial'][key] = config_data
|
||||
return self.save_config()
|
||||
|
||||
def get_database_config(self, db_type=None):
|
||||
"""
|
||||
获取指定类型的数据库配置
|
||||
获取数据库配置
|
||||
|
||||
Args:
|
||||
db_type: 数据库类型,如'sqlite', 'postgresql', 'mysql'等,不指定则使用默认配置
|
||||
db_type: 数据库类型,如果为None则返回当前使用的数据库配置
|
||||
|
||||
Returns:
|
||||
dict: 数据库配置
|
||||
"""
|
||||
# 如果未指定数据库类型,使用当前设置的类型
|
||||
db_config = self.config.get('database', {})
|
||||
db_sources = db_config.get('sources', {})
|
||||
|
||||
# 如果未指定数据库类型,则使用当前配置的数据库类型
|
||||
if db_type is None:
|
||||
db_type = self.get_value('database.default', 'sqlite')
|
||||
db_type = db_config.get('current', 'sqlite')
|
||||
|
||||
# 处理pgsql和postgresql兼容
|
||||
if db_type == 'pgsql':
|
||||
db_type = 'postgresql'
|
||||
|
||||
# 获取数据库配置
|
||||
return self.get_value(f'database.sources.{db_type}', {})
|
||||
# 返回指定类型的数据库配置
|
||||
return db_sources.get(db_type, {})
|
||||
@ -17,31 +17,8 @@ class PalletTypeManager:
|
||||
"""初始化托盘类型管理器"""
|
||||
self.dao = PalletTypeDAO()
|
||||
self.pallet_types = []
|
||||
self.reload_pallet_types()
|
||||
|
||||
def reload_pallet_types(self):
|
||||
"""重新加载托盘类型"""
|
||||
try:
|
||||
self.pallet_types = self.dao.get_all_pallet_types(include_disabled=True)
|
||||
logging.info(f"已加载{len(self.pallet_types)}个托盘类型")
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"加载托盘类型失败: {str(e)}")
|
||||
return False
|
||||
|
||||
def get_all_pallet_types(self, include_disabled=False):
|
||||
"""获取所有托盘类型
|
||||
|
||||
Args:
|
||||
include_disabled: 是否包含禁用的类型
|
||||
|
||||
Returns:
|
||||
list: 托盘类型列表
|
||||
"""
|
||||
if include_disabled:
|
||||
return self.pallet_types
|
||||
else:
|
||||
return [pallet_type for pallet_type in self.pallet_types if pallet_type['enabled']]
|
||||
|
||||
|
||||
def get_pallet_types_by_operation(self, operation_type, include_disabled=False):
|
||||
"""根据操作类型获取托盘类型
|
||||
@ -199,13 +176,32 @@ class PalletTypeManager:
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_pallet_type_by_pallet_id(self, pallet_id):
|
||||
def get_pallet_type_by_pallet_id(self, pallet_code):
|
||||
"""根据托盘号获取托盘类型
|
||||
|
||||
Args:
|
||||
pallet_id: 托盘号
|
||||
pallet_code: 托盘号
|
||||
"""
|
||||
result = self.dao.get_pallet_type_by_pallet_id(pallet_id)
|
||||
result = self.dao.get_pallet_type_by_pallet_id(pallet_code)
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
# 获取托盘号
|
||||
def get_pallet_code(self):
|
||||
"""获取托盘号"""
|
||||
result = self.dao.get_pallet_code()
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
def get_pallet_info_by_pallet_id(self, pallet_code):
|
||||
"""根据托盘号获取托盘信息
|
||||
|
||||
Args:
|
||||
pallet_code: 托盘号
|
||||
"""
|
||||
result = self.dao.get_pallet_info_by_pallet_id(pallet_code)
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
|
||||
195
widgets/loading_dialog_widget.py
Normal file
195
widgets/loading_dialog_widget.py
Normal file
@ -0,0 +1,195 @@
|
||||
from ui.loading_dialog_ui import LoadingDialogUI
|
||||
from apis.tary_api import TaryApi
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
from PySide6.QtWidgets import QMessageBox, QDialog
|
||||
import logging
|
||||
from utils.app_mode import AppMode
|
||||
from utils.pallet_type_manager import PalletTypeManager
|
||||
class LoadingDialog(LoadingDialogUI):
|
||||
# 定义一个信号,用于向主窗口传递托盘号
|
||||
tray_code_signal = Signal(str, str, str, str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""初始化加载对话框"""
|
||||
super().__init__()
|
||||
self.parent = parent
|
||||
|
||||
# 彻底禁用对话框的回车键关闭功能
|
||||
self.setModal(True)
|
||||
# 禁用所有按钮的默认行为
|
||||
self.confirm_button.setAutoDefault(False)
|
||||
self.confirm_button.setDefault(False)
|
||||
self.cancel_button.setAutoDefault(False)
|
||||
self.cancel_button.setDefault(False)
|
||||
|
||||
# 设置对话框特性,按下Escape键才能关闭
|
||||
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
|
||||
|
||||
# 绑定事件
|
||||
self.setup_connections()
|
||||
|
||||
def setup_connections(self):
|
||||
"""设置事件连接"""
|
||||
# 托盘号输入框回车事件触发查询
|
||||
self.tray_input.returnPressed.connect(self.handle_tray_return_pressed)
|
||||
# 移除editingFinished事件,避免重复触发查询
|
||||
# self.tray_input.editingFinished.connect(self.on_tray_query)
|
||||
|
||||
# 确认按钮点击事件
|
||||
self.confirm_button.clicked.connect(self.accept)
|
||||
|
||||
# 取消按钮点击事件
|
||||
self.cancel_button.clicked.connect(self.reject)
|
||||
|
||||
def handle_tray_return_pressed(self):
|
||||
"""处理托盘输入框的回车事件"""
|
||||
# 阻止事件传播
|
||||
logging.info("托盘输入框回车事件触发")
|
||||
self.on_tray_query()
|
||||
|
||||
# 阻止事件继续传播
|
||||
return True
|
||||
|
||||
def on_tray_query(self):
|
||||
"""查询托盘信息"""
|
||||
try:
|
||||
tray_code = self.tray_input.text().strip()
|
||||
if not tray_code:
|
||||
return
|
||||
|
||||
logging.info(f"查询托盘号: {tray_code}")
|
||||
if AppMode.is_api():
|
||||
self.tary_api = TaryApi()
|
||||
# 调用API获取托盘信息
|
||||
response = self.tary_api.get_tary_info(tray_code)
|
||||
else:
|
||||
pallet_type_manager = PalletTypeManager.get_instance()
|
||||
pallet_info = pallet_type_manager.get_pallet_info_by_pallet_id(tray_code)
|
||||
|
||||
# 检查返回的数据类型并进行适当处理
|
||||
if pallet_info is None:
|
||||
response = {
|
||||
"success": False,
|
||||
"message": "未找到托盘信息"
|
||||
}
|
||||
else:
|
||||
# 如果返回的是元组(数据库查询结果),将其转换为字典
|
||||
# 根据dao/pallet_type_dao.py中get_pallet_info_by_pallet_id方法的SQL查询
|
||||
# 返回的字段顺序为:pallet_code, pallet_name, description, axios_name, axios_type, tier, size, amount, weight
|
||||
response = {
|
||||
"success": True,
|
||||
"data": {
|
||||
"tp_note": pallet_info[0] if len(pallet_info) > 0 else "",
|
||||
"product_name": pallet_info[1] if len(pallet_info) > 1 else "",
|
||||
"axis_type": pallet_info[4] if len(pallet_info) > 4 else "",
|
||||
"tier": str(pallet_info[5]) if len(pallet_info) > 5 else "",
|
||||
"weight": str(pallet_info[8]) if len(pallet_info) > 8 else "",
|
||||
"quantity": ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logging.info(f"托盘信息响应: {response}")
|
||||
logging.info(f"response.success={response.get('success')}, response.data存在={response.get('data') is not None}")
|
||||
|
||||
if response.get("success", False) and response.get("data"):
|
||||
tray_data = response.get("data", {})
|
||||
logging.info(f"托盘数据: {tray_data}")
|
||||
|
||||
# 显示托盘相关信息 - 只更新轴型、托盘料和重量,不更新订单号和产品
|
||||
axis_type = str(tray_data.get("axis_type", "--"))
|
||||
tier = str(tray_data.get("tier", "--"))
|
||||
weight = str(tray_data.get("weight", "--"))
|
||||
|
||||
logging.info(f"显示托盘信息: 轴型={axis_type}, 托盘料={tier}, 重量={weight}")
|
||||
|
||||
# 只设置轴型、托盘料和重量字段,不设置产品名称
|
||||
self.axis_value.setText(axis_type)
|
||||
self.pallet_tier_value.setText(tier)
|
||||
self.quantity_value.setText("") # 数量为空
|
||||
self.weight_value.setText(f"{weight} kg")
|
||||
|
||||
# 发送托盘号到主窗口
|
||||
from widgets.main_window import MainWindow
|
||||
main_window = self.parent
|
||||
if main_window and isinstance(main_window, MainWindow):
|
||||
# 检查托盘号是否已存在
|
||||
existed = False
|
||||
for i in range(main_window.tray_edit.count()):
|
||||
if main_window.tray_edit.itemText(i) == tray_code:
|
||||
existed = True
|
||||
break
|
||||
|
||||
# 如果不存在,则添加
|
||||
if not existed:
|
||||
logging.info(f"添加托盘号到主窗口: {tray_code}")
|
||||
main_window.tray_edit.addItem(tray_code)
|
||||
|
||||
# 设置当前选中的托盘号
|
||||
main_window.tray_edit.setCurrentText(tray_code)
|
||||
logging.info(f"设置主窗口当前托盘号: {tray_code}")
|
||||
|
||||
else:
|
||||
# 获取托盘信息失败
|
||||
error_msg = response.get("message", "获取托盘信息失败")
|
||||
logging.warning(f"查询失败: {error_msg}")
|
||||
QMessageBox.warning(self, "查询失败", error_msg)
|
||||
except Exception as e:
|
||||
logging.error(f"查询托盘信息异常: {str(e)}")
|
||||
QMessageBox.critical(self, "查询异常", f"查询托盘信息时发生异常: {str(e)}")
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""重写键盘事件处理,防止回车关闭对话框"""
|
||||
# 如果按下回车键
|
||||
if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
|
||||
logging.info(f"捕获到回车键事件,当前焦点部件: {self.focusWidget()}")
|
||||
|
||||
# 如果焦点在托盘输入框上,触发查询
|
||||
# 注释掉此处的on_tray_query调用,因为已经通过returnPressed信号处理了
|
||||
if self.focusWidget() == self.tray_input:
|
||||
# self.on_tray_query() - 通过returnPressed信号已经处理,这里不需要再调用
|
||||
event.accept() # 消费掉这个事件
|
||||
return
|
||||
|
||||
# 如果焦点在确认按钮上,则允许默认行为(确认)
|
||||
if self.focusWidget() == self.confirm_button:
|
||||
return super().keyPressEvent(event)
|
||||
|
||||
# 其他情况下,阻止回车事件传播
|
||||
event.accept() # 消费掉这个事件
|
||||
return
|
||||
|
||||
# 其他键位事件交给父类处理
|
||||
super().keyPressEvent(event)
|
||||
|
||||
def accept(self):
|
||||
"""重写接受方法,确保在确认前所有数据都已处理"""
|
||||
logging.info("确认按钮被点击或回车触发确认")
|
||||
|
||||
# 确保主窗口启动了监听
|
||||
from widgets.main_window import MainWindow
|
||||
main_window = self.parent
|
||||
if main_window and isinstance(main_window, MainWindow):
|
||||
# 确保主窗口已启动监听
|
||||
try:
|
||||
if not hasattr(main_window, 'modbus_monitor') or not main_window.modbus_monitor.is_running():
|
||||
main_window.setup_modbus_monitor()
|
||||
logging.info("已在LoadingDialog确认时启动Modbus监控")
|
||||
|
||||
# 启动串口监听
|
||||
main_window.serial_manager.auto_open_configured_ports()
|
||||
|
||||
# 启动键盘监听器
|
||||
main_window.serial_manager.start_keyboard_listener()
|
||||
logging.info("已在LoadingDialog确认时启动键盘监听器")
|
||||
except Exception as e:
|
||||
logging.error(f"LoadingDialog确认时启动监听失败: {str(e)}")
|
||||
|
||||
# 调用父类的accept方法关闭对话框
|
||||
super().accept()
|
||||
|
||||
def reject(self):
|
||||
"""重写拒绝方法"""
|
||||
logging.info("取消按钮被点击或ESC触发取消")
|
||||
# 调用父类的reject方法关闭对话框
|
||||
super().reject()
|
||||
@ -23,7 +23,7 @@ from utils.register_handlers import (
|
||||
from PySide6.QtWidgets import (
|
||||
QWidget, QMessageBox, QTableWidgetItem, QStackedWidget, QLabel, QMainWindow,
|
||||
QTableWidget, QMenu, QComboBox, QFormLayout, QDialog, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QStatusBar, QSplitter, QFrame
|
||||
QStatusBar, QSplitter, QFrame, QHeaderView
|
||||
)
|
||||
from PySide6.QtCore import Qt, QTimer, Slot
|
||||
from PySide6.QtGui import QBrush, QColor
|
||||
@ -53,6 +53,7 @@ class MainWindow(MainWindowUI):
|
||||
self.corp_id = corp_id
|
||||
self.position_id = position_id
|
||||
self.init_seq = {} # 初始化轴包装的序号
|
||||
self._loading_data_in_progress = False # 数据加载状态标志,防止循环调用
|
||||
|
||||
# 设置窗口标题
|
||||
if user_name and corp_name:
|
||||
@ -123,8 +124,8 @@ class MainWindow(MainWindowUI):
|
||||
# 设置中央部件为堆叠部件
|
||||
self.setCentralWidget(self.stacked_widget)
|
||||
|
||||
# 添加托盘类型选择下拉框
|
||||
self.add_pallet_type_selectors()
|
||||
# # 添加托盘类型选择下拉框
|
||||
# self.add_pallet_type_selectors()
|
||||
|
||||
# 连接信号和槽
|
||||
self.connect_signals()
|
||||
@ -139,7 +140,7 @@ class MainWindow(MainWindowUI):
|
||||
self.process_table.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
|
||||
# 加载未完成的检验数据
|
||||
self.load_finished_inspection_data()
|
||||
self._safe_load_data()
|
||||
|
||||
# 加载已完成检验数据
|
||||
self.show_pack_item()
|
||||
@ -168,50 +169,53 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 注册串口数据回调函数
|
||||
self.register_serial_callbacks()
|
||||
|
||||
# 加载托盘号列表
|
||||
self.load_pallet_codes()
|
||||
|
||||
def add_pallet_type_selectors(self):
|
||||
"""添加托盘类型选择下拉框"""
|
||||
# 创建上料托盘类型选择下拉框
|
||||
self.input_pallet_type_label = QLabel("上料托盘类型:")
|
||||
self.input_pallet_type_label.setFont(self.normal_font)
|
||||
self.input_pallet_type_label.setVisible(False)
|
||||
self.material_form_layout.addRow(self.input_pallet_type_label)
|
||||
# def add_pallet_type_selectors(self):
|
||||
# """添加托盘类型选择下拉框"""
|
||||
# # 创建上料托盘类型选择下拉框
|
||||
# self.input_pallet_type_label = QLabel("上料托盘类型:")
|
||||
# self.input_pallet_type_label.setFont(self.normal_font)
|
||||
# self.input_pallet_type_label.setVisible(False)
|
||||
# self.material_form_layout.addRow(self.input_pallet_type_label)
|
||||
|
||||
self.input_pallet_type_combo = QComboBox()
|
||||
self.input_pallet_type_combo.setFont(self.normal_font)
|
||||
self.input_pallet_type_combo.setVisible(False)
|
||||
self.material_form_layout.addRow("", self.input_pallet_type_combo)
|
||||
# self.input_pallet_type_combo = QComboBox()
|
||||
# self.input_pallet_type_combo.setFont(self.normal_font)
|
||||
# self.input_pallet_type_combo.setVisible(False)
|
||||
# self.material_form_layout.addRow("", self.input_pallet_type_combo)
|
||||
|
||||
# 创建下料托盘类型选择下拉框
|
||||
self.output_pallet_type_label = QLabel("下料托盘类型:")
|
||||
self.output_pallet_type_label.setFont(self.normal_font)
|
||||
self.output_pallet_type_label.setVisible(False)
|
||||
self.output_form_layout.addRow(self.output_pallet_type_label)
|
||||
# # 创建下料托盘类型选择下拉框
|
||||
# self.output_pallet_type_label = QLabel("下料托盘类型:")
|
||||
# self.output_pallet_type_label.setFont(self.normal_font)
|
||||
# self.output_pallet_type_label.setVisible(False)
|
||||
# self.output_form_layout.addRow(self.output_pallet_type_label)
|
||||
|
||||
self.output_pallet_type_combo = QComboBox()
|
||||
self.output_pallet_type_combo.setFont(self.normal_font)
|
||||
self.output_pallet_type_combo.setVisible(False)
|
||||
self.output_form_layout.addRow("", self.output_pallet_type_combo)
|
||||
# self.output_pallet_type_combo = QComboBox()
|
||||
# self.output_pallet_type_combo.setFont(self.normal_font)
|
||||
# self.output_pallet_type_combo.setVisible(False)
|
||||
# self.output_form_layout.addRow("", self.output_pallet_type_combo)
|
||||
|
||||
# 加载托盘类型数据
|
||||
self.update_pallet_types()
|
||||
# # 加载托盘类型数据
|
||||
# self.update_pallet_types()
|
||||
|
||||
def update_pallet_types(self):
|
||||
"""更新托盘类型下拉框"""
|
||||
# 重新加载托盘类型数据
|
||||
self.pallet_type_manager.reload_pallet_types()
|
||||
# def update_pallet_types(self):
|
||||
# """更新托盘类型下拉框"""
|
||||
# # 重新加载托盘类型数据
|
||||
# self.pallet_type_manager.reload_pallet_types()
|
||||
|
||||
# 更新上料托盘类型
|
||||
input_types = self.pallet_type_manager.get_pallet_types_by_operation("input")
|
||||
self.input_pallet_type_combo.clear()
|
||||
for pallet_type in input_types:
|
||||
self.input_pallet_type_combo.addItem(pallet_type['type_name'], pallet_type['id'])
|
||||
# # 更新上料托盘类型
|
||||
# input_types = self.pallet_type_manager.get_pallet_types_by_operation("input")
|
||||
# self.input_pallet_type_combo.clear()
|
||||
# for pallet_type in input_types:
|
||||
# self.input_pallet_type_combo.addItem(pallet_type['type_name'], pallet_type['id'])
|
||||
|
||||
# 更新下料托盘类型
|
||||
output_types = self.pallet_type_manager.get_pallet_types_by_operation("output")
|
||||
self.output_pallet_type_combo.clear()
|
||||
for pallet_type in output_types:
|
||||
self.output_pallet_type_combo.addItem(pallet_type['type_name'], pallet_type['id'])
|
||||
# # 更新下料托盘类型
|
||||
# output_types = self.pallet_type_manager.get_pallet_types_by_operation("output")
|
||||
# self.output_pallet_type_combo.clear()
|
||||
# for pallet_type in output_types:
|
||||
# self.output_pallet_type_combo.addItem(pallet_type['type_name'], pallet_type['id'])
|
||||
|
||||
def load_config(self):
|
||||
"""加载配置文件"""
|
||||
@ -239,8 +243,8 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 托盘号输入框回车和切换事件,触发未加载数据查询
|
||||
# QComboBox没有returnPressed信号,只有currentTextChanged和activated信号
|
||||
self.tray_edit.currentTextChanged.connect(self.load_finished_inspection_data)
|
||||
self.tray_edit.activated.connect(self.load_finished_inspection_data) # 当用户选择一项时触发
|
||||
self.tray_edit.currentTextChanged.connect(self.handle_tray_changed)
|
||||
self.tray_edit.activated.connect(self.handle_tray_changed) # 当用户选择一项时触发
|
||||
|
||||
# 连接按钮事件
|
||||
self.input_button.clicked.connect(self.handle_input)
|
||||
@ -289,7 +293,7 @@ class MainWindow(MainWindowUI):
|
||||
self.update_inspection_columns()
|
||||
|
||||
# 加载未完成的检验数据
|
||||
self.load_finished_inspection_data()
|
||||
self._safe_load_data()
|
||||
|
||||
# 只有在相机启用时处理相机显示
|
||||
if self.camera_enabled and hasattr(self, 'camera_display'):
|
||||
@ -298,8 +302,54 @@ class MainWindow(MainWindowUI):
|
||||
if not self.camera_display.camera_manager.isGrabbing:
|
||||
self.camera_display.start_display()
|
||||
|
||||
# 加载托盘号列表
|
||||
self.load_pallet_codes()
|
||||
|
||||
logging.info("显示主页面")
|
||||
|
||||
def load_pallet_codes(self):
|
||||
"""从托盘类型管理器加载托盘号并更新到tray_edit"""
|
||||
try:
|
||||
# 获取当前文本,以便保留用户选择
|
||||
current_text = self.tray_edit.currentText()
|
||||
|
||||
# 清空当前项目
|
||||
self.tray_edit.clear()
|
||||
|
||||
# 获取托盘号
|
||||
pallet_codes = self.pallet_type_manager.get_pallet_code()
|
||||
|
||||
if pallet_codes and len(pallet_codes) > 0:
|
||||
# 添加托盘号到下拉框
|
||||
for code in pallet_codes:
|
||||
self.tray_edit.addItem(code)
|
||||
|
||||
# 如果有之前的选择,尝试恢复它
|
||||
if current_text:
|
||||
index = self.tray_edit.findText(current_text)
|
||||
if index >= 0:
|
||||
self.tray_edit.setCurrentIndex(index)
|
||||
logging.info(f"已加载托盘号,共 {len(pallet_codes)} 个")
|
||||
else:
|
||||
# 如果没有托盘号,添加默认项
|
||||
default_codes = ["托盘1", "托盘2", "托盘3", "托盘4", "托盘5", "托盘6"]
|
||||
for code in default_codes:
|
||||
self.tray_edit.addItem(code)
|
||||
logging.warning("未找到托盘号,使用默认值")
|
||||
|
||||
# 尝试恢复之前的选择
|
||||
if current_text:
|
||||
index = self.tray_edit.findText(current_text)
|
||||
if index >= 0:
|
||||
self.tray_edit.setCurrentIndex(index)
|
||||
except Exception as e:
|
||||
logging.error(f"加载托盘号失败: {str(e)}")
|
||||
# 如果加载失败,添加默认项
|
||||
self.tray_edit.clear()
|
||||
default_codes = ["托盘1", "托盘2", "托盘3", "托盘4", "托盘5", "托盘6"]
|
||||
for code in default_codes:
|
||||
self.tray_edit.addItem(code)
|
||||
|
||||
def show_settings_page(self):
|
||||
"""显示设置页面"""
|
||||
# 创建设置窗口
|
||||
@ -324,65 +374,67 @@ class MainWindow(MainWindowUI):
|
||||
# 更新串口管理器配置
|
||||
self.serial_manager.reload_config()
|
||||
|
||||
# 重新加载托盘号
|
||||
self.load_pallet_codes()
|
||||
|
||||
logging.info("设置已更新,重新加载配置")
|
||||
|
||||
def handle_input(self):
|
||||
"""处理上料按钮点击事件"""
|
||||
# 创建对话框
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("上料操作")
|
||||
dialog.setFixedSize(300, 200)
|
||||
# 获取托盘号
|
||||
tray_id = self.tray_edit.currentText()
|
||||
|
||||
# 启动监听(不论后续是否确认上料)
|
||||
# 启动Modbus监控
|
||||
if not hasattr(self, 'modbus_monitor') or not self.modbus_monitor.is_running():
|
||||
self.setup_modbus_monitor()
|
||||
logging.info("已在上料操作前启动Modbus监控")
|
||||
|
||||
# 对话框布局
|
||||
layout = QVBoxLayout(dialog)
|
||||
# 启动串口监听
|
||||
self.serial_manager.auto_open_configured_ports()
|
||||
|
||||
# 添加提示信息
|
||||
info_label = QLabel("请选择拆垛层数:")
|
||||
info_label.setFont(self.normal_font)
|
||||
layout.addWidget(info_label)
|
||||
# 启动键盘监听器
|
||||
self.serial_manager.start_keyboard_listener()
|
||||
logging.info("已在上料操作前启动键盘监听器")
|
||||
|
||||
# 添加托盘类型选择
|
||||
pallet_combo = QComboBox()
|
||||
pallet_combo.setFont(self.normal_font)
|
||||
# 复制当前托盘类型选择器的内容
|
||||
for i in range(self.input_pallet_type_combo.count()):
|
||||
pallet_combo.addItem(self.input_pallet_type_combo.itemText(i))
|
||||
layout.addWidget(pallet_combo)
|
||||
|
||||
# 添加按钮
|
||||
button_layout = QHBoxLayout()
|
||||
confirm_button = QPushButton("确认")
|
||||
confirm_button.setFont(self.normal_font)
|
||||
confirm_button.setStyleSheet("background-color: #e3f2fd; border: 1px solid #2196f3; padding: 8px 16px; font-weight: bold; border-radius: 4px;")
|
||||
|
||||
cancel_button = QPushButton("取消")
|
||||
cancel_button.setFont(self.normal_font)
|
||||
cancel_button.setStyleSheet("padding: 8px 16px; font-weight: bold; border-radius: 4px;")
|
||||
|
||||
button_layout.addStretch()
|
||||
button_layout.addWidget(confirm_button)
|
||||
button_layout.addWidget(cancel_button)
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
# 连接按钮信号
|
||||
confirm_button.clicked.connect(dialog.accept)
|
||||
cancel_button.clicked.connect(dialog.reject)
|
||||
# 创建上料对话框
|
||||
from widgets.loading_dialog_widget import LoadingDialog
|
||||
dialog = LoadingDialog(parent=self)
|
||||
|
||||
# 显示对话框
|
||||
result = dialog.exec()
|
||||
|
||||
# 如果用户确认,则执行上料操作
|
||||
if result == QDialog.Accepted:
|
||||
selected_type = pallet_combo.currentText()
|
||||
|
||||
# 获取托盘料值作为拆垛层数
|
||||
stow_num = dialog.pallet_tier_value.text()
|
||||
if stow_num == "--" or not stow_num:
|
||||
QMessageBox.warning(self, "错误", "未获取到托盘料信息,请重试")
|
||||
return
|
||||
|
||||
# 获取托盘号对应的托盘类型
|
||||
pallet_type = self.pallet_type_manager.get_pallet_type_by_pallet_id(tray_id)
|
||||
# 初始化托盘号对应的序号
|
||||
if tray_id not in self.init_seq:
|
||||
self.init_seq[tray_id] = 1
|
||||
|
||||
if not pallet_type:
|
||||
QMessageBox.warning(self, "错误", "未查到对应托盘类型")
|
||||
return
|
||||
|
||||
# 执行Modbus操作
|
||||
modbus = ModbusUtils()
|
||||
client = modbus.get_client()
|
||||
try:
|
||||
# 上料 D2 寄存器写入 1 ,D0 寄存器写入托盘类型
|
||||
if modbus.write_register_until_success(client, 2, 1) and modbus.write_register_until_success(client, 0, selected_type):
|
||||
# 上料 D2 寄存器写入 1, D0 寄存器写入拆垛层数
|
||||
success0 = modbus.write_register_until_success(client, 0, int(stow_num))
|
||||
success2 = modbus.write_register_until_success(client, 2, 1)
|
||||
success3 = modbus.write_register_until_success(client, 3, 1)
|
||||
|
||||
# 上料 D2 寄存器写入 1, D0 寄存器写入拆垛层数
|
||||
if success0 and success2 and success3:
|
||||
# 创建状态标签并显示在右上角
|
||||
self.show_operation_status("上料托盘", "input", selected_type)
|
||||
self.show_operation_status("拆垛层数", "input", stow_num)
|
||||
else:
|
||||
QMessageBox.information(self, "操作提示", "上料失败")
|
||||
except Exception as e:
|
||||
@ -393,67 +445,64 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
def handle_output(self):
|
||||
"""处理下料按钮点击事件"""
|
||||
# 创建对话框
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("下料操作")
|
||||
dialog.setFixedSize(300, 200)
|
||||
# 获取托盘号
|
||||
tray_id = self.tray_edit.currentText()
|
||||
|
||||
# 启动监听(不论后续是否确认下料)
|
||||
# 启动Modbus监控
|
||||
if not hasattr(self, 'modbus_monitor') or not self.modbus_monitor.is_running():
|
||||
self.setup_modbus_monitor()
|
||||
logging.info("已在下料操作前启动Modbus监控")
|
||||
|
||||
# 对话框布局
|
||||
layout = QVBoxLayout(dialog)
|
||||
# 启动串口监听
|
||||
self.serial_manager.auto_open_configured_ports()
|
||||
|
||||
# 添加提示信息
|
||||
info_label = QLabel("请选择下料托盘类型:")
|
||||
info_label.setFont(self.normal_font)
|
||||
layout.addWidget(info_label)
|
||||
# 启动键盘监听器
|
||||
self.serial_manager.start_keyboard_listener()
|
||||
logging.info("已在下料操作前启动键盘监听器")
|
||||
|
||||
# 添加托盘类型选择
|
||||
pallet_combo = QComboBox()
|
||||
pallet_combo.setFont(self.normal_font)
|
||||
# 复制当前托盘类型选择器的内容
|
||||
for i in range(self.output_pallet_type_combo.count()):
|
||||
pallet_combo.addItem(self.output_pallet_type_combo.itemText(i))
|
||||
layout.addWidget(pallet_combo)
|
||||
|
||||
# 添加按钮
|
||||
button_layout = QHBoxLayout()
|
||||
confirm_button = QPushButton("确认")
|
||||
confirm_button.setFont(self.normal_font)
|
||||
confirm_button.setStyleSheet("background-color: #fff8e1; border: 1px solid #ffc107; padding: 8px 16px; font-weight: bold; border-radius: 4px;")
|
||||
|
||||
cancel_button = QPushButton("取消")
|
||||
cancel_button.setFont(self.normal_font)
|
||||
cancel_button.setStyleSheet("padding: 8px 16px; font-weight: bold; border-radius: 4px;")
|
||||
|
||||
button_layout.addStretch()
|
||||
button_layout.addWidget(confirm_button)
|
||||
button_layout.addWidget(cancel_button)
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
# 连接按钮信号
|
||||
confirm_button.clicked.connect(dialog.accept)
|
||||
cancel_button.clicked.connect(dialog.reject)
|
||||
# 创建下料对话框
|
||||
from widgets.unloading_dialog_widget import UnloadingDialog
|
||||
dialog = UnloadingDialog(parent=self)
|
||||
|
||||
# 显示对话框
|
||||
result = dialog.exec()
|
||||
|
||||
|
||||
# 如果用户确认,则执行下料操作
|
||||
if result == QDialog.Accepted:
|
||||
selected_type = pallet_combo.currentText()
|
||||
# 获取托盘的排序,该顺序影响着下料寄存器的写入值 切记,需要和 PLC 确认沟通完成后才能修改排序值
|
||||
pallets_dict = self.pallet_type_manager.get_pallet_type_by_type(selected_type)
|
||||
# 获取托盘料值作为下料层数
|
||||
stow_num = dialog.pallet_tier_value.text()
|
||||
if stow_num == "--" or not stow_num:
|
||||
QMessageBox.warning(self, "错误", "未获取到托盘料信息,请重试")
|
||||
return
|
||||
|
||||
# 获取托盘号对应的托盘类型
|
||||
pallet_type = self.pallet_type_manager.get_pallet_type_by_pallet_id(tray_id)
|
||||
# 初始化托盘号对应的序号
|
||||
if tray_id not in self.init_seq:
|
||||
self.init_seq[tray_id] = 1
|
||||
|
||||
if not pallet_type:
|
||||
QMessageBox.warning(self, "错误", "未查到对应下料托盘类型")
|
||||
return
|
||||
|
||||
# 执行Modbus操作
|
||||
modbus = ModbusUtils()
|
||||
client = modbus.get_client()
|
||||
try:
|
||||
#TODO: 下料 D3 寄存器写入 1 D1 寄存器写入托盘类型
|
||||
if modbus.write_register_until_success(client, 3, 1) and modbus.write_register_until_success(client, 1, pallets_dict.get(selected_type)):
|
||||
# 下料 D3 寄存器写入 1 D1 寄存器写入托盘类型
|
||||
success0 = modbus.write_register_until_success(client, 0, int(stow_num))
|
||||
success1 = modbus.write_register_until_success(client, 1, int(pallet_type))
|
||||
success3 = modbus.write_register_until_success(client, 3, 1)
|
||||
|
||||
if success0 and success1 and success3:
|
||||
# 创建状态标签并显示在右上角
|
||||
self.show_operation_status("下料托盘", "output", selected_type)
|
||||
self.show_operation_status("码垛层数", "output", stow_num)
|
||||
else:
|
||||
QMessageBox.information(self, "操作提示", "下料失败")
|
||||
QMessageBox.information(self, "操作提示", "码垛层数")
|
||||
except Exception as e:
|
||||
logging.error(f"下料操作失败: {str(e)}")
|
||||
QMessageBox.critical(self, "错误", f"下料操作失败: {str(e)}")
|
||||
logging.error(f"码垛层数操作失败: {str(e)}")
|
||||
QMessageBox.critical(self, "错误", f"码垛失败: {str(e)}")
|
||||
finally:
|
||||
modbus.close_client(client)
|
||||
|
||||
@ -482,7 +531,7 @@ class MainWindow(MainWindowUI):
|
||||
pallet_combo.addItem(str(i))
|
||||
layout.addWidget(pallet_combo)
|
||||
|
||||
# 添加提示信息
|
||||
# 添加提示信息
|
||||
info_label = QLabel("请选择码垛层数:")
|
||||
info_label.setFont(self.normal_font)
|
||||
layout.addWidget(info_label)
|
||||
@ -771,7 +820,7 @@ class MainWindow(MainWindowUI):
|
||||
QMessageBox.warning(self, "添加失败", f"添加新记录失败: {str(e)}")
|
||||
finally:
|
||||
# 重新加载数据,确保UI显示正确
|
||||
self.load_finished_inspection_data()
|
||||
self._safe_load_data()
|
||||
|
||||
def limit_table_rows(self, max_rows):
|
||||
"""限制表格最大行数
|
||||
@ -902,7 +951,9 @@ class MainWindow(MainWindowUI):
|
||||
self.statusBar().showMessage(f"处理检验数据失败: {str(e)[:50]}...", 3000)
|
||||
finally:
|
||||
# 延迟一段时间后再触发查询,避免频繁刷新UI
|
||||
QTimer.singleShot(1000, self.load_finished_inspection_data)
|
||||
# 但要避免在加载过程中触发新的加载
|
||||
if not self._loading_data_in_progress:
|
||||
QTimer.singleShot(1000, self._safe_load_data)
|
||||
|
||||
def validate_inspection_value(self, config, value):
|
||||
"""验证检验值是否有效
|
||||
@ -994,6 +1045,7 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 保存到数据库
|
||||
inspection_dao.save_inspection_data(order_id, data)
|
||||
# 注意:不要在这里调用数据加载方法,而是依靠信号和槽机制或QTimer安全地触发加载
|
||||
|
||||
|
||||
except Exception as e:
|
||||
@ -1001,8 +1053,22 @@ class MainWindow(MainWindowUI):
|
||||
# 显示错误消息
|
||||
self.statusBar().showMessage(f"保存检验数据错误: {str(e)[:50]}...", 3000)
|
||||
|
||||
def _safe_load_data(self):
|
||||
"""安全地加载数据,避免循环调用"""
|
||||
if self._loading_data_in_progress:
|
||||
# 如果已经在加载数据,不要再次触发
|
||||
logging.debug("已有数据加载正在进行,忽略此次请求")
|
||||
return
|
||||
|
||||
try:
|
||||
self._loading_data_in_progress = True
|
||||
self.load_finished_inspection_data()
|
||||
finally:
|
||||
self._loading_data_in_progress = False
|
||||
|
||||
def load_finished_inspection_data(self):
|
||||
"""加载未完成的检验数据并显示在表格中"""
|
||||
# 注意:此方法通常应通过_safe_load_data调用,以防止循环
|
||||
try:
|
||||
# 使用InspectionDAO获取未完成的检验数据
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
@ -1014,11 +1080,29 @@ class MainWindow(MainWindowUI):
|
||||
# 使用get_inspection_data_unfinished获取未完成的数据
|
||||
unfinished_data = inspection_dao.get_inspection_data_unfinished(tray_id)
|
||||
|
||||
# 断开单元格变更信号,避免加载过程中触发保存
|
||||
try:
|
||||
self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 清空表格现有数据行,只保留表头
|
||||
while self.process_table.rowCount() > 2:
|
||||
self.process_table.removeRow(2)
|
||||
|
||||
if not unfinished_data:
|
||||
logging.info("没有未完成的检验数据")
|
||||
# 清空表格现有数据行,但保留表头
|
||||
while self.process_table.rowCount() > 2:
|
||||
self.process_table.removeRow(2)
|
||||
logging.info(f"托盘号 {tray_id} 没有未完成的检验数据")
|
||||
# 确保表格完全清空,只保留表头行
|
||||
self.process_table.setRowCount(2) # 只保留表头的两行
|
||||
|
||||
# 重新连接单元格变更信号
|
||||
try:
|
||||
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 加载包装记录
|
||||
self.show_pack_item()
|
||||
return
|
||||
|
||||
logging.info(f"已加载未完成的检验数据,共 {len(unfinished_data)} 条记录")
|
||||
@ -1033,16 +1117,6 @@ class MainWindow(MainWindowUI):
|
||||
if order_id not in orders_data:
|
||||
orders_data[order_id] = []
|
||||
orders_data[order_id].append(data)
|
||||
|
||||
# 断开单元格变更信号,避免加载过程中触发保存
|
||||
try:
|
||||
self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 清空表格现有数据行,但保留表头
|
||||
while self.process_table.rowCount() > 2:
|
||||
self.process_table.removeRow(2)
|
||||
|
||||
# 添加数据到表格 - 从第3行开始添加数据
|
||||
row_idx = 2
|
||||
@ -1116,9 +1190,14 @@ class MainWindow(MainWindowUI):
|
||||
QMessageBox.warning(self, "加载失败", f"加载未完成的检验数据失败: {str(e)}")
|
||||
|
||||
finally:
|
||||
# 加载包装记录
|
||||
self.show_pack_item()
|
||||
|
||||
# 加载包装记录,但要避免循环调用
|
||||
# 设置一个标志,防止 show_pack_item 触发更多的数据加载
|
||||
if not hasattr(self, '_loading_data_in_progress'):
|
||||
self._loading_data_in_progress = True
|
||||
try:
|
||||
self.show_pack_item()
|
||||
finally:
|
||||
self._loading_data_in_progress = False
|
||||
|
||||
def load_finished_record_to_package_record(self, order_id, tray_id):
|
||||
"""加载已完成检验数据到包装记录
|
||||
@ -1168,8 +1247,13 @@ class MainWindow(MainWindowUI):
|
||||
# 将数据写入到数据库表 inspection_pack_data
|
||||
inspection_dao.save_package_record(order_id, tray_id, label_value, weight_value,net_weight_value, finish_time)
|
||||
|
||||
# 回显数据
|
||||
self.show_pack_item()
|
||||
# 回显数据,但避免循环调用
|
||||
if not hasattr(self, '_loading_data_in_progress'):
|
||||
self._loading_data_in_progress = True
|
||||
try:
|
||||
self.show_pack_item()
|
||||
finally:
|
||||
self._loading_data_in_progress = False
|
||||
|
||||
logging.info(f"已将工程号 {order_id} 托盘号 {tray_id} 的检验数据添加到包装记录并回显")
|
||||
|
||||
@ -1177,17 +1261,18 @@ class MainWindow(MainWindowUI):
|
||||
logging.error(f"加载已完成检验数据到包装记录失败: {str(e)}")
|
||||
QMessageBox.warning(self, "加载失败", f"加载已完成检验数据到包装记录失败: {str(e)}")
|
||||
def show_pack_item(self):
|
||||
"""显示包装记录"""
|
||||
try:
|
||||
from dao.inspection_dao import InspectionDAO
|
||||
inspection_dao = InspectionDAO()
|
||||
|
||||
# 获取托盘号
|
||||
# 获取托盘号
|
||||
tray_id = self.tray_edit.currentText()
|
||||
# 读取已包装的记录信息,然后回显到 UI
|
||||
# 读取已包装的记录信息,然后回显到 UI
|
||||
package_record = inspection_dao.get_package_record(tray_id)
|
||||
|
||||
# 清空包装记录表格,只保留表头
|
||||
while self.record_table.rowCount() > 1:
|
||||
self.record_table.removeRow(1)
|
||||
# 完全清空包装记录表格(包括所有行)
|
||||
self.record_table.setRowCount(0)
|
||||
|
||||
# 断开包装记录表的信号连接(如果有)
|
||||
try:
|
||||
@ -1195,15 +1280,51 @@ class MainWindow(MainWindowUI):
|
||||
except:
|
||||
pass
|
||||
|
||||
# 设置表头固定不动
|
||||
self.record_table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
|
||||
self.record_table.horizontalHeader().setStretchLastSection(False)
|
||||
self.record_table.horizontalHeader().setSectionsMovable(False)
|
||||
self.record_table.horizontalHeader().setSectionsClickable(False)
|
||||
|
||||
# 设置表头标签
|
||||
self.record_table.setHorizontalHeaderLabels(["序号", "订单", "品名", "规格", "托号", "轴包装号", "毛重", "净重", "完成时间"])
|
||||
self.record_table.horizontalHeader().setVisible(True)
|
||||
|
||||
# 设置表头样式
|
||||
self.record_table.horizontalHeader().setStyleSheet("""
|
||||
QHeaderView::section {
|
||||
background-color: #f8f8f8;
|
||||
padding: 4px;
|
||||
border: 1px solid #dddddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
|
||||
# 设置列宽
|
||||
column_widths = [70, 200, 130, 130, 160, 120, 120, 120, 160]
|
||||
for col, width in enumerate(column_widths):
|
||||
self.record_table.setColumnWidth(col, width)
|
||||
self.record_table.horizontalHeader().resizeSection(col, width)
|
||||
|
||||
# 检查是否有包装记录数据
|
||||
if not package_record:
|
||||
logging.info(f"托盘号 {tray_id} 没有包装记录数据")
|
||||
# 表格已清空,不需要再设置行数
|
||||
# 更新包装记录统计数据
|
||||
self.update_package_statistics()
|
||||
return
|
||||
|
||||
logging.info(f"托盘号 {tray_id} 已加载包装记录,共 {len(package_record)} 条记录")
|
||||
|
||||
# 添加所有包装记录到表格
|
||||
for index, item in enumerate(package_record):
|
||||
# 在包装记录表中添加新行
|
||||
row_index = index + 1 # 从第2行开始(索引为1)
|
||||
row_index = self.record_table.rowCount() # 获取当前行数,从0开始
|
||||
self.record_table.insertRow(row_index)
|
||||
|
||||
# 设置包装记录数据
|
||||
# 序号 - 第1列
|
||||
seq_item = QTableWidgetItem(str(row_index))
|
||||
seq_item = QTableWidgetItem(str(index + 1))
|
||||
seq_item.setTextAlignment(Qt.AlignCenter)
|
||||
self.record_table.setItem(row_index, 0, seq_item)
|
||||
|
||||
@ -1246,13 +1367,20 @@ class MainWindow(MainWindowUI):
|
||||
pack_time = QTableWidgetItem(str(item[7]))
|
||||
pack_time.setTextAlignment(Qt.AlignCenter)
|
||||
self.record_table.setItem(row_index, 8, pack_time)
|
||||
|
||||
# 设置表格不可编辑
|
||||
self.record_table.setEditTriggers(QTableWidget.NoEditTriggers)
|
||||
|
||||
# 更新包装记录统计数据
|
||||
self.update_package_statistics()
|
||||
except Exception as e:
|
||||
logging.error(f"显示包装记录失败: {str(e)}")
|
||||
QMessageBox.warning(self, "显示失败", f"显示包装记录失败: {str(e)}")
|
||||
def update_package_statistics(self):
|
||||
"""更新包装记录统计数据"""
|
||||
try:
|
||||
# 获取包装记录表的行数(不包括表头)
|
||||
package_count = self.record_table.rowCount() - 1
|
||||
# 获取包装记录表的行数
|
||||
package_count = self.record_table.rowCount()
|
||||
|
||||
# 更新任务表格中的已完成数量
|
||||
completed_item = QTableWidgetItem(str(package_count))
|
||||
@ -1261,7 +1389,7 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
# 计算已完成公斤数(如果称重列有数值)
|
||||
completed_kg = 0
|
||||
for row in range(1, self.record_table.rowCount()):
|
||||
for row in range(self.record_table.rowCount()):
|
||||
weight_item = self.record_table.item(row, 6) # 称重列
|
||||
if weight_item and weight_item.text():
|
||||
try:
|
||||
@ -1621,7 +1749,7 @@ class MainWindow(MainWindowUI):
|
||||
label_col = 2 + len(enabled_configs)
|
||||
|
||||
# 生成贴标号(托盘号+序号)
|
||||
label_value = f"{tray_id}-{self.init_seq[tray_id]}"
|
||||
label_value = f"{self.init_seq[tray_id]}"
|
||||
|
||||
# 断开单元格变更信号,避免程序自动写入时触发
|
||||
try:
|
||||
@ -1838,7 +1966,7 @@ class MainWindow(MainWindowUI):
|
||||
|
||||
self.inspection_manager.delete_inspection_data(order_id, tray_id)
|
||||
# 触发重新查询,更新数据
|
||||
self.load_finished_inspection_data()
|
||||
self._safe_load_data()
|
||||
logging.info(f"已删除当前在处理的数据: order_id: {order_id}, tray_id: {tray_id}")
|
||||
"""
|
||||
try:
|
||||
@ -1882,7 +2010,7 @@ class MainWindow(MainWindowUI):
|
||||
self.init_seq[tray_id] = 1
|
||||
|
||||
# 生成贴标号(托盘号+序号)
|
||||
label_value = f"{tray_id}-{self.init_seq[tray_id]}-NG"
|
||||
label_value = f"{self.init_seq[tray_id]}-NG"
|
||||
self.init_seq[tray_id] += 1
|
||||
|
||||
# 保存贴标数据到数据库
|
||||
@ -2104,9 +2232,11 @@ class MainWindow(MainWindowUI):
|
||||
else:
|
||||
item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色
|
||||
|
||||
# 保存到数据库
|
||||
tray_id = self.tray_edit.currentText()
|
||||
self.save_inspection_data(order_id, tray_id, config_position, config_id, formatted_value, status)
|
||||
# 保存到数据库,但只在非加载状态下
|
||||
if not self._loading_data_in_progress:
|
||||
tray_id = self.tray_edit.currentText()
|
||||
self.save_inspection_data(order_id, tray_id, config_position, config_id, formatted_value, status)
|
||||
# 不需要在这里主动触发数据重新加载,因为handle_inspection_cell_changed会处理
|
||||
|
||||
# 重新连接信号
|
||||
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
|
||||
@ -2119,4 +2249,39 @@ class MainWindow(MainWindowUI):
|
||||
try:
|
||||
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
|
||||
except:
|
||||
pass
|
||||
pass
|
||||
|
||||
def handle_tray_changed(self):
|
||||
"""处理托盘号变更事件,启动监听并加载数据"""
|
||||
try:
|
||||
tray_id = self.tray_edit.currentText()
|
||||
if tray_id:
|
||||
logging.info(f"托盘号变更为 {tray_id},启动监听")
|
||||
|
||||
# 确保启动Modbus监控
|
||||
if not hasattr(self, 'modbus_monitor') or not self.modbus_monitor.is_running():
|
||||
try:
|
||||
self.setup_modbus_monitor()
|
||||
logging.info("已在托盘号变更时启动Modbus监控")
|
||||
except Exception as e:
|
||||
logging.error(f"托盘号变更时启动Modbus监控失败: {str(e)}")
|
||||
|
||||
# 确保启动串口监听
|
||||
try:
|
||||
self.serial_manager.auto_open_configured_ports()
|
||||
# 启动键盘监听器
|
||||
self.serial_manager.start_keyboard_listener()
|
||||
logging.info("已在托盘号变更时启动串口和键盘监听器")
|
||||
except Exception as e:
|
||||
logging.error(f"托盘号变更时启动串口监听失败: {str(e)}")
|
||||
|
||||
# 初始化托盘号对应的序号(如果不存在)
|
||||
if tray_id not in self.init_seq:
|
||||
self.init_seq[tray_id] = 1
|
||||
logging.info(f"初始化托盘号 {tray_id} 的序号为 1")
|
||||
|
||||
# 加载数据
|
||||
self._safe_load_data()
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"处理托盘号变更失败: {str(e)}")
|
||||
@ -1,4 +1,5 @@
|
||||
from PySide6.QtWidgets import QMessageBox, QVBoxLayout
|
||||
from PySide6.QtCore import Qt
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
@ -7,6 +8,7 @@ from utils.sql_utils import SQLUtils
|
||||
from widgets.inspection_settings_widget import InspectionSettingsWidget
|
||||
from widgets.pallet_type_settings_widget import PalletTypeSettingsWidget
|
||||
from utils.config_loader import ConfigLoader
|
||||
from utils.app_mode import AppMode
|
||||
|
||||
class SettingsWidget(SettingsUI):
|
||||
def __init__(self, parent=None):
|
||||
@ -64,6 +66,9 @@ class SettingsWidget(SettingsUI):
|
||||
# 初始化数据库类型UI状态
|
||||
self.load_db_config()
|
||||
|
||||
# 初始化运行模式状态
|
||||
self.load_app_mode()
|
||||
|
||||
logging.info("SettingsWidget初始化完成")
|
||||
|
||||
def connect_signals(self):
|
||||
@ -86,6 +91,43 @@ class SettingsWidget(SettingsUI):
|
||||
# 返回按钮
|
||||
if hasattr(self, 'back_button'):
|
||||
self.back_button.clicked.connect(self.back_to_main)
|
||||
|
||||
# 运行模式单选按钮
|
||||
self.standalone_mode_radio.toggled.connect(self.on_app_mode_changed)
|
||||
self.api_mode_radio.toggled.connect(self.on_app_mode_changed)
|
||||
|
||||
def load_app_mode(self):
|
||||
"""加载应用运行模式设置"""
|
||||
try:
|
||||
# 获取当前运行模式
|
||||
current_mode = AppMode.get_mode()
|
||||
|
||||
# 设置对应的单选按钮
|
||||
if current_mode == 'api':
|
||||
self.api_mode_radio.setChecked(True)
|
||||
else: # 默认为standalone
|
||||
self.standalone_mode_radio.setChecked(True)
|
||||
|
||||
logging.info(f"已加载应用运行模式: {current_mode}")
|
||||
except Exception as e:
|
||||
logging.error(f"加载应用运行模式失败: {e}")
|
||||
# 默认选择单机模式
|
||||
self.standalone_mode_radio.setChecked(True)
|
||||
|
||||
def on_app_mode_changed(self, checked):
|
||||
"""处理运行模式变更"""
|
||||
if not checked: # 忽略未选中状态的信号
|
||||
return
|
||||
|
||||
try:
|
||||
if self.standalone_mode_radio.isChecked():
|
||||
AppMode.set_mode('standalone')
|
||||
logging.info("已将应用运行模式设置为: 单机模式")
|
||||
elif self.api_mode_radio.isChecked():
|
||||
AppMode.set_mode('api')
|
||||
logging.info("已将应用运行模式设置为: 接口模式")
|
||||
except Exception as e:
|
||||
logging.error(f"设置应用运行模式失败: {e}")
|
||||
|
||||
def load_db_config(self):
|
||||
"""加载数据库配置"""
|
||||
|
||||
166
widgets/unloading_dialog_widget.py
Normal file
166
widgets/unloading_dialog_widget.py
Normal file
@ -0,0 +1,166 @@
|
||||
from ui.unloading_dialog_ui import UnloadingDialogUI
|
||||
from apis.tary_api import TaryApi
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
from PySide6.QtWidgets import QMessageBox, QDialog
|
||||
import logging
|
||||
from utils.app_mode import AppMode
|
||||
from utils.pallet_type_manager import PalletTypeManager
|
||||
|
||||
class UnloadingDialog(UnloadingDialogUI):
|
||||
# 定义一个信号,用于向主窗口传递托盘号
|
||||
tray_code_signal = Signal(str, str, str, str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""初始化下料对话框"""
|
||||
super().__init__()
|
||||
self.parent = parent
|
||||
|
||||
# 初始化API
|
||||
self.tary_api = TaryApi()
|
||||
|
||||
# 彻底禁用对话框的回车键关闭功能
|
||||
self.setModal(True)
|
||||
# 禁用所有按钮的默认行为
|
||||
self.confirm_button.setAutoDefault(False)
|
||||
self.confirm_button.setDefault(False)
|
||||
self.cancel_button.setAutoDefault(False)
|
||||
self.cancel_button.setDefault(False)
|
||||
|
||||
# 设置对话框特性,按下Escape键才能关闭
|
||||
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
|
||||
|
||||
# 绑定事件
|
||||
self.setup_connections()
|
||||
|
||||
def setup_connections(self):
|
||||
"""设置事件连接"""
|
||||
# 托盘号输入框回车事件触发查询
|
||||
self.tray_input.returnPressed.connect(self.handle_tray_return_pressed)
|
||||
# 移除editingFinished事件,避免重复触发查询
|
||||
# self.tray_input.editingFinished.connect(self.on_tray_query)
|
||||
|
||||
# 确认按钮点击事件
|
||||
self.confirm_button.clicked.connect(self.accept)
|
||||
|
||||
# 取消按钮点击事件
|
||||
self.cancel_button.clicked.connect(self.reject)
|
||||
|
||||
def handle_tray_return_pressed(self):
|
||||
"""处理托盘输入框的回车事件"""
|
||||
# 阻止事件传播
|
||||
logging.info("托盘输入框回车事件触发")
|
||||
self.on_tray_query()
|
||||
|
||||
# 阻止事件继续传播
|
||||
return True
|
||||
|
||||
def on_tray_query(self):
|
||||
"""查询托盘信息"""
|
||||
try:
|
||||
tray_code = self.tray_input.text().strip()
|
||||
if not tray_code:
|
||||
return
|
||||
|
||||
logging.info(f"查询托盘号: {tray_code}")
|
||||
|
||||
if AppMode.is_api():
|
||||
self.tary_api = TaryApi()
|
||||
# 调用API获取托盘信息
|
||||
response = self.tary_api.get_tary_info(tray_code)
|
||||
else:
|
||||
pallet_type_manager = PalletTypeManager.get_instance()
|
||||
pallet_info = pallet_type_manager.get_pallet_info_by_pallet_id(tray_code)
|
||||
|
||||
# 检查返回的数据类型并进行适当处理
|
||||
if pallet_info is None:
|
||||
response = {
|
||||
"success": False,
|
||||
"message": "未找到托盘信息"
|
||||
}
|
||||
else:
|
||||
# 如果返回的是元组(数据库查询结果),将其转换为字典
|
||||
# 根据dao/pallet_type_dao.py中get_pallet_info_by_pallet_id方法的SQL查询
|
||||
# 返回的字段顺序为:pallet_code, pallet_name, description, axios_name, axios_type, tier, size, amount, weight
|
||||
response = {
|
||||
"success": True,
|
||||
"data": {
|
||||
"tp_note": pallet_info[0] if len(pallet_info) > 0 else "",
|
||||
"product_name": pallet_info[1] if len(pallet_info) > 1 else "",
|
||||
"axis_type": pallet_info[4] if len(pallet_info) > 4 else "",
|
||||
"tier": str(pallet_info[5]) if len(pallet_info) > 5 else "",
|
||||
"weight": str(pallet_info[8]) if len(pallet_info) > 8 else "",
|
||||
"quantity": ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logging.info(f"托盘信息响应: {response}")
|
||||
logging.info(f"response.success={response.get('success')}, response.data存在={response.get('data') is not None}")
|
||||
|
||||
if response.get("success", False) and response.get("data"):
|
||||
tray_data = response.get("data", {})
|
||||
logging.info(f"托盘数据: {tray_data}")
|
||||
|
||||
# 显示托盘相关信息
|
||||
axis_type = str(tray_data.get("axis_type", "--"))
|
||||
tier = str(tray_data.get("tier", "--"))
|
||||
weight = str(tray_data.get("weight", "--"))
|
||||
|
||||
logging.info(f"显示托盘信息: 轴型={axis_type}, 托盘料={tier}, 重量={weight}")
|
||||
|
||||
# 设置显示值
|
||||
self.axis_value.setText(axis_type)
|
||||
self.pallet_tier_value.setText(tier)
|
||||
self.quantity_value.setText("") # 数量为空
|
||||
self.weight_value.setText(f"{weight} kg")
|
||||
|
||||
# 发送托盘号到主窗口
|
||||
from widgets.main_window import MainWindow
|
||||
main_window = self.parent
|
||||
if main_window and isinstance(main_window, MainWindow):
|
||||
# 检查托盘号是否已存在
|
||||
existed = False
|
||||
for i in range(main_window.tray_edit.count()):
|
||||
if main_window.tray_edit.itemText(i) == tray_code:
|
||||
existed = True
|
||||
break
|
||||
|
||||
# 如果不存在,则添加
|
||||
if not existed:
|
||||
logging.info(f"添加托盘号到主窗口: {tray_code}")
|
||||
main_window.tray_edit.addItem(tray_code)
|
||||
|
||||
# 设置当前选中的托盘号
|
||||
main_window.tray_edit.setCurrentText(tray_code)
|
||||
logging.info(f"设置主窗口当前托盘号: {tray_code}")
|
||||
else:
|
||||
# 获取托盘信息失败
|
||||
error_msg = response.get("message", "获取托盘信息失败")
|
||||
logging.warning(f"查询失败: {error_msg}")
|
||||
QMessageBox.warning(self, "查询失败", error_msg)
|
||||
except Exception as e:
|
||||
logging.error(f"查询托盘信息异常: {str(e)}")
|
||||
QMessageBox.critical(self, "查询异常", f"查询托盘信息时发生异常: {str(e)}")
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
"""重写键盘事件处理,防止回车关闭对话框"""
|
||||
# 如果按下回车键
|
||||
if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
|
||||
logging.info(f"捕获到回车键事件,当前焦点部件: {self.focusWidget()}")
|
||||
|
||||
# 如果焦点在托盘输入框上,触发查询
|
||||
if self.focusWidget() == self.tray_input:
|
||||
# 不需要重复调用on_tray_query,因为returnPressed信号已经处理了
|
||||
event.accept() # 消费掉这个事件
|
||||
return
|
||||
|
||||
# 如果焦点在确认按钮上,则允许默认行为(确认)
|
||||
if self.focusWidget() == self.confirm_button:
|
||||
return super().keyPressEvent(event)
|
||||
|
||||
# 其他情况下,阻止回车事件传播
|
||||
event.accept() # 消费掉这个事件
|
||||
return
|
||||
|
||||
# 其他键位事件交给父类处理
|
||||
super().keyPressEvent(event)
|
||||
Loading…
Reference in New Issue
Block a user