feat: dynamische URL-Anpassung für Entwicklungs- und Produktionsumgebung
- Navigation und Weiterleitungen angepasst, um dynamisch `.html`-Endungen in Produktionsumgebung anzuhängen. - Nutzung von `NEXT_PUBLIC_NODE_ENV` ermöglicht unterschiedliche URL-Strukturen in Entwicklungs- und Produktionsumgebung. - `Navigation`-Komponente und `index.js` entsprechend konfiguriert, um `.html` in der Produktionsumgebung automatisch anzuhängen. - Verbesserte Konsistenz und Funktionalität zwischen beiden Umgebungen, 404-Fehler in Produktion behoben.
This commit is contained in:
34
pages/_app.js
Normal file
34
pages/_app.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import { useEffect } from "react";
|
||||
import Header from "../components/Header";
|
||||
import Navigation from "../components/Navigation";
|
||||
import Footer from "../components/Footer";
|
||||
import "../styles/globals.css";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
// Client-seitige Logik kann hier hinzugefügt werden
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
console.log("Client-side logic can run here.");
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-gray-100 flex flex-col min-h-screen overflow-hidden">
|
||||
<Header />
|
||||
<div className="flex flex-grow w-full">
|
||||
{" "}
|
||||
{/* Flexbox-Container für Navigation und Content */}
|
||||
<Navigation className="w-1/5" />{" "}
|
||||
{/* Navigation nimmt 20% der Breite ein */}
|
||||
<main className="flex-1 p-4">
|
||||
{" "}
|
||||
{/* Der Content nimmt den restlichen Platz ein */}
|
||||
<Component {...pageProps} />
|
||||
</main>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
16
pages/_document.js
Normal file
16
pages/_document.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Html, Head, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="de">
|
||||
<Head>
|
||||
{/* Füge Meta-Tags, CSS-Links und andere Header-Inhalte hier hinzu */}
|
||||
<link rel="icon" href="/favicon.png" type="image/png" />
|
||||
</Head>
|
||||
<body>
|
||||
<Main /> {/* Hier wird der Seiteninhalt eingebettet */}
|
||||
<NextScript /> {/* Fügt Next.js-Skripte für die Seite hinzu */}
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
133
pages/access.js
Normal file
133
pages/access.js
Normal file
@@ -0,0 +1,133 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
|
||||
function Access() {
|
||||
return (
|
||||
<div className="bg-gray-100 min-h-screen p-8">
|
||||
<div className="bg-white rounded-lg shadow p-6 mb-8">
|
||||
<h2 className="text-xl font-bold text-blue-500 mb-4">
|
||||
Zutrittskontrolle 1
|
||||
</h2>
|
||||
<div className="flex justify-between">
|
||||
<div className="w-full lg:w-1/2 p-4">
|
||||
<table className="min-w-full text-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="py-3 px-4">
|
||||
<b>Betrieb</b>
|
||||
</td>
|
||||
<td className="py-3 px-4">Status: ...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">
|
||||
<b>Status</b>
|
||||
</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">Letzte Chip-ID</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">Zeitstempel</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">Access Typ</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="w-full lg:w-1/2 p-4">
|
||||
<table className="min-w-full text-sm">
|
||||
<thead className="bg-gray-200">
|
||||
<tr>
|
||||
<th className="py-3 px-4 text-center">Eingang</th>
|
||||
<th className="py-3 px-4 text-center">Zustand</th>
|
||||
<th className="py-3 px-4">Bezeichnung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="py-3 px-4 text-center">1</td>
|
||||
<td className="py-3 px-4 text-center">...</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4 text-center">2</td>
|
||||
<td className="py-3 px-4 text-center">...</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Zutrittskontrolle 2 */}
|
||||
<div className="bg-white rounded-lg shadow p-6">
|
||||
<h2 className="text-xl font-bold text-blue-500 mb-4">
|
||||
Zutrittskontrolle 2
|
||||
</h2>
|
||||
<div className="flex justify-between">
|
||||
<div className="w-full lg:w-1/2 p-4">
|
||||
<table className="min-w-full text-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="py-3 px-4">
|
||||
<b>Betrieb</b>
|
||||
</td>
|
||||
<td className="py-3 px-4">Status: ...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">
|
||||
<b>Status</b>
|
||||
</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">Letzte Chip-ID</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">Zeitstempel</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4">Access Typ</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="w-full lg:w-1/2 p-4">
|
||||
<table className="min-w-full text-sm">
|
||||
<thead className="bg-gray-200">
|
||||
<tr>
|
||||
<th className="py-3 px-4 text-center">Eingang</th>
|
||||
<th className="py-3 px-4 text-center">Zustand</th>
|
||||
<th className="py-3 px-4">Bezeichnung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="py-3 px-4 text-center">1</td>
|
||||
<td className="py-3 px-4 text-center">...</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 px-4 text-center">2</td>
|
||||
<td className="py-3 px-4 text-center">...</td>
|
||||
<td className="py-3 px-4">...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Access;
|
||||
222
pages/analogeEingaenge.js
Normal file
222
pages/analogeEingaenge.js
Normal file
@@ -0,0 +1,222 @@
|
||||
"use client";
|
||||
import React, { useState } from "react";
|
||||
|
||||
function AnalogeEingaenge() {
|
||||
const [activeConfig, setActiveConfig] = useState(null);
|
||||
|
||||
// Beispiel-Daten, du kannst die Daten dynamisch laden
|
||||
const inputs = [
|
||||
{
|
||||
id: 1,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
value: 0,
|
||||
name: "------------------",
|
||||
uG: true,
|
||||
uW: true,
|
||||
oW: true,
|
||||
oG: true,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="bg-gray-100 min-h-screen p-8">
|
||||
<h1 className="text-2xl font-bold mb-4">Analoge Eingänge</h1>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{inputs.map((input) => (
|
||||
<div key={input.id} className="bg-white rounded-lg shadow-lg p-6">
|
||||
<div className="flex justify-between items-center bg-blue-500 text-white rounded-t-lg p-4">
|
||||
<h2 className="text-lg">XIO-PM {input.id}</h2>
|
||||
<button
|
||||
className="bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded"
|
||||
onClick={() => setActiveConfig(input.id)}
|
||||
>
|
||||
Online
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-4">
|
||||
<table className="min-w-full bg-white border border-gray-300">
|
||||
<thead>
|
||||
<tr className="bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
|
||||
<th className="py-3 px-4 text-center">Eingang</th>
|
||||
<th className="py-3 px-4 text-center">Wert</th>
|
||||
<th className="py-3 px-4 text-left">Bezeichnung</th>
|
||||
<th className="py-3 px-4 text-center">uG</th>
|
||||
<th className="py-3 px-4 text-center">uW</th>
|
||||
<th className="py-3 px-4 text-center">oW</th>
|
||||
<th className="py-3 px-4 text-center">oG</th>
|
||||
<th className="py-3 px-4 text-center">Konfig</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-gray-600 text-sm">
|
||||
<tr className="border-b border-gray-200">
|
||||
<td className="py-3 px-4 text-center">{input.id}</td>
|
||||
<td className="py-3 px-4 text-right">{input.value}</td>
|
||||
<td className="py-3 px-4">{input.name}</td>
|
||||
<td className="py-3 px-4 text-center">
|
||||
<i
|
||||
className={`bi bi-circle-fill text-${
|
||||
input.uG ? "green" : "gray"
|
||||
}-500`}
|
||||
></i>
|
||||
</td>
|
||||
<td className="py-3 px-4 text-center">
|
||||
<i
|
||||
className={`bi bi-circle-fill text-${
|
||||
input.uW ? "green" : "gray"
|
||||
}-500`}
|
||||
></i>
|
||||
</td>
|
||||
<td className="py-3 px-4 text-center">
|
||||
<i
|
||||
className={`bi bi-circle-fill text-${
|
||||
input.oW ? "green" : "gray"
|
||||
}-500`}
|
||||
></i>
|
||||
</td>
|
||||
<td className="py-3 px-4 text-center">
|
||||
<i
|
||||
className={`bi bi-circle-fill text-${
|
||||
input.oG ? "green" : "gray"
|
||||
}-500`}
|
||||
></i>
|
||||
</td>
|
||||
<td className="py-3 px-4 text-center">
|
||||
<button
|
||||
className="text-blue-500"
|
||||
onClick={() => setActiveConfig(input.id)}
|
||||
>
|
||||
<i className="bi bi-gear-fill"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Modal für Konfiguration */}
|
||||
{activeConfig && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white p-8 rounded-lg shadow-lg w-96">
|
||||
<h2 className="text-xl font-bold mb-4">
|
||||
Konfiguration - XIO-PM {activeConfig}
|
||||
</h2>
|
||||
<button
|
||||
className="absolute top-4 right-4 text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setActiveConfig(null)}
|
||||
>
|
||||
<i className="bi bi-x-lg"></i>
|
||||
</button>
|
||||
{/* Konfigurationsformular hier einfügen */}
|
||||
<form>
|
||||
<div className="mb-4">
|
||||
<label
|
||||
className="block text-gray-700 text-sm font-bold mb-2"
|
||||
htmlFor="bezeichnung"
|
||||
>
|
||||
Bezeichnung
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="bezeichnung"
|
||||
name="bezeichnung"
|
||||
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
placeholder="Bezeichnung eingeben"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label
|
||||
className="block text-gray-700 text-sm font-bold mb-2"
|
||||
htmlFor="ug"
|
||||
>
|
||||
Unterer Grenzwert
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="ug"
|
||||
name="ug"
|
||||
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
placeholder="Wert eingeben"
|
||||
/>
|
||||
</div>
|
||||
{/* Weitere Felder hier hinzufügen */}
|
||||
<button
|
||||
type="button"
|
||||
className="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600"
|
||||
onClick={() => setActiveConfig(null)}
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AnalogeEingaenge;
|
||||
371
pages/dashboard.js
Normal file
371
pages/dashboard.js
Normal file
@@ -0,0 +1,371 @@
|
||||
"use client"; // app/dashboard/page.jsx
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import "tailwindcss/tailwind.css";
|
||||
import "@fontsource/roboto";
|
||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
import { loadWindowVariables } from "../utils/loadWindowVariables";
|
||||
import CPLStatus from "../components/modulesStatus/CPLStatus";
|
||||
import Access1Status from "../components/modulesStatus/Access1Status";
|
||||
import Access2Status from "../components/modulesStatus/Access2Status";
|
||||
import KabelModulStatus from "../components/modulesStatus/KabelModulStatus";
|
||||
import XioPM1Status from "../components/modulesStatus/XioPM1Status";
|
||||
import XioPM2Status from "../components/modulesStatus/XioPM2Status";
|
||||
import { Icon } from "@iconify/react";
|
||||
|
||||
function Dashboard() {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
const router = useRouter(); // Router instanzieren
|
||||
const [last20Messages, setLast20Messages] = useState([]);
|
||||
const [kueOnline, setkueOnline] = useState([]);
|
||||
const [ip, setIp] = useState("");
|
||||
const [subnet, setSubnet] = useState("");
|
||||
const [gateway, setGateway] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [kueCableBreak, setKueCableBreak] = useState([]);
|
||||
const [appVersion, setAppVersion] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
loadWindowVariables()
|
||||
.then(() => {
|
||||
if (window.last20Messages) {
|
||||
const parsedMessages = parseMessages(window.last20Messages);
|
||||
setLast20Messages(parsedMessages);
|
||||
setIp(window.ip);
|
||||
setSubnet(window.subnet);
|
||||
setGateway(window.gateway);
|
||||
setAppVersion(window.appVersion);
|
||||
} else {
|
||||
console.error("Konnte last20Messages nicht finden.");
|
||||
setError("Konnte last20Messages nicht finden.");
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Fehler beim Laden des Skripts:", error);
|
||||
setError(error);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
loadWindowVariables()
|
||||
.then(() => {
|
||||
if (window.kueCableBreak && Array.isArray(window.kueCableBreak)) {
|
||||
// Prüfe, ob window.kueCableBreak ein Array ist
|
||||
const cableBreakArray = window.kueCableBreak.map(Number);
|
||||
setKueCableBreak(cableBreakArray); // Array für kueCableBreak
|
||||
} else if (typeof window.kueCableBreak === "string") {
|
||||
// Falls es ein String ist, splitte den String und mappe ihn in ein Array
|
||||
const cableBreakArray = window.kueCableBreak.split(",").map(Number);
|
||||
setKueCableBreak(cableBreakArray);
|
||||
} else {
|
||||
console.error(
|
||||
"Konnte kueCableBreak nicht finden oder es ist kein gültiges Array/String."
|
||||
);
|
||||
setError(
|
||||
"Konnte kueCableBreak nicht finden oder es ist kein gültiges Array/String."
|
||||
);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Fehler beim Laden des Skripts:", error);
|
||||
setError(error);
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const parseMessages = (messages) => {
|
||||
messages = messages
|
||||
.replace(/<tr>/g, "\n")
|
||||
.replace(/<\/?td>/g, "")
|
||||
.replace(/<\/tr>/g, "")
|
||||
.trim();
|
||||
|
||||
const rows = messages.split("\n");
|
||||
return rows.map((row) => {
|
||||
const columns = [
|
||||
row.substring(0, 5), // ID
|
||||
row.substring(5, 10), // Wert (z.B. Modulnummer)
|
||||
row.substring(10, 29), // Zeitstempel, Millisekunden entfernt :000
|
||||
row.substring(33, row.length - 1), // Meldung (ohne letztes Zeichen)
|
||||
row.substring(row.length - 1), // Status (letztes Zeichen)
|
||||
];
|
||||
return columns;
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
loadWindowVariables()
|
||||
.then(() => {
|
||||
// console.log("kueOnline Data: ", window.kueOnline); // Debug: Ausgabe von kueOnline
|
||||
|
||||
if (window.kueOnline) {
|
||||
if (Array.isArray(window.kueOnline)) {
|
||||
const versionArray = window.kueOnline.map(Number);
|
||||
setkueOnline(versionArray);
|
||||
} else {
|
||||
console.error("kueOnline ist kein Array:", window.kueOnline);
|
||||
setError("Konnte kueOnline nicht als Array verarbeiten.");
|
||||
}
|
||||
} else {
|
||||
console.error("Konnte kueOnline nicht finden.");
|
||||
setError("Konnte kueOnline nicht finden.");
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Fehler beim Laden des Skripts:", error);
|
||||
setError(error);
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
loadWindowVariables()
|
||||
.then(() => {
|
||||
// Debug-Ausgaben für kueAlarm1 und kueAlarm2
|
||||
//console.log("kueAlarm1 Data: ", window.kueAlarm1);
|
||||
//console.log("kueAlarm2 Data: ", window.kueAlarm2);
|
||||
|
||||
if (window.kueAlarm1 && Array.isArray(window.kueAlarm1)) {
|
||||
//console.log("kueAlarm1 ist ein Array:", window.kueAlarm1);
|
||||
} else {
|
||||
console.error("kueAlarm1 ist kein Array oder nicht definiert.");
|
||||
setError(
|
||||
"Konnte kueAlarm1 nicht finden oder es ist kein gültiges Array."
|
||||
);
|
||||
}
|
||||
|
||||
if (window.kueAlarm2 && Array.isArray(window.kueAlarm2)) {
|
||||
//console.log("kueAlarm2 ist ein Array:", window.kueAlarm2);
|
||||
} else {
|
||||
console.error("kueAlarm2 ist kein Array oder nicht definiert.");
|
||||
setError(
|
||||
"Konnte kueAlarm2 nicht finden oder es ist kein gültiges Array."
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Fehler beim Laden des Skripts:", error);
|
||||
setError(error);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleModuleClick = (rackNumber) => {
|
||||
// Navigiere zu /kabelueberwachung und übermittle den rackNumber als Parameter
|
||||
router.push(`/kabelueberwachung?rack=${rackNumber}`);
|
||||
};
|
||||
|
||||
const renderBaugruppentraeger = () => {
|
||||
const baugruppen = [];
|
||||
const numBaugruppen = Math.ceil(kueOnline.length / 8);
|
||||
|
||||
for (let i = 0; i < numBaugruppen; i++) {
|
||||
const slots = kueOnline.slice(i * 8, (i + 1) * 8);
|
||||
|
||||
baugruppen.push(
|
||||
<div key={i} className="flex bg-white shadow-md rounded-lg mb-4">
|
||||
<div className="flex gap-1">
|
||||
{slots.map((version, index) => {
|
||||
const slotNumber = i * 8 + index + 1;
|
||||
const moduleVersion = window.kueVersion
|
||||
? window.kueVersion[slotNumber - 1]
|
||||
: version;
|
||||
|
||||
const hasAlarm1 = kueAlarm1.includes(slotNumber);
|
||||
const hasAlarm2 = kueAlarm2.includes(slotNumber);
|
||||
const hasCableBreak = kueCableBreak.includes(slotNumber);
|
||||
const alarmClass =
|
||||
hasAlarm1 || hasAlarm2 || hasCableBreak
|
||||
? "bg-red-500"
|
||||
: "bg-white";
|
||||
|
||||
return (
|
||||
<div
|
||||
key={slotNumber}
|
||||
className={`cursor-pointer ${alarmClass}`} // Sicherstellen, dass cursor-pointer hier verwendet wird
|
||||
onClick={() => handleModuleClick(i + 1)} // Bei Klick navigieren
|
||||
>
|
||||
<KabelModulStatus
|
||||
slot={slotNumber}
|
||||
isOnline={version !== 0} // Prüfen, ob ein Modul online ist
|
||||
moduleVersion={moduleVersion}
|
||||
kueCableBreak={kueCableBreak}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return baugruppen;
|
||||
};
|
||||
return (
|
||||
<div className="flex flex-col p-4">
|
||||
{/* Letzte Meldungen - Titel und Icon Bereich */}
|
||||
<div className="flex justify-between items-center w-full lg:w-2/3">
|
||||
<div className="flex justify-between gap-1">
|
||||
<Icon
|
||||
icon="ri:calendar-schedule-line"
|
||||
className="text-littwin-blue text-4xl"
|
||||
/>
|
||||
<h1 className="text-xl font-bold text-gray-700">
|
||||
Letzten 20 Meldungen
|
||||
</h1>
|
||||
</div>
|
||||
{/*
|
||||
<Icon
|
||||
icon="ph:trash"
|
||||
className="text-red-500 hover:text-red-600 mr-8 text-3xl cursor-pointer"
|
||||
/>
|
||||
*/}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col lg:flex-row gap-1 overflow-hidden">
|
||||
{/* Meldungen Liste */}
|
||||
<div className="bg-white shadow-md rounded-lg w-full lg:w-2/3 overflow-auto flex flex-grow">
|
||||
<table className="min-w-full border border-gray-200 text-left">
|
||||
<thead className="bg-gray-100 border-b border-gray-300">
|
||||
<tr>
|
||||
<th className="py-3 px-4 text-gray-700 text-sm font-medium">
|
||||
ID
|
||||
</th>
|
||||
<th className="py-3 px-4 text-gray-700 text-sm font-medium">
|
||||
Modul
|
||||
</th>
|
||||
<th className="py-3 px-4 text-gray-700 text-sm font-medium">
|
||||
Zeitstempel
|
||||
</th>
|
||||
<th className="py-3 px-4 text-gray-700 text-sm font-medium w-2/3">
|
||||
Meldung
|
||||
</th>
|
||||
<th className="py-3 px-4 text-gray-700 text-sm font-medium">
|
||||
Status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-xs text-gray-600 flex-shrink-0">
|
||||
{last20Messages.length > 0 ? (
|
||||
last20Messages.map((columns, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
className="border-b border-gray-200 hover:bg-gray-50"
|
||||
>
|
||||
<td className="py-1 px-4 w-1/7">{columns[0]}</td>
|
||||
<td className="py-1 px-4 w-1/7">{columns[1]}</td>
|
||||
<td className="py-1 px-4 w-3/7 whitespace-nowrap">
|
||||
<div className="flex flex-row space-x-2">
|
||||
<span>{columns[2].split(" ")[0]}</span>
|
||||
<span>{columns[2].split(" ")[1]}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-1 px-4 w-2/7">{columns[3]}</td>
|
||||
<td className="py-1 px-4 w-1/7">{columns[4]}</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td className="py-3 px-4 text-center" colSpan="5">
|
||||
Keine Meldungen verfügbar.
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Sidebar mit Informationen */}
|
||||
<div className="shadow-md rounded-lg lg:w-1/3 flex flex-col gap-2">
|
||||
{/* Versionsinformationen */}
|
||||
<div className="bg-gray-50 p-4 rounded-lg shadow-sm border border-gray-200">
|
||||
<h2 className="text-lg font-semibold text-gray-700 mb-2">
|
||||
Versionsinformationen
|
||||
</h2>
|
||||
<div className="flex flex-row p-2 space-x-2">
|
||||
<Icon icon="bx:code-block" className="text-xl text-blue-400" />
|
||||
<p className="text-sm text-gray-600">
|
||||
<span className="font-bold"></span> Applikationsversion:{" "}
|
||||
{appVersion}{" "}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-row p-2 space-x-2">
|
||||
<Icon icon="mdi:web" className="text-xl text-blue-400" />
|
||||
<p className="text-sm text-gray-600">
|
||||
<span className="font-bold"> </span>Webserverversion: 1.0.0
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Beispiel für Geräteanzeige */}
|
||||
<div className="bg-gray-50 rounded-lg shadow-sm border border-gray-200 justify-between space-y-1">
|
||||
<div className="flex flex-row item-center justify-between p-1">
|
||||
<CPLStatus />
|
||||
{/*
|
||||
<Access1Status />
|
||||
<Access2Status />
|
||||
*/}
|
||||
</div>
|
||||
<div className="flex flex-col item-center justify-between gap-1">
|
||||
<div className="flex flex-row item-center justify-between space-y-0">
|
||||
<div className="flex flex-col gap-1 mt-2">
|
||||
{loading ? (
|
||||
<p>Lädt...</p>
|
||||
) : error ? (
|
||||
<p className="text-red-500">{error.toString()}</p>
|
||||
) : (
|
||||
renderBaugruppentraeger()
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Die Box für XIOPM1 und XIOPM2, jeweils unter CPL und Access 1 */}
|
||||
|
||||
<div className="grid grid-cols-3 gap-4 p-4">
|
||||
<div className="flex justify-start items-center">
|
||||
{/* <XioPM1Status />*/} {/* Unter CPL */}
|
||||
</div>
|
||||
<div className="flex justify-center items-center">
|
||||
{/*<XioPM2Status /> */} {/* Unter Access 1 */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* IP, Subnet und Gateway Informationen */}
|
||||
<div className="flex-shrink-0 flex justify-between items-center mt-2 bg-white p-4 rounded-lg shadow-md border border-gray-200">
|
||||
<div className="flex items-center space-x-4">
|
||||
<img src="/images/IP-icon.svg" alt="IP Address" className="w-6 h-6" />
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">IP-Adresse</p>
|
||||
<p className="text-sm font-medium text-gray-700">{ip}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<img
|
||||
src="/images/subnet-mask.svg"
|
||||
alt="subnet mask"
|
||||
className="w-6 h-6"
|
||||
/>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Subnet-Maske</p>
|
||||
<p className="text-sm font-medium text-gray-700">{subnet}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<img src="/images/gateway.svg" alt="gateway" className="w-6 h-6" />
|
||||
<div>
|
||||
<p className="text-xs text-gray-500">Gateway</p>
|
||||
<p className="text-sm font-medium text-gray-700">{gateway}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Dashboard;
|
||||
161
pages/einausgaenge.js
Normal file
161
pages/einausgaenge.js
Normal file
@@ -0,0 +1,161 @@
|
||||
"use client";
|
||||
import React, { useState } from "react";
|
||||
|
||||
function Einausgaenge() {
|
||||
// Beispiel-Daten für Ein- und Ausgänge (kannst du durch deine Daten ersetzen)
|
||||
const inputs = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Eingang 1",
|
||||
status: "Aktiv",
|
||||
description: "Beschreibung 1",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Eingang 2",
|
||||
status: "Inaktiv",
|
||||
description: "Beschreibung 2",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Eingang 3",
|
||||
status: "Aktiv",
|
||||
description: "Beschreibung 3",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Eingang 4",
|
||||
status: "Inaktiv",
|
||||
description: "Beschreibung 4",
|
||||
},
|
||||
];
|
||||
|
||||
const outputs = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Ausgang 1",
|
||||
status: "Aktiv",
|
||||
description: "Beschreibung 1",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Ausgang 2",
|
||||
status: "Inaktiv",
|
||||
description: "Beschreibung 2",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Ausgang 3",
|
||||
status: "Aktiv",
|
||||
description: "Beschreibung 3",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Ausgang 4",
|
||||
status: "Inaktiv",
|
||||
description: "Beschreibung 4",
|
||||
},
|
||||
];
|
||||
|
||||
// Zustand für aktiven Tab (Ein- oder Ausgänge)
|
||||
const [activeTab, setActiveTab] = useState("inputs");
|
||||
|
||||
return (
|
||||
<div className="bg-gray-100 min-h-screen p-8">
|
||||
{/* Tabs für Ein- und Ausgänge */}
|
||||
<ul className="flex border-b border-gray-200">
|
||||
<li
|
||||
className={`mr-1 ${
|
||||
activeTab === "inputs" ? "border-blue-500 text-blue-600" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
onClick={() => setActiveTab("inputs")}
|
||||
className={`inline-block px-4 py-2 rounded-t-lg ${
|
||||
activeTab === "inputs"
|
||||
? "bg-blue-500 text-white"
|
||||
: "bg-white text-black hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
Eingänge
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
className={`mr-1 ${
|
||||
activeTab === "outputs" ? "border-blue-500 text-blue-600" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
onClick={() => setActiveTab("outputs")}
|
||||
className={`inline-block px-4 py-2 rounded-t-lg ${
|
||||
activeTab === "outputs"
|
||||
? "bg-blue-500 text-white"
|
||||
: "bg-white text-black hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
Ausgänge
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{/* Inhalt für die aktiven Tabs */}
|
||||
<div className="mt-4 p-4 bg-white rounded-lg shadow overflow-auto">
|
||||
{activeTab === "inputs" && (
|
||||
<div>
|
||||
<h2 className="text-lg font-bold mb-4">Eingänge</h2>
|
||||
<table className="min-w-full bg-white border border-gray-300">
|
||||
<thead>
|
||||
<tr className="w-full bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
|
||||
<th className="py-3 px-4 text-left">ID</th>
|
||||
<th className="py-3 px-4 text-left">Name</th>
|
||||
<th className="py-3 px-4 text-left">Status</th>
|
||||
<th className="py-3 px-4 text-left">Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-gray-600 text-sm">
|
||||
{inputs.map((input) => (
|
||||
<tr key={input.id} className="border-b border-gray-200">
|
||||
<td className="py-3 px-4 text-left">{input.id}</td>
|
||||
<td className="py-3 px-4 text-left">{input.name}</td>
|
||||
<td className="py-3 px-4 text-left">{input.status}</td>
|
||||
<td className="py-3 px-4 text-left">{input.description}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === "outputs" && (
|
||||
<div>
|
||||
<h2 className="text-lg font-bold mb-4">Ausgänge</h2>
|
||||
<table className="min-w-full bg-white border border-gray-300">
|
||||
<thead>
|
||||
<tr className="w-full bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
|
||||
<th className="py-3 px-4 text-left">ID</th>
|
||||
<th className="py-3 px-4 text-left">Name</th>
|
||||
<th className="py-3 px-4 text-left">Status</th>
|
||||
<th className="py-3 px-4 text-left">Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-gray-600 text-sm">
|
||||
{outputs.map((output) => (
|
||||
<tr key={output.id} className="border-b border-gray-200">
|
||||
<td className="py-3 px-4 text-left">{output.id}</td>
|
||||
<td className="py-3 px-4 text-left">{output.name}</td>
|
||||
<td className="py-3 px-4 text-left">{output.status}</td>
|
||||
<td className="py-3 px-4 text-left">
|
||||
{output.description}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Einausgaenge;
|
||||
BIN
pages/favicon.ico
Normal file
BIN
pages/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
pages/fonts/GeistMonoVF.woff
Normal file
BIN
pages/fonts/GeistMonoVF.woff
Normal file
Binary file not shown.
BIN
pages/fonts/GeistVF.woff
Normal file
BIN
pages/fonts/GeistVF.woff
Normal file
Binary file not shown.
17
pages/index.js
Normal file
17
pages/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export default function Home() {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
// Prüft die Umgebung und hängt .html in der Produktion an
|
||||
const isProduction = process.env.NEXT_PUBLIC_NODE_ENV === "production";
|
||||
const dashboardPath = `/dashboard${isProduction ? ".html" : ""}`;
|
||||
|
||||
// Leitet den Benutzer sofort zur richtigen Dashboard-Seite weiter
|
||||
router.replace(dashboardPath);
|
||||
}, [router]);
|
||||
|
||||
return null; // Die Seite zeigt keinen Inhalt an und leitet sofort um
|
||||
}
|
||||
168
pages/kabelueberwachung.js
Normal file
168
pages/kabelueberwachung.js
Normal file
@@ -0,0 +1,168 @@
|
||||
"use client"; // app/kabelueberwachung/page.jsx
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Kue705FO from "../components/modules/Kue705FO";
|
||||
import { loadWindowVariables } from "../utils/loadWindowVariables";
|
||||
|
||||
function Kabelueberwachung() {
|
||||
const router = useRouter();
|
||||
const [activeRack, setActiveRack] = useState(1); // Track the active rack
|
||||
const [kueIso, setKueIso] = useState([]); // State to store isolation values
|
||||
const [kueID, setKueID] = useState([]); // State to store the KUE names
|
||||
const [schleifenwiderstand, setSchleifenwiderstand] = useState([]); // State to store the resistance values
|
||||
const [kueOnline, setKueOnline] = useState([]); // State to store the module status
|
||||
|
||||
// Verwende den useRouter Hook, um den Rack-Parameter zu extrahieren
|
||||
useEffect(() => {
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
const rackParam = query.get("rack");
|
||||
|
||||
if (rackParam) {
|
||||
setActiveRack(parseInt(rackParam)); // Setze das aktive Rack basierend auf dem URL-Parameter
|
||||
}
|
||||
}, [router.query]);
|
||||
|
||||
// Load the external JavaScript file and fetch the isolation values
|
||||
useEffect(() => {
|
||||
loadWindowVariables()
|
||||
.then(() => {
|
||||
if (window.kueIso && Array.isArray(window.kueIso)) {
|
||||
setKueIso(window.kueIso);
|
||||
}
|
||||
if (window.kueRes && Array.isArray(window.kueRes)) {
|
||||
setSchleifenwiderstand(window.kueRes);
|
||||
}
|
||||
if (window.kueOnline && Array.isArray(window.kueOnline)) {
|
||||
setKueOnline(window.kueOnline);
|
||||
}
|
||||
if (window.kueID && Array.isArray(window.kueID)) {
|
||||
setKueID(window.kueID);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Fehler beim Laden der Variablen:", error);
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Zuerst alle Werte der Arrays speichern
|
||||
const allModules = kueIso.map((iso, index) => ({
|
||||
isolationswert: iso,
|
||||
schleifenwiderstand: schleifenwiderstand[index],
|
||||
modulName: kueID[index] || "Unknown",
|
||||
kueOnlineStatus: kueOnline[index],
|
||||
}));
|
||||
|
||||
// Dann die Module für jedes Rack in 8er-Gruppen aufteilen
|
||||
const racks = {
|
||||
rack1: allModules.slice(0, 8),
|
||||
rack2: allModules.slice(8, 16),
|
||||
rack3: allModules.slice(16, 24),
|
||||
rack4: allModules.slice(24, 32),
|
||||
};
|
||||
// Log the racks in the console for debugging
|
||||
/* console.log("Rack 1:", racks.rack1);
|
||||
console.log("Rack 2:", racks.rack2);
|
||||
console.log("Rack 3:", racks.rack3);
|
||||
console.log("Rack 4:", racks.rack4); */
|
||||
|
||||
// Function to handle rack change
|
||||
const changeRack = (rack) => {
|
||||
setActiveRack(rack);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const script = document.createElement("script");
|
||||
// Dynamischer Pfad basierend auf der Umgebung
|
||||
const environment = process.env.NEXT_PUBLIC_NODE_ENV || "production";
|
||||
if (environment === "production") {
|
||||
script.src = `CPL?/CPL/SERVICE/kueData.js`; // Produktions-Pfad
|
||||
} else {
|
||||
script.src = `/mockData/SERVICE/kueData.js`; // Mock-Daten-Pfad
|
||||
}
|
||||
script.async = true;
|
||||
document.body.appendChild(script);
|
||||
|
||||
// Cleanup the script if the component unmounts
|
||||
return () => {
|
||||
document.body.removeChild(script);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-gray-100 flex-1 p-6 text-black">
|
||||
<h1 className="text-2xl mb-4">Kabelüberwachung</h1>
|
||||
|
||||
<div className="mb-4">
|
||||
<button
|
||||
onClick={() => changeRack(1)}
|
||||
className={`mr-1 ${
|
||||
activeRack === 1
|
||||
? "bg-littwin-blue text-white p-1 rounded-sm "
|
||||
: "bg-gray-300 p-1 text-sm"
|
||||
}`}
|
||||
>
|
||||
Rack 1
|
||||
</button>
|
||||
<button
|
||||
onClick={() => changeRack(2)}
|
||||
className={`mr-2 ${
|
||||
activeRack === 2
|
||||
? "bg-littwin-blue text-white p-1 rounded-sm"
|
||||
: "bg-gray-300 p-1 text-sm"
|
||||
}`}
|
||||
>
|
||||
Rack 2
|
||||
</button>
|
||||
<button
|
||||
onClick={() => changeRack(3)}
|
||||
className={`mr-2 ${
|
||||
activeRack === 3
|
||||
? "bg-littwin-blue text-white p-1 rounded-sm"
|
||||
: "bg-gray-300 p-1 text-sm"
|
||||
}`}
|
||||
>
|
||||
Rack 3
|
||||
</button>
|
||||
<button
|
||||
onClick={() => changeRack(4)}
|
||||
className={`mr-2 ${
|
||||
activeRack === 4
|
||||
? "bg-littwin-blue text-white p-1 rounded-sm"
|
||||
: "bg-gray-300 p-1 text-sm"
|
||||
}`}
|
||||
>
|
||||
Rack 4
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row space-x-4 scale-110 ml-[5%] mt-[5%]">
|
||||
{racks[`rack${activeRack}`].map((slot, index) => {
|
||||
const slotIndex = index + (activeRack - 1) * 8;
|
||||
const alarmStatus =
|
||||
(window.kueAlarm1 && window.kueAlarm1[slotIndex]) ||
|
||||
(window.kueAlarm2 && window.kueAlarm2[slotIndex]) ||
|
||||
(window.kueCableBreak && window.kueCableBreak[slotIndex]) ||
|
||||
(window.kueGroundFault && window.kueGroundFault[slotIndex]);
|
||||
|
||||
return (
|
||||
<div key={index} className="flex">
|
||||
<Kue705FO
|
||||
isolationswert={slot.isolationswert}
|
||||
schleifenwiderstand={slot.schleifenwiderstand}
|
||||
modulName={slot.modulName}
|
||||
kueOnline={slot.kueOnlineStatus}
|
||||
alarmStatus={alarmStatus} // Pass the calculated alarm status
|
||||
slotIndex={slotIndex}
|
||||
/>
|
||||
{/*
|
||||
console.log(`Module Data (Rack ${activeRack}, Slot ${index + 1}):`,slot);
|
||||
*/}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Kabelueberwachung;
|
||||
135
pages/meldungen.js
Normal file
135
pages/meldungen.js
Normal file
@@ -0,0 +1,135 @@
|
||||
"use client";
|
||||
import React, { useState } from "react";
|
||||
|
||||
function Meldungen() {
|
||||
const [rowsPerPage, setRowsPerPage] = useState(25);
|
||||
const [filter, setFilter] = useState("");
|
||||
const [selectedMonth, setSelectedMonth] = useState("01");
|
||||
const [selectedYear, setSelectedYear] = useState("23");
|
||||
const [selectedDay, setSelectedDay] = useState("");
|
||||
|
||||
// Platzhalter für Meldungen
|
||||
const messages = Array.from({ length: 50 }, (_, i) => ({
|
||||
date: `2023-01-${String(i + 1).padStart(2, "0")}`,
|
||||
message: `Meldung ${i + 1}`,
|
||||
}));
|
||||
|
||||
const filteredMessages = messages.filter((msg) => {
|
||||
const dayMatch = selectedDay
|
||||
? msg.date.split("-")[2] === selectedDay.padStart(2, "0")
|
||||
: true;
|
||||
const monthMatch = msg.date.split("-")[1] === selectedMonth;
|
||||
const yearMatch = msg.date.split("-")[0].substring(2) === selectedYear;
|
||||
const filterMatch = msg.message
|
||||
.toLowerCase()
|
||||
.includes(filter.toLowerCase());
|
||||
return dayMatch && monthMatch && yearMatch && filterMatch;
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full">
|
||||
{/* Filterleiste */}
|
||||
<div className="flex justify-between items-center bg-blue-500 p-4 text-white rounded-t">
|
||||
<div className="flex items-center space-x-4">
|
||||
<span>Interner Meldungsspeicher</span>
|
||||
<select
|
||||
value={selectedMonth}
|
||||
onChange={(e) => setSelectedMonth(e.target.value)}
|
||||
className="bg-white text-black p-1 rounded"
|
||||
>
|
||||
<option value="01">Januar</option>
|
||||
<option value="02">Februar</option>
|
||||
<option value="03">März</option>
|
||||
<option value="04">April</option>
|
||||
<option value="05">Mai</option>
|
||||
<option value="06">Juni</option>
|
||||
<option value="07">Juli</option>
|
||||
<option value="08">August</option>
|
||||
<option value="09">September</option>
|
||||
<option value="10">Oktober</option>
|
||||
<option value="11">November</option>
|
||||
<option value="12">Dezember</option>
|
||||
</select>
|
||||
<select
|
||||
value={selectedYear}
|
||||
onChange={(e) => setSelectedYear(e.target.value)}
|
||||
className="bg-white text-black p-1 rounded"
|
||||
>
|
||||
<option value="22">2022</option>
|
||||
<option value="23">2023</option>
|
||||
<option value="24">2024</option>
|
||||
<option value="25">2025</option>
|
||||
<option value="26">2026</option>
|
||||
</select>
|
||||
<input
|
||||
type="number"
|
||||
value={selectedDay}
|
||||
onChange={(e) => setSelectedDay(e.target.value)}
|
||||
min="1"
|
||||
max="31"
|
||||
placeholder="Tag"
|
||||
className="bg-white text-black p-1 rounded"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<input
|
||||
type="text"
|
||||
value={filter}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
placeholder="Filter"
|
||||
className="bg-white text-black p-1 rounded"
|
||||
/>
|
||||
<select
|
||||
value={rowsPerPage}
|
||||
onChange={(e) => setRowsPerPage(e.target.value)}
|
||||
className="bg-white text-black p-1 rounded"
|
||||
>
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Meldungen Tabelle */}
|
||||
<div className="flex-grow overflow-auto mt-4">
|
||||
<table className="min-w-full bg-white border border-gray-300">
|
||||
<thead>
|
||||
<tr className="bg-gray-200 text-gray-600 text-sm leading-normal">
|
||||
<th className="py-3 px-4 text-left">Datum</th>
|
||||
<th className="py-3 px-4 text-left">Meldung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-gray-600 text-sm">
|
||||
{filteredMessages.slice(0, rowsPerPage).map((msg, index) => (
|
||||
<tr key={index} className="border-b border-gray-200">
|
||||
<td className="py-3 px-4">{msg.date}</td>
|
||||
<td className="py-3 px-4">{msg.message}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Pagination */}
|
||||
<div className="flex justify-center mt-4">
|
||||
<ul className="flex space-x-2">
|
||||
{Array.from(
|
||||
{ length: Math.ceil(filteredMessages.length / rowsPerPage) },
|
||||
(_, i) => (
|
||||
<li
|
||||
key={i}
|
||||
className="cursor-pointer bg-blue-500 text-white p-2 rounded"
|
||||
>
|
||||
{i + 1}
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Meldungen;
|
||||
45
pages/wait.js
Normal file
45
pages/wait.js
Normal file
@@ -0,0 +1,45 @@
|
||||
"use client"; // app/wait/page.jsx
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { ClipLoader } from "react-spinners";
|
||||
|
||||
// IndexedDB functions only in the browser
|
||||
let storePage, getPage;
|
||||
if (typeof window !== "undefined") {
|
||||
const indexedDBModule = require("../utils/indexedDB");
|
||||
storePage = indexedDBModule.storePage;
|
||||
getPage = indexedDBModule.getPage;
|
||||
}
|
||||
|
||||
export default function WaitPage() {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
// Store the page as a Blob in IndexedDB in the background
|
||||
if (typeof window !== "undefined" && storePage) {
|
||||
const pageContent = `
|
||||
<div style="text-align: center; margin-top: 100px;">
|
||||
<h1>Bitte warten...</h1>
|
||||
<div class="spinner"></div>
|
||||
<p>Die Seite wird automatisch neu geladen.</p>
|
||||
</div>`;
|
||||
storePage("waitPage", new Blob([pageContent], { type: "text/html" }));
|
||||
}
|
||||
|
||||
// Timer to redirect after 20 seconds
|
||||
const timer = setTimeout(() => {
|
||||
router.push("/");
|
||||
}, 20000);
|
||||
|
||||
// Cleanup timer when component is unmounted
|
||||
return () => clearTimeout(timer);
|
||||
}, [router]);
|
||||
|
||||
return (
|
||||
<div style={{ textAlign: "center", marginTop: "100px" }}>
|
||||
<h1>Bitte warten...</h1>
|
||||
<ClipLoader color={"#76c7c0"} size={50} /> {/* Spinner */}
|
||||
<p>Die Seite wird automatisch neu geladen.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user