实现检验配置功能,支持动态配置检验项目;修复表格表头布局错位问题

This commit is contained in:
zhu-mengmeng 2025-06-07 16:44:27 +08:00
parent 5977b29a9c
commit f31871b4f5
16 changed files with 1378 additions and 190 deletions

2
.gitignore vendored
View File

@ -22,7 +22,7 @@ __pycache__/
Thumbs.db
# 缓存文件
__pycache__/
*__pycache__/
.pytest_cache/
.coverage
htmlcov/

327
dao/inspection_dao.py Normal file
View File

@ -0,0 +1,327 @@
import json
import logging
from datetime import datetime
from utils.sql_utils import SQLUtils
class InspectionDAO:
"""检验项目配置和数据访问对象"""
def __init__(self):
"""初始化数据访问对象"""
self.db = SQLUtils('sqlite', database='db/jtDB.db')
def __del__(self):
"""析构函数,确保数据库连接关闭"""
if hasattr(self, 'db'):
self.db.close()
def get_all_inspection_configs(self, include_disabled=False):
"""获取所有检验项目配置
Args:
include_disabled: 是否包含禁用的项目
Returns:
list: 检验项目配置列表
"""
try:
if include_disabled:
sql = """
SELECT id, position, name, display_name, enabled, required,
data_type, min_value, max_value, enum_values, unit, sort_order
FROM inspection_config
WHERE is_deleted = FALSE
ORDER BY sort_order, position
"""
params = ()
else:
sql = """
SELECT id, position, name, display_name, enabled, required,
data_type, min_value, max_value, enum_values, unit, sort_order
FROM inspection_config
WHERE is_deleted = FALSE AND enabled = TRUE
ORDER BY sort_order, position
"""
params = ()
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
configs = []
for row in results:
config = {
'id': row[0],
'position': row[1],
'name': row[2],
'display_name': row[3],
'enabled': bool(row[4]),
'required': bool(row[5]),
'data_type': row[6],
'min_value': row[7],
'max_value': row[8],
'enum_values': json.loads(row[9]) if row[9] else None,
'unit': row[10],
'sort_order': row[11]
}
configs.append(config)
return configs
except Exception as e:
logging.error(f"获取检验项目配置失败: {str(e)}")
return []
def get_enabled_inspection_configs(self):
"""获取已启用的检验项目配置
Returns:
list: 已启用的检验项目配置列表
"""
return self.get_all_inspection_configs(include_disabled=False)
def get_inspection_config_by_position(self, position):
"""根据位置获取检验项目配置
Args:
position: 位置序号 (1-6)
Returns:
dict: 检验项目配置, 未找到则返回None
"""
try:
sql = """
SELECT id, position, name, display_name, enabled, required,
data_type, min_value, max_value, enum_values, unit, sort_order
FROM inspection_config
WHERE position = ? AND is_deleted = FALSE
"""
params = (position,)
self.db.cursor.execute(sql, params)
row = self.db.cursor.fetchone()
if row:
config = {
'id': row[0],
'position': row[1],
'name': row[2],
'display_name': row[3],
'enabled': bool(row[4]),
'required': bool(row[5]),
'data_type': row[6],
'min_value': row[7],
'max_value': row[8],
'enum_values': json.loads(row[9]) if row[9] else None,
'unit': row[10],
'sort_order': row[11]
}
return config
else:
return None
except Exception as e:
logging.error(f"获取检验项目配置失败: {str(e)}")
return None
def update_inspection_config(self, config_id, data, username='system'):
"""更新检验项目配置
Args:
config_id: 配置ID
data: 更新数据
username: 操作用户
Returns:
bool: 更新是否成功
"""
try:
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 构建更新SQL
update_fields = []
params = []
# 可更新的字段
allowed_fields = [
'name', 'display_name', 'enabled', 'required',
'data_type', 'min_value', 'max_value', 'unit',
'sort_order', 'enum_values'
]
for field in allowed_fields:
if field in data:
# 特殊处理enum_values字段确保存储为JSON字符串
if field == 'enum_values' and data[field] is not None:
if isinstance(data[field], list):
update_fields.append(f"{field} = ?")
params.append(json.dumps(data[field]))
elif isinstance(data[field], str):
# 如果已经是字符串检查是否有效的JSON
try:
json.loads(data[field])
update_fields.append(f"{field} = ?")
params.append(data[field])
except:
logging.warning(f"无效的JSON: {data[field]}")
continue
else:
update_fields.append(f"{field} = ?")
params.append(data[field])
# 添加更新时间和更新人
update_fields.append("update_time = ?")
params.append(current_time)
update_fields.append("update_by = ?")
params.append(username)
# 添加配置ID到参数列表
params.append(config_id)
# 构建SQL
sql = f"""
UPDATE inspection_config
SET {', '.join(update_fields)}
WHERE id = ?
"""
self.db.execute_update(sql, params)
return True
except Exception as e:
logging.error(f"更新检验项目配置失败: {str(e)}")
return False
def toggle_inspection_config(self, position, enabled, username='system'):
"""启用或禁用检验项目配置
Args:
position: 位置序号 (1-6)
enabled: 是否启用
username: 操作用户
Returns:
bool: 操作是否成功
"""
try:
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
sql = """
UPDATE inspection_config
SET enabled = ?, update_time = ?, update_by = ?
WHERE position = ? AND is_deleted = FALSE
"""
params = (enabled, current_time, username, position)
self.db.execute_update(sql, params)
return True
except Exception as e:
logging.error(f"更新检验项目启用状态失败: {str(e)}")
return False
def save_inspection_data(self, order_id, data, username='system'):
"""保存检验数据
Args:
order_id: 工程号
data: 检验数据列表格式: [{'position': 1, 'config_id': 1, 'value': '合格'}, ...]
username: 操作用户
Returns:
bool: 保存是否成功
"""
try:
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.db.begin_transaction()
for item in data:
position = item.get('position')
config_id = item.get('config_id')
value = item.get('value')
status = item.get('status', 'pass')
remark = item.get('remark', '')
# 检查是否已存在该工程号和位置的记录
check_sql = """
SELECT id FROM inspection_data
WHERE order_id = ? AND position = ? AND is_deleted = FALSE
"""
check_params = (order_id, position)
self.db.cursor.execute(check_sql, check_params)
existing = self.db.cursor.fetchone()
if existing:
# 更新已有记录
update_sql = """
UPDATE inspection_data
SET config_id = ?, value = ?, status = ?, remark = ?,
update_time = ?, update_by = ?
WHERE id = ?
"""
update_params = (
config_id, value, status, remark,
current_time, username, existing[0]
)
self.db.cursor.execute(update_sql, update_params)
else:
# 插入新记录
insert_sql = """
INSERT INTO inspection_data (
order_id, position, config_id, value, status, remark,
create_time, create_by, is_deleted
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, FALSE)
"""
insert_params = (
order_id, position, config_id, value, status, remark,
current_time, username
)
self.db.cursor.execute(insert_sql, insert_params)
self.db.commit_transaction()
return True
except Exception as e:
self.db.rollback_transaction()
logging.error(f"保存检验数据失败: {str(e)}")
return False
def get_inspection_data_by_order(self, order_id):
"""根据工程号获取检验数据
Args:
order_id: 工程号
Returns:
list: 检验数据列表
"""
try:
sql = """
SELECT d.id, d.position, d.config_id, d.value, d.status, d.remark,
c.name, c.display_name, c.data_type, c.unit
FROM inspection_data d
JOIN inspection_config c ON d.config_id = c.id
WHERE d.order_id = ? AND d.is_deleted = FALSE
ORDER BY d.position
"""
params = (order_id,)
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
data_list = []
for row in results:
data = {
'id': row[0],
'position': row[1],
'config_id': row[2],
'value': row[3],
'status': row[4],
'remark': row[5],
'name': row[6],
'display_name': row[7],
'data_type': row[8],
'unit': row[9]
}
data_list.append(data)
return data_list
except Exception as e:
logging.error(f"获取检验数据失败: {str(e)}")
return []

