Загрузка данных


import sys
import psycopg2
from PyQt6.QtWidgets import (
    QApplication, QWidget, QLabel, QLineEdit, QPushButton,
    QVBoxLayout, QHBoxLayout, QComboBox, QDateTimeEdit, QTextEdit,
    QMessageBox, QStackedWidget, QTableWidget, QTableWidgetItem, QHeaderView
)
from PyQt6.QtCore import QDateTime

# =====================================================================
# НАСТРОЙКА ПОДКЛЮЧЕНИЯ К ВАШЕЙ СУЩЕСТВУЮЩЕЙ POSTGRESQL
# =====================================================================
DB_NAME = "medical_center"
DB_USER = "postgres"
DB_PASSWORD = "your_password"  # <-- Впишите сюда ваш пароль от postgres
DB_HOST = "localhost"
DB_PORT = "5432"

connect = None
cursor = None


def init_db():
    global connect, cursor
    try:
        # Простое подключение к вашей уже готовой базе данных
        connect = psycopg2.connect(dbname=DB_NAME, user=DB_USER, password=DB_PASSWORD, host=DB_HOST, port=DB_PORT)

        # Гарантируем чтение русского текста без кракозябр
        connect.set_client_encoding('UTF8')
        cursor = connect.cursor()
        print("Успешное подключение к существующей базе данных!")
    except Exception as e:
        print(f"Ошибка подключения к вашей БД: {e}")
        sys.exit(1)


# =====================================================================
# ОКНО АВТОРИЗАЦИИ
# =====================================================================
class LoginWindow(QWidget):
    def __init__(self, switch_window_callback):
        super().__init__()
        self.switch_window = switch_window_callback
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('Авторизация')
        self.resize(300, 180)
        layout = QVBoxLayout()

        self.login_input = QLineEdit(self)
        self.login_input.setPlaceholderText('Логин')
        layout.addWidget(self.login_input)

        self.pass_input = QLineEdit(self)
        self.pass_input.setPlaceholderText('Пароль')
        self.pass_input.setEchoMode(QLineEdit.EchoMode.Password)
        layout.addWidget(self.pass_input)

        self.login_btn = QPushButton('Войти', self)
        self.login_btn.clicked.connect(self.handle_login)
        layout.addWidget(self.login_btn)
        self.setLayout(layout)

    def handle_login(self):
        login = self.login_input.text()
        password = self.pass_input.text()
        try:
            cursor.execute("SELECT role FROM users WHERE login=%s AND password=%s", (login, password))
            result = cursor.fetchone()
            if result:
                # Извлекаем роль в нижнем регистре для точного сопоставления окон
                role = str(result[0]).strip().lower()
                QMessageBox.information(self, 'Успех', f'Вы вошли. Роль: {role}')
                self.switch_window(role)
            else:
                QMessageBox.warning(self, 'Ошибка', 'Неверный логин или пароль')
        except Exception as e:
            QMessageBox.critical(self, 'Ошибка БД', f'{e}')


# =====================================================================
# ОКНО ПАЦИЕНТА (ЗАПИСЬ НА ПРИЕМ — МАКЕТ 1)
# =====================================================================
class PatientWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.load_combobox()

    def init_ui(self):
        self.setWindowTitle('Окно добавления записи на прием')
        self.resize(450, 480)
        layout = QVBoxLayout()

        title = QLabel('Окно добавления записи на прием')
        title.setStyleSheet("font-size: 16px; font-weight: bold; margin-bottom: 10px;")
        layout.addWidget(title)

        layout.addWidget(QLabel('Выберите услугу:'))
        self.comboBox = QComboBox(self)
        layout.addWidget(self.comboBox)

        layout.addWidget(QLabel('Выберите время:'))
        self.dateTimeEdit = QDateTimeEdit(self)
        self.dateTimeEdit.setDateTime(QDateTime.currentDateTime())
        layout.addWidget(self.dateTimeEdit)

        layout.addWidget(QLabel('Опишите проблему:'))
        self.textEdit = QTextEdit(self)
        self.textEdit.setPlaceholderText('Опишите проблему')
        layout.addWidget(self.textEdit)

        self.pushButton = QPushButton('Сохранить', self)
        self.pushButton.clicked.connect(self.add_appointment)
        layout.addWidget(self.pushButton)
        self.setLayout(layout)

    def load_combobox(self):
        try:
            self.comboBox.clear()
            cursor.execute('SELECT id_type_product, name FROM type_products')
            for id_type, name in cursor.fetchall():
                self.comboBox.addItem(str(name), id_type)
        except Exception as e:
            print(f"Ошибка загрузки услуг: {e}")

    def add_appointment(self):
        try:
            service_id = self.comboBox.currentData()
            appointment_time = self.dateTimeEdit.dateTime().toString("yyyy-MM-dd HH:mm:ss")
            problem_description = self.textEdit.toPlainText()

            if not problem_description.strip():
                QMessageBox.warning(self, 'Внимание', 'Пожалуйста, опишите проблему.')
                return

            cursor.execute(
                "INSERT INTO appointments (id_type_product, appointment_time, problem_description) VALUES (%s, %s, %s)",
                (service_id, appointment_time, problem_description)
            )
            connect.commit()
            QMessageBox.information(self, 'Успех', 'Запись успешно сохранена!')
            self.textEdit.clear()
        except Exception as e:
            QMessageBox.critical(self, 'Ошибка', f'{e}')


