diff --git a/.env.development b/.env.development index aa0975f..fda0d08 100644 --- a/.env.development +++ b/.env.development @@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false NEXT_PUBLIC_EXPORT_STATIC=false NEXT_PUBLIC_USE_CGI=false # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.667 +NEXT_PUBLIC_APP_VERSION=1.6.668 NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) diff --git a/.env.production b/.env.production index ec51c37..5a6b536 100644 --- a/.env.production +++ b/.env.production @@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL NEXT_PUBLIC_EXPORT_STATIC=true NEXT_PUBLIC_USE_CGI=true # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.667 +NEXT_PUBLIC_APP_VERSION=1.6.668 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e23aa4b..c5ff2e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## [1.6.668] – 2025-07-31 + +- feat: implement chart modal with report functionality for cable monitoring + +- Add chartTitle state management to kabelueberwachungChartSlice with "Messkurve"/"Meldungen" options +- Update IsoChartActionBar dropdown to show current chartTitle value with proper binding +- Implement conditional rendering in IsoChartView between IsoMeasurementChart and Report components +- Create Report.tsx component using same data structure as MeldungenView (Meldung type) +- Add slot-based message filtering for specific cable monitoring units (KÜ) +- Integrate getMessagesThunk for consistent data loading across components +- Style Report component with consistent table layout, German date formatting, and Littwin branding +- Enable seamless switching between measurement chart and filtered messages in modal + +--- ## [1.6.667] – 2025-07-31 - feat: TDR --> Messkurven TDR anzeigen und dort Schalter Messung aktivieren diff --git a/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx b/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx index def321a..74f9e63 100644 --- a/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx +++ b/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartActionBar.tsx @@ -88,6 +88,87 @@ export const useIsoChartLoader = () => { return { loadIsoChartData }; }; +//-----------------------------------------------------------------------------------useIsoDataLoader Hook +export const useIsoDataLoader = () => { + const dispatch = useDispatch(); + 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)); + + console.log("▶️ Automatisches Laden - Isolationswiderstand-Daten für:"); + console.log(" Slot:", slotNumber); + console.log(" Modus:", selectedMode); + console.log(" Von:", vonDatum); + console.log(" Bis:", bisDatum); + + if (Array.isArray(jsonData) && jsonData.length > 0) { + dispatch(setIsoMeasurementCurveChartData(jsonData)); + dispatch(setChartOpen(true)); + } else { + console.log( + "⚠️ Keine Messdaten im gewählten Zeitraum gefunden (automatisches Laden)" + ); + 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: React.FC = () => { const dispatch = useDispatch(); @@ -183,67 +264,71 @@ const IsoChartActionBar: React.FC = () => {
- + {/* DateRangePicker - nur bei Messkurve anzeigen */} + {chartTitle === "Messkurve" && } - { - dispatch(setSelectedMode(value)); - dispatch(setBrushRange({ startIndex: 0, endIndex: 0 })); - }} - > -
- - - { - { - DIA0: "Alle Messwerte", - DIA1: "Stündliche Werte", - DIA2: "Tägliche Werte", - }[selectedMode] - } - - - - - - - {["DIA0", "DIA1", "DIA2"].map((mode) => ( - - `px-4 py-1 cursor-pointer ${ - selected - ? "bg-littwin-blue text-white" - : active - ? "bg-gray-200" - : "" - }` - } - > + {/* DIA0-DIA2 Dropdown - nur bei Messkurve anzeigen */} + {chartTitle === "Messkurve" && ( + { + dispatch(setSelectedMode(value)); + dispatch(setBrushRange({ startIndex: 0, endIndex: 0 })); + }} + > +
+ + { { DIA0: "Alle Messwerte", DIA1: "Stündliche Werte", DIA2: "Tägliche Werte", - }[mode] + }[selectedMode] } - - ))} - -
-
+ + + + + + + {["DIA0", "DIA1", "DIA2"].map((mode) => ( + + `px-4 py-1 cursor-pointer ${ + selected + ? "bg-littwin-blue text-white" + : active + ? "bg-gray-200" + : "" + }` + } + > + { + { + DIA0: "Alle Messwerte", + DIA1: "Stündliche Werte", + DIA2: "Tägliche Werte", + }[mode] + } + + ))} + +
+
+ )} - {/* Dropdown für Auswahl zwischen "Messkurve" und "Meldungen" */} + {/* Dropdown für Auswahl zwischen "Messkurve" und "Meldungen" - immer anzeigen */} dispatch(setChartTitle(value))} @@ -285,14 +370,18 @@ const IsoChartActionBar: React.FC = () => {
- + {/* Daten laden Button - nur bei Messkurve anzeigen */} + {chartTitle === "Messkurve" && ( + + )} - {isLoading && ( + {/* Loading Indicator - nur bei Messkurve anzeigen */} + {chartTitle === "Messkurve" && isLoading && (
Lade Daten... diff --git a/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartView.tsx b/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartView.tsx index f4a781a..c6453a0 100644 --- a/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartView.tsx +++ b/components/main/kabelueberwachung/kue705FO/Charts/IsoMeasurementChart/IsoChartView.tsx @@ -3,7 +3,7 @@ import React, { useEffect } from "react"; import ReactModal from "react-modal"; import IsoMeasurementChart from "./IsoMeasurementChart"; -import IsoChartActionBar from "./IsoChartActionBar"; +import IsoChartActionBar, { useIsoDataLoader } from "./IsoChartActionBar"; import Report from "./Report"; import { useSelector, useDispatch } from "react-redux"; import { AppDispatch } from "@/redux/store"; @@ -36,6 +36,7 @@ const IsoChartView: React.FC = ({ slotIndex, }) => { const dispatch = useDispatch(); + const { loadData } = useIsoDataLoader(); const { isFullScreen, chartTitle } = useSelector( (state: RootState) => state.kabelueberwachungChartSlice @@ -92,8 +93,18 @@ const IsoChartView: React.FC = ({ // Set default to Messkurve dispatch(setChartTitle("Messkurve")); + + // Automatisch Daten laden nach kurzer Verzögerung + // um sicherzustellen, dass alle Redux-States gesetzt sind + const timer = setTimeout(() => { + loadData(); + }, 100); + + // Cleanup timer + return () => clearTimeout(timer); } - }, [isOpen, slotIndex, dispatch]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isOpen, slotIndex, dispatch]); // loadData bewusst ausgelassen um Endlosschleife zu vermeiden return ( { (allMessages: Meldung[], slot: number) => { if (slot === null) return []; - // Filter basierend auf der Quelle (i-Feld) - return allMessages.filter((msg: Meldung) => { - // Verschiedene mögliche Slot-Identifikationen - const slotIdentifiers = [ - `CableLine${slot + 1}`, + // Primärer Filter: Exakte CableLineX Übereinstimmung (X = slot + 1) + const primaryIdentifier = `CableLine${slot + 1}`; + + console.log( + `🔍 Filtere Nachrichten für Slot ${slot} (${primaryIdentifier}):` + ); + console.log(`📥 Gesamt Nachrichten: ${allMessages.length}`); + + // Debug: Zeige alle verfügbaren Quellen + const allSources = [...new Set(allMessages.map((msg) => msg.i))]; + console.log(`📋 Alle verfügbaren Quellen:`, allSources); + + // Filter basierend auf der Quelle (i-Feld) - EXAKTE Übereinstimmung + const filtered = allMessages.filter((msg: Meldung) => { + // Exakte Übereinstimmung: msg.i sollte genau "CableLineX" sein + const isExactMatch = msg.i === primaryIdentifier; + + // Fallback: Falls die Quelle mehr Informationen enthält (z.B. "CableLine1_Sensor") + const isPartialMatch = + msg.i.startsWith(primaryIdentifier) && + (msg.i === primaryIdentifier || + msg.i.charAt(primaryIdentifier.length).match(/[^0-9]/)); + + const isMatch = isExactMatch || isPartialMatch; + + if (isMatch) { + console.log(`✅ Gefunden: "${msg.i}" -> ${msg.m}`); + } + return isMatch; + }); + + console.log( + `📤 Gefilterte Nachrichten für ${primaryIdentifier}: ${filtered.length}` + ); + + // Falls keine Nachrichten mit CableLineX gefunden, versuche alternative Identifikatoren + if (filtered.length === 0) { + console.log( + `⚠️ Keine Nachrichten für ${primaryIdentifier} gefunden. Versuche alternative Identifikatoren...` + ); + + const alternativeIdentifiers = [ `Slot${slot + 1}`, `KÜ${slot + 1}`, `Kue${slot + 1}`, @@ -45,8 +82,29 @@ const Report: React.FC = () => { `Line${slot + 1}`, ]; - return slotIdentifiers.some((identifier) => msg.i.includes(identifier)); - }); + const alternativeFiltered = allMessages.filter((msg: Meldung) => { + return alternativeIdentifiers.some((identifier) => { + const isExactMatch = msg.i === identifier; + const isPartialMatch = + msg.i.startsWith(identifier) && + (msg.i === identifier || + msg.i.charAt(identifier.length).match(/[^0-9]/)); + const isMatch = isExactMatch || isPartialMatch; + + if (isMatch) { + console.log(`🔄 Alternative gefunden: "${msg.i}" -> ${msg.m}`); + } + return isMatch; + }); + }); + + console.log( + `📤 Alternative gefilterte Nachrichten: ${alternativeFiltered.length}` + ); + return alternativeFiltered; + } + + return filtered; }, [] ); @@ -107,25 +165,15 @@ const Report: React.FC = () => { } return ( -
-
-

- Meldungen für KÜ {slotNumber !== null ? slotNumber + 1 : "-"} -

- -
- +
{filteredMessages.length === 0 ? ( -
- Keine Meldungen im gewählten Zeitraum gefunden. +
+ Keine Meldungen für CableLine + {slotNumber !== null ? slotNumber + 1 : "-"} im gewählten Zeitraum + gefunden.
) : ( -
+
@@ -165,7 +213,7 @@ const Report: React.FC = () => { )} -
+
{filteredMessages.length} Meldung(en) gefunden
diff --git a/package-lock.json b/package-lock.json index 93c3988..30c3523 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.667", + "version": "1.6.668", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.667", + "version": "1.6.668", "dependencies": { "@fontsource/roboto": "^5.1.0", "@headlessui/react": "^2.2.4", diff --git a/package.json b/package.json index 461f853..0243490 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpl-v4", - "version": "1.6.667", + "version": "1.6.668", "private": true, "scripts": { "dev": "next dev",