新增日志

This commit is contained in:
zhu-mengmeng 2026-02-28 14:05:55 +08:00
parent a986d57492
commit 1947f5dcda
9 changed files with 191 additions and 39 deletions

View File

@ -2,6 +2,9 @@ import psycopg2
from psycopg2.extras import RealDictCursor from psycopg2.extras import RealDictCursor
import datetime import datetime
import uuid import uuid
from utils.logger import get_logger, log_timing
logger = get_logger("db_manager")
class DatabaseManager: class DatabaseManager:
def __init__(self): def __init__(self):
@ -14,14 +17,16 @@ class DatabaseManager:
} }
self.schema = '"tzwork"' self.schema = '"tzwork"'
@log_timing
def get_connection(self): def get_connection(self):
try: try:
conn = psycopg2.connect(**self.config) conn = psycopg2.connect(**self.config)
return conn return conn
except Exception as e: except Exception as e:
print(f"Database connection error: {e}") logger.error(f"Database connection error: {e}", exc_info=True)
return None return None
@log_timing
def insert_analysis_data(self, data_list): def insert_analysis_data(self, data_list):
conn = self.get_connection() conn = self.get_connection()
if not conn: if not conn:
@ -60,6 +65,7 @@ class DatabaseManager:
conn.close() conn.close()
return False, str(e) return False, str(e)
@log_timing
def authenticate_user(self, user_id, password_md5): def authenticate_user(self, user_id, password_md5):
conn = self.get_connection() conn = self.get_connection()
if not conn: if not conn:
@ -93,11 +99,12 @@ class DatabaseManager:
} }
except Exception as e: except Exception as e:
print(f"Authentication error: {e}") logger.error(f"Authentication error: {e}", exc_info=True)
if conn: if conn:
conn.close() conn.close()
return False, f"认证失败: {str(e)}" return False, f"认证失败: {str(e)}"
@log_timing
def get_latest_sample_data(self): def get_latest_sample_data(self):
""" """
Retrieves the most recently measured sample data, flattened. Retrieves the most recently measured sample data, flattened.
@ -145,7 +152,7 @@ class DatabaseManager:
return result return result
except Exception as e: except Exception as e:
print(f"Query error: {e}") logger.error(f"Query error: {e}", exc_info=True)
if conn: if conn:
conn.close() conn.close()
return None return None
@ -159,6 +166,7 @@ class DatabaseManager:
return "合格" return "合格"
return "不合格" return "不合格"
@log_timing
def insert_inspection_data(self, inspection_data): def insert_inspection_data(self, inspection_data):
""" """
插入检验数据到 e_pz_hjqy_import 插入检验数据到 e_pz_hjqy_import
@ -281,6 +289,7 @@ class DatabaseManager:
conn.close() conn.close()
return False, f"插入失败: {str(e)}" return False, f"插入失败: {str(e)}"
@log_timing
def query_by_gch(self, gch): def query_by_gch(self, gch):
""" """
根据工程号查询产地规格炉号材质等信息 根据工程号查询产地规格炉号材质等信息
@ -322,6 +331,7 @@ class DatabaseManager:
conn.close() conn.close()
return None, f"查询失败: {str(e)}" return None, f"查询失败: {str(e)}"
@log_timing
def get_inspection_list(self, limit=10, offset=0, user_id=''): def get_inspection_list(self, limit=10, offset=0, user_id=''):
""" """
分页获取检验数据列表 分页获取检验数据列表
@ -383,6 +393,7 @@ class DatabaseManager:
conn.close() conn.close()
return None, f"查询失败: {str(e)}" return None, f"查询失败: {str(e)}"
@log_timing
def query_standard_range(self, heat_number, heat_number2): def query_standard_range(self, heat_number, heat_number2):
""" """
根据炉号1(tph)和炉号2(company_ph)查询标准值范围 根据炉号1(tph)和炉号2(company_ph)查询标准值范围

View File

