diff --git a/CHANGELOG.md b/CHANGELOG.md index 13d6e7f..58dc908 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ Alle Änderungen und Versionen des CPLv4.0 Frontends chronologisch dokumentiert. --- +## [1.6.329] – 2025-05-02 + +### Hinzugefügt + +- Auf der Seite **/analogeEingaenge** wird nun nur der ausgewählte Eingang im Chart angezeigt +- Der Titel des Charts enthält die Angabe „letzte 24 Stunden“ +- Die Zeitachse (X-Achse) ist im deutschen Format (`HH:mm Uhr DD.MM.`) + +--- + ## [1.6.328] – 2025-05-02 ### Hinzugefügt diff --git a/README.md b/README.md index deb8028..4302cda 100644 --- a/README.md +++ b/README.md @@ -110,9 +110,9 @@ Beispielaufruf im DEV-Modus (über UI gesteuert, nicht manuell notwendig): - Faktor und Offset anzeigen - Gewichtung und Loggerintervall anzeigen - Neue Chart.js Visualisierung: - - Verlauf aller 8 analogen Eingänge gleichzeitig anzeigen - - Nutzer kann Eingänge einzeln über Legende ein-/ausblenden - - Historische Messwerte der letzten 24 Stunden dargestellt (Zeitskala auf der X-Achse) +- Beim Klick auf einen Eingang in der Tabelle wird nur dessen Verlaufskurve angezeigt +- Der Verlauf bezieht sich auf die letzten 24 Stunden, dargestellt mit deutscher Zeitachse + - Entwicklung mit Mock-Daten: - In der Entwicklungsumgebung werden Mock-Daten über den API-Handler `/api/cpl/fetchAnalogInputsHistory` geladen - In der Produktion wird direkt auf die Live-Daten der CPL-Webschnittstelle (DIA0) zugegriffen diff --git a/components/main/analogeEingaenge/AnalogInputsChart.tsx b/components/main/analogeEingaenge/AnalogInputsChart.tsx index b612f77..6855122 100644 --- a/components/main/analogeEingaenge/AnalogInputsChart.tsx +++ b/components/main/analogeEingaenge/AnalogInputsChart.tsx @@ -1,4 +1,4 @@ -"use client"; // components/main/analogeEingaenge/AnalogInputsChart.tsx +"use client"; import React, { useEffect } from "react"; import { Line } from "react-chartjs-2"; import { @@ -13,6 +13,7 @@ import { TimeScale, } from "chart.js"; import "chartjs-adapter-date-fns"; +import { de } from "date-fns/locale"; import { useSelector, useDispatch } from "react-redux"; import type { RootState, AppDispatch } from "../../../redux/store"; import { fetchAnalogInputsHistoryThunk } from "../../../redux/thunks/fetchAnalogInputsHistoryThunk"; @@ -28,18 +29,11 @@ ChartJS.register( TimeScale ); -const colors = [ - "#007bff", - "#28a745", - "#dc3545", - "#ffc107", - "#17a2b8", - "#6f42c1", - "#fd7e14", - "#20c997", -]; - -export default function AnalogInputsChart() { +export default function AnalogInputsChart({ + selectedId, +}: { + selectedId: number | null; +}) { const dispatch = useDispatch(); const { data, isLoading, error } = useSelector( (state: RootState) => state.analogInputsHistory @@ -49,34 +43,45 @@ export default function AnalogInputsChart() { dispatch(fetchAnalogInputsHistoryThunk()); }, [dispatch]); - const datasets = Object.entries(data).map(([key, inputData], index) => ({ - label: `Eingang ${Number(key) - 99}`, - data: inputData.map((point: any) => ({ - x: point.t, - y: point.m, - })), - fill: false, - borderColor: colors[index % colors.length], - backgroundColor: colors[index % colors.length], - tension: 0.3, - })); + if (!selectedId) { + return
Bitte einen Eingang auswählen
; + } + + const key = String(selectedId + 99); + const inputData = data[key]; + + if (!inputData) { + return ( +
+ Keine Verlaufsdaten für Eingang {selectedId} gefunden. +
+ ); + } const chartData = { - datasets, + datasets: [ + { + label: `Eingang ${selectedId}`, + data: inputData.map((point: any) => ({ + x: point.t, + y: point.m, + })), + fill: false, + borderColor: "#007bff", + backgroundColor: "#007bff", + tension: 0.3, + }, + ], }; const chartOptions = { responsive: true, plugins: { - legend: { - position: "top" as const, - labels: { - usePointStyle: true, - }, - }, - tooltip: { - mode: "index" as const, - intersect: false, + legend: { position: "top" as const }, + tooltip: { mode: "index" as const, intersect: false }, + title: { + display: true, + text: `Verlauf Eingang ${selectedId} – letzte 24 Stunden`, }, }, scales: { @@ -84,14 +89,20 @@ export default function AnalogInputsChart() { type: "time" as const, time: { unit: "hour", - tooltipFormat: "HH:mm", + tooltipFormat: "HH:mm 'Uhr' dd.MM.", displayFormats: { hour: "HH:mm", + day: "dd.MM.", + }, + }, + adapters: { + date: { + locale: de, }, }, title: { display: true, - text: "Zeit", + text: "Zeit ", }, }, y: { @@ -104,20 +115,8 @@ export default function AnalogInputsChart() { }; return ( -
-

- Alle analogen Eingänge – Verlauf der letzten 24 Stunden -

- - {isLoading ? ( -
Lade Daten...
- ) : error ? ( -
Fehler: {error}
- ) : ( -
- -
- )} +
+
); } diff --git a/components/main/analogeEingaenge/AnalogeEingaengeTable.tsx b/components/main/analogeEingaenge/AnalogeEingaengeTable.tsx index ced8d13..1075966 100644 --- a/components/main/analogeEingaenge/AnalogeEingaengeTable.tsx +++ b/components/main/analogeEingaenge/AnalogeEingaengeTable.tsx @@ -1,11 +1,14 @@ "use client"; -// components/main/analogeEingaenge/AnalogeEingaengeTable.tsx -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { RootState, AppDispatch } from "../../../redux/store"; import { fetchAnalogeEingaengeThunk } from "../../../redux/thunks/fetchAnalogeEingaengeThunk"; -export default function AnalogeEingaengeTable() { +export default function AnalogeEingaengeTable({ + setSelectedId, +}: { + setSelectedId: (id: number) => void; +}) { const dispatch = useDispatch(); useEffect(() => { @@ -16,16 +19,6 @@ export default function AnalogeEingaengeTable() { (state: RootState) => state.analogeEingaengeSlice ); - const [selectedEingang, setSelectedEingang] = useState(null); - - const openSettingsModal = (eingang: any) => { - setSelectedEingang(eingang); - }; - - const closeSettingsModal = () => { - setSelectedEingang(null); - }; - return (
@@ -36,92 +29,26 @@ export default function AnalogeEingaengeTable() { Eingang Messwert Bezeichnung - Einstellung {Object.values(analogeEingaenge) - .filter( - (eingang) => eingang?.id !== null && eingang?.id !== undefined - ) - .map((eingang, index) => ( + .filter((e) => e?.id !== null && e?.id !== undefined) + .map((e, index) => ( setSelectedId(e.id!)} > - {eingang.id ?? "-"} - {eingang.value ?? "-"} - {eingang.name || "----"} - - - + {e.id ?? "-"} + {e.value ?? "-"} + {e.name || "----"} ))}
- - {/* Modal */} - {selectedEingang && ( -
-
-
-

- Analoger Eingang {selectedEingang.id} -

-
- -
-
- Name: -
-
{selectedEingang.name}
- -
- Einheit: -
-
{selectedEingang.unit}
- -
- Faktor: -
-
{selectedEingang.factor}
- -
- Offset: -
-
{selectedEingang.offset}
- -
- Gewichtung: -
-
{selectedEingang.weighting}
- -
- Logger-Intervall: -
-
{selectedEingang.loggerInterval} Minuten
-
- -
- -
-
-
- )}
); } diff --git a/config/webVersion.ts b/config/webVersion.ts index 1864777..c494e09 100644 --- a/config/webVersion.ts +++ b/config/webVersion.ts @@ -6,5 +6,5 @@ 2: Patch oder Hotfix (Bugfixes oder kleine Änderungen). */ -const webVersion = "1.6.328"; +const webVersion = "1.6.329"; export default webVersion; diff --git a/pages/analogeEingaenge.tsx b/pages/analogeEingaenge.tsx index fdea02e..34aaf06 100644 --- a/pages/analogeEingaenge.tsx +++ b/pages/analogeEingaenge.tsx @@ -1,4 +1,5 @@ "use client"; ///pages/analogeEingaenge.tsx + import React, { useState, useEffect } from "react"; import AnalogeEingaengeTabelle from "../components/main/analogeEingaenge/AnalogeEingaengeTable"; import AnalogInputsChart from "../components/main/analogeEingaenge/AnalogInputsChart"; @@ -6,9 +7,9 @@ import { fetchAnalogeEingaengeThunk } from "../redux/thunks/fetchAnalogeEingaeng import { useAppDispatch } from "../redux/store"; function AnalogeEingaenge() { - const [activeConfig, setActiveConfig] = useState(null); - //--------------------------------------------------------- + const [selectedId, setSelectedId] = useState(null); const dispatch = useAppDispatch(); + useEffect(() => { if (typeof window !== "undefined") { dispatch(fetchAnalogeEingaengeThunk()); @@ -18,27 +19,23 @@ function AnalogeEingaenge() { return () => clearInterval(interval); } }, [dispatch]); - //--------------------------------------------------------- return ( -
+
- {/* Responsive Grid: 1 Spalte auf mobilen Geräten, 2 Spalten auf größeren Geräten */}
- {/* Tabelle als Card */}

Analoge Eingänge

- +
- {/* Diagramm als Card */}

- Analoge Eingäne Messkurve + Messkurve Eingang {selectedId ?? "–"}

- +