fix: Vergleich und Speicherung von Änderungen im KUE-Modul korrigiert
- Originalwerte werden jetzt direkt aus window.win_kueXYZ geladen - Vergleiche in handleSave.ts angepasst für stabile Zahl/String-Auswertung - Fehlerhafte Meldung „Keine Änderungen vorgenommen“ behoben - Nur geänderte Werte werden per GET-API gesendet
This commit is contained in:
@@ -46,7 +46,11 @@ var win_kueIso = [
|
||||
10.5, 10.0, 200.0, 200.0, 200.0, 200.0,
|
||||
];
|
||||
//Grenzwert (MOhm) für Isolationswiderstand
|
||||
var win_kueLimit1 = [ 8.9, "9.9", 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, ];
|
||||
var win_kueLimit1 = [
|
||||
8.9, 9.9, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0,
|
||||
10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 10.0,
|
||||
10.0, 10.0, 10.0, 10.0, 10.0, 10.0,
|
||||
];
|
||||
|
||||
/*
|
||||
Verzögerung/Filterzeit 420 Sekunden Standardeinstellung
|
||||
@@ -57,7 +61,11 @@ Wenn der Widerstand innerhalb dieser 420 Sekunden wieder über den Grenzwert ste
|
||||
die Filterzeit startet beim nächsten Unterschreiten des Grenzwerts neu. Die Filterzeit verhindert also, dass
|
||||
kurzfristige Schwankungen oder Störungen fälschlicherweise als Fehler gemeldet werden.
|
||||
*/
|
||||
var win_kueDelay1 = [ 10, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, ];
|
||||
var win_kueDelay1 = [
|
||||
10, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420,
|
||||
420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420, 420,
|
||||
420,
|
||||
];
|
||||
//---------------------------------------------------
|
||||
//Schleifenwiderstand in Display (resDisplay) Einheit: KOhm
|
||||
var win_kueResidence = [
|
||||
@@ -66,11 +74,18 @@ var win_kueResidence = [
|
||||
0.615, 0.494, 1.217, 65.0, 65.0, 65.0, 65.0,
|
||||
];
|
||||
//Schleifenmessung Unterer Grenzwert (KOhm)
|
||||
var win_kueLimit2Low = [ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, ];
|
||||
var win_kueLimit2High = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ];
|
||||
var win_kueLimit2Low = [
|
||||
0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
|
||||
0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1,
|
||||
0.1, 0.1,
|
||||
];
|
||||
var win_kueLimit2High = [ "undefined", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ];;
|
||||
|
||||
//Schleifenintervall (h) für Schleifenmessung
|
||||
var win_kueLoopInterval = [ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ];
|
||||
var win_kueLoopInterval = [
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6,
|
||||
];
|
||||
//---------------------------------------------------
|
||||
//KÜ Modul Version soll /100 und davor V angezeigt werden z.B. 4.19V
|
||||
var win_kueVersion = [
|
||||
@@ -80,7 +95,7 @@ var win_kueVersion = [
|
||||
];
|
||||
|
||||
//Modulname in Komponente und auf der Anzeige
|
||||
var win_kueID = [ "FTZ_2", "B23", "Kabel 3", "Kabel 4", "Kabel 5", "Kabel 6", "FTZ4562", "Kabel 8", "12344", "Kabel 10", "Kabel 11", "Kabel 12", "Kabel 13", "Kabel 14", "Kabel 15", "H56-77", "Kabel 17", "Kabel 18", "Kabel 19", "Kabel 20", "Kabel 21", "Kabel 22", "Kabel 23", "Kabel 24", "Kabel 25", "Kabel 26", "Kabel 27", "Kabel 28", "Kabel 29", "Kabel 30", "Kabel 31", "Kabel 32", ];
|
||||
var win_kueID = [ "FTZ_4", "B23", "Kabel 3", "Kabel 4", "Kabel 5", "Kabel 6", "FTZ4562", "Kabel 8", "12344", "Kabel 10", "Kabel 11", "Kabel 12", "Kabel 13", "Kabel 14", "Kabel 15", "H56-77", "Kabel 17", "Kabel 18", "Kabel 19", "Kabel 20", "Kabel 21", "Kabel 22", "Kabel 23", "Kabel 24", "Kabel 25", "Kabel 26", "Kabel 27", "Kabel 28", "Kabel 29", "Kabel 30", "Kabel 31", "Kabel 32", ];;;
|
||||
|
||||
//---------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"; // components/modules/kue705FO/Kue705FO.tsx
|
||||
import React, { useState, useEffect, useRef, useMemo } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import KueModal from "./KueModal";
|
||||
import KueModal from "./modals/KueModal";
|
||||
import "bootstrap-icons/font/bootstrap-icons.css"; // Import Bootstrap Icons
|
||||
import { Kue705FOProps } from "../../../../types/components/Kue705FOProps";
|
||||
import ChartSwitcher from "./Charts/ChartSwitcher";
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
"use client"; // components/modales/KueModal.jsx
|
||||
import ReactModal from "react-modal";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import type { RootState } from "../../../../redux/store";
|
||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
import handleSave, { OriginalValues } from "./handlers/handleSave";
|
||||
import handleDisplayEinschalten from "./handlers/handleDisplayEinschalten";
|
||||
import firmwareUpdate from "./handlers/firmwareUpdate";
|
||||
import decodeToken from "../../../../utils/decodeToken";
|
||||
import { setKueData } from "../../../../redux/slices/kueDataSlice";
|
||||
|
||||
interface KueModalProps {
|
||||
showModal: boolean;
|
||||
onClose: () => void;
|
||||
slot: number;
|
||||
onModulNameChange: (id: string) => void;
|
||||
}
|
||||
|
||||
function KueModal({
|
||||
showModal,
|
||||
onClose,
|
||||
slot,
|
||||
onModulNameChange,
|
||||
}: KueModalProps): JSX.Element {
|
||||
const dispatch = useDispatch();
|
||||
const isAdminLoggedIn = useSelector(
|
||||
(state: any) => state.authSlice.isAdminLoggedIn
|
||||
);
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
|
||||
const {
|
||||
kueID,
|
||||
kueLimit1,
|
||||
kueDelay1,
|
||||
kueLimit2Low,
|
||||
kueLimit2High,
|
||||
kueLoopInterval,
|
||||
} = useSelector((state: RootState) => state.kueDataSlice);
|
||||
|
||||
const [bezeichnungen, setBezeichnungen] = useState(Array(32).fill(""));
|
||||
|
||||
const [originalValues, setOriginalValues] = useState<OriginalValues>({
|
||||
kueID: Array(32).fill(""),
|
||||
kueBezeichnungen: Array(32).fill(""),
|
||||
isolationsgrenzwerte: Array(32).fill(10.0),
|
||||
verzoegerung: Array(32).fill(1.0),
|
||||
untereSchleifenGrenzwerte: Array(32).fill(0.1),
|
||||
obereSchleifenGrenzwerte: Array(32).fill(1.0),
|
||||
schleifenintervall: Array(32).fill(24),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (showModal) {
|
||||
setBezeichnungen(
|
||||
kueID
|
||||
? kueID.map((name: string) => name.trim() || "---")
|
||||
: bezeichnungen
|
||||
);
|
||||
|
||||
setOriginalValues({
|
||||
kueID: [...kueID],
|
||||
kueBezeichnungen: [...bezeichnungen],
|
||||
isolationsgrenzwerte: [...kueLimit1],
|
||||
verzoegerung: [...kueDelay1],
|
||||
untereSchleifenGrenzwerte: [...kueLimit2Low],
|
||||
obereSchleifenGrenzwerte: [...kueLimit2High],
|
||||
schleifenintervall: [...kueLoopInterval],
|
||||
});
|
||||
}
|
||||
}, [
|
||||
showModal,
|
||||
kueID,
|
||||
kueLimit1,
|
||||
kueDelay1,
|
||||
kueLimit2Low,
|
||||
kueLimit2High,
|
||||
kueLoopInterval,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const token = sessionStorage.getItem("token");
|
||||
if (token) {
|
||||
const decoded = decodeToken(token);
|
||||
setIsAdmin(decoded?.role?.toLowerCase() === "admin");
|
||||
}
|
||||
}, [showModal]);
|
||||
|
||||
const handleSaveWrapper = () => {
|
||||
handleSave({
|
||||
ids: [...kueID],
|
||||
bezeichnungen,
|
||||
isolationsgrenzwerte: [...kueLimit1],
|
||||
verzoegerung: [...kueDelay1],
|
||||
untereSchleifenGrenzwerte: [...kueLimit2Low],
|
||||
obereSchleifenGrenzwerte: [...kueLimit2High],
|
||||
schleifenintervall: [...kueLoopInterval],
|
||||
originalValues,
|
||||
slot,
|
||||
dispatch,
|
||||
onModulNameChange,
|
||||
onClose,
|
||||
});
|
||||
};
|
||||
|
||||
// Korrekte updateArray Methode ohne Thunk
|
||||
const updateArray = (
|
||||
key: keyof RootState["kueDataSlice"],
|
||||
array: number[],
|
||||
value: number
|
||||
) => {
|
||||
const updatedArray = [...array];
|
||||
updatedArray[slot] = value;
|
||||
dispatch(setKueData({ [key]: updatedArray }));
|
||||
};
|
||||
|
||||
const handleDisplayEinschaltenWrapper = () => {
|
||||
handleDisplayEinschalten(slot);
|
||||
};
|
||||
|
||||
return (
|
||||
<ReactModal
|
||||
isOpen={showModal}
|
||||
onRequestClose={onClose}
|
||||
ariaHideApp={false}
|
||||
style={{
|
||||
overlay: {
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
zIndex: 100,
|
||||
},
|
||||
content: {
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: "90%",
|
||||
maxWidth: "800px",
|
||||
padding: "10px",
|
||||
borderRadius: "8px",
|
||||
border: "none",
|
||||
position: "relative", // wichtig
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div className="relative bg-littwin-blue text-white p-1 rounded-t-lg">
|
||||
<h2 className="text-sm font-bold">KUE Einstellung - Slot {slot + 1}</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "0rem",
|
||||
right: "0.5rem",
|
||||
background: "transparent",
|
||||
border: "none",
|
||||
fontSize: "1.5rem",
|
||||
color: "#000",
|
||||
cursor: "pointer",
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
<i className="bi bi-x-circle-fill"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="p-2 mb-4 text-black">
|
||||
<label className="font-bold">Kabelbezeichnung:</label>
|
||||
<input
|
||||
type="text"
|
||||
className="border rounded p-1 w-full text-sm"
|
||||
value={kueID[slot] || ""}
|
||||
onChange={(e) => {
|
||||
const newIds = [...kueID];
|
||||
newIds[slot] = e.target.value;
|
||||
dispatch(setKueData({ kueID: newIds }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="p-2 text-black">
|
||||
<h3 className="font-bold text-center mb-4">Isolationsmessung</h3>
|
||||
<table className="w-full text-left border-collapse mb-4">
|
||||
<thead className="bg-gray-100">
|
||||
<tr>
|
||||
<th className="p-2 border text-sm text-center">
|
||||
Grenzwert (MOhm)
|
||||
</th>
|
||||
<th className="p-2 border text-sm text-center">
|
||||
Verzögerung (sek)
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="p-2 border text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1 text-sm"
|
||||
value={kueLimit1[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueLimit1",
|
||||
kueLimit1,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td className="p-2 border text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1 text-sm"
|
||||
value={kueDelay1[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueDelay1",
|
||||
kueDelay1,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3 className="font-bold text-center mb-4">Schleifenmessung</h3>
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead className="bg-gray-100">
|
||||
<tr>
|
||||
<th className="p-2 border text-sm text-center">
|
||||
Grenzwert (kOhm)
|
||||
</th>
|
||||
<th className="p-2 border text-sm text-center">
|
||||
Schleifenintervall (h)
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="p-2 border text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1 text-sm"
|
||||
value={kueLimit2Low[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueLimit2Low",
|
||||
kueLimit2Low,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td className="p-2 border text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1 text-sm"
|
||||
value={kueLoopInterval[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueLoopInterval",
|
||||
kueLoopInterval,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end bg-gray-100 p-4 rounded-b-lg">
|
||||
{isAdminLoggedIn && (
|
||||
<button
|
||||
onClick={() => firmwareUpdate(slot)}
|
||||
className="bg-littwin-blue text-white p-2 rounded flex items-center mr-2"
|
||||
>
|
||||
Firmware Update
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={handleDisplayEinschaltenWrapper}
|
||||
className="bg-littwin-blue text-white p-2 rounded flex items-center mr-2"
|
||||
>
|
||||
<span className="mr-2">📺</span> Display einschalten
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSaveWrapper}
|
||||
className="bg-littwin-blue text-white p-2 rounded flex items-center"
|
||||
>
|
||||
<span className="mr-2">💾</span> Speichern
|
||||
</button>
|
||||
</div>
|
||||
</ReactModal>
|
||||
);
|
||||
}
|
||||
|
||||
export default KueModal;
|
||||
@@ -3,7 +3,6 @@ import { setKueData } from "../../../../../redux/slices/kueDataSlice";
|
||||
|
||||
export interface OriginalValues {
|
||||
kueID: string[];
|
||||
kueBezeichnungen: string[];
|
||||
isolationsgrenzwerte: number[];
|
||||
verzoegerung: number[];
|
||||
untereSchleifenGrenzwerte: number[];
|
||||
@@ -13,7 +12,6 @@ export interface OriginalValues {
|
||||
|
||||
interface HandleSaveParams {
|
||||
ids: string[];
|
||||
bezeichnungen: string[];
|
||||
isolationsgrenzwerte: number[];
|
||||
verzoegerung: number[];
|
||||
untereSchleifenGrenzwerte: number[];
|
||||
@@ -26,9 +24,17 @@ interface HandleSaveParams {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const isDifferent = (a: any, b: any): boolean => {
|
||||
const aNum = Number(a);
|
||||
const bNum = Number(b);
|
||||
if (!isNaN(aNum) && !isNaN(bNum)) {
|
||||
return Math.abs(aNum - bNum) > 0.0001;
|
||||
}
|
||||
return String(a).trim() !== String(b).trim();
|
||||
};
|
||||
|
||||
const handleSave = async ({
|
||||
ids,
|
||||
bezeichnungen,
|
||||
isolationsgrenzwerte,
|
||||
verzoegerung,
|
||||
untereSchleifenGrenzwerte,
|
||||
@@ -40,88 +46,73 @@ const handleSave = async ({
|
||||
onModulNameChange,
|
||||
onClose,
|
||||
}: HandleSaveParams): Promise<void> => {
|
||||
const changes: Partial<{
|
||||
KID: string;
|
||||
KIA: string;
|
||||
KL_: number;
|
||||
KD_: number;
|
||||
KR_: number;
|
||||
KRO_: number;
|
||||
KRI: number;
|
||||
}> = {};
|
||||
const changesForFile: Record<string, any> = {};
|
||||
|
||||
if (ids[slot] !== originalValues.kueID[slot]) {
|
||||
changes.KID = ids[slot];
|
||||
}
|
||||
if (bezeichnungen[slot] !== originalValues.kueBezeichnungen[slot]) {
|
||||
changes.KIA = bezeichnungen[slot];
|
||||
if (isDifferent(ids[slot], originalValues.kueID[slot])) {
|
||||
changesForFile.win_kueID = ids[slot];
|
||||
}
|
||||
if (
|
||||
isolationsgrenzwerte[slot] !== originalValues.isolationsgrenzwerte[slot]
|
||||
isDifferent(
|
||||
isolationsgrenzwerte[slot],
|
||||
originalValues.isolationsgrenzwerte[slot]
|
||||
)
|
||||
) {
|
||||
changes.KL_ = isolationsgrenzwerte[slot];
|
||||
changesForFile.win_kueLimit1 = isolationsgrenzwerte[slot];
|
||||
}
|
||||
if (verzoegerung[slot] !== originalValues.verzoegerung[slot]) {
|
||||
changes.KD_ = verzoegerung[slot];
|
||||
if (isDifferent(verzoegerung[slot], originalValues.verzoegerung[slot])) {
|
||||
changesForFile.win_kueDelay1 = verzoegerung[slot];
|
||||
}
|
||||
if (
|
||||
untereSchleifenGrenzwerte[slot] !==
|
||||
originalValues.untereSchleifenGrenzwerte[slot]
|
||||
isDifferent(
|
||||
untereSchleifenGrenzwerte[slot],
|
||||
originalValues.untereSchleifenGrenzwerte[slot]
|
||||
)
|
||||
) {
|
||||
changes.KR_ = untereSchleifenGrenzwerte[slot];
|
||||
changesForFile.win_kueLimit2Low = untereSchleifenGrenzwerte[slot];
|
||||
}
|
||||
if (
|
||||
obereSchleifenGrenzwerte[slot] !==
|
||||
originalValues.obereSchleifenGrenzwerte[slot]
|
||||
isDifferent(
|
||||
obereSchleifenGrenzwerte[slot],
|
||||
originalValues.obereSchleifenGrenzwerte[slot]
|
||||
)
|
||||
) {
|
||||
changes.KRO_ = obereSchleifenGrenzwerte[slot];
|
||||
changesForFile.win_kueLimit2High = obereSchleifenGrenzwerte[slot];
|
||||
}
|
||||
if (schleifenintervall[slot] !== originalValues.schleifenintervall[slot]) {
|
||||
changes.KRI = schleifenintervall[slot];
|
||||
if (
|
||||
isDifferent(
|
||||
schleifenintervall[slot],
|
||||
originalValues.schleifenintervall[slot]
|
||||
)
|
||||
) {
|
||||
changesForFile.win_kueLoopInterval = schleifenintervall[slot];
|
||||
}
|
||||
|
||||
if (Object.keys(changes).length > 0) {
|
||||
if (Object.keys(changesForFile).length > 0) {
|
||||
const isDev = window.location.hostname === "localhost";
|
||||
|
||||
if (isDev) {
|
||||
await fetch("/api/cpl/updateKueDataAPIHandler", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
slot,
|
||||
changes: {
|
||||
win_kueID: ids[slot],
|
||||
win_kueLimit1: isolationsgrenzwerte[slot],
|
||||
win_kueDelay1: verzoegerung[slot],
|
||||
win_kueLimit2Low: untereSchleifenGrenzwerte[slot],
|
||||
win_kueLimit2High: obereSchleifenGrenzwerte[slot],
|
||||
win_kueLoopInterval: schleifenintervall[slot],
|
||||
},
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
let url = `/cpl?/kabelueberwachung.html&slot=${slot}`;
|
||||
Object.entries(changes).forEach(([paramKey, paramValue]) => {
|
||||
if (paramValue !== undefined) {
|
||||
url += `&${paramKey}${slot}=${encodeURIComponent(paramValue)}`;
|
||||
for (const [key, value] of Object.entries(changesForFile)) {
|
||||
const params = new URLSearchParams({
|
||||
key,
|
||||
value: String(value),
|
||||
slot: String(slot),
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/cpl/updateKueDataAPIHandler?${params.toString()}`
|
||||
);
|
||||
if (!response.ok) {
|
||||
alert(`❌ Fehler beim Schreiben der Datei (${key})`);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
const response = await fetch(url, { method: "GET" });
|
||||
|
||||
if (!response.ok) {
|
||||
alert("Fehler beim Speichern der Daten!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
alert("Daten erfolgreich gespeichert!");
|
||||
alert("✅ Daten erfolgreich gespeichert!");
|
||||
onModulNameChange(ids[slot]);
|
||||
|
||||
dispatch(
|
||||
setKueData({
|
||||
kueID: [...ids],
|
||||
kueBezeichnungen: [...bezeichnungen],
|
||||
isolationsgrenzwerte: [...isolationsgrenzwerte],
|
||||
verzoegerung: [...verzoegerung],
|
||||
untereSchleifenGrenzwerte: [...untereSchleifenGrenzwerte],
|
||||
@@ -130,7 +121,7 @@ const handleSave = async ({
|
||||
})
|
||||
);
|
||||
} else {
|
||||
alert("Keine Änderungen vorgenommen.");
|
||||
alert("ℹ️ Keine Änderungen vorgenommen.");
|
||||
}
|
||||
|
||||
onClose();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
slot: number;
|
||||
}
|
||||
|
||||
export default function Knotenpunkte({ slot }: Props) {
|
||||
return <div>Knotenpunkte – Slot {slot + 1}</div>;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
"use client";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import type { RootState } from "../../../../../redux/store";
|
||||
import { setKueData } from "../../../../../redux/slices/kueDataSlice";
|
||||
import handleSave, { OriginalValues } from "../handlers/handleSave";
|
||||
import handleDisplayEinschalten from "../handlers/handleDisplayEinschalten";
|
||||
import firmwareUpdate from "../handlers/firmwareUpdate";
|
||||
|
||||
interface Props {
|
||||
slot: number;
|
||||
onClose?: () => void;
|
||||
onModulNameChange?: (id: string) => void;
|
||||
}
|
||||
|
||||
export default function KueEinstellung({
|
||||
slot,
|
||||
onClose = () => {},
|
||||
onModulNameChange = () => {},
|
||||
}: Props) {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
kueID,
|
||||
kueLimit1,
|
||||
kueDelay1,
|
||||
kueLimit2Low,
|
||||
kueLoopInterval,
|
||||
kueLimit2High,
|
||||
} = useSelector((state: RootState) => state.kueDataSlice);
|
||||
|
||||
const isAdminLoggedIn = useSelector(
|
||||
(state: any) => state.authSlice.isAdminLoggedIn
|
||||
);
|
||||
|
||||
const handleSaveWrapper = () => {
|
||||
const originalValues: OriginalValues = {
|
||||
kueID: [...(window.win_kueID ?? [])],
|
||||
isolationsgrenzwerte: [...(window.win_kueLimit1 ?? [])],
|
||||
verzoegerung: [...(window.win_kueDelay1 ?? [])],
|
||||
untereSchleifenGrenzwerte: [...(window.win_kueLimit2Low ?? [])],
|
||||
obereSchleifenGrenzwerte: [...(window.win_kueLimit2High ?? [])],
|
||||
schleifenintervall: [...(window.win_kueLoopInterval ?? [])],
|
||||
};
|
||||
|
||||
handleSave({
|
||||
ids: [...kueID],
|
||||
isolationsgrenzwerte: [...kueLimit1],
|
||||
verzoegerung: [...kueDelay1],
|
||||
untereSchleifenGrenzwerte: [...kueLimit2Low],
|
||||
obereSchleifenGrenzwerte: [...kueLimit2High],
|
||||
schleifenintervall: [...kueLoopInterval],
|
||||
originalValues,
|
||||
slot,
|
||||
dispatch,
|
||||
onModulNameChange,
|
||||
onClose,
|
||||
});
|
||||
};
|
||||
|
||||
const updateArray = (
|
||||
key: keyof RootState["kueDataSlice"],
|
||||
array: number[],
|
||||
value: number
|
||||
) => {
|
||||
const updated = [...array];
|
||||
updated[slot] = value;
|
||||
dispatch(setKueData({ [key]: updated }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="text-black space-y-6">
|
||||
<div>
|
||||
<label className="font-bold">Kabelbezeichnung:</label>
|
||||
<input
|
||||
type="text"
|
||||
className="w-full border rounded p-1 text-sm"
|
||||
value={kueID[slot] || ""}
|
||||
onChange={(e) => {
|
||||
const newIds = [...kueID];
|
||||
newIds[slot] = e.target.value;
|
||||
dispatch(setKueData({ kueID: newIds }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="font-bold text-center mb-2">Isolationsmessung</h3>
|
||||
<table className="w-full border-collapse text-sm">
|
||||
<thead className="bg-gray-100">
|
||||
<tr>
|
||||
<th className="border p-2 text-center">Grenzwert (MOhm)</th>
|
||||
<th className="border p-2 text-center">Verzögerung (sek)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="border p-2 text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1"
|
||||
value={kueLimit1[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueLimit1",
|
||||
kueLimit1,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td className="border p-2 text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1"
|
||||
value={kueDelay1[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueDelay1",
|
||||
kueDelay1,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="font-bold text-center mb-2">Schleifenmessung</h3>
|
||||
<table className="w-full border-collapse text-sm">
|
||||
<thead className="bg-gray-100">
|
||||
<tr>
|
||||
<th className="border p-2 text-center">Grenzwert (kOhm)</th>
|
||||
<th className="border p-2 text-center">Schleifenintervall (h)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="border p-2 text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1"
|
||||
value={kueLimit2Low[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueLimit2Low",
|
||||
kueLimit2Low,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td className="border p-2 text-center">
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
className="w-[6rem] border rounded p-1"
|
||||
value={kueLoopInterval[slot] ?? ""}
|
||||
onChange={(e) =>
|
||||
updateArray(
|
||||
"kueLoopInterval",
|
||||
kueLoopInterval,
|
||||
parseFloat(e.target.value)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 bg-gray-100 p-3 rounded">
|
||||
{isAdminLoggedIn && (
|
||||
<button
|
||||
onClick={() => firmwareUpdate(slot)}
|
||||
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
||||
>
|
||||
<span className="mr-2">🔧</span> Firmware Update
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => handleDisplayEinschalten(slot)}
|
||||
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
||||
>
|
||||
<span className="mr-2">📺</span> Display einschalten
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSaveWrapper}
|
||||
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
||||
>
|
||||
<span className="mr-2">💾</span> Speichern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
108
components/main/kabelueberwachung/kue705FO/modals/KueModal.tsx
Normal file
108
components/main/kabelueberwachung/kue705FO/modals/KueModal.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
"use client";
|
||||
import { useState, useEffect } from "react";
|
||||
import ReactModal from "react-modal";
|
||||
import KueEinstellung from "./KueEinstellung";
|
||||
import TdrEinstellung from "./TdrEinstellung";
|
||||
import Knotenpunkte from "./Knotenpunkte";
|
||||
|
||||
interface KueModalProps {
|
||||
showModal: boolean;
|
||||
onClose: () => void;
|
||||
slot: number;
|
||||
onModulNameChange: (id: string) => void; // NEU!
|
||||
}
|
||||
|
||||
export default function KueModal({ showModal, onClose, slot }: KueModalProps) {
|
||||
const [activeTab, setActiveTab] = useState<"kue" | "tdr" | "knoten">("kue");
|
||||
|
||||
useEffect(() => {
|
||||
if (showModal) {
|
||||
setActiveTab("kue");
|
||||
}
|
||||
}, [showModal]);
|
||||
|
||||
return (
|
||||
<ReactModal
|
||||
isOpen={showModal}
|
||||
onRequestClose={onClose}
|
||||
ariaHideApp={false}
|
||||
style={{
|
||||
overlay: {
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
zIndex: 100,
|
||||
},
|
||||
content: {
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
right: "auto",
|
||||
bottom: "auto",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: "90%",
|
||||
maxWidth: "850px",
|
||||
padding: "0px",
|
||||
border: "none",
|
||||
borderRadius: "8px",
|
||||
position: "relative",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div className="bg-littwin-blue text-white p-2 flex justify-between items-center rounded-t-md">
|
||||
<h2 className="text-sm font-bold">Einstellungen – Slot {slot + 1}</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="text-white text-xl hover:text-gray-200"
|
||||
>
|
||||
<i className="bi bi-x-circle-fill"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center bg-gray-100 space-x-2 p-2">
|
||||
<button
|
||||
onClick={() => setActiveTab("kue")}
|
||||
className={`px-4 py-1 rounded-t font-bold text-sm ${
|
||||
activeTab === "kue"
|
||||
? "bg-white text-blue-600"
|
||||
: "text-gray-500 hover:text-black"
|
||||
}`}
|
||||
>
|
||||
KUE Einstellung
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab("tdr")}
|
||||
className={`px-4 py-1 rounded-t font-bold text-sm ${
|
||||
activeTab === "tdr"
|
||||
? "bg-white text-blue-600"
|
||||
: "text-gray-500 hover:text-black"
|
||||
}`}
|
||||
>
|
||||
TDR Einstellung
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab("knoten")}
|
||||
className={`px-4 py-1 rounded-t font-bold text-sm ${
|
||||
activeTab === "knoten"
|
||||
? "bg-white text-blue-600"
|
||||
: "text-gray-500 hover:text-black"
|
||||
}`}
|
||||
>
|
||||
Knotenpunkte
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-white rounded-b-md max-h-[75vh] overflow-y-auto">
|
||||
{activeTab === "kue" && (
|
||||
<KueEinstellung
|
||||
slot={slot}
|
||||
onModulNameChange={(id) => {
|
||||
console.log("Modulname geändert:", id);
|
||||
}}
|
||||
onClose={onClose}
|
||||
/>
|
||||
)}
|
||||
|
||||
{activeTab === "tdr" && <TdrEinstellung slot={slot} />}
|
||||
{activeTab === "knoten" && <Knotenpunkte slot={slot} />}
|
||||
</div>
|
||||
</ReactModal>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
slot: number;
|
||||
}
|
||||
|
||||
export default function TdrEinstellung({ slot }: Props) {
|
||||
return <div>TdrEinstellung – Slot {slot + 1}</div>;
|
||||
}
|
||||
@@ -6,5 +6,5 @@
|
||||
2: Patch oder Hotfix (Bugfixes oder kleine Änderungen).
|
||||
|
||||
*/
|
||||
const webVersion = "1.6.246";
|
||||
const webVersion = "1.6.247";
|
||||
export default webVersion;
|
||||
|
||||
@@ -7,14 +7,16 @@ export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Only GET allowed" });
|
||||
}
|
||||
|
||||
const { slot, changes } = req.body;
|
||||
const slot = parseInt(req.query.slot as string);
|
||||
const key = req.query.key as string;
|
||||
const value = req.query.value as string;
|
||||
|
||||
if (slot === undefined || !changes || typeof changes !== "object") {
|
||||
return res.status(400).json({ error: "Missing slot or changes" });
|
||||
if (isNaN(slot) || !key || value === undefined) {
|
||||
return res.status(400).json({ error: "Missing slot, key or value" });
|
||||
}
|
||||
|
||||
const filePath = path.join(
|
||||
@@ -27,26 +29,47 @@ export default async function handler(
|
||||
try {
|
||||
let fileContent = await fs.readFile(filePath, "utf-8");
|
||||
|
||||
for (const [varName, value] of Object.entries(changes)) {
|
||||
const regex = new RegExp(
|
||||
`(var\\s+${varName}\\s*=\\s*\\[)([^\\]]*)(\\])`,
|
||||
"m"
|
||||
);
|
||||
// Robuste Regex: matcht auch bei Zeilenumbrüchen oder Leerzeichen
|
||||
const regex = new RegExp(
|
||||
`(var\\s+${key}\\s*=\\s*\\[)([\\s\\S]*?)(\\])`,
|
||||
"gm"
|
||||
);
|
||||
|
||||
const match = fileContent.match(regex);
|
||||
if (match) {
|
||||
const values = match[2].split(",").map((v) => v.trim());
|
||||
values[slot] = JSON.stringify(value); // korrektes Format: z. B. `"FTZ_2"` oder `10.5`
|
||||
const updatedArray = `${match[1]} ${values.join(", ")} ${match[3]}`;
|
||||
fileContent = fileContent.replace(regex, updatedArray);
|
||||
}
|
||||
const match = fileContent.match(regex);
|
||||
|
||||
console.log("🔍 Suche nach Variable:", key);
|
||||
if (!match) {
|
||||
console.warn(`⚠️ Variable '${key}' nicht gefunden in Datei.`);
|
||||
return res.status(404).json({ error: `Variable '${key}' not found.` });
|
||||
}
|
||||
|
||||
const arrayPart = match[0].match(/\[(.*)\]/s)?.[1] ?? "";
|
||||
const values = arrayPart
|
||||
.split(",")
|
||||
.map((v) => v.trim())
|
||||
.filter((v) => v.length > 0 || v === "");
|
||||
|
||||
const parsedValue = isNaN(Number(value)) ? JSON.stringify(value) : value;
|
||||
|
||||
if (slot >= values.length) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Slot ${slot} ist außerhalb des gültigen Bereichs.` });
|
||||
}
|
||||
|
||||
values[slot] = parsedValue;
|
||||
const updatedArray = `var ${key} = [ ${values.join(", ")} ];`;
|
||||
|
||||
fileContent = fileContent.replace(regex, updatedArray);
|
||||
|
||||
await fs.writeFile(filePath, fileContent, "utf-8");
|
||||
|
||||
res.status(200).json({ success: true });
|
||||
console.log(`✅ ${key}[${slot}] erfolgreich geändert auf`, parsedValue);
|
||||
return res
|
||||
.status(200)
|
||||
.json({ success: true, key, slot, newValue: parsedValue });
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Schreiben der Datei:", error);
|
||||
res.status(500).json({ error: "Failed to write file" });
|
||||
console.error("❌ Fehler beim Schreiben der Datei:", error);
|
||||
return res.status(500).json({ error: "Failed to write mock file" });
|
||||
}
|
||||
}
|
||||
|
||||
75
pages/api/cpl/updateMockViaGet.ts
Normal file
75
pages/api/cpl/updateMockViaGet.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
// /pages/api/cpl/updateMockViaGet.ts
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Only GET allowed" });
|
||||
}
|
||||
|
||||
const slot = parseInt(req.query.slot as string);
|
||||
const key = req.query.key as string;
|
||||
const value = req.query.value as string;
|
||||
|
||||
if (isNaN(slot) || !key || value === undefined) {
|
||||
return res.status(400).json({ error: "Missing slot, key or value" });
|
||||
}
|
||||
|
||||
const filePath = path.join(
|
||||
process.cwd(),
|
||||
"apiMockData",
|
||||
"SERVICE",
|
||||
"kabelueberwachungMockData.js"
|
||||
);
|
||||
|
||||
try {
|
||||
let fileContent = await fs.readFile(filePath, "utf-8");
|
||||
|
||||
// Robuste Regex: matcht auch bei Zeilenumbrüchen oder Leerzeichen
|
||||
const regex = new RegExp(
|
||||
`(var\\s+${key}\\s*=\\s*\\[)([\\s\\S]*?)(\\])`,
|
||||
"gm"
|
||||
);
|
||||
|
||||
const match = fileContent.match(regex);
|
||||
|
||||
console.log("🔍 Suche nach Variable:", key);
|
||||
if (!match) {
|
||||
console.warn(`⚠️ Variable '${key}' nicht gefunden in Datei.`);
|
||||
return res.status(404).json({ error: `Variable '${key}' not found.` });
|
||||
}
|
||||
|
||||
const arrayPart = match[0].match(/\[(.*)\]/s)?.[1] ?? "";
|
||||
const values = arrayPart
|
||||
.split(",")
|
||||
.map((v) => v.trim())
|
||||
.filter((v) => v.length > 0 || v === "");
|
||||
|
||||
const parsedValue = isNaN(Number(value)) ? JSON.stringify(value) : value;
|
||||
|
||||
if (slot >= values.length) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: `Slot ${slot} ist außerhalb des gültigen Bereichs.` });
|
||||
}
|
||||
|
||||
values[slot] = parsedValue;
|
||||
const updatedArray = `var ${key} = [ ${values.join(", ")} ];`;
|
||||
|
||||
fileContent = fileContent.replace(regex, updatedArray);
|
||||
|
||||
await fs.writeFile(filePath, fileContent, "utf-8");
|
||||
|
||||
console.log(`✅ ${key}[${slot}] erfolgreich geändert auf`, parsedValue);
|
||||
return res
|
||||
.status(200)
|
||||
.json({ success: true, key, slot, newValue: parsedValue });
|
||||
} catch (error) {
|
||||
console.error("❌ Fehler beim Schreiben der Datei:", error);
|
||||
return res.status(500).json({ error: "Failed to write mock file" });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user