55
db/schema.sql Normal file
View File

@ -0,0 +1,55 @@
-- 创建检验项目配置表
CREATE TABLE IF NOT EXISTS inspection_config (
id INTEGER PRIMARY KEY AUTOINCREMENT,
position INTEGER NOT NULL, -- 位置序号 (1-6)
name VARCHAR(50) NOT NULL, -- 检验项目名称
display_name VARCHAR(50) NOT NULL, -- 显示名称
enabled BOOLEAN DEFAULT TRUE, -- 是否启用
required BOOLEAN DEFAULT FALSE, -- 是否必填
data_type VARCHAR(20) DEFAULT 'text', -- 数据类型: text, number, enum
min_value FLOAT, -- 最小值 (用于number类型)
max_value FLOAT, -- 最大值 (用于number类型)
enum_values TEXT, -- 枚举值 (用于enum类型, JSON格式存储)
unit VARCHAR(20), -- 单位
sort_order INTEGER NOT NULL, -- 排序顺序
create_time TIMESTAMP NOT NULL,
create_by VARCHAR(50) NOT NULL,
update_time TIMESTAMP,
update_by VARCHAR(50),
is_deleted BOOLEAN DEFAULT FALSE,
UNIQUE(position, is_deleted) -- 确保同一位置只有一个激活的配置
);
-- 创建检验数据记录表
CREATE TABLE IF NOT EXISTS inspection_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id VARCHAR(50) NOT NULL, -- 关联的工程号
position INTEGER NOT NULL, -- 位置序号
config_id INTEGER NOT NULL, -- 关联的配置ID
value TEXT NOT NULL, -- 检验值 (所有类型都用TEXT存储)
status VARCHAR(20) DEFAULT 'pass', -- 状态: pass, fail, warning
remark TEXT, -- 备注
create_time TIMESTAMP NOT NULL,
create_by VARCHAR(50) NOT NULL,
update_time TIMESTAMP,
update_by VARCHAR(50),
is_deleted BOOLEAN DEFAULT FALSE,
FOREIGN KEY(config_id) REFERENCES inspection_config(id)
);
-- 创建默认检验项目数据
INSERT OR IGNORE INTO inspection_config (
position, name, display_name, enabled, required, data_type,
min_value, max_value, unit, sort_order, create_time, create_by
) VALUES
(1, 'appearance', '外观', TRUE, TRUE, 'enum', NULL, NULL, '', 1, CURRENT_TIMESTAMP, 'system'),
(2, 'diameter', '线径', TRUE, TRUE, 'number', 0, 100, 'mm', 2, CURRENT_TIMESTAMP, 'system'),
(3, 'resistance', '电阻', TRUE, FALSE, 'number', 0, 1000, 'Ω', 3, CURRENT_TIMESTAMP, 'system'),
(4, 'hardness', '硬度', FALSE, FALSE, 'number', 0, 100, 'HRC', 4, CURRENT_TIMESTAMP, 'system'),
(5, 'strength', '强度', FALSE, FALSE, 'number', 0, 1000, 'MPa', 5, CURRENT_TIMESTAMP, 'system'),
(6, 'custom', '自定义', FALSE, FALSE, 'text', NULL, NULL, '', 6, CURRENT_TIMESTAMP, 'system');
-- 为外观检验项设置枚举值
UPDATE inspection_config
SET enum_values = '["合格", "不合格", "需要重检"]'
WHERE name = 'appearance';

View File

