From e3396291a9dad07fa628c4c20bf22ba4101a77f4 Mon Sep 17 00:00:00 2001 From: zhu-mengmeng <15588200382@163.com> Date: Thu, 19 Jun 2025 23:27:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E6=93=8D=E4=BD=9C=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=AE=A2=E5=8D=95=E5=8F=B7=E5=92=8C=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E5=8F=B7=E7=9A=84=E5=85=B3=E8=81=94=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E6=98=BE=E7=A4=BA=E5=92=8C=E4=BF=A1=E5=8F=B7?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apis/tary_api.py | 2 +- dao/inspection_dao.py | 135 ++++++++------ db/jtDB.db | Bin 77824 -> 77824 bytes from pymodbus.py | 2 +- ui/main_window_ui.py | 14 +- utils/inspection_config_manager.py | 9 +- widgets/loading_dialog_widget.py | 56 +++++- widgets/main_window.py | 285 +++++++++++------------------ widgets/unloading_dialog_widget.py | 2 +- 9 files changed, 257 insertions(+), 248 deletions(-) diff --git a/apis/tary_api.py b/apis/tary_api.py index acda137..9931a34 100644 --- a/apis/tary_api.py +++ b/apis/tary_api.py @@ -30,7 +30,7 @@ class TaryApi: if not response.get("status", False): return { "success": False, - "message": "获取托盘信息失败", + "message": "未找到托盘信息", "data": None } diff --git a/dao/inspection_dao.py b/dao/inspection_dao.py index 751f934..531d953 100644 --- a/dao/inspection_dao.py +++ b/dao/inspection_dao.py @@ -227,17 +227,37 @@ class InspectionDAO: if not data: return False - sql = """ - INSERT INTO wsbz_order_info ( - data_corp, user_id, user_name, gzl_zl, ddmo, xpack, - sc_gch, qd, spack_type, mxzs, jt, ddnote, code, type, - lable, lib, gzl, maxsl, cz, size, cd, luno, qfqd, - pono, xj, ysl, dycz, zh, edit_id, remarks - ) VALUES ( - ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, - ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? - ) - """ + # 先检查是否存在记录 + check_sql = "SELECT id FROM wsbz_order_info WHERE ddmo = ?" + self.db.cursor.execute(check_sql, (data.get("mo", ""),)) + existing_record = self.db.cursor.fetchone() + + if existing_record: + # 如果记录存在,执行更新 + sql = """ + UPDATE wsbz_order_info SET + data_corp = ?, user_id = ?, user_name = ?, gzl_zl = ?, xpack = ?, + qd = ?, spack_type = ?, mxzs = ?, jt = ?, ddnote = ?, code = ?, + type = ?, lable = ?, lib = ?, gzl = ?, maxsl = ?, cz = ?, + size = ?, cd = ?, luno = ?, qfqd = ?, pono = ?, xj = ?, + ysl = ?, dycz = ?, zx_code = ?, edit_id = ?, remarks = ?, zx_name = ? + WHERE ddmo = ? + """ + logging.info(f"更新订单信息: ddmo={data.get('mo', '')}") + else: + # 如果记录不存在,执行插入 + sql = """ + INSERT INTO wsbz_order_info ( + data_corp, user_id, user_name, gzl_zl, ddmo, xpack, + qd, spack_type, mxzs, jt, ddnote, code, type, + lable, lib, gzl, maxsl, cz, size, cd, luno, qfqd, + pono, xj, ysl, dycz, zx_code, edit_id, remarks,zx_name + ) VALUES ( + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? + ) + """ + logging.info(f"插入新订单信息: ddmo={data.get('mo', '')}") params = ( data.get("data_corp", "JT"), @@ -246,7 +266,6 @@ class InspectionDAO: data.get("zx_zl", ""), data.get("mo", ""), data.get("xpack", ""), - order_id if order_id else "", data.get("qd", ""), data.get("spack_type", ""), data.get("mxzs", ""), @@ -267,11 +286,16 @@ class InspectionDAO: data.get("size", ""), data.get("ysl", ""), data.get("dycz", ""), - data.get("zh", ""), + data.get("zx_code", ""), data.get("edit_id", ""), data.get("remarks", ""), + data.get("zx_name", ""), ) + # 如果是更新操作,需要添加 WHERE 条件的参数 + if existing_record: + params = params + (data.get("mo", ""),) + self.db.cursor.execute(sql, params) self.db.conn.commit() return True @@ -280,7 +304,7 @@ class InspectionDAO: logging.error(f"保存订单信息失败: {str(e)}") self.db.conn.rollback() return False - def save_inspection_data(self, order_id, data, username='system'): + def save_inspection_data(self, order_id,gc_note, data, username='system'): """保存检验数据 Args: @@ -306,9 +330,9 @@ class InspectionDAO: # 检查是否已存在该工程号和位置的记录 check_sql = """ SELECT id FROM wsbz_inspection_data - WHERE order_id = ? AND position = ? AND is_deleted = FALSE + WHERE order_id = ? and gc_note = ? AND position = ? AND is_deleted = FALSE """ - check_params = (order_id, position) + check_params = (order_id,gc_note, position) self.db.cursor.execute(check_sql, check_params) existing = self.db.cursor.fetchone() @@ -331,12 +355,12 @@ class InspectionDAO: insert_sql = """ INSERT INTO wsbz_inspection_data ( order_id, position, config_id, value, status, remark, - create_time, create_by, is_deleted, tray_id - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, FALSE, ?) + create_time, create_by, is_deleted, tray_id,gc_note + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, FALSE, ?, ?) """ insert_params = ( order_id, position, config_id, value, status, remark, - current_time, username, tray_id + current_time, username, tray_id,gc_note ) self.db.cursor.execute(insert_sql, insert_params) @@ -355,34 +379,34 @@ class InspectionDAO: try: # 先获取所有没有贴标的工程号 sql_orders = """ - SELECT DISTINCT d.order_id + SELECT DISTINCT d.gc_note FROM wsbz_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() + gc_notes = self.db.cursor.fetchall() - if not orders: + if not gc_notes: return [] # 构建IN子句的参数 - order_ids = [order[0] for order in orders] - placeholders = ','.join(['?' for _ in order_ids]) + gc_notes = [gc_note[0] for gc_note in gc_notes] + placeholders = ','.join(['?' for _ in gc_notes]) # 获取这些工程号的所有检验数据 sql = f""" - SELECT d.id, d.order_id, d.position, d.config_id, d.value, d.status, d.remark, + SELECT d.id, d.gc_note, d.position, d.config_id, d.value, d.status, d.remark, c.name, c.display_name, c.data_type, c.unit FROM wsbz_inspection_data d LEFT JOIN wsbz_inspection_config c ON d.config_id = c.id WHERE d.is_deleted = FALSE AND d.tray_id = ? - AND d.order_id IN ({placeholders}) + AND d.gc_note IN ({placeholders}) ORDER BY d.create_time """ - params = [tray_id] + order_ids + params = [tray_id] + gc_notes self.db.cursor.execute(sql, params) results = self.db.cursor.fetchall() @@ -390,7 +414,7 @@ class InspectionDAO: for row in results: data = { 'id': row[0], - 'order_id': row[1], + 'gc_note': row[1], 'position': row[2], 'config_id': row[3], 'value': row[4], @@ -407,11 +431,12 @@ class InspectionDAO: except Exception as e: logging.error(f"获取未完成的检验数据失败: {str(e)}") return [] - def get_inspection_data_by_order(self, order_id, tray_id): + def get_inspection_data_by_order(self, order_id,gc_note, tray_id): """根据工程号获取检验数据 Args: - order_id: 工程号 + order_id: 订单号 + gc_note: 工程号 tray_id: 托盘号 Returns: list: 检验数据列表 @@ -422,10 +447,10 @@ class InspectionDAO: c.name, c.display_name, c.data_type, c.unit FROM wsbz_inspection_data d LEFT JOIN wsbz_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.gc_note = ? AND d.is_deleted = FALSE AND d.tray_id = ? ORDER BY d.create_time, d.order_id, d.position """ - params = (order_id, tray_id) + params = (order_id, gc_note, tray_id) self.db.cursor.execute(sql, params) results = self.db.cursor.fetchall() @@ -461,15 +486,17 @@ class InspectionDAO: """ try: sql = """ - SELECT order_id, - COALESCE(material, '') as material, - COALESCE(spec, '') as spec, + SELECT DISTINCT order_id, + gc_note, + COALESCE(orders.size, '') as material, + COALESCE(orders.cz, '') as spec, tray_id, COALESCE(axis_package_id, '') as axis_package_id, COALESCE(weight, 0) as weight, COALESCE(net_weight, 0) as net_weight, STRFTIME('%Y-%m-%d %H:%M:%S', pack_time) as pack_time - FROM wsbz_inspection_pack_data + FROM wsbz_inspection_pack_data t1 + LEFT JOIN wsbz_order_info orders on t1.order_id = orders.ddmo WHERE tray_id = ? AND is_deleted = FALSE ORDER BY pack_time DESC @@ -481,7 +508,7 @@ class InspectionDAO: except Exception as e: logging.error(f"获取包装记录失败: {str(e)}") return [] - def save_package_record(self, order_id, tray_id, label_value, weight_value,net_weight_value, finish_time): + def save_package_record(self, order_id, tray_id, label_value, weight_value,net_weight_value, finish_time,gc_note): """保存包装记录 Args: @@ -494,10 +521,10 @@ class InspectionDAO: # TODO:调用接口,获取到工程号对应的其他信息,比如材质,规格,后续完成 try: sql = """ - INSERT INTO wsbz_inspection_pack_data (order_id, tray_id, axis_package_id, weight, net_weight, pack_time, create_time, create_by, update_time, update_by, is_deleted) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + INSERT INTO wsbz_inspection_pack_data (order_id, tray_id, axis_package_id, weight, net_weight, pack_time, create_time, create_by, update_time, update_by, is_deleted,gc_note) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) """ - params = (order_id, tray_id, label_value, weight_value, net_weight_value, finish_time, datetime.now(), 'system', datetime.now(), 'system', False) + params = (order_id, tray_id, label_value, weight_value, net_weight_value, finish_time, datetime.now(), 'system', datetime.now(), 'system', False,gc_note) self.db.cursor.execute(sql, params) self.db.conn.commit() except Exception as e: @@ -523,14 +550,14 @@ class InspectionDAO: except Exception as e: logging.error(f"删除检验数据失败: {str(e)}") self.db.conn.rollback() - def get_axios_num_by_order_id(self, order_id): + def get_axios_num_by_order_id(self, gc_note): """获取托盘号对应的轴号""" try: sql = """ - SELECT max(axis_package_id) as axios_num FROM wsbz_inspection_pack_data WHERE order_id = ? + SELECT max(axis_package_id) as axios_num FROM wsbz_inspection_pack_data WHERE gc_note = ? AND is_deleted = FALSE """ - params = (order_id,) + params = (gc_note,) self.db.cursor.execute(sql, params) result = self.db.cursor.fetchone() return int(result[0]) if result else 0 @@ -541,7 +568,7 @@ class InspectionDAO: """获取托盘号对应的轴号""" try: sql = """ - SELECT max(axis_package_id) as axios_num FROM wsbz_inspection_pack_data WHERE tray_id = ? + SELECT max(cast(axis_package_id as int)) as axios_num FROM wsbz_inspection_pack_data WHERE tray_id = ? AND is_deleted = FALSE """ params = (tray_id,) @@ -555,7 +582,7 @@ class InspectionDAO: """获取工字轮重量""" try: sql = """ - SELECT gzl_zl FROM wsbz_order_info WHERE sc_gch = ? + SELECT gzl_zl FROM wsbz_order_info WHERE ddmo = ? """ params = (order_id,) self.db.cursor.execute(sql, params) @@ -604,10 +631,10 @@ class InspectionDAO: # 查询每个工程号的最早创建时间并排序 sql = f""" - SELECT order_id, MIN(create_time) as first_create_time + SELECT gc_note, MIN(create_time) as first_create_time FROM wsbz_inspection_data - WHERE order_id IN ({placeholders}) AND is_deleted = FALSE - GROUP BY order_id + WHERE gc_note IN ({placeholders}) AND is_deleted = FALSE + GROUP BY gc_note ORDER BY first_create_time """ @@ -638,9 +665,9 @@ class InspectionDAO: """ try: sql = """ - SELECT data_corp,user_id,user_name,gzl_zl,mzl,ddmo,xpack,sc_gch,qd,spack_type,mxzs,jt,ddnote,code, - type,lable,lib,gzl,maxsl,cz,size,cd,luno,qfqd,pono,xj,ysl,dycz,zh,edit_id,remarks - FROM wsbz_order_info WHERE sc_gch = ? + SELECT distinct data_corp,user_id,user_name,gzl_zl,mzl,ddmo,qd,spack_type,mxzs,jt,ddnote,code, + type,lable,lib,gzl,maxsl,cz,size,cd,luno,qfqd,pono,xj,ysl,dycz,edit_id,remarks,zx_name + FROM wsbz_order_info WHERE ddmo = ? """ params = (order_id,) self.db.cursor.execute(sql, params) @@ -662,7 +689,7 @@ class InspectionDAO: except Exception as e: logging.error(f"获取订单信息失败: {str(e)}") return {} - def get_order_others_info(self, order_id, tray_id): + def get_order_others_info(self, gc_note, order_id, tray_id): """获取订单其他信息 Args: @@ -677,12 +704,12 @@ class InspectionDAO: SELECT t1.order_id, CASE WHEN t1.position = 12 THEN 'mzl' ELSE name END AS name, value FROM wsbz_inspection_data t1 LEFT JOIN main.wsbz_inspection_config wic ON t1.config_id = wic.id - WHERE order_id = ? + WHERE gc_note = ? AND t1.order_id = ? AND tray_id = ? AND CASE WHEN t1.position = 12 THEN 'mzl' ELSE name END IS NOT NULL AND COALESCE(value, '') != '' """ - params = (order_id, tray_id) + params = (gc_note, order_id, tray_id) self.db.cursor.execute(sql, params) results = self.db.cursor.fetchall() diff --git a/db/jtDB.db b/db/jtDB.db index f50f68c8d727f13cfb0f7a8da3610a5ffac10ce1..554157dd584aa060080ae1cb7b8d70bbd15d9703 100644 GIT binary patch literal 77824 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%0AtUuLQV4G<=mZ_^IJi@6%+6&>UY$ zJ}`I2=2Fo;%$?0~8D#Ek8V0P~dD8wRlFe?{24!jujNA|Vt>Lq|q;hok2ykyH2@`d? zbc<}Z91d`o((^8THd~olqb8KK1A4D7B`?Wg+GJizl_{Iroyy|bG;h?L@F4RwvWP?N zK&lNTbmW)5RXII_X^IAD`KaX8lwU)QI}9o!u2=cLj-a-kH0C`20WDr<~^l&zR>S z_y2Yezy*6T1Q-Gg0fqoWfFZyTU$0*oS=!boO7O_y}%9J^N3m%fcM~_gFE4+fWbx)3q_j)BiRU!@z_({ZGeaPRIXk RDoR)m_4q#>i+P^^_n(h)%`yN0 literal 77824 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 QG-_pxc*58Q=c~#82R8?9%>V!Z diff --git a/from pymodbus.py b/from pymodbus.py index 7b6ba9d..2a9329c 100644 --- a/from pymodbus.py +++ b/from pymodbus.py @@ -2,7 +2,7 @@ from pymodbus.client import ModbusTcpClient client = ModbusTcpClient('localhost', port=5020) client.connect() -# client.write_registers(address=11, values=[110]) +client.write_registers(address=11, values=[111]) client.write_registers(address=13, values=[1]) # client.write_registers(address=6, values=[1]) diff --git a/ui/main_window_ui.py b/ui/main_window_ui.py index 24c9078..0868f75 100644 --- a/ui/main_window_ui.py +++ b/ui/main_window_ui.py @@ -16,7 +16,7 @@ class MainWindowUI(QMainWindow): def init_ui(self): # 设置字体 - self.title_font = QFont("微软雅黑", 16, QFont.Bold) + self.title_font = QFont("微软雅黑", 20, QFont.Bold) self.second_title_font = QFont("微软雅黑", 14, QFont.Bold) self.normal_font = QFont("微软雅黑", 12) self.small_font = QFont("微软雅黑", 9) @@ -74,8 +74,7 @@ class MainWindowUI(QMainWindow): # 创建用户名标签 self.username_label = QLabel(self.username) - username_font = QFont("微软雅黑", 12) # 较小的字体 - self.username_label.setFont(username_font) + self.username_label.setFont(self.normal_font) self.username_label.setStyleSheet("color: #666666;") self.username_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) @@ -87,8 +86,7 @@ class MainWindowUI(QMainWindow): # 创建时间标签 self.time_label = QLabel() - time_font = QFont("微软雅黑", 12) # 较小的字体 - self.time_label.setFont(time_font) + self.time_label.setFont(self.normal_font) self.time_label.setStyleSheet("color: #666666;") self.time_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) @@ -538,13 +536,13 @@ class MainWindowUI(QMainWindow): self.record_layout.addWidget(self.record_title) # 创建表格 - self.record_table = QTableWidget(13, 9) # 13行9列:序号、订单、品名、规格、托号、轴包装号、重量、净重、完成时间 + self.record_table = QTableWidget(13, 10) # 13行10列:序号、订单、工程号、品名、规格、托号、轴包装号、重量、净重、完成时间 # 应用通用表格设置但保留表头 self.setup_table_common(self.record_table, hide_headers=False) # 设置列标题 - record_headers = ["序号", "订单", "品名", "规格", "托号", "轴包装号", "毛重", "净重", "完成时间"] + record_headers = ["序号", "订单", "工程号", "品名", "规格", "托号", "轴包装号", "毛重", "净重", "完成时间"] self.record_table.setHorizontalHeaderLabels(record_headers) # 设置表头样式 @@ -565,7 +563,7 @@ class MainWindowUI(QMainWindow): self.record_table.setRowHeight(row, 35) # 设置列宽 - column_widths = [70, 200, 130, 130, 160, 120, 120, 120, 160] + column_widths = [60, 170, 170, 120, 120, 150, 100, 100, 100, 160] for col, width in enumerate(column_widths): self.record_table.setColumnWidth(col, width) self.record_table.horizontalHeader().resizeSection(col, width) diff --git a/utils/inspection_config_manager.py b/utils/inspection_config_manager.py index 41b0186..8065e26 100644 --- a/utils/inspection_config_manager.py +++ b/utils/inspection_config_manager.py @@ -197,4 +197,11 @@ class InspectionConfigManager: order_id: 工程号 tray_id: 托盘号 """ - return self.dao.delete_inspection_data(order_id, tray_id) \ No newline at end of file + return self.dao.delete_inspection_data(order_id, tray_id) + def get_order_info(self, order_code): + """获取订单信息 + + Args: + order_code: 订单号 + """ + return self.dao.get_order_info(order_code) \ No newline at end of file diff --git a/widgets/loading_dialog_widget.py b/widgets/loading_dialog_widget.py index d7e00d2..a74c1c5 100644 --- a/widgets/loading_dialog_widget.py +++ b/widgets/loading_dialog_widget.py @@ -5,15 +5,21 @@ from PySide6.QtWidgets import QMessageBox, QDialog import logging from utils.app_mode import AppMode from utils.pallet_type_manager import PalletTypeManager +from apis.gc_api import GcApi class LoadingDialog(LoadingDialogUI): + # 定义一个信号,用于向主窗口传递托盘号 tray_code_signal = Signal(str, str, str, str) + # 定义一个信号,用于向主窗口传递订单号 + order_code_signal = Signal(str) - def __init__(self, parent=None): + def __init__(self, parent=None,user_id=None,user_name=None,corp_id=None): """初始化加载对话框""" super().__init__() self.parent = parent - + self.user_id = user_id + self.user_name = user_name + self.corp_id = corp_id # 彻底禁用对话框的回车键关闭功能 self.setModal(True) # 禁用所有按钮的默认行为 @@ -32,15 +38,53 @@ class LoadingDialog(LoadingDialogUI): """设置事件连接""" # 托盘号输入框回车事件触发查询 self.tray_input.returnPressed.connect(self.handle_tray_return_pressed) - # 移除editingFinished事件,避免重复触发查询 - # self.tray_input.editingFinished.connect(self.on_tray_query) + self.order_input.returnPressed.connect(self.handle_order_return_pressed) # 确认按钮点击事件 self.confirm_button.clicked.connect(self.accept) # 取消按钮点击事件 self.cancel_button.clicked.connect(self.reject) - + def handle_order_return_pressed(self): + """处理订单输入框的回车事件""" + logging.info("订单输入框回车事件触发") + # 获取当前订单号值 + order_code = self.order_input.text().strip() + if not order_code: + QMessageBox.warning(self, "提示", "请输入订单号") + return + + # 发送订单号到主窗口 + from widgets.main_window import MainWindow + main_window = self.parent + if main_window and isinstance(main_window, MainWindow): + logging.info(f"发送订单号到主窗口: {order_code}") + self.order_code_signal.emit(order_code) + + #判断是否是接口,如果不是接口直接添加如果是则走接口 + # 如果开启接口模式,则需要调用接口同步到业务库 + order_info = None + if AppMode.is_api(): + # 调用接口 + gc_api = GcApi() + # 防止response为None导致异常 + # 获取工程号信息,并且初始化数据 + order_response = gc_api.get_order_info(order_code) + if(order_response.get("status",False)): + # 将接口数据保存到数据库,用于后续的关联使用 + from dao.inspection_dao import InspectionDAO + inspection_dao = InspectionDAO() + order_info = order_response.get("data", {})[0] + # 设置轴数 + order_info['user_id'] = self.user_id + order_info['user_name'] = self.user_name + order_info['data_corp'] = self.corp_id + inspection_dao.save_order_info(order_code,order_info) + + + + # 阻止事件继续传播 + return True def handle_tray_return_pressed(self): """处理托盘输入框的回车事件""" # 阻止事件传播 @@ -146,7 +190,7 @@ class LoadingDialog(LoadingDialogUI): else: # 获取托盘信息失败 - error_msg = response.get("message", "获取托盘信息失败") + error_msg = response.get("message", "未找到托盘信息") logging.warning(f"查询失败: {error_msg}") QMessageBox.warning(self, "查询失败", error_msg) except Exception as e: diff --git a/widgets/main_window.py b/widgets/main_window.py index d16e2df..f8bf18f 100644 --- a/widgets/main_window.py +++ b/widgets/main_window.py @@ -55,6 +55,7 @@ class MainWindow(MainWindowUI): self.corp_id = corp_id self.init_seq = {} # 初始化轴包装的序号 self._loading_data_in_progress = False # 数据加载状态标志,防止循环调用 + self._current_order_code = None # 存储当前订单号 # 设置窗口标题 if user_name and corp_name: @@ -367,7 +368,10 @@ class MainWindow(MainWindowUI): # 创建上料对话框 from widgets.loading_dialog_widget import LoadingDialog - dialog = LoadingDialog(parent=self) + dialog = LoadingDialog(parent=self,user_id=self.user_id,user_name=self.user_name,corp_id=self.corp_id) + + # 连接订单号信号 + dialog.order_code_signal.connect(self.handle_order_code_received) # 显示对话框 result = dialog.exec() @@ -663,40 +667,13 @@ class MainWindow(MainWindowUI): """处理工程号输入框按下回车事件""" logging.info("工程号输入框按下回车事件") # 获取当前输入的工程号 - order_text = self.order_edit.text().strip() + gc_note = self.order_edit.text().strip() tray_id = self.tray_edit.currentText() - if order_text: - logging.info(f"输入的工程号: {order_text}") + if gc_note: + logging.info(f"输入的工程号: {gc_note}") #判断是否是接口,如果不是接口直接添加如果是则走接口 # 如果开启接口模式,则需要调用接口同步到业务库 - order_info = None - if AppMode.is_api(): - # 调用接口 - gc_api = GcApi() - gc_response = gc_api.get_gc_info(order_text) - axios_num = self.get_axios_num(tray_id) - # 防止response为None导致异常 - if bool(gc_response.get("status", False)): - # 获取工程号信息,并且初始化数据 - data = gc_response.get("data", {}) - order_response = gc_api.get_order_info(data.get("ddnote",{})) - if(order_response.get("status",False)): - # 将接口数据保存到数据库,用于后续的关联使用 - from dao.inspection_dao import InspectionDAO - inspection_dao = InspectionDAO() - order_info = order_response.get("data", {})[0] - # 设置轴数 - order_info["axios_num"] = axios_num - order_info["sc_gch"] = order_text - order_info['user_id'] = self.user_id - order_info['user_name'] = self.user_name - order_info['data_corp'] = self.corp_id - inspection_dao.save_order_info(order_text,order_info) - - - - # 在微丝产线表格中添加一条新记录 - self.add_new_inspection_row(order_text,order_info) + self.add_new_inspection_row(gc_note, self._current_order_code) else: @@ -706,11 +683,11 @@ class MainWindow(MainWindowUI): # 处理完后可以清除焦点,让输入框失去焦点 self.central_widget.setFocus() - def add_new_inspection_row(self, order_id, order_info): + def add_new_inspection_row(self, gc_note, order_code): """在微丝产线表格中添加一条新记录,添加到表格末尾 Args: - order_id: 工程号 + gc_note: 工程号 order_info: 从接口获取的工程号信息 """ try: @@ -741,7 +718,7 @@ class MainWindow(MainWindowUI): new_seq = data_start_row - 1 # 备选方案:使用行索引作为序号 # 添加工程号到表格的第二列 - item = QTableWidgetItem(order_id) + item = QTableWidgetItem(gc_note) item.setTextAlignment(Qt.AlignCenter) self.process_table.setItem(data_start_row, 1, item) @@ -750,6 +727,9 @@ class MainWindow(MainWindowUI): item.setTextAlignment(Qt.AlignCenter) self.process_table.setItem(data_start_row, 0, item) + # 获取订单信息 + order_info = self.inspection_manager.get_order_info(order_code) + # 检验列设置为可编辑状态 for i, config in enumerate(enabled_configs): col_index = 2 + i # 检验列从第3列开始 @@ -781,7 +761,7 @@ class MainWindow(MainWindowUI): 'remark': '', 'tray_id': tray_id }] - inspection_dao.save_inspection_data(order_id, data) + inspection_dao.save_inspection_data(self._current_order_code,gc_note, data) logging.info(f"自动填充字段 {config_name} 值为 {value}") # 设置单元格属性以标识其关联的检验项 @@ -827,7 +807,7 @@ class MainWindow(MainWindowUI): 'remark': '', 'tray_id': tray_id }] - inspection_dao.save_inspection_data(order_id, data) + inspection_dao.save_inspection_data(self._current_order_code,gc_note,gc_note, data) # 为贴标和称重也创建空记录 for position in [11, 12, 13]: # 11是贴标,12是毛重,13是净重 @@ -839,9 +819,9 @@ class MainWindow(MainWindowUI): 'remark': '', 'tray_id': tray_id }] - inspection_dao.save_inspection_data(order_id, data) + inspection_dao.save_inspection_data(self._current_order_code,gc_note, data) - logging.info(f"已添加工程号 {order_id} 的新记录,显示在第{new_seq}条") + logging.info(f"已添加工程号 {gc_note} 的新记录,显示在第{new_seq}条") except Exception as e: logging.error(f"添加新记录失败: {str(e)}") @@ -891,12 +871,12 @@ class MainWindow(MainWindowUI): return # 获取工程号 - order_id_item = self.process_table.item(row, 1) - if not order_id_item: + order_item = self.process_table.item(row, 1) + if not order_item: return - order_id = order_id_item.text().strip() - if not order_id: + gc_note = order_item.text().strip() + if not gc_note: return # 获取托盘号 @@ -942,7 +922,7 @@ class MainWindow(MainWindowUI): status = 'warning' # 保存到数据库 - self.save_inspection_data(order_id, tray_id, config['position'], config['id'], value, status) + self.save_inspection_data(self._current_order_code, gc_note, tray_id, config['position'], config['id'], value, status) # 判断是否是包装列 elif column == packaging_start_col: @@ -952,7 +932,7 @@ class MainWindow(MainWindowUI): # 设置单元格颜色为通过 cell_item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色 # 保存贴标数据,position和config_id都是11 - self.save_inspection_data(order_id, tray_id, 11, 11, value, status) + self.save_inspection_data(self._current_order_code, gc_note, tray_id, 11, 11, value, status) elif column == packaging_start_col + 1: # 毛重列 @@ -961,7 +941,7 @@ class MainWindow(MainWindowUI): # 设置单元格颜色为通过 cell_item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色 # 保存毛重数据,position和config_id都是12 - self.save_inspection_data(order_id, tray_id, 12, 12, value, status) + self.save_inspection_data(self._current_order_code, gc_note, tray_id, 12, 12, value, status) elif column == packaging_start_col + 2: # 净重列 data_type = "净重" @@ -969,10 +949,10 @@ class MainWindow(MainWindowUI): # 设置单元格颜色为通过 cell_item.setBackground(QBrush(QColor("#c8e6c9"))) # 浅绿色 # 保存净重数据,position和config_id都是13 - self.save_inspection_data(order_id, tray_id, 13, 13, value, status) + self.save_inspection_data(self._current_order_code, gc_note, tray_id, 13, 13, value, status) # 记录详细日志 - logging.info(f"处理单元格变更: 行={row}, 列={column}, 类型={data_type}, 工程号={order_id}, 值={value}, 状态={status}") + logging.info(f"处理单元格变更: 行={row}, 列={column}, 类型={data_type}, 工程号={gc_note}, 值={value}, 状态={status}") except Exception as e: logging.error(f"处理检验单元格变更失败: {str(e)}") @@ -1043,11 +1023,12 @@ class MainWindow(MainWindowUI): logging.error(f"验证检验值失败: {str(e)}") return False - def save_inspection_data(self, order_id, tray_id, position, config_id, value, status): + def save_inspection_data(self, order_id, gc_note, tray_id, position, config_id, value, status): """保存检验数据到数据库 Args: - order_id: 工程号 + order_id: 订单号 + gc_note: 工程号 position: 位置序号 config_id: 配置ID value: 检验值 @@ -1059,7 +1040,7 @@ class MainWindow(MainWindowUI): modbus = ModbusUtils() client = modbus.get_client() # 记录保存前的详细日志 - logging.info(f"正在保存检验数据: 工程号={order_id}, 托盘号={tray_id}, 位置={position}, 配置ID={config_id}, 值={value}, 状态={status}") + logging.info(f"正在保存检验数据: 工程号={gc_note}, 托盘号={tray_id}, 位置={position}, 配置ID={config_id}, 值={value}, 状态={status}") # 构建数据 data = [{ @@ -1072,7 +1053,7 @@ class MainWindow(MainWindowUI): }] # 保存到数据库 - inspection_dao.save_inspection_data(order_id, data) + inspection_dao.save_inspection_data(order_id, gc_note, data) except Exception as e: logging.error(f"保存检验数据失败: {str(e)}") # 显示错误消息 @@ -1149,10 +1130,10 @@ class MainWindow(MainWindowUI): # 按工程号分组 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) + gc_note = data['gc_note'] + if gc_note not in orders_data: + orders_data[gc_note] = [] + orders_data[gc_note].append(data) # 添加数据到表格 - 从第3行开始添加数据 row_idx = 2 @@ -1160,10 +1141,10 @@ class MainWindow(MainWindowUI): # 使用DAO方法按创建时间排序工程号,确保FIFO顺序(最早创建的在最前面) from dao.inspection_dao import InspectionDAO inspection_dao = InspectionDAO() - sorted_order_ids = inspection_dao.get_orders_by_create_time(list(orders_data.keys())) + sorted_gc_notes = inspection_dao.get_orders_by_create_time(list(orders_data.keys())) - for order_id in sorted_order_ids: - items = orders_data[order_id] + for gc_note in sorted_gc_notes: + items = orders_data[gc_note] # 添加新行 self.process_table.insertRow(row_idx) @@ -1174,7 +1155,7 @@ class MainWindow(MainWindowUI): self.process_table.setItem(row_idx, 0, seq_item) # 添加工程号到第二列 - order_item = QTableWidgetItem(order_id) + order_item = QTableWidgetItem(gc_note) order_item.setTextAlignment(Qt.AlignCenter) self.process_table.setItem(row_idx, 1, order_item) @@ -1251,7 +1232,7 @@ class MainWindow(MainWindowUI): finally: self._loading_data_in_progress = False - def load_finished_record_to_package_record(self, order_id, tray_id): + def load_finished_record_to_package_record(self, order_id, gc_note, tray_id): """加载已完成检验数据到包装记录 Args: @@ -1263,10 +1244,10 @@ class MainWindow(MainWindowUI): inspection_dao = InspectionDAO() # 获取该工程号的所有检验数据 - inspection_data = inspection_dao.get_inspection_data_by_order(order_id, tray_id) + inspection_data = inspection_dao.get_inspection_data_by_order(order_id, gc_note, tray_id) if not inspection_data: - logging.warning(f"未找到工程号 {order_id} 托盘号 {tray_id} 的检验数据") + logging.warning(f"未找到工程号 {gc_note} 托盘号 {tray_id} 的检验数据") return # 从检验数据中获取贴标和称重数据 @@ -1286,18 +1267,18 @@ class MainWindow(MainWindowUI): 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 + # # 获取当前包装记录,检查是否已经存在相同的记录 TODO 暂时不判断,可能存在多次包装情况 + # 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,net_weight_value, finish_time) + inspection_dao.save_package_record(order_id, tray_id, label_value, weight_value,net_weight_value, finish_time,gc_note) # 回显数据,但避免循环调用 if not getattr(self, '_loading_data_in_progress'): @@ -1329,7 +1310,7 @@ class MainWindow(MainWindowUI): self.update_package_statistics() return - # 读取已包装的记录信息,然后回显到 UI + # 读取已包装的记录信息 package_record = inspection_dao.get_package_record(tray_id) # 记录获取的数据情况 @@ -1338,110 +1319,55 @@ class MainWindow(MainWindowUI): else: logging.info(f"包装记录为空,托盘号={tray_id}") - # 完全清空包装记录表格(包括所有行) + # 清空表格内容 self.record_table.setRowCount(0) # 断开包装记录表的信号连接(如果有) try: - # 检查是否已经连接了cellChanged信号 - if self.record_table.receivers(self.record_table.cellChanged) > 0: - self.record_table.cellChanged.disconnect() - except TypeError: - # 忽略"Failed to disconnect"类型错误 - pass + self.record_table.blockSignals(True) # 使用blockSignals替代手动断开信号 except Exception as e: - logging.warning(f"断开record_table.cellChanged信号失败: {str(e)}") + logging.warning(f"阻止信号失败: {str(e)}") - # 设置表头固定不动 - self.record_table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) - self.record_table.horizontalHeader().setStretchLastSection(False) - self.record_table.horizontalHeader().setSectionsMovable(False) - self.record_table.horizontalHeader().setSectionsClickable(False) - - # 设置表头标签 - self.record_table.setHorizontalHeaderLabels(["序号", "订单", "品名", "规格", "托号", "轴包装号", "毛重", "净重", "完成时间"]) - self.record_table.horizontalHeader().setVisible(True) - - # 设置表头样式 - self.record_table.horizontalHeader().setStyleSheet(""" - QHeaderView::section { - background-color: #f8f8f8; - padding: 4px; - border: 1px solid #dddddd; - font-weight: bold; - } - """) - - # 设置列宽 - column_widths = [70, 200, 130, 130, 160, 120, 120, 120, 160] - for col, width in enumerate(column_widths): - self.record_table.setColumnWidth(col, width) - self.record_table.horizontalHeader().resizeSection(col, width) - - # 检查是否有包装记录数据 + # 如果没有包装记录,直接返回 if not package_record: logging.info(f"托盘号 {tray_id} 没有包装记录数据") - # 表格已清空,不需要再设置行数 - # 更新包装记录统计数据 self.update_package_statistics() + self.record_table.blockSignals(False) # 恢复信号 return logging.info(f"托盘号 {tray_id} 已加载包装记录,共 {len(package_record)} 条记录") # 添加所有包装记录到表格 for index, item in enumerate(package_record): - # 在包装记录表中添加新行 - row_index = self.record_table.rowCount() # 获取当前行数,从0开始 - self.record_table.insertRow(row_index) - - # 设置包装记录数据 - # 序号 - 第1列 - seq_item = QTableWidgetItem(str(index + 1)) - 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) - - # 净重 - 第8列 - net_weight_item = QTableWidgetItem(str(item[6])) - net_weight_item.setTextAlignment(Qt.AlignCenter) - self.record_table.setItem(row_index, 7, net_weight_item) - - # 包装时间 - pack_time = QTableWidgetItem(str(item[7])) - pack_time.setTextAlignment(Qt.AlignCenter) - self.record_table.setItem(row_index, 8, pack_time) - - # 设置表格不可编辑 - self.record_table.setEditTriggers(QTableWidget.NoEditTriggers) + try: + row_index = self.record_table.rowCount() + self.record_table.insertRow(row_index) + + # 设置单元格数据,使用安全的方式访问数据 + cell_data = [ + str(index + 1), # 序号 + str(item[0]) if len(item) > 0 else "", # 订单 + str(item[1]) if len(item) > 1 else "", # 工程号 + str(item[2]) if len(item) > 2 else "", # 品名 + str(item[3]) if len(item) > 3 else "", # 规格 + str(item[4]) if len(item) > 4 else "", # 托号 + str(item[5]) if len(item) > 5 else "", # 轴包装号 + str(item[6]) if len(item) > 6 else "", # 毛重 + str(item[7]) if len(item) > 7 else "", # 净重 + str(item[8]) if len(item) > 8 else "" # 完成时间 + ] + + # 批量设置单元格 + for col, data in enumerate(cell_data): + cell_item = QTableWidgetItem(data) + cell_item.setTextAlignment(Qt.AlignCenter) + self.record_table.setItem(row_index, col, cell_item) + except Exception as e: + logging.error(f"设置第 {index} 行数据时出错: {str(e)}, 数据: {item}") + continue # 继续处理下一行 + + # 恢复信号 + self.record_table.blockSignals(False) # 更新包装记录统计数据 self.update_package_statistics() @@ -1449,6 +1375,7 @@ class MainWindow(MainWindowUI): except Exception as e: logging.error(f"显示包装记录失败: {str(e)}") + self.record_table.blockSignals(False) # 确保信号被恢复 QMessageBox.warning(self, "显示失败", f"显示包装记录失败: {str(e)}") def update_package_statistics(self): """更新包装记录统计数据""" @@ -1729,13 +1656,13 @@ class MainWindow(MainWindowUI): return # 获取工程号 - order_id_item = self.process_table.item(data_row, 1) - if not order_id_item: + gc_note = self.process_table.item(data_row, 1) + if not gc_note: logging.warning("无法获取工程号") return - order_id = order_id_item.text().strip() - if not order_id: + gc_note = gc_note.text().strip() + if not gc_note: logging.warning("工程号为空") return @@ -1752,14 +1679,14 @@ class MainWindow(MainWindowUI): # 保存到数据库 tray_id = self.tray_edit.currentText() - self.save_inspection_data(order_id, tray_id, 12, 12, str(weight), "pass") + self.save_inspection_data(self._current_order_code, gc_note, tray_id, 12, 12, str(weight), "pass") # 保存净重到数据库(毛重-工字轮重量,TODO :先默认工字轮重量为10g后续从接口获取) from dao.inspection_dao import InspectionDAO inspection_dao = InspectionDAO() - gzl_zl = inspection_dao.get_gzl_zl(order_id) + gzl_zl = inspection_dao.get_gzl_zl(self._current_order_code) net_weight = float(weight) - float(gzl_zl) - self.save_inspection_data(order_id, tray_id, 13, 13, str(net_weight), "pass") + self.save_inspection_data(self._current_order_code, gc_note, tray_id, 13, 13, str(net_weight), "pass") # 设置净重单元格 net_weight_item = QTableWidgetItem(str(net_weight)) @@ -1811,8 +1738,8 @@ class MainWindow(MainWindowUI): logging.warning("无法获取工程号") return - order_id = order_id_item.text().strip() - if not order_id: + gc_note = order_id_item.text().strip() + if not gc_note: logging.warning("工程号为空") return @@ -1843,11 +1770,11 @@ class MainWindow(MainWindowUI): logging.info(f"已将贴标数据 {axios_num} 写入表格单元格 [{data_row}, {label_col}]") # 保存贴标数据到数据库 - self.save_inspection_data(order_id, tray_id, 11, 11, axios_num, "pass") + self.save_inspection_data(self._current_order_code, gc_note, tray_id, 11, 11, axios_num, "pass") # 调用加载到包装记录的方法 - self.load_finished_record_to_package_record(order_id, tray_id) - logging.info(f"贴标完成,已将工程号 {order_id} 的记录加载到包装记录") + self.load_finished_record_to_package_record(self._current_order_code,gc_note, tray_id) + logging.info(f"贴标完成,已将工程号 {gc_note} 的记录加载到包装记录") # 删除当前处理的行 self.process_table.removeRow(data_row) @@ -1859,16 +1786,16 @@ class MainWindow(MainWindowUI): inspection_dao = InspectionDAO() # 调用接口 gc_api = GcApi() - axios_num = self.get_axios_num_by_order_id(order_id) + axios_num = self.get_axios_num_by_order_id(gc_note) # 获取订单信息和其他信息,两者都已经是字典格式 info = {} - order_info = inspection_dao.get_order_info(order_id) + order_info = inspection_dao.get_order_info(gc_note) info.update(order_info) # 获取包装号 xpack = gc_api.get_xpack(order_info["ddmo"]) info['xpack'] = xpack['xpack'] info['spack'] = xpack['spack'] - order_others_info = inspection_dao.get_order_others_info(order_id, tray_id) + order_others_info = inspection_dao.get_order_others_info(gc_note, self._current_order_code, tray_id) info.update(order_others_info) info['data_corp'] = 'T' info['zh'] = axios_num @@ -2392,4 +2319,10 @@ class MainWindow(MainWindowUI): self._loading_data_in_progress = prev_loading_state except Exception as e: - logging.error(f"处理托盘号变更失败: {str(e)}") \ No newline at end of file + logging.error(f"处理托盘号变更失败: {str(e)}") + + def handle_order_code_received(self, order_code): + """处理从加载对话框接收到的订单号""" + logging.info(f"主窗口接收到订单号: {order_code}") + # 存储当前订单号 + self._current_order_code = order_code \ No newline at end of file diff --git a/widgets/unloading_dialog_widget.py b/widgets/unloading_dialog_widget.py index 2483d18..e423c8d 100644 --- a/widgets/unloading_dialog_widget.py +++ b/widgets/unloading_dialog_widget.py @@ -135,7 +135,7 @@ class UnloadingDialog(UnloadingDialogUI): logging.info(f"设置主窗口当前托盘号: {tray_code}") else: # 获取托盘信息失败 - error_msg = response.get("message", "获取托盘信息失败") + error_msg = response.get("message", "未找到托盘信息") logging.warning(f"查询失败: {error_msg}") QMessageBox.warning(self, "查询失败", error_msg) except Exception as e: