From 65cfb033a50c7ddd9c71d2326938bc923a647643 Mon Sep 17 00:00:00 2001 From: Ismail Ali Date: Sun, 23 Feb 2025 22:31:06 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20Digitale=20Ausg=C3=A4nge=20aus=20Redux-?= =?UTF-8?q?Store=20in=20UI=20integriert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DigitalOutputs.tsx auf Redux umgestellt, um Werte direkt aus dem Store zu lesen - toggleSwitch-Funktion angepasst, um den Status von digitalen Ausgängen in Redux zu aktualisieren - useDigitalOutputsData.ts nutzt nun Redux zum Speichern der `win_da_state` und `win_da_bezeichnung` Werte - Entfernen von Prop `digitalOutputs` in `DigitalOutputs.tsx`, da Redux nun als Datenquelle dient - Weboberfläche zeigt nun digitale Ausgänge korrekt an und Status kann geändert werden --- .../main/einausgaenge/DigitalOutputs.tsx | 33 +++++++---- config/webVersion.ts | 2 +- hooks/einausgaenge/useDigitalOutputsData.ts | 59 +++++++++++++------ .../windowVariables/useLoadWindowVariables.ts | 36 ++++++----- pages/_app.tsx | 2 + pages/einausgaenge.tsx | 22 +++---- redux/slices/digitalOutputsSlice.ts | 35 +++++++++++ redux/store.ts | 2 + utils/loadWindowVariables.ts | 30 ++++++++++ 9 files changed, 162 insertions(+), 59 deletions(-) create mode 100644 redux/slices/digitalOutputsSlice.ts diff --git a/components/main/einausgaenge/DigitalOutputs.tsx b/components/main/einausgaenge/DigitalOutputs.tsx index 69050b1..d49fdb9 100644 --- a/components/main/einausgaenge/DigitalOutputs.tsx +++ b/components/main/einausgaenge/DigitalOutputs.tsx @@ -1,13 +1,26 @@ -"use client"; // components/main/einausgaenge/DigitalOutputs.tsx - +"use client"; import React from "react"; +import { useSelector, useDispatch } from "react-redux"; +import { RootState } from "../../../redux/store"; +import { setDigitalOutputs } from "../../../redux/slices/digitalOutputsSlice"; import { Icon } from "@iconify/react"; -export default function DigitalOutputs({ - digitalOutputs, - openOutputModal, - toggleSwitch, -}) { +export default function DigitalOutputs({ openOutputModal }) { + const dispatch = useDispatch(); + + // Redux-Store für digitale Ausgänge nutzen + const digitalOutputs = useSelector( + (state: RootState) => state.digitalOutputs?.outputs ?? [] + ); + + // Funktion zum Umschalten des Ausgangsstatus + const toggleSwitch = (id: number) => { + const updatedOutputs = digitalOutputs.map((output) => + output.id === id ? { ...output, status: !output.status } : output + ); + dispatch(setDigitalOutputs(updatedOutputs)); + }; + return (

