fix: digital Inputs Modal

This commit is contained in:
ISA
2025-06-20 10:53:22 +02:00
parent 3cadee04a8
commit b233694fed
11 changed files with 616 additions and 144 deletions

View File

@@ -6,5 +6,5 @@ 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.427 NEXT_PUBLIC_APP_VERSION=1.6.428
NEXT_PUBLIC_CPL_MODE=jsmock # json (Entwicklungsumgebung) oder jsmock (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) NEXT_PUBLIC_CPL_MODE=jsmock # json (Entwicklungsumgebung) oder jsmock (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter)

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.427 NEXT_PUBLIC_APP_VERSION=1.6.428
NEXT_PUBLIC_CPL_MODE=production NEXT_PUBLIC_CPL_MODE=production

View File

@@ -2,39 +2,51 @@
// /components/main/einausgaenge/modals/InputModal.tsx // /components/main/einausgaenge/modals/InputModal.tsx
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux"; import { useSelector, useDispatch } from "react-redux";
import { RootState } from "../../../../redux/store"; import { RootState } from "@/redux/store";
import switchIcon from "@iconify/icons-ion/switch"; import switchIcon from "@iconify/icons-ion/switch";
import { import { updateInvert, updateLabel } from "@/redux/slices/digitalInputsSlice";
updateInvertierung,
updateName,
} from "../../../../redux/slices/digitalInputsSlice";
export default function InputModal({ selectedInput, closeInputModal, isOpen }) { type InputModalProps = {
selectedInput: {
id: number;
[key: string]: any;
} | null;
closeInputModal: () => void;
isOpen: boolean;
};
export default function InputModal({
selectedInput,
closeInputModal,
isOpen,
}: InputModalProps) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const reduxInput = useSelector((state: RootState) => const reduxInput = useSelector((state: RootState) =>
state.digitalInputsSlice.inputs.find( state.digitalInputsSlice.inputs.find(
(input) => input.id === Number(selectedInput?.id) (input) => input.id === Number(selectedInput?.id)
) )
); );
console.log("📦 selectedInput.id:", selectedInput?.id); /* console.log("📦 selectedInput.id:", selectedInput?.id);
console.log("📦 reduxInput:", reduxInput); console.log("📦 reduxInput:", reduxInput); */
const [isInitialLoad, setIsInitialLoad] = useState(true); const [isInitialLoad, setIsInitialLoad] = useState(true);
const [name, setName] = useState(""); const [label, setLabel] = useState("");
const [invertiert, setInvertiert] = useState(false); const [invertiert, setInvertiert] = useState(false);
const [filterzeit, setFilterzeit] = useState(0); const [timeFilter, setTimeFilter] = useState(0);
const [gewichtung, setGewichtung] = useState(0); const [weighting, setWeighting] = useState(0);
const [zaehlerAktiv, setZaehlerAktiv] = useState(false); const [zaehlerAktiv, setZaehlerAktiv] = useState(false);
const [eingangOffline, setEingangOffline] = useState(false); const [eingangOffline, setEingangOffline] = useState(0);
useEffect(() => { useEffect(() => {
if (reduxInput && isInitialLoad) { if (reduxInput && isInitialLoad) {
setName(reduxInput.label || ""); //reduxInput
setInvertiert(reduxInput.invertierung); console.log("📦 reduxInput geladen:", reduxInput);
setFilterzeit(reduxInput.filterzeit); setLabel(reduxInput.label || "");
setGewichtung(reduxInput.gewichtung); setInvertiert(reduxInput.invert);
setTimeFilter(reduxInput.timeFilter);
setWeighting(reduxInput.weighting);
setZaehlerAktiv(reduxInput.zaehlerAktiv); setZaehlerAktiv(reduxInput.zaehlerAktiv);
setEingangOffline(reduxInput.eingangOffline); setEingangOffline(reduxInput.eingangOffline ? 1 : 0);
setIsInitialLoad(false); setIsInitialLoad(false);
} }
}, [reduxInput, isInitialLoad]); }, [reduxInput, isInitialLoad]);
@@ -58,29 +70,29 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
try { try {
// PRODUKTIONSUMGEBUNG (CGI-Modus) // PRODUKTIONSUMGEBUNG (CGI-Modus)
if (process.env.NEXT_PUBLIC_NODE_ENV === "production") { if (process.env.NEXT_PUBLIC_NODE_ENV === "production") {
if (name !== reduxInput.name) { if (label !== reduxInput.label) {
await sendCgiUpdate(`DEN${id}=${encodeURIComponent(name)}`); await sendCgiUpdate(`DEN${id}=${encodeURIComponent(label)}`);
dispatch(updateName({ id, name })); dispatch(updateLabel({ id, label }));
hasChange = true; hasChange = true;
} }
if (invertiert !== reduxInput.invertierung) { if (invertiert !== reduxInput.invert) {
await sendCgiUpdate(`DEI${id}=${invertiert ? 1 : 0}`); await sendCgiUpdate(`DEI${id}=${invertiert ? 1 : 0}`);
dispatch(updateInvertierung({ id, invertierung: invertiert })); dispatch(updateInvert({ id, invert: invertiert }));
hasChange = true; hasChange = true;
} }
if (filterzeit !== reduxInput.filterzeit) { if (timeFilter !== reduxInput.timeFilter) {
await sendCgiUpdate(`DEF${id}=${filterzeit}`); await sendCgiUpdate(`DEF${id}=${timeFilter}`);
hasChange = true; hasChange = true;
} }
if (gewichtung !== reduxInput.gewichtung) { if (weighting !== reduxInput.weighting) {
await sendCgiUpdate(`DEG${id}=${gewichtung}`); await sendCgiUpdate(`DEG${id}=${weighting}`);
hasChange = true; hasChange = true;
} }
if (zaehlerAktiv !== reduxInput.zaehlerAktiv) { if (zaehlerAktiv !== reduxInput.zaehlerAktiv) {
await sendCgiUpdate(`DEZ${id}=${zaehlerAktiv ? 1 : 0}`); await sendCgiUpdate(`DEZ${id}=${zaehlerAktiv ? 1 : 0}`);
hasChange = true; hasChange = true;
} }
if (eingangOffline !== reduxInput.eingangOffline) { if (eingangOffline !== (reduxInput.eingangOffline ? 1 : 0)) {
await sendCgiUpdate(`DEO${id}=${eingangOffline ? 1 : 0}`); await sendCgiUpdate(`DEO${id}=${eingangOffline ? 1 : 0}`);
hasChange = true; hasChange = true;
} }
@@ -92,22 +104,22 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
} else { } else {
// ENTWICKLUNGSUMGEBUNG (lokale API) // ENTWICKLUNGSUMGEBUNG (lokale API)
const updates: any = { id }; const updates: any = { id };
if (name !== reduxInput.name) { if (label !== reduxInput.label) {
updates.name = name; updates.label = label;
dispatch(updateName({ id, name })); dispatch(updateLabel({ id, label }));
hasChange = true; hasChange = true;
} }
if (invertiert !== reduxInput.invertierung) { if (invertiert !== reduxInput.invert) {
updates.invertierung = invertiert ? 1 : 0; updates.invert = invertiert ? 1 : 0;
dispatch(updateInvertierung({ id, invertierung: invertiert })); dispatch(updateInvert({ id, invert: invertiert }));
hasChange = true; hasChange = true;
} }
if (filterzeit !== reduxInput.filterzeit) { if (timeFilter !== reduxInput.timeFilter) {
updates.filterzeit = filterzeit; updates.timeFilter = timeFilter;
hasChange = true; hasChange = true;
} }
if (gewichtung !== reduxInput.gewichtung) { if (weighting !== reduxInput.weighting) {
updates.gewichtung = gewichtung; updates.weighting = weighting;
hasChange = true; hasChange = true;
} }
if (zaehlerAktiv !== reduxInput.zaehlerAktiv) { if (zaehlerAktiv !== reduxInput.zaehlerAktiv) {
@@ -145,6 +157,11 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
setIsInitialLoad(true); setIsInitialLoad(true);
closeInputModal(); closeInputModal();
}; };
useEffect(() => {
if (isOpen && selectedInput) {
setIsInitialLoad(true);
}
}, [isOpen, selectedInput]);
return ( return (
<div className="fixed top-0 left-0 w-full h-full bg-black bg-opacity-50 flex justify-center items-center z-50"> <div className="fixed top-0 left-0 w-full h-full bg-black bg-opacity-50 flex justify-center items-center z-50">
@@ -169,8 +186,8 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
<div> <div>
<input <input
type="text" type="text"
value={name} value={label}
onChange={(e) => setName(e.target.value)} onChange={(e) => setLabel(e.target.value)}
className="border border-gray-300 rounded px-2 py-1 w-full" className="border border-gray-300 rounded px-2 py-1 w-full"
maxLength={32} maxLength={32}
/> />
@@ -206,11 +223,11 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
type="number" type="number"
min={0} min={0}
max={2000} max={2000}
value={filterzeit} value={timeFilter}
onChange={(e) => { onChange={(e) => {
const val = Number(e.target.value); const val = Number(e.target.value);
if (val <= 2000) { if (val <= 2000) {
setFilterzeit(val); setTimeFilter(val);
} }
}} }}
className="border border-gray-300 rounded px-2 py-1 pr-10 w-full text-right" className="border border-gray-300 rounded px-2 py-1 pr-10 w-full text-right"
@@ -230,11 +247,11 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
type="number" type="number"
min={0} min={0}
max={1000} max={1000}
value={gewichtung} value={weighting}
onChange={(e) => { onChange={(e) => {
const val = Number(e.target.value); const val = Number(e.target.value);
if (val <= 1000) { if (val <= 1000) {
setGewichtung(val); setWeighting(val);
} }
}} }}
className="border border-gray-300 rounded px-2 py-1 w-full text-right" className="border border-gray-300 rounded px-2 py-1 w-full text-right"
@@ -250,8 +267,8 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
<button <button
type="button" type="button"
role="switch" role="switch"
aria-checked={eingangOffline} aria-checked={!!eingangOffline}
onClick={() => setEingangOffline(!eingangOffline)} onClick={() => setEingangOffline(eingangOffline ? 0 : 1)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors duration-200 ${ className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors duration-200 ${
eingangOffline ? "bg-littwin-blue" : "bg-gray-300" eingangOffline ? "bg-littwin-blue" : "bg-gray-300"
}`} }`}

View File

@@ -1,34 +1,244 @@
{ {
"win_de_state": [ "win_de_state": [
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0 1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
], ],
"win_de_invert": [ "win_de_invert": [
1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0 0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
], ],
"win_de_counter": [ "win_de_counter": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
], ],
"win_de_time_filter": [ "win_de_time_filter": [
1500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0, 0, 0 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
], ],
"win_de_weighting": [ "win_de_weighting": [
600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,
0, 0, 0, 0, 0, 0, 0 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
], ],
"win_de_counter_active": [ "win_de_counter_active": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
], ],
"win_de_offline": [ "win_de_offline": [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
], ],
"win_de_label": [ "win_de_label": [
"DE112", "DE114",
"DE2", "DE2",
"DE3", "DE3",
"DE4", "DE4",

View File

@@ -1,34 +1,245 @@
// @/mocks/device-cgi-simulator/SERVICE/digitalInputsMockData.js
// auto-generated from update API
var win_de_state = [ var win_de_state = [
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]; ];
var win_de_invert = [ var win_de_invert = [
1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]; ];
var win_de_counter = [ var win_de_counter = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]; ];
var win_de_time_filter = [ var win_de_time_filter = [
1500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
0, 0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]; ];
var win_de_weighting = [ var win_de_weighting = [
600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
0, 0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]; ];
var win_de_counter_active = [ var win_de_counter_active = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]; ];
var win_de_offline = [ var win_de_offline = [
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]; ];
var win_de_label = [ var win_de_label = [
"DE112", "DE1",
"DE2", "DE2",
"DE3", "DE3",
"DE4", "DE4",
@@ -59,5 +270,5 @@ var win_de_label = [
"DE29", "DE29",
"DE30", "DE30",
"DE31", "DE31",
"DE32", "DE32"
]; ];

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "cpl-v4", "name": "cpl-v4",
"version": "1.6.427", "version": "1.6.428",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cpl-v4", "name": "cpl-v4",
"version": "1.6.427", "version": "1.6.428",
"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.427", "version": "1.6.428",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",

View File

@@ -26,12 +26,13 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {
"mocks/device-cgi-simulator/SERVICE/digitalInputsMockData.js" "mocks/device-cgi-simulator/SERVICE/digitalInputsMockData.js"
); );
const fileContent = fs.readFileSync(jsPath, "utf-8"); const fileContent = fs.readFileSync(jsPath, "utf-8");
//console.log("📡 JSMOCK-Daten geladen fileContent:", fileContent);
const extractArray = (name: string) => { const extractArray = (label: string) => {
const match = fileContent.match( const match = fileContent.match(
new RegExp(`var\\s+${name}\\s*=\\s*\\[([\\s\\S]*?)\\];`) new RegExp(`var\\s+${label}\\s*=\\s*\\[([\\s\\S]*?)\\];`)
); );
if (!match) throw new Error(`Feld ${name} nicht gefunden`); if (!match) throw new Error(`Feld ${label} nicht gefunden`);
return match[1] return match[1]
.split(",") .split(",")
.map((s) => s.trim().replace(/^["']|["']$/g, "")); .map((s) => s.trim().replace(/^["']|["']$/g, ""));
@@ -49,7 +50,7 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {
win_de_offline: extractArray("win_de_offline").map(Number), win_de_offline: extractArray("win_de_offline").map(Number),
win_de_label: extractArray("win_de_label"), win_de_label: extractArray("win_de_label"),
}; };
console.log("📡 JSMOCK-Daten geladen:", data); //console.log("📡 JSMOCK-Daten geladen in api in jsmock:", data);
return res.status(200).json(data); return res.status(200).json(data);
} }

View File

@@ -3,15 +3,36 @@ import type { NextApiRequest, NextApiResponse } from "next";
import path from "path"; import path from "path";
import fs from "fs"; import fs from "fs";
// WICHTIG: Der Mock-Datenpfad const mode = process.env.NEXT_PUBLIC_CPL_MODE;
const mockFilePath = path.join(
process.cwd(),
"apiMockData",
"SERVICE",
"digitalInputsMockData.js"
);
// Funktion zum Parsen des JS-Datei-Inhalts in ein eval-fähiges Objekt // 1⃣ Variable vorab definieren
let mockFilePath: string | null = null;
if (mode === "json") {
mockFilePath = path.join(
process.cwd(),
"mocks",
"api",
"SERVICE",
"digitalInputsMockData.json"
);
}
if (mode === "jsmock") {
mockFilePath = path.join(
process.cwd(),
"mocks",
"device-cgi-simulator",
"SERVICE",
"digitalInputsMockData.js"
);
}
// 2⃣ Sicherstellen, dass ein Modus aktiv ist
if (!mockFilePath) {
throw new Error(`❌ Kein gültiger Modus in .env gesetzt: ${mode}`);
}
// Funktion zum Parsen bei jsmock
function extractMockData(raw: string) { function extractMockData(raw: string) {
const context = {}; const context = {};
const func = new Function( const func = new Function(
@@ -44,32 +65,43 @@ export default async function handler(
} }
try { try {
const { id, name, invertierung, filterzeit, gewichtung, zaehlerAktiv } = const {
req.body; id,
label,
invert,
timeFilter,
weighting,
zaehlerAktiv,
eingangOffline,
} = req.body;
if (typeof id !== "number" || id < 1 || id > 32) { if (typeof id !== "number" || id < 1 || id > 32) {
return res.status(400).json({ error: "Ungültige ID (132 erlaubt)" }); return res.status(400).json({ error: "Ungültige ID (132 erlaubt)" });
} }
const rawContent = fs.readFileSync(mockFilePath, "utf-8"); const rawContent = fs.readFileSync(mockFilePath!, "utf-8");
const data = extractMockData(rawContent);
// Update der Daten // 3⃣ JSON vs JS Verarbeitung
if (typeof name === "string") data.win_de_label[id - 1] = name; const data =
if (typeof invertierung === "number") mode === "json" ? JSON.parse(rawContent) : extractMockData(rawContent);
data.win_de_invert[id - 1] = invertierung;
if (typeof filterzeit === "number") // 4⃣ Aktualisieren der Felder
data.win_de_time_filter[id - 1] = filterzeit; if (typeof label === "string") data.win_de_label[id - 1] = label;
if (typeof gewichtung === "number") if (typeof invert === "number") data.win_de_invert[id - 1] = invert;
data.win_de_weighting[id - 1] = gewichtung; if (typeof timeFilter === "number")
data.win_de_time_filter[id - 1] = timeFilter;
if (typeof weighting === "number")
data.win_de_weighting[id - 1] = weighting;
if (typeof zaehlerAktiv === "number") if (typeof zaehlerAktiv === "number")
data.win_de_counter_active[id - 1] = zaehlerAktiv; data.win_de_counter_active[id - 1] = zaehlerAktiv;
if (typeof eingangOffline === "number")
data.win_de_offline[id - 1] = eingangOffline;
if (typeof invertierung === "number") // 5⃣ Speichern
data.win_de_invert[id - 1] = invertierung; if (mode === "json") {
fs.writeFileSync(mockFilePath!, JSON.stringify(data, null, 2), "utf-8");
// Erzeuge neuen Dateiinhalt } else {
const newContent = ` const newContent = `
// auto-generated from update API // auto-generated from update API
var win_de_state = ${JSON.stringify(data.win_de_state, null, 2)}; var win_de_state = ${JSON.stringify(data.win_de_state, null, 2)};
var win_de_invert = ${JSON.stringify(data.win_de_invert, null, 2)}; var win_de_invert = ${JSON.stringify(data.win_de_invert, null, 2)};
@@ -77,19 +109,25 @@ var win_de_counter = ${JSON.stringify(data.win_de_counter, null, 2)};
var win_de_time_filter = ${JSON.stringify(data.win_de_time_filter, null, 2)}; var win_de_time_filter = ${JSON.stringify(data.win_de_time_filter, null, 2)};
var win_de_weighting = ${JSON.stringify(data.win_de_weighting, null, 2)}; var win_de_weighting = ${JSON.stringify(data.win_de_weighting, null, 2)};
var win_de_counter_active = ${JSON.stringify( var win_de_counter_active = ${JSON.stringify(
data.win_de_counter_active, data.win_de_counter_active,
null, null,
2 2
)}; )};
var win_de_offline = ${JSON.stringify(data.win_de_offline, null, 2)}; var win_de_offline = ${JSON.stringify(data.win_de_offline, null, 2)};
var win_de_label = ${JSON.stringify(data.win_de_label, null, 2)}; var win_de_label = ${JSON.stringify(data.win_de_label, null, 2)};
`; `;
fs.writeFileSync(mockFilePath!, newContent, "utf-8");
}
fs.writeFileSync(mockFilePath, newContent, "utf-8"); return res.status(200).json({
message: `Update erfolgreich für ID ${id}`,
return res id,
.status(200) label,
.json({ message: "Update erfolgreich", id, name, invertierung }); invert,
timeFilter,
weighting,
eingangOffline,
});
} catch (err: any) { } catch (err: any) {
console.error("Fehler beim Schreiben:", err); console.error("Fehler beim Schreiben:", err);
return res.status(500).json({ error: "Update fehlgeschlagen" }); return res.status(500).json({ error: "Update fehlgeschlagen" });

View File

@@ -4,15 +4,14 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
interface DigitalInput { interface DigitalInput {
id: number; id: number;
label: string; label: string;
status: boolean; status: number;
counter: number; counter: number;
flutter: number; flutter: number;
invertierung: boolean; invert: boolean;
filterzeit: number; timeFilter: number;
gewichtung: number; weighting: number;
zaehlerAktiv: boolean; zaehlerAktiv: boolean;
eingangOffline: boolean; eingangOffline: boolean;
name: string;
} }
interface DigitalInputsState { interface DigitalInputsState {
@@ -40,35 +39,30 @@ const digitalInputsSlice = createSlice({
input.status = status; input.status = status;
} }
}, },
updateInvertierung: ( updateInvert: (
state, state,
action: PayloadAction<{ id: number; invertierung: boolean }> action: PayloadAction<{ id: number; invert: boolean }>
) => { ) => {
const { id, invertierung } = action.payload; const { id, invert } = action.payload;
const input = state.inputs.find((input) => input.id === id); const input = state.inputs.find((input) => input.id === id);
if (input) { if (input) {
input.invertierung = invertierung; input.invert = invert;
} }
}, },
updateName: ( updateLabel: (
state, state,
action: PayloadAction<{ id: number; name: string }> action: PayloadAction<{ id: number; label: string }>
) => { ) => {
const { id, name } = action.payload; const { id, label } = action.payload;
const input = state.inputs.find((input) => input.id === id); const input = state.inputs.find((input) => input.id === id);
if (input) { if (input) {
input.name = name; input.label = label; // falls du label mit aktualisieren willst
input.label = name; // falls du label mit aktualisieren willst
} }
}, },
}, },
}); });
export const { export const { setInputs, updateInputStatus, updateInvert, updateLabel } =
setInputs, digitalInputsSlice.actions;
updateInputStatus,
updateInvertierung,
updateName, // <- hinzufügen
} = digitalInputsSlice.actions;
export default digitalInputsSlice.reducer; export default digitalInputsSlice.reducer;

View File

@@ -28,7 +28,7 @@ export const fetchDigitalInputsService = async () => {
timeFilter: win.win_de_time_filter[i], timeFilter: win.win_de_time_filter[i],
weighting: win.win_de_weighting[i], weighting: win.win_de_weighting[i],
counterActive: !!win.win_de_counter_active[i], counterActive: !!win.win_de_counter_active[i],
offline: !!win.win_de_offline[i], eingangOffline: !!win.win_de_offline[i],
})); }));
} }
@@ -49,7 +49,7 @@ export const fetchDigitalInputsService = async () => {
timeFilter: data.win_de_time_filter[i], timeFilter: data.win_de_time_filter[i],
weighting: data.win_de_weighting[i], weighting: data.win_de_weighting[i],
counterActive: !!data.win_de_counter_active[i], counterActive: !!data.win_de_counter_active[i],
offline: !!data.win_de_offline[i], eingangOffline: !!data.win_de_offline[i],
})); }));
} }
@@ -60,6 +60,7 @@ export const fetchDigitalInputsService = async () => {
throw new Error("❌ Fehler beim Laden der digitalen Eingänge (json)"); throw new Error("❌ Fehler beim Laden der digitalen Eingänge (json)");
const data = await res.json(); const data = await res.json();
//console.log("📡 JSMOCK-Daten geladen in service:", data);
return data.win_de_state.map((_: any, i: number) => ({ return data.win_de_state.map((_: any, i: number) => ({
id: i + 1, id: i + 1,
@@ -70,7 +71,7 @@ export const fetchDigitalInputsService = async () => {
timeFilter: data.win_de_time_filter[i], timeFilter: data.win_de_time_filter[i],
weighting: data.win_de_weighting[i], weighting: data.win_de_weighting[i],
counterActive: !!data.win_de_counter_active[i], counterActive: !!data.win_de_counter_active[i],
offline: !!data.win_de_offline[i], eingangOffline: !!data.win_de_offline[i],
})); }));
} }