783 lines
29 KiB
Python
783 lines
29 KiB
Python
|
|
'''登录对话模块'''
|
|||
|
|
import os
|
|||
|
|
import json
|
|||
|
|
from pathlib import Path
|
|||
|
|
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
|
|||
|
|
QLineEdit, QPushButton, QMessageBox,
|
|||
|
|
QFileDialog, QCheckBox, QSpacerItem,
|
|||
|
|
QSizePolicy, QFrame)
|
|||
|
|
from PyQt6.QtCore import Qt, pyqtSignal
|
|||
|
|
from PyQt6.QtGui import QFont
|
|||
|
|
|
|||
|
|
import sys
|
|||
|
|
import os
|
|||
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|||
|
|
from login.login import SimpleAuth
|
|||
|
|
|
|||
|
|
class LoginDialog(QDialog):
|
|||
|
|
"""智能登录对话框 - 首次登录自动创建用户"""
|
|||
|
|
|
|||
|
|
login_success = pyqtSignal(str, str) # 登录成功信号:username, config_file_path
|
|||
|
|
|
|||
|
|
def __init__(self, parent=None):
|
|||
|
|
super().__init__(parent)
|
|||
|
|
self.config_file_path = None
|
|||
|
|
self.user_config_path = None
|
|||
|
|
self.user_config_dir = None
|
|||
|
|
self.DEFAULT_CONFIG_FILE = "users.json" # 硬编码的账密文件名
|
|||
|
|
self.setup_ui()
|
|||
|
|
|
|||
|
|
# 检查是否第一次运行
|
|||
|
|
self.check_first_run()
|
|||
|
|
|
|||
|
|
def setup_ui(self):
|
|||
|
|
# 设置窗口标题和大小
|
|||
|
|
self.setWindowTitle("登录")
|
|||
|
|
self.setMinimumSize(600, 400)
|
|||
|
|
self.resize(600, 400)
|
|||
|
|
|
|||
|
|
# 主布局
|
|||
|
|
main_layout = QVBoxLayout(self)
|
|||
|
|
main_layout.setSpacing(20) # 增加间距
|
|||
|
|
main_layout.setContentsMargins(40, 40, 40, 40) # 增加边距
|
|||
|
|
|
|||
|
|
# 用户名输入
|
|||
|
|
username_layout = QVBoxLayout()
|
|||
|
|
username_layout.setSpacing(8)
|
|||
|
|
|
|||
|
|
username_label = QLabel("用户名:")
|
|||
|
|
username_label.setStyleSheet("""
|
|||
|
|
QLabel {
|
|||
|
|
font-weight: bold;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #333333;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
self.username_edit = QLineEdit()
|
|||
|
|
self.username_edit.setPlaceholderText("请输入用户名")
|
|||
|
|
self.username_edit.setMinimumHeight(42)
|
|||
|
|
self.username_edit.setMaximumHeight(42)
|
|||
|
|
self.username_edit.setStyleSheet("""
|
|||
|
|
QLineEdit {
|
|||
|
|
border: 1px solid #cccccc;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 10px 15px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
background-color: white;
|
|||
|
|
}
|
|||
|
|
QLineEdit:focus {
|
|||
|
|
border: 2px solid #3498db;
|
|||
|
|
background-color: #f8fdff;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
username_layout.addWidget(username_label)
|
|||
|
|
username_layout.addWidget(self.username_edit)
|
|||
|
|
main_layout.addLayout(username_layout)
|
|||
|
|
|
|||
|
|
# 添加间距
|
|||
|
|
main_layout.addSpacing(15)
|
|||
|
|
|
|||
|
|
# 密码输入
|
|||
|
|
password_layout = QVBoxLayout()
|
|||
|
|
password_layout.setSpacing(8)
|
|||
|
|
|
|||
|
|
password_label = QLabel("密码:")
|
|||
|
|
password_label.setStyleSheet("""
|
|||
|
|
QLabel {
|
|||
|
|
font-weight: bold;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #333333;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
self.password_edit = QLineEdit()
|
|||
|
|
self.password_edit.setPlaceholderText("请输入密码")
|
|||
|
|
self.password_edit.setEchoMode(QLineEdit.EchoMode.Password)
|
|||
|
|
self.password_edit.setMinimumHeight(42)
|
|||
|
|
self.password_edit.setMaximumHeight(42)
|
|||
|
|
self.password_edit.setStyleSheet("""
|
|||
|
|
QLineEdit {
|
|||
|
|
border: 1px solid #cccccc;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 10px 15px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
background-color: white;
|
|||
|
|
}
|
|||
|
|
QLineEdit:focus {
|
|||
|
|
border: 2px solid #3498db;
|
|||
|
|
background-color: #f8fdff;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
password_layout.addWidget(password_label)
|
|||
|
|
password_layout.addWidget(self.password_edit)
|
|||
|
|
main_layout.addLayout(password_layout)
|
|||
|
|
|
|||
|
|
# 添加弹性空间
|
|||
|
|
main_layout.addSpacing(20)
|
|||
|
|
|
|||
|
|
# 配置文件路径设置
|
|||
|
|
self.config_group = QVBoxLayout()
|
|||
|
|
self.config_group.setSpacing(8)
|
|||
|
|
|
|||
|
|
self.config_path_label = QLabel("账号配置文件目录:")
|
|||
|
|
self.config_path_label.setStyleSheet("""
|
|||
|
|
QLabel {
|
|||
|
|
font-weight: bold;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: #333333;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
# 路径输入和浏览按钮
|
|||
|
|
path_layout = QHBoxLayout()
|
|||
|
|
path_layout.setSpacing(12)
|
|||
|
|
|
|||
|
|
# 文件路径输入框 - 不设置默认路径
|
|||
|
|
self.config_path_edit = QLineEdit()
|
|||
|
|
self.config_path_edit.setPlaceholderText("请选择账号配置文件保存目录")
|
|||
|
|
self.config_path_edit.setMinimumHeight(42)
|
|||
|
|
self.config_path_edit.setMaximumHeight(42)
|
|||
|
|
self.config_path_edit.setStyleSheet("""
|
|||
|
|
QLineEdit {
|
|||
|
|
border: 1px solid #cccccc;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 10px 15px;
|
|||
|
|
font-size: 13px;
|
|||
|
|
background-color: white;
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
QLineEdit:focus {
|
|||
|
|
border: 2px solid #3498db;
|
|||
|
|
background-color: #f8fdff;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
self.config_path_edit.setToolTip(f"请选择账号配置文件存放目录,程序将在此创建 {self.DEFAULT_CONFIG_FILE} 文件")
|
|||
|
|
|
|||
|
|
# 浏览按钮
|
|||
|
|
self.config_browse_btn = QPushButton("浏览")
|
|||
|
|
self.config_browse_btn.setMinimumHeight(42)
|
|||
|
|
self.config_browse_btn.setMinimumWidth(100)
|
|||
|
|
self.config_browse_btn.setStyleSheet("""
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #7f8c8d;
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
padding: 10px 15px;
|
|||
|
|
}
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #95a5a6;
|
|||
|
|
}
|
|||
|
|
QPushButton:pressed {
|
|||
|
|
background-color: #6c7b7d;
|
|||
|
|
padding: 11px 15px 9px 15px;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
self.config_browse_btn.clicked.connect(self.browse_user_config)
|
|||
|
|
|
|||
|
|
# 使用弹性布局:输入框占4份,按钮占1份
|
|||
|
|
path_layout.addWidget(self.config_path_edit, 4)
|
|||
|
|
path_layout.addWidget(self.config_browse_btn, 1)
|
|||
|
|
|
|||
|
|
self.config_group.addWidget(self.config_path_label)
|
|||
|
|
self.config_group.addLayout(path_layout)
|
|||
|
|
|
|||
|
|
# 文件名提示
|
|||
|
|
self.filename_label = QLabel(f"* 账号配置文件将自动保存为:{self.DEFAULT_CONFIG_FILE}")
|
|||
|
|
|
|||
|
|
main_layout.addLayout(self.config_group)
|
|||
|
|
main_layout.addSpacing(15)
|
|||
|
|
|
|||
|
|
# 按钮区域
|
|||
|
|
button_layout = QHBoxLayout()
|
|||
|
|
button_layout.setSpacing(20)
|
|||
|
|
|
|||
|
|
# 左侧添加弹性空间
|
|||
|
|
button_layout.addStretch()
|
|||
|
|
|
|||
|
|
# 退出按钮
|
|||
|
|
self.exit_button = QPushButton("退出")
|
|||
|
|
self.exit_button.setMinimumSize(120, 45)
|
|||
|
|
self.exit_button.setStyleSheet("""
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #95a5a6;
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
padding: 10px 25px;
|
|||
|
|
}
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #7f8c8d;
|
|||
|
|
}
|
|||
|
|
QPushButton:pressed {
|
|||
|
|
background-color: #6c7b7d;
|
|||
|
|
padding: 11px 25px 9px 25px;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
self.exit_button.clicked.connect(self.reject)
|
|||
|
|
|
|||
|
|
# 登录按钮
|
|||
|
|
self.login_button = QPushButton("登录")
|
|||
|
|
self.login_button.setMinimumSize(120, 45)
|
|||
|
|
self.login_button.setStyleSheet("""
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #3498db;
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
padding: 10px 25px;
|
|||
|
|
}
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #2980b9;
|
|||
|
|
}
|
|||
|
|
QPushButton:pressed {
|
|||
|
|
background-color: #1c6ea4;
|
|||
|
|
padding: 11px 25px 9px 25px;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
self.login_button.clicked.connect(self.attempt_login)
|
|||
|
|
|
|||
|
|
button_layout.addWidget(self.exit_button)
|
|||
|
|
button_layout.addWidget(self.login_button)
|
|||
|
|
|
|||
|
|
# 右侧添加弹性空间
|
|||
|
|
button_layout.addStretch()
|
|||
|
|
|
|||
|
|
main_layout.addLayout(button_layout)
|
|||
|
|
|
|||
|
|
# 底部提示信息
|
|||
|
|
self.info_label = QLabel()
|
|||
|
|
self.info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|||
|
|
self.info_label.setStyleSheet("color: #888888; font-size: 12px; margin-top: 10px;")
|
|||
|
|
main_layout.addWidget(self.info_label)
|
|||
|
|
|
|||
|
|
# 添加底部弹性空间
|
|||
|
|
main_layout.addStretch()
|
|||
|
|
|
|||
|
|
# 设置默认焦点
|
|||
|
|
self.username_edit.setFocus()
|
|||
|
|
|
|||
|
|
# 设置回车键事件
|
|||
|
|
self.username_edit.returnPressed.connect(self.password_edit.setFocus)
|
|||
|
|
self.password_edit.returnPressed.connect(self.attempt_login)
|
|||
|
|
self.config_path_edit.returnPressed.connect(self.attempt_login)
|
|||
|
|
|
|||
|
|
def check_first_run(self):
|
|||
|
|
"""检查是否显示目录选择部分"""
|
|||
|
|
# 检查是否有保存的用户配置文件路径
|
|||
|
|
settings_file = Path.home() / ".config_editor" / "user_settings.json"
|
|||
|
|
|
|||
|
|
if settings_file.exists():
|
|||
|
|
try:
|
|||
|
|
with open(settings_file, 'r', encoding='utf-8') as f:
|
|||
|
|
settings = json.load(f)
|
|||
|
|
|
|||
|
|
user_config_dir = settings.get('user_config_dir')
|
|||
|
|
if user_config_dir:
|
|||
|
|
# 构建完整文件路径
|
|||
|
|
user_config_path = os.path.join(user_config_dir, self.DEFAULT_CONFIG_FILE)
|
|||
|
|
|
|||
|
|
# 检查目录和文件是否存在
|
|||
|
|
if os.path.isdir(user_config_dir) and os.path.exists(user_config_path):
|
|||
|
|
# 目录和文件都存在,隐藏目录选择部分
|
|||
|
|
self.user_config_dir = user_config_dir
|
|||
|
|
self.user_config_path = user_config_path
|
|||
|
|
|
|||
|
|
# 更新界面:隐藏目录选择部分
|
|||
|
|
self.config_path_label.setVisible(False)
|
|||
|
|
self.config_path_edit.setVisible(False)
|
|||
|
|
self.config_browse_btn.setVisible(False)
|
|||
|
|
self.filename_label.setVisible(False)
|
|||
|
|
|
|||
|
|
# 更新提示信息
|
|||
|
|
self.info_label.setText(f"账号配置文件位于:{user_config_path}")
|
|||
|
|
return
|
|||
|
|
else:
|
|||
|
|
# 目录存在但文件不存在,显示目录选择部分并填充已保存的目录
|
|||
|
|
self.config_path_edit.setText(user_config_dir)
|
|||
|
|
self.info_label.setText("账号配置文件不存在,请重新选择目录或使用原目录重新创建")
|
|||
|
|
return
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"读取用户设置失败: {e}")
|
|||
|
|
|
|||
|
|
# 第一次运行或设置无效,需要选择目录
|
|||
|
|
self.info_label.setText("首次运行请选择账号配置文件保存目录(首次登录将自动创建用户)")
|
|||
|
|
|
|||
|
|
def save_user_preferences(self, user_config_dir):
|
|||
|
|
"""保存用户选择的配置文件目录"""
|
|||
|
|
try:
|
|||
|
|
settings_dir = Path.home() / ".config_editor"
|
|||
|
|
settings_dir.mkdir(parents=True, exist_ok=True)
|
|||
|
|
|
|||
|
|
settings_file = settings_dir / "user_settings.json"
|
|||
|
|
|
|||
|
|
settings = {
|
|||
|
|
'user_config_dir': user_config_dir,
|
|||
|
|
'config_filename': self.DEFAULT_CONFIG_FILE,
|
|||
|
|
'last_updated': os.path.getmtime(str(settings_file)) if settings_file.exists() else None
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
with open(settings_file, 'w', encoding='utf-8') as f:
|
|||
|
|
json.dump(settings, f, indent=2, ensure_ascii=False)
|
|||
|
|
|
|||
|
|
return True
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"保存用户设置失败: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def browse_user_config(self):
|
|||
|
|
"""浏览并选择账号配置文件目录"""
|
|||
|
|
# 选择目录,而不是文件
|
|||
|
|
dir_path = QFileDialog.getExistingDirectory(
|
|||
|
|
self,
|
|||
|
|
"选择账号配置文件保存目录",
|
|||
|
|
str(Path.home()) # 默认从用户主目录开始
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if dir_path:
|
|||
|
|
# 只保存目录路径
|
|||
|
|
self.config_path_edit.setText(dir_path)
|
|||
|
|
|
|||
|
|
def attempt_login(self):
|
|||
|
|
"""尝试登录(首次登录自动创建用户)"""
|
|||
|
|
username = self.username_edit.text().strip()
|
|||
|
|
password = self.password_edit.text().strip()
|
|||
|
|
|
|||
|
|
# 验证用户名和密码
|
|||
|
|
if not username:
|
|||
|
|
QMessageBox.warning(self, "输入错误", "请输入用户名")
|
|||
|
|
self.username_edit.setFocus()
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
if not password:
|
|||
|
|
QMessageBox.warning(self, "输入错误", "请输入密码")
|
|||
|
|
self.password_edit.setFocus()
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 检查是否需要目录(如果已保存的目录和文件都存在,则不需要)
|
|||
|
|
if not self.user_config_path:
|
|||
|
|
# 需要获取目录
|
|||
|
|
user_config_dir = self.config_path_edit.text().strip()
|
|||
|
|
|
|||
|
|
# 验证路径是否有效
|
|||
|
|
if not user_config_dir:
|
|||
|
|
QMessageBox.warning(self, "输入错误", "请选择账号配置文件保存目录")
|
|||
|
|
self.config_path_edit.setFocus()
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 检查目录是否存在
|
|||
|
|
if not os.path.isdir(user_config_dir):
|
|||
|
|
reply = QMessageBox.question(
|
|||
|
|
self, "目录不存在",
|
|||
|
|
f"选择的目录不存在:{user_config_dir}\n是否创建此目录?",
|
|||
|
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if reply == QMessageBox.StandardButton.Yes:
|
|||
|
|
try:
|
|||
|
|
os.makedirs(user_config_dir, exist_ok=True)
|
|||
|
|
except Exception as e:
|
|||
|
|
QMessageBox.warning(self, "创建目录失败", f"无法创建目录:{str(e)}")
|
|||
|
|
return
|
|||
|
|
else:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 构建完整文件路径
|
|||
|
|
user_config_path = os.path.join(user_config_dir, self.DEFAULT_CONFIG_FILE)
|
|||
|
|
|
|||
|
|
# 保存用户选择的账密文件目录
|
|||
|
|
self.user_config_dir = user_config_dir
|
|||
|
|
self.user_config_path = user_config_path
|
|||
|
|
|
|||
|
|
# 保存用户偏好设置(只保存目录)
|
|||
|
|
self.save_user_preferences(user_config_dir)
|
|||
|
|
|
|||
|
|
# 隐藏目录选择部分
|
|||
|
|
self.config_path_label.setVisible(False)
|
|||
|
|
self.config_path_edit.setVisible(False)
|
|||
|
|
self.config_browse_btn.setVisible(False)
|
|||
|
|
self.filename_label.setVisible(False)
|
|||
|
|
|
|||
|
|
# 更新提示信息
|
|||
|
|
self.info_label.setText(f"账号配置文件位于:{user_config_path}")
|
|||
|
|
|
|||
|
|
# 创建认证管理器,使用完整的文件路径
|
|||
|
|
auth = SimpleAuth(self.user_config_path)
|
|||
|
|
|
|||
|
|
# 验证凭据(首次登录会自动创建用户)
|
|||
|
|
success, message = auth.authenticate(username, password)
|
|||
|
|
|
|||
|
|
if success:
|
|||
|
|
# 如果是首次登录或二级密码未设置,提示设置二级密码
|
|||
|
|
user_info = auth.users.get(username, {})
|
|||
|
|
if not user_info.get("secondary_password"):
|
|||
|
|
self.prompt_set_secondary_password(auth, username)
|
|||
|
|
else:
|
|||
|
|
# 发送登录成功信号,传递用户名和配置文件路径
|
|||
|
|
self.login_success.emit(username, self.user_config_path)
|
|||
|
|
|
|||
|
|
# 关闭对话框
|
|||
|
|
self.accept()
|
|||
|
|
else:
|
|||
|
|
QMessageBox.warning(self, "登录失败", message)
|
|||
|
|
self.password_edit.clear()
|
|||
|
|
self.password_edit.setFocus()
|
|||
|
|
|
|||
|
|
def prompt_set_secondary_password(self, auth, username):
|
|||
|
|
"""提示用户设置二级密码"""
|
|||
|
|
from PyQt6.QtWidgets import QInputDialog
|
|||
|
|
|
|||
|
|
# 弹出对话框要求设置二级密码
|
|||
|
|
secondary_password, ok = QInputDialog.getText(
|
|||
|
|
self, "设置二级密码",
|
|||
|
|
"首次登录需要设置二级密码(用于敏感操作验证):",
|
|||
|
|
QLineEdit.EchoMode.Password
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if ok and secondary_password:
|
|||
|
|
# 确认二级密码
|
|||
|
|
confirm_password, ok2 = QInputDialog.getText(
|
|||
|
|
self, "确认二级密码",
|
|||
|
|
"请再次输入二级密码确认:",
|
|||
|
|
QLineEdit.EchoMode.Password
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if ok2 and secondary_password == confirm_password:
|
|||
|
|
# 设置二级密码
|
|||
|
|
success, message = auth.set_secondary_password(username, secondary_password)
|
|||
|
|
if success:
|
|||
|
|
QMessageBox.information(self, "设置成功", "二级密码设置成功!")
|
|||
|
|
|
|||
|
|
# 发送登录成功信号
|
|||
|
|
self.login_success.emit(username, self.user_config_path)
|
|||
|
|
self.accept()
|
|||
|
|
else:
|
|||
|
|
QMessageBox.warning(self, "设置失败", f"设置二级密码失败:{message}")
|
|||
|
|
self.password_edit.clear()
|
|||
|
|
self.password_edit.setFocus()
|
|||
|
|
elif ok2:
|
|||
|
|
QMessageBox.warning(self, "密码不一致", "两次输入的密码不一致,请重新设置")
|
|||
|
|
self.prompt_set_secondary_password(auth, username)
|
|||
|
|
elif ok:
|
|||
|
|
QMessageBox.warning(self, "密码为空", "二级密码不能为空,请重新设置")
|
|||
|
|
self.prompt_set_secondary_password(auth, username)
|
|||
|
|
else:
|
|||
|
|
QMessageBox.warning(self, "操作取消", "必须设置二级密码才能继续使用")
|
|||
|
|
self.password_edit.clear()
|
|||
|
|
self.password_edit.setFocus()
|
|||
|
|
|
|||
|
|
def get_config_file_path(self) -> str:
|
|||
|
|
"""获取配置文件路径(主配置文件)"""
|
|||
|
|
return self.config_file_path
|
|||
|
|
|
|||
|
|
def get_user_config_path(self) -> str:
|
|||
|
|
"""获取账号配置文件路径(完整路径)"""
|
|||
|
|
return self.user_config_path
|
|||
|
|
|
|||
|
|
class SecondaryPasswordDialog(QDialog):
|
|||
|
|
"""二级密码验证对话框"""
|
|||
|
|
|
|||
|
|
verified = pyqtSignal() # 验证成功信号
|
|||
|
|
|
|||
|
|
def __init__(self, auth_config_path, username, parent=None):
|
|||
|
|
super().__init__(parent)
|
|||
|
|
self.auth_config_path = auth_config_path
|
|||
|
|
self.username = username
|
|||
|
|
self.setup_ui()
|
|||
|
|
|
|||
|
|
def setup_ui(self):
|
|||
|
|
self.setWindowTitle("二级密码验证")
|
|||
|
|
self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint)
|
|||
|
|
self.setMinimumSize(450, 250)
|
|||
|
|
self.resize(450, 250)
|
|||
|
|
|
|||
|
|
layout = QVBoxLayout(self)
|
|||
|
|
layout.setSpacing(25)
|
|||
|
|
layout.setContentsMargins(40, 40, 40, 40)
|
|||
|
|
|
|||
|
|
# 标题
|
|||
|
|
title_label = QLabel("需要验证二级密码")
|
|||
|
|
title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|||
|
|
title_label.setStyleSheet("color: #333333; font-weight: bold; font-size: 16px;")
|
|||
|
|
layout.addWidget(title_label)
|
|||
|
|
|
|||
|
|
layout.addSpacing(15)
|
|||
|
|
|
|||
|
|
# 密码输入
|
|||
|
|
password_layout = QVBoxLayout()
|
|||
|
|
password_layout.setSpacing(10)
|
|||
|
|
|
|||
|
|
# password_label = QLabel("二级密码:")
|
|||
|
|
# password_label.setStyleSheet("font-weight: bold; color: #333333; font-size: 12px;")
|
|||
|
|
|
|||
|
|
self.password_edit = QLineEdit()
|
|||
|
|
self.password_edit.setPlaceholderText("请输入二级密码")
|
|||
|
|
self.password_edit.setEchoMode(QLineEdit.EchoMode.Password)
|
|||
|
|
self.password_edit.setMinimumHeight(48)
|
|||
|
|
self.password_edit.setMaximumHeight(48)
|
|||
|
|
self.password_edit.setStyleSheet("""
|
|||
|
|
QLineEdit {
|
|||
|
|
border: 1px solid #cccccc;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 10px 15px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
QLineEdit:focus {
|
|||
|
|
border: 2px solid #3498db;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
# password_layout.addWidget(password_label)
|
|||
|
|
password_layout.addWidget(self.password_edit)
|
|||
|
|
layout.addLayout(password_layout)
|
|||
|
|
|
|||
|
|
layout.addSpacing(25)
|
|||
|
|
|
|||
|
|
# 按钮
|
|||
|
|
button_layout = QHBoxLayout()
|
|||
|
|
button_layout.setSpacing(20)
|
|||
|
|
|
|||
|
|
button_layout.addStretch()
|
|||
|
|
|
|||
|
|
verify_btn = QPushButton("验证")
|
|||
|
|
verify_btn.setMinimumSize(120, 45)
|
|||
|
|
verify_btn.setStyleSheet("""
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #3498db;
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
padding: 10px 20px;
|
|||
|
|
}
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #2980b9;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
verify_btn.clicked.connect(self.attempt_verify)
|
|||
|
|
|
|||
|
|
cancel_btn = QPushButton("取消")
|
|||
|
|
cancel_btn.setMinimumSize(120, 45)
|
|||
|
|
cancel_btn.setStyleSheet("""
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #95a5a6;
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
padding: 10px 20px;
|
|||
|
|
}
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #7f8c8d;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
cancel_btn.clicked.connect(self.reject)
|
|||
|
|
|
|||
|
|
button_layout.addWidget(verify_btn)
|
|||
|
|
button_layout.addWidget(cancel_btn)
|
|||
|
|
button_layout.addStretch()
|
|||
|
|
|
|||
|
|
layout.addLayout(button_layout)
|
|||
|
|
|
|||
|
|
# 设置焦点和回车键事件
|
|||
|
|
self.password_edit.setFocus()
|
|||
|
|
self.password_edit.returnPressed.connect(self.attempt_verify)
|
|||
|
|
|
|||
|
|
def attempt_verify(self):
|
|||
|
|
"""尝试验证二级密码"""
|
|||
|
|
password = self.password_edit.text().strip()
|
|||
|
|
|
|||
|
|
if not password:
|
|||
|
|
QMessageBox.warning(self, "输入错误", "请输入二级密码")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 创建认证管理器
|
|||
|
|
auth = SimpleAuth(self.auth_config_path)
|
|||
|
|
|
|||
|
|
# 验证二级密码
|
|||
|
|
success, message = auth.verify_secondary_password(self.username, password)
|
|||
|
|
|
|||
|
|
if success:
|
|||
|
|
# 发送验证成功信号
|
|||
|
|
self.verified.emit()
|
|||
|
|
self.accept()
|
|||
|
|
else:
|
|||
|
|
QMessageBox.warning(self, "验证失败", message)
|
|||
|
|
self.password_edit.clear()
|
|||
|
|
self.password_edit.setFocus()
|
|||
|
|
|
|||
|
|
class ReLoginDialog(QDialog):
|
|||
|
|
"""重新登录对话框(会话超时后显示)"""
|
|||
|
|
|
|||
|
|
login_success = pyqtSignal(str, str) # 重新登录成功信号:username, config_file_path
|
|||
|
|
|
|||
|
|
def __init__(self, config_file_path, parent=None):
|
|||
|
|
super().__init__(parent)
|
|||
|
|
self.config_file_path = config_file_path
|
|||
|
|
self.user_config_path = config_file_path
|
|||
|
|
self.setup_ui()
|
|||
|
|
|
|||
|
|
def setup_ui(self):
|
|||
|
|
self.setWindowTitle("会话超时 - 重新登录")
|
|||
|
|
self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint)
|
|||
|
|
self.setMinimumSize(500, 320)
|
|||
|
|
self.resize(500, 320)
|
|||
|
|
|
|||
|
|
layout = QVBoxLayout(self)
|
|||
|
|
layout.setSpacing(25)
|
|||
|
|
layout.setContentsMargins(50, 40, 50, 40)
|
|||
|
|
|
|||
|
|
# 提示信息
|
|||
|
|
info_label = QLabel("会话已超时,请重新登录")
|
|||
|
|
info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|||
|
|
info_label.setStyleSheet("color: #e74c3c; font-weight: bold; font-size: 16px;")
|
|||
|
|
layout.addWidget(info_label)
|
|||
|
|
|
|||
|
|
layout.addSpacing(10)
|
|||
|
|
|
|||
|
|
# 用户名输入
|
|||
|
|
username_layout = QVBoxLayout()
|
|||
|
|
username_layout.setSpacing(10)
|
|||
|
|
|
|||
|
|
# username_label = QLabel("用户名:")
|
|||
|
|
# username_label.setStyleSheet("font-weight: bold; color: #333333; font-size: 14px;")
|
|||
|
|
|
|||
|
|
self.username_edit = QLineEdit()
|
|||
|
|
self.username_edit.setPlaceholderText("请输入用户名")
|
|||
|
|
self.username_edit.setMinimumHeight(48)
|
|||
|
|
self.username_edit.setMaximumHeight(48)
|
|||
|
|
self.username_edit.setStyleSheet("""
|
|||
|
|
QLineEdit {
|
|||
|
|
border: 1px solid #cccccc;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 10px 15px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
QLineEdit:focus {
|
|||
|
|
border: 2px solid #3498db;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
# username_layout.addWidget(username_label)
|
|||
|
|
username_layout.addWidget(self.username_edit)
|
|||
|
|
layout.addLayout(username_layout)
|
|||
|
|
|
|||
|
|
layout.addSpacing(15)
|
|||
|
|
|
|||
|
|
# 密码输入
|
|||
|
|
password_layout = QVBoxLayout()
|
|||
|
|
password_layout.setSpacing(8)
|
|||
|
|
|
|||
|
|
# password_label = QLabel("密码:")
|
|||
|
|
# password_label.setStyleSheet("font-weight: bold; color: #333333; font-size: 14px;")
|
|||
|
|
|
|||
|
|
self.password_edit = QLineEdit()
|
|||
|
|
self.password_edit.setPlaceholderText("请输入密码")
|
|||
|
|
self.password_edit.setEchoMode(QLineEdit.EchoMode.Password)
|
|||
|
|
self.password_edit.setMinimumHeight(42)
|
|||
|
|
self.password_edit.setMaximumHeight(42)
|
|||
|
|
self.password_edit.setStyleSheet("""
|
|||
|
|
QLineEdit {
|
|||
|
|
border: 1px solid #cccccc;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
padding: 10px 15px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
}
|
|||
|
|
QLineEdit:focus {
|
|||
|
|
border: 2px solid #3498db;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
# password_layout.addWidget(password_label)
|
|||
|
|
password_layout.addWidget(self.password_edit)
|
|||
|
|
layout.addLayout(password_layout)
|
|||
|
|
|
|||
|
|
layout.addSpacing(30)
|
|||
|
|
|
|||
|
|
# 按钮
|
|||
|
|
button_layout = QHBoxLayout()
|
|||
|
|
button_layout.setSpacing(30)
|
|||
|
|
|
|||
|
|
button_layout.addStretch()
|
|||
|
|
|
|||
|
|
login_btn = QPushButton("重新登录")
|
|||
|
|
login_btn.setMinimumSize(150, 50)
|
|||
|
|
login_btn.setStyleSheet("""
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #3498db;
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
padding: 10px 25px;
|
|||
|
|
}
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #2980b9;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
login_btn.clicked.connect(self.attempt_login)
|
|||
|
|
|
|||
|
|
cancel_btn = QPushButton("取消")
|
|||
|
|
cancel_btn.setMinimumSize(140, 45)
|
|||
|
|
cancel_btn.setStyleSheet("""
|
|||
|
|
QPushButton {
|
|||
|
|
background-color: #95a5a6;
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
padding: 10px 25px;
|
|||
|
|
}
|
|||
|
|
QPushButton:hover {
|
|||
|
|
background-color: #7f8c8d;
|
|||
|
|
}
|
|||
|
|
""")
|
|||
|
|
cancel_btn.clicked.connect(self.reject)
|
|||
|
|
|
|||
|
|
button_layout.addWidget(login_btn)
|
|||
|
|
button_layout.addWidget(cancel_btn)
|
|||
|
|
button_layout.addStretch()
|
|||
|
|
|
|||
|
|
layout.addLayout(button_layout)
|
|||
|
|
|
|||
|
|
# 设置焦点和回车键事件
|
|||
|
|
self.username_edit.setFocus()
|
|||
|
|
self.username_edit.returnPressed.connect(self.password_edit.setFocus)
|
|||
|
|
self.password_edit.returnPressed.connect(self.attempt_login)
|
|||
|
|
|
|||
|
|
def attempt_login(self):
|
|||
|
|
"""尝试重新登录"""
|
|||
|
|
username = self.username_edit.text().strip()
|
|||
|
|
password = self.password_edit.text().strip()
|
|||
|
|
|
|||
|
|
if not username or not password:
|
|||
|
|
QMessageBox.warning(self, "输入错误", "请输入用户名和密码")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 创建认证管理器,使用原来的账号文件路径
|
|||
|
|
auth = SimpleAuth(self.user_config_path)
|
|||
|
|
|
|||
|
|
# 验证凭据
|
|||
|
|
success, message = auth.authenticate(username, password)
|
|||
|
|
|
|||
|
|
if success:
|
|||
|
|
# 发送重新登录成功信号
|
|||
|
|
self.login_success.emit(username, self.user_config_path)
|
|||
|
|
self.accept()
|
|||
|
|
else:
|
|||
|
|
QMessageBox.warning(self, "登录失败", message)
|
|||
|
|
self.password_edit.clear()
|
|||
|
|
self.password_edit.setFocus()
|