362 lines
12 KiB
TypeScript
362 lines
12 KiB
TypeScript
"use client";
|
|
// /components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx
|
|
import React, { forwardRef, useImperativeHandle } from "react";
|
|
import DateRangePicker from "@/components/common/DateRangePicker";
|
|
import { useSelector } from "react-redux";
|
|
import { RootState, useAppDispatch } from "@/redux/store";
|
|
import {
|
|
setIsoMeasurementCurveChartData,
|
|
setSelectedMode,
|
|
setChartOpen,
|
|
setLoading,
|
|
} from "@/redux/slices/kabelueberwachungChartSlice";
|
|
import { setBrushRange } from "@/redux/slices/brushSlice";
|
|
import { getMessagesThunk } from "@/redux/thunks/getMessagesThunk";
|
|
import { Listbox } from "@headlessui/react";
|
|
|
|
//-----------------------------------------------------------------------------------useIsoChartLoader
|
|
export const useIsoChartLoader = () => {
|
|
const dispatch = useAppDispatch();
|
|
const { vonDatum, bisDatum, selectedMode, slotNumber } = useSelector(
|
|
(state: RootState) => state.kabelueberwachungChartSlice
|
|
);
|
|
const hasShownNoDataAlert = React.useRef(false);
|
|
|
|
const formatDate = (dateString: string) => {
|
|
const [year, month, day] = dateString.split("-");
|
|
return `${year};${month};${day}`;
|
|
};
|
|
|
|
const getApiUrl = (mode: "DIA0" | "DIA1" | "DIA2", slotNumber: number) => {
|
|
const type = 3; // Fest auf Isolationswiderstand gesetzt
|
|
const typeFolder = "isolationswiderstand";
|
|
|
|
let url: string;
|
|
|
|
if (process.env.NODE_ENV === "development") {
|
|
url = `/api/cpl/slotDataAPIHandler?slot=${slotNumber}&messart=${typeFolder}&dia=${mode}&vonDatum=${vonDatum}&bisDatum=${bisDatum}`;
|
|
} else {
|
|
url = `${window.location.origin}/CPL?seite.ACP&${mode}=${formatDate(
|
|
vonDatum
|
|
)};${formatDate(bisDatum)};${slotNumber};${type};`;
|
|
}
|
|
|
|
return url;
|
|
};
|
|
|
|
const loadIsoChartData = async () => {
|
|
if (slotNumber === null) return;
|
|
|
|
dispatch(setLoading(true));
|
|
dispatch(setChartOpen(false));
|
|
dispatch(setIsoMeasurementCurveChartData([]));
|
|
|
|
const startTime = Date.now();
|
|
const MIN_LOADING_TIME_MS = 1000;
|
|
|
|
try {
|
|
const apiUrl = getApiUrl(selectedMode, slotNumber);
|
|
const response = await fetch(apiUrl);
|
|
const data = await response.json();
|
|
|
|
const waitTime = Math.max(
|
|
0,
|
|
MIN_LOADING_TIME_MS - (Date.now() - startTime)
|
|
);
|
|
await new Promise((res) => setTimeout(res, waitTime));
|
|
|
|
if (Array.isArray(data) && data.length > 0) {
|
|
dispatch(setIsoMeasurementCurveChartData(data));
|
|
dispatch(setChartOpen(true));
|
|
} else {
|
|
dispatch(setIsoMeasurementCurveChartData([]));
|
|
dispatch(setChartOpen(false));
|
|
if (!hasShownNoDataAlert.current) {
|
|
alert("⚠️ Keine Messdaten im gewählten Zeitraum gefunden");
|
|
hasShownNoDataAlert.current = true;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error("❌ Fehler beim Laden:", err);
|
|
alert("❌ Fehler beim Laden.");
|
|
} finally {
|
|
dispatch(setLoading(false));
|
|
}
|
|
};
|
|
|
|
return { loadIsoChartData };
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------------useIsoDataLoader Hook
|
|
export const useIsoDataLoader = () => {
|
|
const dispatch = useAppDispatch();
|
|
const { vonDatum, bisDatum, selectedMode, slotNumber } = useSelector(
|
|
(state: RootState) => state.kabelueberwachungChartSlice
|
|
);
|
|
|
|
const formatDate = (dateString: string) => {
|
|
const [year, month, day] = dateString.split("-");
|
|
return `${year};${month};${day}`;
|
|
};
|
|
|
|
const getApiUrl = (mode: "DIA0" | "DIA1" | "DIA2", slotNumber: number) => {
|
|
const type = 3; // Fest auf Isolationswiderstand gesetzt
|
|
const typeFolder = "isolationswiderstand";
|
|
|
|
const baseUrl =
|
|
process.env.NODE_ENV === "development"
|
|
? `/api/cpl/slotDataAPIHandler?slot=${slotNumber}&messart=${typeFolder}&dia=${mode}&vonDatum=${vonDatum}&bisDatum=${bisDatum}`
|
|
: `${window.location.origin}/CPL?seite.ACP&${mode}=${formatDate(
|
|
vonDatum
|
|
)};${formatDate(bisDatum)};${slotNumber};${type};`;
|
|
|
|
return baseUrl;
|
|
};
|
|
|
|
const loadData = async () => {
|
|
if (slotNumber === null) {
|
|
console.log("⚠️ Kein Slot ausgewählt - automatisches Laden übersprungen");
|
|
return;
|
|
}
|
|
|
|
const apiUrl = getApiUrl(selectedMode, slotNumber);
|
|
if (!apiUrl) return;
|
|
|
|
dispatch(setLoading(true));
|
|
dispatch(setChartOpen(false));
|
|
dispatch(setIsoMeasurementCurveChartData([]));
|
|
|
|
const MIN_LOADING_TIME_MS = 1000;
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
const response = await fetch(apiUrl, {
|
|
method: "GET",
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
|
|
if (!response.ok) throw new Error(`Fehler: ${response.status}`);
|
|
|
|
const jsonData = await response.json();
|
|
const elapsedTime = Date.now() - startTime;
|
|
const waitTime = Math.max(0, MIN_LOADING_TIME_MS - elapsedTime);
|
|
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
|
|
if (Array.isArray(jsonData) && jsonData.length > 0) {
|
|
dispatch(setIsoMeasurementCurveChartData(jsonData));
|
|
dispatch(setChartOpen(true));
|
|
} else {
|
|
dispatch(setIsoMeasurementCurveChartData([]));
|
|
dispatch(setChartOpen(false));
|
|
}
|
|
} catch (err) {
|
|
console.error("❌ Fehler beim automatischen Laden der Daten:", err);
|
|
} finally {
|
|
dispatch(setLoading(false));
|
|
}
|
|
};
|
|
|
|
return { loadData };
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------------IsoChartActionBar
|
|
const IsoChartActionBar = forwardRef((_props, ref) => {
|
|
IsoChartActionBar.displayName = "IsoChartActionBar";
|
|
const dispatch = useAppDispatch();
|
|
|
|
const { vonDatum, bisDatum, selectedMode, slotNumber, chartTitle } =
|
|
useSelector((state: RootState) => state.kabelueberwachungChartSlice);
|
|
// Aus DateRangePicker-Slice kommen die Werte, die der User im UI wählt
|
|
const { vonDatum: pickerVonDatum, bisDatum: pickerBisDatum } = useSelector(
|
|
(state: RootState) => state.dateRangePicker
|
|
);
|
|
|
|
const formatDate = (dateString: string) => {
|
|
const [year, month, day] = dateString.split("-");
|
|
return `${year};${month};${day}`;
|
|
};
|
|
|
|
const getApiUrl = (
|
|
mode: "DIA0" | "DIA1" | "DIA2",
|
|
slotNumber: number,
|
|
fromDate: string,
|
|
toDate: string
|
|
) => {
|
|
const type = 3; // Fest auf Isolationswiderstand gesetzt
|
|
const typeFolder = "isolationswiderstand";
|
|
|
|
const baseUrl =
|
|
process.env.NODE_ENV === "development"
|
|
? `/api/cpl/slotDataAPIHandler?slot=${slotNumber}&messart=${typeFolder}&dia=${mode}&vonDatum=${fromDate}&bisDatum=${toDate}`
|
|
: `${window.location.origin}/CPL?seite.ACP&${mode}=${formatDate(
|
|
fromDate
|
|
)};${formatDate(toDate)};${slotNumber};${type};`;
|
|
|
|
console.log("baseUrl", baseUrl);
|
|
return baseUrl;
|
|
};
|
|
|
|
const handleFetchData = async () => {
|
|
if (slotNumber === null) {
|
|
alert("⚠️ Bitte zuerst einen KÜ auswählen!");
|
|
return;
|
|
}
|
|
// Wenn Meldungen-Ansicht aktiv ist, dann Meldungen laden
|
|
if (chartTitle === "Meldungen") {
|
|
try {
|
|
dispatch(setLoading(true));
|
|
const fromDate = pickerVonDatum ?? vonDatum;
|
|
const toDate = pickerBisDatum ?? bisDatum;
|
|
await dispatch(getMessagesThunk({ fromDate, toDate })).unwrap();
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
console.error("❌ Fehler beim Laden der Meldungen:", message);
|
|
alert("❌ Fehler beim Laden der Meldungen.");
|
|
} finally {
|
|
dispatch(setLoading(false));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Messkurve (ISO) laden
|
|
const fromDate = pickerVonDatum ?? vonDatum;
|
|
const toDate = pickerBisDatum ?? bisDatum;
|
|
const apiUrl = getApiUrl(selectedMode, slotNumber, fromDate, toDate);
|
|
if (!apiUrl) return;
|
|
|
|
dispatch(setLoading(true));
|
|
dispatch(setChartOpen(false));
|
|
dispatch(setIsoMeasurementCurveChartData([]));
|
|
|
|
const MIN_LOADING_TIME_MS = 1000;
|
|
const startTime = Date.now();
|
|
|
|
try {
|
|
const response = await fetch(apiUrl, {
|
|
method: "GET",
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
|
|
if (!response.ok) throw new Error(`Fehler: ${response.status}`);
|
|
|
|
const jsonData = await response.json();
|
|
const elapsedTime = Date.now() - startTime;
|
|
const waitTime = Math.max(0, MIN_LOADING_TIME_MS - elapsedTime);
|
|
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
|
|
console.log("▶️ Lade Isolationswiderstand-Daten für:");
|
|
console.log(" Slot:", slotNumber);
|
|
console.log(" Modus:", selectedMode);
|
|
console.log(" Von:", fromDate);
|
|
console.log(" Bis:", toDate);
|
|
console.log(" URL:", apiUrl);
|
|
console.log(" Daten:", jsonData);
|
|
|
|
if (Array.isArray(jsonData) && jsonData.length > 0) {
|
|
dispatch(setIsoMeasurementCurveChartData(jsonData));
|
|
dispatch(setChartOpen(true));
|
|
} else {
|
|
alert("⚠️ Keine Messdaten im gewählten Zeitraum gefunden.");
|
|
dispatch(setIsoMeasurementCurveChartData([]));
|
|
dispatch(setChartOpen(false));
|
|
}
|
|
} catch (err) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
console.error("❌ Fehler beim Laden der Daten:", message);
|
|
alert("❌ Fehler beim Laden der Daten.");
|
|
} finally {
|
|
dispatch(setLoading(false));
|
|
}
|
|
};
|
|
|
|
useImperativeHandle(ref, () => ({ handleFetchData }));
|
|
|
|
const isMeldungen = chartTitle === "Meldungen";
|
|
|
|
return (
|
|
<div className="toolbar w-full justify-between flex-wrap">
|
|
<div className="flex items-center gap-2 pr-4">
|
|
<span className=" font-semibold uppercase tracking-wide text-muted">
|
|
KÜ
|
|
</span>
|
|
<span className=" font-medium px-2 py-0.5 rounded bg-surface-alt border border-base min-w-[3rem] text-center">
|
|
{slotNumber !== null ? slotNumber + 1 : "-"}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-3 flex-1 justify-end">
|
|
{/* Always show date range; requirement: in Meldungen only Von/Bis + Anzeigen */}
|
|
<DateRangePicker />
|
|
{!isMeldungen && (
|
|
<>
|
|
<Listbox
|
|
value={selectedMode}
|
|
onChange={(value) => {
|
|
dispatch(setSelectedMode(value));
|
|
dispatch(setBrushRange({ startIndex: 0, endIndex: 0 }));
|
|
}}
|
|
>
|
|
<div className="relative w-48">
|
|
<Listbox.Button className="dropdown-surface w-full flex items-center justify-between">
|
|
<span className="dropdown-text-fix">
|
|
{
|
|
{
|
|
DIA0: "Alle Messwerte",
|
|
DIA1: "Stündlich",
|
|
DIA2: "Täglich",
|
|
}[selectedMode]
|
|
}
|
|
</span>
|
|
<i className="bi bi-chevron-down opacity-70" />
|
|
</Listbox.Button>
|
|
<Listbox.Options className="dropdown-options absolute z-50 mt-1 w-full max-h-60 overflow-auto">
|
|
{["DIA0", "DIA1", "DIA2"].map((mode) => (
|
|
<Listbox.Option
|
|
key={mode}
|
|
value={mode}
|
|
className={({ selected, active }) =>
|
|
`px-3 py-1.5 cursor-pointer rounded-sm m-0.5 ${
|
|
selected
|
|
? "dropdown-option-active"
|
|
: active
|
|
? "dropdown-option-hover"
|
|
: ""
|
|
}`
|
|
}
|
|
>
|
|
{
|
|
{
|
|
DIA0: "Alle Messwerte",
|
|
DIA1: "Stündlich",
|
|
DIA2: "Täglich",
|
|
}[mode as "DIA0" | "DIA1" | "DIA2"]
|
|
}
|
|
</Listbox.Option>
|
|
))}
|
|
</Listbox.Options>
|
|
</div>
|
|
</Listbox>
|
|
<button
|
|
onClick={handleFetchData}
|
|
className="btn-primary h-8 font-medium px-3"
|
|
type="button"
|
|
>
|
|
Daten laden
|
|
</button>
|
|
</>
|
|
)}
|
|
{isMeldungen && (
|
|
<button
|
|
onClick={handleFetchData}
|
|
className="btn-primary h-8 font-medium px-4"
|
|
type="button"
|
|
>
|
|
Anzeigen
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
});
|
|
|
|
export default IsoChartActionBar;
|