@ -0,0 +1,216 @@
from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLabel,
QLineEdit, QCheckBox, QComboBox, QPushButton, QGroupBox,
QTableWidget, QTableWidgetItem, QHeaderView, QAbstractItemView,
QSpinBox, QDoubleSpinBox, QFrame, QScrollArea
)
from PySide6.QtGui import QFont, QBrush, QColor
from PySide6.QtCore import Qt, Signal
class InspectionSettingsUI(QWidget):
"""检验设置UI"""
def __init__(self, parent=None):
super().__init__(parent)
self.parent = parent
self.init_ui()
def init_ui(self):
"""初始化UI"""
# 设置字体
self.title_font = QFont("微软雅黑", 14, QFont.Bold)
self.normal_font = QFont("微软雅黑", 11)
self.small_font = QFont("微软雅黑", 9)
# 设置背景颜色,便于识别
self.setStyleSheet("background-color: #f5f5f5;")
# 创建主布局
self.main_layout = QVBoxLayout(self)
self.main_layout.setContentsMargins(20, 20, 20, 20)
self.main_layout.setSpacing(15)
# 标题
self.title_label = QLabel("检验项目配置")
self.title_label.setFont(self.title_font)
self.title_label.setAlignment(Qt.AlignCenter)
self.title_label.setStyleSheet("color: #1a237e; padding: 10px;")
self.main_layout.addWidget(self.title_label)
# 说明文本
self.desc_label = QLabel("配置检验二级菜单项目至少1项最多6项。启用的项目将显示在微丝产线表格的检验区域。")
self.desc_label.setWordWrap(True)
self.desc_label.setStyleSheet("color: #666666; padding: 0px 10px 10px 10px;")
self.main_layout.addWidget(self.desc_label)
# 创建滚动区域
self.scroll_area = QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setFrameShape(QFrame.NoFrame)
# 创建滚动区域的内容部件
self.scroll_widget = QWidget()
self.scroll_layout = QVBoxLayout(self.scroll_widget)
self.scroll_layout.setContentsMargins(0, 0, 0, 0)
self.scroll_layout.setSpacing(15)
# 创建6个检验项目配置组
self.config_groups = []
for i in range(6):
group = self.create_config_group(i + 1)
self.scroll_layout.addWidget(group)
self.config_groups.append(group)
# 设置滚动区域的部件
self.scroll_area.setWidget(self.scroll_widget)
self.main_layout.addWidget(self.scroll_area, 1)
# 底部按钮区域
self.button_layout = QHBoxLayout()
self.button_layout.setContentsMargins(0, 10, 0, 0)
self.save_button = QPushButton("保存配置")
self.save_button.setFont(self.normal_font)
self.save_button.setFixedSize(120, 40)
self.save_button.setStyleSheet("""
QPushButton {
background-color: #4caf50;
color: white;
border: none;
border-radius: 5px;
}
QPushButton:hover {
background-color: #45a049;
}
QPushButton:pressed {
background-color: #3d8b40;
}
""")
self.reset_button = QPushButton("重置")
self.reset_button.setFont(self.normal_font)
self.reset_button.setFixedSize(120, 40)
self.reset_button.setStyleSheet("""
QPushButton {
background-color: #f44336;
color: white;
border: none;
border-radius: 5px;
}
QPushButton:hover {
background-color: #e53935;
}
QPushButton:pressed {
background-color: #d32f2f;
}
""")
self.button_layout.addStretch()
self.button_layout.addWidget(self.reset_button)
self.button_layout.addSpacing(20)
self.button_layout.addWidget(self.save_button)
self.main_layout.addLayout(self.button_layout)
def create_config_group(self, position):
"""创建检验项目配置组
Args:
position: 位置序号 (1-6)
Returns:
QGroupBox: 配置组
"""
group = QGroupBox(f"检验项目 {position}")
group.setFont(self.normal_font)
group.setCheckable(True)
group.setChecked(position <= 3) # 默认前3个启用
group_layout = QFormLayout(group)
group_layout.setContentsMargins(15, 25, 15, 15)
group_layout.setSpacing(10)
# 名称
name_label = QLabel("项目名称:")
name_label.setFont(self.normal_font)
name_input = QLineEdit()
name_input.setFont(self.normal_font)
name_input.setObjectName(f"name_input_{position}")
group_layout.addRow(name_label, name_input)
# 显示名称
display_name_label = QLabel("显示名称:")
display_name_label.setFont(self.normal_font)
display_name_input = QLineEdit()
display_name_input.setFont(self.normal_font)
display_name_input.setObjectName(f"display_name_input_{position}")
group_layout.addRow(display_name_label, display_name_input)
# 数据类型
data_type_label = QLabel("数据类型:")
data_type_label.setFont(self.normal_font)
data_type_combo = QComboBox()
data_type_combo.setFont(self.normal_font)
data_type_combo.setObjectName(f"data_type_combo_{position}")
data_type_combo.addItem("文本", "text")
data_type_combo.addItem("数值", "number")
data_type_combo.addItem("枚举", "enum")
group_layout.addRow(data_type_label, data_type_combo)
# 单位 (用于数值类型)
unit_label = QLabel("单位:")
unit_label.setFont(self.normal_font)
unit_input = QLineEdit()
unit_input.setFont(self.normal_font)
unit_input.setObjectName(f"unit_input_{position}")
group_layout.addRow(unit_label, unit_input)
# 最小值 (用于数值类型)
min_value_label = QLabel("最小值:")
min_value_label.setFont(self.normal_font)
min_value_spin = QDoubleSpinBox()
min_value_spin.setFont(self.normal_font)
min_value_spin.setObjectName(f"min_value_spin_{position}")
min_value_spin.setRange(-999999, 999999)
min_value_spin.setDecimals(2)
min_value_spin.setSingleStep(0.1)
group_layout.addRow(min_value_label, min_value_spin)
# 最大值 (用于数值类型)
max_value_label = QLabel("最大值:")
max_value_label.setFont(self.normal_font)
max_value_spin = QDoubleSpinBox()
max_value_spin.setFont(self.normal_font)
max_value_spin.setObjectName(f"max_value_spin_{position}")
max_value_spin.setRange(-999999, 999999)
max_value_spin.setDecimals(2)
max_value_spin.setSingleStep(0.1)
max_value_spin.setValue(100)
group_layout.addRow(max_value_label, max_value_spin)
# 枚举值 (用于枚举类型)
enum_values_label = QLabel("枚举值:")
enum_values_label.setFont(self.normal_font)
enum_values_input = QLineEdit()
enum_values_input.setFont(self.normal_font)
enum_values_input.setObjectName(f"enum_values_input_{position}")
enum_values_input.setPlaceholderText("用逗号分隔,如: 合格,不合格,需重检")
group_layout.addRow(enum_values_label, enum_values_input)
# 是否必填
required_check = QCheckBox("必填项")
required_check.setFont(self.normal_font)
required_check.setObjectName(f"required_check_{position}")
group_layout.addRow("", required_check)
# 保存位置信息
group.setProperty("position", position)
return group
def set_form_enabled(self, enabled):
"""设置表单是否可编辑"""
for group in self.config_groups:
group.setEnabled(enabled)
self.save_button.setEnabled(enabled)
self.reset_button.setEnabled(enabled)

View File

