feat: 完成扫码操作
This commit is contained in:
parent
ead4cfcc95
commit
ce8483d298
@ -49,8 +49,8 @@
|
||||
"default_framerate": 30
|
||||
},
|
||||
"modbus": {
|
||||
"host": "192.168.2.88",
|
||||
"port": "502"
|
||||
"host": "localhost",
|
||||
"port": "5020"
|
||||
},
|
||||
"serial": {
|
||||
"keyboard": {
|
||||
|
||||
@ -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()
|
||||
# 使用上下文管理器自动处理连接和游标
|
||||
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', '')
|
||||
|
||||
for item in data:
|
||||
# 验证item是否为字典类型
|
||||
if not isinstance(item, dict):
|
||||
logging.error(f"保存检验数据失败: 数据项必须是字典,实际类型为 {type(item)}")
|
||||
self.db.rollback_transaction()
|
||||
return False
|
||||
|
||||
# 使用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 {}
|
||||
|
||||
BIN
db/jtDB.db
BIN
db/jtDB.db
Binary file not shown.
2973
tests/main_window_old.py
Normal file
2973
tests/main_window_old.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -86,6 +87,9 @@ class SerialManager:
|
||||
logging.info("键盘监听功能已在配置中禁用,跳过初始化键盘监听器")
|
||||
self.keyboard_listener = None
|
||||
|
||||
# 启动线程监控
|
||||
self._start_thread_monitor()
|
||||
|
||||
def _load_config(self):
|
||||
"""加载配置"""
|
||||
try:
|
||||
@ -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 = threading.Thread(
|
||||
target=self._read_thread,
|
||||
args=(port_name,),
|
||||
daemon=True,
|
||||
name=f"Thread-{port_type}-{port_name}"
|
||||
)
|
||||
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
self.read_threads[port_name] = thread
|
||||
# 统一启动线程
|
||||
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,15 +468,45 @@ 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):
|
||||
"""
|
||||
@ -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,6 +601,8 @@ 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):
|
||||
"""处理米电阻响应数据"""
|
||||
@ -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):
|
||||
"""处理扫码器响应数据"""
|
||||
@ -1198,3 +1271,58 @@ class SerialManager:
|
||||
except Exception as e:
|
||||
logging.error(f"处理扫码数据总体异常: {e}")
|
||||
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()
|
||||
@ -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对象
|
||||
@ -84,31 +87,41 @@ 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):
|
||||
"""从连接池获取连接,如果没有则创建新连接"""
|
||||
# 创建连接键,包含数据库类型和连接参数
|
||||
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]
|
||||
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()
|
||||
# 创建新连接
|
||||
self.connect()
|
||||
|
||||
# 将新连接添加到连接池
|
||||
if self.conn and self.cursor:
|
||||
SQLUtils._connection_pool[conn_key] = (self.conn, self.cursor)
|
||||
# 将新连接添加到连接池
|
||||
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}")
|
||||
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("已关闭所有数据库连接")
|
||||
SQLUtils._connection_pool.clear()
|
||||
logging.info("已关闭所有数据库连接")
|
||||
|
||||
@staticmethod
|
||||
def get_sqlite_connection():
|
||||
|
||||
@ -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):
|
||||
"""设置检验项目值到表格中
|
||||
|
||||
Loading…
Reference in New Issue
Block a user