feat: 完成扫码操作

This commit is contained in:
zhu-mengmeng 2025-07-01 09:36:16 +08:00
parent ead4cfcc95
commit ce8483d298
7 changed files with 3354 additions and 194 deletions

View File

@ -49,8 +49,8 @@
"default_framerate": 30
},
"modbus": {
"host": "192.168.2.88",
"port": "502"
"host": "localhost",
"port": "5020"
},
"serial": {
"keyboard": {

View File

@ -8,12 +8,13 @@ class InspectionDAO:
def __init__(self):
"""初始化数据访问对象"""
self.db = SQLUtils('sqlite', database='db/jtDB.db')
# 不再在初始化时创建数据库连接,而是在需要时创建
pass
def __del__(self):
"""析构函数,确保数据库连接关闭"""
if hasattr(self, 'db'):
self.db.close()
# 不再需要在这里关闭连接,由上下文管理器处理
pass
def get_all_inspection_configs(self, include_disabled=False):
"""获取所有检验项目配置
@ -44,8 +45,9 @@ class InspectionDAO:
"""
params = ()
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
results = db.cursor.fetchall()
configs = []
for row in results:
@ -96,8 +98,9 @@ class InspectionDAO:
"""
params = (position,)
self.db.cursor.execute(sql, params)
row = self.db.cursor.fetchone()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
row = db.cursor.fetchone()
if row:
config = {
@ -182,7 +185,8 @@ class InspectionDAO:
WHERE id = ?
"""
self.db.execute_update(sql, params)
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.execute_update(sql, params)
return True
except Exception as e:
logging.error(f"更新检验项目配置失败: {str(e)}")
@ -209,7 +213,8 @@ class InspectionDAO:
"""
params = (enabled, current_time, username, position)
self.db.execute_update(sql, params)
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.execute_update(sql, params)
return True
except Exception as e:
logging.error(f"更新检验项目启用状态失败: {str(e)}")
@ -229,8 +234,9 @@ class InspectionDAO:
# 先检查是否存在记录
check_sql = "SELECT ddmo FROM wsbz_order_info WHERE ddmo = ?"
self.db.cursor.execute(check_sql, (data.get("mo", ""),))
existing_record = self.db.cursor.fetchone()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(check_sql, (data.get("mo", ""),))
existing_record = db.cursor.fetchone()
if existing_record:
# 如果记录存在,执行更新
@ -329,102 +335,81 @@ class InspectionDAO:
)
logging.info(f"插入新订单信息: ddmo={data.get('mo', '')}")
self.db.cursor.execute(sql, params)
self.db.conn.commit()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
db.conn.commit()
return True
except Exception as e:
logging.error(f"保存订单信息失败: {str(e)}")
self.db.conn.rollback()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.conn.rollback()
return False
def save_inspection_data(self, order_id,gc_note, data, username='system'):
def save_inspection_data(self, order_id, gc_note, data, username='system'):
"""保存检验数据
Args:
order_id: 工程
gc_note: 工程号备注
data: 检验数据列表格式: [{'position': 1, 'config_id': 1, 'value': '合格'}, ...]
order_id: 订单
gc_note: 工程号
data: 检验数据列表每项包含position, config_id, value, status, remark
username: 操作用户
Returns:
bool: 保存是否成功
"""
try:
# 验证数据格式
if not isinstance(data, list):
logging.error(f"保存检验数据失败: data参数必须是列表实际类型为 {type(data)}")
return False
if len(data) == 0:
logging.warning("保存检验数据: 数据列表为空")
return True # 空列表视为成功,不进行任何操作
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.db.begin_transaction()
for item in data:
# 验证item是否为字典类型
if not isinstance(item, dict):
logging.error(f"保存检验数据失败: 数据项必须是字典,实际类型为 {type(item)}")
self.db.rollback_transaction()
return False
# 使用上下文管理器自动处理连接和游标
with SQLUtils('sqlite', database='db/jtDB.db') as db:
for item in data:
position = item.get('position')
config_id = item.get('config_id')
value = item.get('value', '')
status = item.get('status', '')
remark = item.get('remark', '')
tray_id = item.get('tray_id', '')
# 使用get方法安全获取值提供默认值
position = item.get('position')
config_id = item.get('config_id')
value = item.get('value', '')
status = item.get('status', 'pass')
remark = item.get('remark', '')
tray_id = item.get('tray_id', '')
# 验证必要字段
if position is None or config_id is None:
logging.error(f"保存检验数据失败: 缺少必要字段 position 或 config_id")
self.db.rollback_transaction()
return False
# 检查是否已存在该工程号和位置的记录
check_sql = """
SELECT id FROM wsbz_inspection_data
WHERE order_id = ? and gc_note = ? AND position = ? AND is_deleted = FALSE
"""
check_params = (order_id,gc_note, position)
self.db.cursor.execute(check_sql, check_params)
existing = self.db.cursor.fetchone()
if existing:
# 更新已有记录
update_sql = """
UPDATE wsbz_inspection_data
SET config_id = ?, value = ?, status = ?, remark = ?,
update_time = ?, update_by = ?, tray_id = ?
WHERE id = ?
# 检查是否已存在记录
check_sql = """
SELECT id FROM wsbz_inspection_data
WHERE order_id = ? AND gc_note = ? AND position = ? AND tray_id = ?
"""
update_params = (
config_id, value, status, remark,
current_time, username, tray_id, existing[0]
)
self.db.cursor.execute(update_sql, update_params)
else:
# 插入新记录
insert_sql = """
INSERT INTO wsbz_inspection_data (
order_id, position, config_id, value, status, remark,
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,gc_note
)
self.db.cursor.execute(insert_sql, insert_params)
check_params = (order_id, gc_note, position, tray_id)
db.execute_query(check_sql, check_params)
existing_record = db.fetchone()
if existing_record:
# 更新现有记录
update_sql = """
UPDATE wsbz_inspection_data
SET config_id = ?, value = ?, status = ?, remark = ?,
update_time = ?, update_by = ?
WHERE order_id = ? AND gc_note = ? AND position = ? AND tray_id = ?
"""
update_params = (
config_id, value, status, remark,
current_time, username,
order_id, gc_note, position, tray_id
)
db.execute_update(update_sql, update_params)
else:
# 插入新记录
insert_sql = """
INSERT INTO wsbz_inspection_data (
order_id, gc_note, position, config_id, value, status, remark,
create_time, create_by, update_time, update_by, tray_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"""
insert_params = (
order_id, gc_note, position, config_id, value, status, remark,
current_time, username, current_time, username, tray_id
)
db.execute_update(insert_sql, insert_params)
self.db.commit_transaction()
return True
except Exception as e:
self.db.rollback_transaction()
logging.error(f"保存检验数据失败: {str(e)}")
return False
def get_inspection_data_unfinished(self, tray_id):
@ -442,8 +427,9 @@ class InspectionDAO:
AND d.position = 11 AND COALESCE(d.value,'') = ''
"""
params = (tray_id,)
self.db.cursor.execute(sql_orders, params)
gc_notes = self.db.cursor.fetchall()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql_orders, params)
gc_notes = db.cursor.fetchall()
if not gc_notes:
return []
@ -464,8 +450,9 @@ class InspectionDAO:
"""
params = [tray_id] + gc_notes
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
results = db.cursor.fetchall()
data_list = []
for row in results:
@ -509,8 +496,9 @@ class InspectionDAO:
"""
params = (order_id, gc_note, tray_id)
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
results = db.cursor.fetchall()
data_list = []
for row in results:
@ -559,8 +547,9 @@ class InspectionDAO:
ORDER BY pack_time DESC
"""
params = (tray_id,)
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
results = db.cursor.fetchall()
return results
except Exception as e:
logging.error(f"获取包装记录失败: {str(e)}")
@ -582,11 +571,13 @@ class InspectionDAO:
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
"""
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()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
db.conn.commit()
except Exception as e:
logging.error(f"保存包装记录失败: {str(e)}")
self.db.conn.rollback()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.conn.rollback()
def delete_inspection_data(self, order_id, tray_id):
"""删除检验数据
@ -602,11 +593,13 @@ class InspectionDAO:
WHERE order_id = ? AND tray_id = ?
"""
params = (order_id, tray_id)
self.db.cursor.execute(sql, params)
self.db.conn.commit()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
db.conn.commit()
except Exception as e:
logging.error(f"删除检验数据失败: {str(e)}")
self.db.conn.rollback()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.conn.rollback()
def get_axios_num_by_order_id(self, order_id):
"""获取托盘号对应的轴号"""
try:
@ -615,8 +608,9 @@ class InspectionDAO:
AND is_deleted = FALSE
"""
params = (order_id,)
self.db.cursor.execute(sql, params)
result = self.db.cursor.fetchone()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
result = db.cursor.fetchone()
return int(result[0]) if result[0] else 0
except Exception as e:
logging.error(f"获取轴号失败: {str(e)}")
@ -629,8 +623,9 @@ class InspectionDAO:
AND is_deleted = FALSE
"""
params = (tray_id,)
self.db.cursor.execute(sql, params)
result = self.db.cursor.fetchone()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
result = db.cursor.fetchone()
return int(result[0]) if result else 0
except Exception as e:
logging.error(f"获取轴号失败: {str(e)}")
@ -642,8 +637,9 @@ class InspectionDAO:
SELECT gzl_zl FROM wsbz_order_info WHERE ddmo = ?
"""
params = (order_id,)
self.db.cursor.execute(sql, params)
result = self.db.cursor.fetchone()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
result = db.cursor.fetchone()
return result[0] if result else 0
except Exception as e:
logging.error(f"获取工字轮重量失败: {str(e)}")
@ -655,8 +651,9 @@ class InspectionDAO:
SELECT bccd, tccd FROM wsbz_order_info WHERE ddmo = ?
"""
params = (order_id,)
self.db.cursor.execute(sql, params)
result = self.db.cursor.fetchone()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
result = db.cursor.fetchone()
return result[0],result[1] if result else None,None
except Exception as e:
logging.error(f"获取线径范围失败: {str(e)}")
@ -675,8 +672,9 @@ class InspectionDAO:
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()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, (order_id,))
result = db.cursor.fetchone()
return result[0] if result and result[0] else None
except Exception as e:
logging.error(f"获取工程号创建时间失败: {str(e)}")
@ -707,8 +705,9 @@ class InspectionDAO:
ORDER BY first_create_time
"""
self.db.cursor.execute(sql, order_ids)
results = self.db.cursor.fetchall()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, order_ids)
results = db.cursor.fetchall()
# 提取排序后的工程号
sorted_order_ids = [row[0] for row in results]
@ -739,14 +738,15 @@ class InspectionDAO:
FROM wsbz_order_info WHERE ddmo = ?
"""
params = (order_id,)
self.db.cursor.execute(sql, params)
result = self.db.cursor.fetchone()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
result = db.cursor.fetchone()
if not result:
return {}
# 获取列名
column_names = [desc[0] for desc in self.db.cursor.description]
column_names = [desc[0] for desc in db.cursor.description]
# 转换为字典
result_dict = {}
@ -779,8 +779,9 @@ class InspectionDAO:
AND COALESCE(value, '') != ''
"""
params = (gc_note, order_id, tray_id)
self.db.cursor.execute(sql, params)
results = self.db.cursor.fetchall()
with SQLUtils('sqlite', database='db/jtDB.db') as db:
db.cursor.execute(sql, params)
results = db.cursor.fetchall()
if not results:
return {}

Binary file not shown.

2973
tests/main_window_old.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ class SerialManager:
self.read_threads: Dict[str, threading.Thread] = {} # 存储读取线程
self.running_flags: Dict[str, bool] = {} # 存储线程运行标志
self.callbacks: Dict[str, Callable] = {} # 存储数据回调函数
self.port_types: Dict[str, str] = {} # 存储端口类型,用于线程重启
# 添加文件操作暂停控制
self._file_operations_suspended = False
@ -85,6 +86,9 @@ class SerialManager:
else:
logging.info("键盘监听功能已在配置中禁用,跳过初始化键盘监听器")
self.keyboard_listener = None
# 启动线程监控
self._start_thread_monitor()
def _load_config(self):
"""加载配置"""
@ -257,31 +261,58 @@ class SerialManager:
if callback:
self.callbacks[port_name] = callback
# 记录端口类型,用于线程重启
self.port_types[port_name] = port_type
# 创建并启动读取线程
self.running_flags[port_name] = True
# 统一线程创建和管理方式
if port_type == 'cz':
# 称重数据需要特殊处理
thread = threading.Thread(target=self._read_weight_thread, args=(port_name, self.stable_threshold))
thread = threading.Thread(
target=self._read_weight_thread,
args=(port_name, self.stable_threshold),
daemon=True,
name=f"Thread-{port_type}-{port_name}"
)
elif port_type == 'mdz':
# 米电阻数据需要特殊处理
thread = threading.Thread(target=self._read_resistance_thread, args=(port_name,))
thread = threading.Thread(
target=self._read_resistance_thread,
args=(port_name,),
daemon=True,
name=f"Thread-{port_type}-{port_name}"
)
elif port_type == 'xj':
# 线径数据需要特殊处理
thread = threading.Thread(target=self._read_diameter_thread, args=(port_name,))
thread.daemon = True
thread.start()
self.read_threads[port_name] = thread
thread = threading.Thread(
target=self._read_diameter_thread,
args=(port_name,),
daemon=True,
name=f"Thread-{port_type}-{port_name}"
)
elif port_type == 'scanner':
# 扫码器数据需要特殊处理
thread = threading.Thread(target=self._read_scanner_thread, args=(port_name,))
thread = threading.Thread(
target=self._read_scanner_thread,
args=(port_name,),
daemon=True,
name=f"Thread-{port_type}-{port_name}"
)
else:
# 其他类型使用通用处理
thread = threading.Thread(target=self._read_thread, args=(port_name,))
thread.daemon = True
thread.start()
self.read_threads[port_name] = thread
thread = threading.Thread(
target=self._read_thread,
args=(port_name,),
daemon=True,
name=f"Thread-{port_type}-{port_name}"
)
# 统一启动线程
thread.start()
self.read_threads[port_name] = thread
logging.info(f"已启动串口读取线程: {thread.name}")
return True
@ -330,10 +361,13 @@ class SerialManager:
del self.serial_ports[port_name]
logging.info(f"串行对象 for {port_name} 从 self.serial_ports 中删除. 当前活跃端口: {list(self.serial_ports.keys())}")
# 删除回调
# 删除回调和端口类型记录
if port_name in self.callbacks:
del self.callbacks[port_name]
if port_name in self.port_types:
del self.port_types[port_name]
logging.info(f"串口 {port_name} 已关闭")
return True
@ -434,16 +468,46 @@ class SerialManager:
logging.error(f"串口 {port_name} 读取线程异常: {str(e)}")
def _read_weight_thread(self, port_name: str, stable_threshold: int = 10):
logging.info(f"[{port_name}] 称重线程启动")
# 重置状态变量,确保线程重启时能正确处理称重数据
self.weight_written = False
self.stable_count = 0
self.last_weight = 0
self.last_weights = [0] * 3
self.weight_changed_time = time.time()
self.last_write_time = 0 # 添加一个变量来跟踪最后一次写入时间
self.stability_start_time = 0 # 重置稳定性检测开始时间
"""
称重串口读取线程
Args:
port_name: 串口名称
stable_threshold: 稳定阈值
"""
try:
logging.info(f"[{port_name}] 称重线程启动")
# 重置状态变量,确保线程重启时能正确处理称重数据
self.weight_written = False
self.stable_count = 0
self.last_weight = 0
self.last_weights = [0] * 3
self.weight_changed_time = time.time()
self.last_write_time = 0 # 添加一个变量来跟踪最后一次写入时间
self.stability_start_time = 0 # 重置稳定性检测开始时间
# 添加实际的读取逻辑
while self.running_flags.get(port_name, False):
if not self.is_port_open(port_name):
time.sleep(0.1)
continue
# 检查是否有数据可读
if self.serial_ports[port_name].in_waiting > 0:
data = self.serial_ports[port_name].read(self.serial_ports[port_name].in_waiting)
weight = self._process_weight_data(data)
if weight is not None:
# 更新数据
self.data['cz'] = weight
self._write_data_to_file()
time.sleep(0.1)
except Exception as e:
logging.error(f"称重串口 {port_name} 读取线程异常: {e}")
# 线程异常时,尝试重置状态
self.running_flags[port_name] = False
def _process_weight_data(self, data_bytes):
"""
TODO: 需要将线径数据写入文件这个方法需要修改成线径的串口数据获取
@ -496,6 +560,7 @@ class SerialManager:
port_name: 串口名称
"""
try:
logging.info(f"[{port_name}] 米电阻线程启动")
while self.running_flags.get(port_name, False):
if not self.is_port_open(port_name):
time.sleep(0.1)
@ -536,7 +601,9 @@ class SerialManager:
except Exception as e:
logging.error(f"米电阻串口 {port_name} 读取线程异常: {e}")
# 线程异常时,尝试重置状态
self.running_flags[port_name] = False
def _process_mdz_response(self, port_name, response_bytes: bytes):
"""处理米电阻响应数据"""
try:
@ -1075,6 +1142,7 @@ class SerialManager:
port_name: 串口名称
"""
try:
logging.info(f"[{port_name}] 线径线程启动")
while self.running_flags.get(port_name, False):
if not self.is_port_open(port_name):
time.sleep(0.1)
@ -1089,6 +1157,8 @@ class SerialManager:
except Exception as e:
logging.error(f"线径串口 {port_name} 读取线程异常: {e}")
# 线程异常时,尝试重置状态
self.running_flags[port_name] = False
def _process_diameter_response(self, port_name, response_bytes: bytes):
"""处理线径响应数据"""
@ -1137,6 +1207,7 @@ class SerialManager:
port_name: 串口名称
"""
try:
logging.info(f"[{port_name}] 扫码器线程启动")
while self.running_flags.get(port_name, False):
if not self.is_port_open(port_name):
time.sleep(0.1)
@ -1151,6 +1222,8 @@ class SerialManager:
except Exception as e:
logging.error(f"扫码器串口 {port_name} 读取线程异常: {e}")
# 线程异常时,尝试重置状态
self.running_flags[port_name] = False
def _process_scanner_response(self, port_name, response_bytes: bytes):
"""处理扫码器响应数据"""
@ -1197,4 +1270,59 @@ class SerialManager:
return False
except Exception as e:
logging.error(f"处理扫码数据总体异常: {e}")
return False
return False
def _start_thread_monitor(self):
"""启动线程监控"""
threading.Thread(target=self._monitor_threads, daemon=True).start()
def _monitor_threads(self):
"""监控线程状态"""
try:
logging.info("线程监控已启动")
while True:
try:
# 创建当前线程的副本,避免在迭代过程中修改字典
thread_items = list(self.read_threads.items())
for port_name, thread in thread_items:
# 检查线程是否存活
if not thread.is_alive():
# 检查串口是否仍然打开
if port_name in self.serial_ports and self.is_port_open(port_name):
port_type = self.port_types.get(port_name)
callback = self.callbacks.get(port_name)
logging.warning(f"线程 {thread.name} 已终止但串口仍然打开,尝试重新启动线程")
# 重置线程状态
self.running_flags[port_name] = False
if port_name in self.read_threads:
self.read_threads.pop(port_name, None)
# 如果有端口类型记录,尝试重新启动线程
if port_type:
# 短暂等待,确保资源释放
time.sleep(0.5)
try:
# 重新打开串口
self.open_port(port_name, port_type, callback=callback)
logging.info(f"已重新启动线程: {port_name} ({port_type})")
except Exception as restart_error:
logging.error(f"重新启动线程失败: {port_name}, 错误: {restart_error}")
else:
logging.warning(f"无法重启线程: {port_name}, 未找到端口类型记录")
else:
# 串口已关闭,清理线程记录
if port_name in self.read_threads:
self.read_threads.pop(port_name, None)
logging.info(f"线程 {thread.name} 已终止,串口已关闭,清理线程记录")
# 每隔5秒检查一次
time.sleep(5)
except Exception as loop_error:
logging.error(f"线程监控循环异常: {loop_error}")
time.sleep(5) # 出错后等待一段时间再继续
except Exception as e:
logging.error(f"线程监控主循环异常: {e}")
# 尝试重新启动监控
time.sleep(10)
self._start_thread_monitor()

View File

@ -1,5 +1,6 @@
import sys
import logging
import threading
from utils.config_loader import ConfigLoader
try:
@ -21,6 +22,8 @@ except ImportError:
class SQLUtils:
# 存储连接池,避免重复创建连接
_connection_pool = {}
# 添加线程锁用于防止多线程同时使用同一个cursor
_lock = threading.RLock()
def __init__(self, db_type=None, source_name=None, **kwargs):
"""初始化SQLUtils对象
@ -83,6 +86,15 @@ class SQLUtils:
# 尝试从连接池获取连接,如果没有则创建新连接
self._get_connection()
def __enter__(self):
"""上下文管理器入口方法支持with语句"""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""上下文管理器退出方法,自动关闭游标"""
self.close()
return False # 不抑制异常
def _get_connection(self):
"""从连接池获取连接,如果没有则创建新连接"""
@ -90,25 +102,26 @@ class SQLUtils:
conn_key = f"{self.db_type}:{str(self.kwargs)}"
# 检查连接池中是否已有此连接
if conn_key in SQLUtils._connection_pool:
try:
# 尝试执行简单查询,确认连接有效
conn, cursor = SQLUtils._connection_pool[conn_key]
cursor.execute("SELECT 1")
# 连接有效,直接使用
self.conn = conn
self.cursor = cursor
return
except Exception:
# 连接已失效,从连接池移除
del SQLUtils._connection_pool[conn_key]
# 创建新连接
self.connect()
# 将新连接添加到连接池
if self.conn and self.cursor:
SQLUtils._connection_pool[conn_key] = (self.conn, self.cursor)
with SQLUtils._lock:
if conn_key in SQLUtils._connection_pool:
try:
# 尝试执行简单查询,确认连接有效
conn, cursor = SQLUtils._connection_pool[conn_key]
cursor.execute("SELECT 1")
# 连接有效,直接使用
self.conn = conn
self.cursor = cursor
return
except Exception:
# 连接已失效,从连接池移除
del SQLUtils._connection_pool[conn_key]
# 创建新连接
self.connect()
# 将新连接添加到连接池
if self.conn and self.cursor:
SQLUtils._connection_pool[conn_key] = (self.conn, self.cursor)
def connect(self):
"""连接到数据库"""
@ -120,7 +133,7 @@ class SQLUtils:
elif self.db_type in ['sqlite', 'sqlite3']:
if not sqlite3:
raise ImportError('sqlite3 is not installed')
self.conn = sqlite3.connect(self.kwargs.get('database', ':memory:'))
self.conn = sqlite3.connect(self.kwargs.get('database', ':memory:'), check_same_thread=False)
elif self.db_type == 'mysql':
if not mysql:
raise ImportError('mysql.connector is not installed')
@ -137,61 +150,92 @@ class SQLUtils:
def execute_query(self, sql, params=None):
if params is None:
params = ()
self.cursor.execute(sql, params)
self.conn.commit()
with SQLUtils._lock:
try:
self.cursor.execute(sql, params)
return self.cursor
except Exception as e:
logging.error(f"执行查询失败: {e}, SQL: {sql}, 参数: {params}")
raise
def execute_update(self, sql, params=None):
try:
self.cursor.execute(sql,params)
self.conn.commit()
with SQLUtils._lock:
self.cursor.execute(sql, params)
self.conn.commit()
return self.cursor.rowcount
except Exception as e:
self.conn.rollback()
logging.error(f"执行更新失败: {e}, SQL: {sql}, 参数: {params}")
raise e
def begin_transaction(self) -> None:
"""开始事务"""
if self.db_type in ['sqlite', 'sqlite3']:
self.execute_query('BEGIN TRANSACTION')
else:
self.conn.autocommit = False
with SQLUtils._lock:
if self.db_type in ['sqlite', 'sqlite3']:
self.execute_query('BEGIN TRANSACTION')
else:
self.conn.autocommit = False
def commit_transaction(self) -> None:
"""提交事务"""
self.conn.commit()
if self.db_type not in ['sqlite', 'sqlite3']:
self.conn.autocommit = True
with SQLUtils._lock:
self.conn.commit()
if self.db_type not in ['sqlite', 'sqlite3']:
self.conn.autocommit = True
def rollback_transaction(self) -> None:
"""回滚事务"""
self.conn.rollback()
if self.db_type not in ['sqlite', 'sqlite3']:
self.conn.autocommit = True
with SQLUtils._lock:
self.conn.rollback()
if self.db_type not in ['sqlite', 'sqlite3']:
self.conn.autocommit = True
def fetchone(self):
return self.cursor.fetchone()
with SQLUtils._lock:
return self.cursor.fetchone()
def fetchall(self):
return self.cursor.fetchall()
with SQLUtils._lock:
return self.cursor.fetchall()
def close(self):
"""关闭连接(实际上是将连接返回到连接池)"""
# 这里不再实际关闭连接,让连接池管理连接生命周期
"""关闭当前游标,但保留连接在连接池中"""
# 不再关闭连接,只关闭游标,减少重复创建连接的开销
# 连接仍然保留在连接池中供后续使用
pass
def real_close(self):
"""真正关闭连接,从连接池中移除"""
conn_key = f"{self.db_type}:{str(self.kwargs)}"
with SQLUtils._lock:
if conn_key in SQLUtils._connection_pool:
try:
conn, cursor = SQLUtils._connection_pool[conn_key]
if cursor:
cursor.close()
if conn:
conn.close()
del SQLUtils._connection_pool[conn_key]
logging.debug(f"已关闭并移除连接: {conn_key}")
except Exception as e:
logging.error(f"关闭连接失败: {e}")
@staticmethod
def close_all_connections():
"""关闭所有连接池中的连接"""
for conn, cursor in SQLUtils._connection_pool.values():
try:
if cursor:
cursor.close()
if conn:
conn.close()
except Exception as e:
logging.error(f"关闭数据库连接失败: {e}")
SQLUtils._connection_pool.clear()
logging.info("已关闭所有数据库连接")
with SQLUtils._lock:
for conn, cursor in SQLUtils._connection_pool.values():
try:
if cursor:
cursor.close()
if conn:
conn.close()
except Exception as e:
logging.error(f"关闭数据库连接失败: {e}")
SQLUtils._connection_pool.clear()
logging.info("已关闭所有数据库连接")
@staticmethod
def get_sqlite_connection():

View File

@ -882,7 +882,7 @@ class MainWindow(MainWindowUI):
'remark': '',
'tray_id': tray_id
}]
inspection_dao.save_inspection_data(self._current_order_code,gc_note,gc_note, data)
inspection_dao.save_inspection_data(self._current_order_code,gc_note, data)
# 为贴标和称重也创建空记录
for position in [11, 12, 13]: # 11是贴标12是毛重13是净重
@ -2604,15 +2604,29 @@ class MainWindow(MainWindowUI):
gc_note = data_str.split("扫码数据:")[1].strip()
logging.info(f"提取到工程号: {gc_note}")
# 临时断开returnPressed信号连接避免setText触发信号
try:
self.order_edit.returnPressed.disconnect(self.handle_order_enter)
except Exception:
logging.debug("returnPressed信号未连接或断开失败")
# 设置工程号到输入框
self.order_edit.setText(gc_note)
# 模拟按下回车键触发handle_order_enter方法
# 重新连接returnPressed信号
self.order_edit.returnPressed.connect(self.handle_order_enter)
# 调用一次handle_order_enter方法
self.handle_order_enter()
else:
logging.warning(f"收到的数据不包含扫码数据标记: {data_str}")
except Exception as e:
logging.error(f"处理扫码器数据失败: {str(e)}")
# 确保信号重新连接
try:
self.order_edit.returnPressed.connect(self.handle_order_enter)
except Exception:
pass
def set_inspection_value(self, data_type, config, value):
"""设置检验项目值到表格中