# =====================================================================
# ОКНО АДМИНИСТРАТОРА (ДОБАВЛЕНИЕ, РЕДАКТИРОВАНИЕ, УДАЛЕНИЕ — МАКЕТ 2)
# =====================================================================
class AdminWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('Управление услугами (Панель Администратора)')
        self.resize(450, 350)
        layout = QVBoxLayout()

        title = QLabel('Панель управления услугами клиники')
        title.setStyleSheet("font-size: 16px; font-weight: bold; margin-bottom: 10px;")
        layout.addWidget(title)

        self.id_input = QLineEdit(self)
        self.id_input.setPlaceholderText('ID Услуги (для Поиска, Изменения или Удаления)')
        layout.addWidget(QLabel('Идентификатор услуги (ID):'))
        layout.addWidget(self.id_input)

        self.name_input = QLineEdit(self)
        self.name_input.setPlaceholderText('Название медицинской услуги')
        layout.addWidget(QLabel('Название услуги:'))
        layout.addWidget(self.name_input)

        btn_layout_1 = QHBoxLayout()
        self.btn_add = QPushButton('Добавить новую', self)
        self.btn_load = QPushButton('Загрузить по ID', self)
        btn_layout_1.addWidget(self.btn_add)
        btn_layout_1.addWidget(self.btn_load)
        layout.addLayout(btn_layout_1)

        btn_layout_2 = QHBoxLayout()
        self.btn_save = QPushButton('Сохранить изменения', self)
        self.btn_delete = QPushButton('Удалить услугу', self)
        btn_layout_2.addWidget(self.btn_save)
        btn_layout_2.addWidget(self.btn_delete)
        layout.addLayout(btn_layout_2)

        self.setLayout(layout)

        self.btn_add.clicked.connect(self.add_service)
        self.btn_load.clicked.connect(self.load_service)
        self.btn_save.clicked.connect(self.save_service)
        self.btn_delete.clicked.connect(self.delete_service)

    def add_service(self):
        name = self.name_input.text()
        if not name.strip():
            QMessageBox.warning(self, 'Ошибка', 'Введите название услуги')
            return
        try:
            cursor.execute("INSERT INTO type_products (name) VALUES (%s)", (name,))
            connect.commit()
            QMessageBox.information(self, 'Успех', 'Новая услуга успешно добавлена!')
            self.name_input.clear()
        except Exception as e:
            QMessageBox.critical(self, 'Ошибка', f'{e}')

    def load_service(self):
        id_serv = self.id_input.text()
        if not id_serv.strip():
            QMessageBox.warning(self, 'Ошибка', 'Введите ID услуги для поиска')
            return
        try:
            cursor.execute("SELECT name FROM type_products WHERE id_type_product = %s", (id_serv,))
            res = cursor.fetchone()
            if res:
                self.name_input.setText(str(res[0]))
                QMessageBox.information(self, 'Успех', 'Данные услуги успешно загружены в форму')
            else:
                QMessageBox.warning(self, 'Ошибка', 'Услуга с таким ID не найдена')
        except Exception as e:
            QMessageBox.critical(self, 'Ошибка', f'{e}')

    def save_service(self):
        id_serv = self.id_input.text()
        name = self.name_input.text()
        if not id_serv.strip() or not name.strip():
            QMessageBox.warning(self, 'Ошибка', 'Заполни поля ID и Название')
            return
        try:
            cursor.execute("UPDATE type_products SET name = %s WHERE id_type_product = %s", (name, id_serv))
            connect.commit()
            QMessageBox.information(self, 'Успех', 'Название услуги успешно изменено')
        except Exception as e:
            QMessageBox.critical(self, 'Ошибка', f'{e}')

    def delete_service(self):
        id_serv = self.id_input.text()
        if not id_serv.strip():
            QMessageBox.warning(self, 'Ошибка', 'Укажите ID услуги для удаления')
            return
        try:
            cursor.execute("DELETE FROM type_products WHERE id_type_product = %s", (id_serv,))
            connect.commit()
            QMessageBox.information(self, 'Успех', 'Услуга полностью удалена из базы')
            self.id_input.clear()
            self.name_input.clear()
        except Exception as e:
            QMessageBox.critical(self, 'Ошибка', f'{e}')

        # =====================================================================
        # ОКНО ВРАЧА (ВЫВОД ЗАПИСЕЙ В ТАБЛИЦУ)
        # =====================================================================

