Commit b1ef36b5 authored by Ben Wais's avatar Ben Wais
Browse files

rettungsanker

parent 2eda1cad
Loading
Loading
Loading
Loading
+4.76 KiB

File added.

No diff preview for this file type.

+78 −55
Original line number Diff line number Diff line
import json
from ilo import erstelle_schichtplan # Importiere deine Funktion
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Dict, Any
from ilo import erstelle_schichtplan

def run_scheduler():
app = FastAPI()

# 🧩 Eingabedaten vom Frontend
class Shift(BaseModel):
    begin: str
    end: str
    reqEmployees: str

class Employee(BaseModel):
    name: str
    capacity: str
    availableDays: List[str]

class FrontendRequest(BaseModel):
    shiftCount: str
    shifts: List[Shift]
    employeeCount: str
    employees: List[Employee]
    maxWeeklyHours: str
    maxDailyHours: str
    restingPeriod: str

@app.post("/api/plane-schichtplan")
def plane_schichtplan(data: FrontendRequest):
    try:
        # 1. Daten aus JSON-Dateien laden
        with open('personal.json', 'r', encoding='utf-8') as f:
            personal_data = json.load(f)
        
        with open('schicht_anforderungen.json', 'r', encoding='utf-8') as f:
            schicht_requirements = json.load(f)
            
        with open('arbeitszeit_regeln.json', 'r', encoding='utf-8') as f:
            arbeitszeit_rules = json.load(f)

        # 2. Schichtplan-Funktion aufrufen
        success, result = erstelle_schichtplan(personal_data, schicht_requirements, arbeitszeit_rules)

        # 3. Ergebnis verarbeiten
        if success:
            print("Schichtplan erfolgreich erstellt!")
            # Optional: Speichern des Ergebnisses in einer JSON-Datei
            with open('schichtplan_output.json', 'w', encoding='utf-8') as f:
                json.dump(result, f, indent=4, ensure_ascii=False)
            
            # Ausgabe auf der Konsole
            for tag, schichten_am_tag in result.items():
                print(f"\n--- Tag: {tag} ---")
                for schicht_name, zugewiesen in schichten_am_tag.items():
                    # Sicherstellen, dass die Schicht im Original-Requirement existiert,
                    # um die Dauer abrufen zu können.
                    dauer = schicht_requirements.get(tag, {}).get(schicht_name, {}).get('dauer', 'N/A')
                    print(f"  Schicht {schicht_name} ({dauer}h): {', '.join(zugewiesen) if zugewiesen else 'UNBESETZT'}")

            # Optional: Arbeitszeitübersicht zur Überprüfung
            print("\n--- Arbeitszeitübersicht pro Mitarbeiter ---")
            for p in personal_data.keys():
                gesamtarbeitszeit_p = 0
                for t in result.keys():
                    for s_name, zugewiesene_m in result[t].items():
                        if p in zugewiesene_m:
                            # Stellen Sie sicher, dass schicht_requirements[t][s_name]['dauer'] existiert
                            duration = schicht_requirements.get(t, {}).get(s_name, {}).get('dauer', 0)
                            gesamtarbeitszeit_p += duration
                print(f"  {p}: {gesamtarbeitszeit_p} Stunden (Max. Woche: {personal_data[p]['MaxWoche']})")


        else:
            print(f"Fehler: {result}") # Hier wird die Fehlermeldung ausgegeben

    except FileNotFoundError as e:
        print(f"Fehler: Eine der benötigten JSON-Dateien wurde nicht gefunden: {e}")
    except json.JSONDecodeError as e:
        print(f"Fehler beim Parsen der JSON-Dateien: {e}")
        # 🔁 1. Konvertiere ins Backend-Format
        personal_data = {}
        for emp in data.employees:
            personal_data[emp.name] = {
                "Verfuegbar": {day: True for day in emp.availableDays},
                "MaxWoche": int(emp.capacity),
            }

        # Schichtanforderungen auf alle Wochentage anwenden
        tage = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"]
        schichtanforderungen = {}
        for tag in tage:
            schichtanforderungen[tag] = {}
            for idx, shift in enumerate(data.shifts):
                schichtanforderungen[tag][f"S{idx+1}"] = {
                    "beginn": shift.begin,
                    "ende": shift.end,
                    "anzahl": int(shift.reqEmployees),
                    "dauer": _berechne_dauer(shift.begin, shift.end)
                }

        arbeitszeitregeln = {
            "MaxTagesstunden": int(data.maxDailyHours),
            "Ruhezeit": int(data.restingPeriod),
            "MaxWoche": int(data.maxWeeklyHours)
        }

        # 🧠 2. Aufruf der Planungslogik
        success, result = erstelle_schichtplan(personal_data, schichtanforderungen, arbeitszeitregeln)

        if not success:
            raise HTTPException(status_code=400, detail=result)

        return {
            "status": "ok",
            "schichtplan": result
        }

    except Exception as e:
        print(f"Ein unerwarteter Fehler ist aufgetreten: {e}")
        raise HTTPException(status_code=500, detail=str(e))