@ -4,6 +4,7 @@ from ui.inspection_window import InspectionWindow
from ui.login_window import LoginWindow from ui.login_window import LoginWindow
from src.session_manager import SessionManager from src.session_manager import SessionManager
from datetime import datetime from datetime import datetime
from utils.logger import setup_logging, get_logger
def get_mock_data(): def get_mock_data():
return [ return [
@ -73,6 +74,9 @@ def get_mock_data():
] ]
def main(): def main():
setup_logging()
logger = get_logger("inspection_app")
logger.info("Application starting...")
app = QApplication(sys.argv) app = QApplication(sys.argv)
font = app.font() font = app.font()

View File

@ -1,7 +1,10 @@
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import os import os
from utils.logger import get_logger, log_timing
logger = get_logger("xml_parser")
class XmlParser: class XmlParser:
@log_timing
def parse_file(self, file_path): def parse_file(self, file_path):
if not os.path.exists(file_path): if not os.path.exists(file_path):
return None, f"文件未找到: {file_path}" return None, f"文件未找到: {file_path}"
@ -123,6 +126,5 @@ class XmlParser:
return extracted_data, "Success" return extracted_data, "Success"
except Exception as e: except Exception as e:
import traceback logger.error(f"Parse error: {str(e)}", exc_info=True)
traceback.print_exc()
return None, f"Parse error: {str(e)}" return None, f"Parse error: {str(e)}"

View File

