Initial
This commit is contained in:
commit
95c854f215
9 changed files with 287 additions and 0 deletions
BIN
__pycache__/base.cpython-314.pyc
Normal file
BIN
__pycache__/base.cpython-314.pyc
Normal file
Binary file not shown.
BIN
__pycache__/composer.cpython-314.pyc
Normal file
BIN
__pycache__/composer.cpython-314.pyc
Normal file
Binary file not shown.
BIN
__pycache__/data.cpython-314.pyc
Normal file
BIN
__pycache__/data.cpython-314.pyc
Normal file
Binary file not shown.
BIN
__pycache__/windows.cpython-314.pyc
Normal file
BIN
__pycache__/windows.cpython-314.pyc
Normal file
Binary file not shown.
15
base.py
Normal file
15
base.py
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
from PyQt6.QtWidgets import QWidget
|
||||||
|
|
||||||
|
class BaseWindow(QWidget):
|
||||||
|
def __init__(self, window_title: str, username: str, composer: object):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._composer = composer
|
||||||
|
|
||||||
|
title: str = "%s - %s" % (window_title, username)
|
||||||
|
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self._setup_ui()
|
||||||
|
|
||||||
|
def _setup_ui(self):
|
||||||
|
pass
|
||||||
39
composer.py
Normal file
39
composer.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import sys
|
||||||
|
from base import BaseWindow
|
||||||
|
from windows import CustomerWindow, CashierWindow, LoginWindow
|
||||||
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
from PyQt6.QtCore import pyqtSignal, pyqtSlot, QObject
|
||||||
|
|
||||||
|
|
||||||
|
class Composer(QObject):
|
||||||
|
render_request = pyqtSignal(str)
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
app: QApplication
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._app = app
|
||||||
|
self._entry = LoginWindow("Окно Авторизации", "", self)
|
||||||
|
self._current = None
|
||||||
|
|
||||||
|
self.render_request.connect(self._render)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self._current = self._entry
|
||||||
|
self._current.show()
|
||||||
|
sys.exit(self._app.exec())
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def _render(self, user: str):
|
||||||
|
if self._current:
|
||||||
|
self._current.close()
|
||||||
|
|
||||||
|
match user:
|
||||||
|
case "Покупатель":
|
||||||
|
window = CustomerWindow("Покупатель", user, self)
|
||||||
|
case "Кассир":
|
||||||
|
window = CashierWindow("Кассир", user, self)
|
||||||
|
|
||||||
|
self._current = window
|
||||||
|
self._current.show()
|
||||||
18
data.py
Normal file
18
data.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
USERS = {
|
||||||
|
'petlover': {'password': '1111', 'role': 'Покупатель'},
|
||||||
|
'cash1': {'password': '2222', 'role': 'Кассир'},
|
||||||
|
}
|
||||||
|
|
||||||
|
PRODUCTS = [
|
||||||
|
{'name': 'Корм кошек', 'animal': 'Кот', 'price': 500},
|
||||||
|
{'name': 'Игрушка', 'animal': 'Собака', 'price': 300},
|
||||||
|
]
|
||||||
|
|
||||||
|
ORDERS = [
|
||||||
|
{'id': '1', 'customer': 'Анна Петрова',
|
||||||
|
'sum': '2500 р.', 'status': 'Новый'},
|
||||||
|
{'id': '2', 'customer': 'Иван Иванов',
|
||||||
|
'sum': '1800 р.', 'status': 'Оплачен'},
|
||||||
|
]
|
||||||
|
|
||||||
|
STATUS_OPTIONS = ['Новый', 'Оплачен', 'Отправлен', 'Отменён']
|
||||||
12
main.py
Normal file
12
main.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import sys
|
||||||
|
from composer import Composer
|
||||||
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
composer = Composer(app)
|
||||||
|
composer.run()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
203
windows.py
Normal file
203
windows.py
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QLabel, QLineEdit, QComboBox, QPushButton,
|
||||||
|
QMessageBox, QHBoxLayout, QVBoxLayout, QFormLayout, QTableWidget,
|
||||||
|
QTableWidgetItem, QSpinBox, QGroupBox, QFrame
|
||||||
|
)
|
||||||
|
from PyQt6.QtCore import Qt
|
||||||
|
|
||||||
|
from base import BaseWindow
|
||||||
|
from data import USERS, PRODUCTS, ORDERS, STATUS_OPTIONS
|
||||||
|
|
||||||
|
class LoginWindow(BaseWindow):
|
||||||
|
def _setup_ui(self):
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
form = QFormLayout()
|
||||||
|
self.login_edit = QLineEdit()
|
||||||
|
self.pass_edit = QLineEdit()
|
||||||
|
self.pass_edit.setEchoMode(QLineEdit.EchoMode.Password)
|
||||||
|
self.role_combo = QComboBox()
|
||||||
|
self.role_combo.addItems(['Покупатель', 'Кассир'])
|
||||||
|
|
||||||
|
form.addRow('Логин:', self.login_edit)
|
||||||
|
form.addRow('Пароль:', self.pass_edit)
|
||||||
|
form.addRow('Роль:', self.role_combo)
|
||||||
|
|
||||||
|
self.login_btn = QPushButton('Войти в систему')
|
||||||
|
self.login_btn.clicked.connect(self.try_login)
|
||||||
|
|
||||||
|
layout.addLayout(form)
|
||||||
|
layout.addWidget(self.login_btn)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def try_login(self):
|
||||||
|
username = self.login_edit.text().strip()
|
||||||
|
password = self.pass_edit.text()
|
||||||
|
role = self.role_combo.currentText()
|
||||||
|
|
||||||
|
if username not in USERS:
|
||||||
|
QMessageBox.critical(self, 'Ошибка', 'Пользователь не найден')
|
||||||
|
return
|
||||||
|
user = USERS[username]
|
||||||
|
if password != user['password']:
|
||||||
|
QMessageBox.critical(self, 'Ошибка', 'Неправильный пароль')
|
||||||
|
return
|
||||||
|
if role != user['role']:
|
||||||
|
QMessageBox.critical(self, 'Ошибка',
|
||||||
|
'Выбранная роль не совпадает с ролью пользователя')
|
||||||
|
return
|
||||||
|
|
||||||
|
if role == 'Покупатель':
|
||||||
|
self._composer.render_request.emit("Покупатель")
|
||||||
|
else:
|
||||||
|
self._composer.render_request.emit("Кассир")
|
||||||
|
|
||||||
|
class CustomerWindow(BaseWindow):
|
||||||
|
def _setup_ui(self):
|
||||||
|
main_layout = QVBoxLayout()
|
||||||
|
|
||||||
|
top_layout = QHBoxLayout()
|
||||||
|
|
||||||
|
left_box = QVBoxLayout()
|
||||||
|
self.table = QTableWidget(len(PRODUCTS), 3)
|
||||||
|
self.table.setHorizontalHeaderLabels([
|
||||||
|
'Товар', 'Тип животного', 'Цена'
|
||||||
|
])
|
||||||
|
self.table.setSelectionBehavior(
|
||||||
|
self.table.SelectionBehavior.SelectRows
|
||||||
|
)
|
||||||
|
self.table.setEditTriggers(self.table.EditTrigger.NoEditTriggers)
|
||||||
|
for row, p in enumerate(PRODUCTS):
|
||||||
|
self.table.setItem(row, 0, QTableWidgetItem(p['name']))
|
||||||
|
self.table.setItem(row, 1, QTableWidgetItem(p['animal']))
|
||||||
|
self.table.setItem(row, 2, QTableWidgetItem(f"{p['price']} р."))
|
||||||
|
left_box.addWidget(self.table)
|
||||||
|
|
||||||
|
self.select_btn = QPushButton('Выбрать товар')
|
||||||
|
self.select_btn.clicked.connect(self.select_product)
|
||||||
|
left_box.addWidget(self.select_btn)
|
||||||
|
|
||||||
|
top_layout.addLayout(left_box, 2)
|
||||||
|
|
||||||
|
# Правая колонка: расчёт стоимости
|
||||||
|
right_group = QGroupBox('Расчёт стоимости')
|
||||||
|
right_layout = QFormLayout()
|
||||||
|
|
||||||
|
self.price_edit = QLineEdit()
|
||||||
|
self.price_edit.setReadOnly(True)
|
||||||
|
self.quantity_spin = QSpinBox()
|
||||||
|
self.quantity_spin.setRange(1, 1000)
|
||||||
|
self.quantity_spin.setValue(1)
|
||||||
|
|
||||||
|
self.calc_btn = QPushButton('Рассчитать стоимость')
|
||||||
|
self.calc_btn.setStyleSheet('background-color: #4CAF50; color: white;')
|
||||||
|
self.calc_btn.clicked.connect(self.calculate_sum)
|
||||||
|
|
||||||
|
self.sum_label = QLabel('0 р.')
|
||||||
|
self.sum_label.setFrameShape(QFrame.Shape.Box)
|
||||||
|
self.sum_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
|
||||||
|
self.add_btn = QPushButton('Добавить в заказ')
|
||||||
|
self.add_btn.setStyleSheet('background-color: #4CAF50; color: white;')
|
||||||
|
self.add_btn.clicked.connect(self.add_to_order)
|
||||||
|
|
||||||
|
right_layout.addRow('Цена за единицу:', self.price_edit)
|
||||||
|
right_layout.addRow('Количество:', self.quantity_spin)
|
||||||
|
right_layout.addRow(self.calc_btn)
|
||||||
|
right_layout.addRow('Сумма:', self.sum_label)
|
||||||
|
right_layout.addRow(self.add_btn)
|
||||||
|
|
||||||
|
right_group.setLayout(right_layout)
|
||||||
|
top_layout.addWidget(right_group, 1)
|
||||||
|
|
||||||
|
main_layout.addLayout(top_layout)
|
||||||
|
|
||||||
|
# Внизу: закрыть
|
||||||
|
self.close_btn = QPushButton('Закрыть')
|
||||||
|
self.close_btn.clicked.connect(self.close)
|
||||||
|
main_layout.addWidget(self.close_btn,
|
||||||
|
alignment=Qt.AlignmentFlag.AlignRight)
|
||||||
|
|
||||||
|
self.setLayout(main_layout)
|
||||||
|
|
||||||
|
# Внутренний список заказа (простой)
|
||||||
|
self.current_order = []
|
||||||
|
|
||||||
|
def select_product(self):
|
||||||
|
selected = self.table.currentRow()
|
||||||
|
if selected < 0:
|
||||||
|
QMessageBox.warning(self, 'Ошибка', 'Не выбран товар')
|
||||||
|
return
|
||||||
|
price_item = self.table.item(selected, 2).text()
|
||||||
|
# Из строки "500 р." выделим число
|
||||||
|
price_number = ''.join(ch for ch in price_item if ch.isdigit())
|
||||||
|
self.price_edit.setText(price_number)
|
||||||
|
|
||||||
|
def calculate_sum(self):
|
||||||
|
price_text = self.price_edit.text().strip()
|
||||||
|
if not price_text.isdigit():
|
||||||
|
QMessageBox.warning(self, 'Ошибка', 'Сначала выберите товар')
|
||||||
|
return
|
||||||
|
price = int(price_text)
|
||||||
|
qty = self.quantity_spin.value()
|
||||||
|
total = price * qty
|
||||||
|
self.sum_label.setText(f"{total} р.")
|
||||||
|
|
||||||
|
def add_to_order(self):
|
||||||
|
sum_text = self.sum_label.text()
|
||||||
|
if sum_text.startswith('0') or sum_text == '0 р.':
|
||||||
|
QMessageBox.warning(self, 'Ошибка',
|
||||||
|
'Нужно рассчитать сумму перед добавлением')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Для простоты — добавляем запись в список и показываем сообщение
|
||||||
|
self.current_order.append({'sum': sum_text})
|
||||||
|
QMessageBox.information(self, 'Добавлено',
|
||||||
|
f'Добавлено в заказ: {sum_text}')
|
||||||
|
|
||||||
|
class CashierWindow(BaseWindow):
|
||||||
|
def _setup_ui(self):
|
||||||
|
main_layout = QVBoxLayout()
|
||||||
|
|
||||||
|
self.orders_table = QTableWidget(len(ORDERS), 4)
|
||||||
|
self.orders_table.setHorizontalHeaderLabels([
|
||||||
|
'№ заказа', 'Покупатель', 'Сумма', 'Статус'
|
||||||
|
])
|
||||||
|
self.orders_table.setSelectionBehavior(
|
||||||
|
self.orders_table.SelectionBehavior.SelectRows
|
||||||
|
)
|
||||||
|
self.orders_table.setEditTriggers(
|
||||||
|
self.orders_table.EditTrigger.NoEditTriggers
|
||||||
|
)
|
||||||
|
for row, o in enumerate(ORDERS):
|
||||||
|
self.orders_table.setItem(row, 0, QTableWidgetItem(o['id']))
|
||||||
|
self.orders_table.setItem(row, 1, QTableWidgetItem(o['customer']))
|
||||||
|
self.orders_table.setItem(row, 2, QTableWidgetItem(o['sum']))
|
||||||
|
self.orders_table.setItem(row, 3, QTableWidgetItem(o['status']))
|
||||||
|
|
||||||
|
main_layout.addWidget(self.orders_table)
|
||||||
|
|
||||||
|
ctrl_layout = QHBoxLayout()
|
||||||
|
self.status_combo = QComboBox()
|
||||||
|
self.status_combo.addItems(STATUS_OPTIONS)
|
||||||
|
self.change_btn = QPushButton('Изменить статус')
|
||||||
|
self.change_btn.clicked.connect(self.change_status)
|
||||||
|
ctrl_layout.addWidget(QLabel('Новый статус:'))
|
||||||
|
ctrl_layout.addWidget(self.status_combo)
|
||||||
|
ctrl_layout.addWidget(self.change_btn)
|
||||||
|
|
||||||
|
main_layout.addLayout(ctrl_layout)
|
||||||
|
|
||||||
|
self.setLayout(main_layout)
|
||||||
|
|
||||||
|
self.setFixedSize(450, 200)
|
||||||
|
|
||||||
|
def change_status(self):
|
||||||
|
selected = self.orders_table.currentRow()
|
||||||
|
if selected < 0:
|
||||||
|
QMessageBox.critical(self, 'Ошибка', 'Не выбрана строка')
|
||||||
|
return
|
||||||
|
new_status = self.status_combo.currentText()
|
||||||
|
self.orders_table.setItem(selected, 3, QTableWidgetItem(new_status))
|
||||||
|
QMessageBox.information(self, 'Готово', 'Статус обновлён')
|
||||||
Loading…
Add table
Add a link
Reference in a new issue