docs: README.md mit Bilder

This commit is contained in:
ISA
2025-06-23 12:33:08 +02:00
parent c343bfb785
commit fae7595a58
16 changed files with 7900 additions and 9 deletions

View File

@@ -0,0 +1,29 @@
#.env.local
# DB-Settings (nur Backend)
DB_HOST=localhost
DB_USER=root
DB_PASSWORD="root#$"
DB_NAME=talas_v5
DB_PORT=3306
# Public Settings (Client braucht IP/Domain) , Variablen mit dem Präfix "NEXT_PUBLIC" ist in Browser sichtbar
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
NEXT_PUBLIC_API_PORT_MODE=prod
NEXT_PUBLIC_USE_MOCKS=false
# Der Unterordner talas5 gleich hinter der IP-Adresse (oder Servername) muss konfigurierbar sein.
# Es muss auch möglich sein kein Unterorder anzugeben (z.B. nur http://talasserver/).
# Ein Unterordner in der dort hinter liegenden Ordnerstruktur (z.B. http://talasserver/talas5/nodemap/api/talas_v5_DB/ usw.)
# kann bleiben da der Kunde diesen Unterordner talas:v5_db nicht ändert.
#Füge in deiner .env.local Datei die folgende Zeile hinzu wenn du einen Unterordner verwenden möchtest mit entsprechende Bezeichnung.
# z.B. http://10.10.0.13/talas5/index.aspx -> NEXT_PUBLIC_BASE_PATH=/talas5
# z.B. http://10.10.0.13/xyz/index.aspx -> NEXT_PUBLIC_BASE_PATH=/xyz
NEXT_PUBLIC_BASE_PATH=/talas5
# Oder leer lassen für direkten Zugriff -> NEXT_PUBLIC_BASE_PATH=
# App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.1.274

6
deployment/Start-Dev.ps1 Normal file
View File

@@ -0,0 +1,6 @@
# Navigiere zum Verzeichnis deines Projekts
cd 'C:\inetpub\wwwroot\talas5\nodeMap'
# F<>hre den npm Befehl aus
npm start

View File

@@ -0,0 +1 @@
PowerShell -ExecutionPolicy Bypass -File "C:\inetpub\wwwroot\talas5\nodeMap\Start-Dev.ps1"

BIN
deployment/nssm.exe Normal file

Binary file not shown.

View File

@@ -0,0 +1,48 @@
```markdown
- Als Administrator Eingabeaufforderung oder PowerShell öffnen
- Navigiere zu dem NodeMap Projekt Verzeichnis:
```shell
C:\Users\Administrator>cd C:\inetpub\wwwroot\talas5\nodeMap
```
- Befehl zum Erstellen eines Dienstes:
Führen Sie den folgenden Befehl aus, um einen neuen Dienst zu erstellen:
```shell
nssm.exe install NodeMapService
```
Nachdem Sie diesen Befehl ausgeführt haben, öffnet sich ein NSSM-Dialogfenster.
**Dienstkonfiguration:**
In dem geöffneten NSSM-Dialogfenster müssen Sie einige Parameter angeben:
- **Path:** Der Pfad zur ausführbaren Datei, die der Dienst ausführen soll.
```shell
C:\inetpub\wwwroot\talas5\nodeMap\StartNodeApp.bat
```
- **Startup directory:** Das Verzeichnis, in dem die Anwendung gestartet werden soll.
```shell
C:\inetpub\wwwroot\talas5\nodeMap
```
- **Arguments:** kann leer gelassen werden.
- Dienst starten:
Sobald der Dienst erstellt wurde, können Sie ihn starten.
Das können Sie entweder über die Eingabeaufforderung oder über die Diensteverwaltung von Windows tun.
Um den Dienst über die Eingabeaufforderung zu starten, verwenden Sie den folgenden Befehl:
```shell
nssm.exe start DienstName
```
---
- **Dienst bearbeiten:**
```shell
nssm.exe edit NodeMapService
```
- **Dienst entfernen:**
```shell
nssm.exe remove NodeMapService confirm
```
dauert bis 1 Minute
```

7670
deployment/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

62
deployment/package.json Normal file
View File

