add: wenn input folder leer -> hochladen von xlxs Dateien vereinfacht

This commit is contained in:
Rob committed 2026-10-07 21:16:46 +02:00
1 parent 7d63063024
commit 2237779e56
4 files changed
+76 -3

No files matched your search

+6
View File
@@ -9,6 +9,12 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
## [1.3.2] – 2026-10-07
### Hinzugefügt
- **Input-Dateien hinzufügen**: Bei leerem Input-Ordner können `.xlsx`-Dateien per Drag-and-drop oder Dateiauswahl in den Input-Ordner kopiert werden
- **Input-Ordner öffnen**: Ein Button öffnet den Input-Ordner direkt im Explorer
- **Input-Ordner neu einlesen**: Dateiliste kann über Button aktualisiert werden
### Behoben
- EXE erkennt laufende Entwicklungsinstanz und fragt vor dem Neustart
+5 -1
View File
@@ -9,6 +9,10 @@ Um das Programm zu starten: Doppelklick auf `Tätigkeitsnachweis-Generator.exe`
## Bedienung
1. **Input-Datei wählen** – Dropdown zeigt alle `.xlsx`-Dateien aus dem `input/`-Ordner
- Bei leerem Input-Ordner: „Input-Ordner öffnen“ öffnet den Explorer.
- Excel-Dateien können per Drag-and-drop hochgeladen werden. Sie werden in den
Input-Ordner kopiert; danach wird die Dateiliste automatisch neu eingelesen.
- Nach manuellem Kopieren im Explorer „Input-Ordner neu einlesen“ anklicken.
- Nach Auswahl wird die Datei sofort validiert
- Angezeigt werden: Anzahl Mitarbeiter, Antragsnummern, Einträge pro Monat
2. **Template wählen** – Dropdown zeigt alle `.xlsx`-Dateien aus dem `template/`-Ordner
@@ -54,4 +58,4 @@ Mapping von Input-Feldern auf Template-Zellen:
- Pro selektiertem Mitarbeiter wird eine `.xlsx`-Datei erstellt
- Jeder Monat wird als eigenes Sheet (Kopie des Templates) eingefügt
- Dateiname: `{Nachname}_{Vorname}_Tätigkeitsnachweis.xlsx`
- Dateiname: `{Nachname}_{Vorname}_Tätigkeitsnachweis.xlsx`
+64 -1
View File
@@ -32,6 +32,14 @@ from src.writer import generate_activity_reports
from version_check import UPDATE_DIR, get_latest_version
def open_input_folder(directory: Path):
directory.mkdir(parents=True, exist_ok=True)
if sys.platform == "win32":
os.startfile(str(directory))
else:
subprocess.run(["open" if sys.platform == "darwin" else "xdg-open", str(directory)], check=True)
def set_active_employee(employee_name: str):
"""Merkt die zuletzt angeklickte Person für die Monatsliste."""
st.session_state.active_month_employee = employee_name
@@ -155,9 +163,64 @@ col1, col2 = st.columns(2)
with col1:
st.subheader("1. Input-Datei")
input_files = get_available_input_files(app_config)
for message in st.session_state.pop("input_upload_messages", []):
st.success(message)
for message in st.session_state.pop("input_upload_errors", []):
st.error(message)
if not input_files:
st.warning("Keine .xlsx-Dateien im input/-Ordner gefunden.")
with st.container(border=True, key="input_file_panel"):
st.markdown("**Excel-Datei hinzufügen**")
st.caption("Keine .xlsx-Dateien im Input/-Ordner gefunden.")
input_directory = Path(app_config.input_dir)
uploaded_files = st.file_uploader(
"Excel-Dateien hierher ziehen oder auswählen",
type=["xlsx"], accept_multiple_files=True,
key=f"input_upload_{st.session_state.get('input_upload_generation', 0)}",
label_visibility="collapsed",
)
if uploaded_files:
saved, errors = [], []
for uploaded_file in uploaded_files:
try:
name = uploaded_file.name
if (Path(name).name != name or "/" in name or "\\" in name
or Path(name).suffix.lower() != ".xlsx" or name.startswith("~")):
raise ValueError("Bitte eine .xlsx-Datei mit gültigem Dateinamen auswählen.")
input_directory.mkdir(parents=True, exist_ok=True)
destination = input_directory / name
counter = 1
while True:
try:
with destination.open("xb") as output:
output.write(uploaded_file.getbuffer())
break
except FileExistsError:
counter += 1
destination = input_directory / f"{Path(name).stem} ({counter}).xlsx"
saved.append(f"{destination.name} wurde in den Input-Ordner kopiert.")
except (OSError, ValueError) as exc:
errors.append(f"{uploaded_file.name} konnte nicht übernommen werden: {exc}")
st.session_state.input_upload_messages = saved
st.session_state.input_upload_errors = errors
st.session_state.input_upload_generation = st.session_state.get("input_upload_generation", 0) + 1
st.session_state.last_input_file = None
st.rerun()
st.caption("Dateien hierher ziehen oder auswählen. Sie werden automatisch im Input-Ordner gespeichert.")
folder_action, refresh_action = st.columns(2)
with folder_action:
if st.button("Ordner öffnen", icon="📁", key="open_input_directory", use_container_width=True):
try:
open_input_folder(input_directory)
except (OSError, subprocess.SubprocessError) as exc:
st.error(f"Der Input-Ordner konnte nicht geöffnet werden: {exc}")
with refresh_action:
if st.button("Neu einlesen", icon="🔄", key="refresh_input_directory", use_container_width=True,
help="Dateiliste aktualisieren, nachdem Dateien im Explorer hinzugefügt wurden."):
st.rerun()
selected_input = None
st.session_state.parsed_records = []
st.session_state.input_validated = False
st.session_state.last_input_file = None
else:
# Bei nur einer Datei: automatisch selektieren (keine Leerauswahl)
if len(input_files) == 1: