From 0906f188fb0e374c49a763622445fd937f96c903 Mon Sep 17 00:00:00 2001 From: zhu-mengmeng <15588200382@163.com> Date: Wed, 18 Jun 2025 15:48:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A6=82=E6=9E=9C=E5=BC=80=E5=90=AF=20?= =?UTF-8?q?api=20=E6=8E=A5=E5=8F=A3=EF=BC=8C=E9=82=A3=E4=B9=88=E5=B0=B1?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apis/gc_api.py | 83 +++++ config/app_config.json | 7 +- dao/gc_dao.py | 29 ++ dao/inspection_dao.py | 252 +++++++++++++- db/jtDB.db | Bin 65536 -> 77824 bytes from pymodbus.py | 8 +- tests/test_gc_api.py | 48 +++ utils/api_utils.py | 21 +- widgets/loading_dialog_widget.py | 35 +- widgets/login_widget.py | 6 +- widgets/main_window.py | 308 ++++++++++++------ ...'JT2504019', 'type_name': '不锈钢丝.groovy | 37 +++ 12 files changed, 709 insertions(+), 125 deletions(-) create mode 100644 apis/gc_api.py create mode 100644 dao/gc_dao.py create mode 100644 tests/test_gc_api.py create mode 100644 widgets/{'note': 'JT2504019', 'type_name': '不锈钢丝.groovy diff --git a/apis/gc_api.py b/apis/gc_api.py new file mode 100644 index 0000000..b981c21 --- /dev/null +++ b/apis/gc_api.py @@ -0,0 +1,83 @@ +from utils.api_utils import ApiUtils +import logging +import json +class GcApi: + def __init__(self): + """初始化托盘API工具类""" + self.api_utils = ApiUtils() + + def get_gc_info(self, gc_code): + """ + 获取GC信息 + + Args: + gc_code: GC编号 + + Returns: + dict: GC信息 + """ + try: + # API 配置中的键名 + api_key = "get_gc_info" + # 构建 form-data 格式的数据 + data = { + "sc_gch": gc_code, + "data_corp":"JT" + } + # 将工程号作为参数传递,使用 data 参数传递 form-data 格式数据 + response = self.api_utils.post(api_key, data=data) + + # 请求失败时返回空数据 + if not response.get("status", False): + return { + "success": False, + "message": "获取GC信息失败", + "data": None + } + return response + except Exception as e: + logging.error(f"获取GC信息失败: {str(e)}") + return None + def get_order_info(self, order_code): + """ + 获取订单信息 + """ + try: + # API 配置中的键名 + api_key = "get_order_info" + # 构建 form-data 格式的数据 + order_dict = {"srch_mo":order_code,"data_corp":"JT"} + data = { + "parms": json.dumps(order_dict), # 必须将数据序列化为JSON字符串 + "pageIndex": 0, + "pageSize": 10, + "sortField": "", + "sortOrder": "" + } + # 将工程号作为参数传递,使用 data 参数传递 form-data 格式数据 + response = self.api_utils.post(api_key, data=data) + return response + except Exception as e: + logging.error(f"获取订单信息失败: {str(e)}") + return None + def add_order_info(self, info): + """ + 添加订单信息 + """ + try: + # API 配置中的键名 + api_key = "add_order_info" + # 构建 form-data 格式的数据 + data = { + "parms": json.dumps(info), # 必须将数据序列化为JSON字符串 + "pageIndex": 0, + "pageSize": 10, + "sortField": "", + "sortOrder": "" + } + # 将工程号作为参数传递,使用 data 参数传递 form-data 格式数据 + response = self.api_utils.post(api_key, data=data) + return response + except Exception as e: + logging.error(f"添加订单信息失败: {str(e)}") + return None \ No newline at end of file diff --git a/config/app_config.json b/config/app_config.json index 243cfd4..a46b7fb 100644 --- a/config/app_config.json +++ b/config/app_config.json @@ -8,10 +8,13 @@ "enable_camera": false }, "base_url": "http://localhost:8084", - "mode": "standalone" + "mode": "api" }, "apis": { - "get_tray_info": "/apjt/xcsc/tpda/getByTp_note/" + "get_tray_info": "/apjt/xcsc/tpda/getByTp_note/", + "get_gc_info": "/jsjt/xcsc/tprk/getBZGCInfoToWsbz.do", + "get_order_info": "/jsjt/xcsc/tprk/getXsddBzrkGridListToWsbz.do", + "add_order_info": "/jsjt/xcsc/tprk/bzrkAdd01.do" }, "database": { "default": "sqlite", diff --git a/dao/gc_dao.py b/dao/gc_dao.py new file mode 100644 index 0000000..50b66ce --- /dev/null +++ b/dao/gc_dao.py @@ -0,0 +1,29 @@ +import json +import logging +from datetime import datetime +from utils.sql_utils import SQLUtils + +class GcDao: + """检验项目配置和数据访问对象""" + + def __init__(self): + """初始化数据访问对象""" + self.db = SQLUtils('sqlite', database='db/jtDB.db') + + def __del__(self): + """析构函数,确保数据库连接关闭""" + if hasattr(self, 'db'): + self.db.close() + + def get_gc_info_by_id(self, id): + """根据id获取GC信息""" + try: + sql = """ + SELECT * FROM wsbz_gc_info WHERE id = ? + """ + self.db.cursor.execute(sql, (id,)) + return self.db.cursor.fetchone() + except Exception as e: + logging.error(f"获取GC信息失败: {str(e)}") + return None + \ No newline at end of file diff --git a/dao/inspection_dao.py b/dao/inspection_dao.py index 8773de9..d9e1f59 100644 --- a/dao/inspection_dao.py +++ b/dao/inspection_dao.py @@ -214,7 +214,72 @@ class InspectionDAO: except Exception as e: logging.error(f"更新检验项目启用状态失败: {str(e)}") return False - + def save_order_info(self, order_id,data): + """保存订单信息到 wsbz_order_info 表 + + Args: + data: 订单信息字典 + + Returns: + bool: 操作是否成功 + """ + try: + 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 ( + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? + ) + """ + + params = ( + data.get("data_corp", "JT"), + data.get("user_id", ""), + data.get("user_name", ""), + data.get("zx_zl", ""), + data.get("note", ""), + data.get("xpack", ""), + order_id if order_id else "", + data.get("qd", ""), + data.get("spack_type", ""), + data.get("mxzs", ""), + data.get("jt", ""), + data.get("note", ""), + data.get("code", ""), + data.get("type", ""), + data.get("template_name", ""), + data.get("lib", ""), + data.get("zx_code", ""), + data.get("maxsl", ""), + data.get("cz", ""), + data.get("size", ""), + data.get("cd", ""), + data.get("luno", ""), + data.get("qfqd", ""), + data.get("khno", ""), + data.get("size", ""), + data.get("ysl", ""), + data.get("dycz", ""), + data.get("zh", ""), + data.get("edit_id", ""), + data.get("remarks", ""), + ) + + self.db.cursor.execute(sql, params) + self.db.conn.commit() + return True + + except Exception as e: + logging.error(f"保存订单信息失败: {str(e)}") + self.db.conn.rollback() + return False def save_inspection_data(self, order_id, data, username='system'): """保存检验数据 @@ -314,7 +379,7 @@ class InspectionDAO: 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}) - ORDER BY d.create_time, d.order_id, d.position + ORDER BY d.create_time """ params = [tray_id] + order_ids @@ -384,8 +449,7 @@ class InspectionDAO: return data_list except Exception as e: logging.error(f"获取检验数据失败: {str(e)}") - return [] - + return [] def get_package_record(self, tray_id): """根据托盘号获取包装记录 @@ -458,4 +522,182 @@ class InspectionDAO: self.db.conn.commit() except Exception as e: logging.error(f"删除检验数据失败: {str(e)}") - self.db.conn.rollback() \ No newline at end of file + self.db.conn.rollback() + def get_axios_num_by_order_id(self, order_id): + """获取托盘号对应的轴号""" + try: + sql = """ + SELECT max(axis_package_id) as axios_num FROM wsbz_inspection_pack_data WHERE order_id = ? + AND is_deleted = FALSE + """ + params = (order_id,) + self.db.cursor.execute(sql, params) + result = self.db.cursor.fetchone() + return int(result[0]) if result else 0 + except Exception as e: + logging.error(f"获取轴号失败: {str(e)}") + return 0 + def get_axios_num(self, tray_id): + """获取托盘号对应的轴号""" + try: + sql = """ + SELECT max(axis_package_id) as axios_num FROM wsbz_inspection_pack_data WHERE tray_id = ? + AND is_deleted = FALSE + """ + params = (tray_id,) + self.db.cursor.execute(sql, params) + result = self.db.cursor.fetchone() + return int(result[0]) if result else 0 + except Exception as e: + logging.error(f"获取轴号失败: {str(e)}") + return 0 + def get_gzl_zl(self,order_id): + """获取工字轮重量""" + try: + sql = """ + SELECT gzl_zl FROM wsbz_order_info WHERE sc_gch = ? + """ + params = (order_id,) + self.db.cursor.execute(sql, params) + result = self.db.cursor.fetchone() + return result[0] if result else 0 + except Exception as e: + logging.error(f"获取工字轮重量失败: {str(e)}") + return 0 + + def get_order_create_time(self, order_id): + """获取工程号的最早创建时间 + + Args: + order_id: 工程号 + + Returns: + str: 创建时间,格式为'YYYY-MM-DD HH:MM:SS',如果未找到则返回None + """ + try: + sql = """ + SELECT MIN(create_time) FROM wsbz_inspection_data + WHERE order_id = ? AND is_deleted = FALSE + """ + self.db.cursor.execute(sql, (order_id,)) + result = self.db.cursor.fetchone() + return result[0] if result and result[0] else None + except Exception as e: + logging.error(f"获取工程号创建时间失败: {str(e)}") + return None + + def get_orders_by_create_time(self, order_ids): + """按创建时间排序工程号 + + Args: + order_ids: 工程号列表 + + Returns: + list: 按创建时间排序的工程号列表 + """ + try: + if not order_ids: + return [] + + # 构建IN子句 + placeholders = ','.join(['?' for _ in order_ids]) + + # 查询每个工程号的最早创建时间并排序 + sql = f""" + SELECT order_id, MIN(create_time) as first_create_time + FROM wsbz_inspection_data + WHERE order_id IN ({placeholders}) AND is_deleted = FALSE + GROUP BY order_id + ORDER BY first_create_time + """ + + self.db.cursor.execute(sql, order_ids) + results = self.db.cursor.fetchall() + + # 提取排序后的工程号 + sorted_order_ids = [row[0] for row in results] + + # 确保所有传入的工程号都在结果中 + for order_id in order_ids: + if order_id not in sorted_order_ids: + sorted_order_ids.append(order_id) + + return sorted_order_ids + except Exception as e: + logging.error(f"按创建时间排序工程号失败: {str(e)}") + return order_ids # 出错时返回原始顺序 + + def get_order_info(self, order_id): + """获取订单信息 + + Args: + order_id: 工程号 + + Returns: + dict: 订单信息字典 + """ + 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 = ? + """ + params = (order_id,) + self.db.cursor.execute(sql, params) + result = self.db.cursor.fetchone() + + if not result: + return {} + + # 获取列名 + column_names = [desc[0] for desc in self.db.cursor.description] + + # 转换为字典 + result_dict = {} + for i, value in enumerate(result): + if i < len(column_names): + result_dict[column_names[i]] = value + + return result_dict + except Exception as e: + logging.error(f"获取订单信息失败: {str(e)}") + return {} + def get_order_others_info(self, order_id, tray_id): + """获取订单其他信息 + + Args: + order_id: 工程号 + tray_id: 托盘号 + + Returns: + dict: 订单其他信息字典,以name为key,value为值 + """ + try: + sql = """ + 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 = ? + 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) + self.db.cursor.execute(sql, params) + results = self.db.cursor.fetchall() + + if not results: + return {} + + # 将结果转换为字典,以name为key,value为值 + result_dict = {} + for row in results: + if len(row) >= 3: # 确保行至少有3个元素 + name = row[1] # name在第二列 + value = row[2] # value在第三列 + result_dict[name] = value + + return result_dict + except Exception as e: + logging.error(f"获取订单其他信息失败: {str(e)}") + return {} \ No newline at end of file diff --git a/db/jtDB.db b/db/jtDB.db index f553f26f16ce21bc47d18b3d62ee542362ed091e..e64b73d84755e8e528e284bd5f83650e37a9309e 100644 GIT binary patch literal 77824 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 M#Nx(2IA2ZvKUcC<>i_@% delta 6173 zcmb_gd2AHd8J}y9+1;73v5i?4I}523sPOXMT)R6-+8QuKX#yk=!r>e?Ho*iNgE@m? zGpnQu3J9#1Do9bFshSAIX&S|CsT!#bEf|#?sQl4NRhp2h3Q0q&9;vFfr0IKe?u!(R!1Is65q^W{8#TG(|^z(14pW=b3s zZxKG`zso-qA7KALZ>Cp{9{7EdK6uL$jFf0T_1R3Cjhz~Z)6ekZT-{$6%uw(;p5Hm# zw_T6`6&J=R;UCgoVQgId+8l|Iev0JfOIsE*(u&q@in_WO{=rC};(sYo`j_SfzQcI?q#t+hFAMrFUj8f8m@t@)e zu~Ya&7#**#+b@V~lGCW0vpm+XWRnzn;ki4-HHpBZ|By%Vz@z()<43W;qgRjL)j)I8 zs5VzuuC0xpO(E&TP@_q)7QkCZ9ANas&~4bO9Q`gORV7aRhL{wd5`@gY^vCI*)NfKN z`M3DasHKvc zZ}}h>4Y^p*bOjdSP|$}OsDuum%(mKM4hv>%TF@NYdtlZBK@CthASjfIrBXQ@pa+$K z6F|gL4>!4bG*X$n+E1OFhed;APb-vVSd_swPe%yS!UZ%5M^_FUp(Si!Mnwsc= zpn|Cf1x0~c3HkDbkZ~m&YG-fP}>;= zDG+@y)|l~S6$K4f4znhgA#pANAsc}>v5k@ev;qLKQUtq0Haw_QBsMC(Y{|){$)&@A zIlTy?d(nqo zM3i}LvUyE~8pP(cS{s_7LPLWE6=;fDoE-(ZY@pp^V#QyfJGmH%TYgBxo>}yBq`~bUwx`}y~jc<;pWADU{#8z;haEGLy zOOH#P;w8}(7mG1rLg*Hl%*&Zo>8t5)r5B~+sdK3(Q#bNwk|&wZ`3>w3nP-#riHix8 zD8w&tZR~q^Gq;$HF%!&2hNoYq_s|RJ40VyZhDo2zFxtB;ag0urNN9*gFEq#SZbB{l zet)p3iS07CAn}E4TqdCwQT@pV4p)#)-g`~>-6}hNI-S*HK7#H(IYWSQI_*4aS0*h| zob)*ox0;(#{fpU~WR~>^ao_XMDFsio-xg(<>xmlXCbZ(k?3d*033izeTM=5xw46mx zeP?>JwYPFNGG2HaNq7u|=+Wm}eKB_kI$~Yb6w!ENnQ#We2~e!Ph4bb@;)OihQ{{=; zyI|R8ZBpI>%eG2@#Z$S4Qe2q<9iC{y7OkN)Le!|n38igi&wPX+pQ6^` zN?px9Sf$bH6WJWRcEQ_ig3FCwi1lO7SEJh`pQ9f5YGBTN9k;>#`N)CmA?G-+?41$8@QR>*n!i!0s}tvEpaHQ68zZw#b*rMVj`=6PW% zkG(qiqV9H?yGRKyQAr7_0ZQ?(v=3%ZT09#rpalnRkGazxV=8*&WDZ^VlrRf5Iy@EzZP73blSK`4fUqz-aNG^}<>-8xZf4h$tG%9Y zj?nK*Ph`YIv!>x&z8&2?Tl&!5Uu}FQpQ9T`zxS2#_vwGrt@BfP{2A!R*LD5fTgd-+ zb#LFWseAie4a`fO8fl>)XUMJK)BJth>(pH4%|zx{=AKL@J;5S&0lovfg?Tge9RGcO zC$A@emE4=0mG~&}T4E%zFn&dPNm?zniXVzE;k!p!_zds0jtHxSZ00>~ZT!jj&9O5v ziv2s@Hw}}0QzO}Jpys!4M|0kpK)*QCi+(iG!^L{3PCWQKQ2W_lj{ggFKmO5$M$h)p z6#CoQv-K;hd68LdAl`rkHweY*4VI+!=D^pKIed~%rx85YfL=YF zYH|2es;#yZ=}$UHwwa8|CX=5Y6;3$HYd z|MvWkX)aAuci?cApaMCHpbC>ywgozrJV@eK76zU=H_TPE0Mjr?X>KXMR=3!aF 0 else "", - "product_name": pallet_info[1] if len(pallet_info) > 1 else "", - "axis_type": pallet_info[4] if len(pallet_info) > 4 else "", - "tier": str(pallet_info[5]) if len(pallet_info) > 5 else "", - "weight": str(pallet_info[8]) if len(pallet_info) > 8 else "", - "quantity": "" + try: + response = { + "success": True, + "data": { + "tp_note": pallet_info[0] if isinstance(pallet_info, tuple) and len(pallet_info) > 0 else "", + "product_name": pallet_info[1] if isinstance(pallet_info, tuple) and len(pallet_info) > 1 else "", + "axis_type": pallet_info[4] if isinstance(pallet_info, tuple) and len(pallet_info) > 4 else "", + "tier": str(pallet_info[5]) if isinstance(pallet_info, tuple) and len(pallet_info) > 5 else "", + "weight": str(pallet_info[8]) if isinstance(pallet_info, tuple) and len(pallet_info) > 8 else "", + "quantity": "" + } + } + except (IndexError, TypeError) as e: + logging.warning(f"处理托盘信息时出错: {str(e)}, pallet_info类型: {type(pallet_info)}") + # 如果pallet_info是字符串或其他非元组类型,创建一个基本响应 + response = { + "success": True, + "data": { + "tp_note": tray_code, + "product_name": "", + "axis_type": "", + "tier": "", + "weight": "", + "quantity": "" + } } - } logging.info(f"托盘信息响应: {response}") diff --git a/widgets/login_widget.py b/widgets/login_widget.py index eda75bb..9ffb786 100644 --- a/widgets/login_widget.py +++ b/widgets/login_widget.py @@ -25,7 +25,7 @@ def get_user_info(user_id): try: # 始终使用SQLite数据源获取用户信息 db = SQLUtils(source_name='sqlite') - db.execute_query("SELECT username, 'Default Corp', 1, 1 FROM user WHERE username = ?", (user_id,)) + db.execute_query("SELECT username, corp_id as corp_name, corp_id FROM wsbz_user WHERE username = ?", (user_id,)) result = db.fetchone() db.close() if result: @@ -70,7 +70,7 @@ class LoginWidget(LoginUI): return if check_user_login(user_id, password): try: - user_name, corp_name, corp_id, position_id = get_user_info(user_id) + user_name, corp_name, corp_id = get_user_info(user_id) if not corp_name: corp_name = "未知公司" # 移除登录成功的弹框 @@ -81,7 +81,7 @@ class LoginWidget(LoginUI): try: import logging logging.info(f"正在创建主窗口,用户ID: {user_id}, 姓名: {user_name}, 公司: {corp_name}") - self.main_window = MainWindow(user_id, user_name, corp_name, corp_id, position_id) + self.main_window = MainWindow(user_id, user_name, corp_name, corp_id) self.main_window.showMaximized() # 窗口最大化显示 logging.info("主窗口已显示(最大化)") except Exception as e: diff --git a/widgets/main_window.py b/widgets/main_window.py index 3680751..f96befb 100644 --- a/widgets/main_window.py +++ b/widgets/main_window.py @@ -6,6 +6,8 @@ from datetime import datetime from pathlib import Path from utils.modbus_utils import ModbusUtils from utils.modbus_monitor import get_instance as get_modbus_monitor +from utils.app_mode import AppMode +from apis.gc_api import GcApi from utils.register_handlers import ( NGHandler, WeightDataHandler, @@ -44,14 +46,13 @@ from utils.serial_manager import SerialManager class MainWindow(MainWindowUI): """主窗口""" - def __init__(self, user_id=None, user_name=None, corp_name=None, corp_id=None, position_id=None): + def __init__(self, user_id=None, user_name=None, corp_name=None, corp_id=None): super().__init__() self.user_id = user_id self.user_name = user_name self.corp_name = corp_name self.corp_id = corp_id - self.position_id = position_id self.init_seq = {} # 初始化轴包装的序号 self._loading_data_in_progress = False # 数据加载状态标志,防止循环调用 @@ -172,51 +173,18 @@ class MainWindow(MainWindowUI): # 加载托盘号列表 self.load_pallet_codes() - - # def add_pallet_type_selectors(self): - # """添加托盘类型选择下拉框""" - # # 创建上料托盘类型选择下拉框 - # self.input_pallet_type_label = QLabel("上料托盘类型:") - # self.input_pallet_type_label.setFont(self.normal_font) - # self.input_pallet_type_label.setVisible(False) - # self.material_form_layout.addRow(self.input_pallet_type_label) - - # self.input_pallet_type_combo = QComboBox() - # self.input_pallet_type_combo.setFont(self.normal_font) - # self.input_pallet_type_combo.setVisible(False) - # self.material_form_layout.addRow("", self.input_pallet_type_combo) - - # # 创建下料托盘类型选择下拉框 - # self.output_pallet_type_label = QLabel("下料托盘类型:") - # self.output_pallet_type_label.setFont(self.normal_font) - # self.output_pallet_type_label.setVisible(False) - # self.output_form_layout.addRow(self.output_pallet_type_label) - - # self.output_pallet_type_combo = QComboBox() - # self.output_pallet_type_combo.setFont(self.normal_font) - # self.output_pallet_type_combo.setVisible(False) - # self.output_form_layout.addRow("", self.output_pallet_type_combo) - - # # 加载托盘类型数据 - # self.update_pallet_types() - - # def update_pallet_types(self): - # """更新托盘类型下拉框""" - # # 重新加载托盘类型数据 - # self.pallet_type_manager.reload_pallet_types() - - # # 更新上料托盘类型 - # input_types = self.pallet_type_manager.get_pallet_types_by_operation("input") - # self.input_pallet_type_combo.clear() - # for pallet_type in input_types: - # self.input_pallet_type_combo.addItem(pallet_type['type_name'], pallet_type['id']) - - # # 更新下料托盘类型 - # output_types = self.pallet_type_manager.get_pallet_types_by_operation("output") - # self.output_pallet_type_combo.clear() - # for pallet_type in output_types: - # self.output_pallet_type_combo.addItem(pallet_type['type_name'], pallet_type['id']) - + def get_axios_num(self,tray_id): + """获取托盘号对应的轴号""" + from dao.inspection_dao import InspectionDAO + inspection_dao = InspectionDAO() + axios_num = inspection_dao.get_axios_num(tray_id) + return axios_num + def get_axios_num_by_order_id(self, order_id): + """获取订单号对应的轴号""" + from dao.inspection_dao import InspectionDAO + inspection_dao = InspectionDAO() + axios_num = inspection_dao.get_axios_num_by_order_id(order_id) + return axios_num def load_config(self): """加载配置文件""" config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "config", "app_config.json") @@ -308,7 +276,7 @@ class MainWindow(MainWindowUI): logging.info("显示主页面") def load_pallet_codes(self): - """从托盘类型管理器加载托盘号并更新到tray_edit""" + """从托盘类型管理器加载托盘号并更新到tray_edit TODO:要实现动态数据源切换""" try: # 获取当前文本,以便保留用户选择 current_text = self.tray_edit.currentText() @@ -696,12 +664,40 @@ class MainWindow(MainWindowUI): logging.info("工程号输入框按下回车事件") # 获取当前输入的工程号 order_text = self.order_edit.text().strip() - + tray_id = self.tray_edit.currentText() if order_text: logging.info(f"输入的工程号: {order_text}") - - # 在微丝产线表格中添加一条新记录 - self.add_new_inspection_row(order_text) + #判断是否是接口,如果不是接口直接添加如果是则走接口 + # 如果开启接口模式,则需要调用接口同步到业务库 + 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) + else: logging.warning("工程号为空") @@ -710,11 +706,12 @@ class MainWindow(MainWindowUI): # 处理完后可以清除焦点,让输入框失去焦点 self.central_widget.setFocus() - def add_new_inspection_row(self, order_id): + def add_new_inspection_row(self, order_id, order_info): """在微丝产线表格中添加一条新记录,添加到表格末尾 Args: order_id: 工程号 + order_info: 从接口获取的工程号信息 """ try: # 获取启用的检验配置 @@ -757,9 +754,36 @@ class MainWindow(MainWindowUI): for i, config in enumerate(enabled_configs): col_index = 2 + i # 检验列从第3列开始 - # 创建空的可编辑单元格 + # 创建单元格 item = QTableWidgetItem("") item.setTextAlignment(Qt.AlignCenter) + + # 如果有order_info数据,尝试匹配字段并设置值 + if order_info: + config_name = config.get('name') + # 检查order_info中是否有与config_name匹配的键 + if config_name in order_info: + value = str(order_info[config_name]) + item = QTableWidgetItem(value) + item.setTextAlignment(Qt.AlignCenter) + # 设置单元格背景为浅绿色,表示自动填充 + item.setBackground(QBrush(QColor("#c8e6c9"))) + + # 保存到数据库 + from dao.inspection_dao import InspectionDAO + inspection_dao = InspectionDAO() + tray_id = self.tray_edit.currentText() + data = [{ + 'position': config.get('position'), + 'config_id': config.get('id'), + 'value': value, + 'status': 'pass', # 默认设置为通过状态 + 'remark': '', + 'tray_id': tray_id + }] + inspection_dao.save_inspection_data(order_id, data) + logging.info(f"自动填充字段 {config_name} 值为 {value}") + # 设置单元格属性以标识其关联的检验项 item.setData(Qt.UserRole, config.get('id')) self.process_table.setItem(data_start_row, col_index, item) @@ -790,16 +814,20 @@ class MainWindow(MainWindowUI): 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) + config_name = config.get('name') + # 如果order_info中没有对应的键,或者order_info为None + if not order_info or config_name not in order_info: + 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, 13]: # 11是贴标,12是毛重,13是净重 @@ -1045,9 +1073,6 @@ class MainWindow(MainWindowUI): # 保存到数据库 inspection_dao.save_inspection_data(order_id, data) - # 注意:不要在这里调用数据加载方法,而是依靠信号和槽机制或QTimer安全地触发加载 - - except Exception as e: logging.error(f"保存检验数据失败: {str(e)}") # 显示错误消息 @@ -1055,14 +1080,26 @@ class MainWindow(MainWindowUI): def _safe_load_data(self): """安全地加载数据,避免循环调用""" + # 获取当前托盘号,用于日志记录 + tray_id = self.tray_edit.currentText() + if self._loading_data_in_progress: # 如果已经在加载数据,不要再次触发 - logging.debug("已有数据加载正在进行,忽略此次请求") + logging.debug(f"已有数据加载正在进行,忽略此次请求 (托盘号: {tray_id})") return try: self._loading_data_in_progress = True self.load_finished_inspection_data() + logging.info(f"数据加载完成,托盘号: {tray_id}") + except Exception as e: + logging.error(f"安全加载数据失败: {str(e)}, 托盘号: {tray_id}") + # 即使加载失败,也尝试显示包装记录 + try: + self.show_pack_item() + logging.info(f"加载失败后尝试显示包装记录, 托盘号: {tray_id}") + except Exception as ex: + logging.error(f"加载失败后显示包装记录失败: {str(ex)}, 托盘号: {tray_id}") finally: self._loading_data_in_progress = False @@ -1121,8 +1158,10 @@ class MainWindow(MainWindowUI): # 添加数据到表格 - 从第3行开始添加数据 row_idx = 2 - # 确保按工程号倒序排列,最新的工程号在最前面 - sorted_order_ids = sorted(orders_data.keys(), reverse=False) + # 使用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())) for order_id in sorted_order_ids: items = orders_data[order_id] @@ -1192,10 +1231,24 @@ class MainWindow(MainWindowUI): finally: # 加载包装记录,但要避免循环调用 # 设置一个标志,防止 show_pack_item 触发更多的数据加载 - if not hasattr(self, '_loading_data_in_progress'): + # 只有在_safe_load_data调用此方法,且没有明确设置加载状态的情况下才调用 + has_loading_flag = hasattr(self, '_loading_data_in_progress') + is_loading = getattr(self, '_loading_data_in_progress', False) + + # 如果是被_safe_load_data调用(即已经设置了_loading_data_in_progress),则无需额外设置 + if has_loading_flag and is_loading: + # 直接调用show_pack_item,不改变加载状态 + try: + self.show_pack_item() + logging.info("在load_finished_inspection_data中调用show_pack_item") + except Exception as e: + logging.error(f"在load_finished_inspection_data中调用show_pack_item失败: {str(e)}") + # 否则,这是直接调用此方法(非_safe_load_data),需要设置加载状态 + elif not is_loading: self._loading_data_in_progress = True try: self.show_pack_item() + logging.info("在load_finished_inspection_data中直接调用show_pack_item") finally: self._loading_data_in_progress = False @@ -1248,7 +1301,7 @@ class MainWindow(MainWindowUI): inspection_dao.save_package_record(order_id, tray_id, label_value, weight_value,net_weight_value, finish_time) # 回显数据,但避免循环调用 - if not hasattr(self, '_loading_data_in_progress'): + if not getattr(self, '_loading_data_in_progress'): self._loading_data_in_progress = True try: self.show_pack_item() @@ -1268,17 +1321,37 @@ class MainWindow(MainWindowUI): # 获取托盘号 tray_id = self.tray_edit.currentText() + logging.info(f"显示包装记录,当前托盘号: {tray_id}") + + if not tray_id: + logging.warning("托盘号为空,无法显示包装记录") + # 清空表格 + self.record_table.setRowCount(0) + self.update_package_statistics() + return + # 读取已包装的记录信息,然后回显到 UI package_record = inspection_dao.get_package_record(tray_id) + + # 记录获取的数据情况 + if package_record: + logging.info(f"成功获取包装记录,托盘号={tray_id},记录数量={len(package_record)}") + else: + logging.info(f"包装记录为空,托盘号={tray_id}") # 完全清空包装记录表格(包括所有行) self.record_table.setRowCount(0) # 断开包装记录表的信号连接(如果有) try: - self.record_table.cellChanged.disconnect() - except: + # 检查是否已经连接了cellChanged信号 + if self.record_table.receivers(self.record_table.cellChanged) > 0: + self.record_table.cellChanged.disconnect() + except TypeError: + # 忽略"Failed to disconnect"类型错误 pass + except Exception as e: + logging.warning(f"断开record_table.cellChanged信号失败: {str(e)}") # 设置表头固定不动 self.record_table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) @@ -1373,6 +1446,8 @@ class MainWindow(MainWindowUI): # 更新包装记录统计数据 self.update_package_statistics() + logging.info(f"包装记录显示完成,托盘号={tray_id},总记录数={self.record_table.rowCount()}") + except Exception as e: logging.error(f"显示包装记录失败: {str(e)}") QMessageBox.warning(self, "显示失败", f"显示包装记录失败: {str(e)}") @@ -1681,7 +1756,10 @@ class MainWindow(MainWindowUI): self.save_inspection_data(order_id, tray_id, 12, 12, str(weight), "pass") # 保存净重到数据库(毛重-工字轮重量,TODO :先默认工字轮重量为10g后续从接口获取) - net_weight = weight - 10 + from dao.inspection_dao import InspectionDAO + inspection_dao = InspectionDAO() + gzl_zl = inspection_dao.get_gzl_zl(order_id) + net_weight = float(weight) - float(gzl_zl) self.save_inspection_data(order_id, tray_id, 13, 13, str(net_weight), "pass") # 设置净重单元格 @@ -1748,8 +1826,8 @@ class MainWindow(MainWindowUI): # 计算贴标列索引 - 贴标位置在检验列之后的第一列 label_col = 2 + len(enabled_configs) - # 生成贴标号(托盘号+序号) - label_value = f"{self.init_seq[tray_id]}" + # 生成贴标号(托盘号+轴号) + axios_num = self.get_axios_num(tray_id)+1 # 断开单元格变更信号,避免程序自动写入时触发 try: @@ -1758,15 +1836,15 @@ class MainWindow(MainWindowUI): pass # 创建并设置贴标单元格 - label_item = QTableWidgetItem(label_value) + label_item = QTableWidgetItem(axios_num) label_item.setTextAlignment(Qt.AlignCenter) # 写入单元格 self.process_table.setItem(data_row, label_col, label_item) - logging.info(f"已将贴标数据 {label_value} 写入表格单元格 [{data_row}, {label_col}]") + logging.info(f"已将贴标数据 {axios_num} 写入表格单元格 [{data_row}, {label_col}]") # 保存贴标数据到数据库 - self.save_inspection_data(order_id, tray_id, 11, 11, label_value, "pass") + self.save_inspection_data(order_id, tray_id, 11, 11, axios_num, "pass") # 调用加载到包装记录的方法 self.load_finished_record_to_package_record(order_id, tray_id) @@ -1775,12 +1853,44 @@ class MainWindow(MainWindowUI): # 删除当前处理的行 self.process_table.removeRow(data_row) logging.info(f"已删除处理完成的行 {data_row}") - + + #如果开启 api 模式,则调用接口添加到包装记录 + if AppMode.is_api(): + from dao.inspection_dao import InspectionDAO + inspection_dao = InspectionDAO() + # 调用接口 + gc_api = GcApi() + axios_num = self.get_axios_num_by_order_id(order_id) + # 获取订单信息和其他信息,两者都已经是字典格式 + info = {} + order_info = inspection_dao.get_order_info(order_id) + info.update(order_info) + + order_others_info = inspection_dao.get_order_others_info(order_id, tray_id) + info.update(order_others_info) + info['data_corp'] = 'T' + info['zh'] = axios_num + + # 获取本机IP地址 + import socket + try: + # 通过连接外部服务器获取本机IP(不实际建立连接) + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) + local_ip = s.getsockname()[0] + s.close() + info['nw_ip'] = local_ip.replace('.', '') + except Exception as e: + logging.error(f"获取本机IP失败: {str(e)}") + # 如果获取失败,使用本地回环地址 + info['nw_ip'] = '127.0.0.1'.replace('.', '') + + # 调用接口添加到包装记录 + gc_api.add_order_info(info) + # 重新连接单元格变更信号 self.process_table.cellChanged.connect(self.handle_inspection_cell_changed) - # 更新托盘号对应的序号 - self.init_seq[tray_id] += 1 except Exception as e: logging.error(f"处理贴标完成信号失败: {str(e)}") # 确保信号重新连接 @@ -2257,31 +2367,27 @@ class MainWindow(MainWindowUI): tray_id = self.tray_edit.currentText() if tray_id: logging.info(f"托盘号变更为 {tray_id},启动监听") - - # 确保启动Modbus监控 - if not hasattr(self, 'modbus_monitor') or not self.modbus_monitor.is_running(): - try: - self.setup_modbus_monitor() - logging.info("已在托盘号变更时启动Modbus监控") - except Exception as e: - logging.error(f"托盘号变更时启动Modbus监控失败: {str(e)}") - - # 确保启动串口监听 - try: - self.serial_manager.auto_open_configured_ports() - # 启动键盘监听器 - self.serial_manager.start_keyboard_listener() - logging.info("已在托盘号变更时启动串口和键盘监听器") - except Exception as e: - logging.error(f"托盘号变更时启动串口监听失败: {str(e)}") - # 初始化托盘号对应的序号(如果不存在) if tray_id not in self.init_seq: self.init_seq[tray_id] = 1 logging.info(f"初始化托盘号 {tray_id} 的序号为 1") - # 加载数据 + # 加载检验数据 self._safe_load_data() + # 无论_safe_load_data是否成功,都确保显示包装记录 + # 临时保存当前加载状态 + prev_loading_state = getattr(self, '_loading_data_in_progress', False) + + try: + # 设置加载状态为True,避免无限循环调用 + self._loading_data_in_progress = True + # 强制显示包装记录 + self.show_pack_item() + logging.info(f"托盘号变更:直接调用显示包装记录, 托盘号={tray_id}") + finally: + # 恢复之前的加载状态 + self._loading_data_in_progress = prev_loading_state + except Exception as e: logging.error(f"处理托盘号变更失败: {str(e)}") \ No newline at end of file diff --git a/widgets/{'note': 'JT2504019', 'type_name': '不锈钢丝.groovy b/widgets/{'note': 'JT2504019', 'type_name': '不锈钢丝.groovy new file mode 100644 index 0000000..37935d5 --- /dev/null +++ b/widgets/{'note': 'JT2504019', 'type_name': '不锈钢丝.groovy @@ -0,0 +1,37 @@ +{'note': 'JT2504019', 'type_name': '不锈钢丝', 'code': 'CP02013', 'corp': '江苏佳腾', 'spack': 'JT2504019-0005', 'tqd': '780', 'zx_name': 'DIN-355/ABS无字白轴', 'cdname': '待定', 'bzfs': '托盘上大纸箱', 'bccd': '0.494', 'type': 'ZL00', 'bz_bqd': '700', 'maxsl': 35.45, 'ysl': None, 'khjq': '2025-05-31', 'price': 19.2, 'sl': 4600.0, 'spack_type': '木托', 'ddzl': '外销合同', 'qfqd': None, 'customerexp': 'JW', 'zzyq': '42-44', 'cd': '待定', 'mo': 'JT2504019-1', 'dycz': None, 'tccd': '0.506', 'zx_code': 'ZX0023', 'bqlb': '14', 'khno': 'SCJW25-010Add', 'template_name': '日本-白签', 'size': '0.5', 'bqd': None, 'remarks_hb': 'G01|生产注意产品表面及排线,装箱时做好固定,外箱相连两侧各贴一张标签,每箱27轴|42-44公斤/轴,27轴/箱', 'mxid': 17321, 'ddyq': '42-44公斤/轴,27轴/箱', 'cz': '304', 'luno': 'J2410115', 'yzgg': None, 'je': 88320.0, 'zx_zl': '1.95', 'remarks': '42-44公斤/轴,27轴/箱', 'rq': '2025-04-08', 'bz_tqd': '800', 'customer': 'JTDW00070'} +size 线径 +zx_zl 工字轮重量 + +{ + "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":, +} \ No newline at end of file