@ -8,6 +8,8 @@ from src.db_manager import DatabaseManager
from src.xml_parser import XmlParser from src.xml_parser import XmlParser
from utils.readMTP import MTPHandler from utils.readMTP import MTPHandler
from src.session_manager import SessionManager from src.session_manager import SessionManager
from utils.logger import get_logger, log_timing_context
logger = get_logger("base_page")
class BaseInspectionPage(QDialog): class BaseInspectionPage(QDialog):
def __init__(self, title, parent=None): def __init__(self, title, parent=None):
@ -172,6 +174,7 @@ class BaseInspectionPage(QDialog):
self.main_layout.addWidget(button_bar) self.main_layout.addWidget(button_bar)
def on_sync(self): def on_sync(self):
logger.info(f"[{self.page_type}] 开始同步操作")
sync_mode = self.settings.value("sync_mode", "local") sync_mode = self.settings.value("sync_mode", "local")
xml_path = None xml_path = None
@ -189,13 +192,15 @@ class BaseInspectionPage(QDialog):
latest_xml = max(xml_files, key=os.path.getmtime) latest_xml = max(xml_files, key=os.path.getmtime)
xml_path = latest_xml xml_path = latest_xml
target_xml_name = os.path.basename(latest_xml) target_xml_name = os.path.basename(latest_xml)
logger.info(f"本地模式,选定文件: {target_xml_name}")
else: else:
device_name = self.settings.value("mtp_device", "Trizeps VII") device_name = self.settings.value("mtp_device", "Trizeps VII")
remote_path = self.settings.value("mtp_path", "") remote_path = self.settings.value("mtp_path", "")
self.show_info("正在同步", f"正在从设备 [{device_name}] 读取最新数据...") self.show_info("正在同步", f"正在从设备 [{device_name}] 读取最新数据...")
local_cache, filename = self.mtp_handler.get_latest_xml_windows(device_name, remote_path) with log_timing_context(f"MTP同步 设备={device_name}", "base_page"):
local_cache, filename = self.mtp_handler.get_latest_xml_windows(device_name, remote_path)
if not local_cache: if not local_cache:
self.show_info("同步失败", f"MTP同步错误: {filename}") self.show_info("同步失败", f"MTP同步错误: {filename}")
return return
@ -205,7 +210,8 @@ class BaseInspectionPage(QDialog):
# 1.解析xml # 1.解析xml
parser = XmlParser() parser = XmlParser()
parsed_data, msg = parser.parse_file(xml_path) with log_timing_context("XML解析", "base_page"):
parsed_data, msg = parser.parse_file(xml_path)
if not parsed_data: if not parsed_data:
self.show_info("同步失败", f"XML解析错误: {msg}") self.show_info("同步失败", f"XML解析错误: {msg}")
@ -213,19 +219,21 @@ class BaseInspectionPage(QDialog):
# 2. 写入数据 # 2. 写入数据
db = DatabaseManager() db = DatabaseManager()
success, db_msg = db.insert_analysis_data(parsed_data) with log_timing_context("DB写入分析数据", "base_page"):
success, db_msg = db.insert_analysis_data(parsed_data)
if not success: if not success:
self.show_info("数据库错误", f"插入失败: {db_msg}\n(请检查数据库连接)") self.show_info("数据库错误", f"插入失败: {db_msg}\n(请检查数据库连接)")
return return
latest_data = db.get_latest_sample_data() with log_timing_context("DB读取最新样本数据", "base_page"):
latest_data = db.get_latest_sample_data()
if latest_data: if latest_data:
self.update_ui_with_data(latest_data) self.update_ui_with_data(latest_data)
self.show_info("同步成功", f"已同步 {len(parsed_data)} 条元素数据。\n源文件: {target_xml_name}") self.show_info("同步成功", f"已同步 {len(parsed_data)} 条元素数据。\n源文件: {target_xml_name}")
else: else:
self.show_info("同步异常", "数据插入成功但无法读取回显。") self.show_info("同步异常", "数据插入成功但无法读取回显。")
logger.info(f"[{self.page_type}] 同步操作完成")
def update_ui_with_data(self, data): def update_ui_with_data(self, data):
### 更新UI界面如果不符合对不符合的元素字体标红并且 ### 更新UI界面如果不符合对不符合的元素字体标红并且
pass pass
@ -236,6 +244,7 @@ class BaseInspectionPage(QDialog):
def on_submit(self): def on_submit(self):
"""提交检验数据到 e_pz_hjqy_import 表""" """提交检验数据到 e_pz_hjqy_import 表"""
logger.info(f"[{self.page_type}] 开始提交检验数据")
try: try:
# 1. 收集表单数据 # 1. 收集表单数据
gch = self.inputs.get("batch_no").text().strip() if self.inputs.get("batch_no") else "" gch = self.inputs.get("batch_no").text().strip() if self.inputs.get("batch_no") else ""
@ -296,15 +305,19 @@ class BaseInspectionPage(QDialog):
# 6. 插入数据库 # 6. 插入数据库
db = DatabaseManager() db = DatabaseManager()
success, message = db.insert_inspection_data(inspection_data) with log_timing_context(f"DB提交检验数据 gch={gch}", "base_page"):
success, message = db.insert_inspection_data(inspection_data)
if success: if success:
logger.info(f"[{self.page_type}] 提交成功: {message}")
self.show_info("提交成功", message) self.show_info("提交成功", message)
self.clear_data() self.clear_data()
else: else:
logger.warning(f"[{self.page_type}] 提交失败: {message}")
self.show_info("提交失败", message) self.show_info("提交失败", message)
except Exception as e: except Exception as e:
logger.error(f"[{self.page_type}] 提交异常: {e}", exc_info=True)
self.show_info("提交异常", f"发生错误: {str(e)}") self.show_info("提交异常", f"发生错误: {str(e)}")
def show_info(self, title, message): def show_info(self, title, message):

View File

