feat: POI-Erstellung, -Bearbeitung und -Löschung vollständig überarbeitet
- POI-Tooltip zeigt jetzt den korrekten Gerätenamen aus Redux (gisStationsStaticDistrict) - Bearbeitungsmodal (PoiUpdateModal) verwendet Redux-Daten (idLD → Gerätelabel) zur Initialisierung - Fix: Geräte-Dropdown im Modal zeigt nun den ausgewählten POI korrekt an - Refactor: `handleUpdatePoi()` nutzt `description` statt `name` - Fehlerbehandlung im Modal verbessert (alert bei leerem Feld, besseres Logging) - Redux-Thunk `updatePoiThunk` + `updatePoiService` stabilisiert - Map aktualisiert POIs nach Bearbeitung automatisch 📦 Version erhöht auf 1.1.253 🗓️ 11.06.2025
This commit is contained in:
@@ -12,7 +12,7 @@ NEXT_PUBLIC_DEBUG_LOG=false
|
|||||||
|
|
||||||
|
|
||||||
#auf dem Entwicklungsrechner dev läuft auf Port 3000 und auf dem Server prod auf Port 80, aber der WebService ist immer auf PORT 80
|
#auf dem Entwicklungsrechner dev läuft auf Port 3000 und auf dem Server prod auf Port 80, aber der WebService ist immer auf PORT 80
|
||||||
NEXT_PUBLIC_API_PORT_MODE=prod
|
|
||||||
NEXT_PUBLIC_USE_MOCKS=false
|
NEXT_PUBLIC_USE_MOCKS=false
|
||||||
|
|
||||||
# Der Unterordner talas5 gleich hinter der IP-Adresse (oder Servername) muss konfigurierbar sein.
|
# Der Unterordner talas5 gleich hinter der IP-Adresse (oder Servername) muss konfigurierbar sein.
|
||||||
|
|||||||
25
CHANGELOG.md
25
CHANGELOG.md
@@ -4,6 +4,31 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [1.1.253] – 2025-06-11
|
||||||
|
|
||||||
|
### ✨ Features
|
||||||
|
|
||||||
|
- POIs lassen sich jetzt vollständig erstellen, bearbeiten und löschen
|
||||||
|
- Tooltip zeigt den korrekten Gerätenamen (aus `gisStationsStaticDistrict`)
|
||||||
|
- Bearbeitungsdialog lädt initial die richtige Gerätezuteilung (Dropdown)
|
||||||
|
- Redux-Anbindung für `updatePoiService`, `updatePoiThunk`, `handlers.js` konsolidiert
|
||||||
|
|
||||||
|
### 🛠 Fixed
|
||||||
|
|
||||||
|
- Fehler beim Aktualisieren behoben (idLD und leeres Name-Feld)
|
||||||
|
- Dropdown im Modal zeigt jetzt korrekt das zum POI zugehörige Gerät
|
||||||
|
|
||||||
|
### 🧠 Architektur
|
||||||
|
|
||||||
|
- Kein direkter Zugriff mehr auf Name – nur `description` und `idLD`
|
||||||
|
- Fehlerhandling und Zustandskontrolle über Redux (Status, Error)
|
||||||
|
|
||||||
|
### 🔧 Version
|
||||||
|
|
||||||
|
- 📦 `appVersion.js` auf Version **1.1.253** erhöht
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [1.1.240] – 2025-06-06
|
## [1.1.240] – 2025-06-06
|
||||||
|
|
||||||
### ✨ UI-Verbesserung
|
### ✨ UI-Verbesserung
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -86,17 +86,16 @@ umgesetzt.
|
|||||||
2. **ZIP-Paket vorbereiten (lokal):**
|
2. **ZIP-Paket vorbereiten (lokal):**
|
||||||
|
|
||||||
- Verzeichnis `.next/`
|
- Verzeichnis `.next/`
|
||||||
- Verzeichnisse `public/`, `node_modules/` falls nich vorhanden sind oder etwas hinzugefügt wurd
|
- Verzeichnisse `public/`, `node_modules/` falls nicht vorhanden sind oder etwas hinzugefügt
|
||||||
(Bilder oder Bibliothek)
|
wurde (Bilder oder Bibliothek)
|
||||||
- Dateien `.env.production`, `package.json` falls nich vorhanden sind oder etwas hinzugefügt wurd
|
- Dateien `.env.production`, `package.json` falls nicht vorhanden sind oder etwas hinzugefügt
|
||||||
(Umgebungsvariablen oder Bibliothek)
|
wurde (Umgebungsvariablen oder Bibliothek)
|
||||||
- optional: `nssm.exe`, `StartNodeApp.bat`, `Start-Dev.ps1` um Windows Dienst zu erstellen falls
|
- `nssm.exe`, `StartNodeApp.bat`, `Start-Dev.ps1` um Windows Dienst zu erstellen falls noch nicht
|
||||||
noch nicht vorhanden ist Download:
|
vorhanden ist Download:
|
||||||
[nssm](https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt)
|
[nssm](https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt)
|
||||||
|
|
||||||
3. **Auf Server kopieren nach:** Ein Ordner temp auf dem Desktop erstellen->ZIP-Paket
|
3. **Auf Server kopieren nach:** Ein Ordner temp auf dem Desktop erstellen->ZIP-Paket
|
||||||
einfügen->entpacken->Inhalt in folgende Verzeichnis einfügen, weil verhindert Windows Server
|
einfügen->entpacken->Inhalt in folgende Verzeichnis einfügen
|
||||||
direkt kopieren in folgende Verzeichnis
|
|
||||||
|
|
||||||
```
|
```
|
||||||
C:\inetpub\wwwroot\talas5\nodeMap\
|
C:\inetpub\wwwroot\talas5\nodeMap\
|
||||||
|
|||||||
3
TODO.md
3
TODO.md
@@ -48,5 +48,6 @@
|
|||||||
optimiert besser als setInterval, zuerst nur für TALAS.web WebServices erstellen, irgendwann soll
|
optimiert besser als setInterval, zuerst nur für TALAS.web WebServices erstellen, irgendwann soll
|
||||||
die Daten von DB auch mit WebSocket gelöst werden
|
die Daten von DB auch mit WebSocket gelöst werden
|
||||||
|
|
||||||
- [ ] TODO: POI bearbeiten funktioniert es nicht
|
- [x] TODO: POI bearbeiten funktioniert es nicht
|
||||||
- [ ] TODO: Linien Links noch mit Port 3000
|
- [ ] TODO: Linien Links noch mit Port 3000
|
||||||
|
- [ ] TODO: Checkliste für README.md vorbereiten
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { selectMapLayersState } from "@/redux/slices/mapLayersSlice";
|
|||||||
import { selectPoiTypData, selectPoiTypStatus } from "@/redux/slices/database/pois/poiTypSlice";
|
import { selectPoiTypData, selectPoiTypStatus } from "@/redux/slices/database/pois/poiTypSlice";
|
||||||
import { deletePoiThunk } from "@/redux/thunks/database/pois/deletePoiThunk";
|
import { deletePoiThunk } from "@/redux/thunks/database/pois/deletePoiThunk";
|
||||||
import { updatePoiThunk } from "@/redux/thunks/database/pois/updatePoiThunk";
|
import { updatePoiThunk } from "@/redux/thunks/database/pois/updatePoiThunk";
|
||||||
import { selectSelectedPoi } from "@/redux/slices/database/pois/selectedPoiSlice";
|
|
||||||
import { handleSubmit } from "@/components/pois/poiUpdateModal/utils/handlers";
|
import { handleSubmit } from "@/components/pois/poiUpdateModal/utils/handlers";
|
||||||
import { selectCurrentPoi } from "@/redux/slices/database/pois/currentPoiSlice";
|
import { selectCurrentPoi } from "@/redux/slices/database/pois/currentPoiSlice";
|
||||||
import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice";
|
import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice";
|
||||||
@@ -56,17 +55,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
|||||||
}
|
}
|
||||||
}, [dispatch, poiTypStatus]);
|
}, [dispatch, poiTypStatus]);
|
||||||
|
|
||||||
/* useEffect(() => {
|
|
||||||
console.log("devices in PoiUpdateModal:", devices);
|
|
||||||
if (poi && devices.length > 0) {
|
|
||||||
const selectedDevice = devices.find(device => Number(device.idLD) === Number(poi.idLD));
|
|
||||||
console.log("Selected Device:", selectedDevice);
|
|
||||||
if (selectedDevice) {
|
|
||||||
setDeviceName({ value: selectedDevice.idLD, label: selectedDevice.name });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [poi, devices]); */
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("poiTypData in PoiUpdateModal:", poiTypData);
|
console.log("poiTypData in PoiUpdateModal:", poiTypData);
|
||||||
if (poi && poiTypData.length > 0) {
|
if (poi && poiTypData.length > 0) {
|
||||||
@@ -80,13 +68,13 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("availableDevices in PoiUpdateModal:", availableDevices);
|
console.log("availableDevices in PoiUpdateModal:", availableDevices);
|
||||||
if (poiData && availableDevices.length > 0) {
|
if (poi && availableDevices.length > 0) {
|
||||||
const selectedDevice = availableDevices.find(device => device.idLD === poiData.idLD);
|
const selectedDevice = availableDevices.find(device => device.IdLD === poi.idLD);
|
||||||
if (selectedDevice) {
|
if (selectedDevice) {
|
||||||
setDeviceName({ value: selectedDevice.idLD, label: selectedDevice.LD_Name }); // ✅ auch hier korrigieren
|
setDeviceName({ value: selectedDevice.IdLD, label: selectedDevice.LD_Name });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [poiData, availableDevices]);
|
}, [poi, availableDevices]);
|
||||||
|
|
||||||
const filterDevices = () => {
|
const filterDevices = () => {
|
||||||
const activeSystems = Object.keys(mapLayersVisibility).filter(
|
const activeSystems = Object.keys(mapLayersVisibility).filter(
|
||||||
@@ -106,7 +94,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
const deviceOptions = availableDevices.map(device => ({
|
const deviceOptions = availableDevices.map(device => ({
|
||||||
value: device.idLD,
|
value: device.IdLD,
|
||||||
label: device.LD_Name,
|
label: device.LD_Name,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -153,7 +141,22 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<form onSubmit={handleSubmit} className="m-0 p-2 w-full">
|
<form
|
||||||
|
onSubmit={event =>
|
||||||
|
handleSubmit({
|
||||||
|
event,
|
||||||
|
dispatch,
|
||||||
|
poiId,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
poiTypeId,
|
||||||
|
deviceName,
|
||||||
|
poi,
|
||||||
|
onClose,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
className="m-0 p-2 w-full"
|
||||||
|
>
|
||||||
<div className="flex flex-col mb-4">
|
<div className="flex flex-col mb-4">
|
||||||
<label htmlFor="description" className="block mb-2 font-bold text-sm text-gray-700">
|
<label htmlFor="description" className="block mb-2 font-bold text-sm text-gray-700">
|
||||||
Beschreibung:
|
Beschreibung:
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
|
// @/components/pois/poiUpdateModal/utils/handlers.js
|
||||||
|
import { updatePoiThunk } from "@/redux/thunks/database/pois/updatePoiThunk";
|
||||||
|
import { deletePoiThunk } from "@/redux/thunks/database/pois/deletePoiThunk";
|
||||||
|
|
||||||
export const handleSubmit = async ({
|
export const handleSubmit = async ({
|
||||||
event,
|
event,
|
||||||
dispatch,
|
dispatch,
|
||||||
poiId,
|
poiId,
|
||||||
name,
|
|
||||||
description,
|
description,
|
||||||
poiTypeId,
|
poiTypeId,
|
||||||
deviceName,
|
deviceName,
|
||||||
@@ -10,16 +13,18 @@ export const handleSubmit = async ({
|
|||||||
onClose,
|
onClose,
|
||||||
}) => {
|
}) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
const payload = {
|
||||||
|
idPoi: poiId,
|
||||||
|
name: description, // 💡 <- Das ist die entscheidende Änderung!
|
||||||
|
description,
|
||||||
|
idPoiTyp: poiTypeId?.value ?? poi?.idPoiTyp,
|
||||||
|
idLD: deviceName?.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("🔍 POI Update Payload:", payload);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await dispatch(
|
await dispatch(updatePoiThunk(payload)).unwrap();
|
||||||
updatePoiThunk({
|
|
||||||
idPoi: poiId,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
idPoiTyp: poiTypeId?.value ?? poi?.idPoiTyp,
|
|
||||||
idLD: deviceName?.value,
|
|
||||||
})
|
|
||||||
).unwrap();
|
|
||||||
onClose();
|
onClose();
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// /config/appVersion
|
// /config/appVersion
|
||||||
export const APP_VERSION = "1.1.253";
|
export const APP_VERSION = "1.1.254";
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
// pages/api/[...path].js
|
// pages/api/[...path].js
|
||||||
import { createProxyMiddleware } from "http-proxy-middleware";
|
import { createProxyMiddleware } from "http-proxy-middleware";
|
||||||
|
|
||||||
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
|
|
||||||
|
|
||||||
const target = mode === "dev" ? "http://localhost:80" : "http://localhost";
|
|
||||||
|
|
||||||
export default createProxyMiddleware({
|
export default createProxyMiddleware({
|
||||||
target,
|
target,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ app.prepare().then(() => {
|
|||||||
|
|
||||||
// fetchData immer ausführen – unabhängig vom Modus
|
// fetchData immer ausführen – unabhängig vom Modus
|
||||||
fetchData();
|
fetchData();
|
||||||
const interval = setInterval(fetchData, 5000);
|
const interval = setInterval(fetchData, 12000); // 12 Sekunden ,TALAS.web nutzt auch 12 Sekunden
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
console.log("❌ WebSocket getrennt");
|
console.log("❌ WebSocket getrennt");
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// /services/database/updatePoiService.js
|
// /services/database/updatePoiService.js
|
||||||
|
export const updatePoiService = async poi => {
|
||||||
export const updatePoiService = async (poi) => {
|
|
||||||
const response = await fetch("/api/talas_v5_DB/pois/updatePoi", {
|
const response = await fetch("/api/talas_v5_DB/pois/updatePoi", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -227,11 +227,7 @@ export const setupPolylines = (
|
|||||||
callback: e => {
|
callback: e => {
|
||||||
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
|
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
|
||||||
|
|
||||||
const baseUrl =
|
const baseUrl = `${window.location.protocol}//${window.location.hostname}:80${basePath}/`;
|
||||||
mode === "dev"
|
|
||||||
? `${window.location.protocol}//${window.location.hostname}:80${basePath}/`
|
|
||||||
: `${window.location.origin}${basePath}/`;
|
|
||||||
|
|
||||||
const link = `${baseUrl}devices/cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
|
const link = `${baseUrl}devices/cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
|
||||||
|
|
||||||
window.open(link, "_blank");
|
window.open(link, "_blank");
|
||||||
@@ -291,11 +287,7 @@ export const setupPolylines = (
|
|||||||
polyline.setStyle({ weight: 14 });
|
polyline.setStyle({ weight: 14 });
|
||||||
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
|
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
|
||||||
|
|
||||||
const baseUrl =
|
const baseUrl = `${window.location.protocol}//${window.location.hostname}:80${basePath}/`;
|
||||||
mode === "dev"
|
|
||||||
? `${window.location.protocol}//${window.location.hostname}:80${basePath}/`
|
|
||||||
: `${window.location.origin}${basePath}/`;
|
|
||||||
|
|
||||||
const link = `${baseUrl}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
|
const link = `${baseUrl}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
|
||||||
});
|
});
|
||||||
// error TypeError: Cannot read properties of null (reading 'contextmenu') wenn der Mas auf die Linie bleibt
|
// error TypeError: Cannot read properties of null (reading 'contextmenu') wenn der Mas auf die Linie bleibt
|
||||||
|
|||||||
Reference in New Issue
Block a user