Py.Cafe

marco.mannweiler/

mangelmanagement

Mangelmanagement mit Bildern und Berichten

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
import streamlit as st
import os
import pandas as pd
from datetime import datetime
from io import BytesIO
from PIL import Image
from reportlab.lib.pagesizes import landscape, A4
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Image as ReportLabImage
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Spacer, Paragraph

# Streamlit app
st.title("Eingaben")

# Funktion zum Erstellen des Ordners und der CSV-Datei
def create_project(project_name):
    if not os.path.exists(project_name):
        os.makedirs(project_name)

    csv_path = os.path.join(project_name, f"{project_name}.csv")

    if not os.path.exists(csv_path):
        columns = ["Nummer", "Kategorie", "Gewerk", "Foto", "Beschrieb", "Datum", "Bemerkung"]
        df = pd.DataFrame(columns=columns)
        df.to_csv(csv_path, index=False)

    return csv_path


# Funktion zum Ermitteln der nächsten fortlaufenden Nummer
def get_next_number(csv_path):
    if os.path.exists(csv_path):
        df = pd.read_csv(csv_path)
        if not df.empty:
            return df['Nummer'].max() + 1
    return 1


# Funktion zum Speichern des Fotos
def save_photo(photo, project_name, number, category, date):
    if photo is not None:
        img = Image.open(photo)
        photo_name = f"{number}_{category}_{date.strftime('%Y%m%d')}.jpg"
        image_path = os.path.join(project_name, photo_name)
        img.save(image_path)
        return image_path
    return None


# Funktion zum Erstellen des PDF-Berichts mit ReportLab
def create_pdf_report(csv_path, project_name, export_date):
    # Speicherort und Dateiname
    pdf_output_path = os.path.join(project_name, f"{project_name}_Bericht_{export_date.strftime('%Y%m%d')}.pdf")

    # Querformat PDF erstellen
    document = SimpleDocTemplate(pdf_output_path, pagesize=landscape(A4), rightMargin=36, leftMargin=36, topMargin=36, bottomMargin=36)
    elements = []

    # Titel des Berichts
    title = f"Übersicht der Mängel und Themen: {project_name} - {export_date.strftime('%Y-%m-%d')}"
    elements.append(Spacer(1, 24))
    elements.append(Paragraph(title, style=getSampleStyleSheet()['Title']))  # Titel hinzufügen
    elements.append(Spacer(1, 12))

    # CSV-Datei laden
    df = pd.read_csv(csv_path)

    if not df.empty:
        # Erstellen der Kopfzeile für die Tabelle
        data = [["Nummer", "Kategorie", "Gewerk", "Foto", "Datum", "Beschrieb", "Bemerkung"]]

        for index, row in df.iterrows():
            img_path = row['Foto']
            if img_path and os.path.exists(img_path):
                # Bildgröße anpassen und sicherstellen, dass es innerhalb der Zelle bleibt
                img = ReportLabImage(img_path, width=80, height=80)  # Bildgröße auf 70x70 setzen
                data.append([
                    str(row['Nummer']),
                    row['Kategorie'],
                    row['Gewerk'],
                    img,
                    row['Datum'],
                    row['Beschrieb'],
                    row['Bemerkung']
                ])
            else:
                data.append([
                    str(row['Nummer']),
                    row['Kategorie'],
                    row['Gewerk'],
                    "",  # Falls kein Bild vorhanden ist
                    row['Datum'],
                    row['Beschrieb'],
                    row['Bemerkung']
                ])

        for i in range(0, len(data[0])):  # Für die Spalten "Beschrieb" und "Bemerkung"
            for j in range(1, len(data)):
                if isinstance(data[j][i], str):  # Nur für Texte in den Zellen
                    data[j][i] = Paragraph(data[j][i], style=getSampleStyleSheet()['Normal'])

        # Tabelle erstellen mit angepassten Zellenbreiten und Zeilenhöhen
        table = Table(data, colWidths=[50, 80, 80, 100, 70, 200, 200], rowHeights=90)  # Erste Spalte breiter

        # Style anpassen
        table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey),  # Hintergrundfarbe der Kopfzeile (hellgrau)
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),  # Textfarbe der Kopfzeile (weiß)
            ('ALIGN', (0, 0), (-1, -1), 'LEFT'),  # Text zentrieren
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),  # Schriftart der Kopfzeile fett
            ('SIZE', (0, 0), (-1, -1), 10),  # Schriftgröße für alle Zellen
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),  # Vertikale Ausrichtung der Zellen
            ('GRID', (0, 0), (-1, -1), 1, colors.black),  # Gitterlinien für die gesamte Tabelle
            ('LINEBEFORE', (0, 0), (0, -1), 1, colors.black),  # Linie links von der Tabelle
            ('LINEAFTER', (-1, 0), (-1, -1), 1, colors.black),  # Linie rechts von der Tabelle
        ]))

        elements.append(table)
        elements.append(Spacer(1, 24))  # Abstand nach der Tabelle

    else:
        # Wenn keine Daten vorhanden sind
        elements.append(Paragraph("Keine Daten vorhanden", style=getSampleStyleSheet()['Normal']))

    # PDF speichern
    document.build(elements)
    return pdf_output_path


