feat: Digitale Ausgänge aus Redux-Store in UI integriert
- 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
This commit is contained in:
@@ -1,13 +1,26 @@
|
|||||||
"use client"; // components/main/einausgaenge/DigitalOutputs.tsx
|
"use client";
|
||||||
|
|
||||||
import React from "react";
|
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";
|
import { Icon } from "@iconify/react";
|
||||||
|
|
||||||
export default function DigitalOutputs({
|
export default function DigitalOutputs({ openOutputModal }) {
|
||||||
digitalOutputs,
|
const dispatch = useDispatch();
|
||||||
openOutputModal,
|
|
||||||
toggleSwitch,
|
// 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 (
|
return (
|
||||||
<div className="bg-white shadow-md rounded-lg border border-gray-200 p-4 w-2/5 h-[fit-content]">
|
<div className="bg-white shadow-md rounded-lg border border-gray-200 p-4 w-2/5 h-[fit-content]">
|
||||||
<h2 className="text-md font-bold mb-4 flex items-center">
|
<h2 className="text-md font-bold mb-4 flex items-center">
|
||||||
@@ -33,16 +46,16 @@ export default function DigitalOutputs({
|
|||||||
/>
|
/>
|
||||||
{output.id}
|
{output.id}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-2 py-1">{output.description}</td>
|
<td className="px-2 py-1">{output.label}</td>
|
||||||
<td className="px-2 py-1">
|
<td className="px-2 py-1">
|
||||||
<span
|
<span
|
||||||
title={`Schalter ${output.toggle ? "EIN" : "AUS"} schalten`}
|
title={`Schalter ${output.status ? "EIN" : "AUS"} schalten`}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon="ion:switch"
|
icon="ion:switch"
|
||||||
onClick={() => toggleSwitch(output.id)}
|
onClick={() => toggleSwitch(output.id)}
|
||||||
className={`cursor-pointer text-2xl transform ${
|
className={`cursor-pointer text-2xl transform ${
|
||||||
output.toggle
|
output.status
|
||||||
? "text-blue-500 scale-x-100"
|
? "text-blue-500 scale-x-100"
|
||||||
: "text-gray-500 scale-x-[-1]"
|
: "text-gray-500 scale-x-[-1]"
|
||||||
}`}
|
}`}
|
||||||
|
|||||||
@@ -6,5 +6,5 @@
|
|||||||
2: Patch oder Hotfix (Bugfixes oder kleine Änderungen).
|
2: Patch oder Hotfix (Bugfixes oder kleine Änderungen).
|
||||||
|
|
||||||
*/
|
*/
|
||||||
const webVersion = "1.6.94";
|
const webVersion = "1.6.95";
|
||||||
export default webVersion;
|
export default webVersion;
|
||||||
|
|||||||
@@ -1,42 +1,63 @@
|
|||||||
"use client"; // /hooks/einausgaenge/useDigitalOutputsData.ts
|
"use client";
|
||||||
import { useState, useEffect } from "react";
|
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 {
|
interface DigitalOutput {
|
||||||
id: number;
|
id: number;
|
||||||
description: string;
|
label: string;
|
||||||
toggle: boolean;
|
status: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useDigitalOutputs() {
|
export function useDigitalOutputs() {
|
||||||
const [digitalOutputs, setDigitalOutputs] = useState<DigitalOutput[]>([]);
|
const dispatch = useDispatch();
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const digitalOutputs = useSelector(
|
||||||
|
(state: RootState) => state.digitalOutputs?.outputs ?? []
|
||||||
|
);
|
||||||
|
const isLoading = digitalOutputs.length === 0;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log("Lade da.js für digitale Ausgänge...");
|
||||||
|
|
||||||
const script = document.createElement("script");
|
const script = document.createElement("script");
|
||||||
script.src = "/CPLmockData/SERVICE/da.js";
|
script.src = "/CPLmockData/SERVICE/da.js";
|
||||||
script.async = true;
|
script.async = true;
|
||||||
|
|
||||||
script.onload = () => {
|
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 da = window.win_da_state;
|
||||||
const bezeichnungen = window.win_da_bezeichnung;
|
const bezeichnungen = window.win_da_bezeichnung;
|
||||||
|
|
||||||
if (da && bezeichnungen) {
|
if (
|
||||||
const outputs = da.map((status: number, index: number) => ({
|
Array.isArray(da) &&
|
||||||
id: index + 1,
|
Array.isArray(bezeichnungen) &&
|
||||||
description: bezeichnungen[index] || `Ausgang${index + 1}`,
|
da.length === bezeichnungen.length
|
||||||
toggle: status === 1,
|
) {
|
||||||
}));
|
const outputs: DigitalOutput[] = da.map(
|
||||||
setDigitalOutputs(outputs);
|
(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 {
|
} 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 = () => {
|
script.onerror = () => {
|
||||||
console.error("Fehler beim Laden der da.js-Datei.");
|
console.error("Fehler beim Laden der da.js-Datei.");
|
||||||
setIsLoading(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
document.body.appendChild(script);
|
document.body.appendChild(script);
|
||||||
@@ -44,7 +65,7 @@ export function useDigitalOutputs() {
|
|||||||
return () => {
|
return () => {
|
||||||
document.body.removeChild(script);
|
document.body.removeChild(script);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [dispatch]);
|
||||||
|
|
||||||
return { digitalOutputs, isLoading, setDigitalOutputs };
|
return { digitalOutputs, isLoading };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
// hooks/windowvariables/useLoadWindowVariables.ts
|
// hooks/windowvariables/useLoadWindowVariables.ts
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
import { setDigitalOutputs } from "../../redux/slices/digitalOutputsSlice";
|
||||||
|
|
||||||
const requiredVars: string[] = [
|
const requiredVars: string[] = ["win_da_state", "win_da_bezeichnung"];
|
||||||
// Hier verbleiben nur die noch benötigten Variablen
|
|
||||||
];
|
|
||||||
|
|
||||||
const scripts: string[] = [
|
const scripts: string[] = [
|
||||||
"da.js",
|
"da.js",
|
||||||
@@ -37,24 +36,29 @@ export const useLoadWindowVariables = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadVariables = async () => {
|
const loadVariables = async () => {
|
||||||
try {
|
try {
|
||||||
|
await loadScript("da.js"); // Lade `da.js` zuerst
|
||||||
for (const script of scripts) {
|
for (const script of scripts) {
|
||||||
await loadScript(script);
|
if (script !== "da.js") await loadScript(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
const variablesObj: { [key: string]: any } = requiredVars.reduce(
|
console.log("Laden abgeschlossen. Jetzt werden Variablen geprüft.");
|
||||||
(acc, variable) => {
|
console.log("win_da_state:", window.win_da_state);
|
||||||
const winVar = (window as any)[variable];
|
console.log("win_da_bezeichnung:", window.win_da_bezeichnung);
|
||||||
if (winVar !== undefined) {
|
|
||||||
acc[variable.replace("win_", "")] = winVar;
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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) {
|
} catch (error) {
|
||||||
console.error("Fehler beim Laden der Skripte oder Variablen:", error);
|
console.error("Fehler beim Laden der Skripte:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ function MyApp({ Component, pageProps }: AppProps) {
|
|||||||
de,
|
de,
|
||||||
de_label,
|
de_label,
|
||||||
de_state,
|
de_state,
|
||||||
|
da_state,
|
||||||
|
da_bezeichnung,
|
||||||
...restVariables
|
...restVariables
|
||||||
} = variables;
|
} = variables;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"use client"; // pages/einausgaenge.tsx
|
"use client"; // pages/einausgaenge.tsx
|
||||||
|
|
||||||
|
"use client";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import DigitalOutputs from "../components/main/einausgaenge/DigitalOutputs";
|
import DigitalOutputs from "../components/main/einausgaenge/DigitalOutputs";
|
||||||
import DigitalInputs from "../components/main/einausgaenge/DigitalInputs";
|
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 OutputModal from "../components/main/einausgaenge/modals/OutputModal";
|
||||||
import { useDigitalInputData } from "../hooks/einausgaenge/useDigitalInputsData";
|
import { useDigitalInputData } from "../hooks/einausgaenge/useDigitalInputsData";
|
||||||
import { useDigitalOutputs } from "../hooks/einausgaenge/useDigitalOutputsData";
|
import { useDigitalOutputs } from "../hooks/einausgaenge/useDigitalOutputsData";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { setDigitalOutputs } from "../redux/slices/digitalOutputsSlice";
|
||||||
|
|
||||||
function EinAusgaenge() {
|
function EinAusgaenge() {
|
||||||
// Verwendung des benutzerdefinierten Hooks für digitale Ausgänge
|
const dispatch = useDispatch();
|
||||||
const {
|
const { digitalOutputs, isLoading: isLoadingOutputs } = useDigitalOutputs();
|
||||||
digitalOutputs,
|
const { mockData, isLoading: isLoadingInputs } = useDigitalInputData();
|
||||||
isLoading: isLoadingOutputs,
|
|
||||||
setDigitalOutputs,
|
|
||||||
} = useDigitalOutputs();
|
|
||||||
|
|
||||||
// Zustand für Modale
|
// Zustand für Modale
|
||||||
const [selectedInput, setSelectedInput] = useState(null);
|
const [selectedInput, setSelectedInput] = useState(null);
|
||||||
@@ -22,16 +22,12 @@ function EinAusgaenge() {
|
|||||||
const [isInputModalOpen, setIsInputModalOpen] = useState(false);
|
const [isInputModalOpen, setIsInputModalOpen] = useState(false);
|
||||||
const [isOutputModalOpen, setIsOutputModalOpen] = useState(false);
|
const [isOutputModalOpen, setIsOutputModalOpen] = useState(false);
|
||||||
|
|
||||||
// Laden der digitalen Eingänge
|
|
||||||
const { mockData, isLoading: isLoadingInputs } = useDigitalInputData();
|
|
||||||
|
|
||||||
// Funktion zum Umschalten des Ausgangs
|
// Funktion zum Umschalten des Ausgangs
|
||||||
const toggleSwitch = (id: number) => {
|
const toggleSwitch = (id: number) => {
|
||||||
setDigitalOutputs((prevOutputs) =>
|
const updatedOutputs = digitalOutputs.map((output) =>
|
||||||
prevOutputs.map((output) =>
|
output.id === id ? { ...output, status: !output.status } : output
|
||||||
output.id === id ? { ...output, toggle: !output.toggle } : output
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
dispatch(setDigitalOutputs(updatedOutputs));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Funktionen zum Öffnen und Schließen der Modale
|
// Funktionen zum Öffnen und Schließen der Modale
|
||||||
|
|||||||
35
redux/slices/digitalOutputsSlice.ts
Normal file
35
redux/slices/digitalOutputsSlice.ts
Normal file
@@ -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<DigitalOutput[]>) {
|
||||||
|
state.outputs = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Aktionen exportieren
|
||||||
|
export const { setDigitalOutputs } = digitalOutputsSlice.actions;
|
||||||
|
|
||||||
|
// Reducer exportieren
|
||||||
|
export default digitalOutputsSlice.reducer;
|
||||||
@@ -9,6 +9,7 @@ import kabelueberwachungChartReducer from "./slices/kabelueberwachungChartSlice"
|
|||||||
import dashboardReducer from "./slices/dashboardSlice";
|
import dashboardReducer from "./slices/dashboardSlice";
|
||||||
import systemSettingsReducer from "./slices/systemSettingsSlice";
|
import systemSettingsReducer from "./slices/systemSettingsSlice";
|
||||||
import opcuaSettingsReducer from "./slices/opcuaSettingsSlice";
|
import opcuaSettingsReducer from "./slices/opcuaSettingsSlice";
|
||||||
|
import digitalOutputsReducer from "./slices/digitalOutputsSlice";
|
||||||
|
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
@@ -21,6 +22,7 @@ const store = configureStore({
|
|||||||
dashboard: dashboardReducer,
|
dashboard: dashboardReducer,
|
||||||
systemSettings: systemSettingsReducer,
|
systemSettings: systemSettingsReducer,
|
||||||
opcuaSettings: opcuaSettingsReducer,
|
opcuaSettings: opcuaSettingsReducer,
|
||||||
|
digitalOutputs: digitalOutputsReducer,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
addOpcUaUser,
|
addOpcUaUser,
|
||||||
removeOpcUaUser,
|
removeOpcUaUser,
|
||||||
} from "../redux/slices/opcuaSettingsSlice";
|
} from "../redux/slices/opcuaSettingsSlice";
|
||||||
|
import { setDigitalOutputs } from "../redux/slices/digitalOutputsSlice";
|
||||||
|
|
||||||
// ✅ Interface für `window`-Objekt zur TypeScript-Sicherheit
|
// ✅ Interface für `window`-Objekt zur TypeScript-Sicherheit
|
||||||
interface CustomWindow extends Window {
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user