@ -6,6 +6,8 @@ from openpyxl.styles.builtins import headline_1
from ui.base_page import BaseInspectionPage from ui.base_page import BaseInspectionPage
from src.db_manager import DatabaseManager from src.db_manager import DatabaseManager
from utils.logger import get_logger, log_timing_context
logger = get_logger("incoming_inspection")
class IncomingInspectionPage(BaseInspectionPage): class IncomingInspectionPage(BaseInspectionPage):
def __init__(self, parent=None): def __init__(self, parent=None):
@ -241,8 +243,11 @@ class IncomingInspectionPage(BaseInspectionPage):
return return
self.last_gch = gch self.last_gch = gch
data, err = self.db_manager.query_by_gch(gch) logger.info(f"查询工程号: {gch}")
with log_timing_context(f"query_by_gch({gch})", "incoming_inspection"):
data, err = self.db_manager.query_by_gch(gch)
if err: if err:
logger.warning(f"查询失败: {err}")
self.show_info("查询失败", err) self.show_info("查询失败", err)
return return
@ -252,7 +257,6 @@ class IncomingInspectionPage(BaseInspectionPage):
self.inputs["spec1"].setText(data.get("qy_czt") or "") self.inputs["spec1"].setText(data.get("qy_czt") or "")
self.inputs["info1"].setText(data.get("heat_number2") or "") self.inputs["info1"].setText(data.get("heat_number2") or "")
self.inputs["spec2"].setText(data.get("qy_czw") or "") self.inputs["spec2"].setText(data.get("qy_czw") or "")
def update_ui_with_data(self, data): def update_ui_with_data(self, data):
""" """
根据数据库数据更新UI 根据数据库数据更新UI
@ -294,7 +298,8 @@ class IncomingInspectionPage(BaseInspectionPage):
if not hn1 and not hn2: if not hn1 and not hn2:
return return
heat1_range, heat2_range, err = self.db_manager.query_standard_range(hn1, hn2) with log_timing_context("query_standard_range", "incoming_inspection"):
heat1_range, heat2_range, err = self.db_manager.query_standard_range(hn1, hn2)
if err: if err:
self.show_info("标准值查询失败", err) self.show_info("标准值查询失败", err)
return return
@ -334,7 +339,7 @@ class IncomingInspectionPage(BaseInspectionPage):
min_val = float(min_val) if min_val is not None and min_val != '' else None min_val = float(min_val) if min_val is not None and min_val != '' else None
max_val = float(max_val) if max_val is not None and max_val != '' else None max_val = float(max_val) if max_val is not None and max_val != '' else None
except (ValueError, TypeError) as e: except (ValueError, TypeError) as e:
print(e) logger.debug(f"标准值解析异常: {e}")
is_out = False is_out = False
if min_val is not None and value < min_val: if min_val is not None and value < min_val:
is_out = True is_out = True

View File

@ -8,6 +8,8 @@ from ui.incoming_inspection_page import IncomingInspectionPage
from ui.manual_inspection_page import ManualInspectionPage from ui.manual_inspection_page import ManualInspectionPage
from src.db_manager import DatabaseManager from src.db_manager import DatabaseManager
from src.session_manager import SessionManager from src.session_manager import SessionManager
from utils.logger import get_logger, log_timing_context
logger = get_logger("inspection_window")
class InspectionWindow(QMainWindow): class InspectionWindow(QMainWindow):
def __init__(self): def __init__(self):
@ -116,6 +118,7 @@ class InspectionWindow(QMainWindow):
self.is_loading = True self.is_loading = True
self.loading_label.show() self.loading_label.show()
logger.debug(f"触发加载更多数据, page={self.current_page}")
# 使用 QTimer 异步加载,避免阻塞 UI # 使用 QTimer 异步加载,避免阻塞 UI
QTimer.singleShot(100, self._fetch_data) QTimer.singleShot(100, self._fetch_data)
@ -124,9 +127,11 @@ class InspectionWindow(QMainWindow):
"""从数据库获取数据""" """从数据库获取数据"""
offset = self.current_page * self.page_size offset = self.current_page * self.page_size
user_id = self.session_manager.get_user_id() or '' user_id = self.session_manager.get_user_id() or ''
rows, error = self.db_manager.get_inspection_list(self.page_size, offset, user_id=user_id) with log_timing_context(f"get_inspection_list(page={self.current_page})", "inspection_window"):
rows, error = self.db_manager.get_inspection_list(self.page_size, offset, user_id=user_id)
if error: if error:
logger.error(f"加载失败: {error}")
self.loading_label.setText(f"加载失败: {error}") self.loading_label.setText(f"加载失败: {error}")
self.is_loading = False self.is_loading = False
QTimer.singleShot(2000, lambda: self.loading_label.hide()) QTimer.singleShot(2000, lambda: self.loading_label.hide())
@ -141,6 +146,7 @@ class InspectionWindow(QMainWindow):
self.add_card(dict(row)) self.add_card(dict(row))
self.current_page += 1 self.current_page += 1
logger.debug(f"加载了 {len(rows)} 条记录, 当前页={self.current_page}")
if len(rows) < self.page_size: if len(rows) < self.page_size:
self.has_more_data = False self.has_more_data = False