@@ -33,16 +46,16 @@ export default function DigitalOutputs({ /> {output.id} - {output.description} + {output.label} toggleSwitch(output.id)} className={`cursor-pointer text-2xl transform ${ - output.toggle + output.status ? "text-blue-500 scale-x-100" : "text-gray-500 scale-x-[-1]" }`} diff --git a/config/webVersion.ts b/config/webVersion.ts index 7e37877..218588b 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.94"; +const webVersion = "1.6.95"; export default webVersion; diff --git a/hooks/einausgaenge/useDigitalOutputsData.ts b/hooks/einausgaenge/useDigitalOutputsData.ts index 82a5f21..4bdab86 100644 --- a/hooks/einausgaenge/useDigitalOutputsData.ts +++ b/hooks/einausgaenge/useDigitalOutputsData.ts @@ -1,42 +1,63 @@ -"use client"; // /hooks/einausgaenge/useDigitalOutputsData.ts -import { useState, useEffect } from "react"; +"use client"; +import { useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "../../redux/store"; +import { setDigitalOutputs } from "../../redux/slices/digitalOutputsSlice"; -// Definition des Typs für digitale Ausgänge +// Typ für digitale Ausgänge interface DigitalOutput { id: number; - description: string; - toggle: boolean; + label: string; + status: boolean; } export function useDigitalOutputs() { - const [digitalOutputs, setDigitalOutputs] = useState([]); - const [isLoading, setIsLoading] = useState(true); + const dispatch = useDispatch(); + const digitalOutputs = useSelector( + (state: RootState) => state.digitalOutputs?.outputs ?? [] + ); + const isLoading = digitalOutputs.length === 0; useEffect(() => { + console.log("Lade da.js für digitale Ausgänge..."); + const script = document.createElement("script"); script.src = "/CPLmockData/SERVICE/da.js"; script.async = true; script.onload = () => { + console.log("Skript geladen. Überprüfe window-Variablen:"); + console.log("win_da_state:", window.win_da_state); + console.log("win_da_bezeichnung:", window.win_da_bezeichnung); + const da = window.win_da_state; const bezeichnungen = window.win_da_bezeichnung; - if (da && bezeichnungen) { - const outputs = da.map((status: number, index: number) => ({ - id: index + 1, - description: bezeichnungen[index] || `Ausgang${index + 1}`, - toggle: status === 1, - })); - setDigitalOutputs(outputs); + if ( + Array.isArray(da) && + Array.isArray(bezeichnungen) && + da.length === bezeichnungen.length + ) { + const outputs: DigitalOutput[] = da.map( + (status: number, index: number) => ({ + id: index + 1, + label: bezeichnungen[index] || `Ausgang ${index + 1}`, + status: status === 1, + }) + ); + + console.log("Dispatching setDigitalOutputs mit Werten:", outputs); + dispatch(setDigitalOutputs(outputs)); } else { - console.error("Daten konnten nicht geladen werden."); + console.error("Digitale Ausgänge konnten nicht geladen werden.", { + da_state: da, + da_bezeichnung: bezeichnungen, + }); } - setIsLoading(false); }; script.onerror = () => { console.error("Fehler beim Laden der da.js-Datei."); - setIsLoading(false); }; document.body.appendChild(script); @@ -44,7 +65,7 @@ export function useDigitalOutputs() { return () => { document.body.removeChild(script); }; - }, []); + }, [dispatch]); - return { digitalOutputs, isLoading, setDigitalOutputs }; + return { digitalOutputs, isLoading }; } diff --git a/hooks/windowVariables/useLoadWindowVariables.ts b/hooks/windowVariables/useLoadWindowVariables.ts index 2e25af3..f03b3f1 100644 --- a/hooks/windowVariables/useLoadWindowVariables.ts +++ b/hooks/windowVariables/useLoadWindowVariables.ts @@ -1,10 +1,9 @@ // hooks/windowvariables/useLoadWindowVariables.ts import { useEffect } from "react"; import { useDispatch } from "react-redux"; +import { setDigitalOutputs } from "../../redux/slices/digitalOutputsSlice"; -const requiredVars: string[] = [ - // Hier verbleiben nur die noch benötigten Variablen -]; +const requiredVars: string[] = ["win_da_state", "win_da_bezeichnung"]; const scripts: string[] = [ "da.js", @@ -37,24 +36,29 @@ export const useLoadWindowVariables = () => { useEffect(() => { const loadVariables = async () => { try { + await loadScript("da.js"); // Lade `da.js` zuerst for (const script of scripts) { - await loadScript(script); + if (script !== "da.js") await loadScript(script); } - const variablesObj: { [key: string]: any } = requiredVars.reduce( - (acc, variable) => { - const winVar = (window as any)[variable]; - if (winVar !== undefined) { - acc[variable.replace("win_", "")] = winVar; - } - return acc; - }, - {} - ); + console.log("Laden abgeschlossen. Jetzt werden Variablen geprüft."); + console.log("win_da_state:", window.win_da_state); + console.log("win_da_bezeichnung:", window.win_da_bezeichnung); - // Falls noch andere Variablen verarbeitet werden müssen, kann hier Code eingefügt werden + if (window.win_da_state && window.win_da_bezeichnung) { + const digitalOutputs = window.win_da_state.map( + (status: number, index: number) => ({ + id: index + 1, + label: window.win_da_bezeichnung[index] || `Ausgang ${index + 1}`, + status: status === 1, + }) + ); + + console.log("Dispatching digitalOutputs:", digitalOutputs); + dispatch(setDigitalOutputs(digitalOutputs)); + } } catch (error) { - console.error("Fehler beim Laden der Skripte oder Variablen:", error); + console.error("Fehler beim Laden der Skripte:", error); } }; diff --git a/pages/_app.tsx b/pages/_app.tsx index 0a34ace..276ada5 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -47,6 +47,8 @@ function MyApp({ Component, pageProps }: AppProps) { de, de_label, de_state, + da_state, + da_bezeichnung, ...restVariables } = variables; diff --git a/pages/einausgaenge.tsx b/pages/einausgaenge.tsx index 3e2c977..f5f5997 100644 --- a/pages/einausgaenge.tsx +++ b/pages/einausgaenge.tsx @@ -1,5 +1,6 @@ "use client"; // pages/einausgaenge.tsx +"use client"; import React, { useState } from "react"; import DigitalOutputs from "../components/main/einausgaenge/DigitalOutputs"; import DigitalInputs from "../components/main/einausgaenge/DigitalInputs"; @@ -7,14 +8,13 @@ import InputModal from "../components/main/einausgaenge/modals/InputModal"; import OutputModal from "../components/main/einausgaenge/modals/OutputModal"; import { useDigitalInputData } from "../hooks/einausgaenge/useDigitalInputsData"; import { useDigitalOutputs } from "../hooks/einausgaenge/useDigitalOutputsData"; +import { useDispatch } from "react-redux"; +import { setDigitalOutputs } from "../redux/slices/digitalOutputsSlice"; function EinAusgaenge() { - // Verwendung des benutzerdefinierten Hooks für digitale Ausgänge - const { - digitalOutputs, - isLoading: isLoadingOutputs, - setDigitalOutputs, - } = useDigitalOutputs(); + const dispatch = useDispatch(); + const { digitalOutputs, isLoading: isLoadingOutputs } = useDigitalOutputs(); + const { mockData, isLoading: isLoadingInputs } = useDigitalInputData(); // Zustand für Modale const [selectedInput, setSelectedInput] = useState(null); @@ -22,16 +22,12 @@ function EinAusgaenge() { const [isInputModalOpen, setIsInputModalOpen] = useState(false); const [isOutputModalOpen, setIsOutputModalOpen] = useState(false); - // Laden der digitalen Eingänge - const { mockData, isLoading: isLoadingInputs } = useDigitalInputData(); - // Funktion zum Umschalten des Ausgangs const toggleSwitch = (id: number) => { - setDigitalOutputs((prevOutputs) => - prevOutputs.map((output) => - output.id === id ? { ...output, toggle: !output.toggle } : output - ) + const updatedOutputs = digitalOutputs.map((output) => + output.id === id ? { ...output, status: !output.status } : output ); + dispatch(setDigitalOutputs(updatedOutputs)); }; // Funktionen zum Öffnen und Schließen der Modale diff --git a/redux/slices/digitalOutputsSlice.ts b/redux/slices/digitalOutputsSlice.ts new file mode 100644 index 0000000..4a97e02 --- /dev/null +++ b/redux/slices/digitalOutputsSlice.ts @@ -0,0 +1,35 @@ +// redux/slices/digitalOutputsSlice.ts +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +// Typ für den Zustand der digitalen Ausgänge +interface DigitalOutput { + id: number; + label: string; + status: boolean; +} + +interface DigitalOutputsState { + outputs: DigitalOutput[]; +} + +// Initialer Zustand +const initialState: DigitalOutputsState = { + outputs: [], +}; + +// Slice erstellen +const digitalOutputsSlice = createSlice({ + name: "digitalOutputs", + initialState, + reducers: { + setDigitalOutputs(state, action: PayloadAction) { + state.outputs = action.payload; + }, + }, +}); + +// Aktionen exportieren +export const { setDigitalOutputs } = digitalOutputsSlice.actions; + +// Reducer exportieren +export default digitalOutputsSlice.reducer; diff --git a/redux/store.ts b/redux/store.ts index 2d278b6..eb04342 100644 --- a/redux/store.ts +++ b/redux/store.ts @@ -9,6 +9,7 @@ import kabelueberwachungChartReducer from "./slices/kabelueberwachungChartSlice" import dashboardReducer from "./slices/dashboardSlice"; import systemSettingsReducer from "./slices/systemSettingsSlice"; import opcuaSettingsReducer from "./slices/opcuaSettingsSlice"; +import digitalOutputsReducer from "./slices/digitalOutputsSlice"; const store = configureStore({ reducer: { @@ -21,6 +22,7 @@ const store = configureStore({ dashboard: dashboardReducer, systemSettings: systemSettingsReducer, opcuaSettings: opcuaSettingsReducer, + digitalOutputs: digitalOutputsReducer, }, }); diff --git a/utils/loadWindowVariables.ts b/utils/loadWindowVariables.ts index cedcb12..a1756d5 100644 --- a/utils/loadWindowVariables.ts +++ b/utils/loadWindowVariables.ts @@ -10,6 +10,7 @@ import { addOpcUaUser, removeOpcUaUser, } from "../redux/slices/opcuaSettingsSlice"; +import { setDigitalOutputs } from "../redux/slices/digitalOutputsSlice"; // ✅ Interface für `window`-Objekt zur TypeScript-Sicherheit interface CustomWindow extends Window { @@ -234,3 +235,32 @@ const loadAndStoreOpcUaSettings = (win: CustomWindow) => { }); } }; + +// ✅ Funktion zum Speichern der digitalen Ausgänge in Redux +const loadAndStoreDigitalOutputs = (win: CustomWindow) => { + console.log("Prüfe digitale Ausgänge in window:"); + console.log("win_da_state:", win.win_da_state); + console.log("win_da_bezeichnung:", win.win_da_bezeichnung); + + if ( + Array.isArray(win.win_da_state) && + Array.isArray(win.win_da_bezeichnung) && + win.win_da_state.length === win.win_da_bezeichnung.length + ) { + const digitalOutputs = win.win_da_state.map( + (status: number, index: number) => ({ + id: index + 1, + label: win.win_da_bezeichnung[index] || `Ausgang ${index + 1}`, + status: status === 1, // Status in Boolean umwandeln + }) + ); + + console.log("Dispatching digitalOutputs:", digitalOutputs); + store.dispatch(setDigitalOutputs(digitalOutputs)); + } else { + console.warn("Digitale Ausgänge konnten nicht geladen werden:", { + da_state: win.win_da_state, + da_bezeichnung: win.win_da_bezeichnung, + }); + } +};