增强InspectionDAO以支持包装记录的保存和查询功能,更新主窗口以加载和显示已完成的检验数据,优化表格以适应新数据结构,添加包装记录统计功能。

This commit is contained in:
zhu-mengmeng 2025-06-10 13:37:43 +08:00
parent 703f03f0bb
commit b51848e2af
5 changed files with 576 additions and 174 deletions

View File

@ -258,7 +258,7 @@ class InspectionDAO:
""" """
update_params = ( update_params = (
config_id, value, status, remark, config_id, value, status, remark,
current_time, username, existing[0] current_time, username, tray_id, existing[0]
) )
self.db.cursor.execute(update_sql, update_params) self.db.cursor.execute(update_sql, update_params)
else: else:
@ -282,22 +282,42 @@ class InspectionDAO:
logging.error(f"保存检验数据失败: {str(e)}") logging.error(f"保存检验数据失败: {str(e)}")
return False return False
def get_inspection_data_unfinished(self, tray_id): def get_inspection_data_unfinished(self, tray_id):
"""获取未完成的检验数据 """获取未完成的检验数据,通过是否贴标来判断
Returns: Returns:
list: 未完成的检验数据列表 list: 未完成的检验数据列表
""" """
try: try:
sql = """ # 先获取所有没有贴标的工程号
sql_orders = """
SELECT DISTINCT d.order_id
FROM inspection_data d
WHERE d.is_deleted = FALSE AND d.tray_id = ?
AND d.position = 11 AND COALESCE(d.value,'') = ''
"""
params = (tray_id,)
self.db.cursor.execute(sql_orders, params)
orders = self.db.cursor.fetchall()
if not orders:
return []
# 构建IN子句的参数
order_ids = [order[0] for order in orders]
placeholders = ','.join(['?' for _ in order_ids])
# 获取这些工程号的所有检验数据
sql = f"""
SELECT d.id, d.order_id, d.position, d.config_id, d.value, d.status, d.remark, SELECT d.id, d.order_id, d.position, d.config_id, d.value, d.status, d.remark,
c.name, c.display_name, c.data_type, c.unit c.name, c.display_name, c.data_type, c.unit
FROM inspection_data d FROM inspection_data d
JOIN inspection_config c ON d.config_id = c.id LEFT JOIN inspection_config c ON d.config_id = c.id
WHERE d.is_deleted = FALSE AND d.tray_id = ? WHERE d.is_deleted = FALSE AND d.tray_id = ?
AND order_id IN (SELECT distinct order_id FROM inspection_data WHERE status != 'pass') AND d.order_id IN ({placeholders})
ORDER BY d.order_id, d.position ORDER BY d.order_id, d.position
""" """
params = (tray_id,)
params = [tray_id] + order_ids
self.db.cursor.execute(sql, params) self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall() results = self.db.cursor.fetchall()
@ -336,7 +356,7 @@ class InspectionDAO:
SELECT d.id, d.position, d.config_id, d.value, d.status, d.remark, SELECT d.id, d.position, d.config_id, d.value, d.status, d.remark,
c.name, c.display_name, c.data_type, c.unit c.name, c.display_name, c.data_type, c.unit
FROM inspection_data d FROM inspection_data d
JOIN inspection_config c ON d.config_id = c.id LEFT JOIN inspection_config c ON d.config_id = c.id
WHERE d.order_id = ? AND d.is_deleted = FALSE AND d.tray_id = ? WHERE d.order_id = ? AND d.is_deleted = FALSE AND d.tray_id = ?
ORDER BY d.position ORDER BY d.position
""" """
@ -365,3 +385,83 @@ class InspectionDAO:
except Exception as e: except Exception as e:
logging.error(f"获取检验数据失败: {str(e)}") logging.error(f"获取检验数据失败: {str(e)}")
return [] return []
def get_inspection_unfinished_count(self, order_id, tray_id):
"""根据托盘号和工程号获取未完成检验的数量,如果存在一个未完成则都算未完成
Args:
order_id: 工程号
tray_id: 托盘号
Returns:
tuple: 工程号, 托盘号, 未完成检验的数量
"""
try:
sql ="""
select order_id, tray_id, count(case when status != 'pass' then null else status end) as unfinished_count
from inspection_data
where is_deleted = 0 and order_id = ? and tray_id = ?
group by order_id, tray_id
"""
params = (order_id, tray_id)
self.db.cursor.execute(sql, params)
result = self.db.cursor.fetchone()
if result:
return result[0], result[1], result[2]
return order_id, tray_id, 0
except Exception as e:
logging.error(f"获取未完成检验数据失败: {str(e)}")
return order_id, tray_id, 0
def get_package_record(self, tray_id):
"""根据托盘号获取包装记录
Args:
tray_id: 托盘号
Returns:
list: 包装记录列表
"""
try:
sql = """
SELECT order_id,
COALESCE(material, '') as material,
COALESCE(spec, '') as spec,
tray_id,
COALESCE(axis_package_id, '') as axis_package_id,
COALESCE(weight, 0) as weight,
STRFTIME('%Y-%m-%d %H:%M:%S', pack_time) as pack_time
FROM inspection_pack_data
WHERE tray_id = ?
AND is_deleted = FALSE
ORDER BY pack_time DESC
"""
params = (tray_id,)
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
return results
except Exception as e:
logging.error(f"获取包装记录失败: {str(e)}")
return []
def save_package_record(self, order_id, tray_id, label_value, weight_value, finish_time):
"""保存包装记录
Args:
order_id: 工程号
tray_id: 托盘号
label_value: 标签值
weight_value: 重量值
finish_time: 完成时间
"""
# TODO调用接口获取到工程号对应的其他信息比如材质规格后续完成
try:
sql = """
INSERT INTO inspection_pack_data (order_id, tray_id, axis_package_id, weight, pack_time, create_time, create_by, update_time, update_by, is_deleted)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
params = (order_id, tray_id, label_value, weight_value, finish_time, datetime.now(), 'system', datetime.now(), 'system', False)
self.db.cursor.execute(sql, params)
self.db.conn.commit()
except Exception as e:
logging.error(f"保存包装记录失败: {str(e)}")
self.db.conn.rollback()

Binary file not shown.

View File

@ -53,3 +53,26 @@ INSERT OR IGNORE INTO inspection_config (
UPDATE inspection_config UPDATE inspection_config
SET enum_values = '["合格", "不合格", "需要重检"]' SET enum_values = '["合格", "不合格", "需要重检"]'
WHERE name = 'appearance'; WHERE name = 'appearance';
--
drop table if exists inspection_pack_data;
create table if not exists inspection_pack_data
(
--
order_id VARCHAR(50),
--
material VARCHAR(50),
--
spec VARCHAR(50),
--
tray_id VARCHAR(50),
--
axis_package_id VARCHAR(50),
create_time TIMESTAMP NOT NULL,
create_by VARCHAR(50) NOT NULL,
update_time TIMESTAMP,
update_by VARCHAR(50),
is_deleted BOOLEAN
)

View File

@ -501,13 +501,13 @@ class MainWindowUI(QMainWindow):
self.record_layout.addWidget(self.record_title) self.record_layout.addWidget(self.record_title)
# 创建表格 # 创建表格
self.record_table = QTableWidget(14, 7) # 14行7列序号、订单、材质、规格、托号、轴包装号、重量 self.record_table = QTableWidget(14, 8) # 14行7列序号、订单、材质、规格、托号、轴包装号、重量
# 应用通用表格设置 # 应用通用表格设置
self.setup_table_common(self.record_table) self.setup_table_common(self.record_table)
# 设置列标题 # 设置列标题
record_headers = ["序号", "订单", "材质", "规格", "托号", "轴包装号", "重量"] record_headers = ["序号", "订单", "材质", "规格", "托号", "轴包装号", "重量", "完成时间"]
for col, header in enumerate(record_headers): for col, header in enumerate(record_headers):
self.record_table.setItem(0, col, self.create_header_item(header)) self.record_table.setItem(0, col, self.create_header_item(header))
@ -520,7 +520,7 @@ class MainWindowUI(QMainWindow):
self.record_table.setRowHeight(row, 35) self.record_table.setRowHeight(row, 35)
# 设置列宽 # 设置列宽
column_widths = [70, 220, 170, 170, 170, 170, 170] # 各列的默认宽度 column_widths = [70, 220, 160, 160, 160, 160, 160, 190] # 各列的默认宽度
for col, width in enumerate(column_widths): for col, width in enumerate(column_widths):
self.record_table.setColumnWidth(col, width) self.record_table.setColumnWidth(col, width)

View File

@ -80,18 +80,17 @@ class MainWindow(MainWindowUI):
# 默认显示主页面 # 默认显示主页面
self.stacked_widget.setCurrentIndex(0) self.stacked_widget.setCurrentIndex(0)
# 初始化数据
self.initialize_data()
# 配置检验列 - 使用检验配置管理器获取启用的列数和标题 # 配置检验列 - 使用检验配置管理器获取启用的列数和标题
self.update_inspection_columns() self.update_inspection_columns()
# 设置表格上下文菜单 # 设置表格上下文菜单
self.process_table.setContextMenuPolicy(Qt.CustomContextMenu) self.process_table.setContextMenuPolicy(Qt.CustomContextMenu)
self.process_table.customContextMenuRequested.connect(self.show_table_context_menu)
# 加载未完成的检验数据 # 加载未完成的检验数据
self.load_unfinished_inspection_data() self.load_finished_inspection_data()
# 加载已完成检验数据
self.show_pack_item()
logging.info(f"主窗口已创建,用户: {user_name}") logging.info(f"主窗口已创建,用户: {user_name}")
@ -117,8 +116,8 @@ class MainWindow(MainWindowUI):
# 托盘号输入框回车和切换事件,触发未加载数据查询 # 托盘号输入框回车和切换事件,触发未加载数据查询
# QComboBox没有returnPressed信号只有currentTextChanged和activated信号 # QComboBox没有returnPressed信号只有currentTextChanged和activated信号
self.tray_edit.currentTextChanged.connect(self.load_unfinished_inspection_data) self.tray_edit.currentTextChanged.connect(self.load_finished_inspection_data)
self.tray_edit.activated.connect(self.load_unfinished_inspection_data) # 当用户选择一项时触发 self.tray_edit.activated.connect(self.load_finished_inspection_data) # 当用户选择一项时触发
# 连接按钮事件 # 连接按钮事件
self.input_button.clicked.connect(self.handle_input) self.input_button.clicked.connect(self.handle_input)
@ -126,37 +125,16 @@ class MainWindow(MainWindowUI):
self.start_button.clicked.connect(self.handle_start) self.start_button.clicked.connect(self.handle_start)
self.stop_button.clicked.connect(self.handle_stop) self.stop_button.clicked.connect(self.handle_stop)
# 设置表格上下文菜单
self.process_table.setContextMenuPolicy(Qt.CustomContextMenu)
self.process_table.customContextMenuRequested.connect(self.show_table_context_menu)
# 只有在相机启用时连接相机信号 # 只有在相机启用时连接相机信号
if self.camera_enabled and hasattr(self, 'camera_display'): if self.camera_enabled and hasattr(self, 'camera_display'):
self.camera_display.signal_camera_status.connect(self.handle_camera_status) self.camera_display.signal_camera_status.connect(self.handle_camera_status)
def initialize_data(self): # 初始化后检查是否有已完成的记录
"""初始化界面数据""" QTimer.singleShot(1000, self.check_and_process_finished_records)
# 设置订单和批号
self.order_edit.setText("ORD-2025-001")
self.tray_edit.setCurrentText("托盘1")
# 初始化项目表格数据示例
project_data = [
["100", "50", "200", "95%"],
["3000", "1500", "6000", "92%"],
["36000", "18000", "72000", "90%"],
["120000", "60000", "240000", "91%"]
]
for row in range(4):
for col in range(0, 4): # 从第2列开始跳过项目列
item = QTableWidgetItem(project_data[row][col])
# item.setTextAlignment(Qt.AlignCenter) # 设置文本居中对齐
self.project_table.setItem(row, col, item)
# 初始化任务表格数据示例 - 注意现在表格有3行第0行是一级标题第1行是二级标题第2行是数据行
# 数据应该填充在第2行索引为2
data = ["200", "95", "0", "0"] # 分别对应:总生产数量、总生产公斤、已完成数量、已完成公斤
for col, value in enumerate(data):
item = QTableWidgetItem(value)
item.setTextAlignment(Qt.AlignCenter) # 设置文本居中对齐
self.task_table.setItem(2, col, item)
def update_inspection_columns(self): def update_inspection_columns(self):
"""更新检验列配置 - 使用检验配置管理器获取启用的列数和标题""" """更新检验列配置 - 使用检验配置管理器获取启用的列数和标题"""
@ -189,7 +167,7 @@ class MainWindow(MainWindowUI):
self.update_inspection_columns() self.update_inspection_columns()
# 加载未完成的检验数据 # 加载未完成的检验数据
self.load_unfinished_inspection_data() self.load_finished_inspection_data()
# 只有在相机启用时处理相机显示 # 只有在相机启用时处理相机显示
if self.camera_enabled and hasattr(self, 'camera_display'): if self.camera_enabled and hasattr(self, 'camera_display'):
@ -324,7 +302,13 @@ class MainWindow(MainWindowUI):
# 固定的数据起始行索引 # 固定的数据起始行索引
data_start_row = 2 # 数据从第3行开始 data_start_row = 2 # 数据从第3行开始
# 在指定行索引插入新行 # 断开单元格变更信号,避免加载过程中触发保存
try:
self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed)
except:
pass
# 在指定行索引插入新行 - 总是插入到第一个数据行
self.process_table.insertRow(data_start_row) self.process_table.insertRow(data_start_row)
# 更新序号 - 所有现有行序号+1 # 更新序号 - 所有现有行序号+1
@ -369,14 +353,7 @@ class MainWindow(MainWindowUI):
# 设置表格为可编辑状态 # 设置表格为可编辑状态
self.process_table.setEditTriggers(QTableWidget.DoubleClicked | QTableWidget.EditKeyPressed) self.process_table.setEditTriggers(QTableWidget.DoubleClicked | QTableWidget.EditKeyPressed)
# 连接单元格内容变更信号 # 重新连接单元格内容变更信号
# 断开之前的连接(如果有)
try:
self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed)
except:
pass # 如果没有连接过,会抛出异常,忽略即可
# 重新连接信号
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed) self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
# 选中新添加的行 # 选中新添加的行
@ -385,11 +362,43 @@ class MainWindow(MainWindowUI):
# 限制最大行数 # 限制最大行数
self.limit_table_rows(10) # 最多保留10行数据 self.limit_table_rows(10) # 最多保留10行数据
# 将工程号和托盘号保存到数据库,确保能够正确关联
from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO()
tray_id = self.tray_edit.currentText()
# 为每个检验位置创建一个空记录,确保工程号在数据库中存在
for config in enabled_configs:
data = [{
'position': config.get('position'),
'config_id': config.get('id'),
'value': '',
'status': '', # 默认设置为通过状态
'remark': '',
'tray_id': tray_id
}]
inspection_dao.save_inspection_data(order_id, data)
# 为贴标和称重也创建空记录
for position in [11, 12]: # 11是贴标12是称重
data = [{
'position': position,
'config_id': position,
'value': '',
'status': 'pass', # 默认设置为通过状态
'remark': '',
'tray_id': tray_id
}]
inspection_dao.save_inspection_data(order_id, data)
logging.info(f"已添加工程号 {order_id} 的新记录显示在第1条") logging.info(f"已添加工程号 {order_id} 的新记录显示在第1条")
except Exception as e: except Exception as e:
logging.error(f"添加新记录失败: {str(e)}") logging.error(f"添加新记录失败: {str(e)}")
QMessageBox.warning(self, "添加失败", f"添加新记录失败: {str(e)}") QMessageBox.warning(self, "添加失败", f"添加新记录失败: {str(e)}")
finally:
# 重新加载数据确保UI显示正确
self.load_finished_inspection_data()
def limit_table_rows(self, max_rows): def limit_table_rows(self, max_rows):
"""限制表格最大行数 """限制表格最大行数
@ -448,11 +457,6 @@ class MainWindow(MainWindowUI):
# 判断是否是检验列(非包装列) # 判断是否是检验列(非包装列)
packaging_start_col = 2 + len(enabled_configs) packaging_start_col = 2 + len(enabled_configs)
if column >= 2 and column < packaging_start_col:
# 是检验列
config_index = column - 2
if config_index < len(enabled_configs):
config = enabled_configs[config_index]
# 获取单元格内容 # 获取单元格内容
cell_item = self.process_table.item(row, column) cell_item = self.process_table.item(row, column)
@ -461,8 +465,21 @@ class MainWindow(MainWindowUI):
value = cell_item.text().strip() value = cell_item.text().strip()
# 默认设置为通过状态
status = 'pass'
# 记录当前正在处理的数据类型,用于日志输出
data_type = "检验"
if column >= 2 and column < packaging_start_col:
# 是检验列
config_index = column - 2
if config_index < len(enabled_configs):
config = enabled_configs[config_index]
data_type = config['display_name']
# 显示临时状态消息 # 显示临时状态消息
self.statusBar().showMessage(f"正在保存检验数据: {config['display_name']}={value}", 1000) self.statusBar().showMessage(f"正在保存检验数据: {data_type}={value}", 1000)
# 验证数据有效性 # 验证数据有效性
if self.validate_inspection_value(config, value): if self.validate_inspection_value(config, value):
@ -477,11 +494,34 @@ class MainWindow(MainWindowUI):
# 保存到数据库 # 保存到数据库
self.save_inspection_data(order_id, tray_id, config['position'], config['id'], value, status) self.save_inspection_data(order_id, tray_id, config['position'], config['id'], value, status)
# 触发查询, 更新页面记录回显 # 判断是否是包装列
self.load_unfinished_inspection_data() elif column == packaging_start_col:
# 贴标列
data_type = "贴标"
self.statusBar().showMessage(f"正在保存贴标数据: {value}", 1000)
# 设置单元格颜色为通过
cell_item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色
# 保存贴标数据position和config_id都是11
self.save_inspection_data(order_id, tray_id, 11, 11, value, status)
elif column == packaging_start_col + 1:
# 称重列
data_type = "称重"
self.statusBar().showMessage(f"正在保存称重数据: {value}", 1000)
# 设置单元格颜色为通过
cell_item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色
# 保存称重数据position和config_id都是12
self.save_inspection_data(order_id, tray_id, 12, 12, value, status)
# 记录详细日志
logging.info(f"处理单元格变更: 行={row}, 列={column}, 类型={data_type}, 工程号={order_id}, 值={value}, 状态={status}")
except Exception as e: except Exception as e:
logging.error(f"处理检验单元格变更失败: {str(e)}") logging.error(f"处理检验单元格变更失败: {str(e)}")
self.statusBar().showMessage(f"处理检验数据失败: {str(e)[:50]}...", 3000) self.statusBar().showMessage(f"处理检验数据失败: {str(e)[:50]}...", 3000)
finally:
# 延迟一段时间后再触发查询避免频繁刷新UI
QTimer.singleShot(1000, self.load_finished_inspection_data)
def validate_inspection_value(self, config, value): def validate_inspection_value(self, config, value):
"""验证检验值是否有效 """验证检验值是否有效
@ -494,6 +534,10 @@ class MainWindow(MainWindowUI):
bool: 是否有效 bool: 是否有效
""" """
try: try:
# 特殊处理贴标和称重数据 - 这些数据默认都是有效的
if config.get('position') in [11, 12]: # 11是贴标12是称重
return True
# 检查值是否为空 # 检查值是否为空
if not value and config.get('required', False): if not value and config.get('required', False):
return False return False
@ -504,6 +548,10 @@ class MainWindow(MainWindowUI):
if data_type == 'number': if data_type == 'number':
# 数值类型验证 # 数值类型验证
try: try:
# 如果值为空且不是必填,则视为有效
if not value and not config.get('required', False):
return True
num_value = float(value) num_value = float(value)
min_value = config.get('min_value') min_value = config.get('min_value')
max_value = config.get('max_value') max_value = config.get('max_value')
@ -522,6 +570,9 @@ class MainWindow(MainWindowUI):
# 枚举类型验证 # 枚举类型验证
enum_values = config.get('enum_values') enum_values = config.get('enum_values')
if enum_values and isinstance(enum_values, list): if enum_values and isinstance(enum_values, list):
# 如果值为空且不是必填,则视为有效
if not value and not config.get('required', False):
return True
return value in enum_values return value in enum_values
return False return False
@ -561,11 +612,19 @@ class MainWindow(MainWindowUI):
# 保存到数据库 # 保存到数据库
result = inspection_dao.save_inspection_data(order_id, data) result = inspection_dao.save_inspection_data(order_id, data)
# 判断,如果保存成功后,且当前工程号中,全部为 pass 说明该工序已经完成,需要流转到下一步,回显到包装记录中
if result: if result:
logging.info(f"已成功保存工程号 {order_id} 的检验数据,位置: {position}, 值: {value}") logging.info(f"已成功保存工程号 {order_id} 的检验数据,位置: {position}, 值: {value}")
# 显示临时状态消息 # 显示临时状态消息
self.statusBar().showMessage(f"已保存检验数据:{value}", 3000) self.statusBar().showMessage(f"已保存检验数据:{value}", 3000)
# 如果是贴标字段且有值,直接写入包装记录
if position == 11 and value:
# 直接调用加载到包装记录的方法
self.load_finished_record_to_package_record(order_id, tray_id)
logging.info(f"检测到贴标字段有值,已自动写入包装记录")
else:
# 使用延迟调用避免频繁刷新UI
QTimer.singleShot(500, self.check_and_process_finished_records)
else: else:
logging.warning(f"保存工程号 {order_id} 的检验数据失败") logging.warning(f"保存工程号 {order_id} 的检验数据失败")
# 显示错误消息 # 显示错误消息
@ -576,6 +635,328 @@ class MainWindow(MainWindowUI):
# 显示错误消息 # 显示错误消息
self.statusBar().showMessage(f"保存检验数据错误: {str(e)[:50]}...", 3000) self.statusBar().showMessage(f"保存检验数据错误: {str(e)[:50]}...", 3000)
def load_finished_inspection_data(self):
"""加载未完成的检验数据并显示在表格中"""
try:
# 使用InspectionDAO获取未完成的检验数据
from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO()
# 获取托盘号
tray_id = self.tray_edit.currentText()
# 使用get_inspection_data_unfinished获取未完成的数据
unfinished_data = inspection_dao.get_inspection_data_unfinished(tray_id)
if not unfinished_data:
logging.info("没有未完成的检验数据")
# 清空表格现有数据行,但保留表头
while self.process_table.rowCount() > 2:
self.process_table.removeRow(2)
return
logging.info(f"已加载未完成的检验数据,共 {len(unfinished_data)} 条记录")
# 获取启用的检验配置
enabled_configs = self.inspection_manager.get_enabled_configs()
# 按工程号分组
orders_data = {}
for data in unfinished_data:
order_id = data['order_id']
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
# 确保按工程号倒序排列,最新的工程号在最前面
sorted_order_ids = sorted(orders_data.keys(), reverse=True)
for order_id in sorted_order_ids:
items = orders_data[order_id]
# 添加新行
self.process_table.insertRow(row_idx)
# 添加序号到第一列
seq_item = QTableWidgetItem(str(row_idx - 1))
seq_item.setTextAlignment(Qt.AlignCenter)
self.process_table.setItem(row_idx, 0, seq_item)
# 添加工程号到第二列
order_item = QTableWidgetItem(order_id)
order_item.setTextAlignment(Qt.AlignCenter)
self.process_table.setItem(row_idx, 1, order_item)
# 添加检验数据
for item in items:
position = item['position']
value = item['value'] if item['value'] else ""
status = item['status']
config_id = item['config_id']
# 找到对应的列索引
col_index = None
for i, config in enumerate(enabled_configs):
if config.get('position') == position:
col_index = 2 + i # 检验列从第3列开始
break
if col_index is not None:
# 创建单元格并设置值
cell_item = QTableWidgetItem(str(value))
cell_item.setTextAlignment(Qt.AlignCenter)
# 存储配置ID用于保存时确定是哪个检验项
cell_item.setData(Qt.UserRole, config_id)
# 根据状态设置单元格颜色
if status == 'fail':
cell_item.setBackground(QBrush(QColor("#ffcdd2"))) # 浅红色
elif status == 'warning':
cell_item.setBackground(QBrush(QColor("#fff9c4"))) # 浅黄色
elif status == 'pass':
cell_item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色
# 设置单元格
self.process_table.setItem(row_idx, col_index, cell_item)
# 添加贴标11和称重数据12
if position == 11: # 贴标
# 贴标列索引 = 2(序号和工程号) + 检验列数
label_col = 2 + len(enabled_configs)
self.process_table.setItem(row_idx, label_col, QTableWidgetItem(str(value)))
elif position == 12: # 称重
# 称重列索引 = 2(序号和工程号) + 检验列数 + 1(贴标)
weight_col = 2 + len(enabled_configs) + 1
self.process_table.setItem(row_idx, weight_col, QTableWidgetItem(str(value)))
row_idx += 1
# 设置表格为可编辑状态
self.process_table.setEditTriggers(QTableWidget.DoubleClicked | QTableWidget.EditKeyPressed)
# 重新连接单元格变更信号
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
except Exception as e:
logging.error(f"加载未完成的检验数据失败: {str(e)}")
QMessageBox.warning(self, "加载失败", f"加载未完成的检验数据失败: {str(e)}")
finally:
# 加载包装记录
self.show_pack_item()
def load_finished_record_to_package_record(self, order_id, tray_id):
"""加载已完成检验数据到包装记录
Args:
order_id: 工程号
tray_id: 托盘号
"""
try:
from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO()
# 获取该工程号的所有检验数据
inspection_data = inspection_dao.get_inspection_data_by_order(order_id, tray_id)
if not inspection_data:
logging.warning(f"未找到工程号 {order_id} 托盘号 {tray_id} 的检验数据")
return
# 从检验数据中获取贴标和称重数据
label_value = ""
weight_value = ""
for item in inspection_data:
if item['position'] == 11: # 贴标
label_value = item['value']
elif item['position'] == 12: # 称重
weight_value = item['value']
# 只要贴标字段有值,就可以写入包装记录
if not label_value:
logging.warning(f"工程号 {order_id} 托盘号 {tray_id} 的贴标字段为空,不添加到包装记录")
return
# 获取当前包装记录,检查是否已经存在相同的记录
existing_records = inspection_dao.get_package_record(tray_id)
for record in existing_records:
if record[0] == order_id and record[4] == label_value:
logging.info(f"工程号 {order_id} 托盘号 {tray_id} 贴标值 {label_value} 的包装记录已存在,不重复添加")
return
# 获取当前时间作为完成时间
finish_time = datetime.now()
# 将数据写入到数据库表 inspection_pack_data
inspection_dao.save_package_record(order_id, tray_id, label_value, weight_value, finish_time)
# 回显数据
self.show_pack_item()
logging.info(f"已将工程号 {order_id} 托盘号 {tray_id} 的检验数据添加到包装记录并回显")
except Exception as e:
logging.error(f"加载已完成检验数据到包装记录失败: {str(e)}")
QMessageBox.warning(self, "加载失败", f"加载已完成检验数据到包装记录失败: {str(e)}")
def show_pack_item(self):
from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO()
# 获取托盘号
tray_id = self.tray_edit.currentText()
# 读取已包装的记录信息,然后回显到 UI
package_record = inspection_dao.get_package_record(tray_id)
# 清空包装记录表格,只保留表头
while self.record_table.rowCount() > 1:
self.record_table.removeRow(1)
# 断开包装记录表的信号连接(如果有)
try:
self.record_table.cellChanged.disconnect()
except:
pass
# 添加所有包装记录到表格
for index, item in enumerate(package_record):
# 在包装记录表中添加新行
row_index = index + 1 # 从第2行开始索引为1
self.record_table.insertRow(row_index)
# 设置包装记录数据
# 序号 - 第1列
seq_item = QTableWidgetItem(str(row_index))
seq_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 0, seq_item)
# 工程号 - 第2列
order_item = QTableWidgetItem(item[0])
order_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 1, order_item)
# 材质 - 第3列
material_item = QTableWidgetItem(item[1])
material_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 2, material_item)
# 规格 - 第4列
spec_item = QTableWidgetItem(item[2])
spec_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 3, spec_item)
# 托盘号 - 第5列
tray_item = QTableWidgetItem(item[3])
tray_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 4, tray_item)
# 轴包装号(贴标)- 第6列
label_item = QTableWidgetItem(item[4])
label_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 5, label_item)
# 重量 - 第7列
weight_item = QTableWidgetItem(str(item[5]))
weight_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 6, weight_item)
# 包装时间
pack_time = QTableWidgetItem(str(item[6]))
weight_item.setTextAlignment(Qt.AlignCenter)
self.record_table.setItem(row_index, 7, pack_time)
# 更新包装记录统计数据
self.update_package_statistics()
def update_package_statistics(self):
"""更新包装记录统计数据"""
try:
# 获取包装记录表的行数(不包括表头)
package_count = self.record_table.rowCount() - 1
# 更新任务表格中的已完成数量
completed_item = QTableWidgetItem(str(package_count))
completed_item.setTextAlignment(Qt.AlignCenter)
self.task_table.setItem(2, 2, completed_item)
# 计算已完成公斤数(如果称重列有数值)
completed_kg = 0
for row in range(1, self.record_table.rowCount()):
weight_item = self.record_table.item(row, 6) # 称重列
if weight_item and weight_item.text():
try:
completed_kg += float(weight_item.text())
except ValueError:
pass
# 更新任务表格中的已完成公斤
completed_kg_item = QTableWidgetItem(str(completed_kg))
completed_kg_item.setTextAlignment(Qt.AlignCenter)
self.task_table.setItem(2, 3, completed_kg_item)
logging.info(f"已更新包装记录统计数据: 完成数量={package_count}, 完成公斤={completed_kg}")
except Exception as e:
logging.error(f"更新包装记录统计数据失败: {str(e)}")
def check_and_process_finished_records(self):
"""检查并处理所有已完成的检验记录"""
try:
# 获取当前托盘号
tray_id = self.tray_edit.currentText()
# 使用InspectionDAO获取未完成的检验数据
from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO()
# 获取所有检验数据
all_data = inspection_dao.get_inspection_data_unfinished(tray_id)
# 按工程号分组
orders_data = {}
for data in all_data:
order_id = data['order_id']
if order_id not in orders_data:
orders_data[order_id] = []
orders_data[order_id].append(data)
# 检查每个工程号是否有贴标数据
for order_id, items in orders_data.items():
# 查找贴标数据
has_label = False
label_value = ""
for item in items:
if item['position'] == 11: # 贴标
label_value = item['value']
if label_value:
has_label = True
break
if has_label:
# 将已有贴标的记录添加到包装记录
self.load_finished_record_to_package_record(order_id, tray_id)
logging.info(f"已将工程号 {order_id} 的贴标记录添加到包装记录")
# 重新加载检验数据
self.load_finished_inspection_data()
except Exception as e:
logging.error(f"检查并处理已完成的检验记录失败: {str(e)}")
QMessageBox.warning(self, "处理失败", f"检查并处理已完成的检验记录失败: {str(e)}")
def show_table_context_menu(self, pos): def show_table_context_menu(self, pos):
"""显示表格上下文菜单 """显示表格上下文菜单
@ -638,6 +1019,7 @@ class MainWindow(MainWindowUI):
Args: Args:
order_id: 工程号 order_id: 工程号
position: 位置序号 position: 位置序号
tray_id: 托盘号
""" """
try: try:
from dao.inspection_dao import InspectionDAO from dao.inspection_dao import InspectionDAO
@ -671,106 +1053,3 @@ class MainWindow(MainWindowUI):
except Exception as e: except Exception as e:
logging.error(f"检查数据库记录失败: {str(e)}") logging.error(f"检查数据库记录失败: {str(e)}")
QMessageBox.warning(self, "查询失败", f"检查数据库记录失败: {str(e)}") QMessageBox.warning(self, "查询失败", f"检查数据库记录失败: {str(e)}")
def load_unfinished_inspection_data(self):
"""加载未完成的检验数据并显示在表格中"""
try:
# 使用InspectionDAO获取未完成的检验数据
from dao.inspection_dao import InspectionDAO
inspection_dao = InspectionDAO()
# 获取托盘号
tray_id = self.tray_edit.currentText()
# 使用get_inspection_data_unfinished获取未完成的数据
unfinished_data = inspection_dao.get_inspection_data_unfinished(tray_id)
if not unfinished_data:
logging.info("没有未完成的检验数据")
# 清空表格现有数据行
while self.process_table.rowCount() > 2:
self.process_table.removeRow(2)
return
logging.info(f"已加载未完成的检验数据,共 {len(unfinished_data)} 条记录")
# 获取启用的检验配置
enabled_configs = self.inspection_manager.get_enabled_configs()
# 按工程号分组
orders_data = {}
for data in unfinished_data:
order_id = data['order_id']
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)
# 添加数据到表格
row_idx = 2 # 从第3行开始添加数据
for order_id, items in orders_data.items():
# 添加新行
self.process_table.insertRow(row_idx)
# 添加序号到第一列
seq_item = QTableWidgetItem(str(row_idx - 1))
seq_item.setTextAlignment(Qt.AlignCenter)
self.process_table.setItem(row_idx, 0, seq_item)
# 添加工程号到第二列
order_item = QTableWidgetItem(order_id)
order_item.setTextAlignment(Qt.AlignCenter)
self.process_table.setItem(row_idx, 1, order_item)
# 添加检验数据
for item in items:
position = item['position']
value = item['value'] if item['value'] else ""
status = item['status']
config_id = item['config_id']
# 找到对应的列索引
col_index = None
for i, config in enumerate(enabled_configs):
if config.get('position') == position:
col_index = 2 + i # 检验列从第3列开始
break
if col_index is not None:
# 创建单元格并设置值
cell_item = QTableWidgetItem(str(value))
cell_item.setTextAlignment(Qt.AlignCenter)
# 存储配置ID用于保存时确定是哪个检验项
cell_item.setData(Qt.UserRole, config_id)
# 根据状态设置单元格颜色
if status == 'fail':
cell_item.setBackground(QBrush(QColor("#ffcdd2"))) # 浅红色
elif status == 'warning':
cell_item.setBackground(QBrush(QColor("#fff9c4"))) # 浅黄色
elif status == 'pass':
cell_item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色
# 设置单元格
self.process_table.setItem(row_idx, col_index, cell_item)
row_idx += 1
# 设置表格为可编辑状态
self.process_table.setEditTriggers(QTableWidget.DoubleClicked | QTableWidget.EditKeyPressed)
# 重新连接单元格变更信号
self.process_table.cellChanged.connect(self.handle_inspection_cell_changed)
except Exception as e:
logging.error(f"加载未完成的检验数据失败: {str(e)}")
QMessageBox.warning(self, "加载失败", f"加载未完成的检验数据失败: {str(e)}")