View File

@ -6,6 +6,8 @@ from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QFont from PySide6.QtGui import QFont
import hashlib import hashlib
from src.db_manager import DatabaseManager from src.db_manager import DatabaseManager
from utils.logger import get_logger, log_timing_context
logger = get_logger("login")
class LoginWindow(QMainWindow): class LoginWindow(QMainWindow):
@ -117,12 +119,16 @@ class LoginWindow(QMainWindow):
QMessageBox.warning(self, "登录失败", "请输入账号和密码") QMessageBox.warning(self, "登录失败", "请输入账号和密码")
return return
logger.info(f"用户登录尝试: {user_id}")
password_md5 = hashlib.md5(password.encode()).hexdigest() password_md5 = hashlib.md5(password.encode()).hexdigest()
success, user_info = self.db.authenticate_user(user_id, password_md5) with log_timing_context(f"authenticate_user({user_id})", "login"):
success, user_info = self.db.authenticate_user(user_id, password_md5)
if success: if success:
logger.info(f"登录成功: {user_id}")
self.login_success.emit(user_info) self.login_success.emit(user_info)
self.close() self.close()
else: else:
logger.warning(f"登录失败: {user_id} - {user_info}")
QMessageBox.warning(self, "登录失败", user_info) QMessageBox.warning(self, "登录失败", user_info)
self.password_input.clear() self.password_input.clear()
self.password_input.setFocus() self.password_input.setFocus()

102
utils/logger.py Normal file
View File

@ -0,0 +1,102 @@
import os
import time
import logging
import functools
from logging.handlers import RotatingFileHandler
from contextlib import contextmanager
_logger_initialized = False
LOG_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "logs")
LOG_FILE = os.path.join(LOG_DIR, "app.log")
SLOW_THRESHOLD = 1.0
CRITICAL_THRESHOLD = 5.0
LOG_FORMAT = "[%(asctime)s] [%(levelname)-8s] [%(name)s:%(funcName)s:%(lineno)d] %(message)s"
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
def setup_logging(level=logging.DEBUG):
global _logger_initialized
if _logger_initialized:
return
_logger_initialized = True
os.makedirs(LOG_DIR, exist_ok=True)
root_logger = logging.getLogger("app")
root_logger.setLevel(level)
if root_logger.handlers:
return
formatter = logging.Formatter(LOG_FORMAT, datefmt=DATE_FORMAT)
file_handler = RotatingFileHandler(
LOG_FILE, maxBytes=5 * 1024 * 1024, backupCount=3, encoding="utf-8"
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)
root_logger.addHandler(file_handler)
root_logger.addHandler(console_handler)
def get_logger(name):
return logging.getLogger(f"app.{name}")
def log_timing(func=None, *, logger_name=None):
def decorator(fn):
_logger = get_logger(logger_name or fn.__module__)
@functools.wraps(fn)
def wrapper(*args, **kwargs):
fn_name = fn.__qualname__
_logger.debug(f"[ENTER] {fn_name}")
start = time.perf_counter()
try:
result = fn(*args, **kwargs)
return result
except Exception as e:
_logger.error(f"[ERROR] {fn_name}: {e}", exc_info=True)
raise
finally:
elapsed = time.perf_counter() - start
if elapsed >= CRITICAL_THRESHOLD:
_logger.critical(f"[SLOW!] {fn_name} took {elapsed:.3f}s (>={CRITICAL_THRESHOLD}s)")
elif elapsed >= SLOW_THRESHOLD:
_logger.warning(f"[SLOW] {fn_name} took {elapsed:.3f}s (>={SLOW_THRESHOLD}s)")
else:
_logger.debug(f"[EXIT] {fn_name} took {elapsed:.3f}s")
return wrapper
if func is not None:
return decorator(func)
return decorator
@contextmanager
def log_timing_context(operation, logger_name=None):
_logger = get_logger(logger_name or "timing")
_logger.debug(f"[START] {operation}")
start = time.perf_counter()
try:
yield
except Exception as e:
_logger.error(f"[ERROR] {operation}: {e}", exc_info=True)
raise
finally:
elapsed = time.perf_counter() - start
if elapsed >= CRITICAL_THRESHOLD:
_logger.critical(f"[SLOW!] {operation} took {elapsed:.3f}s (>={CRITICAL_THRESHOLD}s)")
elif elapsed >= SLOW_THRESHOLD:
_logger.warning(f"[SLOW] {operation} took {elapsed:.3f}s (>={SLOW_THRESHOLD}s)")
else:
_logger.debug(f"[DONE] {operation} took {elapsed:.3f}s")

