Compare commits

2 Commits

10 changed files with 195 additions and 146 deletions

View File

@@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false
NEXT_PUBLIC_EXPORT_STATIC=false
NEXT_PUBLIC_USE_CGI=false
# App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.6.867
NEXT_PUBLIC_APP_VERSION=1.6.869
NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (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_USE_CGI=true
# App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.6.867
NEXT_PUBLIC_APP_VERSION=1.6.869
NEXT_PUBLIC_CPL_MODE=production

View File

@@ -1,3 +1,13 @@
## [1.6.869] 2025-09-08
- fix: Beim Ausführen einer TDR-Messung (Klick auf blauen Button in der TDR-Detailseite) erscheint keine Rückmeldung. Dort müsste ein Hinweis erscheinen “TDR-Messung wird ausgeführt und kann bis zu zwei Minuten dauern”
---
## [1.6.868] 2025-09-08
- fix: Timer für jeder KÜ separate und nicht eine für alle, aktuell wird prozentzahl bei allen das gleiche angezeigt
---
## [1.6.867] 2025-09-08
- WIP: Timer für jeder KÜ separate und nicht eine für alle, aktuell wird prozentzahl bei allen das gleiche angezeigt

View File

@@ -389,7 +389,8 @@ const LoopChartActionBar = forwardRef((_props, ref) => {
<div className="mb-4 text-center space-y-1">
<p className="text-lg font-semibold">RSL Messung läuft</p>
<p className="text-sm text-gray-700">
Bitte warten (noch {TOTAL_DURATION - rslProgress}s)
Bitte warten{" "}
{Math.min(100, Math.round((rslProgress / TOTAL_DURATION) * 100))}%
</p>
</div>
<div className="w-2/3 max-w-xl h-4 bg-gray-200 rounded overflow-hidden shadow-inner">

View File

@@ -30,6 +30,36 @@ const TDRChartActionBar: React.FC = () => {
const [selectedId, setSelectedId] = useState<number | null>(null);
const currentChartData = selectedId !== null ? tdrDataById[selectedId] : [];
// ▶ Fortschrittsanzeige für laufende TDR-Messung (max. 120s bzw. konfigurierbar)
const TDR_TOTAL_DURATION = parseInt(
process.env.NEXT_PUBLIC_TDR_DURATION_SECONDS || "120",
10
);
const [tdrRunning, setTdrRunning] = useState(false);
const [tdrProgress, setTdrProgress] = useState(0); // Sekunden
useEffect(() => {
if (!tdrRunning) return;
setTdrProgress(0);
const startedAt = Date.now();
const interval = setInterval(() => {
const elapsed = Math.floor((Date.now() - startedAt) / 1000);
if (elapsed >= TDR_TOTAL_DURATION) {
setTdrProgress(TDR_TOTAL_DURATION);
setTdrRunning(false);
clearInterval(interval);
} else {
setTdrProgress(elapsed);
}
}, 1000);
return () => clearInterval(interval);
}, [tdrRunning, TDR_TOTAL_DURATION]);
const startTdrProgress = () => {
setTdrRunning(true);
setTdrProgress(0);
};
// 📌 Referenz setzen (nutzt Slotnummer + 1 für die API)
const handleSetReference = async () => {
if (
@@ -94,15 +124,19 @@ const TDRChartActionBar: React.FC = () => {
try {
console.log("🚀 Starte TDR Messung für Slot:", selectedSlot);
console.log("📡 CGI URL:", cgiUrl);
const response = await fetch(cgiUrl);
if (!response.ok) {
throw new Error(`CGI-Fehler: ${response.status}`);
const isDev = process.env.NEXT_PUBLIC_NODE_ENV === "development";
if (isDev) {
// Dev / Simulator: sofort starten & Progress anzeigen
await new Promise((r) => setTimeout(r, 150));
console.log("✅ [DEV] TDR Mock-Start ok für Slot", selectedSlot);
startTdrProgress();
return;
}
const response = await fetch(cgiUrl);
if (!response.ok) throw new Error(`CGI-Fehler: ${response.status}`);
console.log("✅ TDR Messung gestartet für Slot", selectedSlot);
//alert(`✅ TDR Messung für Slot ${selectedSlot + 1} gestartet`);
startTdrProgress();
} catch (err) {
console.error("❌ Fehler beim Starten der TDR Messung:", err);
//alert("❌ Fehler beim Starten der TDR Messung.");
@@ -130,6 +164,7 @@ const TDRChartActionBar: React.FC = () => {
}, [selectedSlot, dispatch]);
return (
<>
<div className="flex justify-between items-center p-2 bg-gray-100 rounded-lg space-x-4">
{/* 🧩 Slot-Anzeige (1-basiert für Benutzer) */}
<div className="text-sm font-semibold">
@@ -150,9 +185,14 @@ const TDRChartActionBar: React.FC = () => {
<button
onClick={handleStartTDR}
className="px-4 py-1 bg-littwin-blue text-white rounded text-sm whitespace-nowrap "
disabled={selectedSlot === null}
disabled={selectedSlot === null || tdrRunning}
>
TDR-Messung starten
{tdrRunning
? `TDR läuft... (${Math.min(
100,
Math.round((tdrProgress / TDR_TOTAL_DURATION) * 100)
)}%)`
: "TDR-Messung starten"}
</button>
{/* 🔽 Dropdown für Messungen */}
@@ -233,6 +273,30 @@ const TDRChartActionBar: React.FC = () => {
</Listbox>
</div>
</div>
{tdrRunning && (
<div className="fixed inset-0 z-[1000] flex flex-col items-center justify-center bg-white/80 backdrop-blur-sm">
<div className="mb-4 text-center space-y-1">
<p className="text-lg font-semibold">TDR Messung läuft</p>
<p className="text-sm text-gray-700">
Bitte warten{" "}
{Math.min(
100,
Math.round((tdrProgress / TDR_TOTAL_DURATION) * 100)
)}
%
</p>
</div>
<div className="w-2/3 max-w-xl h-4 bg-gray-200 rounded overflow-hidden shadow-inner">
<div
className="h-full bg-littwin-blue transition-all ease-linear"
style={{
width: `${(tdrProgress / TDR_TOTAL_DURATION) * 100}%`,
}}
/>
</div>
</div>
)}
</>
);
};

View File

@@ -174,18 +174,6 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
const openTdrModal = () => {
setActiveButton("TDR");
setloopTitleText("Entfernung [km]");
const latestTdrDistanceMeters =
Array.isArray(tdmChartData?.[slotIndex]) &&
tdmChartData[slotIndex].length > 0 &&
typeof tdmChartData[slotIndex][0].d === "number"
? tdmChartData[slotIndex][0].d
: 0;
const latestTdrDistance = Number(
(latestTdrDistanceMeters / 1000).toFixed(3)
);
setLoopDisplayValue(latestTdrDistance);
setShowTdrModal(true);
};
@@ -272,30 +260,16 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
return () => window.removeEventListener("resize", measure);
}, [moduleName48, scrollFeatureEnabled]);
//---------------------------------
const tdmChartData = useSelector(
(state: RootState) => state.tdmChartSlice.data
);
const latestTdrDistanceMeters =
Array.isArray(tdmChartData?.[slotIndex]) &&
tdmChartData[slotIndex].length > 0 &&
typeof tdmChartData[slotIndex][0].d === "number"
? tdmChartData[slotIndex][0].d
: 0;
const latestTdrDistance = Number((latestTdrDistanceMeters / 1000).toFixed(3));
//setLoopDisplayValue(latestTdrDistance);
// TDR Distanz wird im Display nicht angezeigt Daten für Modal werden separat geladen
//---------------------------------
const loopValue =
activeButton === "TDR"
? latestTdrDistance
: typeof schleifenwiderstand === "number"
const rslValue =
typeof schleifenwiderstand === "number"
? schleifenwiderstand
: Number(schleifenwiderstand);
const { loopDisplayValue, setLoopDisplayValue } = useLoopDisplay(
loopValue,
rslValue,
activeButton
);
@@ -409,7 +383,7 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
.toFixed(2)
.replace(".", ",")} MOhm`}
</span>
{/* 3. Zeile: Schleifenwert, in Rot bei Schleifenfehler, sonst normal */}
{/* 3. Zeile: Schleifenwert (RSL) immer anzeigen, unabhängig von aktivem Button */}
<span
className={`whitespace-nowrap block text-[0.65rem] font-semibold ${
Number(kueAlarm2?.[slotIndex]) === 1 ? "text-red-500" : ""

View File

@@ -1,19 +1,19 @@
// components/main/kabelueberwachung/kue705FO/hooks/useLoopDisplay.ts
import { useEffect, useState } from "react";
// Keeps and updates the loop (RSL) display value only when "Schleife" active.
// For ISO or TDR views we do not overwrite the displayed RSL value.
const useLoopDisplay = (
schleifenwiderstand: number,
rslValue: number,
activeButton: "Schleife" | "TDR" | "ISO"
) => {
const [loopDisplayValue, setLoopDisplayValue] =
useState<number>(schleifenwiderstand);
const [loopDisplayValue, setLoopDisplayValue] = useState<number>(rslValue);
useEffect(() => {
if (activeButton === "Schleife") {
setLoopDisplayValue(schleifenwiderstand);
setLoopDisplayValue(rslValue);
}
// For ISO and TDR, the value is set manually via setLoopDisplayValue
}, [schleifenwiderstand, activeButton]);
}, [rslValue, activeButton]);
return { loopDisplayValue, setLoopDisplayValue };
};

View File

@@ -271,7 +271,7 @@ var tdrMeasurementEvent = [
//Event Abgleich
var comparisonEvent = [
// renamed from alignmentEvent
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
];
// expose for browser simulation

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "cpl-v4",
"version": "1.6.867",
"version": "1.6.869",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cpl-v4",
"version": "1.6.867",
"version": "1.6.869",
"dependencies": {
"@fontsource/roboto": "^5.1.0",
"@headlessui/react": "^2.2.4",

View File

@@ -1,6 +1,6 @@
{
"name": "cpl-v4",
"version": "1.6.867",
"version": "1.6.869",
"private": true,
"scripts": {
"dev": "next dev -p 3000",