# ⏱ Hilfsfunktion zur Dauerberechnung
def _berechne_dauer(start: str, ende: str) -> int:
    from datetime import datetime, timedelta

if __name__ == '__main__':
    run_scheduler()
 No newline at end of file
    fmt = "%H:%M"
    s = datetime.strptime(start, fmt)
    e = datetime.strptime(ende, fmt)
    if e <= s:
        e += timedelta(days=1)
    return int((e - s).seconds // 3600)
+75 −18
Original line number Diff line number Diff line
import { useState } from 'react'
import { useState, useRef } from 'react'
import logo from './assets/pfannkuchentorte_trans.png'
import './App.css'

function App() {
  const [shiftCount, setShiftCount] = useState(0)
  const [employeeCount, setEmployeeCount] = useState(0)
  const formRef = useRef(null);

  function sendConstraints(formData) {
  const sendConstraints = (e) => {
    e.preventDefault();
    const formData = new FormData(formRef.current);
    console.log(formData)
    console.log(formData.get("TU01"))
    
    const data = {
      shiftCount: shiftCount.toString(),
      shifts: [],
      employeeCount: employeeCount.toString(),
      employees: [],
      maxWeeklyHours: formData.get("maxWeeklyHours"),
      maxDailyHours: formData.get("maxDailyHours"),
      restingPeriod: formData.get("restingPeriod")
    }

    for (let i = 1; i <= shiftCount; i++){
      data.shifts.push({
        begin: formData.get(`shiftStart${i}`),
        end: formData.get(`shiftEnd${i}`),
        reqEmployees: formData.get('reqEmployees${i}')
      });
    }

    for (let i = 1; i <= employeeCount; i++){
      const availableDays = [];
      const days = ["MO", "TU", "WE", "TH", "FR", "SA", "SO"];

      days.forEach((day) => {
        console.log(`formData.get(${day}0${i})`)
        console.log(formData.get(`${day}0${i}`))
        if (formData.get(`${day}${i}`)=="on") {
          availableDays.push(day);
        }
      });

      data.employees.push({

        name: formData.get(`name${i}`),
        capacity: formData.get(`capacity${i}`),
        availableDays
      });
    }

    console.log("Daten: ", data);

    fetch("/api", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({})
    })
    .then((res) => res.json())
    .then((err) => console.error("Error: ", err))

  }



  return (
    <>
      <div>
@@ -28,48 +85,48 @@ function App() {
        <p>Mitarbeiter: {employeeCount}</p>
        <button onClick={() => setEmployeeCount(employeeCount+1)}>+</button>
        <button onClick={() => setEmployeeCount(employeeCount-1)}>-</button>
         <form action="sendConstraints">
         <form ref={formRef} onSubmit={sendConstraints}>
          {Array.from({ length: shiftCount}).map((_, index) => (
            <div>
              <label>Start Schicht {index+1}</label>
              <input type="text" />
              <input name={"shiftStart"+index+1} type="text" />
              <label>Ende Schicht {index+1}</label>
              <input type="text" name="" id="" />
              <input name={"shiftEnd"+index+1}type="text" id="" />
              <label>Anzahl von Personen für Schicht {index+1}</label>
              <input type="text" />
              <input name={"reqEmployees"+index+1} type="text" />
            </div>
          ))}
          {Array.from({ length: employeeCount}).map((_, index) => (
            <div>
              <label>Name: </label>
              <input type="text" /><br />
              <input name={"name"+index+1}type="text" /><br />
              <label>Kapazität (Stunden pro Woche) von Mitarbeiter {index+1}: </label>
              <input type="text" /><br />
              <input name={"capacity"+index+1}type="text" /><br />
              <label>Verfügbarkeit von Mitarbeiter {index+1}: </label><br />
              <label>MO</label>
              <input type="checkbox" name="MO" id="" defaultChecked/><br />
              <input name={"MO"+index+1} type="checkbox" id="" defaultChecked/><br />
              <label>DI</label>
              <input type="checkbox" name="DI" id="" defaultChecked/><br />
              <input name={"TU"+index+1} type="checkbox" id="" defaultChecked/><br />
              <label>MI</label>
              <input type="checkbox" name="MI" id="" defaultChecked/><br />
              <input type="checkbox" name={"WE"+index+1} id="" defaultChecked/><br />
              <label>DO</label>
              <input type="checkbox" name="DO" id="" defaultChecked/><br />
              <input type="checkbox" name={"TH"+index+1} id="" defaultChecked/><br />
              <label>FR</label>
              <input type="checkbox" name="FR" id="" defaultChecked/><br />
              <input type="checkbox" name={"FR"+index+1} id="" defaultChecked/><br />
              <label>SA</label>
              <input type="checkbox" name="SA" id="" defaultChecked/><br />
              <input type="checkbox" name={"SA"+index+1} id="" defaultChecked/><br />
              <label>SO</label>
              <input type="checkbox" name="SO" id="" defaultChecked/><br />
              <input type="checkbox" name={"SO"+index+1} id="" defaultChecked/><br />
              <br />
              <br />
            </div>
          ))}
          <label>max. Wochenstunden pro Mitarbeiter: </label>
          <input type="text" name="" id="" /><br />
          <input name="maxWeeklyHours" type="text" id="" /><br />
          <label>max. Tagesstunden pro Mitarbeiter: </label>
          <input type="text" name="" id="" /><br />
          <input name="maxDailyHours" type="text" id="" /><br />
          <label>einzuhaltene Ruhezeit zwischen Schichten: </label>
          <input type="text" name="" id="" /><br />
          <input name="restingPeriod" type="text" id="" /><br />
          <button type="submit">Dienstplan erstellen</button>
         </form>
      </section>
+4 −4
Original line number Diff line number Diff line
@@ -2,17 +2,17 @@ FROM node:18 AS build
WORKDIR /app

# 1. Nur package.json + package-lock.json kopieren
COPY frontend/package*.json ./
COPY 02_frontend/package*.json ./

# 2. npm install ausführen
RUN npm install

# 3. Restlichen Frontend-Code kopieren
COPY frontend/ ./
COPY 02_frontend/ ./

# 4. Build ausführen
RUN npm run build

FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
 No newline at end of file
COPY --from=build /app/dist /usr/share/nginx/html
COPY 00_nginx/default.conf /etc/nginx/conf.d/default.conf
 No newline at end of file
+15 −7
Original line number Diff line number Diff line
# docker-compose.yml (Korrektur der command-Zeile)
version: '3.8'

services:
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
    volumes:
      - ./00_nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./frontend/dist:/usr/share/nginx/html  # statisches Frontend
    depends_on:
      - backend

  backend:
    build:
      context: .
@@ -17,10 +27,8 @@ services:
    build:
      context: .
      dockerfile: Dockerfile.frontend
      volumes:
      - ./00_nginx/defulat.conf:/etc/nginx/conf.d/default.conf
    container_name: frontend
    ports:
      - "80:80"
    # KEIN NGINX hier nötig – nur Build-Zweck
    # kein ports:, kein volumes: (wird nach Build in nginx gemountet)
    depends_on:
      - backend