View File

@ -1,5 +1,7 @@
import os import os
import time import time
from utils.logger import get_logger, log_timing
logger = get_logger("mtp")
try: try:
import win32com.client import win32com.client
@ -14,11 +16,12 @@ class MTPHandler:
if not os.path.exists(self.cache_dir): if not os.path.exists(self.cache_dir):
os.makedirs(self.cache_dir) os.makedirs(self.cache_dir)
@log_timing
def get_latest_xml_windows(self, device_name, path_str): def get_latest_xml_windows(self, device_name, path_str):
""" """
Windows MTP 设备上寻找并复制最新的 XML 文件 Windows MTP 设备上寻找并复制最新的 XML 文件
""" """
print(f"\n[MTP] >>> 开始同步工作: 设备={device_name}") logger.info(f"开始同步工作: 设备={device_name}")
if win32com is None: if win32com is None:
return None, "系统未安装 pywin32。" return None, "系统未安装 pywin32。"
@ -31,7 +34,7 @@ class MTPHandler:
device_item = None device_item = None
target_name = device_name.strip().lower() target_name = device_name.strip().lower()
print(f"[MTP] 正在检索设备,目标名称: '{target_name}'") logger.debug(f"正在检索设备,目标名称: '{target_name}'")
items = computer.Items() items = computer.Items()
available_devices = [] available_devices = []
@ -39,12 +42,12 @@ class MTPHandler:
available_devices.append(item.Name) available_devices.append(item.Name)
if item.Name.strip().lower() == target_name: if item.Name.strip().lower() == target_name:
device_item = item device_item = item
print(f"[MTP] 匹配成功: '{item.Name}'") logger.info(f"匹配成功: '{item.Name}'")
break break
if not device_item: if not device_item:
print(f"[MTP] 未找到设备: '{device_name}'") logger.warning(f"未找到设备: '{device_name}'")
print(f"[MTP] 当前电脑识别到的设备列表: {available_devices}") logger.warning(f"当前电脑识别到的设备列表: {available_devices}")
return None, f"未找到 MTP 设备: {device_name} (请检查名称)" return None, f"未找到 MTP 设备: {device_name} (请检查名称)"
current_folder = device_item.GetFolder current_folder = device_item.GetFolder
@ -59,20 +62,20 @@ class MTPHandler:
found = True found = True
break break
if not found: if not found:
print(f"[MTP] 路径中断,找不到文件夹: '{folder_name}'") logger.warning(f"路径中断,找不到文件夹: '{folder_name}'")
# 打印一下当前目录下有的东西,帮用户排查 # 打印一下当前目录下有的东西,帮用户排查
content = [i.Name for i in current_folder.Items()] content = [i.Name for i in current_folder.Items()]
print(f"[MTP] 当前所在位置 [ {current_folder.Title} ] 下的可选内容: {content}") logger.debug(f"当前所在位置 [ {current_folder.Title} ] 下的可选内容: {content}")
return None, f"路径点不存在: {folder_name}" return None, f"路径点不存在: {folder_name}"
# 3. 扫描文件并识别“最新” # 3. 扫描文件并识别“最新”
print(f"[MTP] 已到达目标目录: [ {current_folder.Title} ]") logger.info(f"已到达目标目录: [ {current_folder.Title} ]")
print(f"[MTP] 正在列出该目录下所有项目...") logger.debug(f"正在列出该目录下所有项目...")
print("-" * 40) logger.debug("-" * 40)
xml_items = [] xml_items = []
all_items = current_folder.Items() all_items = current_folder.Items()
print(f"[MTP] 目录内总项数: {all_items.Count}") logger.debug(f"目录内总项数: {all_items.Count}")
for i in range(all_items.Count): for i in range(all_items.Count):
try: try:
@ -83,7 +86,7 @@ class MTPHandler:
# 打印每一个文件的详细信息用于排查 # 打印每一个文件的详细信息用于排查
# 尝试打印前 6 个详情列,看看哪一列是类型,哪一列是时间 # 尝试打印前 6 个详情列,看看哪一列是类型,哪一列是时间
details = [str(current_folder.GetDetailsOf(item, j)) for j in range(6)] details = [str(current_folder.GetDetailsOf(item, j)) for j in range(6)]
if i == 0: print(f"[MTP] 属性列参考(0-5): {details}") if i == 0: logger.debug(f"属性列参考(0-5): {details}")
item_type = details[2] item_type = details[2]
# 识别逻辑: # 识别逻辑:
@ -106,16 +109,16 @@ class MTPHandler:
'time': mtime, 'time': mtime,
'name_ts': name_ts 'name_ts': name_ts
}) })
print(f"[MTP] 识别 XML: '{name}' | 创建/修改时间: {mtime} | 文件名时间: {name_ts}") logger.debug(f"识别 XML: '{name}' | 创建/修改时间: {mtime} | 文件名时间: {name_ts}")
else: else:
pass pass
except Exception as e: except Exception as e:
print(f"[MTP] 读取第 {i} 个项目时出错: {e}") logger.error(f"读取第 {i} 个项目时出错: {e}")
print("-" * 40) logger.debug("-" * 40)
if not xml_items: if not xml_items:
print(f"[MTP] 报错: 在目录 [ {current_folder.Title} ] 中没有找到任何以 .xml 结尾的文件") logger.warning(f"在目录 [ {current_folder.Title} ] 中没有找到任何以 .xml 结尾的文件")
return None, "该目录中没有 XML 文件" return None, "该目录中没有 XML 文件"
# 排序逻辑优化: # 排序逻辑优化:
@ -128,9 +131,9 @@ class MTPHandler:
latest_item = latest['item'] latest_item = latest['item']
filename = latest['name'] filename = latest['name']
print(f"[MTP] 选定最新文件: {filename}") logger.info(f"选定最新文件: {filename}")
print(f"[MTP] - 属性时间: {latest['time']}") logger.debug(f" - 属性时间: {latest['time']}")
print(f"[MTP] - 名称日期: {latest['name_ts']}") logger.debug(f" - 名称日期: {latest['name_ts']}")
# 4. 复制到本地 # 4. 复制到本地
local_path = os.path.abspath(os.path.join(self.cache_dir, filename)) local_path = os.path.abspath(os.path.join(self.cache_dir, filename))
@ -140,7 +143,7 @@ class MTPHandler:
try: os.remove(os.path.join(self.cache_dir, f)) try: os.remove(os.path.join(self.cache_dir, f))
except: pass except: pass
print(f"[MTP] 正在拉取文件到本地缓存...") logger.info(f"正在拉取文件到本地缓存...")
dest_shell_folder = shell.NameSpace(os.path.abspath(self.cache_dir)) dest_shell_folder = shell.NameSpace(os.path.abspath(self.cache_dir))
dest_shell_folder.CopyHere(latest_item, 4 | 16) dest_shell_folder.CopyHere(latest_item, 4 | 16)
@ -153,13 +156,13 @@ class MTPHandler:
time.sleep(0.5) time.sleep(0.5)
if success: if success:
print(f"[MTP] ✨ 同步成功: {filename}") logger.info(f"同步成功: {filename}")
return local_path, filename return local_path, filename
else: else:
return None, "同步超时" return None, "同步超时"
except Exception as e: except Exception as e:
print(f"[MTP] 异常: {e}") logger.error(f"MTP异常: {e}", exc_info=True)
return None, str(e) return None, str(e)
finally: finally:
pythoncom.CoUninitialize() pythoncom.CoUninitialize()