@ -84,26 +84,14 @@ class MainWindowUI(QMainWindow):
self.project_table = QTableWidget(4, 4)
self.project_table.setHorizontalHeaderLabels(["用电", "数量", "产量", "开机率"])
self.project_table.setVerticalHeaderLabels(["当日", "当月", "当年", "累计"])
#设置字体
self.project_table.setFont(self.normal_font)
# 设置垂直表头宽度
self.project_table.verticalHeader().setFixedWidth(60)
self.project_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.project_table.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.project_table.setEditTriggers(QTableWidget.NoEditTriggers) # 设置为不可编辑
# 设置表格样式
self.project_table.setStyleSheet("""
QTableWidget {
border: none;
gridline-color: #dddddd;
}
QHeaderView::section {
background-color: #f0f0f0;
padding: 4px;
border: 1px solid #cccccc;
font-weight: bold;
}
""")
self.project_layout.addWidget(self.project_table)
self.left_layout.addWidget(self.project_frame)
# 任务信息区域 - 使用QFrame包裹添加边框
@ -162,7 +150,7 @@ class MainWindowUI(QMainWindow):
# 订单行
self.order_layout = QHBoxLayout()
self.order_label = QLabel("订单")
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;")
@ -463,9 +451,9 @@ class MainWindowUI(QMainWindow):
self.process_content_layout.setSpacing(0)
# 创建表格 - 支持动态配置检验列数
self.inspection_columns = 3 # 默认3列可动态配置
# TODO后续从数据库中读
self.inspection_headers = ["外观", "线径", "电阻", "硬度", "强度"] # 默认检验标题
self.inspection_columns = 1 # 默认至少显示1列
# 默认检验标题实际运行时将通过InspectionConfigManager获
self.inspection_headers = ["检验项"]
total_columns = 2 + self.inspection_columns + 2 # 上料2列 + 检验N列 + 包装2列
self.process_table = QTableWidget(8, total_columns) # 8行1行标题区域 + 1行列标题 + 6行数据
@ -486,9 +474,7 @@ class MainWindowUI(QMainWindow):
# 创建表头 - 合并单元格
self.create_process_table_headers()
# 填充表格内容
self.fill_process_table_cells()
# 添加表格到布局
self.process_content_layout.addWidget(self.process_table)
@ -540,9 +526,7 @@ class MainWindowUI(QMainWindow):
# 添加表格到布局
self.record_layout.addWidget(self.record_table)
# 填充表格内容
self.fill_record_table_cells()
# 添加一个通用的单元格创建方法
def create_cell_item(self, text, alignment=Qt.AlignCenter):
@ -559,61 +543,6 @@ class MainWindowUI(QMainWindow):
item.setTextAlignment(alignment)
return item
def fill_process_table_cells(self):
"""填充微丝产线表格单元格"""
# 工序工程数据
process_data = ["拉丝", "退火", "检验", "包装", "入库", "出库"]
# 填充工序数据
for row in range(6):
# 设置序号
self.process_table.setItem(row + 2, 0, self.create_cell_item(row + 1))
# 设置工序工程名称
self.process_table.setItem(row + 2, 1, self.create_cell_item(process_data[row]))
# 只为前3行设置数据
if row < 3:
# 检验区域 - 动态列
inspection_data = ["合格", f"{0.5 + row * 0.1:.1f}", f"{10 + row * 5}", f"{80 + row * 5}", f"{90 + row * 2}"]
for i in range(min(self.inspection_columns, len(inspection_data))):
self.process_table.setItem(row + 2, 2 + i, self.create_cell_item(inspection_data[i]))
# 包装区域 - 贴标和称重
packaging_start_col = 2 + self.inspection_columns
self.process_table.setItem(row + 2, packaging_start_col, self.create_cell_item("已完成"))
self.process_table.setItem(row + 2, packaging_start_col + 1, self.create_cell_item(f"{50 + row * 10}"))
def fill_record_table_cells(self):
"""填充包装记录表格单元格"""
# 填充序号列
for row in range(12):
self.record_table.setItem(row + 1, 0, self.create_cell_item(row + 1))
# 填充示例数据
record_data = [
["ORD-2025-001", "不锈钢", "0.5mm", "T001", "A001", "50kg"],
["ORD-2025-001", "不锈钢", "0.6mm", "T001", "A002", "55kg"],
["ORD-2025-001", "不锈钢", "0.7mm", "T001", "A003", "60kg"],
]
# 只填充前3行
for row in range(3):
for col, value in enumerate(record_data[row]):
self.record_table.setItem(row + 1, col + 1, self.create_cell_item(value))
# 设置合计行
self.record_table.setItem(13, 0, self.create_header_item("合计"))
# 轴数
self.record_table.setItem(13, 3, self.create_header_item("轴数"))
self.record_table.setItem(13, 4, self.create_cell_item("0"))
# 重量
self.record_table.setItem(13, 5, self.create_header_item("重量"))
self.record_table.setItem(13, 6, self.create_cell_item("0.0"))
def set_inspection_columns(self, columns, headers=None):
"""设置检验列数和标题
@ -621,6 +550,9 @@ class MainWindowUI(QMainWindow):
columns: 检验列数量
headers: 检验列标题列表如果为None则使用默认标题
"""
# 确保列数在1-6之间
columns = max(1, min(6, columns))
# 保存旧的列数
old_column_count = self.process_table.columnCount()
@ -636,18 +568,30 @@ class MainWindowUI(QMainWindow):
if item_r1:
del item_r1
# 清除所有单元格合并
for row in range(2):
for col in range(old_column_count):
try:
self.process_table.setSpan(row, col, 1, 1)
except:
pass # 忽略错误,可能有些单元格没有合并
# 更新检验列数
self.inspection_columns = columns
# 更新检验标题
if headers is not None and len(headers) >= columns:
self.inspection_headers = headers
self.inspection_headers = headers[:columns] # 只使用前N个标题
elif len(self.inspection_headers) < columns:
# 如果当前标题不足,扩展标题列表
current_len = len(self.inspection_headers)
for i in range(current_len, columns):
self.inspection_headers.append(f"检验项{i+1}")
# 截断多余的标题
if len(self.inspection_headers) > columns:
self.inspection_headers = self.inspection_headers[:columns]
# 计算总列数
total_columns = 2 + self.inspection_columns + 2 # 上料2列 + 检验N列 + 包装2列
self.process_table.setColumnCount(total_columns)
@ -657,9 +601,6 @@ class MainWindowUI(QMainWindow):
# 重新创建表头
self.create_process_table_headers()
# 重新填充数据
self.fill_process_table_cells()
def create_process_table_headers(self):
"""创建微丝产线表格的表头,实现合并单元格"""
@ -680,7 +621,7 @@ class MainWindowUI(QMainWindow):
# 第二行:列标题
# 上料区域列标题
material_headers = ["序号", "序工"]
material_headers = ["序号", ""]
for col, header in enumerate(material_headers):
self.process_table.setItem(1, col, self.create_header_item(header))
@ -703,7 +644,7 @@ class MainWindowUI(QMainWindow):
"""设置微丝产线表格的列宽 - 支持动态配置检验列"""
# 上料区域列宽
self.process_table.setColumnWidth(0, 70) # 序号
self.process_table.setColumnWidth(1, 190) # 工序工
self.process_table.setColumnWidth(1, 190) # 工
# 检验区域列宽
for i in range(self.inspection_columns):
@ -714,40 +655,41 @@ class MainWindowUI(QMainWindow):
self.process_table.setColumnWidth(packaging_start_col, 140) # 贴标
self.process_table.setColumnWidth(packaging_start_col + 1, 140) # 称重
def create_process_table_headers(self):
"""创建微丝产线表格的表头,实现合并单元格"""
# 第一行:上料、检验、包装标题区域
# 上料区域2列
self.process_table.setSpan(0, 0, 1, 2)
self.process_table.setItem(0, 0, self.create_header_item("上料"))
# 检验区域(动态列数)
self.process_table.setSpan(0, 2, 1, self.inspection_columns)
self.process_table.setItem(0, 2, self.create_header_item("检验"))
# 包装区域2列
packaging_start_col = 2 + self.inspection_columns
self.process_table.setSpan(0, packaging_start_col, 1, 2)
self.process_table.setItem(0, packaging_start_col, self.create_header_item("包装"))
# 第二行:列标题
# 上料区域列标题
material_headers = ["序号", "工序工程"]
for col, header in enumerate(material_headers):
self.process_table.setItem(1, col, self.create_header_item(header))
# 检验区域列标题 - 可动态配置
for i in range(self.inspection_columns):
header_text = ""
if i < len(self.inspection_headers):
header_text = self.inspection_headers[i]
else:
header_text = f"检验项{i+1}" # 如果没有定义足够的标题,使用默认标题
self.process_table.setItem(1, 2 + i, self.create_header_item(header_text))
# 包装区域列标题
packaging_headers = ["贴标", "称重"]
for i, header in enumerate(packaging_headers):
self.process_table.setItem(1, packaging_start_col + i, self.create_header_item(header))
# 删除这个重复的方法,下面的是重复定义
# def create_process_table_headers(self):
# """创建微丝产线表格的表头,实现合并单元格"""
# # 第一行:上料、检验、包装标题区域
#
# # 上料区域2列
# self.process_table.setSpan(0, 0, 1, 2)
# self.process_table.setItem(0, 0, self.create_header_item("上料"))
#
# # 检验区域(动态列数)
# self.process_table.setSpan(0, 2, 1, self.inspection_columns)
# self.process_table.setItem(0, 2, self.create_header_item("检验"))
#
# # 包装区域2列
# packaging_start_col = 2 + self.inspection_columns
# self.process_table.setSpan(0, packaging_start_col, 1, 2)
# self.process_table.setItem(0, packaging_start_col, self.create_header_item("包装"))
#
# # 第二行:列标题
# # 上料区域列标题
# material_headers = ["序号", "工序工程"]
# for col, header in enumerate(material_headers):
# self.process_table.setItem(1, col, self.create_header_item(header))
#
# # 检验区域列标题 - 可动态配置
# for i in range(self.inspection_columns):
# header_text = ""
# if i < len(self.inspection_headers):
# header_text = self.inspection_headers[i]
# else:
# header_text = f"检验项{i+1}" # 如果没有定义足够的标题,使用默认标题
#
# self.process_table.setItem(1, 2 + i, self.create_header_item(header_text))
#
# # 包装区域列标题
# packaging_headers = ["贴标", "称重"]
# for i, header in enumerate(packaging_headers):
# self.process_table.setItem(1, packaging_start_col + i, self.create_header_item(header))

