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 f553f26..e64b73d 100644 Binary files a/db/jtDB.db and b/db/jtDB.db differ diff --git a/from pymodbus.py b/from pymodbus.py index fa3471e..7b6ba9d 100644 --- a/from pymodbus.py +++ b/from pymodbus.py @@ -2,14 +2,16 @@ from pymodbus.client import ModbusTcpClient client = ModbusTcpClient('localhost', port=5020) client.connect() -# client.write_registers(address=11, values=[114]) +# client.write_registers(address=11, values=[110]) +client.write_registers(address=13, values=[1]) + # client.write_registers(address=6, values=[1]) # client.write_registers(address=5, values=[16]) # 贴标完成 -# client.write_registers(address=13, values=[1]) # client.write_registers(address=24, values=[1]) +# client.write_registers(address=13, values=[0]) -result = client.read_holding_registers(address=4, count=1) +result = client.read_holding_registers(address=13, count=1) print(result.registers[0],"123===") client.close() \ No newline at end of file diff --git a/tests/test_gc_api.py b/tests/test_gc_api.py new file mode 100644 index 0000000..b15d8e2 --- /dev/null +++ b/tests/test_gc_api.py @@ -0,0 +1,48 @@ +import sys +import os +import logging +from pathlib import Path + +# 添加项目根目录到系统路径,以便导入模块 +project_root = str(Path(__file__).parent.parent) +sys.path.insert(0, project_root) + +# 配置日志 +logging.basicConfig(level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s:%(lineno)d] - %(message)s') + +# 导入需要测试的模块 +from apis.gc_api import GcApi + +def test_gc_api(): + """测试 GcApi 的 get_gc_info 方法是否能正确处理 form-data 格式的请求""" + print("开始测试 GcApi.get_gc_info 方法...") + + # 创建 GcApi 实例 + gc_api = GcApi() + + # 测试工程号 + test_gc_code = "JTPD25060003" + + # 调用方法 + print(f"使用工程号 {test_gc_code} 调用 get_gc_info...") + response = gc_api.get_gc_info(test_gc_code) + + # 打印结果 + print(f"API 响应: {response}") + + if response: + print("测试成功: API 返回了有效响应") + else: + print("测试失败: API 返回了空响应") + + # 检查响应格式 + if isinstance(response, dict) and "status" in response: + print(f"响应状态: {response.get('status', False)}") + print(f"响应消息: {response.get('message', '')}") + print(f"响应数据: {response.get('data', None)}") + else: + print(f"响应格式不符合预期: {response}") + +if __name__ == "__main__": + test_gc_api() \ No newline at end of file diff --git a/utils/api_utils.py b/utils/api_utils.py index a1765eb..3186e14 100644 --- a/utils/api_utils.py +++ b/utils/api_utils.py @@ -1,6 +1,7 @@ import requests import json from .config_loader import ConfigLoader +import logging class ApiUtils: def __init__(self): @@ -54,10 +55,22 @@ class ApiUtils: "Content-Type": "application/json" } + # 如果是 POST 请求且有表单数据,则使用 form-data 格式 + if method.upper() == "POST" and data and not json_data: + # 对于 form-data 格式,不设置 Content-Type,让 requests 自动处理 + default_headers = {} + if headers: default_headers.update(headers) try: + # 记录请求信息,便于调试 + logging.info(f"发送 {method} 请求到 {full_url}") + logging.info(f"参数: {params}") + logging.info(f"数据: {data}") + logging.info(f"JSON数据: {json_data}") + logging.info(f"请求头: {default_headers}") + response = requests.request( method=method, url=full_url, @@ -67,11 +80,17 @@ class ApiUtils: headers=default_headers ) + # 记录响应状态 + logging.info(f"响应状态码: {response.status_code}") + logging.info(f"响应内容: {response.text[:500]}...") # 只记录前500个字符 + response.raise_for_status() return response.json() except requests.exceptions.RequestException as e: + logging.error(f"请求异常: {str(e)}") return {"success": False, "message": f"请求异常: {str(e)}"} - except json.JSONDecodeError: + except json.JSONDecodeError as e: + logging.error(f"响应数据不是有效的JSON格式: {str(e)}") return {"success": False, "message": "响应数据不是有效的 JSON 格式"} def get(self, url, params=None, headers=None): diff --git a/widgets/loading_dialog_widget.py b/widgets/loading_dialog_widget.py index 586d009..d7e00d2 100644 --- a/widgets/loading_dialog_widget.py +++ b/widgets/loading_dialog_widget.py @@ -76,17 +76,32 @@ class LoadingDialog(LoadingDialogUI): # 如果返回的是元组(数据库查询结果),将其转换为字典 # 根据dao/pallet_type_dao.py中get_pallet_info_by_pallet_id方法的SQL查询 # 返回的字段顺序为:pallet_code, pallet_name, description, axios_name, axios_type, tier, size, amount, weight - response = { - "success": True, - "data": { - "tp_note": pallet_info[0] if len(pallet_info) > 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