174 lines
6.1 KiB
Python
174 lines
6.1 KiB
Python
from PyQt5.QtWidgets import (
|
|
QWidget, QVBoxLayout, QTableWidget, QTableWidgetItem,
|
|
QPushButton, QHBoxLayout, QDialog, QLabel, QLineEdit, QComboBox, QMessageBox,
|
|
QMenu, QAction, QSizePolicy
|
|
)
|
|
from PyQt5.QtCore import Qt
|
|
from PyQt5.QtGui import QFont
|
|
from PyQt5.QtWidgets import QHeaderView
|
|
from database.models import Account
|
|
|
|
PAGE_SIZE = 10
|
|
|
|
class AccountForm(QDialog):
|
|
def __init__(self, parent=None, account=None):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Account Form")
|
|
self.account = account
|
|
self.setMinimumSize(400, 200) # Form to hơn
|
|
layout = QVBoxLayout()
|
|
|
|
layout.addWidget(QLabel("Email"))
|
|
self.email_input = QLineEdit()
|
|
self.email_input.setMinimumWidth(250)
|
|
layout.addWidget(self.email_input)
|
|
|
|
layout.addWidget(QLabel("Password"))
|
|
self.password_input = QLineEdit()
|
|
layout.addWidget(self.password_input)
|
|
|
|
layout.addWidget(QLabel("Status"))
|
|
self.active_input = QComboBox()
|
|
self.active_input.addItems(["Inactive", "Active"])
|
|
layout.addWidget(self.active_input)
|
|
|
|
btn_layout = QHBoxLayout()
|
|
self.save_btn = QPushButton("Save")
|
|
self.save_btn.setMinimumWidth(80)
|
|
self.save_btn.clicked.connect(self.save)
|
|
btn_layout.addWidget(self.save_btn)
|
|
|
|
self.cancel_btn = QPushButton("Cancel")
|
|
self.cancel_btn.setMinimumWidth(80)
|
|
self.cancel_btn.clicked.connect(self.close)
|
|
btn_layout.addWidget(self.cancel_btn)
|
|
|
|
layout.addLayout(btn_layout)
|
|
self.setLayout(layout)
|
|
|
|
# nếu edit account
|
|
if account:
|
|
self.email_input.setText(account.get("email", ""))
|
|
self.password_input.setText(account.get("password", ""))
|
|
self.active_input.setCurrentText("Active" if account.get("is_active", 1) == 1 else "Inactive")
|
|
|
|
def save(self):
|
|
email = self.email_input.text()
|
|
password = self.password_input.text()
|
|
is_active = 1 if self.active_input.currentText() == "Active" else 0
|
|
try:
|
|
if self.account and "id" in self.account:
|
|
Account.update(self.account["id"], email, password, is_active)
|
|
else:
|
|
Account.create(email, password, is_active)
|
|
self.accept()
|
|
except Exception as e:
|
|
QMessageBox.warning(self, "Error", str(e))
|
|
|
|
|
|
class AccountTab(QWidget):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.current_page = 0
|
|
layout = QVBoxLayout()
|
|
|
|
# Add button
|
|
self.add_btn = QPushButton("Add Account")
|
|
self.add_btn.setMinimumWidth(120)
|
|
self.add_btn.clicked.connect(self.add_account)
|
|
layout.addWidget(self.add_btn)
|
|
|
|
# Table
|
|
self.table = QTableWidget()
|
|
self.table.verticalHeader().setDefaultSectionSize(28) # row gọn
|
|
self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
layout.addWidget(self.table)
|
|
|
|
# Pagination
|
|
pag_layout = QHBoxLayout()
|
|
self.prev_btn = QPushButton("Previous")
|
|
self.prev_btn.setMinimumWidth(100)
|
|
self.prev_btn.clicked.connect(self.prev_page)
|
|
pag_layout.addWidget(self.prev_btn)
|
|
|
|
self.next_btn = QPushButton("Next")
|
|
self.next_btn.setMinimumWidth(100)
|
|
self.next_btn.clicked.connect(self.next_page)
|
|
pag_layout.addWidget(self.next_btn)
|
|
layout.addLayout(pag_layout)
|
|
|
|
self.setLayout(layout)
|
|
self.load_data()
|
|
|
|
def load_data(self):
|
|
accounts = Account.all()
|
|
start = self.current_page * PAGE_SIZE
|
|
end = start + PAGE_SIZE
|
|
page_items = accounts[start:end]
|
|
|
|
self.table.setRowCount(len(page_items))
|
|
self.table.setColumnCount(4)
|
|
self.table.setHorizontalHeaderLabels(["ID", "Email", "Status", "Actions"])
|
|
|
|
for i, acc in enumerate(page_items):
|
|
# convert sqlite3.Row -> dict
|
|
acc_dict = {k: acc[k] for k in acc.keys()}
|
|
|
|
self.table.setItem(i, 0, QTableWidgetItem(str(acc_dict["id"])))
|
|
self.table.setItem(i, 1, QTableWidgetItem(acc_dict["email"]))
|
|
self.table.setItem(i, 2, QTableWidgetItem("Active" if acc_dict["is_active"] == 1 else "Inactive"))
|
|
|
|
# nút menu Actions
|
|
btn_menu = QPushButton("Actions")
|
|
menu = QMenu()
|
|
action_edit = QAction("Edit", btn_menu)
|
|
action_edit.triggered.connect(lambda _, a=acc_dict: self.edit_account(a))
|
|
menu.addAction(action_edit)
|
|
|
|
action_delete = QAction("Delete", btn_menu)
|
|
action_delete.triggered.connect(lambda _, a=acc_dict: self.delete_account(a))
|
|
menu.addAction(action_delete)
|
|
|
|
btn_menu.setMenu(menu)
|
|
self.table.setCellWidget(i, 3, btn_menu)
|
|
|
|
# Phân bổ column width hợp lý
|
|
header = self.table.horizontalHeader()
|
|
header.setSectionResizeMode(0, QHeaderView.ResizeToContents) # ID
|
|
header.setSectionResizeMode(1, QHeaderView.Stretch) # Email stretch
|
|
header.setSectionResizeMode(2, QHeaderView.ResizeToContents) # Status
|
|
header.setSectionResizeMode(3, QHeaderView.Fixed) # Actions fixed width
|
|
self.table.setColumnWidth(3, 100) # 100px cho Actions
|
|
|
|
# Enable/disable pagination buttons
|
|
self.prev_btn.setEnabled(self.current_page > 0)
|
|
self.next_btn.setEnabled(end < len(accounts))
|
|
|
|
def add_account(self):
|
|
form = AccountForm(self)
|
|
if form.exec_():
|
|
self.current_page = 0
|
|
self.load_data()
|
|
|
|
def edit_account(self, account):
|
|
form = AccountForm(self, account)
|
|
if form.exec_():
|
|
self.load_data()
|
|
|
|
def delete_account(self, account):
|
|
confirm = QMessageBox.question(
|
|
self, "Confirm", f"Delete account {account['email']}?",
|
|
QMessageBox.Yes | QMessageBox.No
|
|
)
|
|
if confirm == QMessageBox.Yes:
|
|
Account.delete(account["id"])
|
|
self.load_data()
|
|
|
|
def next_page(self):
|
|
self.current_page += 1
|
|
self.load_data()
|
|
|
|
def prev_page(self):
|
|
self.current_page -= 1
|
|
self.load_data()
|