View File

@ -36,6 +36,7 @@ class SettingsUI(QWidget):
# 创建各个选项卡
self.create_camera_tab()
self.create_database_tab()
self.create_inspection_tab()
self.create_plc_tab()
self.create_push_tab()
self.create_auth_tab()
@ -293,6 +294,24 @@ class SettingsUI(QWidget):
self.tab_widget.addTab(self.database_tab, "数据源设置")
def create_inspection_tab(self):
"""创建检验配置选项卡"""
# 检验配置选项卡
self.inspection_tab = QWidget()
self.inspection_layout = QVBoxLayout(self.inspection_tab)
self.inspection_layout.setContentsMargins(0, 0, 0, 0)
self.inspection_layout.setSpacing(0)
# 添加一个临时提示标签表示此处将由InspectionSettingsWidget替换
self.inspection_placeholder = QLabel("正在加载检验配置...")
self.inspection_placeholder.setFont(self.normal_font)
self.inspection_placeholder.setAlignment(Qt.AlignCenter)
self.inspection_placeholder.setStyleSheet("color: #888888; padding: 20px;")
self.inspection_layout.addWidget(self.inspection_placeholder)
# 添加到选项卡
self.tab_widget.addTab(self.inspection_tab, "检验配置")
def create_plc_tab(self):
# PLC设置选项卡
self.plc_tab = QWidget()

View File

@ -1,44 +1,62 @@
from sql_utils import SQLUtils
from utils.sql_utils import SQLUtils
import datetime
import os
import logging
def init_database():
db = SQLUtils('sqlite', database='db/jtDB.db')
# 创建用户表
create_table_sql = """
CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
create_time TIMESTAMP NOT NULL,
create_by VARCHAR(50) NOT NULL,
update_time TIMESTAMP,
update_by VARCHAR(50),
is_deleted BOOLEAN DEFAULT FALSE
);
"""
# 获取当前时间
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 插入系统用户
insert_system_user_sql = """
INSERT OR IGNORE INTO user (
username, password, create_time, create_by, is_deleted
) VALUES (
'system', '123456', ?, 'system', FALSE
);
"""
try:
db.begin_transaction()
db.execute_query(create_table_sql)
# 创建用户表
create_user_table_sql = """
CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL,
create_time TIMESTAMP NOT NULL,
create_by VARCHAR(50) NOT NULL,
update_time TIMESTAMP,
update_by VARCHAR(50),
is_deleted BOOLEAN DEFAULT FALSE
);
"""
db.execute_query(create_user_table_sql)
# 获取当前时间
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 插入系统用户
insert_system_user_sql = """
INSERT OR IGNORE INTO user (
username, password, create_time, create_by, is_deleted
) VALUES (
'system', '123456', ?, 'system', FALSE
);
"""
db.execute_query(insert_system_user_sql, (current_time,))
# 检查是否存在schema.sql文件如果存在则执行其中的SQL
schema_file = 'db/schema.sql'
if os.path.exists(schema_file):
with open(schema_file, 'r', encoding='utf-8') as f:
schema_sql = f.read()
# 按语句分割并执行SQL
statements = schema_sql.split(';')
for statement in statements:
statement = statement.strip()
if statement: # 跳过空语句
db.execute_query(statement)
logging.info("已执行schema.sql中的数据库初始化脚本")
db.commit_transaction()
print("Database initialized successfully!")
logging.info("数据库初始化成功!")
except Exception as e:
db.rollback_transaction()
print(f"Error initializing database: {str(e)}")
logging.error(f"数据库初始化失败: {str(e)}")
finally:
db.close()

View File

@ -0,0 +1,155 @@
import logging
from dao.inspection_dao import InspectionDAO
class InspectionConfigManager:
"""检验配置管理器,用于管理检验项目配置"""
_instance = None
@classmethod
def get_instance(cls):
"""获取单例实例"""
if cls._instance is None:
cls._instance = InspectionConfigManager()
return cls._instance
def __init__(self):
"""初始化检验配置管理器"""
self.dao = InspectionDAO()
self.configs = []
self.reload_configs()
def reload_configs(self):
"""重新加载检验配置"""
try:
self.configs = self.dao.get_all_inspection_configs(include_disabled=True)
logging.info(f"已加载{len(self.configs)}个检验项目配置")
return True
except Exception as e:
logging.error(f"加载检验配置失败: {str(e)}")
return False
def get_configs(self, include_disabled=False):
"""获取检验配置列表
Args:
include_disabled: 是否包含禁用的项目
Returns:
list: 检验配置列表
"""
if include_disabled:
return self.configs
else:
return [config for config in self.configs if config['enabled']]
def get_enabled_configs(self):
"""获取已启用的检验配置列表
Returns:
list: 已启用的检验配置列表
"""
return self.get_configs(include_disabled=False)
def get_enabled_count(self):
"""获取已启用的检验项目数量
Returns:
int: 已启用的检验项目数量
"""
return len(self.get_enabled_configs())
def get_config_by_position(self, position):
"""根据位置获取检验配置
Args:
position: 位置序号 (1-6)
Returns:
dict: 检验配置未找到则返回None
"""
for config in self.configs:
if config['position'] == position:
return config
return None
def toggle_config(self, position, enabled, username='system'):
"""启用或禁用检验配置
Args:
position: 位置序号 (1-6)
enabled: 是否启用
username: 操作用户
Returns:
bool: 操作是否成功
"""
result = self.dao.toggle_inspection_config(position, enabled, username)
if result:
self.reload_configs()
return result
def update_config(self, config_id, data, username='system'):
"""更新检验配置
Args:
config_id: 配置ID
data: 更新数据
username: 操作用户
Returns:
bool: 更新是否成功
"""
result = self.dao.update_inspection_config(config_id, data, username)
if result:
self.reload_configs()
return result
def get_inspection_headers(self):
"""获取检验表头用于UI显示
Returns:
list: 检验表头列表
"""
enabled_configs = self.get_enabled_configs()
headers = []
# 按位置排序
enabled_configs.sort(key=lambda x: x['position'])
for config in enabled_configs:
headers.append(config['display_name'])
return headers
def get_inspection_column_count(self):
"""获取检验列数量
Returns:
int: 检验列数量
"""
return len(self.get_enabled_configs())
def save_inspection_data(self, order_id, data, username='system'):
"""保存检验数据
Args:
order_id: 工程号
data: 检验数据列表
username: 操作用户
Returns:
bool: 保存是否成功
"""
return self.dao.save_inspection_data(order_id, data, username)
def get_inspection_data(self, order_id):
"""获取检验数据
Args:
order_id: 工程号
Returns:
list: 检验数据列表
"""
return self.dao.get_inspection_data_by_order(order_id)

