feat: Zeitraum einstellbar in AnalogInputsChart mit Zoom- und Pan-Funktion umgesetzt

This commit is contained in:
ISA
2025-06-25 13:48:14 +02:00
parent 2fcd0755a4
commit 53c2a02224
13 changed files with 291 additions and 14 deletions

View File

@@ -6,5 +6,16 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false
NEXT_PUBLIC_EXPORT_STATIC=false NEXT_PUBLIC_EXPORT_STATIC=false
NEXT_PUBLIC_USE_CGI=false NEXT_PUBLIC_USE_CGI=false
# App-Versionsnummer # App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.6.445 NEXT_PUBLIC_APP_VERSION=1.6.446
NEXT_PUBLIC_CPL_MODE=jsSimulatedProd # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) NEXT_PUBLIC_CPL_MODE=jsSimulatedProd # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter)
#### Feature-Flags ####
# 🔄 Zusatzfunktionen (Kai, 25.06.2025)
NEXT_PUBLIC_FEATURE_MESSWERTANZEIGE_EINGANG=true
NEXT_PUBLIC_FEATURE_MELDUNG_SPALTE_QUELLE=false
NEXT_PUBLIC_FEATURE_STARTSEITE_SPALTENREIHENFOLGE=false
NEXT_PUBLIC_FEATURE_BERICHTE_SPALTENREIHENFOLGE=false
NEXT_PUBLIC_FEATURE_FILTER_QUELLE=false
NEXT_PUBLIC_FEATURE_MESSWERT_DETAILANZEIGE=false
NEXT_PUBLIC_FEATURE_ADMIN_PASSWORT_AENDERN=false
NEXT_PUBLIC_FEATURE_OPC_CLIENT_ANZAHL=false

View File

@@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL
NEXT_PUBLIC_EXPORT_STATIC=true NEXT_PUBLIC_EXPORT_STATIC=true
NEXT_PUBLIC_USE_CGI=true NEXT_PUBLIC_USE_CGI=true
# App-Versionsnummer # App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.6.445 NEXT_PUBLIC_APP_VERSION=1.6.446
NEXT_PUBLIC_CPL_MODE=production NEXT_PUBLIC_CPL_MODE=production

View File

@@ -1,3 +1,8 @@
## [1.6.446] 2025-06-25
- docs: Zusatzfunktionen (Kai, 25.06.2025) in TODO.md ergänzt
---
## [1.6.445] 2025-06-25 ## [1.6.445] 2025-06-25
- docs: README - docs: README

View File

