feat(ui): Slot-Nummer nach links verschoben und Datumsauswahl horizontal ausgerichtet

- Slot-Nr.-Anzeige nach links im ActionBar verschoben.
- Datum-Labels („Von“ & „Bis“) und Eingabefelder horizontal ausgerichtet.
- Verbesserte UI/UX der Chart-Steuerungskomponenten.
This commit is contained in:
Ismail Ali
2025-03-14 21:30:21 +01:00
parent 162a0aa318
commit e0379c24a6
18 changed files with 14734 additions and 92 deletions

View File

@@ -23,22 +23,28 @@ const LoopChartActionBar: React.FC = () => {
selectedSlotType,
isChartOpen,
slotNumber,
loopMeasurementCurveChartData, // ⬅️ HIER FEHLTE DIESE ZEILE
loopMeasurementCurveChartData,
} = useSelector((state: RootState) => state.kabelueberwachungChart);
/**
* API-URL-Erstellung für Entwicklung und Produktion
*/
const getApiUrl = (mode: "DIA0" | "DIA1" | "DIA2", type: number) => {
const getApiUrl = (
mode: "DIA0" | "DIA1" | "DIA2",
type: number,
slotNumber: number
) => {
if (!slotNumber) {
console.error("⚠️ Slot-Nummer nicht gesetzt!");
return "";
}
// Dynamische Basis-URL abhängig von Umgebung
const typeFolder =
type === 3 ? "isolationswiderstand" : "schleifenwiderstand";
const baseUrl =
process.env.NODE_ENV === "development"
? `/CPLmockData/kuesChartData/${mode}_${type}.json`
? `/CPLmockData/kuesChartData/slot${slotNumber}/${typeFolder}/${mode}.json`
: `${window.location.origin}/CPL?seite.ACP&${mode}=${formatDate(
vonDatum
)};${formatDate(bisDatum)};${slotNumber};${type};`;
@@ -52,18 +58,21 @@ const LoopChartActionBar: React.FC = () => {
return `${dateParts[0]};${dateParts[1]};${dateParts[2]}`;
};
/**
* Funktion zum Laden der Messwerte
*/
/**
* Funktion zum Laden der Messwerte
*/
const handleFetchData = async () => {
const type = selectedSlotType === "schleifenwiderstand" ? 4 : 3;
const apiUrl = getApiUrl(selectedMode, type);
if (slotNumber === null) {
console.error("⚠️ Slot-Nummer nicht gesetzt!");
return;
}
const apiUrl = getApiUrl(selectedMode, type, slotNumber); // ✅ slotNumber ergänzt
if (!apiUrl) return;
try {
console.log("📡 API-Request an:", apiUrl); // Debugging
console.log("📡 API-Request an:", apiUrl);
const response = await fetch(apiUrl, {
method: "GET",
headers: { "Content-Type": "application/json" },
@@ -75,7 +84,7 @@ const LoopChartActionBar: React.FC = () => {
console.log("✅ Daten erfolgreich geladen:", jsonData);
if (Array.isArray(jsonData)) {
dispatch(setLoopMeasurementCurveChartData([...jsonData])); // Erzwingt eine neue Referenz
dispatch(setLoopMeasurementCurveChartData([...jsonData]));
// Falls das Chart zum ersten Mal geöffnet wird, setze vonDatum & bisDatum
if (!isChartOpen && jsonData.length > 0) {
@@ -83,22 +92,18 @@ const LoopChartActionBar: React.FC = () => {
const lastDate = new Date(jsonData[0].t);
dispatch(setVonDatum(firstDate.toISOString().split("T")[0]));
dispatch(setBisDatum(lastDate.toISOString().split("T")[0]));
dispatch(setChartOpen(true)); // Chart öffnen
dispatch(setChartOpen(true));
}
} else {
console.error("⚠️ Erwartetes Array, aber erhalten:", jsonData);
}
} catch (error) {
console.error("❌ Fehler beim Laden der Produktions-Daten:", error);
console.error("❌ Fehler beim Laden der Daten:", error);
}
};
const minDate = useMemo(() => {
if (
!loopMeasurementCurveChartData ||
loopMeasurementCurveChartData.length === 0
)
return "";
if (!loopMeasurementCurveChartData?.length) return "";
return new Date(
loopMeasurementCurveChartData[loopMeasurementCurveChartData.length - 1].t
)
@@ -107,77 +112,78 @@ const LoopChartActionBar: React.FC = () => {
}, [loopMeasurementCurveChartData]);
const maxDate = useMemo(() => {
if (
!loopMeasurementCurveChartData ||
loopMeasurementCurveChartData.length === 0
)
return "";
if (!loopMeasurementCurveChartData?.length) return "";
return new Date(loopMeasurementCurveChartData[0].t)
.toISOString()
.split("T")[0];
}, [loopMeasurementCurveChartData]);
// **Automatische Datenaktualisierung bei Auswahländerung**
// Automatische Datenaktualisierung bei Auswahländerung
useEffect(() => {
handleFetchData();
}, [selectedMode, selectedSlotType]); // Wird ausgeführt, wenn sich ein Dropdown ändert
// Wenn sich slotNumber, Zeitraum oder Auswahl ändert, neu laden:
}, [selectedMode, selectedSlotType, slotNumber, vonDatum, bisDatum]);
return (
<div className="flex justify-end items-center p-2 bg-gray-100 rounded-lg space-x-2">
{/* Datumsauswahl */}
<DateRangePicker
setVonDatum={(date) => {
const isoDate = date.toISOString().split("T")[0];
<div className="flex justify-between items-center p-2 bg-gray-100 rounded-lg space-x-2">
{/* Slot Nummer links positioniert */}
<div className="flex items-center">
<label className="text-sm font-semibold">
Slot-Nr.: {slotNumber ?? "-"}
</label>
</div>
if (isoDate < minDate || isoDate > maxDate) return;
<div className="flex items-center space-x-2">
<DateRangePicker
setVonDatum={(date) => {
const isoDate = date.toISOString().split("T")[0];
dispatch(setVonDatum(isoDate));
if (isoDate < minDate || isoDate > maxDate) return;
if (isoDate > bisDatum) {
dispatch(setBisDatum(isoDate)); // Sicherstellen, dass bisDatum >= vonDatum bleibt
}
}}
setBisDatum={(date) => {
const isoDate = date.toISOString().split("T")[0];
dispatch(setVonDatum(isoDate));
if (isoDate < minDate || isoDate > maxDate) return;
if (isoDate > bisDatum) dispatch(setBisDatum(isoDate));
}}
setBisDatum={(date) => {
const isoDate = date.toISOString().split("T")[0];
if (isoDate >= vonDatum) {
dispatch(setBisDatum(isoDate));
}
}}
minDate={minDate}
maxDate={maxDate}
/>
if (isoDate < minDate || isoDate > maxDate) return;
{/* Dropdown für DIA-Modus */}
<select
value={selectedMode}
onChange={(e) =>
dispatch(setSelectedMode(e.target.value as "DIA0" | "DIA1" | "DIA2"))
}
className="px-3 py-1 bg-white border rounded text-sm"
>
<option value="DIA0">Alle Messwerte</option>
<option value="DIA1">Stündliche Werte</option>
<option value="DIA2">Tägliche Werte</option>
</select>
if (isoDate >= vonDatum) dispatch(setBisDatum(isoDate));
}}
minDate={minDate}
maxDate={maxDate}
/>
{/* Dropdown für Slot-Typ */}
<select
value={selectedSlotType}
onChange={(e) =>
dispatch(
setSelectedSlotType(
e.target.value as "isolationswiderstand" | "schleifenwiderstand"
<select
value={selectedMode}
onChange={(e) =>
dispatch(
setSelectedMode(e.target.value as "DIA0" | "DIA1" | "DIA2")
)
)
}
className="px-3 py-1 bg-white border rounded text-sm"
>
<option value="schleifenwiderstand">Schleifenwiderstand</option>
<option value="isolationswiderstand">Isolationswiderstand</option>
</select>
}
className="px-3 py-1 bg-white border rounded text-sm"
>
<option value="DIA0">Alle Messwerte</option>
<option value="DIA1">Stündliche Werte</option>
<option value="DIA2">Tägliche Werte</option>
</select>
<select
value={selectedSlotType}
onChange={(e) =>
dispatch(
setSelectedSlotType(
e.target.value as "isolationswiderstand" | "schleifenwiderstand"
)
)
}
className="px-3 py-1 bg-white border rounded text-sm"
>
<option value="schleifenwiderstand">Schleifenwiderstand</option>
<option value="isolationswiderstand">Isolationswiderstand</option>
</select>
</div>
</div>
);
};