umsortierung.
This commit is contained in:
parent
a7e3dfffcb
commit
20123348a7
0
gui/.gitignore → .gitignore
vendored
0
gui/.gitignore → .gitignore
vendored
Binary file not shown.
BIN
ats_doku.db
BIN
ats_doku.db
Binary file not shown.
2
data/data_api.py
Normal file
2
data/data_api.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
import sqlite3
|
||||||
|
from data.database import DB_NAME
|
||||||
|
|
@ -29,7 +29,6 @@ def initialize_db():
|
||||||
''')
|
''')
|
||||||
|
|
||||||
# Optional: Ein paar Test-ats anlegen, falls die Tabelle leer ist
|
# Optional: Ein paar Test-ats anlegen, falls die Tabelle leer ist
|
||||||
# (Damit du direkt was im Dropdown siehst)
|
|
||||||
cursor.execute("SELECT count(*) FROM ats")
|
cursor.execute("SELECT count(*) FROM ats")
|
||||||
if cursor.fetchone()[0] == 0:
|
if cursor.fetchone()[0] == 0:
|
||||||
ats_liste = [("Tim Grubmüller",), ("Phil Langer",), ("Max Hämmerle",)]
|
ats_liste = [("Tim Grubmüller",), ("Phil Langer",), ("Max Hämmerle",)]
|
||||||
Binary file not shown.
Binary file not shown.
9
gui/gui_admin.py
Normal file
9
gui/gui_admin.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
from nicegui import ui
|
||||||
|
from data import database
|
||||||
|
from gui import gui_style
|
||||||
|
|
||||||
|
def setup_route():
|
||||||
|
@ui.page("/")
|
||||||
|
|
||||||
|
def admin_page():
|
||||||
|
ui.label("kasdlkfs")
|
||||||
22
gui/gui_style.py
Normal file
22
gui/gui_style.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
from nicegui import ui
|
||||||
|
|
||||||
|
# Funktion die jede GUI Seite am Anfang aufrufen kann. Dann haben alle die gleichen Farbeinstellungen. Und, wenn man was ändert,
|
||||||
|
# muss man es nur hier ändern!
|
||||||
|
|
||||||
|
def apply_design():
|
||||||
|
ui.add_css('body { background-color: #171721; }')
|
||||||
|
# 1. Dark Mode aktivieren
|
||||||
|
ui.dark_mode(True)
|
||||||
|
ui.colors(
|
||||||
|
primary='#e30013', # Hauptfarbe (z.B. für Standard-Buttons) Wenn keine Farbe angegeben wird, ist es diese Farbe
|
||||||
|
secondary='#FF3333', # Zweitfarbe
|
||||||
|
accent='#2078D4', # Akzentfarbe
|
||||||
|
positive='#188C42', # Farbe für Erfolg (Grün)
|
||||||
|
negative='#E31919', # Farbe für Fehler/Abbruch (Rot)
|
||||||
|
info='#939393', # Info-Farbe
|
||||||
|
warning='#f59e0b', # Warn-Farbe (Orange)
|
||||||
|
# Farben für Texte
|
||||||
|
normaltext="#F7F7F7",
|
||||||
|
accenttext="#2078D4",
|
||||||
|
infotext="#A8A8A8"
|
||||||
|
)
|
||||||
199
gui/main_gui.py
199
gui/main_gui.py
|
|
@ -1,127 +1,108 @@
|
||||||
from nicegui import ui
|
from nicegui import ui
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import database
|
from data import database
|
||||||
|
from gui import gui_style, gui_admin
|
||||||
|
|
||||||
def build_ui():
|
|
||||||
ui.colors(primary='#e30013')
|
|
||||||
|
|
||||||
# 1. HAUPT-CONTAINER:
|
|
||||||
# Spalte die exakt so hoch ist wie der Bildschirm (h-screen).
|
|
||||||
# 'items-stretch' sorgt dafür, dass die Kinder (Header, Mitte, Footer) die volle Breite nutzen.
|
|
||||||
with ui.column().classes('w-full h-screen no-wrap gap-0 items-stretch'):
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
def setup_route():
|
||||||
# BEREICH OBEN (Header) - Feste Höhe (h-25)
|
@ui.page("/")
|
||||||
# ---------------------------------------------------------
|
|
||||||
with ui.card().classes("h-25 rounded-none").style("background-color: #e30013"):
|
|
||||||
# Hinweis: rounded-none entfernt die abgerundeten Ecken, damit es nahtlos aussieht
|
|
||||||
ui.image('gui/logo.png').classes('absolute top-4 right-4 w-55')
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
def main_page():
|
||||||
# BEREICH MITTE (Inhalt) - Variable Höhe (flex-1)
|
with ui.column().classes('w-full h-screen no-wrap gap-0 items-stretch'):
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# 'flex-1' ist hier entscheidend. Es sagt: "Nimm allen Platz zwischen Header und Footer".
|
# Header
|
||||||
# 'overflow-hidden' verhindert, dass das ganze Fenster scrollt -> wir wollen nur die Tabelle scrollen.
|
# ---------------------------------------------------------
|
||||||
with ui.row().classes("w-full flex-1 p-4 gap-4 no-wrap overflow-hidden"):
|
with ui.card().classes("h-25 rounded-none").style("background-color: #e30013"):
|
||||||
|
# Hinweis: rounded-none entfernt die abgerundeten Ecken, damit es nahtlos aussieht
|
||||||
|
ui.image('gui/logo.png').classes('absolute top-4 right-4 w-55')
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# MITTE
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
with ui.row().classes("w-full flex-1 p-4 gap-4 no-wrap overflow-hidden"):
|
||||||
|
|
||||||
with ui.column():
|
with ui.column():
|
||||||
# --- Linke Karte: Eingabemaske ---
|
# --- Linke Karte: Eingabemaske ---
|
||||||
# 'overflow-y-auto': Falls das Formular zu lang für kleine Bildschirme wird, bekommt nur diese Karte einen Scrollbalken.
|
with ui.card().classes('overflow-y-auto'):
|
||||||
with ui.card().classes('overflow-y-auto'):
|
traeger = database.get_ats_names()
|
||||||
|
input_name = ui.select(label="ATS Träger Name", options=traeger, with_input=True).classes('w-full')
|
||||||
|
input_location = ui.input(label='Einsatzort', placeholder='Adresse, oder Beschreibung').classes("w-full")
|
||||||
|
with ui.row().classes('gap-10'):
|
||||||
|
today = datetime.now().strftime("%Y-%m-%d")
|
||||||
|
with ui.input('Datum', value=today).classes('flex-1') as date_input:
|
||||||
|
with date_input.add_slot('append'):
|
||||||
|
ui.icon('event').classes('cursor-pointer') \
|
||||||
|
.on('click', lambda: menu.open())
|
||||||
|
with ui.menu() as menu:
|
||||||
|
input_date = ui.date().bind_value(date_input)
|
||||||
|
|
||||||
traeger = database.get_ats_names()
|
input_time = ui.number(label="Dauer (Min)", value=0).classes('flex-1')
|
||||||
input_name = ui.select(label="ATS Träger Name", options=traeger, with_input=True).classes('w-full')
|
with ui.row().classes("gap-10 w-full items-center"):
|
||||||
|
input_type = ui.toggle(["Einsatz", "Übung"]).classes('flex-1 center')
|
||||||
|
input_device = ui.select(["ATS Gerät 1", "ATS Gerät 2"], label="ATS Gerät auswählen").classes('flex-1')
|
||||||
|
|
||||||
input_location = ui.input(label='Einsatzort', placeholder='Adresse, oder Beschreibung').classes("w-full")
|
def ClearForm():
|
||||||
|
input_name.value = ""
|
||||||
|
input_location.value = ""
|
||||||
|
input_date.value = today
|
||||||
|
input_time.value = 0
|
||||||
|
input_type.value = "Einsatz" # Achtung: Value sollte zum Toggle passen (String, nicht 0)
|
||||||
|
input_device.value = None # Select resetten
|
||||||
|
ui.notify("Gelöscht.")
|
||||||
|
|
||||||
with ui.row().classes('gap-10'):
|
def InputDataToTable():
|
||||||
today = datetime.now().strftime("%Y-%m-%d")
|
name = input_name.value
|
||||||
with ui.input('Datum', value=today).classes('flex-1') as date_input:
|
location = input_location.value
|
||||||
with date_input.add_slot('append'):
|
date = input_date.value
|
||||||
ui.icon('event').classes('cursor-pointer') \
|
time = input_time.value
|
||||||
.on('click', lambda: menu.open())
|
etype = input_type.value
|
||||||
with ui.menu() as menu:
|
device = input_device.value
|
||||||
input_date = ui.date().bind_value(date_input)
|
# Hinweis: database Aufruf ist hier korrekt, sofern importiert
|
||||||
|
database.add_data_to_einsaetze(name, location, date, time, etype, device)
|
||||||
|
einsaetze_table.rows = database.get_einsaetze()
|
||||||
|
einsaetze_table.update()
|
||||||
|
ui.notify("Eintrag in Datenbank erstellt.")
|
||||||
|
ClearForm()
|
||||||
|
|
||||||
input_time = ui.number(label="Dauer (Min)", value=0).classes('flex-1')
|
|
||||||
|
|
||||||
with ui.row().classes("gap-10 w-full items-center"):
|
|
||||||
input_type = ui.toggle(["Einsatz", "Übung"]).classes('flex-1 center')
|
|
||||||
input_device = ui.select(["ATS Gerät 1", "ATS Gerät 2"], label="ATS Gerät auswählen").classes('flex-1')
|
|
||||||
|
|
||||||
def InputDataToTable():
|
ui.separator()
|
||||||
name = input_name.value
|
ui.space() # Drückt die Buttons nach unten (innerhalb der Formular-Karte)
|
||||||
location = input_location.value
|
|
||||||
date = input_date.value
|
|
||||||
time = input_time.value
|
|
||||||
etype = input_type.value
|
|
||||||
device = input_device.value
|
|
||||||
# Hinweis: database Aufruf ist hier korrekt, sofern importiert
|
|
||||||
database.add_data_to_einsaetze(name, location, date, time, etype, device)
|
|
||||||
|
|
||||||
einsaetze_table.rows = database.get_einsaetze()
|
|
||||||
einsaetze_table.update()
|
|
||||||
ui.notify("Eintrag in Datenbank erstellt.")
|
|
||||||
|
|
||||||
def ClearForm():
|
|
||||||
input_name.value = ""
|
|
||||||
input_location.value = ""
|
|
||||||
input_date.value = today
|
|
||||||
input_time.value = 0
|
|
||||||
input_type.value = "Einsatz" # Achtung: Value sollte zum Toggle passen (String, nicht 0)
|
|
||||||
input_device.value = None # Select resetten
|
|
||||||
ui.notify("Gelöscht.")
|
|
||||||
ui.notify(admin_login.value)
|
|
||||||
|
|
||||||
ui.separator()
|
|
||||||
ui.space() # Drückt die Buttons nach unten (innerhalb der Formular-Karte)
|
|
||||||
with ui.row().classes('w-full'):
|
|
||||||
ui.button(text="Leeren", on_click=ClearForm)
|
|
||||||
ui.space()
|
|
||||||
ui.button(text="Eintragen", on_click=InputDataToTable)
|
|
||||||
|
|
||||||
admin_container = ui.column().classes("w-full")
|
|
||||||
|
|
||||||
with ui.card().classes("w-full"):
|
|
||||||
# 1. Das Passwort-Feld
|
|
||||||
pw_input = ui.input("Passwort", password=True)
|
|
||||||
|
|
||||||
# Das Admin-Panel wird nur angezeigt, wenn der Wert vom Input '1234' ist.
|
|
||||||
# lambda v: v == '1234' ist die Prüf-Logik (True/False).
|
|
||||||
|
|
||||||
with ui.card().bind_visibility_from(pw_input, 'value', backward=lambda v: v == '1234').classes("w-full"):
|
|
||||||
ui.label("Admin Panel")
|
|
||||||
with ui.row().classes('w-full'):
|
with ui.row().classes('w-full'):
|
||||||
ui.input(label="Neuer ATS Träger").classes('flex-1')
|
ui.button(text="Leeren", on_click=ClearForm)
|
||||||
ui.button(text="Hinzufügen")
|
ui.space()
|
||||||
|
ui.button(text="Eintragen", on_click=InputDataToTable)
|
||||||
|
|
||||||
# --- Rechte Karte: Tabelle ---
|
with ui.card().classes("w-full"):
|
||||||
# 'flex-1': Diese Karte nimmt die restliche Breite der Reihe ein.
|
# 1. Das Passwort-Feld
|
||||||
# 'h-full': Diese Karte nutzt die volle Höhe des mittleren Bereichs.
|
pw_input = ui.input("Passwort", password=True)
|
||||||
with ui.card().classes('flex-1 h-full p-0'):
|
|
||||||
collums = [
|
|
||||||
{'name': 'date', 'label': 'Datum', 'field': 'date', 'sortable': True, 'align': 'left'},
|
|
||||||
{'name': 'name', 'label': 'Name', 'field': 'name', 'sortable': True, 'align': 'left'},
|
|
||||||
{'name': 'location', 'label': 'Ort', 'field': 'location', 'align': 'left'},
|
|
||||||
{'name': 'time', 'label': 'Dauer', 'field': 'time'},
|
|
||||||
{'name': 'etype', 'label': 'Art', 'field': 'etype', "sortable": True},
|
|
||||||
{'name': 'device', 'label': 'Gerät', 'field': 'device', "sortable": True},
|
|
||||||
]
|
|
||||||
# Die Tabelle selbst bekommt auch h-full, damit sie die Karte ausfüllt
|
|
||||||
einsaetze_table = ui.table(
|
|
||||||
columns = collums,
|
|
||||||
rows = database.get_einsaetze(),
|
|
||||||
row_key = "id"
|
|
||||||
).classes("w-full h-full")
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
with ui.card().bind_visibility_from(pw_input, 'value', backward=lambda v: v == '1234').classes("w-full"):
|
||||||
# BEREICH UNTEN (Footer) - Automatische Höhe
|
ui.button(text="Admin Seite", on_click=lambda:ui.navigate.to("/admin"))
|
||||||
# ---------------------------------------------------------
|
|
||||||
# Hier landet dein Switch. Durch 'flex-1' im mittleren Bereich wird dieser Teil
|
|
||||||
# immer an den unteren Bildschirmrand geschoben.
|
|
||||||
|
|
||||||
with ui.row().classes("p-2 pb-6 items-center"):
|
# --- Rechte Karte: Tabelle ---
|
||||||
dark = ui.dark_mode(True)
|
with ui.card().classes('flex-1 h-full p-0'):
|
||||||
#Light/Dark Switch in der Leiste unten.
|
collums = [
|
||||||
ui.switch('Dark mode').bind_value(dark)
|
{'name': 'date', 'label': 'Datum', 'field': 'date', 'sortable': True, 'align': 'left'},
|
||||||
|
{'name': 'name', 'label': 'Name', 'field': 'name', 'sortable': True, 'align': 'left'},
|
||||||
|
{'name': 'location', 'label': 'Ort', 'field': 'location', 'align': 'left'},
|
||||||
|
{'name': 'time', 'label': 'Dauer', 'field': 'time'},
|
||||||
|
{'name': 'etype', 'label': 'Art', 'field': 'etype', "sortable": True},
|
||||||
|
{'name': 'device', 'label': 'Gerät', 'field': 'device', "sortable": True},
|
||||||
|
]
|
||||||
|
# Die Tabelle selbst bekommt auch h-full, damit sie die Karte ausfüllt
|
||||||
|
einsaetze_table = ui.table(
|
||||||
|
columns = collums,
|
||||||
|
rows = database.get_einsaetze(),
|
||||||
|
row_key = "id"
|
||||||
|
).classes("w-full h-full")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# Footer
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
|
with ui.row().classes("p-2 pb-6 items-center"):
|
||||||
|
dark = ui.dark_mode(True)
|
||||||
|
#Light/Dark Switch in der Leiste unten.
|
||||||
|
ui.switch('Dark mode').bind_value(dark)
|
||||||
|
|
||||||
|
|
|
||||||
4
main.py
4
main.py
|
|
@ -1,10 +1,10 @@
|
||||||
from gui import main_gui
|
from gui import main_gui
|
||||||
from nicegui import ui
|
from nicegui import ui
|
||||||
import database
|
from data import database
|
||||||
|
|
||||||
|
|
||||||
database.initialize_db()
|
database.initialize_db()
|
||||||
main_gui.build_ui()
|
main_gui.setup_route()
|
||||||
|
|
||||||
main_gui.ui.run(
|
main_gui.ui.run(
|
||||||
title="ATS Träger Dokumentation",
|
title="ATS Träger Dokumentation",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user