253 lines
9.7 KiB
Python
253 lines
9.7 KiB
Python
# gui/login_window.py
|
||
"""
|
||
Окно авторизации менеджера
|
||
Соответствует требованиям ТЗ по аутентификации
|
||
"""
|
||
import sys
|
||
from PyQt6.QtWidgets import (QApplication, QDialog, QVBoxLayout, QHBoxLayout,
|
||
QLabel, QLineEdit, QPushButton, QMessageBox,
|
||
QFrame, QCheckBox)
|
||
from PyQt6.QtCore import Qt, pyqtSignal
|
||
from PyQt6.QtGui import QFont, QPixmap, QIcon
|
||
import requests
|
||
from requests.auth import HTTPBasicAuth
|
||
|
||
class LoginWindow(QDialog):
|
||
"""Окно авторизации системы MasterPol"""
|
||
|
||
login_success = pyqtSignal(dict) # Сигнал об успешной авторизации
|
||
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.setup_ui()
|
||
self.load_settings()
|
||
|
||
def setup_ui(self):
|
||
"""Настройка интерфейса окна авторизации"""
|
||
self.setWindowTitle("MasterPol - Авторизация")
|
||
self.setFixedSize(400, 500)
|
||
self.setModal(True)
|
||
|
||
# Установка иконки приложения
|
||
try:
|
||
self.setWindowIcon(QIcon("resources/icon.png"))
|
||
except:
|
||
pass
|
||
|
||
layout = QVBoxLayout()
|
||
layout.setContentsMargins(30, 30, 30, 30)
|
||
layout.setSpacing(0)
|
||
|
||
# Заголовок
|
||
title_label = QLabel("MasterPol")
|
||
title_label.setFont(QFont("Arial", 24, QFont.Weight.Bold))
|
||
title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||
title_label.setStyleSheet("color: #007acc; margin-bottom: 20px;")
|
||
|
||
subtitle_label = QLabel("Система управления партнерами")
|
||
subtitle_label.setFont(QFont("Arial", 12))
|
||
subtitle_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||
subtitle_label.setStyleSheet("color: #666; margin-bottom: 30px;")
|
||
|
||
layout.addWidget(title_label)
|
||
layout.addWidget(subtitle_label)
|
||
|
||
# Форма авторизаци
|
||
form_frame = QFrame()
|
||
form_frame.setStyleSheet("""
|
||
QFrame {
|
||
background-color: white;
|
||
border: 0px solid #ddd;
|
||
border-radius: 4px;
|
||
padding: 20px;
|
||
}
|
||
""")
|
||
|
||
form_layout = QVBoxLayout()
|
||
form_layout.setSpacing(15)
|
||
|
||
# Поле логина
|
||
username_layout = QVBoxLayout()
|
||
username_label = QLabel("Имя пользователя:")
|
||
username_label.setStyleSheet("font-weight: bold; color: #333;")
|
||
|
||
self.username_input = QLineEdit()
|
||
self.username_input.setPlaceholderText("Введите имя пользователя")
|
||
self.username_input.setStyleSheet("""
|
||
QLineEdit {
|
||
padding: 8px 12px;
|
||
border: 2px solid #ccc;
|
||
border-radius: 6px;
|
||
font-size: 14px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #007acc;
|
||
}
|
||
""")
|
||
|
||
username_layout.addWidget(username_label)
|
||
username_layout.addWidget(self.username_input)
|
||
|
||
# Поле пароля
|
||
password_layout = QVBoxLayout()
|
||
password_label = QLabel("Пароль:")
|
||
password_label.setStyleSheet("font-weight: bold; color: #333;")
|
||
|
||
self.password_input = QLineEdit()
|
||
self.password_input.setPlaceholderText("Введите пароль")
|
||
self.password_input.setEchoMode(QLineEdit.EchoMode.Password)
|
||
self.password_input.setStyleSheet("""
|
||
QLineEdit {
|
||
padding: 10px;
|
||
border: 1px solid #ccc;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
}
|
||
QLineEdit:focus {
|
||
border-color: #007acc;
|
||
}
|
||
""")
|
||
|
||
password_layout.addWidget(password_label)
|
||
password_layout.addWidget(self.password_input)
|
||
|
||
# Запомнить меня
|
||
self.remember_checkbox = QCheckBox("Запомнить меня")
|
||
self.remember_checkbox.setStyleSheet("color: #333;")
|
||
|
||
# Кнопка входа
|
||
self.login_button = QPushButton("Войти в систему")
|
||
self.login_button.clicked.connect(self.authenticate)
|
||
self.login_button.setStyleSheet("""
|
||
QPushButton {
|
||
background-color: #007acc;
|
||
color: white;
|
||
border: none;
|
||
padding: 12px;
|
||
border-radius: 4px;
|
||
font-weight: bold;
|
||
font-size: 14px;
|
||
}
|
||
QPushButton:hover {
|
||
background-color: #005a9e;
|
||
}
|
||
QPushButton:disabled {
|
||
background-color: #ccc;
|
||
color: #666;
|
||
}
|
||
""")
|
||
|
||
# Подсказка
|
||
hint_label = QLabel("Используйте логин: manager, пароль: pass123")
|
||
hint_label.setStyleSheet("color: #666; font-size: 12px; margin-top: 10px;")
|
||
hint_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||
|
||
form_layout.addLayout(username_layout)
|
||
form_layout.addLayout(password_layout)
|
||
form_layout.addWidget(self.remember_checkbox)
|
||
form_layout.addWidget(self.login_button)
|
||
form_layout.addWidget(hint_label)
|
||
|
||
form_frame.setLayout(form_layout)
|
||
layout.addWidget(form_frame)
|
||
|
||
# Информация о системе
|
||
info_label = QLabel("MasterPol v1.0.0\nСистема управления партнерами и продажами")
|
||
info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||
info_label.setStyleSheet("color: #999; font-size: 11px; margin-top: 20px;")
|
||
layout.addWidget(info_label)
|
||
|
||
self.setLayout(layout)
|
||
|
||
# Подключаем обработчики событий
|
||
self.username_input.returnPressed.connect(self.authenticate)
|
||
self.password_input.returnPressed.connect(self.authenticate)
|
||
|
||
def load_settings(self):
|
||
"""Загрузка сохраненных настроек авторизации"""
|
||
try:
|
||
# Здесь можно добавить загрузку из файла настроек
|
||
# Пока просто устанавливаем значения по умолчанию
|
||
self.username_input.setText("manager")
|
||
except:
|
||
pass
|
||
|
||
def save_settings(self):
|
||
"""Сохранение настроек авторизации"""
|
||
if self.remember_checkbox.isChecked():
|
||
# Здесь можно добавить сохранение в файл настроек
|
||
pass
|
||
|
||
def authenticate(self):
|
||
"""Аутентификация пользователя"""
|
||
username = self.username_input.text().strip()
|
||
password = self.password_input.text().strip()
|
||
|
||
if not username or not password:
|
||
QMessageBox.warning(self, "Ошибка", "Заполните все поля")
|
||
return
|
||
|
||
# Блокируем кнопку во время аутентификации
|
||
self.login_button.setEnabled(False)
|
||
self.login_button.setText("Проверка...")
|
||
|
||
try:
|
||
# Выполняем аутентификацию через API
|
||
response = requests.post(
|
||
"http://localhost:8000/api/v1/auth/login",
|
||
auth=HTTPBasicAuth(username, password),
|
||
timeout=10
|
||
)
|
||
|
||
if response.status_code == 200:
|
||
user_data = response.json()
|
||
|
||
# Сохраняем настройки
|
||
self.save_settings()
|
||
|
||
# Сохраняем учетные данные для будущих запросов
|
||
user_data['auth'] = HTTPBasicAuth(username, password)
|
||
|
||
# Отправляем сигнал об успешной авторизации
|
||
self.login_success.emit(user_data)
|
||
|
||
else:
|
||
QMessageBox.warning(
|
||
self,
|
||
"Ошибка авторизации",
|
||
"Неверное имя пользователя или пароль"
|
||
)
|
||
|
||
except requests.exceptions.ConnectionError:
|
||
QMessageBox.critical(
|
||
self,
|
||
"Ошибка подключения",
|
||
"Не удалось подключиться к серверу.\n"
|
||
"Убедитесь, что сервер запущен на localhost:8000"
|
||
)
|
||
except requests.exceptions.Timeout:
|
||
QMessageBox.critical(
|
||
self,
|
||
"Ошибка подключения",
|
||
"Превышено время ожидания ответа от сервера"
|
||
)
|
||
except Exception as e:
|
||
QMessageBox.critical(
|
||
self,
|
||
"Ошибка",
|
||
f"Произошла непредвиденная ошибка:\n{str(e)}"
|
||
)
|
||
finally:
|
||
# Разблокируем кнопку
|
||
self.login_button.setEnabled(True)
|
||
self.login_button.setText("Войти в систему")
|
||
|
||
def main():
|
||
"""Точка входа для тестирования окна авторизации"""
|
||
app = QApplication(sys.argv)
|
||
window = LoginWindow()
|
||
window.show()
|
||
sys.exit(app.exec())
|
||
|
||
if __name__ == "__main__":
|
||
main()
|