Kableüberwachung Modal und digitale Eingänge Modal
This commit is contained in:
@@ -33,6 +33,15 @@ export default function AnalogeEingaengeTable({
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<h2 className="text-sm laptop:text-xs font-bold mb-3 flex items-center">
|
||||
<img
|
||||
src="/images/analogeEingaengeIcon.svg"
|
||||
alt="Analoge Eingänge"
|
||||
className="w-6 h-6 mr-2 text-littwin-blue"
|
||||
/>
|
||||
Messwerteingänge
|
||||
</h2>
|
||||
|
||||
<div className="bg-white shadow-lg rounded-lg p-4 border border-gray-200">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full border-collapse border border-gray-300 text-sm md:text-base">
|
||||
|
||||
@@ -64,7 +64,7 @@ export default function DigitalInputs({ openInputModal, inputRange }: Props) {
|
||||
●
|
||||
</span>
|
||||
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 w-max bg-gray-400 text-xs laptop:text-[10px] text-white rounded opacity-0 group-hover:opacity-100 transition p-1 z-10 xl:text-sm ">
|
||||
Eingang Aus
|
||||
Eingang Ein
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
@@ -73,7 +73,7 @@ export default function DigitalInputs({ openInputModal, inputRange }: Props) {
|
||||
●
|
||||
</span>
|
||||
<div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 w-max bg-gray-400 text-xs laptop:text-[10px] text-white rounded opacity-0 group-hover:opacity-100 transition p-1 z-10">
|
||||
Eingang Ein
|
||||
Eingang Aus
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -23,6 +23,7 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
const [filterzeit, setFilterzeit] = useState(0);
|
||||
const [gewichtung, setGewichtung] = useState(0);
|
||||
const [zaehlerAktiv, setZaehlerAktiv] = useState(false);
|
||||
const [eingangOffline, setEingangOffline] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (reduxInput && isInitialLoad) {
|
||||
@@ -31,6 +32,7 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
setFilterzeit(reduxInput.filterzeit);
|
||||
setGewichtung(reduxInput.gewichtung);
|
||||
setZaehlerAktiv(reduxInput.zaehlerAktiv);
|
||||
setEingangOffline(reduxInput.eingangOffline);
|
||||
setIsInitialLoad(false);
|
||||
}
|
||||
}, [reduxInput, isInitialLoad]);
|
||||
@@ -76,6 +78,10 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
await sendCgiUpdate(`DEZ${id}=${zaehlerAktiv ? 1 : 0}`);
|
||||
hasChange = true;
|
||||
}
|
||||
if (eingangOffline !== reduxInput.eingangOffline) {
|
||||
await sendCgiUpdate(`DEO${id}=${eingangOffline ? 1 : 0}`);
|
||||
hasChange = true;
|
||||
}
|
||||
if (!hasChange) {
|
||||
alert("⚠️ Keine Änderungen erkannt.");
|
||||
return;
|
||||
@@ -141,30 +147,13 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
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="bg-white rounded-lg shadow-lg p-6 w-1/2 max-w-lg">
|
||||
<h2 className="text-xl font-semibold text-blue-500 mb-4 border-b pb-2">
|
||||
Parameter für Eingang {selectedInput.id}
|
||||
<h2 className="text-base font-bold mb-4 border-b pb-2">
|
||||
Einstellungen Eingang {selectedInput.id}
|
||||
</h2>
|
||||
|
||||
<div className="grid grid-cols-2 gap-x-4 gap-y-3">
|
||||
<div>
|
||||
<strong>Zustand:</strong>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-xl font-semibold col-span-1">
|
||||
{reduxInput.status ? (
|
||||
<>
|
||||
<span className="text-red-500 text-2xl">●</span>
|
||||
<span className="text-red-600">Aus</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="text-green-500 text-2xl">●</span>
|
||||
<span className="text-green-600">Ein</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Name:</strong>
|
||||
<span className="font-normal">Bezeichnung:</span>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
@@ -177,17 +166,16 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Invertierung:</strong>
|
||||
<span className="font-normal">Invertierung:</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span>{invertiert ? "Ein" : "Aus"}</span>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={invertiert}
|
||||
onClick={() => setInvertiert(!invertiert)}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors duration-200 ${
|
||||
invertiert ? "bg-green-500" : "bg-gray-300"
|
||||
invertiert ? "bg-littwin-blue" : "bg-gray-300"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
@@ -196,17 +184,11 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
<span>{invertiert ? "Ein" : "Aus"}</span>
|
||||
</div>
|
||||
{/* Zählerstand ausblenden */}
|
||||
{/*
|
||||
<div>
|
||||
<strong>Zählerstand:</strong>
|
||||
</div>
|
||||
<div>{reduxInput.counter}</div>
|
||||
*/}
|
||||
|
||||
<div>
|
||||
<strong>Filterzeit:</strong>
|
||||
<span className="font-normal">Filterzeit:</span>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<input
|
||||
@@ -220,16 +202,17 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
setFilterzeit(val);
|
||||
}
|
||||
}}
|
||||
className="border border-gray-300 rounded px-2 py-1 pr-10 w-full"
|
||||
className="border border-gray-300 rounded px-2 py-1 pr-10 w-full text-right"
|
||||
title="Maximal 2000 ms erlaubt"
|
||||
/>
|
||||
|
||||
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
||||
ms
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<strong>Gewichtung:</strong>
|
||||
<span className="font-normal">Gewichtung:</span>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
@@ -243,57 +226,45 @@ export default function InputModal({ selectedInput, closeInputModal, isOpen }) {
|
||||
setGewichtung(val);
|
||||
}
|
||||
}}
|
||||
className="border border-gray-300 rounded px-2 py-1 w-full"
|
||||
className="border border-gray-300 rounded px-2 py-1 w-full text-right"
|
||||
title="Maximal 1000 erlaubt"
|
||||
/>
|
||||
</div>
|
||||
{/* Zähler aktiv ausblenden */}
|
||||
{/*
|
||||
|
||||
<div>
|
||||
<strong>Zähler aktiv:</strong>
|
||||
|
||||
<div className="relative group inline-block">
|
||||
<span className="font-normal">Out of Service:</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<span>{zaehlerAktiv ? "Ja" : "Nein"}</span>
|
||||
<button
|
||||
type="button"
|
||||
role="switch"
|
||||
aria-checked={zaehlerAktiv}
|
||||
onClick={() => setZaehlerAktiv(!zaehlerAktiv)}
|
||||
aria-checked={eingangOffline}
|
||||
onClick={() => setEingangOffline(!eingangOffline)}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors duration-200 ${
|
||||
zaehlerAktiv ? "bg-green-500" : "bg-gray-300"
|
||||
eingangOffline ? "bg-littwin-blue" : "bg-gray-300"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform duration-200 ${
|
||||
zaehlerAktiv ? "translate-x-6" : "translate-x-1"
|
||||
eingangOffline ? "translate-x-6" : "translate-x-1"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
<span>{eingangOffline ? "Ein" : "Aus"}</span>
|
||||
</div>
|
||||
|
||||
*/}
|
||||
|
||||
<div className="relative group inline-block">
|
||||
<strong>OOS:</strong>
|
||||
<span className="absolute top-full left-1/2 -translate-x-1/2 mt-1 px-2 py-1 text-xs text-white bg-gray-700 rounded opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
Out of Service
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>{reduxInput.eingangOffline ? "aus" : "ein"}</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex justify-end gap-2">
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="px-4 py-2 bg-gray-300 hover:bg-gray-400 text-black rounded-lg transition"
|
||||
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
||||
>
|
||||
Schließen
|
||||
</button>
|
||||
<button
|
||||
onClick={handleSpeichern}
|
||||
className="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-lg transition"
|
||||
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
|
||||
@@ -164,26 +164,30 @@ export default function KueEinstellung({
|
||||
<h3 className="font-bold mb-2">Isolationsmessung</h3>
|
||||
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
||||
<label className="w-48 ">Grenzwert:</label>
|
||||
<div>
|
||||
<div className="relative w-36">
|
||||
<input
|
||||
type="number"
|
||||
className="w-24 border rounded p-1 mr-2 text-right"
|
||||
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
||||
value={formData.limit1}
|
||||
onChange={(e) => handleChange("limit1", e.target.value)}
|
||||
/>
|
||||
<span>MOhm</span>
|
||||
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
||||
MOhm
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
||||
<label className="w-48 ">Verzögerung:</label>
|
||||
<div>
|
||||
<div className="relative w-36">
|
||||
<input
|
||||
type="number"
|
||||
className="w-24 border rounded p-1 mr-2 text-right"
|
||||
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
||||
value={formData.delay1}
|
||||
onChange={(e) => handleChange("delay1", e.target.value)}
|
||||
/>
|
||||
<span>Sekunden</span>
|
||||
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
||||
Sekunden
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -192,26 +196,30 @@ export default function KueEinstellung({
|
||||
<h3 className="font-bold mb-2">Schleifenmessung</h3>
|
||||
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
||||
<label className="w-48 ">Grenzwert:</label>
|
||||
<div>
|
||||
<div className="relative w-36">
|
||||
<input
|
||||
type="number"
|
||||
className="w-24 border rounded p-1 mr-2 text-right"
|
||||
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
||||
value={formData.limit2Low}
|
||||
onChange={(e) => handleChange("limit2Low", e.target.value)}
|
||||
/>
|
||||
<span>kOhm</span>
|
||||
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
||||
kOhm
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
||||
<label className="w-48 ">Schleifenmessintervall:</label>
|
||||
<div>
|
||||
<div className="relative w-36">
|
||||
<input
|
||||
type="number"
|
||||
className="w-24 border rounded p-1 mr-2 text-right"
|
||||
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
||||
value={formData.loopInterval}
|
||||
onChange={(e) => handleChange("loopInterval", e.target.value)}
|
||||
/>
|
||||
<span>Stunden</span>
|
||||
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
||||
Stunden
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -189,10 +189,10 @@ export default function TdrEinstellung({ slot, onClose }: Props) {
|
||||
<div className="mt-6 mb-4">
|
||||
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
||||
<label className="">TDR Dämpfung:</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative w-36">
|
||||
<input
|
||||
type="number"
|
||||
className="w-24 border rounded p-1 mr-2 text-right"
|
||||
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
||||
value={tdrData.daempfung}
|
||||
onChange={(e) => {
|
||||
const updated = { ...tdrData, daempfung: e.target.value };
|
||||
@@ -200,15 +200,17 @@ export default function TdrEinstellung({ slot, onClose }: Props) {
|
||||
updateCache(updated);
|
||||
}}
|
||||
/>
|
||||
<span>dB</span>
|
||||
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
||||
dB
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
||||
<label className="">Geschwindigkeit:</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="relative w-36">
|
||||
<input
|
||||
type="number"
|
||||
className="w-24 border rounded p-1 mr-2 text-right"
|
||||
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
||||
value={tdrData.geschwindigkeit}
|
||||
onChange={(e) => {
|
||||
const updated = { ...tdrData, geschwindigkeit: e.target.value };
|
||||
@@ -216,7 +218,9 @@ export default function TdrEinstellung({ slot, onClose }: Props) {
|
||||
updateCache(updated);
|
||||
}}
|
||||
/>
|
||||
<span>m/µs</span>
|
||||
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
||||
m/µs
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
2: Patch oder Hotfix (Bugfixes oder kleine Änderungen).
|
||||
|
||||
*/
|
||||
const webVersion = "1.6.369";
|
||||
const webVersion = "1.6.370";
|
||||
export default webVersion;
|
||||
|
||||
@@ -43,7 +43,7 @@ const EinAusgaenge: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3 p-4 h-[calc(100vh-13vh-8vh)] laptop:h-[calc(100vh-10vh-5vh)] xl:h-[calc(100vh-10vh-6vh)] laptop:gap-0">
|
||||
<h1 className="text-base font-semibold mb-2">Ein- und Ausgänge</h1>
|
||||
<h1 className="text-base font-semibold mb-2">Schaltausgänge</h1>
|
||||
|
||||
<div className="grid grid-cols-1 xl:grid-cols-3 gap-4 items-start ">
|
||||
<DigitalOutputs openOutputModal={openOutputModal} />
|
||||
|
||||
7
public/images/analogInputIcon.svg
Normal file
7
public/images/analogInputIcon.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="#FFFFFF" stroke="#00B0F0" stroke-width="1.06497" stroke-linecap="round" stroke-linejoin="round">
|
||||
<!-- Rahmen -->
|
||||
<rect x="1" y="1" width="30" height="30" rx="4" ry="4" fill="none" stroke="#00B0F0" stroke-width="1.5" />
|
||||
|
||||
<!-- Wellenlinie -->
|
||||
<path d="M4 16h3l3 8 4-16 3 8h11" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 382 B |
3
public/images/analogeEingaengeIcon.svg
Normal file
3
public/images/analogeEingaengeIcon.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#FFFFFF" stroke="#00B0F0" stroke-width="1.06497" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 12h3l3 8 4-16 3 8h7" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 231 B |
Reference in New Issue
Block a user