feat: Overlay nicht über die Seite sondern nur über den KÜ Slot wenn ein Event kommt
This commit is contained in:
@@ -6,6 +6,6 @@ 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.711
|
NEXT_PUBLIC_APP_VERSION=1.6.712
|
||||||
NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter)
|
NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter)
|
||||||
|
|
||||||
|
|||||||
@@ -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.711
|
NEXT_PUBLIC_APP_VERSION=1.6.712
|
||||||
NEXT_PUBLIC_CPL_MODE=production
|
NEXT_PUBLIC_CPL_MODE=production
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
## [1.6.712] – 2025-08-13
|
||||||
|
|
||||||
|
- doc in TODO
|
||||||
|
|
||||||
|
---
|
||||||
## [1.6.711] – 2025-08-13
|
## [1.6.711] – 2025-08-13
|
||||||
|
|
||||||
- CPL Events Progressbar in Prozent anzeigen
|
- CPL Events Progressbar in Prozent anzeigen
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import IsoChartView from "./Charts/IsoMeasurementChart/IsoChartView";
|
|||||||
import LoopChartView from "./Charts/LoopMeasurementChart/LoopChartView";
|
import LoopChartView from "./Charts/LoopMeasurementChart/LoopChartView";
|
||||||
import TDRChartView from "./Charts/TDRChart/TDRChartView";
|
import TDRChartView from "./Charts/TDRChart/TDRChartView";
|
||||||
import KVZChartView from "./Charts/KVZChart/KVZChartView";
|
import KVZChartView from "./Charts/KVZChart/KVZChartView";
|
||||||
|
import SlotActivityOverlay from "./SlotActivityOverlay";
|
||||||
// Keep ChartSwitcher import for backwards compatibility if needed
|
// Keep ChartSwitcher import for backwards compatibility if needed
|
||||||
// import ChartSwitcher from "./Charts/ChartSwitcher";
|
// import ChartSwitcher from "./Charts/ChartSwitcher";
|
||||||
// Remove separate chart imports since we use ChartView components
|
// Remove separate chart imports since we use ChartView components
|
||||||
@@ -251,6 +252,8 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
|
|||||||
className="relative bg-gray-300 w-[7.25rem] h-[23.375rem] border border-gray-400 transform laptop:-translate-y-12 2xl:-translate-y-0
|
className="relative bg-gray-300 w-[7.25rem] h-[23.375rem] border border-gray-400 transform laptop:-translate-y-12 2xl:-translate-y-0
|
||||||
scale-100 sm:scale-95 md:scale-100 lg:scale-105 xl:scale-90 2xl:scale-125 top-3 qhd:scale-150 qhd:-translate-y-0"
|
scale-100 sm:scale-95 md:scale-100 lg:scale-105 xl:scale-90 2xl:scale-125 top-3 qhd:scale-150 qhd:-translate-y-0"
|
||||||
>
|
>
|
||||||
|
{/* Per-slot activity overlay */}
|
||||||
|
<SlotActivityOverlay slotIndex={slotIndex} />
|
||||||
{kueOnline === 1 ? (
|
{kueOnline === 1 ? (
|
||||||
<>
|
<>
|
||||||
<div className="relative w-[7.075rem] h-[15.156rem] bg-littwin-blue border-[0.094rem] border-gray-400 z-0">
|
<div className="relative w-[7.075rem] h-[15.156rem] bg-littwin-blue border-[0.094rem] border-gray-400 z-0">
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
"use client";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { useAppSelector } from "@/redux/store";
|
||||||
|
|
||||||
|
export default function SlotActivityOverlay({
|
||||||
|
slotIndex,
|
||||||
|
}: {
|
||||||
|
slotIndex: number;
|
||||||
|
}) {
|
||||||
|
const ksx = useAppSelector((s) => s.deviceEvents.ksx);
|
||||||
|
const ksy = useAppSelector((s) => s.deviceEvents.ksy);
|
||||||
|
const ksz = useAppSelector((s) => s.deviceEvents.ksz);
|
||||||
|
const loopStartedAt = useAppSelector((s) => s.deviceEvents.loopStartedAt);
|
||||||
|
const tdrStartedAt = useAppSelector((s) => s.deviceEvents.tdrStartedAt);
|
||||||
|
const alignmentStartedAt = useAppSelector(
|
||||||
|
(s) => s.deviceEvents.alignmentStartedAt
|
||||||
|
);
|
||||||
|
|
||||||
|
const loopActive = Array.isArray(ksx) && ksx[slotIndex] === 1;
|
||||||
|
const tdrActive = Array.isArray(ksy) && ksy[slotIndex] === 1;
|
||||||
|
const alignActive = Array.isArray(ksz) && ksz[slotIndex] === 1;
|
||||||
|
|
||||||
|
// Progress ticker
|
||||||
|
const [now, setNow] = useState<number>(Date.now());
|
||||||
|
useEffect(() => {
|
||||||
|
const any = loopActive || tdrActive || alignActive;
|
||||||
|
if (!any) return;
|
||||||
|
const id = setInterval(() => setNow(Date.now()), 1000);
|
||||||
|
return () => clearInterval(id);
|
||||||
|
}, [loopActive, tdrActive, alignActive]);
|
||||||
|
|
||||||
|
const clamp = (v: number, min = 0, max = 1) =>
|
||||||
|
Math.max(min, Math.min(max, v));
|
||||||
|
const compute = (startedAt: number | null, durationMs: number) => {
|
||||||
|
if (!startedAt) return { pct: 0 };
|
||||||
|
const elapsed = now - startedAt;
|
||||||
|
const pct = clamp(elapsed / durationMs) * 100;
|
||||||
|
return { pct };
|
||||||
|
};
|
||||||
|
|
||||||
|
// Durations
|
||||||
|
const LOOP_MS = 2 * 60 * 1000; // ~2 min
|
||||||
|
const TDR_MS = 30 * 1000; // ~30 s
|
||||||
|
const ALIGN_MS = 10 * 60 * 1000; // ~10 min
|
||||||
|
|
||||||
|
if (!loopActive && !tdrActive && !alignActive) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute inset-0 z-20 flex items-center justify-center bg-white/70 backdrop-blur-sm">
|
||||||
|
<div className="p-2 rounded-md shadow bg-white/90 border border-gray-200 w-[min(90%,12rem)]">
|
||||||
|
<div className="text-[0.75rem] font-semibold mb-2 text-gray-800">
|
||||||
|
Bitte warten…
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{loopActive && (
|
||||||
|
<div>
|
||||||
|
<div className="text-[0.7rem] text-gray-800 mb-1">Schleife</div>
|
||||||
|
{(() => {
|
||||||
|
const { pct } = compute(loopStartedAt, LOOP_MS);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="h-2 w-full bg-gray-200 rounded overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="h-full bg-littwin-blue transition-all"
|
||||||
|
style={{ width: `${pct}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-[0.65rem] text-gray-700 mt-1">
|
||||||
|
{Math.round(pct)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{tdrActive && (
|
||||||
|
<div>
|
||||||
|
<div className="text-[0.7rem] text-gray-800 mb-1">TDR</div>
|
||||||
|
{(() => {
|
||||||
|
const { pct } = compute(tdrStartedAt, TDR_MS);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="h-2 w-full bg-gray-200 rounded overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="h-full bg-littwin-blue transition-all"
|
||||||
|
style={{ width: `${pct}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-[0.65rem] text-gray-700 mt-1">
|
||||||
|
{Math.round(pct)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{alignActive && (
|
||||||
|
<div>
|
||||||
|
<div className="text-[0.7rem] text-gray-800 mb-1">Abgleich</div>
|
||||||
|
{(() => {
|
||||||
|
const { pct } = compute(alignmentStartedAt, ALIGN_MS);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="h-2 w-full bg-gray-200 rounded overflow-hidden">
|
||||||
|
<div
|
||||||
|
className="h-full bg-littwin-blue transition-all"
|
||||||
|
style={{ width: `${pct}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-[0.65rem] text-gray-700 mt-1">
|
||||||
|
{Math.round(pct)}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -260,16 +260,16 @@ var win_fallSensors = [
|
|||||||
|
|
||||||
// Event Schleifenmessung KSX
|
// Event Schleifenmessung KSX
|
||||||
var loopMeasurementEvent = [
|
var loopMeasurementEvent = [
|
||||||
0, 0, 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, 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,
|
||||||
];
|
];
|
||||||
//Event TDR-Messung
|
//Event TDR-Messung
|
||||||
var tdrMeasurementEvent = [
|
var tdrMeasurementEvent = [
|
||||||
0, 0, 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, 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,
|
||||||
];
|
];
|
||||||
//Event Abgleich
|
//Event Abgleich
|
||||||
var alignmentEvent = [
|
var alignmentEvent = [
|
||||||
0, 0, 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, 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,
|
||||||
];
|
];
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.711",
|
"version": "1.6.712",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.711",
|
"version": "1.6.712",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/roboto": "^5.1.0",
|
"@fontsource/roboto": "^5.1.0",
|
||||||
"@headlessui/react": "^2.2.4",
|
"@headlessui/react": "^2.2.4",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cpl-v4",
|
"name": "cpl-v4",
|
||||||
"version": "1.6.711",
|
"version": "1.6.712",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { store } from "@/redux/store";
|
|||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
import DeviceEventsBridge from "@/components/common/DeviceEventsBridge";
|
import DeviceEventsBridge from "@/components/common/DeviceEventsBridge";
|
||||||
import GlobalActivityOverlay from "@/components/common/GlobalActivityOverlay";
|
import GlobalActivityOverlay from "@/components/common/GlobalActivityOverlay";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
|
||||||
// Thunks importieren
|
// Thunks importieren
|
||||||
import { getKueDataThunk } from "@/redux/thunks/getKueDataThunk";
|
import { getKueDataThunk } from "@/redux/thunks/getKueDataThunk";
|
||||||
@@ -67,6 +68,7 @@ function AppContent({
|
|||||||
pageProps: AppProps["pageProps"];
|
pageProps: AppProps["pageProps"];
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
const pathnameHook = usePathname();
|
||||||
const [sessionExpired] = useState(false);
|
const [sessionExpired] = useState(false);
|
||||||
const mode = "DIA0"; // oder aus Router oder Session
|
const mode = "DIA0"; // oder aus Router oder Session
|
||||||
const type = 0; // Beispiel: 0 für "loop", 1 für "iso" (bitte ggf. anpassen)
|
const type = 0; // Beispiel: 0 für "loop", 1 für "iso" (bitte ggf. anpassen)
|
||||||
@@ -160,7 +162,10 @@ function AppContent({
|
|||||||
)}
|
)}
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
<ToastContainer position="top-right" autoClose={3000} />
|
<ToastContainer position="top-right" autoClose={3000} />
|
||||||
<GlobalActivityOverlay />
|
{/* Hide global overlay on kabelueberwachung page so only per-slot overlays show */}
|
||||||
|
{pathnameHook?.includes("kabelueberwachung") ? null : (
|
||||||
|
<GlobalActivityOverlay />
|
||||||
|
)}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
Reference in New Issue
Block a user