@@ -0,0 +1,62 @@
{
"name": "nodemap",
"version": "1.1.274",
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@heroicons/react": "^2.1.5",
"@mui/icons-material": "^6.0.2",
"@reduxjs/toolkit": "^2.5.1",
"autoprefixer": "^10.4.19",
"axios": "^1.7.9",
"cookies": "^0.9.1",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"fast-xml-parser": "^4.5.1",
"http-proxy-middleware": "^3.0.0",
"leaflet": "^1.9.4",
"leaflet-contextmenu": "^1.4.0",
"leaflet-control-geocoder": "^3.1.0",
"leaflet.smooth_marker_bouncing": "^3.1.0",
"mysql": "^2.18.1",
"mysql2": "^3.11.0",
"next": "^14.2.5",
"nextjs-cors": "^2.2.0",
"overlapping-marker-spiderfier-leaflet": "^0.2.7",
"postcss": "^8.4.40",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.2.0",
"react-select": "^5.8.0",
"react-toastify": "^10.0.5",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"tailwindcss": "^3.4.7",
"xml2js": "^0.6.2"
},
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "cross-env NODE_ENV=production node server.js",
"export": "next export",
"test": "jest",
"cypress": "cypress open",
"cypress:run": "cypress run",
"prepare": "husky",
"bump-version": "node ./scripts/bumpVersion.js"
},
"devDependencies": {
"cross-env": "^7.0.3",
"cypress": "^13.17.0",
"husky": "^9.1.7",
"identity-obj-proxy": "^3.0.0",
"jest-environment-jsdom": "^29.7.0",
"jest-fetch-mock": "^3.0.3",
"jest-junit": "^16.0.0",
"node-fetch": "^3.3.2",
"node-mocks-http": "^1.16.2",
"raw-loader": "^4.0.2"
}
}

128
deployment/server.js Normal file
View File

@@ -0,0 +1,128 @@
// server.js
const { createServer } = require("http");
const next = require("next");
const { Server } = require("socket.io");
const path = require("path");
const fs = require("fs");
const fetch = (...args) => import("node-fetch").then(({ default: fetch }) => fetch(...args));
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const PORT = 3000;
// Hilfsfunktion zum Schreiben von JSON-Dateien bei Änderung
const writeJsonFile = (filename, data) => {
const dir = path.join(process.cwd(), "websocketDump");
if (!fs.existsSync(dir)) fs.mkdirSync(dir);
const fullPath = path.join(dir, filename);
fs.writeFileSync(fullPath, JSON.stringify(data, null, 2), "utf-8");
};
// Extrahiert relevante Datenstruktur aus Antwort
const extractData = (json, name) => {
return (
json?.Statis || json?.Points || json?.Systems || json?.Rights || json?.[name] || json || []
);
};
app.prepare().then(() => {
const server = createServer((req, res) => {
handle(req, res);
});
const io = new Server(server);
io.on("connection", socket => {
const { m: idMap, u: idUser } = socket.handshake.query;
console.log(`🔌 WebSocket verbunden (idMap=${idMap}, idUser=${idUser})`);
const endpoints = [
{
name: "GisLinesStatus",
getUrl: () => `WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`,
mock: "GisLinesStatus.json",
},
{
name: "GisStationsMeasurements",
getUrl: () => `WebServiceMap.asmx/GisStationsMeasurements?idMap=${idMap}`,
mock: "GisStationsMeasurements.json",
},
{
name: "GisStationsStaticDistrict",
getUrl: () =>
`WebServiceMap.asmx/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`,
mock: "GisStationsStaticDistrict.json",
},
{
name: "GisStationsStatusDistrict",
getUrl: () =>
`WebServiceMap.asmx/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`,
mock: "GisStationsStatusDistrict.json",
},
{
name: "GisSystemStatic",
getUrl: () => `WebServiceMap.asmx/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`,
mock: "GisSystemStatic.json",
},
];
const lastDataMap = {};
const fetchData = async () => {
for (const { name, getUrl, mock } of endpoints) {
try {
let statis;
if (dev) {
const mockPath = path.join(process.cwd(), "mockData", mock);
const jsonStr = fs.readFileSync(mockPath, "utf-8");
const json = JSON.parse(jsonStr);
statis = extractData(json, name);
console.log(`🧪 [Mock] ${name}`);
} else {
const fetchUrl = `http://localhost/talas5/ClientData/${getUrl()}`;
const res = await fetch(fetchUrl);
const text = await res.text();
let json;
try {
json = JSON.parse(text);
} catch (err) {
console.error(`${name}: JSON Parsing fehlgeschlagen:`, err.message);
console.error(`🔍 Antwort war:`, text.slice(0, 300));
continue;
}
statis = extractData(json, name);
console.log(`📡 Webservice-Daten empfangen für ${name}`);
}
const newDataStr = JSON.stringify(statis);
if (newDataStr !== lastDataMap[name]) {
lastDataMap[name] = newDataStr;
socket.emit(`${name}Updated`, statis);
console.log(`✅ Änderung bei ${name} erkannt → gesendet`);
writeJsonFile(`${name}.json`, statis);
} else {
// console.log(`🔁 ${name}: Keine Änderung`);
}
} catch (error) {
console.error(`❌ Fehler bei ${name}:`, error.message);
}
}
};
// fetchData immer ausführen unabhängig vom Modus
fetchData();
const interval = setInterval(fetchData, 5000); // 5 Sekunden ,TALAS.web nutzt 12 Sekunden
socket.on("disconnect", () => {
clearInterval(interval);
console.log("❌ WebSocket getrennt");
});
});
server.listen(PORT, () => {
console.log(`🚀 App + WebSocket läuft auf http://localhost:${PORT}`);
});
});