@@ -1,7 +1,7 @@
"use client"; // /components/main/analogeEingaenge/AnalogInputsChart.tsx "use client";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { Line } from "react-chartjs-2"; import { Line } from "react-chartjs-2";
import { getColor } from "../../../utils/colors"; import { getColor } from "@/utils/colors";
import { import {
Chart as ChartJS, Chart as ChartJS,
LineElement, LineElement,
@@ -19,6 +19,7 @@ import { useSelector, useDispatch } from "react-redux";
import type { RootState, AppDispatch } from "../../../redux/store"; import type { RootState, AppDispatch } from "../../../redux/store";
import { getAnalogInputsHistoryThunk } from "@/redux/thunks/getAnalogInputsHistoryThunk"; import { getAnalogInputsHistoryThunk } from "@/redux/thunks/getAnalogInputsHistoryThunk";
// Basis-Registrierung (ohne Zoom-Plugin)
ChartJS.register( ChartJS.register(
LineElement, LineElement,
PointElement, PointElement,
@@ -35,19 +36,32 @@ export default function AnalogInputsChart({
}: { }: {
selectedId: number | null; selectedId: number | null;
}) { }) {
const zoomEnabled =
process.env.NEXT_PUBLIC_FEATURE_MESSWERTANZEIGE_EINGANG === "true";
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const { data, isLoading, error } = useSelector( const { data } = useSelector(
(state: RootState) => state.analogInputsHistory (state: RootState) => state.analogInputsHistory
) as { ) as {
data: { [key: string]: any[] }; data: { [key: string]: any[] };
isLoading: boolean;
error: any;
}; };
useEffect(() => { useEffect(() => {
dispatch(getAnalogInputsHistoryThunk()); dispatch(getAnalogInputsHistoryThunk());
}, [dispatch]); }, [dispatch]);
// ✅ Zoom-Plugin dynamisch importieren und registrieren
useEffect(() => {
const loadZoomPlugin = async () => {
if (typeof window !== "undefined") {
const zoomPlugin = (await import("chartjs-plugin-zoom")).default;
if (!ChartJS.registry.plugins.get("zoom")) {
ChartJS.register(zoomPlugin);
}
}
};
loadZoomPlugin();
}, []);
if (!selectedId) { if (!selectedId) {
return ( return (
<div className="text-gray-500">Bitte einen Messwerteingang auswählen</div> <div className="text-gray-500">Bitte einen Messwerteingang auswählen</div>
@@ -77,7 +91,6 @@ export default function AnalogInputsChart({
borderColor: getColor("littwin-blue"), borderColor: getColor("littwin-blue"),
backgroundColor: "rgba(59,130,246,0.5)", backgroundColor: "rgba(59,130,246,0.5)",
borderWidth: 2, borderWidth: 2,
// fill: false,
pointRadius: 0, pointRadius: 0,
pointHoverRadius: 10, pointHoverRadius: 10,
tension: 0.1, tension: 0.1,
@@ -92,8 +105,21 @@ export default function AnalogInputsChart({
tooltip: { mode: "index" as const, intersect: false }, tooltip: { mode: "index" as const, intersect: false },
title: { title: {
display: true, display: true,
text: `Verlauf der letzte 24 Stunden`, text: `Verlauf der letzten 24 Stunden`,
}, },
...(zoomEnabled && {
zoom: {
pan: {
enabled: true,
mode: "x" as const,
},
zoom: {
wheel: { enabled: true },
pinch: { enabled: true },
mode: "x" as const,
},
},
}),
}, },
scales: { scales: {
x: { x: {
@@ -113,7 +139,7 @@ export default function AnalogInputsChart({
}, },
title: { title: {
display: true, display: true,
text: "Zeit ", text: "Zeit",
}, },
}, },
y: { y: {

View File

@@ -10,3 +10,5 @@
- [ ] System: Button bei jedem Messwert für Detailansicht (inkl. Kurve im Popup und Zeitauswahl) - [ ] System: Button bei jedem Messwert für Detailansicht (inkl. Kurve im Popup und Zeitauswahl)
- [ ] Einstellungen Benutzerverwaltung: Admin kann Adminpasswort ändern - [ ] Einstellungen Benutzerverwaltung: Admin kann Adminpasswort ändern
- [ ] Einstellungen OPC: Anzahl der aktuellen Clients (ggf. KAS-Variable einbauen) - [ ] Einstellungen OPC: Anzahl der aktuellen Clients (ggf. KAS-Variable einbauen)
![Zusatzfunktionen Kai 25.06.2025](./TODOsScreenshots/Zusatzfunktionen_25-06-2025.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

View File

@@ -0,0 +1,51 @@
<!-- /docs/components/main/analogInputs/AnalogInputsChart.md -->
# 📈 AnalogInputsChart
Die Komponente `AnalogInputsChart` zeigt den Verlauf der Messwerte für einen ausgewählten analogen Eingang an. Sie nutzt `react-chartjs-2` mit `chart.js` (inkl. TimeScale).
---
## ⚙️ Funktion
- Ruft über `Redux Thunk` die Historie der analogen Eingänge ab
- Zeigt eine Liniendiagramm-Kurve mit Zeit auf der X-Achse und Messwerten auf der Y-Achse
- Berücksichtigt die Auswahl des Messwerteingangs (`selectedId`)
---
## 🧩 Feature-Flag: Zoom & Pan
Der Zoom- und Pan-Modus (interaktives Scrollen/Ziehen im Chart) wird über ein Feature-Flag gesteuert:
```env
NEXT_PUBLIC_FEATURE_MESSWERTANZEIGE_EINGANG=true
```
### Verhalten:
- Wenn `true`: Nutzer kann in das Zeitfenster hineinzoomen und sich bewegen (pan).
- Wenn `false`: Chart ist statisch und nur lesbar.
### Technisch:
- `chartjs-plugin-zoom` wird **dynamisch nur im Browser** geladen
- Die Optionen für `zoom` und `pan` werden nur gesetzt, wenn das Flag aktiv ist
---
## 📦 Technologien
- `react-chartjs-2`
- `chart.js` mit `TimeScale`
- `chartjs-plugin-zoom` (lazy import)
- `redux` & `thunks` für Daten
- `date-fns` mit deutscher Lokalisierung
---
## 🔍 Hinweise
- Der Messwert-Key wird berechnet als `selectedId + 99`, da Backend-Daten mit Key `99`, `100`, usw. zurückkommen.
- Wenn keine Daten vorhanden sind, wird ein entsprechender Hinweis angezeigt.
- Farbschema nutzt `getColor("littwin-blue")` aus den Projektfarben.

View File

@@ -0,0 +1,70 @@
<!-- /docs/components/main/analogInputs/AnalogInputsSettingsModal.md -->
# ⚙️ AnalogInputsSettingsModal
Diese Komponente zeigt ein zentriertes Modal zur Konfiguration eines analogen Eingangs.
---
## 🧩 Funktion
- Wird angezeigt, wenn `isOpen` true ist und ein `selectedInput` gesetzt ist.
- Zeigt alle relevanten Felder zur Konfiguration:
- **Bezeichnung**
- **Offset** (z.B. für Kalibrierung)
- **Faktor** (Multiplikator)
- **Einheit** (Dropdown: V, mA, °C, bar, %)
- **Loggerintervall** (in Minuten)
---
## ✏️ Verwendung
```tsx
<AnalogInputSettingsModal
selectedInput={input}
isOpen={modalOpen}
onClose={() => setModalOpen(false)}
/>
```
---
## 💾 Speichern-Logik
Beim Klick auf „Speichern“ werden die Einstellungen auf zwei verschiedene Arten verarbeitet:
### 🔧 Entwicklungsmodus (`localhost`):
- Daten werden per POST an die lokale API gesendet:
`/api/cpl/updateAnalogInputsSettingsHandler`
- Die Datenstruktur orientiert sich an `window.win_analogInputs*` Variablen
### 🚀 Produktionsmodus:
- Daten werden über einen GET-Request mit URL-Parametern an ein CGI-Backend übermittelt:
`/CPL?/Service/ae.ACP&ACN{slot}=...&ACO{slot}=...`
---
## 🧪 Besonderheiten
- Werte wie `offset` und `factor` werden als String mit `,` oder `.` akzeptiert und korrekt konvertiert.
- Eingabefelder sind per `useState` gebunden.
- Ein `console.log` zeigt `loggerInterval`, wenn `selectedInput` geladen wird.
- Nach erfolgreichem Speichern wird die Seite neu geladen (`location.reload()`), um aktuelle Werte anzuzeigen.
---
## 🛑 Validierung
- Aktuell keine Validierung gegen ungültige Werte (z.B. negatives Intervall oder leere Felder).
- Sollte ggf. ergänzt werden, wenn das Backend empfindlich auf falsche Werte reagiert.
---
## 🖼️ UI/UX
- Modal ist zentriert mit dunklem Overlay.
- Abbrechen über „X“-Button oben rechts.
- Tailwind CSS für Layout und Styling verwendet.

View File

@@ -0,0 +1,52 @@
<!-- /docs/components/main/analogInputs/AnalogInputsTable.md -->
# 🧮 AnalogInputsTable
Die Komponente `AnalogInputsTable` zeigt eine Tabelle mit allen verfügbaren analogen Eingängen an, einschließlich Messwert, Einheit und Bezeichnung.
---
## ⚙️ Funktion
- Ruft beim Laden die Liste der analogen Eingänge aus dem Redux-Store über `getAnalogInputsThunk()` ab.
- Zeigt alle Eingänge in einer Tabelle mit folgenden Spalten:
- Eingang (ID)
- Messwert
- Einheit
- Bezeichnung
- Aktion (Zahnrad-Icon zur Konfiguration)
---
## 🔄 Interaktion
- Beim Klick auf eine Tabellenzeile:
- Wird der Eingang als aktiv markiert (`activeId`)
- `setSelectedId` wird gesetzt → z.B. für Diagrammanzeige
- Beim Klick auf das ⚙️-Icon:
- `setSelectedInput` wird mit dem aktuellen Objekt befüllt
- Das Einstellungs-Modal (`AnalogInputsSettingsModal`) wird geöffnet
---
## 📦 Technologien
- `react-redux` für Zustand und Datenabruf
- `@iconify/react` für Icons (z.B. `mdi/waveform`, `mdi/settings`)
- Tailwind CSS für Styling und Layout
- Typ `AnalogInput` zur Definition der Eingangsdatenstruktur
---
## 🧪 Besonderheiten
- `unit` ist optional wird als `"-"` angezeigt, wenn nicht vorhanden
- Die Auswahlfarbe der Zeile (hellblau) zeigt den aktiven Eingang an
- Mobilfreundlich durch `overflow-x-auto` und responsives Tailwind-Layout
---
## 🔍 Hinweise
- Die `label`-, `value`- und `unit`-Werte stammen direkt aus dem Redux-State `analogInputs`
- Eingänge ohne `id` oder `label` werden gefiltert

View File

@@ -0,0 +1,60 @@
<!-- /docs/components/main/analogInputs/README.md -->
# 📂 Komponentenübersicht: Analoge Eingänge
Dieses Verzeichnis enthält alle React-Komponenten zur Visualisierung und Konfiguration der analogen Eingänge im System.
---
## 📋 Übersicht der Komponenten
### 1. [`AnalogInputsTable`](./AnalogInputsTable.md)
Zeigt eine tabellarische Übersicht aller analogen Eingänge mit Messwert, Einheit und Bezeichnung.
- Auswahl eines Eingangs durch Klick
- Öffnet Einstellungen per Zahnrad-Icon
- Nutzt Redux für Datenabruf
➡️ Dokumentation: [AnalogInputsTable.md](./AnalogInputsTable.md)
---
### 2. [`AnalogInputsChart`](./AnalogInputsChart.md)
Zeigt den zeitlichen Verlauf eines Messwerteingangs im Liniendiagramm.
- Zoom & Pan steuerbar über Feature-Flag `NEXT_PUBLIC_FEATURE_MESSWERTANZEIGE_EINGANG`
- Chart.js mit Zeitachse (TimeScale)
- Daten aus Redux-State
➡️ Dokumentation: [AnalogInputsChart.md](./AnalogInputsChart.md)
---
### 3. [`AnalogInputsSettingsModal`](./AnalogInputsSettingsModal.md)
Modal zur Bearbeitung eines analogen Eingangs (Label, Offset, Faktor, Einheit, Speicherintervall).
- Werte werden lokal oder über API/CGI gespeichert
- Dynamische Anzeige der aktuellen Einstellungen
- Eingaben mit `useState` gebunden
➡️ Dokumentation: [AnalogInputsSettingsModal.md](./AnalogInputsSettingsModal.md)
---
## 🧩 Technologien
- React & Redux
- Chart.js / react-chartjs-2
- Tailwind CSS
- Iconify
- API-Anbindung & lokale Mockdaten
---
## 🗂️ Speicherort
Pfad: `/components/main/analogInputs/`
Dokumentation: `/docs/components/main/analogInputs/`

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "cpl-v4", "name": "cpl-v4",
"version": "1.6.445", "version": "1.6.446",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cpl-v4", "name": "cpl-v4",
"version": "1.6.445", "version": "1.6.446",
"dependencies": { "dependencies": {
"@fontsource/roboto": "^5.1.0", "@fontsource/roboto": "^5.1.0",
"@iconify-icons/ri": "^1.2.10", "@iconify-icons/ri": "^1.2.10",

View File

@@ -1,6 +1,6 @@
{ {
"name": "cpl-v4", "name": "cpl-v4",
"version": "1.6.445", "version": "1.6.446",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",