上传文件至 /

This commit is contained in:
hujinyang 2026-01-19 08:02:47 +00:00
parent ab5321a93c
commit 2c9087ccf9
2 changed files with 1023 additions and 0 deletions

240
login.py Normal file
View File

@ -0,0 +1,240 @@
'''用户认证登录模块'''
import json
import os
import datetime
from pathlib import Path
from typing import Tuple, Optional
class SimpleAuth:
"""用户认证管理器"""
def __init__(self, config_path: str = None):
"""
初始化认证管理器
Args:
config_path: 用户配置文件路径
"""
self.config_path = config_path
self.users = {}
# 初始化时加载用户数据
if config_path:
self.load_users()
def load_users(self) -> bool:
"""加载用户数据"""
try:
if not self.config_path:
print("未设置配置文件路径")
return False
# 如果文件不存在,创建空文件
if not os.path.exists(self.config_path):
print(f"配置文件不存在,创建空文件: {self.config_path}")
return self.create_empty_file()
# 读取文件内容
with open(self.config_path, 'r', encoding='utf-8') as f:
content = f.read().strip()
if not content: # 空文件
self.users = {}
return True
# 解析JSON
self.users = json.loads(content)
print(f"已加载 {len(self.users)} 个用户")
return True
except json.JSONDecodeError:
print("配置文件格式错误,重置为空文件")
return self.create_empty_file()
except Exception as e:
print(f"加载用户数据失败: {e}")
return False
def create_empty_file(self) -> bool:
"""创建空的配置文件"""
try:
if not self.config_path:
return False
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
self.users = {}
with open(self.config_path, 'w', encoding='utf-8') as f:
json.dump({}, f, indent=2, ensure_ascii=False)
print(f"已创建空白配置文件: {self.config_path}")
return True
except Exception as e:
print(f"创建配置文件失败: {e}")
return False
def save_users(self) -> bool:
"""保存用户数据"""
try:
if not self.config_path:
return False
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
with open(self.config_path, 'w', encoding='utf-8') as f:
json.dump(self.users, f, indent=2, ensure_ascii=False)
return True
except Exception as e:
print(f"保存用户数据失败: {e}")
return False
def authenticate(self, username: str, password: str) -> Tuple[bool, str]:
"""
验证用户凭据
重要如果用户不存在则创建用户首次登录即注册
"""
if not username or not password:
return False, "用户名和密码不能为空"
# 加载用户数据
if not self.load_users():
return False, "加载用户数据失败"
# 检查用户名是否存在(作为字典键)
if username not in self.users:
# 首次登录,自动创建用户
print(f"用户 '{username}' 不存在,首次登录将自动创建用户")
return self.create_first_user(username, password)
# 检查密码是否正确
user_info = self.users[username]
if user_info.get("password") != password:
return False, "密码错误"
# 更新最后登录时间
user_info["last_login"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.save_users()
return True, "登录成功"
def create_first_user(self, username: str, password: str) -> Tuple[bool, str]:
"""创建第一个用户(首次登录)"""
try:
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 创建用户信息
self.users[username] = {
"username": username,
"password": password,
"secondary_password": "", # 二级密码初始为空,首次登录后设置
"created_at": current_time,
"last_login": current_time,
"is_first_user": True
}
# 保存用户数据
if self.save_users():
print(f"已创建用户 '{username}' 并登录")
return True, f"首次登录成功,已创建用户 '{username}'"
else:
return False, "创建用户失败"
except Exception as e:
print(f"创建用户失败: {e}")
return False, f"创建用户失败: {str(e)}"
def set_secondary_password(self, username: str, secondary_password: str) -> Tuple[bool, str]:
"""设置二级密码"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
if not secondary_password:
return False, "二级密码不能为空"
# 更新二级密码
self.users[username]["secondary_password"] = secondary_password
self.users[username]["secondary_password_updated_at"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if self.save_users():
return True, "二级密码设置成功"
else:
return False, "保存二级密码失败"
except Exception as e:
return False, f"设置二级密码失败: {str(e)}"
def verify_secondary_password(self, username: str, secondary_password: str) -> Tuple[bool, str]:
"""验证二级密码"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
user_info = self.users[username]
# 检查用户是否设置了二级密码
if not user_info.get("secondary_password"):
return False, "未设置二级密码,请先设置"
# 验证二级密码
if user_info.get("secondary_password") != secondary_password:
return False, "二级密码错误"
return True, "二级密码验证成功"
except Exception as e:
return False, f"验证二级密码失败: {str(e)}"
def get_secondary_password_status(self, username: str) -> Tuple[bool, str]:
"""获取二级密码设置状态"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
user_info = self.users[username]
if user_info.get("secondary_password"):
return True, f"已设置二级密码(更新于: {user_info.get('secondary_password_updated_at', '未知时间')}"
else:
return False, "未设置二级密码"
except Exception as e:
return False, f"获取二级密码状态失败: {str(e)}"
def get_default_config_path(self) -> str:
"""获取默认配置文件路径"""
return str(Path.home() / ".config_editor" / "users.json")
@staticmethod
def validate_config_path(config_path: str) -> bool:
"""验证配置文件路径是否有效"""
try:
# 检查路径是否包含有效的目录
dir_path = os.path.dirname(config_path)
if not dir_path:
return False
# 检查是否是绝对路径
if not os.path.isabs(config_path):
return False
# 检查文件扩展名(可选)
if not config_path.endswith(('.json', '.txt', '.dat')):
return False
return True
except Exception:
return False

783
login_dialog.py Normal file
View File

@ -0,0 +1,783 @@
'''登录对话模块'''
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()