class DoctorWindow(QWidget):
        def __init__(self):  # Исправлено: __init__ вместо init
            super().__init__()
            self.init_ui()
            self.view_appointments()

        def init_ui(self):
            self.setWindowTitle('Панель Врача — Список приемов')
            self.resize(600, 400)
            layout = QVBoxLayout()

            layout.addWidget(QLabel('Список активных записей пациентов на прием:'))

            self.tableWidget = QTableWidget(self)
            self.tableWidget.setColumnCount(3)
            self.tableWidget.setHorizontalHeaderLabels(['Номер записи', 'Медицинская услуга', 'Дата и время приема'])
            self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
            layout.addWidget(self.tableWidget)

            self.btn_refresh = QPushButton('Обновить список', self)
            self.btn_refresh.clicked.connect(self.view_appointments)
            layout.addWidget(self.btn_refresh)

            self.setLayout(layout)

        def view_appointments(self):
            try:
                cursor.execute('''
                            SELECT appointments.id, type_products.name, appointments.appointment_time
                            FROM appointments
                            JOIN type_products ON type_products.id_type_product = appointments.id_type_product
                            ORDER BY appointments.appointment_time DESC
                        ''')
                rows = cursor.fetchall()

                self.tableWidget.setRowCount(0)
                for row_idx, row_data in enumerate(rows):
                    self.tableWidget.insertRow(row_idx)
                    for col_idx, col_data in enumerate(row_data):
                        self.tableWidget.setItem(row_idx, col_idx, QTableWidgetItem(str(col_data)))
            except Exception as e:
                print(f"Ошибка вывода приемов: {e}")

        # =====================================================================
        # ГЛАВНЫЙ СТЕК-КОНТРОЛЛЕР ПРИЛОЖЕНИЯ (МЕНЕДЖЕР СМЕНЫ ОКОН)
        # =====================================================================

class MainController:
    def __init__(self):  # Исправлено: __init__ вместо init
        self.stacked_widget = QStackedWidget()
        self.login_window = LoginWindow(self.switch_window)
        self.stacked_widget.addWidget(self.login_window)
        self.stacked_widget.setCurrentWidget(self.login_window)
        self.stacked_widget.show()

    def switch_window(self, role):
        if role in ['пациент', 'patient']:
            self.patient_window = PatientWindow()
            self.stacked_widget.addWidget(self.patient_window)
            self.stacked_widget.setCurrentWidget(self.patient_window)
        elif role in ['администратор', 'admin']:
            self.admin_window = AdminWindow()
            self.stacked_widget.addWidget(self.admin_window)
            self.stacked_widget.setCurrentWidget(self.admin_window)
        elif role in ['врач', 'doctor']:
            self.doctor_window = DoctorWindow()
            self.stacked_widget.addWidget(self.doctor_window)
            self.stacked_widget.setCurrentWidget(self.doctor_window)
        else:
            QMessageBox.critical(self.login_window, 'Ошибка', f'Роль "{role}" не поддерживается.')


if __name__ == '__main__':  # Исправлено: добавлены двойные подчеркивания
    app = QApplication(sys.argv)
    init_db()
    controller = MainController()
    sys.exit(app.exec())

===============================================================================================
CREATE TABLE users (id SERIAL PRIMARY KEY, login VARCHAR(100), password VARCHAR(100) NOT NULL, role VARCHAR(50));
CREATE TABLE type_products (id_type_product SERIAL PRIMARY KEY, name VARCHAR(255));
CREATE TABLE appointments (id SERIAL PRIMARY KEY, id_type_product INT REFERENCES type_products(id_type_product), appointment_time TIMESTAMP, problem_description TEXT);
INSERT INTO users (login, password, role) VALUES ('admin', 'admin123', 'администратор'), ('doctor', 'doc123', 'врач'), ('patient', 'pat123', 'пациент');
INSERT INTO type_products (name) VALUES ('Прием терапевта'),  ('УЗИ диагностика'), ('Консультация кардиолога');