# Funktion zum Erstellen des Excel-Exports mit eingebetteten Bildern
def create_excel_export(csv_path, project_name, export_date):
    df = pd.read_csv(csv_path)

    # Speicherort und Dateiname für den Excel-Export
    excel_output_path = os.path.join(project_name, f"{project_name}_Bericht_{export_date.strftime('%Y%m%d')}.xlsx")

    # Excel-Datei im Excel Writer erstellen
    with pd.ExcelWriter(excel_output_path, engine="xlsxwriter") as writer:
        df.to_excel(writer, sheet_name="Übersicht", index=False)

        workbook = writer.book
        worksheet = workbook.get_worksheet_by_name('Übersicht')

        # Gehe durch jede Zeile und füge die Bilder in die Excel-Datei ein
        for idx, row in df.iterrows():
            img_path = row['Foto']
            if img_path and os.path.exists(img_path):
                # Zellenhöhe und -breite entsprechend dem Bild anpassen
                worksheet.set_row(idx + 1, 80)  # Zeilenhöhe anpassen
                worksheet.set_column('D:D', 20)  # Spaltenbreite anpassen

                # Bild in die Excel-Zelle einfügen (fixiert)
                worksheet.insert_image(idx + 1, 3, img_path, {'x_scale': 0.2, 'y_scale': 0.2, 'object_position': 2})

    return excel_output_path


# Seitenleiste für das neue Projekt
st.sidebar.title("Projektverwaltung")

# Eingabefeld für den neuen Projektnamen
project_name = st.sidebar.text_input("Projektname eingeben:")

# Button zum Erstellen des Projekts
create_project_button = st.sidebar.button("Projekt erstellen")

if create_project_button:
    if project_name:
        # Erstellen der CSV-Datei, falls noch nicht existiert
        csv_path = create_project(project_name)
        st.sidebar.success(f"Projekt '{project_name}' wurde erfolgreich erstellt.")
    else:
        st.sidebar.error("Bitte einen Projektnamen eingeben.")

# Auswahl eines bestehenden Projekts
project_folders = [folder for folder in os.listdir() if os.path.isdir(folder)]  # Verzeichnisse im aktuellen Ordner
selected_project = st.sidebar.selectbox("Oder bestehendes Projekt auswählen", project_folders)

# Wenn ein bestehendes Projekt ausgewählt wurde
if selected_project:
    project_name = selected_project
    csv_path = os.path.join(project_name, f"{project_name}.csv")

    # Datum für den PDF-Export
    export_date = st.sidebar.date_input("Exportdatum", value=datetime.today().date())

    # Button zum PDF-Bericht exportieren
    if st.sidebar.button("PDF Bericht exportieren"):
        pdf_path = create_pdf_report(csv_path, project_name, export_date)
        st.sidebar.success(f"PDF-Bericht erfolgreich erstellt: {pdf_path}")
        st.download_button("Download PDF", data=open(pdf_path, "rb"), file_name=os.path.basename(pdf_path),
                           mime="application/pdf")

    # Button zum Excel-Export
    if st.sidebar.button("Excel Bericht exportieren"):
        excel_path = create_excel_export(csv_path, project_name, export_date)
        st.sidebar.success(f"Excel-Bericht erfolgreich erstellt: {excel_path}")


    # Nummer für den neuen Mangel automatisch festlegen
    number = get_next_number(csv_path)

    # Eingabefelder für Mängel
    st.header(f"Sie befinden sich im Projekt: {project_name}")

    # Dropdown für Kategorie anstelle von Textinput
    category = st.selectbox("Kategorie", ["Mangel", "Aufgabe", "Sicherheit", "Sonstiges"])

    gewerk = st.text_input("Gewerk:")
    photo = st.camera_input("Foto aufnehmen:")
    description = st.text_area("Beschrieb:")
    date = st.date_input("Datum", value=datetime.today().date())
    remarks = st.text_area("Bemerkung:")

    # Speichern-Button für Mängel
    if st.button("Mangel speichern"):
        if gewerk and description and date:
            photo_path = save_photo(photo, project_name, number, category, date)

            # Neue Mangelzeile in die CSV-Datei einfügen
            new_row = {
                "Nummer": number,
                "Kategorie": category,
                "Gewerk": gewerk,
                "Foto": photo_path,
                "Beschrieb": description,
                "Datum": date.strftime("%Y-%m-%d"),
                "Bemerkung": remarks
            }

            df = pd.read_csv(csv_path)
            df = df.append(new_row, ignore_index=True)
            df.to_csv(csv_path, index=False)

            st.success(f"Mangel {number} erfolgreich gespeichert.")
        else:
            st.error("Bitte alle Pflichtfelder ausfüllen.")