feat: WebSocket-Integration mit UI-Reaktivierung für GisStationsStaticDistrict

- WebSocket-Trigger implementiert, der `fetchGisStationsStaticDistrictThunk` ausführt.
- Trigger-Mechanismus über `useState` (`triggerUpdate`) sorgt für gezielten UI-Re-Render.
- Problem gelöst, dass Redux-Store zwar neue Daten enthielt, aber die UI nicht aktualisiert wurde.
- MapComponent.js und useDynamicDeviceLayers.js entsprechend angepasst.
This commit is contained in:
Ismail Ali
2025-06-09 00:24:33 +02:00
parent fbffc82e1b
commit b067a4c97e
12 changed files with 113 additions and 66 deletions

View File

@@ -82,11 +82,14 @@ import { cleanupMarkers } from "@/utils/common/cleanupMarkers";
import { monitorHeapAndReload } from "@/utils/common/monitorMemory";
import { monitorHeapWithRedux } from "@/utils/common/monitorMemory";
import { io } from "socket.io-client";
import { setGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice.js";
//-----------------------------------------------------------------------------------------------------
const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
//-------------------------------
const dispatch = useDispatch();
// useDataUpdater();
const [triggerUpdate, setTriggerUpdate] = useState(false);
const countdown = useSelector(state => state.polylineContextMenu.countdown);
const countdownActive = useSelector(state => state.polylineContextMenu.countdownActive);
@@ -818,9 +821,11 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
socket.on("GisStationsMeasurementsUpdated", data => {
dispatch(fetchGisStationsMeasurementsThunk(data));
});
socket.on("GisStationsStaticDistrictUpdated", data => {
dispatch(fetchGisStationsStaticDistrictThunk(data));
socket.on("GisStationsStaticDistrictUpdated", () => {
console.log("🛰 WebSocket-Trigger empfangen → Thunk wird erneut ausgeführt");
dispatch(fetchGisStationsStaticDistrictThunk());
console.log("🛰 WebSocket-Trigger empfangen → Trigger wird gesetzt");
setTriggerUpdate(prev => !prev); // Trigger toggeln
});
socket.on("GisStationsStatusDistrictUpdated", data => {
@@ -835,7 +840,12 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
socket.disconnect();
};
}, [dispatch]);
//--------------------------------------------
useEffect(() => {
console.log("📦 Neue Daten empfangen:", GisStationsStaticDistrict);
}, [GisStationsStaticDistrict]);
const { Points = [] } = useSelector(selectGisStationsStaticDistrict);
useEffect(() => {}, [triggerUpdate]);
//---------------------------------------------
//--------------------------------------------
return (

View File

@@ -178,6 +178,19 @@ function MapLayersControlPanel() {
console.log("📌 stationListing aktualisiert:", filteredAreas);
}
}, [GisStationsStaticDistrict, GisSystemStatic]);
//---------------------------
useEffect(() => {
const next = (GisStationsStaticDistrict.Points || []).map(p => p.Area_Name).join("|");
const current = stationListing.map(s => s.name).join("|");
if (next !== current) {
setStationListing(
GisStationsStaticDistrict.Points.map((area, index) => ({
id: index + 1,
name: area.Area_Name,
}))
);
}
}, [GisStationsStaticDistrict]);
//---------------------------
return (
@@ -194,9 +207,9 @@ function MapLayersControlPanel() {
style={{ minWidth: "150px", maxWidth: "200px" }}
>
<option value="Station wählen">Station wählen</option>
{stationListing.map(station => (
<option key={station.id} value={station.id}>
{station.name}
{(GisStationsStaticDistrict.Points || []).map((item, index) => (
<option key={index} value={item.IdLD}>
{item.Area_Name}
</option>
))}
</select>

View File

@@ -1,2 +1,2 @@
// /config/appVersion
export const APP_VERSION = "1.1.247";
export const APP_VERSION = "1.1.248";

View File

@@ -12,8 +12,9 @@ import { fetchGisSystemStaticThunk } from "../redux/thunks/webservice/fetchGisSy
const REFRESH_INTERVAL = parseInt(process.env.NEXT_PUBLIC_REFRESH_INTERVAL || "10000");
export default function useDataUpdater() {
export const useDataUpdater = () => {
const dispatch = useDispatch();
useEffect(() => {
const updateAll = () => {
dispatch(fetchGisLinesStatusThunk());
@@ -23,9 +24,17 @@ export default function useDataUpdater() {
dispatch(fetchGisSystemStaticThunk());
};
updateAll(); // direkt initial einmal laden
const interval = setInterval(updateAll, REFRESH_INTERVAL);
return () => clearInterval(interval); // Cleanup
updateAll();
const interval = setInterval(updateAll, 10000);
return () => clearInterval(interval);
}, [dispatch]);
}
};
// Das ist eine normale Funktion
export const triggerDataUpdate = dispatch => {
dispatch(fetchGisLinesStatusThunk());
dispatch(fetchGisStationsMeasurementsThunk());
dispatch(fetchGisStationsStaticDistrictThunk());
dispatch(fetchGisStationsStatusDistrictThunk());
dispatch(fetchGisSystemStaticThunk());
};

View File

@@ -4,6 +4,8 @@ import L from "leaflet";
import { createAndSetDevices } from "../utils/devices/createAndSetDevices";
import { checkOverlappingMarkers } from "../utils/mapUtils";
import plusRoundIcon from "@/components/icons/devices/overlapping/PlusRoundIcon";
import { useSelector } from "react-redux";
import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice.js";
/**
* Dynamisch GIS-System-Marker erstellen & Sichtbarkeit steuern.
@@ -14,6 +16,7 @@ import plusRoundIcon from "@/components/icons/devices/overlapping/PlusRoundIcon"
* @returns {{ markerStates, layerRefs }} Alle Marker und Referenzen
*/
const useDynamicDeviceLayers = (map, GisSystemStatic, mapLayersVisibility, priorityConfig, oms) => {
const staticDistrictData = useSelector(selectGisStationsStaticDistrict);
const [markerStates, setMarkerStates] = useState({});
const layerRefs = useRef({});
@@ -54,7 +57,7 @@ const useDynamicDeviceLayers = (map, GisSystemStatic, mapLayersVisibility, prior
oms
);
});
}, [map, GisSystemStatic, priorityConfig]);
}, [map, GisSystemStatic, priorityConfig, staticDistrictData]);
// Sichtbarkeit nach Redux-Status steuern
useEffect(() => {

View File

@@ -11,10 +11,23 @@ const slice = createSlice({
status: "idle",
error: null,
},
reducers: {},
extraReducers: (builder) => {
reducers: {
setGisStationsStaticDistrict: (state, action) => {
// Stelle sicher, dass die Struktur immer gleich bleibt
if (Array.isArray(action.payload)) {
state.data = { Points: action.payload };
} else if (action.payload?.Points) {
state.data = { Points: action.payload.Points };
} else {
state.data = { Points: [] };
}
state.status = "succeeded";
state.lastUpdated = Date.now();
},
}, // Ende der reducers
extraReducers: builder => {
builder
.addCase(fetchGisStationsStaticDistrictThunk.pending, (state) => {
.addCase(fetchGisStationsStaticDistrictThunk.pending, state => {
state.status = "loading";
})
.addCase(fetchGisStationsStaticDistrictThunk.fulfilled, (state, action) => {
@@ -28,5 +41,6 @@ const slice = createSlice({
},
});
export const selectGisStationsStaticDistrict = (state) => state.gisStationsStaticDistrict.data;
export const selectGisStationsStaticDistrict = state => state.gisStationsStaticDistrict.data;
export default slice.reducer;
export const { setGisStationsStaticDistrict } = slice.actions;

View File

@@ -35,7 +35,6 @@ app.prepare().then(() => {
io.on("connection", socket => {
const { m: idMap, u: idUser, mode } = socket.handshake.query;
const isLiveMode = mode === "live";
console.log(`🔌 WebSocket verbunden (idMap=${idMap}, idUser=${idUser}, mode=${mode})`);
const endpoints = [
@@ -80,7 +79,7 @@ app.prepare().then(() => {
const jsonStr = fs.readFileSync(mockPath, "utf-8");
const json = JSON.parse(jsonStr);
statis = extractData(json, name);
console.log(`🧪 [Mock] ${name}`);
//console.log(`🧪 [Mock] ${name}`);
} else {
const fetchUrl = `http://localhost/talas5/ClientData/${getUrl()}`;
const res = await fetch(fetchUrl);
@@ -106,7 +105,7 @@ app.prepare().then(() => {
console.log(`✅ Änderung bei ${name} erkannt → gesendet`);
writeJsonFile(`${name}.json`, statis);
} else {
console.log(`🔁 ${name}: Keine Änderung`);
// console.log(`🔁 ${name}: Keine Änderung`);
}
} catch (error) {
console.error(`❌ Fehler bei ${name}:`, error.message);
@@ -114,14 +113,13 @@ app.prepare().then(() => {
}
};
if (isLiveMode) {
// fetchData immer ausführen unabhängig vom Modus
fetchData();
const interval = setInterval(fetchData, 5000);
socket.on("disconnect", () => {
clearInterval(interval);
console.log("❌ WebSocket getrennt");
});
}
});
server.listen(PORT, () => {

View File

@@ -3,9 +3,9 @@
"IdLD": 50922,
"Modul": 8,
"DpName": "KUE08_Messwertalarm",
"ModulName": "Test12",
"ModulName": "Test9",
"ModulTyp": "Kü705-FO",
"Message": "KÜG 08: Überspannung gehend",
"Message": "KÜG 08: Überspannung gehend",
"Level": 3,
"PrioColor": "#FFFF00",
"PrioName": "minor",
@@ -17,7 +17,7 @@
"DpName": "KUE02_Aderbruch",
"ModulName": "Kue 2",
"ModulTyp": "Kü705-FO",
"Message": "KÜG 02: Aderbruch kommend",
"Message": "KÜG 02: Aderbruch kommend",
"Level": 1,
"PrioColor": "#FF0000",
"PrioName": "critical",
@@ -29,7 +29,7 @@
"DpName": "KUE03_Aderbruch",
"ModulName": "Kue 3",
"ModulTyp": "Kü705-FO",
"Message": "KÜG 03: Aderbruch kommend",
"Message": "KÜG 03: Aderbruch kommend",
"Level": 1,
"PrioColor": "#FF0000",
"PrioName": "critical",
@@ -1227,7 +1227,7 @@
"IdLD": 50922,
"Modul": 8,
"DpName": "KUE08_Messwert",
"ModulName": "Test12",
"ModulName": "Test8",
"ModulTyp": "Kü705-FO",
"Message": "?",
"Level": -1,
@@ -1335,7 +1335,7 @@
"IdLD": 50922,
"Modul": 8,
"DpName": "KUE08_Schleifenwert",
"ModulName": "Test12",
"ModulName": "Test8",
"ModulTyp": "Kü705-FO",
"Message": "?",
"Level": -1,

View File

@@ -4,7 +4,7 @@
"IdL": 24101,
"IdDP": 3,
"Na": "FBT",
"Val": "6",
"Val": "7",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Rastede"
@@ -105,7 +105,7 @@
"IdDP": 7,
"Na": "WR",
"Val": "180",
"Unit": "°",
"Unit": "°",
"Gr": "GMA",
"Area_Name": "Rastede"
}

View File

@@ -1,6 +1,6 @@
[
{
"LD_Name": "CPL Ismael",
"LD_Name": "CPL Ismail31",
"IdLD": 50922,
"Device": "CPL V3.5 mit 24 Kü",
"Link": "cpl.aspx?ver=35&kue=24&id=50922",
@@ -10,8 +10,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 20,
"System": 1,
"Active": 1
@@ -27,8 +27,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 12,
"System": 5,
"Active": 1
@@ -44,8 +44,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 21,
"System": 6,
"Active": 1
@@ -61,8 +61,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 1,
"System": 11,
"Active": 1
@@ -78,8 +78,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 12,
"System": 111,
"Active": 1
@@ -95,8 +95,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 20,
"System": 1,
"Active": 1
@@ -112,8 +112,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 9,
"System": 7,
"Active": 1
@@ -129,8 +129,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 21,
"System": 6,
"Active": 1
@@ -146,8 +146,8 @@
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.243954,
"Y": 8.160439,
"X": 53.242157,
"Y": 8.160353,
"Icon": 21,
"System": 6,
"Active": 1

View File

@@ -67,7 +67,7 @@
"Na": "minor",
"Le": 3,
"Co": "#FFFF00",
"Me": "KÜG 08: Überspannung gehend",
"Me": "KÜG 08: Überspannung gehend",
"Feld": 4,
"Icon": 0
},
@@ -85,7 +85,7 @@
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 02: Aderbruch kommend",
"Me": "KÜG 02: Aderbruch kommend",
"Feld": 4,
"Icon": 0
},
@@ -94,7 +94,7 @@
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 03: Aderbruch kommend",
"Me": "KÜG 03: Aderbruch kommend",
"Feld": 4,
"Icon": 0
}

View File

@@ -9,14 +9,14 @@
{
"IdSystem": 2,
"Name": "ECI",
"Longname": "ECI Geräte",
"Longname": "ECI Geräte",
"Allow": 1,
"Icon": 2
},
{
"IdSystem": 3,
"Name": "ULAF",
"Longname": "ULAF Geräte",
"Longname": "ULAF Geräte",
"Allow": 0,
"Icon": 3
},
@@ -51,7 +51,7 @@
{
"IdSystem": 9,
"Name": "OTDR",
"Longname": "Glasfaserüberwachung OTU",
"Longname": "Glasfaserüberwachung OTU",
"Allow": 1,
"Icon": 9
},
@@ -65,7 +65,7 @@
{
"IdSystem": 11,
"Name": "GMA",
"Longname": "Glättemeldeanlagen",
"Longname": "Glättemeldeanlagen",
"Allow": 1,
"Icon": 11
},
@@ -73,7 +73,7 @@
"IdSystem": 13,
"Name": "Messstellen",
"Longname": "Messstellen",
"Allow": 0,
"Allow": 1,
"Icon": 13
},
{
@@ -93,7 +93,7 @@
{
"IdSystem": 110,
"Name": "DAUZ",
"Longname": "Dauerzählstellen",
"Longname": "Dauerzählstellen",
"Allow": 1,
"Icon": 110
},