View File

@ -0,0 +1,384 @@
import logging
import json
from PySide6.QtWidgets import QMessageBox, QLabel
from PySide6.QtCore import QObject, Signal
from PySide6.QtCore import Qt
from ui.inspection_settings_ui import InspectionSettingsUI
from utils.inspection_config_manager import InspectionConfigManager
from dao.inspection_dao import InspectionDAO
class InspectionSettingsWidget(InspectionSettingsUI):
"""检验设置部件"""
# 定义信号
signal_configs_changed = Signal() # 配置变更信号
def __init__(self, parent=None):
super().__init__(parent)
self.parent = parent
# 添加一个明显的标签,方便测试
self.test_label = QLabel("检验配置已加载", self)
self.test_label.setStyleSheet("color: green; font-size: 16px; font-weight: bold; background-color: #e0f7e0; padding: 5px; border-radius: 5px;")
self.test_label.setAlignment(Qt.AlignCenter)
self.main_layout.insertWidget(0, self.test_label)
# 初始化检验配置管理器
self.inspection_manager = InspectionConfigManager.get_instance()
# 保存配置ID
self.config_ids = [None] * 6
# 连接信号和槽
self.connect_signals()
# 加载配置
self.load_configs()
def connect_signals(self):
"""连接信号和槽"""
# 保存按钮
self.save_button.clicked.connect(self.save_configs)
# 重置按钮
self.reset_button.clicked.connect(self.load_configs)
# 数据类型下拉框
for i in range(6):
position = i + 1
combo = self.findChild(QObject, f"data_type_combo_{position}")
if combo:
combo.currentIndexChanged.connect(lambda idx, pos=position: self.update_form_by_data_type(pos))
def load_configs(self):
"""加载检验配置"""
try:
# 设置表单禁用,避免加载过程中的错误操作
self.set_form_enabled(False)
# 重新加载配置
self.inspection_manager.reload_configs()
# 获取所有配置(包括禁用的)
configs = self.inspection_manager.get_configs(include_disabled=True)
# 添加详细日志用于调试
logging.info(f"加载检验配置成功,共 {len(configs)} 项: {[c.get('name', 'unknown') for c in configs]}")
self.test_label.setText(f"检验配置已加载({len(configs)}项)")
# 清空当前配置ID
self.config_ids = [None] * 6
# 按位置加载配置
for config in configs:
position = config.get('position')
if 1 <= position <= 6:
self.config_ids[position - 1] = config.get('id')
self.load_config_to_form(position, config)
# 恢复表单可用
self.set_form_enabled(True)
logging.info("已加载检验配置")
except Exception as e:
logging.error(f"加载检验配置失败: {str(e)}")
self.test_label.setText(f"加载检验配置失败: {str(e)}")
self.test_label.setStyleSheet("color: red; font-size: 16px; font-weight: bold; background-color: #ffe0e0; padding: 5px; border-radius: 5px;")
QMessageBox.critical(self, "错误", f"加载检验配置失败: {str(e)}")
# 恢复表单可用
self.set_form_enabled(True)
def load_config_to_form(self, position, config):
"""将配置加载到表单
Args:
position: 位置序号 (1-6)
config: 配置数据
"""
# 获取分组
group = self.config_groups[position - 1]
# 设置启用状态
group.setChecked(config.get('enabled', False))
# 设置表单值
# 名称
name_input = self.findChild(QObject, f"name_input_{position}")
if name_input:
name_input.setText(config.get('name', ''))
# 显示名称
display_name_input = self.findChild(QObject, f"display_name_input_{position}")
if display_name_input:
display_name_input.setText(config.get('display_name', ''))
# 数据类型
data_type_combo = self.findChild(QObject, f"data_type_combo_{position}")
if data_type_combo:
data_type = config.get('data_type', 'text')
index = data_type_combo.findData(data_type)
if index >= 0:
data_type_combo.setCurrentIndex(index)
# 单位
unit_input = self.findChild(QObject, f"unit_input_{position}")
if unit_input:
unit_input.setText(config.get('unit', ''))
# 最小值
min_value_spin = self.findChild(QObject, f"min_value_spin_{position}")
if min_value_spin:
min_value = config.get('min_value')
if min_value is not None:
min_value_spin.setValue(float(min_value))
else:
min_value_spin.setValue(0)
# 最大值
max_value_spin = self.findChild(QObject, f"max_value_spin_{position}")
if max_value_spin:
max_value = config.get('max_value')
if max_value is not None:
max_value_spin.setValue(float(max_value))
else:
max_value_spin.setValue(100)
# 枚举值
enum_values_input = self.findChild(QObject, f"enum_values_input_{position}")
if enum_values_input:
enum_values = config.get('enum_values')
if enum_values:
if isinstance(enum_values, list):
enum_values_input.setText(','.join(enum_values))
elif isinstance(enum_values, str):
try:
values = json.loads(enum_values)
if isinstance(values, list):
enum_values_input.setText(','.join(values))
else:
enum_values_input.setText(str(enum_values))
except:
enum_values_input.setText(str(enum_values))
else:
enum_values_input.setText('')
# 是否必填
required_check = self.findChild(QObject, f"required_check_{position}")
if required_check:
required_check.setChecked(config.get('required', False))
# 根据数据类型更新表单
self.update_form_by_data_type(position)
def update_form_by_data_type(self, position):
"""根据数据类型更新表单项的可用性
Args:
position: 位置序号 (1-6)
"""
# 获取数据类型
data_type_combo = self.findChild(QObject, f"data_type_combo_{position}")
if not data_type_combo:
return
data_type = data_type_combo.currentData()
# 获取相关控件
unit_input = self.findChild(QObject, f"unit_input_{position}")
min_value_spin = self.findChild(QObject, f"min_value_spin_{position}")
max_value_spin = self.findChild(QObject, f"max_value_spin_{position}")
enum_values_input = self.findChild(QObject, f"enum_values_input_{position}")
# 根据数据类型设置控件可用性
if data_type == 'number':
# 数值类型:启用单位、最小值、最大值,禁用枚举值
if unit_input:
unit_input.setEnabled(True)
if min_value_spin:
min_value_spin.setEnabled(True)
if max_value_spin:
max_value_spin.setEnabled(True)
if enum_values_input:
enum_values_input.setEnabled(False)
enum_values_input.setText('')
elif data_type == 'enum':
# 枚举类型:禁用单位、最小值、最大值,启用枚举值
if unit_input:
unit_input.setEnabled(False)
unit_input.setText('')
if min_value_spin:
min_value_spin.setEnabled(False)
min_value_spin.setValue(0)
if max_value_spin:
max_value_spin.setEnabled(False)
max_value_spin.setValue(0)
if enum_values_input:
enum_values_input.setEnabled(True)
else: # text 或其他
# 文本类型:禁用所有特殊字段
if unit_input:
unit_input.setEnabled(False)
unit_input.setText('')
if min_value_spin:
min_value_spin.setEnabled(False)
min_value_spin.setValue(0)
if max_value_spin:
max_value_spin.setEnabled(False)
max_value_spin.setValue(0)
if enum_values_input:
enum_values_input.setEnabled(False)
enum_values_input.setText('')
def get_form_data(self, position):
"""获取表单数据
Args:
position: 位置序号 (1-6)
Returns:
dict: 表单数据
"""
# 获取分组
group = self.config_groups[position - 1]
# 获取控件
name_input = self.findChild(QObject, f"name_input_{position}")
display_name_input = self.findChild(QObject, f"display_name_input_{position}")
data_type_combo = self.findChild(QObject, f"data_type_combo_{position}")
unit_input = self.findChild(QObject, f"unit_input_{position}")
min_value_spin = self.findChild(QObject, f"min_value_spin_{position}")
max_value_spin = self.findChild(QObject, f"max_value_spin_{position}")
enum_values_input = self.findChild(QObject, f"enum_values_input_{position}")
required_check = self.findChild(QObject, f"required_check_{position}")
# 获取数据
enabled = group.isChecked()
name = name_input.text() if name_input else ''
display_name = display_name_input.text() if display_name_input else ''
data_type = data_type_combo.currentData() if data_type_combo else 'text'
unit = unit_input.text() if unit_input and data_type == 'number' else ''
min_value = min_value_spin.value() if min_value_spin and data_type == 'number' else None
max_value = max_value_spin.value() if max_value_spin and data_type == 'number' else None
# 处理枚举值
enum_values = None
if enum_values_input and data_type == 'enum':
enum_text = enum_values_input.text().strip()
if enum_text:
enum_values = [v.strip() for v in enum_text.split(',') if v.strip()]
required = required_check.isChecked() if required_check else False
# 构建数据
data = {
'position': position,
'name': name,
'display_name': display_name,
'enabled': enabled,
'data_type': data_type,
'required': required,
'sort_order': position
}
# 根据数据类型添加特定字段
if data_type == 'number':
data['min_value'] = min_value
data['max_value'] = max_value
data['unit'] = unit
elif data_type == 'enum':
data['enum_values'] = enum_values
return data
def validate_form(self):
"""验证表单数据
Returns:
bool: 验证是否通过
"""
# 检查是否至少启用一个检验项
enabled_count = 0
for group in self.config_groups:
if group.isChecked():
enabled_count += 1
if enabled_count == 0:
QMessageBox.warning(self, "验证失败", "请至少启用一个检验项目!")
return False
# 检查每个启用的检验项是否填写了必要信息
for i in range(6):
position = i + 1
group = self.config_groups[i]
if group.isChecked():
# 获取控件
name_input = self.findChild(QObject, f"name_input_{position}")
display_name_input = self.findChild(QObject, f"display_name_input_{position}")
data_type_combo = self.findChild(QObject, f"data_type_combo_{position}")
enum_values_input = self.findChild(QObject, f"enum_values_input_{position}")
# 验证名称和显示名称
if not name_input.text().strip():
QMessageBox.warning(self, "验证失败", f"检验项目 {position} 的项目名称不能为空!")
return False
if not display_name_input.text().strip():
QMessageBox.warning(self, "验证失败", f"检验项目 {position} 的显示名称不能为空!")
return False
# 验证枚举类型的枚举值
data_type = data_type_combo.currentData()
if data_type == 'enum' and not enum_values_input.text().strip():
QMessageBox.warning(self, "验证失败", f"检验项目 {position} 是枚举类型,枚举值不能为空!")
return False
return True
def save_configs(self):
"""保存检验配置"""
try:
# 验证表单
if not self.validate_form():
return
# 设置表单禁用,避免保存过程中的错误操作
self.set_form_enabled(False)
# 收集更新数据
for i in range(6):
position = i + 1
config_id = self.config_ids[i]
# 获取表单数据
data = self.get_form_data(position)
# 检查配置ID是否存在
if config_id is not None:
# 更新已有配置
result = self.inspection_manager.update_config(config_id, data)
if not result:
raise Exception(f"更新检验项目 {position} 失败")
else:
# 新建配置不应该进入这个分支因为默认已经创建了6个配置
logging.warning(f"检验项目 {position} 不存在,需要在初始化时创建")
# 重新加载配置
self.inspection_manager.reload_configs()
# 恢复表单可用
self.set_form_enabled(True)
# 显示成功消息
QMessageBox.information(self, "保存成功", "检验配置已保存成功!")
# 发送配置变更信号
self.signal_configs_changed.emit()
logging.info("已保存检验配置")
except Exception as e:
logging.error(f"保存检验配置失败: {str(e)}")
QMessageBox.critical(self, "错误", f"保存检验配置失败: {str(e)}")
# 恢复表单可用
self.set_form_enabled(True)

