diff --git a/dao/inspection_dao.py b/dao/inspection_dao.py index 2112ce9..10e51ae 100644 --- a/dao/inspection_dao.py +++ b/dao/inspection_dao.py @@ -258,7 +258,7 @@ class InspectionDAO: """ update_params = ( 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) else: @@ -282,22 +282,42 @@ class InspectionDAO: logging.error(f"保存检验数据失败: {str(e)}") return False def get_inspection_data_unfinished(self, tray_id): - """获取未完成的检验数据 + """获取未完成的检验数据,通过是否贴标来判断 Returns: list: 未完成的检验数据列表 """ - try: - sql = """ + try: + # 先获取所有没有贴标的工程号 + 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, c.name, c.display_name, c.data_type, c.unit 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 = ? - 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 """ - params = (tray_id,) + + params = [tray_id] + order_ids self.db.cursor.execute(sql, params) 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, c.name, c.display_name, c.data_type, c.unit 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 = ? ORDER BY d.position """ @@ -364,4 +384,84 @@ class InspectionDAO: return data_list except Exception as e: logging.error(f"获取检验数据失败: {str(e)}") - return [] \ No newline at end of file + 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() + + \ No newline at end of file diff --git a/db/jtDB.db b/db/jtDB.db index 0810f0b..74ab178 100644 Binary files a/db/jtDB.db and b/db/jtDB.db differ diff --git a/db/schema.sql b/db/schema.sql index cdd261e..af4527c 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -52,4 +52,27 @@ INSERT OR IGNORE INTO inspection_config ( -- 为外观检验项设置枚举值 UPDATE inspection_config SET enum_values = '["合格", "不合格", "需要重检"]' -WHERE name = 'appearance'; \ No newline at end of file +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 +) + diff --git a/ui/main_window_ui.py b/ui/main_window_ui.py index 98b8ead..a2e9c90 100644 --- a/ui/main_window_ui.py +++ b/ui/main_window_ui.py @@ -501,13 +501,13 @@ class MainWindowUI(QMainWindow): 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) # 设置列标题 - record_headers = ["序号", "订单", "材质", "规格", "托号", "轴包装号", "重量"] + record_headers = ["序号", "订单", "材质", "规格", "托号", "轴包装号", "重量", "完成时间"] for col, header in enumerate(record_headers): self.record_table.setItem(0, col, self.create_header_item(header)) @@ -520,7 +520,7 @@ class MainWindowUI(QMainWindow): 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): self.record_table.setColumnWidth(col, width) diff --git a/widgets/main_window.py b/widgets/main_window.py index 74e053b..0960ab2 100644 --- a/widgets/main_window.py +++ b/widgets/main_window.py @@ -80,18 +80,17 @@ class MainWindow(MainWindowUI): # 默认显示主页面 self.stacked_widget.setCurrentIndex(0) - # 初始化数据 - self.initialize_data() - # 配置检验列 - 使用检验配置管理器获取启用的列数和标题 self.update_inspection_columns() # 设置表格上下文菜单 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}") @@ -117,8 +116,8 @@ class MainWindow(MainWindowUI): # 托盘号输入框回车和切换事件,触发未加载数据查询 # QComboBox没有returnPressed信号,只有currentTextChanged和activated信号 - self.tray_edit.currentTextChanged.connect(self.load_unfinished_inspection_data) - self.tray_edit.activated.connect(self.load_unfinished_inspection_data) # 当用户选择一项时触发 + self.tray_edit.currentTextChanged.connect(self.load_finished_inspection_data) + self.tray_edit.activated.connect(self.load_finished_inspection_data) # 当用户选择一项时触发 # 连接按钮事件 self.input_button.clicked.connect(self.handle_input) @@ -126,37 +125,16 @@ class MainWindow(MainWindowUI): self.start_button.clicked.connect(self.handle_start) 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'): self.camera_display.signal_camera_status.connect(self.handle_camera_status) - - def initialize_data(self): - """初始化界面数据""" - # 设置订单和批号 - 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) + # 初始化后检查是否有已完成的记录 + QTimer.singleShot(1000, self.check_and_process_finished_records) def update_inspection_columns(self): """更新检验列配置 - 使用检验配置管理器获取启用的列数和标题""" @@ -189,7 +167,7 @@ class MainWindow(MainWindowUI): self.update_inspection_columns() # 加载未完成的检验数据 - self.load_unfinished_inspection_data() + self.load_finished_inspection_data() # 只有在相机启用时处理相机显示 if self.camera_enabled and hasattr(self, 'camera_display'): @@ -324,7 +302,13 @@ class MainWindow(MainWindowUI): # 固定的数据起始行索引 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) # 更新序号 - 所有现有行序号+1 @@ -369,14 +353,7 @@ class MainWindow(MainWindowUI): # 设置表格为可编辑状态 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) # 选中新添加的行 @@ -385,11 +362,43 @@ class MainWindow(MainWindowUI): # 限制最大行数 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条") except Exception as e: logging.error(f"添加新记录失败: {str(e)}") QMessageBox.warning(self, "添加失败", f"添加新记录失败: {str(e)}") + finally: + # 重新加载数据,确保UI显示正确 + self.load_finished_inspection_data() def limit_table_rows(self, max_rows): """限制表格最大行数 @@ -448,21 +457,29 @@ class MainWindow(MainWindowUI): # 判断是否是检验列(非包装列) packaging_start_col = 2 + len(enabled_configs) + + # 获取单元格内容 + cell_item = self.process_table.item(row, column) + if not cell_item: + return + + 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] - - # 获取单元格内容 - cell_item = self.process_table.item(row, column) - if not cell_item: - return - - value = cell_item.text().strip() + 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): @@ -476,12 +493,35 @@ class MainWindow(MainWindowUI): # 保存到数据库 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: logging.error(f"处理检验单元格变更失败: {str(e)}") 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): """验证检验值是否有效 @@ -494,6 +534,10 @@ class MainWindow(MainWindowUI): bool: 是否有效 """ try: + # 特殊处理贴标和称重数据 - 这些数据默认都是有效的 + if config.get('position') in [11, 12]: # 11是贴标,12是称重 + return True + # 检查值是否为空 if not value and config.get('required', False): return False @@ -504,6 +548,10 @@ class MainWindow(MainWindowUI): if data_type == 'number': # 数值类型验证 try: + # 如果值为空且不是必填,则视为有效 + if not value and not config.get('required', False): + return True + num_value = float(value) min_value = config.get('min_value') max_value = config.get('max_value') @@ -522,6 +570,9 @@ class MainWindow(MainWindowUI): # 枚举类型验证 enum_values = config.get('enum_values') 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 False @@ -561,11 +612,19 @@ class MainWindow(MainWindowUI): # 保存到数据库 result = inspection_dao.save_inspection_data(order_id, data) - # 判断,如果保存成功后,且当前工程号中,全部为 pass 说明该工序已经完成,需要流转到下一步,回显到包装记录中 if result: logging.info(f"已成功保存工程号 {order_id} 的检验数据,位置: {position}, 值: {value}") # 显示临时状态消息 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: logging.warning(f"保存工程号 {order_id} 的检验数据失败") # 显示错误消息 @@ -576,6 +635,328 @@ class MainWindow(MainWindowUI): # 显示错误消息 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): """显示表格上下文菜单 @@ -631,13 +1012,14 @@ class MainWindow(MainWindowUI): except Exception as e: logging.error(f"显示表格上下文菜单失败: {str(e)}") - + def check_database_record(self, order_id, position, tray_id): """检查数据库记录 Args: order_id: 工程号 position: 位置序号 + tray_id: 托盘号 """ try: from dao.inspection_dao import InspectionDAO @@ -670,107 +1052,4 @@ class MainWindow(MainWindowUI): except Exception as e: logging.error(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)}") \ No newline at end of file + QMessageBox.warning(self, "查询失败", f"检查数据库记录失败: {str(e)}") \ No newline at end of file