fix: POI Bearbeiten

This commit is contained in:
ISA
2025-06-10 08:52:17 +02:00
parent 2d897081c5
commit 004af608fc
10 changed files with 155 additions and 71 deletions

View File

@@ -44,6 +44,8 @@
Polling-Mechanismus → unbedingt prüfen, ob `clearInterval()` im useEffect-Cleanup enthalten
ist.
-[ ] TODO: WebSocket für webService erstellen , falls etwas geändert wird dann soll aktualisiert,
-[x] TODO: WebSocket für webService erstellen , falls etwas geändert wird dann soll aktualisiert,
optimiert besser als setInterval, zuerst nur für TALAS.web WebServices erstellen, irgendwann soll
die Daten von DB auch mit WebSocket gelöst werden
- [ ] TODO: POI bearbeiten funktioniert es nicht

View File

@@ -1,2 +1,2 @@
// /config/appVersion
export const APP_VERSION = "1.1.251";
export const APP_VERSION = "1.1.252";

View File

@@ -2,7 +2,9 @@
# 🧠 Architekturübersicht NodeMap
Dieses Dokument beschreibt die technische Gesamtarchitektur des Projekts **NodeMap**, einer kartenbasierten Webanwendung zur Anzeige, Bearbeitung und Verwaltung von GIS-Daten, POIs und Gerätestatus.
Dieses Dokument beschreibt die technische Gesamtarchitektur des Projekts **NodeMap**, einer
kartenbasierten Webanwendung zur Anzeige, Bearbeitung und Verwaltung von GIS-Daten, POIs und
Gerätestatus.
---
@@ -64,7 +66,8 @@ Dieses Dokument beschreibt die technische Gesamtarchitektur des Projekts **NodeM
## 🧩 Besonderheiten
- **Konfigurierbarer basePath:**
Pfad wie `/talas5` ist optional und kann per `NEXT_PUBLIC_BASE_PATH` in `.env.local` gesetzt werden.
Pfad wie `/talas5` ist optional und kann per `NEXT_PUBLIC_BASE_PATH` in `.env.local` gesetzt
werden.
- **Rechteabhängige UI:**
Funktionen (z.B. POI bearbeiten) basieren auf Benutzerrechten (`IdRight`) vom Server.
- **Zentrale Komponentensteuerung:**
@@ -78,7 +81,8 @@ Dieses Dokument beschreibt die technische Gesamtarchitektur des Projekts **NodeM
- Version ist in `appVersion.js` definiert → wird über `NEXT_PUBLIC_APP_VERSION` eingeblendet
- Build erfolgt via `npm run build`, Auslieferung über `.next/`
- Nicht benötigte Dateien wie `__tests__`, `docs/`, `scripts/` etc. werden nicht in den Build aufgenommen
- Nicht benötigte Dateien wie `__tests__`, `docs/`, `scripts/` etc. werden nicht in den Build
aufgenommen
---
@@ -141,24 +145,17 @@ flowchart TD
---
Jetzt (dynamisch & Redux-basiert):
MapComponent.js ruft folgenden Hook auf:
Jetzt (dynamisch & Redux-basiert): MapComponent.js ruft folgenden Hook auf:
js
Copy
Edit
const { markerStates, layerRefs } = useDynamicDeviceLayers(map, GisSystemStatic, mapLayersVisibility, priorityConfig, oms);
useDynamicDeviceLayers.js verarbeitet die GisSystemStatic-Liste:
js Copy Edit const { markerStates, layerRefs } = useDynamicDeviceLayers(map, GisSystemStatic,
mapLayersVisibility, priorityConfig, oms); useDynamicDeviceLayers.js verarbeitet die
GisSystemStatic-Liste:
Jedes System (z.B. "TALAS", "ECI", "Cisco") bekommt einen eigenen Marker-Layer.
Die Marker werden erstellt durch:
js
Copy
Edit
createAndSetDevices(...) // Systemweise Marker erzeugen
createAndSetDevices.js:
js Copy Edit createAndSetDevices(...) // Systemweise Marker erzeugen createAndSetDevices.js:
Filtert alle Stations aus staticDistrictData, deren System === IdSystem.
@@ -170,11 +167,7 @@ Ruft setMarkersFunction(markers) auf → Übergibt die Marker zurück an den Hoo
Der Hook speichert:
js
Copy
Edit
setMarkerStates((prev) => ({ ...prev, [Name]: newMarkers }));
MapComponent.js hat dann:
js Copy Edit setMarkerStates((prev) => ({ ...prev, [Name]: newMarkers })); MapComponent.js hat dann:
Zugriff auf alle Marker dynamisch über markerStates (ein Objekt mit Schlüssel = Systemname)
@@ -182,9 +175,11 @@ Sichtbarkeit und OverlappingMarkerSpiderfier werden damit verarbeitet.
---
🔁 Die Geräte-Marker sind nicht mehr fest codiert, sondern werden dynamisch erzeugt anhand der Webservice-Daten GisSystemStatic.
🔁 Die Geräte-Marker sind nicht mehr fest codiert, sondern werden dynamisch erzeugt anhand der
Webservice-Daten GisSystemStatic.
🔄 Sichtbarkeit (Checkbox im Control Panel) löst ein Event visibilityChanged aus → MapComponent reagiert und rendert Marker neu.
🔄 Sichtbarkeit (Checkbox im Control Panel) löst ein Event visibilityChanged aus → MapComponent
reagiert und rendert Marker neu.
🕷️ Überlappende Marker werden mit checkOverlappingMarkers + PlusRoundIcon verarbeitet.
@@ -202,3 +197,90 @@ flowchart TD
A2 --> I1[Map aktualisiert Marker]
A2 --> I2[checkOverlappingMarkers mit OMS]
```
---
10.06.2025
# Datenfluss-Konzept: WebSocket ↔ Redux ↔ UI
Dieses Dokument beschreibt den technischen Ablauf des Live-Datenflusses im NodeMap-Projekt, um neue
Entwickler\:innen beim Onboarding zu unterstützen.
## ᵀᵃᵗᵉᵖᵏᴼᵏᴼᵉ: Architekturübersicht
```mermaid
sequenceDiagram
autonumber
participant WS_Server as WebSocket Server
participant WebService as TALAS WebService
participant Browser
participant ReduxStore as Redux Store
participant UI as React Leaflet UI
loop Alle 5 Sekunden
WS_Server->>WebService: fetch endpointX
alt Daten haben sich geändert
WS_Server-->>Browser: emit 'endpointXUpdated'
Browser->>ReduxStore: dispatch(fetchEndpointXThunk())
ReduxStore->>WebService: fetch endpointX
WebService-->>ReduxStore: JSON response
ReduxStore-->>UI: update Slice
UI-->>User: re-render Markers
else Keine Änderung
WS_Server-->>WS_Server: keine Aktion
end
end
```
## Beteiligte Komponenten
### WebSocket Server (`server.js`)
- Ruft regelmäßig (`setInterval`) die Webservice-Endpunkte auf.
- Erkennt Änderungen durch JSON-Vergleich (`JSON.stringify`).
- Sendet WebSocket-Events nur bei echten Änderungen.
### Client: MapComponent
- Hört auf `socket.on("endpointXUpdated")`.
- Ruft dann gezielt den passenden Redux-Thunk auf (z.B. `fetchGisLinesStatusThunk`).
### Redux Store & Thunks
- Jeder Endpunkt besitzt:
- einen `Service` (API-Fetch)
- einen `Thunk` (Redux-Logik)
- einen `Slice` (State-Verwaltung)
### React UI (Leaflet Map)
- Beobachtet relevante Redux-Slices via `useSelector()`.
- Aktualisiert Marker, Tooltip und Popup über `createAndSetDevices()` und
`useDynamicDeviceLayers()`.
## Beispiel-Endpunkte
| Endpunktname | WebSocket Event | Redux Thunk |
| --------------------------- | ---------------------------------- | --------------------------------------- |
| `GisLinesStatus` | `GisLinesStatusUpdated` | `fetchGisLinesStatusThunk()` |
| `GisStationsMeasurements` | `GisStationsMeasurementsUpdated` | `fetchGisStationsMeasurementsThunk()` |
| `GisStationsStaticDistrict` | `GisStationsStaticDistrictUpdated` | `fetchGisStationsStaticDistrictThunk()` |
| `GisStationsStatusDistrict` | `GisStationsStatusDistrictUpdated` | `fetchGisStationsStatusDistrictThunk()` |
## Vorteile
- UI aktualisiert sich nur bei echten Datenänderungen → weniger Re-Renders.
- Live-Synchronisation zwischen Datenquelle und Anzeige.
- Skalierbar für beliebige Endpunkte.
## ToDo/Erweiterungen
- Automatische Reconnect-Logik für WebSocket.
- Anzeige des letzten Update-Zeitpunkts in UI.
- Logging-UI für WebSocket-Messages zur Diagnose.
---
> Letzte Änderung: `{{heutiges Datum}}` von Ismail Ali

View File

@@ -1,10 +1,10 @@
// /utils/markerUtils.js
import L from "leaflet";
import { toast } from "react-toastify";
import circleIcon from "../components/CircleIcon";
import circleIcon from "@/components/gisPolylines/icons/CircleIcon";
import { store } from "../redux/store";
import { updatePolylineCoordinatesThunk } from "../redux/thunks/database/polylines/updatePolylineCoordinatesThunk";
import { redrawPolyline } from "./mapUtils";
import { updatePolylineCoordinatesThunk } from "@/redux/thunks/database/polylines/updatePolylineCoordinatesThunk";
import { redrawPolyline } from "@/utils/mapUtils";
import { cleanupMarkers } from "@/utils/common/cleanupMarkers";
const savePolylineRedux = lineData => {
@@ -57,37 +57,3 @@ export const removeMarker = (marker, lineData, currentZoom, currentCenter) => {
window.location.reload();
}
};
export const handleEditPoi = (
marker,
userRights,
setCurrentPoiData,
setShowPoiUpdateModal,
fetchPoiData,
toast
) => {
if (!Array.isArray(userRights)) {
toast.error("Benutzerrechte sind ungültig.", {
position: "top-center",
autoClose: 5000,
});
return;
}
if (!userRights.some(r => r.IdRight === 56)) {
toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", {
position: "top-center",
autoClose: 5000,
});
return;
}
setCurrentPoiData({
idPoi: marker.options.id,
name: marker.options.name,
description: marker.options.description,
});
fetchPoiData(marker.options.id);
setShowPoiUpdateModal(true);
};

View File

@@ -1,8 +1,8 @@
// /utils/poiUtils.js
import L from "leaflet";
import { toast } from "react-toastify";
import circleIcon from "../components/gisPolylines/icons/CircleIcon.js";
import { redrawPolyline } from "./polylines/redrawPolyline.js";
import circleIcon from "@/components/gisPolylines/icons/CircleIcon.js";
import { redrawPolyline } from "@/utils/polylines/redrawPolyline.js";
import { store } from "../redux/store";
import { updatePolylineCoordinatesThunk } from "../redux/thunks/database/polylines/updatePolylineCoordinatesThunk";
@@ -67,3 +67,37 @@ export const updateMarkerPosition = (newCoords, lineData, marker) => {
if (!marker) return;
marker.setLatLng([newCoords.lat, newCoords.lng]);
};
export const handleEditPoi = (
marker,
userRights,
setCurrentPoiData,
setShowPoiUpdateModal,
fetchPoiData,
toast
) => {
if (!Array.isArray(userRights)) {
toast.error("Benutzerrechte sind ungültig.", {
position: "top-center",
autoClose: 5000,
});
return;
}
if (!userRights.some(r => r.IdRight === 56)) {
toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", {
position: "top-center",
autoClose: 5000,
});
return;
}
setCurrentPoiData({
idPoi: marker.options.id,
name: marker.options.name,
description: marker.options.description,
});
fetchPoiData(marker.options.id);
setShowPoiUpdateModal(true);
};

View File

@@ -1,8 +1,8 @@
// utils/setupPOIs.js
import { parsePoint } from "./geometryUtils";
import { handleEditPoi } from "./poiUtils";
import { updateLocationInDatabaseService } from "../services/database/updateLocationInDatabaseService";
import { setSelectedPoi, clearSelectedPoi } from "../redux/slices/database/pois/selectedPoiSlice";
import { parsePoint } from "@/utils/geometryUtils";
import { handleEditPoi } from "@/utils/poiUtils";
import { updateLocationInDatabaseService } from "@/services/database/updateLocationInDatabaseService";
import { setSelectedPoi, clearSelectedPoi } from "@/redux/slices/database/pois/selectedPoiSlice";
import { cleanupMarkers } from "@/utils/common/cleanupMarkers";
export const setupPOIs = async (

View File

@@ -3,7 +3,7 @@
"IdLD": 50922,
"Modul": 8,
"DpName": "KUE08_Messwertalarm",
"ModulName": "Test9",
"ModulName": "Test11",
"ModulTyp": "Kü705-FO",
"Message": "KÜG 08: Überspannung gehend",
"Level": 3,

View File

@@ -4,7 +4,7 @@
"IdL": 24101,
"IdDP": 3,
"Na": "FBT",
"Val": "13",
"Val": "15",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Rastede"

View File

@@ -1,6 +1,6 @@
[
{
"LD_Name": "CPL Ismail31",
"LD_Name": "CPL Ismail",
"IdLD": 50922,
"Device": "CPL V3.5 mit 24 Kü",
"Link": "cpl.aspx?ver=35&kue=24&id=50922",

View File

@@ -4,7 +4,7 @@
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 01 kommend",
"Me": "Eingang DE 01 kommend test2",
"Feld": 4,
"Icon": 0
},