View File

@ -16,6 +16,9 @@ from ui.main_window_ui import MainWindowUI
from widgets.camera_display_widget import CameraDisplayWidget
from widgets.camera_settings_widget import CameraSettingsWidget
# 导入检验配置管理器
from utils.inspection_config_manager import InspectionConfigManager
class MainWindow(MainWindowUI):
"""主窗口"""
@ -36,6 +39,9 @@ class MainWindow(MainWindowUI):
self.config = self.load_config()
self.camera_enabled = self.config.get('camera', {}).get('enabled', False)
# 初始化检验配置管理器
self.inspection_manager = InspectionConfigManager.get_instance()
# 只有在相机启用时创建相机显示组件
if self.camera_enabled:
# 创建相机显示组件并添加到上料区
@ -74,8 +80,8 @@ class MainWindow(MainWindowUI):
# 初始化数据
self.initialize_data()
# 配置检验列为5列
self.set_inspection_columns(5)
# 配置检验列 - 使用检验配置管理器获取启用的列数和标题
self.update_inspection_columns()
logging.info(f"主窗口已创建,用户: {user_name}")
@ -96,6 +102,9 @@ class MainWindow(MainWindowUI):
self.main_action.triggered.connect(self.show_main_page)
self.settings_action.triggered.connect(self.show_settings_page)
# 工程号输入框回车事件
self.order_edit.returnPressed.connect(self.handle_order_enter)
# 连接按钮事件
self.input_button.clicked.connect(self.handle_input)
self.output_button.clicked.connect(self.handle_output)
@ -134,9 +143,36 @@ class MainWindow(MainWindowUI):
item.setTextAlignment(Qt.AlignCenter) # 设置文本居中对齐
self.task_table.setItem(2, col, item)
def update_inspection_columns(self):
"""更新检验列配置 - 使用检验配置管理器获取启用的列数和标题"""
try:
# 获取已启用的检验配置
enabled_configs = self.inspection_manager.get_enabled_configs()
# 获取启用的列数
column_count = len(enabled_configs)
if column_count == 0:
# 如果没有启用的列,至少显示一列
column_count = 1
headers = ["检验项"]
else:
# 如果有启用的列,使用配置的标题
headers = [config['display_name'] for config in enabled_configs]
# 设置检验列
self.set_inspection_columns(column_count, headers)
logging.info(f"已更新检验列配置:{column_count}列, 标题: {headers}")
except Exception as e:
logging.error(f"更新检验列配置失败: {str(e)}")
# 如果更新失败,使用默认配置
self.set_inspection_columns(1, ["检验项"])
def show_main_page(self):
self.stacked_widget.setCurrentWidget(self.central_widget)
# 更新检验列配置
self.update_inspection_columns()
# 只有在相机启用时处理相机显示
if self.camera_enabled and hasattr(self, 'camera_display'):
# 如果相机已连接,直接开始显示相机画面
@ -147,24 +183,15 @@ class MainWindow(MainWindowUI):
logging.info("显示主页面")
def show_settings_page(self):
# 只有在相机启用时才创建相机设置组件
if self.camera_enabled:
# 延迟创建相机设置组件
if self.camera_settings is None:
self.camera_settings = CameraSettingsWidget()
# 连接相机设置信号
self.camera_settings.signal_camera_connection.connect(self.handle_camera_connection)
self.camera_settings.signal_camera_params_changed.connect(self.handle_camera_params_changed)
self.camera_settings.signal_camera_error.connect(self.handle_camera_error)
# 添加到堆叠部件
self.stacked_widget.addWidget(self.camera_settings)
# 切换到设置页面
self.stacked_widget.setCurrentWidget(self.camera_settings)
else:
# 如果相机未启用,显示提示信息
QMessageBox.information(self, "设置", "相机功能已在配置文件中禁用,无法打开相机设置页面。")
"""显示设置页面"""
# 延迟创建设置组件
if not hasattr(self, 'settings_widget'):
from widgets.settings_widget import SettingsWidget
self.settings_widget = SettingsWidget(self)
self.stacked_widget.addWidget(self.settings_widget)
# 切换到设置页面
self.stacked_widget.setCurrentWidget(self.settings_widget)
logging.info("显示设置页面")
def handle_input(self):
@ -245,4 +272,21 @@ class MainWindow(MainWindowUI):
self.camera_display.stop_display()
# 接受关闭事件
event.accept()
event.accept()
def handle_order_enter(self):
"""处理工程号输入框按下回车事件"""
logging.info("工程号输入框按下回车事件")
# 获取当前输入的工程号
order_text = self.order_edit.text().strip()
if order_text:
logging.info(f"输入的工程号: {order_text}")
QMessageBox.information(self, "工程号确认", f"您输入的工程号是: {order_text}")
# 这里可以添加其他工程号处理逻辑
else:
logging.warning("工程号为空")
QMessageBox.warning(self, "输入提示", "请输入有效的工程号")
# 处理完后可以清除焦点,让输入框失去焦点
self.central_widget.setFocus()

