2025-06-07 10:45:09 +08:00
|
|
|
|
import sys
|
|
|
|
|
|
import logging
|
|
|
|
|
|
import os
|
|
|
|
|
|
import tempfile
|
|
|
|
|
|
import traceback
|
|
|
|
|
|
from logging.handlers import TimedRotatingFileHandler
|
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from PySide6.QtWidgets import QApplication, QMessageBox
|
|
|
|
|
|
from PySide6.QtCore import QTranslator, QLocale, QLibraryInfo
|
|
|
|
|
|
from widgets.login_widget import LoginWidget
|
|
|
|
|
|
from utils.menu_translator import MenuTranslator
|
|
|
|
|
|
from utils.config_loader import ConfigLoader
|
|
|
|
|
|
|
|
|
|
|
|
# 自定义异常处理器
|
|
|
|
|
|
def global_exception_handler(exctype, value, tb):
|
|
|
|
|
|
"""全局异常处理器,捕获未处理的异常并记录日志"""
|
|
|
|
|
|
error_msg = ''.join(traceback.format_exception(exctype, value, tb))
|
|
|
|
|
|
logging.critical(f"未捕获的异常: {error_msg}")
|
|
|
|
|
|
|
|
|
|
|
|
# 如果已经有QApplication实例,显示错误对话框
|
|
|
|
|
|
if QApplication.instance():
|
|
|
|
|
|
QMessageBox.critical(None, "系统错误",
|
|
|
|
|
|
f"发生了未处理的错误:\n{value}\n\n请联系管理员并提供日志文件。")
|
|
|
|
|
|
|
|
|
|
|
|
# 调用原始的异常处理器
|
|
|
|
|
|
sys.__excepthook__(exctype, value, tb)
|
|
|
|
|
|
|
|
|
|
|
|
# 安装全局异常处理器
|
|
|
|
|
|
sys.excepthook = global_exception_handler
|
|
|
|
|
|
|
|
|
|
|
|
# 设置日志目录
|
|
|
|
|
|
log_dir = 'logs'
|
|
|
|
|
|
temp_log_dir = None
|
|
|
|
|
|
|
|
|
|
|
|
# 尝试使用应用程序目录
|
|
|
|
|
|
try:
|
|
|
|
|
|
if not os.path.exists(log_dir):
|
|
|
|
|
|
os.makedirs(log_dir, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
# 测试目录是否可写
|
|
|
|
|
|
test_file = os.path.join(log_dir, 'test_write.tmp')
|
|
|
|
|
|
with open(test_file, 'w') as f:
|
|
|
|
|
|
f.write('test')
|
|
|
|
|
|
os.remove(test_file)
|
|
|
|
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
|
|
|
|
|
logging.info(f"使用应用程序日志目录: {os.path.abspath(log_dir)}")
|
|
|
|
|
|
|
|
|
|
|
|
except (OSError, PermissionError) as e:
|
|
|
|
|
|
# 如果应用程序目录不可用或不可写,使用临时目录
|
|
|
|
|
|
temp_log_dir = os.path.join(tempfile.gettempdir(), 'app_logs')
|
|
|
|
|
|
log_dir = temp_log_dir
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
if not os.path.exists(log_dir):
|
|
|
|
|
|
os.makedirs(log_dir, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(message)s')
|
|
|
|
|
|
logging.info(f"无法使用应用程序日志目录,原因: {e}")
|
|
|
|
|
|
logging.info(f"使用临时日志目录: {log_dir}")
|
|
|
|
|
|
except Exception as e2:
|
|
|
|
|
|
# 如果临时目录也失败,只使用控制台输出
|
|
|
|
|
|
print(f"无法创建日志目录,将只使用控制台输出: {e2}")
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
|
|
|
|
|
|
|
|
# 配置全局日志
|
|
|
|
|
|
# 使用日期命名日志文件
|
|
|
|
|
|
today = datetime.now().strftime('%Y-%m-%d')
|
|
|
|
|
|
log_file_path = os.path.join(log_dir, f'app_{today}.log')
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 创建一个TimedRotatingFileHandler,每天轮换一次日志文件
|
|
|
|
|
|
file_handler = TimedRotatingFileHandler(
|
|
|
|
|
|
log_file_path,
|
|
|
|
|
|
when='midnight', # 每天午夜轮换
|
|
|
|
|
|
interval=1, # 轮换间隔为1天
|
|
|
|
|
|
backupCount=30, # 保留30天的日志
|
|
|
|
|
|
encoding='utf-8' # 使用UTF-8编码
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 配置日志格式
|
|
|
|
|
|
log_format = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s:%(lineno)d] - %(message)s')
|
|
|
|
|
|
file_handler.setFormatter(log_format)
|
|
|
|
|
|
|
|
|
|
|
|
# 控制台输出处理器
|
|
|
|
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
|
|
|
|
console_handler.setFormatter(log_format)
|
|
|
|
|
|
|
|
|
|
|
|
# 配置根日志记录器
|
|
|
|
|
|
root_logger = logging.getLogger()
|
|
|
|
|
|
root_logger.setLevel(logging.INFO) # 将默认级别设为INFO,减少DEBUG级别的输出
|
|
|
|
|
|
# 清除已有的handlers
|
|
|
|
|
|
for handler in root_logger.handlers[:]:
|
|
|
|
|
|
root_logger.removeHandler(handler)
|
|
|
|
|
|
root_logger.addHandler(file_handler)
|
|
|
|
|
|
root_logger.addHandler(console_handler)
|
|
|
|
|
|
|
|
|
|
|
|
logging.info("=================================================================")
|
|
|
|
|
|
logging.info("应用程序启动")
|
|
|
|
|
|
logging.info(f"Python version: {sys.version}")
|
|
|
|
|
|
logging.info(f"Working directory: {os.getcwd()}")
|
|
|
|
|
|
logging.info(f"日志文件: {log_file_path}")
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
# 如果文件处理器创建失败,仅使用控制台输出
|
|
|
|
|
|
logging.error(f"无法设置日志文件,将只使用控制台输出: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
# 确保根logger至少有一个控制台处理器
|
|
|
|
|
|
root_logger = logging.getLogger()
|
|
|
|
|
|
if not root_logger.handlers:
|
|
|
|
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
|
|
|
|
console_format = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - [%(funcName)s:%(lineno)d] - %(message)s')
|
|
|
|
|
|
console_handler.setFormatter(console_format)
|
|
|
|
|
|
root_logger.addHandler(console_handler)
|
|
|
|
|
|
|
|
|
|
|
|
logging.info("=================================================================")
|
|
|
|
|
|
logging.info("应用程序启动 (仅控制台日志)")
|
|
|
|
|
|
logging.info(f"Python version: {sys.version}")
|
|
|
|
|
|
logging.info(f"Working directory: {os.getcwd()}")
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
"""主程序入口"""
|
|
|
|
|
|
|
|
|
|
|
|
app = QApplication(sys.argv)
|
|
|
|
|
|
logging.info("=====================================================")
|
|
|
|
|
|
logging.info(" 应用程序启动 ")
|
|
|
|
|
|
logging.info("=====================================================")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 读取配置
|
|
|
|
|
|
config = ConfigLoader.get_instance()
|
|
|
|
|
|
# 打印关键配置信息
|
2025-06-12 17:29:35 +08:00
|
|
|
|
enable_serial_ports = config.get_value('serial.printer.enabled', False)
|
|
|
|
|
|
# 键盘监听器配置信息
|
|
|
|
|
|
enable_keyboard_listener = config.get_value('serial.keyboard.enabled', False)
|
2025-06-07 10:45:09 +08:00
|
|
|
|
logging.info(f"配置信息 - 启用串口: {enable_serial_ports}, 启用键盘监听: {enable_keyboard_listener}")
|
|
|
|
|
|
|
|
|
|
|
|
# 设置中文翻译器
|
|
|
|
|
|
translator = QTranslator(app)
|
|
|
|
|
|
# 使用兼容新旧版本的方式获取翻译路径
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 新版本API
|
|
|
|
|
|
translations_path = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath)
|
|
|
|
|
|
except AttributeError:
|
|
|
|
|
|
# 旧版本API
|
|
|
|
|
|
translations_path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
|
|
|
|
|
|
|
|
|
|
|
|
# 尝试加载翻译文件
|
|
|
|
|
|
translation_loaded = translator.load("qt_zh_CN", translations_path)
|
|
|
|
|
|
|
|
|
|
|
|
# 如果加载失败,尝试在可执行文件目录下查找翻译文件
|
|
|
|
|
|
if not translation_loaded and getattr(sys, 'frozen', False):
|
|
|
|
|
|
# 打包后的应用
|
|
|
|
|
|
app_dir = os.path.dirname(sys.executable)
|
|
|
|
|
|
possible_paths = [
|
|
|
|
|
|
os.path.join(app_dir, "translations"),
|
|
|
|
|
|
os.path.join(app_dir, "PySide6", "translations"),
|
|
|
|
|
|
os.path.join(app_dir, "Qt", "translations"),
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
for path in possible_paths:
|
|
|
|
|
|
if os.path.exists(path):
|
|
|
|
|
|
if translator.load("qt_zh_CN", path):
|
|
|
|
|
|
translation_loaded = True
|
|
|
|
|
|
translations_path = path
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
app.installTranslator(translator)
|
|
|
|
|
|
|
|
|
|
|
|
# 设置应用程序的本地化
|
|
|
|
|
|
locale = QLocale(QLocale.Chinese, QLocale.China)
|
|
|
|
|
|
QLocale.setDefault(locale)
|
|
|
|
|
|
|
|
|
|
|
|
# 安装菜单翻译器
|
|
|
|
|
|
MenuTranslator.install_menu_translator(app)
|
|
|
|
|
|
|
|
|
|
|
|
logging.info(f"已设置中文翻译器,翻译路径: {translations_path},加载状态: {translation_loaded}")
|
|
|
|
|
|
|
|
|
|
|
|
# 创建db目录(如果不存在)
|
|
|
|
|
|
os.makedirs('db', exist_ok=True)
|
|
|
|
|
|
|
2025-06-13 17:14:03 +08:00
|
|
|
|
# 从配置获取SQLite数据库路径
|
|
|
|
|
|
config_loader = ConfigLoader.get_instance()
|
|
|
|
|
|
sqlite_config = config_loader.get_database_config('sqlite')
|
|
|
|
|
|
sqlite_db_path = sqlite_config.get('path', 'db/jtDB.db')
|
|
|
|
|
|
|
2025-06-07 10:45:09 +08:00
|
|
|
|
# 检查数据库是否存在,如果不存在则初始化
|
2025-06-13 17:14:03 +08:00
|
|
|
|
if not os.path.exists(sqlite_db_path):
|
2025-06-07 10:45:09 +08:00
|
|
|
|
from utils.init_db import init_database
|
|
|
|
|
|
init_database()
|
|
|
|
|
|
logging.info("初始化数据库完成")
|
|
|
|
|
|
|
|
|
|
|
|
login_widget = LoginWidget()
|
|
|
|
|
|
login_widget.show()
|
|
|
|
|
|
|
|
|
|
|
|
exit_code = app.exec()
|
|
|
|
|
|
logging.info(f"应用程序退出,退出码: {exit_code}")
|
2025-06-13 17:14:03 +08:00
|
|
|
|
|
|
|
|
|
|
# 关闭所有数据库连接
|
|
|
|
|
|
from utils.sql_utils import SQLUtils
|
|
|
|
|
|
SQLUtils.close_all_connections()
|
|
|
|
|
|
|
2025-06-07 10:45:09 +08:00
|
|
|
|
sys.exit(exit_code)
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logging.critical(f"严重错误: {e}", exc_info=True)
|
|
|
|
|
|
print(f"严重错误: {e}") # 确保即使日志系统故障也能看到错误
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
main()
|