View File

@ -1,19 +1,44 @@
from PySide6.QtWidgets import QMessageBox
from PySide6.QtWidgets import QMessageBox, QVBoxLayout
import logging
from ui.settings_ui import SettingsUI
from utils.sql_utils import SQLUtils
from widgets.inspection_settings_widget import InspectionSettingsWidget
class SettingsWidget(SettingsUI):
def __init__(self, parent=None):
super().__init__(parent)
self.parent = parent
logging.info("正在初始化SettingsWidget")
# 创建检验设置部件
logging.info("创建InspectionSettingsWidget实例")
self.inspection_settings = InspectionSettingsWidget()
# 移除临时占位符标签并添加检验设置部件
if hasattr(self, 'inspection_placeholder'):
logging.info("移除临时占位符")
self.inspection_layout.removeWidget(self.inspection_placeholder)
self.inspection_placeholder.hide()
self.inspection_placeholder.deleteLater()
else:
logging.warning("未找到临时占位符标签")
# 检查布局是否可用
if hasattr(self, 'inspection_layout'):
logging.info("添加检验设置部件到布局")
self.inspection_layout.addWidget(self.inspection_settings)
else:
logging.error("无法找到inspection_layout布局")
# 连接信号和槽
self.connect_signals()
# 初始化数据库类型UI状态
self.update_db_ui_state()
logging.info("SettingsWidget初始化完成")
def connect_signals(self):
# 数据库类型选择
self.sqlite_radio.toggled.connect(self.update_db_ui_state)
@ -23,6 +48,9 @@ class SettingsWidget(SettingsUI):
# 按钮动作
self.test_conn_button.clicked.connect(self.test_connection)
self.save_db_button.clicked.connect(self.save_db_settings)
# 检验配置变更信号
self.inspection_settings.signal_configs_changed.connect(self.handle_inspection_configs_changed)
def update_db_ui_state(self):
"""根据选择的数据库类型更新UI状态"""
@ -98,25 +126,18 @@ class SettingsWidget(SettingsUI):
# 创建数据库连接
db = SQLUtils(db_type, **params)
# 尝试执行简单查询
if db_type == "sqlite":
db.execute_query("SELECT sqlite_version();")
elif db_type == "pgsql":
db.execute_query("SELECT version();")
elif db_type == "mysql":
db.execute_query("SELECT version();")
# 测试连接
db.cursor.execute("SELECT 1")
result = db.fetchone()
# 关闭连接
db.close()
# 显示成功消息
QMessageBox.information(self, "连接成功", f"数据库连接测试成功!\n数据库版本: {result[0]}")
logging.info(f"数据库连接测试成功,类型: {db_type}, 版本: {result[0]}")
QMessageBox.information(self, "连接成功", "数据库连接测试成功!")
logging.info(f"数据库连接测试成功,类型: {db_type}")
except Exception as e:
# 显示错误消息
QMessageBox.critical(self, "连接失败", f"数据库连接测试失败!\n错误: {str(e)}")
QMessageBox.critical(self, "连接失败", f"数据库连接测试失败!\n\n错误: {str(e)}")
logging.error(f"数据库连接测试失败,类型: {db_type}, 错误: {str(e)}")
def save_db_settings(self):
@ -137,4 +158,11 @@ class SettingsWidget(SettingsUI):
settings_info += f"说明: {desc}"
QMessageBox.information(self, "设置已保存", f"数据库设置已保存!\n\n{settings_info}")
logging.info(f"数据库设置已保存,类型: {db_type}")
logging.info(f"数据库设置已保存,类型: {db_type}")
def handle_inspection_configs_changed(self):
"""处理检验配置变更"""
logging.info("检验配置已更新")
# 如果有父窗口,通知父窗口更新检验配置
if self.parent and hasattr(self.parent, 'update_inspection_columns'):
self.parent.update_inspection_columns()