commit
3415819c25
13
.foreverignore
Normal file
13
.foreverignore
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
node_modules/*
|
||||||
|
public/*
|
||||||
|
views/*
|
||||||
|
misc/*
|
||||||
|
*.html
|
||||||
|
*.jpeg
|
||||||
|
*.png
|
||||||
|
*.mp3
|
||||||
|
*.wav
|
||||||
|
*.md
|
||||||
|
*.sqlite3
|
||||||
|
*-journal
|
||||||
|
sessions
|
||||||
10
.gitignore
vendored
10
.gitignore
vendored
@ -80,9 +80,8 @@ _old/
|
|||||||
|
|
||||||
# db
|
# db
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
|
|
||||||
# other
|
|
||||||
*.db
|
*.db
|
||||||
|
sessions
|
||||||
|
|
||||||
# ssl
|
# ssl
|
||||||
.crt
|
.crt
|
||||||
@ -95,4 +94,11 @@ public/media/*
|
|||||||
!public/media/marker-shadow.png
|
!public/media/marker-shadow.png
|
||||||
!public/media/bell_long.mp3
|
!public/media/bell_long.mp3
|
||||||
!public/media/bell_short.mp3
|
!public/media/bell_short.mp3
|
||||||
|
!public/media/bell_message.mp3
|
||||||
*.bak
|
*.bak
|
||||||
|
*.save
|
||||||
|
|
||||||
|
# backup-files
|
||||||
|
misc/*
|
||||||
|
!misc/server.cert
|
||||||
|
!misc/server.key
|
||||||
15
README.md
15
README.md
@ -1,7 +1,7 @@
|
|||||||
# Wachalarm-IP-Web
|
# Wachalarm-IP-Web
|
||||||

|

|
||||||
# DEMO
|
# DEMO
|
||||||
[📺🔥 https://am7.info.tm/](https://am7.info.tm/)
|
[📺🔥 https://wachalarm.info.tm/](https://wachalarm.info.tm/)
|
||||||
|
|
||||||
Login-Daten:
|
Login-Daten:
|
||||||
- Benutzer: me
|
- Benutzer: me
|
||||||
@ -9,17 +9,11 @@ Login-Daten:
|
|||||||
|
|
||||||
Die Demo-Version zeigt frei erfundene Einsätze die jede Stunde neu alarmiert werden. Ohne Login wird der Wachalarm mit reduziertem Inhalt dargestellt (zur Wahrung des Datenschutzes).
|
Die Demo-Version zeigt frei erfundene Einsätze die jede Stunde neu alarmiert werden. Ohne Login wird der Wachalarm mit reduziertem Inhalt dargestellt (zur Wahrung des Datenschutzes).
|
||||||
|
|
||||||
## TO-DO
|
|
||||||
Nachfolgende Funktionen befinden sich noch in der Entwicklung:
|
|
||||||
- Dauer der Anzeige des Wachalarms sollte durch Benutzer festgelegt werden können (aktuell immer 10 Minuten)
|
|
||||||
- für jeden neuen Einsatz sollte eine UUID erstellt werden, die bei nachfolgen Alarmierungen verglichen wird (zur Vermeidung von doppelten Alarmierungen)
|
|
||||||
- Rückmeldefunktion für Einsatzkräfte (auf der Oberfläche des Wachalarms, ohne externe Schnittstelle)
|
|
||||||
- Mehr Informationen für angemeldete Benutzer ("Angemeldet als ...", Berechtigungen, etc.)
|
|
||||||
|
|
||||||
# Beschreibung
|
# Beschreibung
|
||||||
Ziel dieser Version des Wachalarms soll es sein, auf jedem Endgerät - egal ob Windows, Linux, Mac, PC oder Smartphone - Alarme anzuzeigen ohne zusätzliche Software zu installieren. Da es sich beim Wachalarm-IP-Web um eine reine Web-Server-Anwendung handelt, sollte dieser am besten durch eine Leitstelle betrieben werden, die Einsatzalarme direkt an das System übergibt. Der Zugriff erfolgt dann innerhalb eines geschützten Netzwerkes (VPN, LAN etc.) oder direkt über das Internet (sofern freigegeben und gewollt).
|
Ziel dieser Version des Wachalarms soll es sein, auf jedem Endgerät - egal ob Windows, Linux, Mac, PC oder Smartphone - Alarme anzuzeigen ohne zusätzliche Software zu installieren. Da es sich beim Wachalarm-IP-Web um eine reine Web-Server-Anwendung handelt, sollte dieser am besten durch eine Leitstelle betrieben werden, die Einsatzalarme direkt an das System übergibt. Der Zugriff erfolgt dann innerhalb eines geschützten Netzwerkes (VPN, LAN etc.) oder direkt über das Internet (sofern freigegeben und gewollt).
|
||||||
Der Web-Server empfängt Einsatzdaten über eine definierte [Schnittstelle
|
Der Web-Server empfängt Einsatzdaten über eine definierte [Schnittstelle
|
||||||
](#schnittstelle) aus dem Einsatzleitsystem (oder anderen Systemen) und übersendet diese dann an die jeweiligen Clients.
|
](#schnittstelle) aus dem Einsatzleitsystem (oder anderen Systemen) und übersendet diese dann an die jeweiligen Clients.
|
||||||
|
|
||||||
## Funktionsumfang
|
## Funktionsumfang
|
||||||
- Anzeige verschiedener Wachalarme für einzelne Wachen, Träger oder ganze Kreise
|
- Anzeige verschiedener Wachalarme für einzelne Wachen, Träger oder ganze Kreise
|
||||||
- Ausgabe synthetischer Sprachdurchsagen (Gong, Einsatzart, Stichwort, Ort, Ortsteile, beteiligte Einsatzmittel, Sondersignal)
|
- Ausgabe synthetischer Sprachdurchsagen (Gong, Einsatzart, Stichwort, Ort, Ortsteile, beteiligte Einsatzmittel, Sondersignal)
|
||||||
@ -32,6 +26,11 @@ Der Web-Server empfängt Einsatzdaten über eine definierte [Schnittstelle
|
|||||||
- Volle kompatibilität mit den gängigen Browsern (getestet in Chrome, Firefox, Safari, Microsoft Edge)
|
- Volle kompatibilität mit den gängigen Browsern (getestet in Chrome, Firefox, Safari, Microsoft Edge)
|
||||||
- Basierend auf modernsten Web-Technologien ([Node.js](https://nodejs.org/), [Express](https://expressjs.com/de/), [Socket.io](https://socket.io/), [Passport](http://www.passportjs.org/), [SQLite](https://www.sqlite.org/), [Bootstrap](https://getbootstrap.com/), [Leaflet](https://leafletjs.com/))
|
- Basierend auf modernsten Web-Technologien ([Node.js](https://nodejs.org/), [Express](https://expressjs.com/de/), [Socket.io](https://socket.io/), [Passport](http://www.passportjs.org/), [SQLite](https://www.sqlite.org/), [Bootstrap](https://getbootstrap.com/), [Leaflet](https://leafletjs.com/))
|
||||||
|
|
||||||
|
## offene Punkte
|
||||||
|
Neue Funktionen oder bekannte Probleme werden schrittweise hinterlegt.
|
||||||
|
Eine Aufzählung findet sich [hier](https://github.com/Robert-112/Wachalarm-IP-Web/TODO.md).
|
||||||
|
|
||||||
|
|
||||||
# Installation & Konfiguration
|
# Installation & Konfiguration
|
||||||
## Vorbereitung & Installation
|
## Vorbereitung & Installation
|
||||||
1. Installation von [Node.js](https://nodejs.org/) (Version 10 LTS oder höher)
|
1. Installation von [Node.js](https://nodejs.org/) (Version 10 LTS oder höher)
|
||||||
|
|||||||
54
TODO.md
Normal file
54
TODO.md
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# Fehler und geplante Neuerungen
|
||||||
|
|
||||||
|
## 1. Priorität (Fehler)
|
||||||
|
|
||||||
|
- für jeden neuen Einsatz sollte eine UUID erstellt werden, die bei nachfolgen Alarmierungen verglichen wird (zur Vermeidung von doppelten Alarmierungen, falls über die Schnittstelle der Alarm nochmals gleichlautend übermittelt wird)
|
||||||
|
- Wachalarm-Besonderheiten-Text bei senden an bestehende Verbindung fehlerhaft (KW)
|
||||||
|
- Darstellung in Safari-Mobil fehlerhaft (generell Mobil, ggf. extra Darstellung)
|
||||||
|
- Buttons für Sounds werden fehlerhaft dargestellt
|
||||||
|
- Uhrzeit in der Datenbank (und im Log) ist auf UTC, sollte aber lokale Zeit sein
|
||||||
|
- Absturz bei unbekannter/falscher Wachennummer in Alarmmonitor-URL
|
||||||
|
- openstreetmap credit
|
||||||
|
- name, leitstelle, version immer mitgeben
|
||||||
|
- Eingaben auf validität prüfen
|
||||||
|
|
||||||
|
## 2. Priorität (notwendige Anpassungen)
|
||||||
|
|
||||||
|
- Mehr Informationen für angemeldete Benutzer ("Angemeldet als ...", Berechtigungen, etc.)
|
||||||
|
- Login verbessern:
|
||||||
|
- Login-Seite benötigt Fehlerrückmeldung (wie Nutzerverwaltung): falsches Kennwort, Nutzer nicht vorhanden etc.
|
||||||
|
- Login/Logout protokollieren
|
||||||
|
- fehlerhafte/doppelte Logins protokollieren
|
||||||
|
- prüfen ob es sinnvoll ist, bereits eingeloggte User nicht mehr zulassen (Session prüfen)
|
||||||
|
- bei fehlendem Login zur Login-Seite weiterleiten und nach dem Login die zuvor besuchte Seite anzeigen
|
||||||
|
- Information in Wachalarm-Bild ob alle Rechte, oder ob reduzierte Version
|
||||||
|
- ❗Benutzerrechte in Implizite (darf reduziert sehen) und Explizite (darf alles sehen) unterscheiden
|
||||||
|
- ❗/waip/0 umändern, so dass nur die Wachalarme angezeigt werden, für die man entsprechende rechte hat
|
||||||
|
- ❗/waip/einsatz-Id schaffen
|
||||||
|
- Seite mit aktiven Clients anpassen:
|
||||||
|
- nicht zwingend als Tabelle, sondern eher als .col mit Buttons um Aktionen an Clients zu senden
|
||||||
|
- einzelnen Client über Verwaltungsoberfläche neu laden lassen
|
||||||
|
- besserer Log-Status: Browserversion ermitteln, User ermitteln
|
||||||
|
- Uhrzeit am Anfang irgendwo platzieren (nicht immer oben links)
|
||||||
|
- Maus auf Alarmmonitor nach Zeit x ausblenden
|
||||||
|
- Datenbank nach bestimmter Zeit aufräumen
|
||||||
|
- Client-IP bei Reverse-Proxy richtig ermitteln
|
||||||
|
- eingehende JSON-Objekte auf plausibilität prüfen
|
||||||
|
|
||||||
|
## 3. Priorität (Neuerungen)
|
||||||
|
|
||||||
|
- Rückmeldefunktion für Einsatzkräfte
|
||||||
|
- Schnittstelle zu weiterem Wachalarm-Web-Server um Einsätze und Rückmeldungen untereinander auszutauschen
|
||||||
|
- Pakete aktualisieren
|
||||||
|
- textfit aktualisieren
|
||||||
|
|
||||||
|
## 4. Priorität (zu späterer Zeit)
|
||||||
|
|
||||||
|
- anpassen der Durchsage je Benutzer, durch eigene Ersetzung und Reihenfolge
|
||||||
|
- Ausnahmen festlegen können, wann keine Musik abgespielt wird
|
||||||
|
- Indivduelle Texte für Web-Anwendung hinterlegen können:
|
||||||
|
- "© Leitstelle Lausitz"
|
||||||
|
- Impressium
|
||||||
|
- Datenschutzerklärung
|
||||||
|
- Titel der Anwendung
|
||||||
|
- Versionsnummer
|
||||||
9651
package-lock.json
generated
9651
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
@ -2,28 +2,39 @@
|
|||||||
"name": "waip-web",
|
"name": "waip-web",
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"description": "Web-Version des Wachalarm-IP",
|
"description": "Web-Version des Wachalarm-IP",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Robert-112/Wachalarm-IP-Web.git"
|
||||||
|
},
|
||||||
|
"license": "Creative Commons Attribution Share Alike 4.0 International",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js"
|
"start": "node server.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@turf/turf": "^5.1.6",
|
||||||
"async": "^3.1.0",
|
"async": "^3.1.0",
|
||||||
"bcrypt": "^3.0.6",
|
"bcrypt": "^3.0.7",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"connect-sqlite3": "^0.9.11",
|
"connect-sqlite3": "^0.9.11",
|
||||||
"cookie-parser": "^1.4.4",
|
"cookie-parser": "^1.4.4",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.16.2",
|
"express-session": "^1.17.0",
|
||||||
"npm": "^6.10.2",
|
"json2csv": "^5.0.1",
|
||||||
"passport": "^0.4.0",
|
"nodemailer": "^6.4.10",
|
||||||
|
"npm": "^6.13.4",
|
||||||
|
"passport": "^0.4.1",
|
||||||
"passport-ip": "^0.1.2",
|
"passport-ip": "^0.1.2",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"passport.socketio": "^3.7.0",
|
"passport.socketio": "^3.7.0",
|
||||||
"pug": "^2.0.4",
|
"pug": "^2.0.4",
|
||||||
"req-flash": "0.0.3",
|
"req-flash": "0.0.3",
|
||||||
"serve-favicon": "^2.5.0",
|
"serve-favicon": "^2.5.0",
|
||||||
"socket.io": "^2.2.0",
|
"socket.io": "^2.3.0",
|
||||||
"sqlite3": "^4.0.9"
|
"socket.io-client": "^2.3.0",
|
||||||
|
"sqlite3": "^4.1.1",
|
||||||
|
"twit": "^2.2.11",
|
||||||
|
"uuid": "^8.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
13693
public/css/bootstrap.css
vendored
13693
public/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
4
public/css/ionicons.min.css
vendored
4
public/css/ionicons.min.css
vendored
File diff suppressed because one or more lines are too long
2
public/css/vis-timeline.css
Executable file
2
public/css/vis-timeline.css
Executable file
File diff suppressed because one or more lines are too long
@ -24,7 +24,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fullheight {
|
.fullheight {
|
||||||
height: calc(100vh - 60px - 5rem);
|
height: calc(100vh - 60px - 5rem - 2rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Anpassungen an Bootstrap ******************/
|
/*** Anpassungen an Bootstrap ******************/
|
||||||
@ -61,10 +61,6 @@ audio {
|
|||||||
height: 40% !important;
|
height: 40% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h-70 {
|
|
||||||
height: 70% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h-45 {
|
.h-45 {
|
||||||
height: 45% !important;
|
height: 45% !important;
|
||||||
}
|
}
|
||||||
@ -73,10 +69,18 @@ audio {
|
|||||||
height: 55% !important;
|
height: 55% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-60 {
|
||||||
|
height: 60% !important;
|
||||||
|
}
|
||||||
|
|
||||||
.h-65 {
|
.h-65 {
|
||||||
height: 65% !important;
|
height: 65% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-70 {
|
||||||
|
height: 70% !important;
|
||||||
|
}
|
||||||
|
|
||||||
.h-80 {
|
.h-80 {
|
||||||
height: 80% !important;
|
height: 80% !important;
|
||||||
}
|
}
|
||||||
@ -161,7 +165,23 @@ audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** Texte des Bildschirmschoners dynamisch bewegen lassen **********/
|
/*** Texte des Bildschirmschoners dynamisch bewegen lassen ***/
|
||||||
|
|
||||||
|
.clock_y {
|
||||||
|
position:fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client_wache {
|
||||||
|
animation: x2 1200s linear infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes x2 {
|
||||||
|
100% {
|
||||||
|
transform: translatex(300%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Texte des Bildschirmschoners dynamisch bewegen lassen
|
||||||
|
|
||||||
.clock_x {
|
.clock_x {
|
||||||
animation: x 1200s linear infinite alternate;
|
animation: x 1200s linear infinite alternate;
|
||||||
@ -183,12 +203,12 @@ audio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.client_wache {
|
******/
|
||||||
animation: x2 1200s linear infinite alternate;
|
|
||||||
|
#em_alarmiert, #rmld_container {
|
||||||
|
font-size: 1.6vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes x2 {
|
#headline {
|
||||||
100% {
|
height: 2rem;
|
||||||
transform: translatex(300%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 305 KiB After Width: | Height: | Size: 305 KiB |
Binary file not shown.
Binary file not shown.
546
public/js/client_dbrd.js
Executable file
546
public/js/client_dbrd.js
Executable file
@ -0,0 +1,546 @@
|
|||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
// Sound nicht beim laden der Seite abspielen
|
||||||
|
var audio = document.getElementById('audio');
|
||||||
|
audio.src = ('/media/bell_message.mp3');
|
||||||
|
audio.volume = 0.0;
|
||||||
|
setTimeout(function () {
|
||||||
|
audio.pause();
|
||||||
|
audio.currentTime = 0;
|
||||||
|
audio.volume = 1.0;
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ######### LEAFLET ######### */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// Karte definieren
|
||||||
|
var map = L.map('map', {
|
||||||
|
zoomControl: false
|
||||||
|
}).setView([51.733005, 14.338048], 13);
|
||||||
|
|
||||||
|
// Layer der Karte
|
||||||
|
mapLink = L.tileLayer(
|
||||||
|
map_tile, {
|
||||||
|
maxZoom: 18,
|
||||||
|
attribution: map_attribution
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// Icon der Karte zuordnen
|
||||||
|
var redIcon = new L.Icon({
|
||||||
|
iconUrl: '/media/marker-icon-2x-red.png',
|
||||||
|
shadowUrl: '/media/marker-shadow.png',
|
||||||
|
iconSize: [25, 41],
|
||||||
|
iconAnchor: [12, 41],
|
||||||
|
popupAnchor: [1, -34],
|
||||||
|
shadowSize: [41, 41]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Icon setzen
|
||||||
|
var marker = L.marker(new L.LatLng(0, 0), {
|
||||||
|
icon: redIcon
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// GeoJSON vordefinieren
|
||||||
|
var geojson = L.geoJSON().addTo(map);
|
||||||
|
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ####### Rückmeldung ####### */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
var counter_rmld = [];
|
||||||
|
|
||||||
|
var counter_ID = 0;
|
||||||
|
|
||||||
|
function start_counter(zeitstempel, ablaufzeit) {
|
||||||
|
// Split timestamp into [ Y, M, D, h, m, s ]
|
||||||
|
var t1 = zeitstempel.split(/[- :]/),
|
||||||
|
t2 = ablaufzeit.split(/[- :]/);
|
||||||
|
|
||||||
|
var start = new Date(t1[0], t1[1] - 1, t1[2], t1[3], t1[4], t1[5]),
|
||||||
|
end = new Date(t2[0], t2[1] - 1, t2[2], t2[3], t2[4], t2[5]);
|
||||||
|
|
||||||
|
clearInterval(counter_ID);
|
||||||
|
counter_ID = setInterval(function () {
|
||||||
|
do_progressbar(start, end);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
function reset_rmld(p_uuid) {
|
||||||
|
var bar_uuid = 'bar-' + p_uuid;
|
||||||
|
$('#pg-ek').children().each(function (i) {
|
||||||
|
if (!$(this).hasClass(bar_uuid)) {
|
||||||
|
$(this).remove();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
$('#pg-ma').children().each(function (i) {
|
||||||
|
if (!$(this).hasClass(bar_uuid)) {
|
||||||
|
$(this).remove();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
$('#pg-fk').children().each(function (i) {
|
||||||
|
if (!$(this).hasClass(bar_uuid)) {
|
||||||
|
$(this).remove();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function add_resp_progressbar(p_uuid, p_id, p_type, p_agt, p_start, p_end) {
|
||||||
|
// Hintergrund der Progressbar festlegen
|
||||||
|
var bar_background = '';
|
||||||
|
var bar_border = '';
|
||||||
|
if (p_agt) {
|
||||||
|
bar_border = 'border border-warning';
|
||||||
|
};
|
||||||
|
switch (p_type) {
|
||||||
|
case 'ek':
|
||||||
|
bar_background = 'bg-success';
|
||||||
|
break;
|
||||||
|
case 'ma':
|
||||||
|
bar_background = 'bg-info';
|
||||||
|
break;
|
||||||
|
case 'fk':
|
||||||
|
bar_background = 'bg-light';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bar_background = '';
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
var bar_uuid = 'bar-' + p_uuid;
|
||||||
|
// pruefen ob div mit id 'pg-'+p_id schon vorhanden ist
|
||||||
|
var pgbar = document.getElementById('pg-' + p_id);
|
||||||
|
if (!pgbar) {
|
||||||
|
$('#pg-' + p_type).append('<div class="progress mt-1 position-relative ' + bar_border + ' ' + bar_uuid + '" id="pg-' + p_id + '" style="height: 15px; font-size: 14px;"></div>');
|
||||||
|
$('#pg-' + p_id).append('<div id="pg-bar-' + p_id + '" class="progress-bar progress-bar-striped ' + bar_background + '" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>');
|
||||||
|
$('#pg-bar-' + p_id).append('<small id="pg-text-' + p_id + '" class="justify-content-center d-flex position-absolute w-100"></small>');
|
||||||
|
} else {
|
||||||
|
// TODO PG-Bar ändern falls neue/angepasste Rückmeldung
|
||||||
|
};
|
||||||
|
// Zeitschiene Anpassen
|
||||||
|
clearInterval(counter_rmld[p_id]);
|
||||||
|
counter_rmld[p_id] = 0;
|
||||||
|
counter_rmld[p_id] = setInterval(function () {
|
||||||
|
do_rmld_bar(p_id, p_start, p_end);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
function do_rmld_bar(p_id, start, end) {
|
||||||
|
//console.log(p_id);
|
||||||
|
today = new Date();
|
||||||
|
// restliche Zeit ermitteln
|
||||||
|
var current_progress = Math.round(100 / (start.getTime() - end.getTime()) * (start.getTime() - today.getTime()));
|
||||||
|
|
||||||
|
var diff = Math.abs(end - today);
|
||||||
|
var minutesDifference = Math.floor(diff / 1000 / 60);
|
||||||
|
diff -= minutesDifference * 1000 * 60;
|
||||||
|
var secondsDifference = Math.floor(diff / 1000);
|
||||||
|
if (secondsDifference <= 9) {
|
||||||
|
secondsDifference = '0' + secondsDifference;
|
||||||
|
};
|
||||||
|
var minutes = minutesDifference + ':' + secondsDifference;
|
||||||
|
// Progressbar anpassen
|
||||||
|
if (current_progress >= 100) {
|
||||||
|
$('#pg-bar-' + p_id)
|
||||||
|
.css('width', '100%')
|
||||||
|
.attr('aria-valuenow', 100)
|
||||||
|
.addClass('ion-md-checkmark-circle');
|
||||||
|
$('#pg-text-' + p_id).text('');
|
||||||
|
// FIXME Counter_Id not defined
|
||||||
|
clearInterval(counter_ID[p_id]);
|
||||||
|
} else {
|
||||||
|
$('#pg-bar-' + p_id)
|
||||||
|
.css('width', current_progress + '%')
|
||||||
|
.attr('aria-valuenow', current_progress);
|
||||||
|
$('#pg-text-' + p_id).text(minutes);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function recount_rmld(p_uuid) {
|
||||||
|
var bar_uuid = 'bar-' + p_uuid;
|
||||||
|
var agt_count = 0;
|
||||||
|
// Zähler auf 0 Setzen
|
||||||
|
$('#ek-counter').text(0);
|
||||||
|
$('#ma-counter').text(0);
|
||||||
|
$('#fk-counter').text(0);
|
||||||
|
$('#agt-counter').text(0);
|
||||||
|
// EK zählen
|
||||||
|
$('#pg-ek').children().each(function (i) {
|
||||||
|
if ($(this).hasClass(bar_uuid)) {
|
||||||
|
var tmp_count = parseInt($('#ek-counter').text());
|
||||||
|
$('#ek-counter').text(tmp_count + 1);
|
||||||
|
if ($(this).hasClass('border-warning')) {
|
||||||
|
agt_count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// MA zählen
|
||||||
|
$('#pg-ma').children().each(function (i) {
|
||||||
|
if ($(this).hasClass(bar_uuid)) {
|
||||||
|
var tmp_count = parseInt($('#ma-counter').text());
|
||||||
|
$('#ma-counter').text(tmp_count + 1);
|
||||||
|
if ($(this).hasClass('border-warning')) {
|
||||||
|
agt_count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// FK zählen
|
||||||
|
$('#pg-fk').children().each(function (i) {
|
||||||
|
if ($(this).hasClass(bar_uuid)) {
|
||||||
|
var tmp_count = parseInt($('#fk-counter').text());
|
||||||
|
$('#fk-counter').text(tmp_count + 1);
|
||||||
|
if ($(this).hasClass('border-warning')) {
|
||||||
|
agt_count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// AGT setzen
|
||||||
|
$('#agt-counter').text(agt_count);
|
||||||
|
// Rückmeldecontainer anzeigen/ausblenden
|
||||||
|
if ($('#ek-counter').text() == '0' && $('#ma-counter').text() == '0' && $('#fk-counter').text() == '0' && $('#agt-counter').text() == '0') {
|
||||||
|
$('#rmld_container').addClass('d-none');
|
||||||
|
} else {
|
||||||
|
$('#rmld_container').removeClass('d-none');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ####### Timeline ######## */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// DOM element where the Timeline will be attached
|
||||||
|
var container = document.getElementById('visualization');
|
||||||
|
var items = new vis.DataSet();
|
||||||
|
var groups = new vis.DataSet();
|
||||||
|
|
||||||
|
// Configuration for the Timeline
|
||||||
|
var customDate = new Date();
|
||||||
|
var alert_start = new Date(customDate.setMinutes(customDate.getMinutes() - 2));
|
||||||
|
var timeline_end = new Date(customDate.setMinutes(customDate.getMinutes() + 13));
|
||||||
|
var options = {
|
||||||
|
rollingMode: {
|
||||||
|
follow: true,
|
||||||
|
offset: 0.25
|
||||||
|
},
|
||||||
|
start: alert_start,
|
||||||
|
end: timeline_end
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a Timeline
|
||||||
|
var timeline = new vis.Timeline(container, items, options);
|
||||||
|
timeline.setGroups(groups);
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ######## SOCKET.IO ######## */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// Websocket
|
||||||
|
var socket = io('/dbrd');
|
||||||
|
|
||||||
|
// Wachen-ID bei Connect an Server senden
|
||||||
|
socket.on('connect', function () {
|
||||||
|
socket.emit('dbrd', dbrd_uuid);
|
||||||
|
$('#waipModal').modal('hide');
|
||||||
|
// TODO: bei Reconnect des Clients durch Verbindungsabbruch, erneut Daten anfordern
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('connect_error', function (err) {
|
||||||
|
$('#waipModalTitle').html('FEHLER');
|
||||||
|
$('#waipModalBody').html('Verbindung zum Server getrennt!');
|
||||||
|
$('#waipModal').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ID von Server und Client vergleichen, falls ungleich -> Seite neu laden
|
||||||
|
socket.on('io.version', function (server_id) {
|
||||||
|
if (client_id != server_id) {
|
||||||
|
$('#waipModal').modal('hide');
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#waipModalTitle').html('ACHTUNG');
|
||||||
|
$('#waipModalBody').html('Neue Server-Version. Seite wird in 10 Sekunden neu geladen!');
|
||||||
|
$('#waipModal').modal('show');
|
||||||
|
setTimeout(function () {
|
||||||
|
location.reload();
|
||||||
|
}, 10000);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// ggf. Fehler ausgeben
|
||||||
|
socket.on('io.error', function (data) {
|
||||||
|
console.log('Error:', data);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Daten löschen, Uhr anzeigen
|
||||||
|
socket.on('io.deleted', function (data) {
|
||||||
|
console.log('del')
|
||||||
|
// Einsatz nicht mehr vorhanden
|
||||||
|
$('#waipModal').modal('hide');
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#waipModalTitle').html('ACHTUNG');
|
||||||
|
$('#waipModalBody').html(`Der aufgerufene Einsatz wurde gelöscht und ist in diesem System nicht mehr verfügbar.<br>
|
||||||
|
Sie werden in einer Minute auf die Startseite zurückgeleitet.`);
|
||||||
|
$('#waipModal').modal('show');
|
||||||
|
setTimeout(function () {
|
||||||
|
window.location.href = window.location.origin;
|
||||||
|
}, 60000);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Einsatzdaten laden, Wachalarm anzeigen
|
||||||
|
socket.on('io.Einsatz', function (data) {
|
||||||
|
// DEBUG
|
||||||
|
console.log(data);
|
||||||
|
// Einsatz-ID speichern
|
||||||
|
waip_id = data.id;
|
||||||
|
// DBRD-ID und Zeit setzten
|
||||||
|
$('#dbrd_id').html(data.uuid);
|
||||||
|
$('#einsatz_datum').html(data.zeitstempel);
|
||||||
|
|
||||||
|
// Hintergrund der Einsatzart zunächst entfernen
|
||||||
|
$('#einsatz_art').removeClass(function (index, className) {
|
||||||
|
return (className.match(/(^|\s)bg-\S+/g) || []).join(' ');
|
||||||
|
});
|
||||||
|
// Icon der Einsatzart enfernen
|
||||||
|
$('#einsatz_stichwort').removeClass();
|
||||||
|
// Art und Stichwort festlegen hinterlegen
|
||||||
|
switch (data.einsatzart) {
|
||||||
|
case 'Brandeinsatz':
|
||||||
|
$('#einsatz_art').addClass('bg-danger');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-flame');
|
||||||
|
$('#rueckmeldung').removeClass('d-none');
|
||||||
|
break;
|
||||||
|
case 'Hilfeleistungseinsatz':
|
||||||
|
$('#einsatz_art').addClass('bg-info');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-construct');
|
||||||
|
$('#rueckmeldung').removeClass('d-none');
|
||||||
|
break;
|
||||||
|
case 'Rettungseinsatz':
|
||||||
|
$('#einsatz_art').addClass('bg-warning');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-medkit');
|
||||||
|
break;
|
||||||
|
case 'Krankentransport':
|
||||||
|
$('#einsatz_art').addClass('bg-success');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-medical');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$('#einsatz_art').addClass('bg-secondary');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-information-circle');
|
||||||
|
};
|
||||||
|
$('#einsatz_stichwort').html(' ' + data.stichwort);
|
||||||
|
// Sondersignal setzen
|
||||||
|
$('#sondersignal').removeClass();
|
||||||
|
switch (data.sondersignal) {
|
||||||
|
case 1:
|
||||||
|
$('#sondersignal').addClass('ion-md-notifications');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$('#sondersignal').addClass('ion-md-notifications-off');
|
||||||
|
};
|
||||||
|
// Ortsdaten zusammenstellen und setzen
|
||||||
|
$('#einsatzort_list').empty();
|
||||||
|
if (data.objekt) {
|
||||||
|
$('#einsatzort_list').append('<li class="list-group-item">' + data.objekt+ '</li>');
|
||||||
|
};
|
||||||
|
if (data.ort) {
|
||||||
|
$('#einsatzort_list').append('<li class="list-group-item">' + data.ort+ '</li>');
|
||||||
|
};
|
||||||
|
if (data.ortsteil) {
|
||||||
|
$('#einsatzort_list').append('<li class="list-group-item">' + data.ortsteil+ '</li>');
|
||||||
|
};
|
||||||
|
if (data.strasse) {
|
||||||
|
$('#einsatzort_list').append('<li class="list-group-item">' + data.strasse+ '</li>');
|
||||||
|
};
|
||||||
|
if (data.besonderheiten) {
|
||||||
|
$('#einsatzort_list').append('<li class="list-group-item text-warning">' + data.besonderheiten+ '</li>');
|
||||||
|
};
|
||||||
|
// Alte Einsatzmittel loeschen
|
||||||
|
var table_em = document.getElementById('table_einsatzmittel');
|
||||||
|
table_em.getElementsByTagName('tbody')[0].innerHTML = '';
|
||||||
|
// Einsatzmittel-Tabelle
|
||||||
|
for (var i in data.einsatzmittel) {
|
||||||
|
|
||||||
|
var wache_vorhanden = false;
|
||||||
|
var wache_zeile = 0;
|
||||||
|
var wachen_idstr =data.einsatzmittel[i].wachenname.replace(/[^A-Z0-9]+/ig, '_');
|
||||||
|
for (var j = 0, row; row = table_em.rows[j]; j++) {
|
||||||
|
//console.log(row.cells[0].innerHTML);
|
||||||
|
if (row.cells[0].innerHTML == data.einsatzmittel[i].wachenname) {
|
||||||
|
wache_vorhanden = true;
|
||||||
|
wache_zeile = j;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (!wache_vorhanden){
|
||||||
|
// Zeile fuer Wache anlegen, falls diese noch nicht hinterlegt
|
||||||
|
var tableRef = document.getElementById('table_einsatzmittel').getElementsByTagName('tbody')[0];
|
||||||
|
var newRow = tableRef.insertRow();
|
||||||
|
|
||||||
|
//var newCell = newRow.insertCell(0);
|
||||||
|
// Wachennamen hinterlegen
|
||||||
|
var new_th = document.createElement('th');
|
||||||
|
new_th.innerHTML = data.einsatzmittel[i].wachenname;
|
||||||
|
//var newText = document.createTextNode(data.einsatzmittel[i].wachenname);
|
||||||
|
//newCell.outerHTML = "<th></th>";
|
||||||
|
//newCell.appendChild(newText);
|
||||||
|
newRow.appendChild(new_th);
|
||||||
|
|
||||||
|
//Flex-Element fuer Einsatzmittel der Wache erzeugen
|
||||||
|
var flex_div_wa = document.createElement('div');
|
||||||
|
flex_div_wa.className = 'd-flex flex-wrap justify-content-between align-items-center';
|
||||||
|
flex_div_wa.id = wachen_idstr;
|
||||||
|
|
||||||
|
//Flexelement zur Tabelle hinzuefuegen
|
||||||
|
var new_td = document.createElement('td');
|
||||||
|
new_td.appendChild(flex_div_wa);
|
||||||
|
newRow.appendChild(new_td);
|
||||||
|
//table_em.rows[wache_zeile].cells[1].appendChild(flex_div_wa);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Flex-Element fuer Einsatzmittel erzeugen
|
||||||
|
var flex_div_em = document.createElement('div');
|
||||||
|
flex_div_em.className = 'flex-fill rounded bg-secondary p-2 m-1';
|
||||||
|
|
||||||
|
//Justify-Rahmen feuer Einsatzmittel erzeugen
|
||||||
|
var justify_div = document.createElement('div');
|
||||||
|
justify_div.className = 'd-flex justify-content-between';
|
||||||
|
|
||||||
|
//Einsatzmittel-Div erzeugen
|
||||||
|
var em_div = document.createElement('div');
|
||||||
|
em_div.className = 'pr-2';
|
||||||
|
em_div.innerHTML = data.einsatzmittel[i].einsatzmittel;
|
||||||
|
|
||||||
|
//Status-Div erzeugen
|
||||||
|
var status_div = document.createElement('div');
|
||||||
|
switch (data.einsatzmittel[i].status) {
|
||||||
|
case '1':
|
||||||
|
status_div.className = 'p-2 badge badge-info';
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
status_div.className = 'p-2 badge badge-success';
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
status_div.className = 'p-2 badge badge-warning';
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
status_div.className = 'p-2 badge badge-danger';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
status_div.className = 'p-2 badge badge-dark';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
status_div.innerHTML = data.einsatzmittel[i].status;
|
||||||
|
|
||||||
|
//Erzeugte Div zusammensetzen
|
||||||
|
flex_div_em.appendChild(justify_div);
|
||||||
|
justify_div.appendChild(em_div);
|
||||||
|
justify_div.appendChild(status_div);
|
||||||
|
|
||||||
|
// Einsatzmittel hinzuefuegen
|
||||||
|
document.getElementById(wachen_idstr).appendChild(flex_div_em);
|
||||||
|
|
||||||
|
};
|
||||||
|
// Karte leeren
|
||||||
|
map.removeLayer(marker);
|
||||||
|
map.removeLayer(geojson);
|
||||||
|
// Karte setzen
|
||||||
|
if (data.wgs84_x && data.wgs84_y) {
|
||||||
|
marker = L.marker(new L.LatLng(data.wgs84_x, data.wgs84_y), {
|
||||||
|
icon: redIcon
|
||||||
|
}).addTo(map);
|
||||||
|
map.setView(new L.LatLng(data.wgs84_x, data.wgs84_y), 15);
|
||||||
|
} else {
|
||||||
|
geojson = L.geoJSON(JSON.parse(data.wgs84_area));
|
||||||
|
geojson.addTo(map);
|
||||||
|
map.fitBounds(geojson.getBounds());
|
||||||
|
map.setZoom(13);
|
||||||
|
};
|
||||||
|
// Marker in Timeline setzen
|
||||||
|
var markerText = 'Alarmierung';
|
||||||
|
var alarm_zeit = 'alarm_zeit';
|
||||||
|
|
||||||
|
|
||||||
|
timeline.addCustomTime(
|
||||||
|
data.zeitstempel,
|
||||||
|
alarm_zeit
|
||||||
|
);
|
||||||
|
timeline.customTimes[timeline.customTimes.length - 1].hammer.off("panstart panmove panend");
|
||||||
|
timeline.setCustomTimeMarker(markerText, alarm_zeit, false);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO Ablaufzeit setzen
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('io.new_rmld', function (data) {
|
||||||
|
// DEBUG
|
||||||
|
console.log(data);
|
||||||
|
// FIXME Änderung des Funktions-Typ berücksichtigen
|
||||||
|
// Neue Rueckmeldung hinterlegen
|
||||||
|
data.forEach(function (arrayItem) {
|
||||||
|
// HTML festlegen
|
||||||
|
var item_type = '';
|
||||||
|
var item_content = '';
|
||||||
|
var item_classname = '';
|
||||||
|
// wenn Einsatzkraft dann:
|
||||||
|
if (arrayItem.einsatzkraft) {
|
||||||
|
item_content = 'Einsatzkraft';
|
||||||
|
item_classname = 'ek';
|
||||||
|
item_type = 'ek';
|
||||||
|
};
|
||||||
|
// wenn Maschinist dann:
|
||||||
|
if (arrayItem.maschinist) {
|
||||||
|
item_content = 'Maschinist';
|
||||||
|
item_classname = 'ma';
|
||||||
|
item_type = 'ma';
|
||||||
|
};
|
||||||
|
// wenn Fuehrungskraft dann:
|
||||||
|
if (arrayItem.fuehrungskraft) {
|
||||||
|
item_content = 'Führungskraft';
|
||||||
|
item_classname = 'fk'
|
||||||
|
item_type = 'fk';
|
||||||
|
};
|
||||||
|
// wenn AGT
|
||||||
|
var item_agt = arrayItem.agt;
|
||||||
|
if (arrayItem.agt){
|
||||||
|
item_content = item_content + (' (AGT)');
|
||||||
|
item_classname = item_classname + ('-agt');
|
||||||
|
};
|
||||||
|
// Variablen für Anzeige vorbereiten
|
||||||
|
var pg_waip_uuid = arrayItem.waip_uuid;
|
||||||
|
var pg_rmld_uuid = arrayItem.rmld_uuid;
|
||||||
|
var pg_start = new Date(arrayItem.set_time);
|
||||||
|
var pg_end = new Date(arrayItem.arrival_time);
|
||||||
|
var timeline_item = {
|
||||||
|
id: arrayItem.rmld_uuid,
|
||||||
|
group: arrayItem.wache_id,
|
||||||
|
className: item_classname,
|
||||||
|
start: new Date(arrayItem.set_time),
|
||||||
|
end: new Date(arrayItem.arrival_time),
|
||||||
|
content: item_content
|
||||||
|
};
|
||||||
|
// Progressbar hinterlegen
|
||||||
|
add_resp_progressbar(pg_waip_uuid, pg_rmld_uuid, item_type, item_agt, pg_start, pg_end);
|
||||||
|
// in Timeline hinterlegen
|
||||||
|
items.update(timeline_item);
|
||||||
|
groups.update({ id: arrayItem.wache_id, content: arrayItem.wache_name });
|
||||||
|
// Anzahl der Rückmeldung zählen
|
||||||
|
recount_rmld(pg_waip_uuid);
|
||||||
|
});
|
||||||
|
var audio = document.getElementById('audio');
|
||||||
|
audio.src = ('/media/bell_message.mp3');
|
||||||
|
// Audio-Blockade des Browsers erkennen
|
||||||
|
var playPromise = document.querySelector('audio').play();
|
||||||
|
if (playPromise !== undefined) {
|
||||||
|
playPromise.then(function () {
|
||||||
|
audio.play();
|
||||||
|
}).catch(function (error) {
|
||||||
|
console.log('Notification playback failed');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
108
public/js/client_rmld.js
Executable file
108
public/js/client_rmld.js
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
/* ########################### */
|
||||||
|
/* ######### LEAFLET ######### */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// Karte definieren
|
||||||
|
var map = L.map('map', {
|
||||||
|
zoomControl: false
|
||||||
|
}).setView([51.733005, 14.338048], 13);
|
||||||
|
|
||||||
|
// Layer der Karte
|
||||||
|
// TODO: internen Kartendienst setzten
|
||||||
|
mapLink = L.tileLayer(
|
||||||
|
map_tile, {
|
||||||
|
maxZoom: 18,
|
||||||
|
attribution: map_attribution
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// Icon der Karte zuordnen
|
||||||
|
var redIcon = new L.Icon({
|
||||||
|
iconUrl: '/media/marker-icon-2x-red.png',
|
||||||
|
shadowUrl: '/media/marker-shadow.png',
|
||||||
|
iconSize: [25, 41],
|
||||||
|
iconAnchor: [12, 41],
|
||||||
|
popupAnchor: [1, -34],
|
||||||
|
shadowSize: [41, 41]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Icon setzen
|
||||||
|
var marker = L.marker(new L.LatLng(0, 0), {
|
||||||
|
icon: redIcon
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// Karte setzen
|
||||||
|
map.removeLayer(marker);
|
||||||
|
if (einsatzdaten_obj.wgs84_x && einsatzdaten_obj.wgs84_y) {
|
||||||
|
marker = L.marker(new L.LatLng(einsatzdaten_obj.wgs84_x, einsatzdaten_obj.wgs84_y), {
|
||||||
|
icon: redIcon
|
||||||
|
}).addTo(map);
|
||||||
|
map.setView(new L.LatLng(einsatzdaten_obj.wgs84_x, einsatzdaten_obj.wgs84_y), 13);
|
||||||
|
} else {
|
||||||
|
var geojson = L.geoJSON(JSON.parse(einsatzdaten_obj.wgs84_area)).addTo(map);
|
||||||
|
map.fitBounds(geojson.getBounds());
|
||||||
|
map.setZoom(13);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ####### Funktionen ######## */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
|
||||||
|
// Split timestamp into [ Y, M, D, h, m, s ]
|
||||||
|
var t1 = einsatzdaten_obj.zeitstempel.split(/[- :]/);
|
||||||
|
var d = new Date(t1[0], t1[1] - 1, t1[2], t1[3], t1[4], t1[5]);
|
||||||
|
|
||||||
|
// Zeitwerte
|
||||||
|
var curr_day = d.getDay();
|
||||||
|
var curr_date = d.getDate();
|
||||||
|
var curr_month_id = d.getMonth();
|
||||||
|
curr_month_id = curr_month_id + 1;
|
||||||
|
var curr_year = d.getFullYear();
|
||||||
|
var curr_hour = d.getHours();
|
||||||
|
var curr_min = d.getMinutes();
|
||||||
|
var curr_sek = d.getSeconds();
|
||||||
|
// Tag und Monat Anpassen
|
||||||
|
if ((String(curr_date)).length == 1)
|
||||||
|
curr_date = '0' + curr_date;
|
||||||
|
if ((String(curr_month_id)).length == 1)
|
||||||
|
curr_month_id = '0' + curr_month_id;
|
||||||
|
// Uhrzeit anpassen
|
||||||
|
if (curr_min <= 9) {
|
||||||
|
curr_min = '0' + curr_min;
|
||||||
|
};
|
||||||
|
if (curr_hour <= 9) {
|
||||||
|
curr_hour = '0' + curr_hour;
|
||||||
|
};
|
||||||
|
if (curr_sek <= 9) {
|
||||||
|
curr_sek = '0' + curr_sek;
|
||||||
|
};
|
||||||
|
var curr_month = d.getMonth();
|
||||||
|
var curr_year = d.getFullYear();
|
||||||
|
|
||||||
|
// Datum und Uhrzeit setzen
|
||||||
|
$("#einsatz_datum").text(curr_date + '.' + curr_month_id + '.' + curr_year);
|
||||||
|
$("#einsatz_uhrzeit").text(curr_hour + ':' + curr_min + ':' + curr_sek);
|
||||||
|
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ####### Rückmeldung ####### */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
$('#rueckmeldung').each(function(index) {
|
||||||
|
$(this).on("click", function(){
|
||||||
|
$('#responseModal').modal('show');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ######## SOCKET.IO ######## */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// Websocket
|
||||||
|
//var socket = io.connect();
|
||||||
|
|
||||||
|
// Wachen-ID bei Connect an Server senden
|
||||||
|
/*socket.on('connect', function() {
|
||||||
|
socket.emit('dbrd_uuid', wachen_id);
|
||||||
|
$('#waipModal').modal('hide');
|
||||||
|
});*/
|
||||||
803
public/js/client_waip.js
Normal file
803
public/js/client_waip.js
Normal file
@ -0,0 +1,803 @@
|
|||||||
|
// TODO: Remote-Reload per Socket
|
||||||
|
// TODO: Modal bei Server-Verbindung, und Modal bei Reload
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
set_clock();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).on('resize', function () {
|
||||||
|
resize_text();
|
||||||
|
// Position neu setzen
|
||||||
|
var newq = makeNewPosition();
|
||||||
|
$('.clock_y').css('top', newq[0]);
|
||||||
|
$('.clock_y').css('left', newq[1]);
|
||||||
|
// langsam verschieben
|
||||||
|
animateDiv();
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ############################ */
|
||||||
|
/* ######### BUTTONS ########## */
|
||||||
|
/* ############################ */
|
||||||
|
|
||||||
|
|
||||||
|
var waipAudio = document.getElementById('audio');
|
||||||
|
|
||||||
|
waipAudio.addEventListener('ended', function () {
|
||||||
|
console.log('ended');
|
||||||
|
|
||||||
|
var tmp_element;
|
||||||
|
// Pause-Symbol in Play-Symbol
|
||||||
|
tmp_element = document.querySelector('.ion-md-pause');
|
||||||
|
if (tmp_element.classList.contains('ion-md-pause')) {
|
||||||
|
tmp_element.classList.remove('ion-md-pause');
|
||||||
|
tmp_element.classList.add('ion-md-play-circle');
|
||||||
|
};
|
||||||
|
// Lautsprecher-Symbol in Leise-Symbol
|
||||||
|
tmp_element = document.querySelector('.ion-md-volume-high');
|
||||||
|
if (tmp_element.classList.contains('ion-md-volume-high')) {
|
||||||
|
tmp_element.classList.remove('ion-md-volume-high');
|
||||||
|
tmp_element.classList.add('ion-md-volume-off');
|
||||||
|
};
|
||||||
|
// Button Hintergrund entfernen, falls vorhanden
|
||||||
|
tmp_element = document.querySelector('#volume');
|
||||||
|
if (tmp_element.classList.contains('btn-danger')) {
|
||||||
|
tmp_element.classList.remove('btn-danger');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
waipAudio.addEventListener('play', function () {
|
||||||
|
var tmp_element;
|
||||||
|
// Pause-Symbol in Play-Symbol
|
||||||
|
tmp_element = document.querySelector('.ion-md-play-circle');
|
||||||
|
if (tmp_element.classList.contains('ion-md-play-circle')) {
|
||||||
|
tmp_element.classList.remove('ion-md-play-circle');
|
||||||
|
tmp_element.classList.add('ion-md-pause');
|
||||||
|
};
|
||||||
|
// Lautsprecher-Symbol in Leise-Symbol
|
||||||
|
tmp_element = document.querySelector('.ion-md-volume-off');
|
||||||
|
if (tmp_element.classList.contains('ion-md-volume-off')) {
|
||||||
|
tmp_element.classList.remove('ion-md-volume-off');
|
||||||
|
tmp_element.classList.add('ion-md-volume-high');
|
||||||
|
};
|
||||||
|
// Button Hintergrund entfernen, falls vorhanden
|
||||||
|
tmp_element = document.querySelector('#volume');
|
||||||
|
if (tmp_element.classList.contains('btn-danger')) {
|
||||||
|
tmp_element.classList.remove('btn-danger');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#replay').on('click', function (event) {
|
||||||
|
document.getElementById('audio').play();
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ############################ */
|
||||||
|
/* ####### TEXT-RESIZE ######## */
|
||||||
|
/* ############################ */
|
||||||
|
|
||||||
|
// Größen dynamisch anpassen, Hintergrundfarbe ggf. anpassen
|
||||||
|
function resize_text() {
|
||||||
|
// Uhr-Text nur Anpassen wenn sichtbar
|
||||||
|
if ($('#waipclock').is(':visible')) {
|
||||||
|
textFit(document.getElementsByClassName('tf_clock'), {
|
||||||
|
minFontSize: 3,
|
||||||
|
maxFontSize: 500
|
||||||
|
});
|
||||||
|
$('body').css('background-color', '#000');
|
||||||
|
};
|
||||||
|
// Tableau nur Anpassen wenn sichtbar
|
||||||
|
if ($('#waiptableau').is(':visible')) {
|
||||||
|
textFit(document.getElementsByClassName('tf_singleline'), {
|
||||||
|
minFontSize: 1,
|
||||||
|
maxFontSize: 500
|
||||||
|
});
|
||||||
|
textFit(document.getElementsByClassName('tf_multiline'), {
|
||||||
|
detectMultiLine: false
|
||||||
|
});
|
||||||
|
// Karte neu setzen
|
||||||
|
map.invalidateSize();
|
||||||
|
$('body').css('background-color', '#222');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Text nach bestimmter Laenge, in Abhaengigkeit von Zeichen, umbrechen
|
||||||
|
function break_text_15(text) {
|
||||||
|
var new_text;
|
||||||
|
new_text = text.replace(/.{15}(\s+|\-+)+/g, '$&@')
|
||||||
|
new_text = new_text.split(/@/);
|
||||||
|
new_text = new_text.join('<br>');
|
||||||
|
//console.log(new_text);
|
||||||
|
return new_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
function break_text_35(text) {
|
||||||
|
var new_text;
|
||||||
|
new_text = text.replace(/.{50}\S*\s+/g, '$&@').split(/\s+@/);
|
||||||
|
new_text = new_text.join('<br>');
|
||||||
|
//console.log(new_text);
|
||||||
|
return new_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ############################ */
|
||||||
|
/* ####### INAKTIVITAET ####### */
|
||||||
|
/* ############################ */
|
||||||
|
|
||||||
|
var timeoutID;
|
||||||
|
|
||||||
|
// Inactivitaet auswerten
|
||||||
|
function setup_inactivcheck() {
|
||||||
|
this.addEventListener('mousemove', resetActivTimer, false);
|
||||||
|
this.addEventListener('mousedown', resetActivTimer, false);
|
||||||
|
this.addEventListener('keypress', resetActivTimer, false);
|
||||||
|
this.addEventListener('DOMMouseScroll', resetActivTimer, false);
|
||||||
|
this.addEventListener('mousewheel', resetActivTimer, {
|
||||||
|
passive: true
|
||||||
|
}, false);
|
||||||
|
this.addEventListener('touchmove', resetActivTimer, false);
|
||||||
|
this.addEventListener('MSPointerMove', resetActivTimer, false);
|
||||||
|
start_inactivtimer();
|
||||||
|
};
|
||||||
|
|
||||||
|
setup_inactivcheck();
|
||||||
|
|
||||||
|
// warte xxxx Millisekunden um dann do_on_Inactive zu starten
|
||||||
|
function start_inactivtimer() {
|
||||||
|
clearTimeout(timeoutID);
|
||||||
|
timeoutID = window.setTimeout(do_on_Inactive, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// bei Inaktivitaet Header/Footer ausblenden
|
||||||
|
function do_on_Inactive() {
|
||||||
|
// do something
|
||||||
|
$('.navbar').fadeOut('slow');
|
||||||
|
$('.footer').fadeOut('slow');
|
||||||
|
$('.fullheight').css({
|
||||||
|
height: 'calc(100vh - 4rem)',
|
||||||
|
cursor: 'none'
|
||||||
|
});
|
||||||
|
$('body').css({
|
||||||
|
paddingTop: '1rem',
|
||||||
|
margin: 0
|
||||||
|
});
|
||||||
|
resize_text();
|
||||||
|
};
|
||||||
|
|
||||||
|
// bei Activitaet Header/Footer einblenden
|
||||||
|
function do_on_Active() {
|
||||||
|
start_inactivtimer();
|
||||||
|
// do something
|
||||||
|
$('.navbar').fadeIn('slow');
|
||||||
|
$('.footer').fadeIn('slow');
|
||||||
|
$('body').css({
|
||||||
|
marginBottom: '60px',
|
||||||
|
paddingTop: '5rem',
|
||||||
|
paddingBottom: '0'
|
||||||
|
});
|
||||||
|
$('.fullheight').css({
|
||||||
|
height: 'calc(100vh - 60px - 7rem)',
|
||||||
|
cursor: 'auto'
|
||||||
|
});
|
||||||
|
resize_text();
|
||||||
|
};
|
||||||
|
|
||||||
|
// bei Event (Aktiviaet) alles zuruecksetzen
|
||||||
|
function resetActivTimer(e) {
|
||||||
|
do_on_Active();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ############################ */
|
||||||
|
/* ####### Progressbar ####### */
|
||||||
|
/* ############################ */
|
||||||
|
|
||||||
|
var counter_ID = 0;
|
||||||
|
|
||||||
|
function start_counter(zeitstempel, ablaufzeit) {
|
||||||
|
// Split timestamp into [ Y, M, D, h, m, s ]
|
||||||
|
var t1 = zeitstempel.split(/[- :]/),
|
||||||
|
t2 = ablaufzeit.split(/[- :]/);
|
||||||
|
|
||||||
|
var start = new Date(t1[0], t1[1] - 1, t1[2], t1[3], t1[4], t1[5]),
|
||||||
|
end = new Date(t2[0], t2[1] - 1, t2[2], t2[3], t2[4], t2[5]);
|
||||||
|
|
||||||
|
clearInterval(counter_ID);
|
||||||
|
counter_ID = setInterval(function () {
|
||||||
|
do_progressbar(start, end);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
function do_progressbar(start, end) {
|
||||||
|
today = new Date();
|
||||||
|
// restliche Zeit ermitteln
|
||||||
|
var current_progress = Math.round(100 / (end.getTime() - start.getTime()) * (end.getTime() - today.getTime()));
|
||||||
|
|
||||||
|
var diff = Math.abs(end - today);
|
||||||
|
var minutesDifference = Math.floor(diff / 1000 / 60);
|
||||||
|
diff -= minutesDifference * 1000 * 60;
|
||||||
|
var secondsDifference = Math.floor(diff / 1000);
|
||||||
|
if (secondsDifference <= 9) {
|
||||||
|
secondsDifference = '0' + secondsDifference;
|
||||||
|
};
|
||||||
|
var minutes = minutesDifference + ':' + secondsDifference;
|
||||||
|
// Progressbar anpassen
|
||||||
|
$('#hilfsfrist')
|
||||||
|
.css('width', current_progress + '%')
|
||||||
|
.attr('aria-valuenow', current_progress)
|
||||||
|
.text(minutes + ' min');
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ######### LEAFLET ######### */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// Karte definieren
|
||||||
|
var map = L.map('map', {
|
||||||
|
zoomControl: false
|
||||||
|
}).setView([51.733005, 14.338048], 13);
|
||||||
|
|
||||||
|
// Layer der Karte
|
||||||
|
mapLink = L.tileLayer(
|
||||||
|
map_tile, {
|
||||||
|
maxZoom: 18,
|
||||||
|
attribution: map_attribution
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// Icon der Karte zuordnen
|
||||||
|
var redIcon = new L.Icon({
|
||||||
|
iconUrl: '/media/marker-icon-2x-red.png',
|
||||||
|
shadowUrl: '/media/marker-shadow.png',
|
||||||
|
iconSize: [25, 41],
|
||||||
|
iconAnchor: [12, 41],
|
||||||
|
popupAnchor: [1, -34],
|
||||||
|
shadowSize: [41, 41]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Icon setzen
|
||||||
|
var marker = L.marker(new L.LatLng(0, 0), {
|
||||||
|
icon: redIcon
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
// GeoJSON vordefinieren
|
||||||
|
var geojson = L.geoJSON().addTo(map);
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ######## SOCKET.IO ######## */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// Websocket
|
||||||
|
var socket = io('/waip');
|
||||||
|
|
||||||
|
// Wachen-ID bei Connect an Server senden
|
||||||
|
socket.on('connect', function () {
|
||||||
|
socket.emit('WAIP', wachen_id);
|
||||||
|
$('#waipModal').modal('hide');
|
||||||
|
// TODO: bei Reconnect des Clients durch Verbindungsabbruch, erneut Daten anfordern
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('connect_error', function (err) {
|
||||||
|
$('#waipModalTitle').html('FEHLER');
|
||||||
|
$('#waipModalBody').html('Verbindung zum Server getrennt!');
|
||||||
|
$('#waipModal').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ID von Server und Client vergleichen, falls ungleich -> Seite neu laden
|
||||||
|
socket.on('io.version', function (server_id) {
|
||||||
|
if (client_id != server_id) {
|
||||||
|
$('#waipModal').modal('hide');
|
||||||
|
setTimeout(function () {
|
||||||
|
$('#waipModalTitle').html('ACHTUNG');
|
||||||
|
$('#waipModalBody').html('Neue Server-Version. Seite wird in 10 Sekunden neu geladen!');
|
||||||
|
$('#waipModal').modal('show');
|
||||||
|
setTimeout(function () {
|
||||||
|
location.reload();
|
||||||
|
}, 10000);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// ggf. Fehler ausgeben
|
||||||
|
socket.on('io.error', function (data) {
|
||||||
|
console.log('Error:', data);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sounds stoppen
|
||||||
|
socket.on('io.stopaudio', function (data) {
|
||||||
|
tmp_audio = document.getElementById('audio');
|
||||||
|
tmp_audio.pause();
|
||||||
|
tmp_audio.currentTime = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sounds abspielen
|
||||||
|
socket.on('io.playtts', function (data) {
|
||||||
|
var audio = document.getElementById('audio');
|
||||||
|
audio.src = (data);
|
||||||
|
console.log($('#audio'));
|
||||||
|
|
||||||
|
// Audio-Blockade des Browsers erkennen
|
||||||
|
var playPromise = document.querySelector('audio').play();
|
||||||
|
|
||||||
|
// In browsers that don’t yet support this functionality,
|
||||||
|
// playPromise won’t be defined.
|
||||||
|
if (playPromise !== undefined) {
|
||||||
|
playPromise.then(function () {
|
||||||
|
// Automatic playback started!
|
||||||
|
audio.play();
|
||||||
|
//$('.ion-md-volume-high').toggleClass('ion-md-pause');
|
||||||
|
}).catch(function (error) {
|
||||||
|
console.log('Automatic playback failed');
|
||||||
|
// Automatic playback failed.
|
||||||
|
// Show a UI element to let the user manually start playback.
|
||||||
|
var tmp_element;
|
||||||
|
tmp_element = document.querySelector('#volume');
|
||||||
|
if (!tmp_element.classList.contains('btn-danger')) {
|
||||||
|
tmp_element.classList.add('btn-danger');
|
||||||
|
};
|
||||||
|
tmp_element = document.querySelector('.ion-md-volume-high');
|
||||||
|
if (tmp_element.classList.contains('ion-md-volume-high')) {
|
||||||
|
tmp_element.classList.remove('ion-md-volume-high');
|
||||||
|
tmp_element.classList.add('ion-md-volume-off');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Daten löschen, Uhr anzeigen
|
||||||
|
socket.on('io.standby', function (data) {
|
||||||
|
// Einsatz-ID auf 0 setzen
|
||||||
|
waip_id = null;
|
||||||
|
// TODO: Wenn vorhanden, hier #hilfsfrist zurücksetzen
|
||||||
|
$('#einsatz_art').removeClass(function (index, className) {
|
||||||
|
return (className.match(/(^|\s)bg-\S+/g) || []).join(' ');
|
||||||
|
});
|
||||||
|
$('#einsatz_stichwort').removeClass();
|
||||||
|
$('#einsatz_stichwort').html('');
|
||||||
|
$('#sondersignal').removeClass();
|
||||||
|
$('#ortsdaten').html('');
|
||||||
|
$('#besonderheiten').html('');
|
||||||
|
$('#em_alarmiert').empty();
|
||||||
|
$('#em_weitere').html('');
|
||||||
|
reset_rmld();
|
||||||
|
recount_rmld();
|
||||||
|
map.setView(new L.LatLng(0, 0), 14);
|
||||||
|
// Tareset_responsebleau ausblenden
|
||||||
|
$('#waiptableau').addClass('d-none');
|
||||||
|
$('#waipclock').removeClass('d-none');
|
||||||
|
// Text anpassen
|
||||||
|
resize_text();
|
||||||
|
// Position neu setzen
|
||||||
|
setTimeout(function () {
|
||||||
|
// Position neu setzen
|
||||||
|
var newq = makeNewPosition();
|
||||||
|
$('.clock_y').css('top', newq[0]);
|
||||||
|
$('.clock_y').css('left', newq[1]);
|
||||||
|
// langsam verschieben
|
||||||
|
animateDiv();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Einsatzdaten laden, Wachalarm anzeigen
|
||||||
|
socket.on('io.new_waip', function (data) {
|
||||||
|
// DEBUG
|
||||||
|
console.log(data);
|
||||||
|
// Einsatz-ID speichern
|
||||||
|
waip_id = data.id;
|
||||||
|
// Alarmzeitsetzen:
|
||||||
|
$('#date-time').html(data.zeitstempel);
|
||||||
|
// Hintergrund der Einsatzart zunächst entfernen
|
||||||
|
$('#einsatz_art').removeClass(function (index, className) {
|
||||||
|
return (className.match(/(^|\s)bg-\S+/g) || []).join(' ');
|
||||||
|
});
|
||||||
|
// Icon der Einsatzart enfernen
|
||||||
|
$('#einsatz_stichwort').removeClass();
|
||||||
|
// Art und Stichwort festlegen hinterlegen
|
||||||
|
switch (data.einsatzart) {
|
||||||
|
case 'Brandeinsatz':
|
||||||
|
$('#einsatz_art').addClass('bg-danger');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-flame');
|
||||||
|
$('#rueckmeldung').removeClass('d-none');
|
||||||
|
break;
|
||||||
|
case 'Hilfeleistungseinsatz':
|
||||||
|
$('#einsatz_art').addClass('bg-info');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-construct');
|
||||||
|
$('#rueckmeldung').removeClass('d-none');
|
||||||
|
break;
|
||||||
|
case 'Rettungseinsatz':
|
||||||
|
$('#einsatz_art').addClass('bg-warning');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-medkit');
|
||||||
|
break;
|
||||||
|
case 'Krankentransport':
|
||||||
|
$('#einsatz_art').addClass('bg-success');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-medical');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$('#einsatz_art').addClass('bg-secondary');
|
||||||
|
$('#einsatz_stichwort').addClass('ion-md-information-circle');
|
||||||
|
};
|
||||||
|
$('#einsatz_stichwort').html(' ' + data.stichwort);
|
||||||
|
// Sondersignal setzen
|
||||||
|
$('#sondersignal').removeClass();
|
||||||
|
switch (data.sondersignal) {
|
||||||
|
case 1:
|
||||||
|
$('#sondersignal').addClass('ion-md-notifications');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$('#sondersignal').addClass('ion-md-notifications-off');
|
||||||
|
};
|
||||||
|
// Ortsdaten zusammenstellen und setzen
|
||||||
|
var small_ortsdaten;
|
||||||
|
small_ortsdaten = '';
|
||||||
|
if (data.objekt) {
|
||||||
|
small_ortsdaten = small_ortsdaten + break_text_15(data.objekt) + '<br>';
|
||||||
|
};
|
||||||
|
if (data.ort) {
|
||||||
|
small_ortsdaten = small_ortsdaten + break_text_15(data.ort) + '<br>';
|
||||||
|
};
|
||||||
|
if (data.ortsteil) {
|
||||||
|
small_ortsdaten = small_ortsdaten + break_text_15(data.ortsteil) + '<br>';
|
||||||
|
};
|
||||||
|
if (data.strasse) {
|
||||||
|
small_ortsdaten = small_ortsdaten + break_text_15(data.strasse) + '<br>';
|
||||||
|
};
|
||||||
|
if (small_ortsdaten.substr(small_ortsdaten.length - 4) == '<br>') {
|
||||||
|
small_ortsdaten = small_ortsdaten.slice(0, -4);
|
||||||
|
};
|
||||||
|
$('#ortsdaten').html(small_ortsdaten);
|
||||||
|
// Besonderheiten setzen
|
||||||
|
$('#besonderheiten').html(break_text_35(data.besonderheiten));
|
||||||
|
// alarmierte Einsatzmittel setzen
|
||||||
|
$('#em_alarmiert').empty();
|
||||||
|
var data_em_alarmiert = JSON.parse(data.em_alarmiert);
|
||||||
|
for (var i in data_em_alarmiert) {
|
||||||
|
var tmp = data_em_alarmiert[i].name.replace(/[^a-z0-9\s]/gi, '').replace(/[_\s]/g, '-');
|
||||||
|
$('#em_alarmiert').append('<div id="cn_' + tmp + '" class="rounded bg-secondary d-flex justify-content-between p-2 m-1"></div>');
|
||||||
|
$('#cn_' + tmp).append('<div class="pr-2">' + data_em_alarmiert[i].name + '</div>');
|
||||||
|
};
|
||||||
|
// weitere alarmierte Einsatzmittel setzen
|
||||||
|
$('#em_weitere').html('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
var data_em_weitere = JSON.parse(data.em_weitere);
|
||||||
|
|
||||||
|
if (data_em_weitere.length > 0) {
|
||||||
|
var tmp_weitere;
|
||||||
|
for (var i in data_em_weitere) {
|
||||||
|
if (tmp_weitere) {
|
||||||
|
tmp_weitere = tmp_weitere + ', ' + data_em_weitere[i].name;
|
||||||
|
} else {
|
||||||
|
tmp_weitere = data_em_weitere[i].name;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
$('#em_weitere').html(tmp_weitere);
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
//console.log(e); // error in the above string (in this case, yes)!
|
||||||
|
};
|
||||||
|
|
||||||
|
// Karte leeren
|
||||||
|
map.removeLayer(marker);
|
||||||
|
map.removeLayer(geojson);
|
||||||
|
// Karte setzen
|
||||||
|
if (data.wgs84_x && data.wgs84_y) {
|
||||||
|
marker = L.marker(new L.LatLng(data.wgs84_x, data.wgs84_y), {
|
||||||
|
icon: redIcon
|
||||||
|
}).addTo(map);
|
||||||
|
map.setView(new L.LatLng(data.wgs84_x, data.wgs84_y), 15);
|
||||||
|
} else {
|
||||||
|
geojson = L.geoJSON(JSON.parse(data.wgs84_area));
|
||||||
|
geojson.addTo(map);
|
||||||
|
map.fitBounds(geojson.getBounds());
|
||||||
|
map.setZoom(13);
|
||||||
|
};
|
||||||
|
// Ablaufzeit setzen
|
||||||
|
start_counter(data.zeitstempel, data.ablaufzeit);
|
||||||
|
// alte Rückmeldung entfernen
|
||||||
|
reset_rmld(data.uuid);
|
||||||
|
recount_rmld(data.uuid);
|
||||||
|
// TODO: Einzeige vergrößern wenn Felder nicht angezeigt werden
|
||||||
|
// Uhr ausblenden
|
||||||
|
$('#waipclock').addClass('d-none');
|
||||||
|
$('#waiptableau').removeClass('d-none');
|
||||||
|
// Text anpassen
|
||||||
|
resize_text();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('io.new_rmld', function (data) {
|
||||||
|
// DEBUG
|
||||||
|
console.log(data);
|
||||||
|
// FIXME Änderung des Funktions-Typ berücksichtigen
|
||||||
|
// Neue Rueckmeldung hinterlegen
|
||||||
|
data.forEach(function (arrayItem) {
|
||||||
|
// HTML festlegen
|
||||||
|
var item_type = '';
|
||||||
|
// wenn Einsatzkraft dann:
|
||||||
|
if (arrayItem.einsatzkraft) {
|
||||||
|
item_type = 'ek';
|
||||||
|
};
|
||||||
|
// wenn Maschinist dann:
|
||||||
|
if (arrayItem.maschinist) {
|
||||||
|
item_type = 'ma';
|
||||||
|
};
|
||||||
|
// wenn Fuehrungskraft dann:
|
||||||
|
if (arrayItem.fuehrungskraft) {
|
||||||
|
item_type = 'fk';
|
||||||
|
};
|
||||||
|
// wenn AGT
|
||||||
|
var item_agt = arrayItem.agt;
|
||||||
|
// Variablen für Anzeige vorbereiten
|
||||||
|
var pg_waip_uuid = arrayItem.waip_uuid;
|
||||||
|
console.log(arrayItem.waip_uuid);
|
||||||
|
console.log(pg_waip_uuid);
|
||||||
|
var pg_rmld_uuid = arrayItem.rmld_uuid;
|
||||||
|
var pg_start = new Date(arrayItem.set_time);
|
||||||
|
var pg_end = new Date(arrayItem.arrival_time);
|
||||||
|
// Progressbar hinterlegen
|
||||||
|
add_resp_progressbar(pg_waip_uuid, pg_rmld_uuid, item_type, item_agt, pg_start, pg_end);
|
||||||
|
// Anzahl der Rückmeldung zählen
|
||||||
|
recount_rmld(pg_waip_uuid);
|
||||||
|
});
|
||||||
|
// Text anpassen
|
||||||
|
resize_text();
|
||||||
|
// Bing abspielen
|
||||||
|
var audio = document.getElementById('audio');
|
||||||
|
audio.src = ('/media/bell_message.mp3');
|
||||||
|
// Audio-Blockade des Browsers erkennen
|
||||||
|
var playPromise = document.querySelector('audio').play();
|
||||||
|
if (playPromise !== undefined) {
|
||||||
|
playPromise.then(function () {
|
||||||
|
audio.play();
|
||||||
|
}).catch(function (error) {
|
||||||
|
console.log('Notification playback failed');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ####### Rückmeldung ####### */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
var counter_rmld = [];
|
||||||
|
|
||||||
|
function reset_rmld(p_uuid) {
|
||||||
|
var bar_uuid = 'bar-' + p_uuid;
|
||||||
|
$('#pg-ek').children().each(function (i) {
|
||||||
|
if (!$(this).hasClass(bar_uuid)) {
|
||||||
|
$(this).remove();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
$('#pg-ma').children().each(function (i) {
|
||||||
|
if (!$(this).hasClass(bar_uuid)) {
|
||||||
|
$(this).remove();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
$('#pg-fk').children().each(function (i) {
|
||||||
|
if (!$(this).hasClass(bar_uuid)) {
|
||||||
|
$(this).remove();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
/*$('#pg-ek').empty();
|
||||||
|
$('#pg-ma').empty();
|
||||||
|
$('#pg-fk').empty();
|
||||||
|
$('#ek-counter').text(0);
|
||||||
|
$('#ma-counter').text(0);
|
||||||
|
$('#fk-counter').text(0);
|
||||||
|
$('#agt-counter').text(0);*/
|
||||||
|
};
|
||||||
|
|
||||||
|
function add_resp_progressbar(p_uuid, p_id, p_type, p_agt, p_start, p_end) {
|
||||||
|
// Hintergrund der Progressbar festlegen
|
||||||
|
var bar_background = '';
|
||||||
|
var bar_border = '';
|
||||||
|
if (p_agt) {
|
||||||
|
bar_border = 'border border-warning';
|
||||||
|
};
|
||||||
|
switch (p_type) {
|
||||||
|
case 'ek':
|
||||||
|
bar_background = 'bg-success';
|
||||||
|
break;
|
||||||
|
case 'ma':
|
||||||
|
bar_background = 'bg-info';
|
||||||
|
break;
|
||||||
|
case 'fk':
|
||||||
|
bar_background = 'bg-light';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bar_background = '';
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
var bar_uuid = 'bar-' + p_uuid;
|
||||||
|
// pruefen ob div mit id 'pg-'+p_id schon vorhanden ist
|
||||||
|
var pgbar = document.getElementById('pg-' + p_id);
|
||||||
|
if (!pgbar) {
|
||||||
|
$('#pg-' + p_type).append('<div class="progress mt-1 position-relative ' + bar_border + ' ' + bar_uuid + '" id="pg-' + p_id + '" style="height: 15px; font-size: 14px;"></div>');
|
||||||
|
$('#pg-' + p_id).append('<div id="pg-bar-' + p_id + '" class="progress-bar progress-bar-striped ' + bar_background + '" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>');
|
||||||
|
$('#pg-bar-' + p_id).append('<small id="pg-text-' + p_id + '" class="justify-content-center d-flex position-absolute w-100"></small>');
|
||||||
|
} else {
|
||||||
|
// TODO PG-Bar ändern falls neue/angepasste Rückmeldung
|
||||||
|
};
|
||||||
|
// Zeitschiene Anpassen
|
||||||
|
clearInterval(counter_rmld[p_id]);
|
||||||
|
counter_rmld[p_id] = 0;
|
||||||
|
counter_rmld[p_id] = setInterval(function () {
|
||||||
|
do_rmld_bar(p_id, p_start, p_end);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
function do_rmld_bar(p_id, start, end) {
|
||||||
|
//console.log(p_id);
|
||||||
|
today = new Date();
|
||||||
|
// restliche Zeit ermitteln
|
||||||
|
var current_progress = Math.round(100 / (start.getTime() - end.getTime()) * (start.getTime() - today.getTime()));
|
||||||
|
|
||||||
|
var diff = Math.abs(end - today);
|
||||||
|
var minutesDifference = Math.floor(diff / 1000 / 60);
|
||||||
|
diff -= minutesDifference * 1000 * 60;
|
||||||
|
var secondsDifference = Math.floor(diff / 1000);
|
||||||
|
if (secondsDifference <= 9) {
|
||||||
|
secondsDifference = '0' + secondsDifference;
|
||||||
|
};
|
||||||
|
var minutes = minutesDifference + ':' + secondsDifference;
|
||||||
|
// Progressbar anpassen
|
||||||
|
if (current_progress >= 100) {
|
||||||
|
$('#pg-bar-' + p_id)
|
||||||
|
.css('width', '100%')
|
||||||
|
.attr('aria-valuenow', 100)
|
||||||
|
.addClass('ion-md-checkmark-circle');
|
||||||
|
$('#pg-text-' + p_id).text('');
|
||||||
|
clearInterval(counter_ID[p_id]);
|
||||||
|
} else {
|
||||||
|
$('#pg-bar-' + p_id)
|
||||||
|
.css('width', current_progress + '%')
|
||||||
|
.attr('aria-valuenow', current_progress);
|
||||||
|
$('#pg-text-' + p_id).text(minutes);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function recount_rmld(p_uuid) {
|
||||||
|
var bar_uuid = 'bar-' + p_uuid;
|
||||||
|
var agt_count = 0;
|
||||||
|
// Zähler auf 0 Setzen
|
||||||
|
$('#ek-counter').text(0);
|
||||||
|
$('#ma-counter').text(0);
|
||||||
|
$('#fk-counter').text(0);
|
||||||
|
$('#agt-counter').text(0);
|
||||||
|
// EK zählen
|
||||||
|
$('#pg-ek').children().each(function (i) {
|
||||||
|
if ($(this).hasClass(bar_uuid)) {
|
||||||
|
var tmp_count = parseInt($('#ek-counter').text());
|
||||||
|
$('#ek-counter').text(tmp_count + 1);
|
||||||
|
if ($(this).hasClass('border-warning')) {
|
||||||
|
agt_count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// MA zählen
|
||||||
|
$('#pg-ma').children().each(function (i) {
|
||||||
|
if ($(this).hasClass(bar_uuid)) {
|
||||||
|
var tmp_count = parseInt($('#ma-counter').text());
|
||||||
|
$('#ma-counter').text(tmp_count + 1);
|
||||||
|
if ($(this).hasClass('border-warning')) {
|
||||||
|
agt_count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// FK zählen
|
||||||
|
$('#pg-fk').children().each(function (i) {
|
||||||
|
if ($(this).hasClass(bar_uuid)) {
|
||||||
|
var tmp_count = parseInt($('#fk-counter').text());
|
||||||
|
$('#fk-counter').text(tmp_count + 1);
|
||||||
|
if ($(this).hasClass('border-warning')) {
|
||||||
|
agt_count++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// AGT setzen
|
||||||
|
$('#agt-counter').text(agt_count);
|
||||||
|
// Rückmeldecontainer anzeigen/ausblenden
|
||||||
|
if ($('#ek-counter').text() == '0' && $('#ma-counter').text() == '0' && $('#fk-counter').text() == '0' && $('#agt-counter').text() == '0') {
|
||||||
|
$('#rmld_container').addClass('d-none');
|
||||||
|
} else {
|
||||||
|
$('#rmld_container').removeClass('d-none');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ########################### */
|
||||||
|
/* ####### SCREENSAVER ####### */
|
||||||
|
/* ########################### */
|
||||||
|
|
||||||
|
// Uhrzeit und Datum für Bildschirmschoner
|
||||||
|
function set_clock() {
|
||||||
|
// TODO Sekunden anzeigen
|
||||||
|
// Wochentage
|
||||||
|
var d_names = new Array('Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag');
|
||||||
|
// Monate
|
||||||
|
var m_names = new Array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember');
|
||||||
|
// Aktuelle Zeit
|
||||||
|
var d = new Date();
|
||||||
|
var curr_day = d.getDay();
|
||||||
|
var curr_date = d.getDate();
|
||||||
|
var curr_month_id = d.getMonth();
|
||||||
|
curr_month_id = curr_month_id + 1;
|
||||||
|
var curr_year = d.getFullYear();
|
||||||
|
var curr_hour = d.getHours();
|
||||||
|
var curr_min = d.getMinutes();
|
||||||
|
var curr_sek = d.getSeconds();
|
||||||
|
// Tag und Monat Anpassen
|
||||||
|
if ((String(curr_date)).length == 1)
|
||||||
|
curr_date = '0' + curr_date;
|
||||||
|
if ((String(curr_month_id)).length == 1)
|
||||||
|
curr_month_id = '0' + curr_month_id;
|
||||||
|
// Uhrzeit und Minute anpassen
|
||||||
|
if (curr_min <= 9) {
|
||||||
|
curr_min = '0' + curr_min;
|
||||||
|
};
|
||||||
|
if (curr_hour <= 9) {
|
||||||
|
curr_hour = '0' + curr_hour;
|
||||||
|
};
|
||||||
|
if (curr_sek <= 9) {
|
||||||
|
curr_sek = '0' + curr_sek;
|
||||||
|
};
|
||||||
|
var curr_month = d.getMonth();
|
||||||
|
var curr_year = d.getFullYear();
|
||||||
|
var element_time = curr_hour + ':' + curr_min;
|
||||||
|
var element_day = d_names[curr_day] + ', ' + curr_date + '. ' + m_names[curr_month];
|
||||||
|
var element_date_time = curr_date + '.' + curr_month_id + '.' + curr_year + ' - ' + element_time + ':' + curr_sek;
|
||||||
|
// Easter-Egg :-)
|
||||||
|
if (element_time.substr(0, 5) == '13:37') {
|
||||||
|
element_time = '1337';
|
||||||
|
};
|
||||||
|
// nur erneuern wenn sich Zeit geändert hat
|
||||||
|
if ($('#time').text() !== element_time) {
|
||||||
|
// Uhrzeit anzeigen
|
||||||
|
$('#time').html(element_time);
|
||||||
|
// Datum (Text) anzeigen
|
||||||
|
$('#day').html(element_day);
|
||||||
|
// Textgröße neu setzen
|
||||||
|
resize_text();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Uhrzeit jede Sekunden anpassen
|
||||||
|
setInterval(set_clock, 1000);
|
||||||
|
|
||||||
|
// Uhrzeit verschieben
|
||||||
|
$(document).ready(function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
// Position neu setzen
|
||||||
|
var newq = makeNewPosition();
|
||||||
|
$('.clock_y').css('top', newq[0]);
|
||||||
|
$('.clock_y').css('left', newq[1]);
|
||||||
|
// langsam verschieben
|
||||||
|
animateDiv();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// neue Random-Position fuer Uhrzeit ermitteln
|
||||||
|
function makeNewPosition() {
|
||||||
|
// Get viewport dimensions
|
||||||
|
var h = $('.fullheight').height() - $('.clock_y').height();
|
||||||
|
var w = $('.fullheight').width() - $('.clock_y').width();
|
||||||
|
var nh = Math.floor(Math.random() * h);
|
||||||
|
var nw = Math.floor(Math.random() * w);
|
||||||
|
return [nh, nw];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verschieben animieren
|
||||||
|
function animateDiv() {
|
||||||
|
var newq = makeNewPosition();
|
||||||
|
var oldq = $('.clock_y').offset();
|
||||||
|
var speed = calcSpeed([oldq.top, oldq.left], newq);
|
||||||
|
$('.clock_y').animate({
|
||||||
|
top: newq[0],
|
||||||
|
left: newq[1]
|
||||||
|
}, speed, function () {
|
||||||
|
animateDiv();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verschiebe-Geschwindigkeit berechnen
|
||||||
|
function calcSpeed(prev, next) {
|
||||||
|
var x = Math.abs(prev[1] - next[1]);
|
||||||
|
var y = Math.abs(prev[0] - next[0]);
|
||||||
|
var greatest = x > y ? x : y;
|
||||||
|
var speedModifier = 0.001;
|
||||||
|
var speed = Math.ceil(greatest / speedModifier);
|
||||||
|
return speed;
|
||||||
|
};
|
||||||
60
public/js/vis-timeline.min.js
vendored
Executable file
60
public/js/vis-timeline.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
@ -1,507 +0,0 @@
|
|||||||
// TODO: Remote-Reload per Socket
|
|
||||||
// TODO: Client-Server-Version abgleichen
|
|
||||||
// TODO: Modal bei Chrome, dass Audio erst bei interaktion aktiv
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
set_clock();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(window).on("resize", function() {
|
|
||||||
resize_text();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#replay').on('click', function(event) {
|
|
||||||
audio.play();
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ############################ */
|
|
||||||
/* ######### BUTTONS ########## */
|
|
||||||
/* ############################ */
|
|
||||||
|
|
||||||
var waipAudio = document.getElementById('audio');
|
|
||||||
|
|
||||||
waipAudio.addEventListener('ended', function(){
|
|
||||||
$('.ion-md-pause').toggleClass("ion-md-play-circle");
|
|
||||||
});
|
|
||||||
|
|
||||||
waipAudio.addEventListener("play", function () {
|
|
||||||
$('.ion-md-play-circle').toggleClass("ion-md-pause");
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ############################ */
|
|
||||||
/* ####### TEXT-RESIZE ######## */
|
|
||||||
/* ############################ */
|
|
||||||
|
|
||||||
// Textgröße dynamisch anpassen, Hintergrundfarbe ggf. anpassen
|
|
||||||
function resize_text() {
|
|
||||||
// Uhr-Text nur Anpassen wenn sichtbar
|
|
||||||
if ($('#waipclock').is(':visible')) {
|
|
||||||
textFit(document.getElementsByClassName('tf_clock'), {
|
|
||||||
minFontSize: 3,
|
|
||||||
maxFontSize: 500
|
|
||||||
});
|
|
||||||
$("body").css("background-color", "#000");
|
|
||||||
};
|
|
||||||
// Tableau-Text nur Anpassen wenn sichtbar
|
|
||||||
if ($('#waiptableau').is(':visible')) {
|
|
||||||
textFit(document.getElementsByClassName('tf_singleline'), {
|
|
||||||
minFontSize: 1,
|
|
||||||
maxFontSize: 500
|
|
||||||
});
|
|
||||||
textFit(document.getElementsByClassName('tf_multiline'), {
|
|
||||||
detectMultiLine: false
|
|
||||||
});
|
|
||||||
textFit(document.getElementsByClassName('tf_test'), {
|
|
||||||
widthOnly: true,
|
|
||||||
alignHoriz: false,
|
|
||||||
alignVert: false,
|
|
||||||
alignVertWithFlexbox: false
|
|
||||||
});
|
|
||||||
map.invalidateSize();
|
|
||||||
$("body").css("background-color", "#222");
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Text nach bestimmter Laenge, in Abhaengigkeit von Zeichen, umbrechen
|
|
||||||
function break_text_15(text){
|
|
||||||
var new_text;
|
|
||||||
new_text = text.replace(/.{15}(\s+|\-+)+/g, "$&@")
|
|
||||||
new_text = new_text.split(/@/);
|
|
||||||
new_text= new_text.join("<br>");
|
|
||||||
console.log(new_text);
|
|
||||||
return new_text;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function break_text_35(text){
|
|
||||||
var new_text;
|
|
||||||
new_text = text.replace(/.{50}\S*\s+/g, "$&@").split(/\s+@/);
|
|
||||||
new_text= new_text.join("<br>");
|
|
||||||
console.log(new_text);
|
|
||||||
return new_text;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ############################ */
|
|
||||||
/* ####### INAKTIVITAET ####### */
|
|
||||||
/* ############################ */
|
|
||||||
|
|
||||||
var timeoutID;
|
|
||||||
|
|
||||||
// Inactivitaet auswerten
|
|
||||||
function setup_inactivcheck() {
|
|
||||||
this.addEventListener("mousemove", resetActivTimer, false);
|
|
||||||
this.addEventListener("mousedown", resetActivTimer, false);
|
|
||||||
this.addEventListener("keypress", resetActivTimer, false);
|
|
||||||
this.addEventListener("DOMMouseScroll", resetActivTimer, false);
|
|
||||||
this.addEventListener("mousewheel", resetActivTimer, {
|
|
||||||
passive: true
|
|
||||||
}, false);
|
|
||||||
this.addEventListener("touchmove", resetActivTimer, false);
|
|
||||||
this.addEventListener("MSPointerMove", resetActivTimer, false);
|
|
||||||
start_inactivtimer();
|
|
||||||
};
|
|
||||||
|
|
||||||
setup_inactivcheck();
|
|
||||||
|
|
||||||
// warte xxxx Millisekunden um dann do_on_Inactive zu starten
|
|
||||||
function start_inactivtimer() {
|
|
||||||
clearTimeout(timeoutID);
|
|
||||||
timeoutID = window.setTimeout(do_on_Inactive, 3000);
|
|
||||||
};
|
|
||||||
|
|
||||||
// bei Inaktivitaet Header/Footer ausblenden
|
|
||||||
function do_on_Inactive() {
|
|
||||||
// do something
|
|
||||||
$(".navbar").fadeOut("slow");
|
|
||||||
$(".footer").fadeOut("slow");
|
|
||||||
$(".fullheight").css({
|
|
||||||
height: 'calc(100vh - 2rem)'
|
|
||||||
});
|
|
||||||
$("body").css({
|
|
||||||
paddingTop: "1rem",
|
|
||||||
margin: 0
|
|
||||||
});
|
|
||||||
resize_text();
|
|
||||||
};
|
|
||||||
|
|
||||||
// bei Activitaet Header/Footer einblenden
|
|
||||||
function do_on_Active() {
|
|
||||||
start_inactivtimer();
|
|
||||||
// do something
|
|
||||||
$(".navbar").fadeIn('slow');
|
|
||||||
$(".footer").fadeIn('slow');
|
|
||||||
$("body").css({
|
|
||||||
marginBottom: '60px',
|
|
||||||
paddingTop: '5rem',
|
|
||||||
paddingBottom: '0'
|
|
||||||
});
|
|
||||||
$(".fullheight").css({
|
|
||||||
height: 'calc(100vh - 60px - 5rem)'
|
|
||||||
});
|
|
||||||
resize_text();
|
|
||||||
};
|
|
||||||
|
|
||||||
// bei Event (Aktiviaet) alles zuruecksetzen
|
|
||||||
function resetActivTimer(e) {
|
|
||||||
do_on_Active();
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ############################ */
|
|
||||||
/* ####### Progressbar ####### */
|
|
||||||
/* ############################ */
|
|
||||||
|
|
||||||
var counter_ID = 0;
|
|
||||||
|
|
||||||
function start_counter(zeitstempel, ablaufzeit) {
|
|
||||||
// Split timestamp into [ Y, M, D, h, m, s ]
|
|
||||||
var t1 = zeitstempel.split(/[- :]/),
|
|
||||||
t2 = ablaufzeit.split(/[- :]/);
|
|
||||||
|
|
||||||
var start = new Date(t1[0], t1[1] - 1, t1[2], t1[3], t1[4], t1[5]),
|
|
||||||
end = new Date(t2[0], t2[1] - 1, t2[2], t2[3], t2[4], t2[5]);
|
|
||||||
|
|
||||||
clearInterval(counter_ID);
|
|
||||||
counter_ID = setInterval(function() {
|
|
||||||
do_progressbar(start, end);
|
|
||||||
}, 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
function do_progressbar(start, end) {
|
|
||||||
today = new Date();
|
|
||||||
// restliche Zeit ermitteln
|
|
||||||
var current_progress = Math.round(100 / (end.getTime() - start.getTime()) * (end.getTime() - today.getTime()));
|
|
||||||
|
|
||||||
var diff = Math.abs(end - today);
|
|
||||||
var minutesDifference = Math.floor(diff / 1000 / 60);
|
|
||||||
diff -= minutesDifference * 1000 * 60;
|
|
||||||
var secondsDifference = Math.floor(diff / 1000);
|
|
||||||
if (secondsDifference <= 9) {
|
|
||||||
secondsDifference = '0' + secondsDifference;
|
|
||||||
};
|
|
||||||
var minutes = minutesDifference + ':' + secondsDifference;
|
|
||||||
// Progressbar anpassen
|
|
||||||
$("#hilfsfrist")
|
|
||||||
.css("width", current_progress + "%")
|
|
||||||
.attr("aria-valuenow", current_progress)
|
|
||||||
.text(minutes + " min");
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ########################### */
|
|
||||||
/* ######### LEAFLET ######### */
|
|
||||||
/* ########################### */
|
|
||||||
|
|
||||||
// Karte definieren
|
|
||||||
var map = L.map('map', {
|
|
||||||
zoomControl: false
|
|
||||||
}).setView([51.733005, 14.338048], 13);
|
|
||||||
|
|
||||||
// Layer der Karte
|
|
||||||
mapLink = L.tileLayer(
|
|
||||||
map_tile, {
|
|
||||||
maxZoom: 18
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
// Icon der Karte zuordnen
|
|
||||||
var redIcon = new L.Icon({
|
|
||||||
iconUrl: '/media/marker-icon-2x-red.png',
|
|
||||||
shadowUrl: '/media/marker-shadow.png',
|
|
||||||
iconSize: [25, 41],
|
|
||||||
iconAnchor: [12, 41],
|
|
||||||
popupAnchor: [1, -34],
|
|
||||||
shadowSize: [41, 41]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Icon setzen
|
|
||||||
var marker = L.marker(new L.LatLng(0, 0), {
|
|
||||||
icon: redIcon
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
/* ########################### */
|
|
||||||
/* ######## SOCKET.IO ######## */
|
|
||||||
/* ########################### */
|
|
||||||
|
|
||||||
// Websocket
|
|
||||||
var socket = io.connect();
|
|
||||||
|
|
||||||
// Wachen-ID bei Connect an Server senden
|
|
||||||
socket.on('connect', function() {
|
|
||||||
socket.emit('wachen_id', wachen_id);
|
|
||||||
$('#waipModal').modal('hide');
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('connect_error', function(err) {
|
|
||||||
$('#waipModalTitle').html('FEHLER');
|
|
||||||
$('#waipModalBody').html('Verbindung zum Server getrennt!');
|
|
||||||
$('#waipModal').modal('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
// ID von Server und Client vergleichen, falls ungleich -> Seite neu laden
|
|
||||||
socket.on('io.version', function(server_id) {
|
|
||||||
// TODO: socket.emit(lade client xxx neu)
|
|
||||||
if (client_id != server_id) {
|
|
||||||
$('#waipModalTitle').html('ACHTUNG');
|
|
||||||
$('#waipModalBody').html('Neue Server-Version. Seite wird in 10 Sekunden neu geladen!');
|
|
||||||
if ($('#waipModal').hasClass('in')) {
|
|
||||||
$('#waipModal').modal('hide');
|
|
||||||
};
|
|
||||||
$('#waipModal').modal('show');
|
|
||||||
setTimeout(function() {
|
|
||||||
location.reload();
|
|
||||||
}, 10000);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// ggf. Fehler ausgeben
|
|
||||||
socket.on('io.error', function(data) {
|
|
||||||
console.log('Error:', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sounds stoppen
|
|
||||||
socket.on('io.stopaudio', function(data) {
|
|
||||||
var audio = document.getElementById('audio');
|
|
||||||
audio.pause;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sounds abspielen
|
|
||||||
socket.on('io.playtts', function(data) {
|
|
||||||
var audio = document.getElementById('audio');
|
|
||||||
audio.src = (data);
|
|
||||||
// Audio-Blockade des Browsers erkennen
|
|
||||||
var promise = document.querySelector('audio').play();
|
|
||||||
if (promise !== undefined) {
|
|
||||||
promise.then(function(_) {
|
|
||||||
audio.play();
|
|
||||||
}).catch(function(error) {
|
|
||||||
//$('#waipModalTitle').html('Audio-Fehler');
|
|
||||||
//$('#waipModalBody').html('Die automatische Audio-Wiedergabe wird durch Ihren Browser blockiert! Fehlermeldung: ' + error.message);
|
|
||||||
//$('#waipModal').modal('show');
|
|
||||||
$('#volume').addClass("btn-danger");
|
|
||||||
$('.ion-md-volume-high').toggleClass("ion-md-volume-off");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Daten löschen, Uhr anzeigen
|
|
||||||
socket.on('io.standby', function(data) {
|
|
||||||
// Einsatz-ID auf 0 setzen
|
|
||||||
waip_id = null;
|
|
||||||
// TODO: Wenn vorhanden, hier #hilfsfrist zurücksetzen
|
|
||||||
$('#einsatz_art').removeClass(function(index, className) {
|
|
||||||
return (className.match(/(^|\s)bg-\S+/g) || []).join(' ');
|
|
||||||
});
|
|
||||||
$('#einsatz_stichwort').removeClass();
|
|
||||||
$('#einsatz_stichwort').html('');
|
|
||||||
$('#sondersignal').removeClass();
|
|
||||||
$('#ortsdaten').html('');
|
|
||||||
$('#besonderheiten').html('');
|
|
||||||
$('#em_alarmiert').empty();
|
|
||||||
$('#em_weitere').html('');
|
|
||||||
map.setView(new L.LatLng(0, 0), 14);
|
|
||||||
// Tableau ausblenden
|
|
||||||
$("#waiptableau").addClass("d-none");
|
|
||||||
$("#waipclock").removeClass("d-none");
|
|
||||||
// Text anpassen
|
|
||||||
resize_text();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Einsatzdaten laden, Wachalarm anzeigen
|
|
||||||
socket.on('io.neuerEinsatz', function(data) {
|
|
||||||
// DEBUG
|
|
||||||
//console.log(data);
|
|
||||||
// Einsatz-ID speichern
|
|
||||||
waip_id = data.id;
|
|
||||||
// Hintergrund der Einsatzart zunächst entfernen
|
|
||||||
$('#einsatz_art').removeClass(function(index, className) {
|
|
||||||
return (className.match(/(^|\s)bg-\S+/g) || []).join(' ');
|
|
||||||
});
|
|
||||||
// Icon der Einsatzart enfernen
|
|
||||||
$('#einsatz_stichwort').removeClass();
|
|
||||||
// Rückmeldung ausblenden
|
|
||||||
$('#rueckmeldung').addClass("d-none");
|
|
||||||
// Art und Stichwort festlegen hinterlegen
|
|
||||||
switch (data.einsatzart) {
|
|
||||||
case 'Brandeinsatz':
|
|
||||||
$('#einsatz_art').addClass("bg-danger");
|
|
||||||
$('#einsatz_stichwort').addClass("ion-md-flame");
|
|
||||||
$('#rueckmeldung').removeClass("d-none");
|
|
||||||
break;
|
|
||||||
case 'Hilfeleistungseinsatz':
|
|
||||||
$('#einsatz_art').addClass("bg-info");
|
|
||||||
$('#einsatz_stichwort').addClass("ion-md-construct");
|
|
||||||
$('#rueckmeldung').removeClass("d-none");
|
|
||||||
break;
|
|
||||||
case 'Rettungseinsatz':
|
|
||||||
$('#einsatz_art').addClass("bg-warning");
|
|
||||||
$('#einsatz_stichwort').addClass("ion-md-medkit");
|
|
||||||
break;
|
|
||||||
case 'Krankentransport':
|
|
||||||
$('#einsatz_art').addClass("bg-success");
|
|
||||||
$('#einsatz_stichwort').addClass("ion-md-medical");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$('#einsatz_art').addClass("bg-secondary");
|
|
||||||
$('#einsatz_stichwort').addClass("ion-md-information-circle");
|
|
||||||
};
|
|
||||||
$('#einsatz_stichwort').html(' ' + data.stichwort);
|
|
||||||
// Sondersignal setzen
|
|
||||||
$('#sondersignal').removeClass();
|
|
||||||
switch (data.sondersignal) {
|
|
||||||
case 1:
|
|
||||||
$('#sondersignal').addClass('ion-md-notifications');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$('#sondersignal').addClass('ion-md-notifications-off');
|
|
||||||
};
|
|
||||||
// Ortsdaten zusammenstellen und setzen
|
|
||||||
var small_ortsdaten;
|
|
||||||
small_ortsdaten = '';
|
|
||||||
if (data.objekt) {
|
|
||||||
small_ortsdaten = small_ortsdaten + break_text_15(data.objekt) + '<br>';
|
|
||||||
};
|
|
||||||
if (data.ort) {
|
|
||||||
small_ortsdaten = small_ortsdaten + break_text_15(data.ort) + '<br>';
|
|
||||||
};
|
|
||||||
if (data.ortsteil) {
|
|
||||||
small_ortsdaten = small_ortsdaten + break_text_15(data.ortsteil) + '<br>';
|
|
||||||
};
|
|
||||||
if (data.strasse) {
|
|
||||||
small_ortsdaten = small_ortsdaten + break_text_15(data.strasse) + '<br>';
|
|
||||||
};
|
|
||||||
if (small_ortsdaten.substr(small_ortsdaten.length - 4) == '<br>') {
|
|
||||||
small_ortsdaten = small_ortsdaten.slice(0, -4);
|
|
||||||
};
|
|
||||||
$('#ortsdaten').html(small_ortsdaten);
|
|
||||||
// Besonderheiten setzen
|
|
||||||
$('#besonderheiten').html(break_text_35(data.besonderheiten));
|
|
||||||
// alarmierte Einsatzmittel setzen
|
|
||||||
$('#em_alarmiert').empty();
|
|
||||||
var data_em_alarmiert = JSON.parse(data.em_alarmiert);
|
|
||||||
for (var i in data_em_alarmiert) {
|
|
||||||
$('#em_alarmiert').append('<li class="list-group-item d-flex justify-content-between align-items-center">' + data_em_alarmiert[i].name + '</li>');
|
|
||||||
};
|
|
||||||
// weitere alarmierte Einsatzmittel setzen
|
|
||||||
$('#em_weitere').html('');
|
|
||||||
var data_em_weitere = JSON.parse(data.em_weitere);
|
|
||||||
if (data_em_weitere == null) {
|
|
||||||
// TODO: Einzeige vergrößern (-.h-5) wenn keine weiteren Einsatzmittel beteiligt
|
|
||||||
} else {
|
|
||||||
var tmp;
|
|
||||||
for (var i in data_em_weitere) {
|
|
||||||
if (tmp) {
|
|
||||||
tmp = tmp + ', ' + data_em_weitere[i].name;
|
|
||||||
} else {
|
|
||||||
tmp = data_em_weitere[i].name;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
$('#em_weitere').html(tmp);
|
|
||||||
};
|
|
||||||
// Karte setzen
|
|
||||||
map.removeLayer(marker);
|
|
||||||
marker = L.marker(new L.LatLng(data.wgs84_x, data.wgs84_y), {
|
|
||||||
icon: redIcon
|
|
||||||
}).addTo(map);
|
|
||||||
map.setView(new L.LatLng(data.wgs84_x, data.wgs84_y), 15);
|
|
||||||
// Hilfsfrist setzen
|
|
||||||
start_counter(data.zeitstempel, data.ablaufzeit);
|
|
||||||
// Uhr ausblenden
|
|
||||||
$("#waipclock").addClass("d-none");
|
|
||||||
$("#waiptableau").removeClass("d-none");
|
|
||||||
// Text anpassen
|
|
||||||
resize_text();
|
|
||||||
});
|
|
||||||
|
|
||||||
/* ########################### */
|
|
||||||
/* ####### SCREENSAVER ####### */
|
|
||||||
/* ########################### */
|
|
||||||
|
|
||||||
// Uhrzeit und Datum für Bildschirmschoner
|
|
||||||
function set_clock() {
|
|
||||||
// Wochentage
|
|
||||||
var d_names = new Array('Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag');
|
|
||||||
// Monate
|
|
||||||
var m_names = new Array('Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember');
|
|
||||||
// Aktuelle Zeit
|
|
||||||
var d = new Date();
|
|
||||||
var curr_day = d.getDay();
|
|
||||||
var curr_date = d.getDate();
|
|
||||||
var curr_month_id = d.getMonth();
|
|
||||||
curr_month_id = curr_month_id + 1;
|
|
||||||
var curr_year = d.getFullYear();
|
|
||||||
var curr_hour = d.getHours();
|
|
||||||
var curr_min = d.getMinutes();
|
|
||||||
// Tag und Monat Anpassen
|
|
||||||
if ((String(curr_date)).length == 1)
|
|
||||||
curr_date = '0' + curr_date;
|
|
||||||
if ((String(curr_month_id)).length == 1)
|
|
||||||
curr_month_id = '0' + curr_month_id;
|
|
||||||
// Uhrzeit und Minute anpassen
|
|
||||||
if (curr_min <= 9) {
|
|
||||||
curr_min = '0' + curr_min;
|
|
||||||
};
|
|
||||||
if (curr_hour <= 9) {
|
|
||||||
curr_hour = '0' + curr_hour;
|
|
||||||
};
|
|
||||||
var curr_month = d.getMonth();
|
|
||||||
var curr_year = d.getFullYear();
|
|
||||||
var element_time = curr_hour + ':' + curr_min;
|
|
||||||
var element_day = d_names[curr_day] + ', ' + curr_date + '. ' + m_names[curr_month];
|
|
||||||
var element_date_time = curr_date + '.' + curr_month_id + '.' + curr_year + ' - ' + element_time;
|
|
||||||
// nur erneuern wenn sich Zeit geändert hat
|
|
||||||
if (document.getElementById('time').textContent !== element_time) {
|
|
||||||
// Uhrzeit anzeigen
|
|
||||||
document.getElementById('time').innerHTML = element_time;
|
|
||||||
// Datum (Text) anzeigen
|
|
||||||
document.getElementById('day').innerHTML = element_day;
|
|
||||||
// Datum anzeigen, sofern sichtbar
|
|
||||||
document.getElementById('date-time').innerHTML = element_date_time;
|
|
||||||
// Textgröße neu setzen
|
|
||||||
resize_text();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uhrzeit jede Sekunden anpassen
|
|
||||||
setInterval(set_clock, 1000);
|
|
||||||
|
|
||||||
/* ########################### */
|
|
||||||
/* ####### Rückmeldung ####### */
|
|
||||||
/* ########################### */
|
|
||||||
|
|
||||||
$('#rueckmeldung').each(function(index) {
|
|
||||||
$(this).on("click", function(){
|
|
||||||
$('#responseModal').modal('show');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#send_response').on('click', function() {
|
|
||||||
// Rückmeldung senden
|
|
||||||
socket.emit(
|
|
||||||
'response',
|
|
||||||
waip_id,
|
|
||||||
$('#radios_res_ek').prop('checked'),
|
|
||||||
$('#radios_res_ma').prop('checked'),
|
|
||||||
$('#radios_res_fk').prop('checked'),
|
|
||||||
$('#cb_res_agt').prop('checked')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('io.response', function(data) {
|
|
||||||
// Rückmeldungen hinterlegen
|
|
||||||
$('#rueckmeldung').empty();
|
|
||||||
//{einsatzkraft: "0", maschinist: "0", fuehrungskraft: "0", atemschutz: "0"}
|
|
||||||
for (var i in data) {
|
|
||||||
var item_class = 'list-group-item flex-fill list-group-item-action tf_singleline';
|
|
||||||
switch (data[i]) {
|
|
||||||
case '0':
|
|
||||||
item_class = item_class + ' text-danger';
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
item_class = item_class + ' text-warning';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
item_class = item_class + ' text-success';
|
|
||||||
};
|
|
||||||
$('#rueckmeldung').append('<a class="' + item_class + '">' + data[i] + ' ' + i + '</a>');
|
|
||||||
};
|
|
||||||
resize_text();
|
|
||||||
});
|
|
||||||
BIN
public/media/bell_message.mp3
Executable file
BIN
public/media/bell_message.mp3
Executable file
Binary file not shown.
81
server.js
81
server.js
@ -1,24 +1,42 @@
|
|||||||
// Module laden
|
const fs = require('fs');
|
||||||
var fs = require('fs');
|
const express = require('express');
|
||||||
var express = require('express');
|
const app = express();
|
||||||
var app = express();
|
const http = require('http');
|
||||||
var http = require('http') //.Server(app);
|
const https = require('https');
|
||||||
var https = require('https'); //.Server(app);
|
const webserver = https.createServer({
|
||||||
var webserver = https.createServer({
|
key: fs.readFileSync('./misc/server.key', 'utf8'),
|
||||||
key: fs.readFileSync('./server/server.key', 'utf8'),
|
cert: fs.readFileSync('./misc/server.cert', 'utf8')
|
||||||
cert: fs.readFileSync('./server/server.cert', 'utf8')
|
|
||||||
}, app);
|
}, app);
|
||||||
var io = require('socket.io').listen(webserver);
|
const io = require('socket.io').listen(webserver);
|
||||||
var async = require('async');
|
const io_api = require('socket.io-client');
|
||||||
var path = require('path');
|
const async = require('async');
|
||||||
var favicon = require('serve-favicon');
|
const path = require('path');
|
||||||
var bodyParser = require('body-parser');
|
const favicon = require('serve-favicon');
|
||||||
var bcrypt = require('bcrypt');
|
const bodyParser = require('body-parser');
|
||||||
var passport = require('passport');
|
const bcrypt = require('bcrypt');
|
||||||
|
const passport = require('passport');
|
||||||
|
const { v4: uuidv4 } = require('uuid');
|
||||||
|
|
||||||
|
// Basis-Konfiguration laden und generische App-UUID erzeugen
|
||||||
|
var app_cfg = require('./server/app_cfg.js');
|
||||||
|
app_cfg.global.app_id = uuidv4();
|
||||||
|
app_cfg.public.version = 'Version 1.2.1';
|
||||||
|
|
||||||
|
// Remote-Api aktivieren
|
||||||
|
var remote_api;
|
||||||
|
if (app_cfg.endpoint.enabled) {
|
||||||
|
remote_api = io_api.connect(app_cfg.endpoint.host, {
|
||||||
|
reconnect: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Express-Einstellungen
|
// Express-Einstellungen
|
||||||
app.set('views', path.join(__dirname, 'views'));
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
app.locals.basedir = app.get('views');
|
||||||
app.set('view engine', 'pug');
|
app.set('view engine', 'pug');
|
||||||
|
if (!app_cfg.global.development) {
|
||||||
|
app.set('view cache', true);
|
||||||
|
};
|
||||||
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
|
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
|
||||||
app.use(express.static(path.join(__dirname, 'public')));
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
@ -27,21 +45,24 @@ app.use(bodyParser.urlencoded({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Scripte einbinden
|
// Scripte einbinden
|
||||||
var app_cfg = require('./server/app_cfg.js');
|
|
||||||
var sql_cfg = require('./server/sql_cfg')(fs, bcrypt, app_cfg);
|
var sql_cfg = require('./server/sql_cfg')(fs, bcrypt, app_cfg);
|
||||||
var sql = require('./server/sql_qry')(sql_cfg, async, app_cfg)
|
var sql = require('./server/sql_qry')(sql_cfg, app_cfg);
|
||||||
var waip_io = require('./server/waip_io')(io, sql, async, app_cfg);
|
var brk = require('./server/broker')(app_cfg, sql, uuidv4);
|
||||||
var udp = require('./server/udp')(app_cfg, waip_io, sql);
|
var waip = require('./server/waip')(io, sql, fs, brk, async, app_cfg);
|
||||||
|
var saver = require('./server/saver')(app_cfg, sql, waip, uuidv4, io, remote_api);
|
||||||
|
var api = require('./server/api')(io, sql, app_cfg, remote_api, saver);
|
||||||
|
var socket = require('./server/socket')(io, sql, app_cfg, waip);
|
||||||
|
var udp = require('./server/udp')(app_cfg, sql, saver);
|
||||||
var auth = require('./server/auth')(app, app_cfg, sql_cfg, async, bcrypt, passport, io);
|
var auth = require('./server/auth')(app, app_cfg, sql_cfg, async, bcrypt, passport, io);
|
||||||
var routes = require('./server/routing')(app, sql, app_cfg, passport, auth, udp);
|
var routes = require('./server/routing')(app, sql, uuidv4, app_cfg, passport, auth, udp, saver);
|
||||||
|
|
||||||
// Server starten
|
// Server starten
|
||||||
webserver.listen(app_cfg.global.https_port, function() {
|
webserver.listen(app_cfg.global.https_port, function () {
|
||||||
sql.db_log('Anwendung', 'Wachalarm-IP-Webserver auf Port ' + app_cfg.global.https_port + ' gestartet');
|
sql.db_log('Anwendung', 'Wachalarm-IP-Webserver auf Port ' + app_cfg.global.https_port + ' gestartet');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redirect all HTTP traffic to HTTPS
|
// Redirect all HTTP traffic to HTTPS
|
||||||
http.createServer(function(req, res) {
|
http.createServer(function (req, res) {
|
||||||
var host = req.headers.host;
|
var host = req.headers.host;
|
||||||
// prüfen ob host gesetzt, sonst 404
|
// prüfen ob host gesetzt, sonst 404
|
||||||
if (typeof host !== 'undefined' && host) {
|
if (typeof host !== 'undefined' && host) {
|
||||||
@ -53,12 +74,10 @@ http.createServer(function(req, res) {
|
|||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
// HTTP status 404: NotFound
|
// HTTP status 404: NotFound
|
||||||
res.writeHead(404, {
|
res.writeHead(404, {
|
||||||
"Content-Type": "text/plain"
|
"Content-Type": "text/plain"
|
||||||
});
|
});
|
||||||
res.write("404 Not Found - use https instead!\n");
|
res.write("404 Not Found - use https instead!\n");
|
||||||
res.end();
|
res.end();
|
||||||
};
|
};
|
||||||
}).listen(app_cfg.global.http_port);
|
}).listen(app_cfg.global.http_port);
|
||||||
|
|
||||||
// TODO: auf HTTPS mit TLS1.2 umstellen, inkl. WSS
|
|
||||||
118
server/api.js
Executable file
118
server/api.js
Executable file
@ -0,0 +1,118 @@
|
|||||||
|
module.exports = function (io, sql, app_cfg, remote_api, saver) {
|
||||||
|
|
||||||
|
// ###
|
||||||
|
// Server Socket.IO Empfangs-API (anderer Server stellt Verbindung her und sendet Daten)
|
||||||
|
// ###
|
||||||
|
|
||||||
|
if (app_cfg.api.enabled) {
|
||||||
|
|
||||||
|
// Namespace API festlegen
|
||||||
|
var nsp_api = io.of('/api');
|
||||||
|
|
||||||
|
nsp_api.on('connection', function (socket) {
|
||||||
|
// versuche Remote-IP zu ermitteln
|
||||||
|
var remote_ip = socket.handshake.headers["x-real-ip"] || socket.handshake.headers['x-forwarded-for'] || socket.request.connection.remoteAddress;
|
||||||
|
|
||||||
|
// Remote-Verbindung nur zulassen, wenn IP in Access-List, und Access-List ueberhaupt befuellt
|
||||||
|
if (!app_cfg.api.access_list.includes(remote_ip) && app_cfg.api.access_list.length > 0) {
|
||||||
|
socket.disconnect(true);
|
||||||
|
sql.db_log('API', 'Verbindung von ' + remote_ip + ' geschlossen, da nicht in Zugangsliste.');
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO API: Eingehende Verbindung nur mit passendem Geheimnis zulassen, das Ergebnis loggen
|
||||||
|
|
||||||
|
// in Liste der Clients mit aufnehmen
|
||||||
|
sql.db_client_update_status(socket, 'api');
|
||||||
|
|
||||||
|
// Neuen Einsatz speichern
|
||||||
|
socket.on('from_client_to_server_new_waip', function (raw_data) {
|
||||||
|
var data = raw_data.data;
|
||||||
|
var app_id = raw_data.app_id;
|
||||||
|
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
||||||
|
if (app_id != app_cfg.global.app_id) {
|
||||||
|
saver.save_new_waip(data, remote_ip, app_id);
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
sql.db_log('API', 'Neuer Wachalarm von ' + remote_ip + ': ' + JSON.stringify(data));
|
||||||
|
} else {
|
||||||
|
sql.db_log('API', 'Neuer Wachalarm von ' + remote_ip + '. Wird verarbeitet.');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// neue externe Rueckmeldung speichern
|
||||||
|
socket.on('from_client_to_server_new_rmld', function (raw_data) {
|
||||||
|
var data = raw_data.data;
|
||||||
|
var app_id = raw_data.app_id;
|
||||||
|
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
||||||
|
if (app_id != app_cfg.global.app_id) {
|
||||||
|
saver.save_new_rmld(data, remote_ip, app_id, function (result) {
|
||||||
|
if (!result) {
|
||||||
|
sql.db_log('API', 'Fehler beim speichern der Rückmeldung von ' + remote_ip + ': ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disconnect
|
||||||
|
socket.on('disconnect', function () {
|
||||||
|
sql.db_log('API', 'Schnittstelle von ' + remote_ip + ' (' + socket.id + ') geschlossen.');
|
||||||
|
sql.db_client_delete(socket);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ###
|
||||||
|
// Client Socket.IO Sende-API (Daten an Server senden, zu denen eine Verbindung hergestellt wurde)
|
||||||
|
// ###
|
||||||
|
|
||||||
|
if (app_cfg.endpoint.enabled) {
|
||||||
|
// Verbindung zu anderem Server aufbauen
|
||||||
|
// TODO API: Verbindungsaufbau mit passendem Geheimnis absichern, IP-Adresse senden
|
||||||
|
|
||||||
|
// Verbindungsaufbau protokollieren
|
||||||
|
remote_api.on('connect', function () {
|
||||||
|
sql.db_log('API', 'Verbindung mit ' + app_cfg.endpoint.host + ' ergestellt');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fehler protokollieren
|
||||||
|
remote_api.on('connect_error', function (err) {
|
||||||
|
sql.db_log('API', 'Verbindung zu ' + app_cfg.endpoint.host + ' verloren, Fehler: ' + err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verbindungsabbau protokollieren
|
||||||
|
remote_api.on('disconnect', function (reason) {
|
||||||
|
sql.db_log('API', 'Verbindung zu ' + app_cfg.endpoint.host + ' verloren, Fehler: ' + reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
// neuer Einsatz vom Endpoint-Server
|
||||||
|
remote_api.on('from_server_to_client_new_waip', function (raw_data) {
|
||||||
|
var data = raw_data.data;
|
||||||
|
var app_id = raw_data.app_id;
|
||||||
|
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
||||||
|
if (app_id != app_cfg.global.app_id) {
|
||||||
|
// nicht erwuenschte Daten ggf. enfernen (Datenschutzoption)
|
||||||
|
saver.save_new_waip(data, app_cfg.endpoint.host, app_id);
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
sql.db_log('API', 'Neuer Wachalarm von ' + app_cfg.endpoint.host + ': ' + JSON.stringify(data));
|
||||||
|
} else {
|
||||||
|
sql.db_log('API', 'Neuer Wachalarm von ' + app_cfg.endpoint.host + '. Wird verarbeitet.');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// neue Rückmeldung vom Endpoint-Server
|
||||||
|
remote_api.on('from_server_to_client_new_rmld', function (raw_data) {
|
||||||
|
var data = raw_data.data;
|
||||||
|
var app_id = raw_data.app_id;
|
||||||
|
// nur speichern wenn app_id nicht eigenen globalen app_id entspricht
|
||||||
|
if (app_id != app_cfg.global.app_id) {
|
||||||
|
saver.save_new_rmld(data, app_cfg.endpoint.host, app_id, function (result) {
|
||||||
|
if (!result) {
|
||||||
|
sql.db_log('API', 'Fehler beim speichern der Rückmeldung von ' + app_cfg.endpoint.host + ': ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
@ -1,22 +1,71 @@
|
|||||||
var app_cfg = {};
|
var app_cfg = {};
|
||||||
|
|
||||||
|
// Server-Einstellungen
|
||||||
app_cfg.global = {
|
app_cfg.global = {
|
||||||
http_port: 3000,
|
development: true,
|
||||||
https_port: 3443,
|
http_port: 3000,
|
||||||
udpport: 60233,
|
https_port: 3443,
|
||||||
database: './database.sqlite3',
|
udpport: 60233,
|
||||||
soundpath: '/public/media/',
|
database: './database.sqlite3',
|
||||||
mediapath: '/media/',
|
soundpath: '/public/media/',
|
||||||
time_to_delete_waip: 60,
|
mediapath: '/media/',
|
||||||
default_time_for_standby: 10,
|
time_to_delete_waip: 4,
|
||||||
defaultuser: 'me',
|
default_time_for_standby: 10,
|
||||||
defaultpass: '123',
|
circumcircle: 5,
|
||||||
defaultuserip: '127.0.0.1',
|
defaultuser: 'me',
|
||||||
ip_auth_range: ['::ffff:172.16.5.0/24', '::ffff:192.168.2.0/24'],
|
defaultpass: '123',
|
||||||
saltRounds: 10,
|
defaultuserip: '127.0.0.1',
|
||||||
sessionsecret: '0987654321abcdef#xyz',
|
ip_auth_range: ['::ffff:172.16.5.0/24', '::ffff:192.168.2.0/24'],
|
||||||
app_id: process.pid,
|
saltRounds: 10,
|
||||||
map_tile: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
|
sessionsecret: '0987654321abcdef#xyz'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Einstellungen zur Erscheinung der Seite
|
||||||
|
app_cfg.public = {
|
||||||
|
url: 'https://wachalarm.mooo.com',
|
||||||
|
app_name: 'Wachalarm IP-Web',
|
||||||
|
company: 'Leitstelle Lausitz',
|
||||||
|
map_tile: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
|
map_attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||||
|
ext_imprint: false,
|
||||||
|
url_imprint: 'https://www.nix.nix/impressium',
|
||||||
|
ext_privacy: false,
|
||||||
|
url_privacy: 'https://www.nix.nix/datenschutz'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Einstellungen fuer Backups von Rueckmeldungen
|
||||||
|
app_cfg.rmld = {
|
||||||
|
backup_to_file: true,
|
||||||
|
backup_path: '/misc/bkp/',
|
||||||
|
backup_to_mail: false,
|
||||||
|
mailserver_host: 'smtp.xxx.xxx',
|
||||||
|
mailserver_port: 587,
|
||||||
|
secure_mail: false,
|
||||||
|
unauthorized_mail: false,
|
||||||
|
mail_user: 'testuser',
|
||||||
|
mail_pass: 'testuserpass',//'testpass',
|
||||||
|
mail_from: 'xyz@xxx.xxx'//'keineantwort@wachalarm.info.tm'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schnittstelle um Daten von anderen Clients zu empfangen
|
||||||
|
app_cfg.api = {
|
||||||
|
enabled: true,
|
||||||
|
secret: 'asdfwert1234567890#',
|
||||||
|
access_list: ['192.168.2.20', '192.168.2.30', '80.147.87.170']
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schnittstelle um Daten an andere Server zu senden
|
||||||
|
app_cfg.endpoint = {
|
||||||
|
enabled: true,
|
||||||
|
host: 'https://wachalarm.leitstelle-lausitz.de/api',
|
||||||
|
secret: 'asdfwert1234567890#'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schnittstellendaten von bestimmten Clients entfernen (Datenschutzoption)
|
||||||
|
app_cfg.filter = {
|
||||||
|
enabled: true,
|
||||||
|
on_message_from: ['192.168.2.20', 'https://192.168.1.25:8090/api'],
|
||||||
|
remove_data: ['besonderheiten', 'strasse', 'objekt', 'objektnr', 'wachfolge', 'wgs84_x', 'wgs84_y']
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = app_cfg;
|
module.exports = app_cfg;
|
||||||
|
|||||||
@ -78,7 +78,7 @@ module.exports = function(app, app_cfg, db, async, bcrypt, passport, io) {
|
|||||||
|
|
||||||
passport.deserializeUser(function(id, done) {
|
passport.deserializeUser(function(id, done) {
|
||||||
db.get(`SELECT id, user, permissions,
|
db.get(`SELECT id, user, permissions,
|
||||||
(select reset_counter from waip_configs where user_id = ?) reset_counter
|
(select reset_counter from waip_user_config where user_id = ?) reset_counter
|
||||||
FROM waip_users WHERE id = ?`, [id, id], function(err, row) {
|
FROM waip_users WHERE id = ?`, [id, id], function(err, row) {
|
||||||
if (!row) {
|
if (!row) {
|
||||||
return done(null, false);
|
return done(null, false);
|
||||||
@ -123,17 +123,17 @@ module.exports = function(app, app_cfg, db, async, bcrypt, passport, io) {
|
|||||||
// if(err)
|
// if(err)
|
||||||
if (row) {
|
if (row) {
|
||||||
req.flash('errorMessage', "Es existiert bereits ein Benutzer mit diesem Namen!");
|
req.flash('errorMessage', "Es existiert bereits ein Benutzer mit diesem Namen!");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
} else {
|
} else {
|
||||||
bcrypt.hash(req.body.password, app_cfg.global.saltRounds, function(err, hash) {
|
bcrypt.hash(req.body.password, app_cfg.global.saltRounds, function(err, hash) {
|
||||||
db.run('INSERT INTO waip_users ( user, password, permissions, ip_address ) VALUES( ?, ?, ?, ? )', req.body.username, hash, req.body.permissions, req.body.ip, function(err) {
|
db.run('INSERT INTO waip_users ( user, password, permissions, ip_address ) VALUES( ?, ?, ?, ? )', req.body.username, hash, req.body.permissions, req.body.ip, function(err) {
|
||||||
// if(err)
|
// if(err)
|
||||||
if (this.lastID) {
|
if (this.lastID) {
|
||||||
req.flash('successMessage', "Neuer Benutzer wurde angelegt.");
|
req.flash('successMessage', "Neuer Benutzer wurde angelegt.");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
} else {
|
} else {
|
||||||
req.flash('errorMessage', "Da ist etwas schief gegangen...");
|
req.flash('errorMessage', "Da ist etwas schief gegangen...");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -144,14 +144,14 @@ module.exports = function(app, app_cfg, db, async, bcrypt, passport, io) {
|
|||||||
function deleteUser(req, res) {
|
function deleteUser(req, res) {
|
||||||
if (req.user.id == req.body.id) {
|
if (req.user.id == req.body.id) {
|
||||||
req.flash('errorMessage', "Sie können sich nicht selbst löschen!");
|
req.flash('errorMessage', "Sie können sich nicht selbst löschen!");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
} else {
|
} else {
|
||||||
db.run('DELETE FROM waip_users WHERE id = ?', req.body.id, function(err) {
|
db.run('DELETE FROM waip_users WHERE id = ?', req.body.id, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
//...
|
//...
|
||||||
} else {
|
} else {
|
||||||
req.flash('successMessage', "Benutzer \'" + req.body.username + "\' wurde gelöscht!");
|
req.flash('successMessage', "Benutzer \'" + req.body.username + "\' wurde gelöscht!");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -195,15 +195,15 @@ module.exports = function(app, app_cfg, db, async, bcrypt, passport, io) {
|
|||||||
//...
|
//...
|
||||||
console.log(err);
|
console.log(err);
|
||||||
req.flash('errorMessage', "Da ist etwas schief gegangen...");
|
req.flash('errorMessage', "Da ist etwas schief gegangen...");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
} else {
|
} else {
|
||||||
req.flash('successMessage', "Benutzer aktualisiert.");
|
req.flash('successMessage', "Benutzer aktualisiert.");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
req.flash('errorMessage', "Da ist etwas schief gegangen...");
|
req.flash('errorMessage', "Da ist etwas schief gegangen...");
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
124
server/broker.js
Executable file
124
server/broker.js
Executable file
@ -0,0 +1,124 @@
|
|||||||
|
module.exports = function (app_cfg, sql, uuidv4) {
|
||||||
|
|
||||||
|
// Module laden
|
||||||
|
const twit = require('twit');
|
||||||
|
|
||||||
|
function alert_vmtl_list(list_data, callback) {
|
||||||
|
|
||||||
|
// waip_wachen_id, vmlt_typ, vmlt_account_name, vmtl_account_group, waip_id
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
console.log('Liste Vermittlung: ' + JSON.stringify(list_data));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (list_data.vmtl_typ == 'twitter') {
|
||||||
|
// wenn es sich um eine Twitter-Liste/Gruppe handelt, Account-Zugangsdaten ermitteln
|
||||||
|
sql.db_vmtl_get_tw_account(list_data, function (vmtl_data) {
|
||||||
|
|
||||||
|
// vmtl_data: tw_screen_name, tw_consumer_key, tw_consumer_secret, tw_access_token_key, tw_access_token_secret, uuid, einsatzart, name_wache
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
console.log('Twitter-Account-Daten: ' + JSON.stringify(vmtl_data));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (vmtl_data) {
|
||||||
|
// Prüfen ob zuletzt bereits eine Nachricht gesendet wurde (Doppelalarmierung vermeiden)
|
||||||
|
sql.db_vmtl_check_history(vmtl_data, list_data, function (exists) {
|
||||||
|
if (!exists) {
|
||||||
|
var T = new twit({
|
||||||
|
consumer_key: vmtl_data.tw_consumer_key,
|
||||||
|
consumer_secret: vmtl_data.tw_consumer_secret,
|
||||||
|
access_token: vmtl_data.tw_access_token_key,
|
||||||
|
access_token_secret: vmtl_data.tw_access_token_secret
|
||||||
|
})
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
screen_name: vmtl_data.tw_screen_name
|
||||||
|
};
|
||||||
|
|
||||||
|
// Twitter-Liste beschicken
|
||||||
|
T.get('lists/list', params, function (error, lists, response) {
|
||||||
|
if (!error) {
|
||||||
|
var list_obj = lists.filter(function (o) {
|
||||||
|
return o.name == vmtl_data.list;
|
||||||
|
});
|
||||||
|
var member_params = {
|
||||||
|
list_id: list_obj[0].id_str,
|
||||||
|
count: 50
|
||||||
|
};
|
||||||
|
// mit List_id die Mitglieder der Liste auslesen
|
||||||
|
T.get('lists/members', member_params, function (error, members, response) {
|
||||||
|
if (!error) {
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
console.log('Mitglieder der Twitter-Liste: ' + JSON.stringify(members));
|
||||||
|
console.log('Response der Twitter-Liste: ' + JSON.stringify(response));
|
||||||
|
};
|
||||||
|
// an jedes Mitglied der Liste eine Meldung senden
|
||||||
|
var arrayLength = members.users.length;
|
||||||
|
for (var i = 0; i < arrayLength; i++) {
|
||||||
|
// Mitteilungstext festelgen
|
||||||
|
console.log(members);
|
||||||
|
var tw_text = String.fromCodePoint(0x1F4DF) + ' ' + String.fromCodePoint(0x1F6A8) + String.fromCodePoint(0x0A) +
|
||||||
|
'Einsatz für ' + vmtl_data.name_wache + ' ' + String.fromCodePoint(0x27A1) + ' ' + vmtl_data.einsatzart + ', ' + vmtl_data.stichwort + String.fromCodePoint(0x0A) +
|
||||||
|
'jetzt Rückmeldung senden: ' + app_cfg.public.url + '/rmld/' + vmtl_data.uuid + '/' + uuidv4();
|
||||||
|
// Parameter der Mitteilung
|
||||||
|
var msg_params = {
|
||||||
|
event: {
|
||||||
|
type: "message_create",
|
||||||
|
message_create: {
|
||||||
|
target: {
|
||||||
|
recipient_id: members.users[i].id_str
|
||||||
|
},
|
||||||
|
message_data: {
|
||||||
|
text: tw_text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Mitteilung senden
|
||||||
|
T.post('direct_messages/events/new', msg_params, function (error, members, response) {
|
||||||
|
if (!error) {
|
||||||
|
sql.db_log('VMTL', 'Einsatz-Link gesendet: ' + JSON.stringify(members));
|
||||||
|
callback && callback(vmtl_data.list);
|
||||||
|
} else {
|
||||||
|
console.log('e1');
|
||||||
|
sql.db_log('VMTL', 'Fehler beim senden eines Einsatz-Links: ' + error);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
console.log('e2');
|
||||||
|
sql.db_log('VMTL', 'Fehler beim lesen der Mitglieder der Twitter-Liste: ' + error);
|
||||||
|
callback && callback(null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('e3');
|
||||||
|
sql.db_log('VMTL', 'Fehler beim lesen der Twitter-Liste: ' + error);
|
||||||
|
callback && callback(null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('e4');
|
||||||
|
sql.db_log('VMTL', 'Rückmeldungs-Link für Twitter-Account ' + list_data.vmtl_account_name + ' bereits zuvor gesendet. Wird verworfen.');
|
||||||
|
callback && callback(null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log('e5');
|
||||||
|
sql.db_log('VMTL', 'Zugangsdaten für Twitter-Account ' + list_data.vmtl_account_name + ' konnten nicht ermittelt werden.');
|
||||||
|
callback && callback(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// andere Listen/Gruppen/Schnittstellen koennten hier noch abgefragt werden
|
||||||
|
console.log('e6');
|
||||||
|
callback && callback(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
alert_vmtl_list: alert_vmtl_list
|
||||||
|
};
|
||||||
|
};
|
||||||
446
server/routing.js
Normal file → Executable file
446
server/routing.js
Normal file → Executable file
@ -1,56 +1,115 @@
|
|||||||
module.exports = function(app, sql, app_cfg, passport, auth, udp) {
|
module.exports = function (app, sql, uuidv4, app_cfg, passport, auth, udp, saver) {
|
||||||
|
|
||||||
// get index
|
/* ########################### */
|
||||||
app.get('/', function(req, res) {
|
/* ##### Statische Seiten #### */
|
||||||
sql.db_list_wachen(function(data) {
|
/* ########################### */
|
||||||
var data_wachen = data
|
|
||||||
sql.db_list_traeger(function(data) {
|
// Startseite
|
||||||
var data_traeger = data
|
app.get('/', function (req, res) {
|
||||||
sql.db_list_kreis(function(data) {
|
sql.db_einsatz_count_all(function (data) {
|
||||||
var data_kreis = data
|
res.render('home', {
|
||||||
res.render('home', {
|
public: app_cfg.public,
|
||||||
title: 'Startseite',
|
title: 'Startseite',
|
||||||
list_wache: data_wachen,
|
anzahl_einsaetze: data,
|
||||||
list_traeger: data_traeger,
|
user: req.user
|
||||||
list_kreis: data_kreis,
|
|
||||||
user: req.user
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /waip
|
// Ueber die Anwendung
|
||||||
app.get('/waip', function(req, res) {
|
app.get('/about', function (req, res) {
|
||||||
res.redirect('/waip/0');
|
res.render('about', {
|
||||||
});
|
public: app_cfg.public,
|
||||||
|
title: 'Über',
|
||||||
// get /waip/<wachennummer>
|
user: req.user
|
||||||
// TODO: Abstruz bei unbekannter/falscher Wachennummer
|
|
||||||
app.get('/waip/:wachen_id', function(req, res, next) {
|
|
||||||
var parmeter_id = req.params.wachen_id;
|
|
||||||
sql.db_wache_vorhanden(parmeter_id, function(result) {
|
|
||||||
if (result) {
|
|
||||||
res.render('waip', {
|
|
||||||
title: 'Alarmmonitor',
|
|
||||||
wachen_id: parmeter_id,
|
|
||||||
data_wache: ' ' + result.name,
|
|
||||||
app_id: app_cfg.global.app_id,
|
|
||||||
map_tile: app_cfg.global.map_tile,
|
|
||||||
user: req.user
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var err = new Error('Wache ' + parmeter_id + ' nicht vorhanden!');
|
|
||||||
err.status = 404;
|
|
||||||
next(err);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /config
|
// Impressum
|
||||||
app.get('/config', auth.ensureAuthenticated, function(req, res) {
|
app.get('/impressum', function (req, res) {
|
||||||
sql.db_get_userconfig(req.user.id, function(data) {
|
if (app_cfg.public.ext_imprint) {
|
||||||
res.render('config', {
|
res.redirect(app_cfg.public.url_imprint);
|
||||||
|
} else {
|
||||||
|
res.render('imprint', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Impressum',
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Datenschutzerklaerung
|
||||||
|
app.get('/datenschutz', function (req, res) {
|
||||||
|
if (app_cfg.public.ext_privacy) {
|
||||||
|
res.redirect(app_cfg.public.url_privacy);
|
||||||
|
} else {
|
||||||
|
res.render('privacy', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Datenschutzerklärung',
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// API
|
||||||
|
app.get('/api', function (req, res, next) {
|
||||||
|
var err = new Error('Sie sind nicht berechtigt diese Seite aufzurufen!');
|
||||||
|
err.status = 403;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ##################### */
|
||||||
|
/* ####### Login ####### */
|
||||||
|
/* ##################### */
|
||||||
|
|
||||||
|
// Loginseite
|
||||||
|
app.get('/login', function (req, res) {
|
||||||
|
res.render('login', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Login',
|
||||||
|
user: req.user,
|
||||||
|
error: req.flash('error')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Login-Formular verarbeiten
|
||||||
|
app.post('/login', passport.authenticate('local', {
|
||||||
|
failureRedirect: '/login',
|
||||||
|
failureFlash: 'Login fehlgeschlagen! Bitte prüfen Sie Benutzername und Passwort.'
|
||||||
|
}), function (req, res) {
|
||||||
|
if (req.body.rememberme) {
|
||||||
|
// der Benutzer muss sich fuer 5 Jahre nicht anmelden
|
||||||
|
req.session.cookie.maxAge = 5 * 365 * 24 * 60 * 60 * 1000;
|
||||||
|
};
|
||||||
|
res.redirect('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Login mit IP verarbeiten
|
||||||
|
app.post('/login_ip', passport.authenticate('ip', {
|
||||||
|
failureRedirect: '/login',
|
||||||
|
failureFlash: 'Login mittels IP-Adresse fehlgeschlagen!'
|
||||||
|
}), function (req, res) {
|
||||||
|
// der Benutzer muss sich fuer 5 Jahre nicht anmelden
|
||||||
|
req.session.cookie.maxAge = 5 * 365 * 24 * 60 * 60 * 1000;
|
||||||
|
res.redirect('/');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logout verarbeiten
|
||||||
|
app.post('/logout', function (req, res) {
|
||||||
|
req.session.destroy(function (err) {
|
||||||
|
res.redirect('/');
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ######################### */
|
||||||
|
/* ##### Einstellungen ##### */
|
||||||
|
/* ######################### */
|
||||||
|
|
||||||
|
// Einstellungen anzeigen
|
||||||
|
app.get('/config', auth.ensureAuthenticated, function (req, res) {
|
||||||
|
sql.db_user_get_config(req.user.id, function (data) {
|
||||||
|
res.render('user/user_config', {
|
||||||
|
public: app_cfg.public,
|
||||||
title: 'Einstellungen',
|
title: 'Einstellungen',
|
||||||
user: req.user,
|
user: req.user,
|
||||||
reset_counter: data
|
reset_counter: data
|
||||||
@ -58,40 +117,182 @@ module.exports = function(app, sql, app_cfg, passport, auth, udp) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/config', auth.ensureAuthenticated, function(req, res) {
|
// Einstellungen speichern
|
||||||
sql.db_set_userconfig(req.user.id, req.body.set_reset_counter, function(data) {
|
app.post('/config', auth.ensureAuthenticated, function (req, res) {
|
||||||
|
sql.db_user_set_config(req.user.id, req.body.set_reset_counter, function (data) {
|
||||||
res.redirect('/config');
|
res.redirect('/config');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /help
|
/* ##################### */
|
||||||
app.get('/help', function(req, res) {
|
/* ##### Wachalarm ##### */
|
||||||
res.render('help', {
|
/* ##################### */
|
||||||
title: 'Hilfe',
|
|
||||||
user: req.user
|
// /waip nach /waip/0 umleiten
|
||||||
|
app.get('/waip', function (req, res) {
|
||||||
|
sql.db_wache_get_all(function (data) {
|
||||||
|
res.render('overviews/overview_waip', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Alarmmonitor',
|
||||||
|
list_wachen: data,
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /uhr
|
// Alarmmonitor aufloesen /waip/<wachennummer>
|
||||||
app.get('/test_clock', function(req, res) {
|
app.get('/waip/:wachen_id', function (req, res, next) {
|
||||||
res.render('test_clock', {
|
var parmeter_id = req.params.wachen_id;
|
||||||
title: 'Test Uhr',
|
sql.db_wache_vorhanden(parmeter_id, function (wache) {
|
||||||
user: req.user
|
if (wache) {
|
||||||
|
res.render('waip', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Alarmmonitor',
|
||||||
|
wachen_id: parmeter_id,
|
||||||
|
data_wache: wache.name,
|
||||||
|
map_tile: app_cfg.public.map_tile,
|
||||||
|
map_attribution: app_cfg.public.map_attribution,
|
||||||
|
app_id: app_cfg.global.app_id,
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var err = new Error('Wache ' + parmeter_id + ' nicht vorhanden!');
|
||||||
|
err.status = 404;
|
||||||
|
next(err);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /test_tableau
|
/* ######################## */
|
||||||
app.get('/test_tableau', function(req, res) {
|
/* ###### Dashboard ####### */
|
||||||
res.render('test_wachalarm', {
|
/* ######################## */
|
||||||
title: 'Test Wachalarm',
|
|
||||||
user: req.user
|
// Dasboard-Uebersicht
|
||||||
|
app.get('/dbrd', function (req, res, next) {
|
||||||
|
// pruefen ob ein Paramater fuer die Einsatznummer angegeben wurde, dann Dashboard direkt oeffnen
|
||||||
|
if (req.query.enr_str) {
|
||||||
|
sql.db_einsatz_get_uuid_by_enr(req.query.enr_str, function (data) {
|
||||||
|
if (data) {
|
||||||
|
res.redirect('/dbrd/' + data);
|
||||||
|
} else {
|
||||||
|
var err = new Error('Dashboard oder Einsatz nicht (mehr) vorhanden!');
|
||||||
|
err.status = 404;
|
||||||
|
next(err);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sql.db_einsatz_get_active(function (data) {
|
||||||
|
res.render('overviews/overview_dbrd', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Dashboard',
|
||||||
|
map_tile: app_cfg.public.map_tile,
|
||||||
|
map_attribution: app_cfg.public.map_attribution,
|
||||||
|
user: req.user,
|
||||||
|
dataSet: data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dasboard fuer einen Einsatz
|
||||||
|
app.get('/dbrd/:dbrd_uuid', function (req, res, next) {
|
||||||
|
var dbrd_uuid = req.params.dbrd_uuid;
|
||||||
|
sql.db_einsatz_check_uuid(dbrd_uuid, function (wache) {
|
||||||
|
if (wache) {
|
||||||
|
res.render('dbrd', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Dashboard',
|
||||||
|
dbrd_uuid: dbrd_uuid,
|
||||||
|
map_tile: app_cfg.public.map_tile,
|
||||||
|
map_attribution: app_cfg.public.map_attribution,
|
||||||
|
app_id: app_cfg.global.app_id,
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var err = new Error('Dashboard oder Einsatz nicht (mehr) vorhanden!');
|
||||||
|
err.status = 404;
|
||||||
|
next(err);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /show_active_user
|
/* ######################## */
|
||||||
app.get('/show_active_user', auth.ensureAdmin, function(req, res) {
|
/* ##### Rueckmeldung ##### */
|
||||||
sql.db_get_active_clients(function(data) {
|
/* ######################## */
|
||||||
res.render('show_active_user', {
|
|
||||||
|
// Rueckmeldungs-Aufruf ohne waip_uuid eblehnen
|
||||||
|
app.get('/rmld', function (req, res, next) {
|
||||||
|
var err = new Error('Rückmeldungen sind nur mit gültiger Einsatz-ID erlaubt!');
|
||||||
|
err.status = 404;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rueckmeldungs-Aufruf mit waip_uuid aber ohne rmld_uuid an zufällige rmld_uuid weiterleiten
|
||||||
|
app.get('/rmld/:waip_uuid', function (req, res, next) {
|
||||||
|
res.redirect('/rmld/' + req.params.waip_uuid + '/' + uuidv4());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rueckmeldung anzeigen /rueckmeldung/waip_uuid/rmld_uuid
|
||||||
|
app.get('/rmld/:waip_uuid/:rmld_uuid', function (req, res, next) {
|
||||||
|
var waip_uuid = req.params.waip_uuid;
|
||||||
|
var rmld_uuid = req.params.rmld_uuid;
|
||||||
|
sql.db_einsatz_get_by_uuid(waip_uuid, function (einsatzdaten) {
|
||||||
|
if (einsatzdaten) {
|
||||||
|
sql.db_user_check_permission(req.user, einsatzdaten.id, function (valid) {
|
||||||
|
if (!valid) {
|
||||||
|
delete einsatzdaten.objekt;
|
||||||
|
delete einsatzdaten.besonderheiten;
|
||||||
|
delete einsatzdaten.strasse;
|
||||||
|
delete einsatzdaten.wgs84_x;
|
||||||
|
delete einsatzdaten.wgs84_y;
|
||||||
|
};
|
||||||
|
einsatzdaten.rmld_uuid = rmld_uuid;
|
||||||
|
res.render('rmld', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Einsatz-Rückmeldung',
|
||||||
|
user: req.user,
|
||||||
|
einsatzdaten: einsatzdaten,
|
||||||
|
map_tile: app_cfg.public.map_tile,
|
||||||
|
map_attribution: app_cfg.public.map_attribution,
|
||||||
|
error: req.flash("errorMessage"),
|
||||||
|
success: req.flash("successMessage")
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var err = new Error('Der angefragte Einsatz ist nicht - oder nicht mehr - vorhanden!');
|
||||||
|
err.status = 404;
|
||||||
|
next(err);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rueckmeldung entgegennehmen
|
||||||
|
app.post('/rmld/:waip_uuid/:rmld_uuid', function (req, res) {
|
||||||
|
// Remote-IP erkennen, fuer Fehler-Auswertung
|
||||||
|
var remote_ip = req.headers["x-real-ip"] || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||||
|
// auf Saver verweisen
|
||||||
|
saver.save_new_rmld(req.body, remote_ip, 'web', function (saved) {
|
||||||
|
var waip_uuid = req.body.waip_uuid;
|
||||||
|
var rmld_uuid = req.body.rmld_uuid;
|
||||||
|
if (saved) {
|
||||||
|
req.flash('successMessage', 'Rückmeldung erfolgreich gesendet, auf zum Einsatz!');
|
||||||
|
res.redirect('/rmld/' + waip_uuid + '/' + rmld_uuid);
|
||||||
|
} else {
|
||||||
|
req.flash('errorMessage', 'Fehler beim Senden der Rückmeldung!');
|
||||||
|
res.redirect('/rmld/' + waip_uuid + '/' + rmld_uuid);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ########################## */
|
||||||
|
/* ##### Administration ##### */
|
||||||
|
/* ########################## */
|
||||||
|
|
||||||
|
// verbundene Clients anzeigen
|
||||||
|
app.get('/adm_show_clients', auth.ensureAdmin, function (req, res) {
|
||||||
|
sql.db_client_get_connected(function (data) {
|
||||||
|
res.render('admin/adm_show_clients', {
|
||||||
|
public: app_cfg.public,
|
||||||
title: 'Verbundene PCs/Benutzer',
|
title: 'Verbundene PCs/Benutzer',
|
||||||
user: req.user,
|
user: req.user,
|
||||||
dataSet: data
|
dataSet: data
|
||||||
@ -99,10 +300,11 @@ module.exports = function(app, sql, app_cfg, passport, auth, udp) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /show_active_waip
|
// laufende Einsaetze anzeigen
|
||||||
app.get('/show_active_waip', auth.ensureAdmin, function(req, res) {
|
app.get('/adm_show_missions', auth.ensureAdmin, function (req, res) {
|
||||||
sql.db_get_active_waips(function(data) {
|
sql.db_einsatz_get_active(function (data) {
|
||||||
res.render('show_active_waip', {
|
res.render('admin/adm_show_missions', {
|
||||||
|
public: app_cfg.public,
|
||||||
title: 'Akutelle Einsätze',
|
title: 'Akutelle Einsätze',
|
||||||
user: req.user,
|
user: req.user,
|
||||||
dataSet: data
|
dataSet: data
|
||||||
@ -110,10 +312,11 @@ module.exports = function(app, sql, app_cfg, passport, auth, udp) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /show_log
|
// Logdatei
|
||||||
app.get('/show_log', auth.ensureAdmin, function(req, res) {
|
app.get('/adm_show_log', auth.ensureAdmin, function (req, res) {
|
||||||
sql.db_get_log(function(data) {
|
sql.db_log_get_5000(function (data) {
|
||||||
res.render('show_log', {
|
res.render('admin/adm_show_log', {
|
||||||
|
public: app_cfg.public,
|
||||||
title: 'Log-Datei',
|
title: 'Log-Datei',
|
||||||
user: req.user,
|
user: req.user,
|
||||||
dataSet: data
|
dataSet: data
|
||||||
@ -121,33 +324,35 @@ module.exports = function(app, sql, app_cfg, passport, auth, udp) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /test_alert
|
// direkten Alarm ausloesen
|
||||||
app.get('/test_alert', auth.ensureAdmin, function(req, res) {
|
app.get('/adm_run_alert', auth.ensureAdmin, function (req, res) {
|
||||||
res.render('test_alert', {
|
res.render('admin/adm_run_alert', {
|
||||||
|
public: app_cfg.public,
|
||||||
title: 'Test-Alarm',
|
title: 'Test-Alarm',
|
||||||
user: req.user,
|
user: req.user,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/test_alert', auth.ensureAdmin, function(req, res) {
|
app.post('/adm_run_alert', auth.ensureAdmin, function (req, res) {
|
||||||
udp.send_message(req.body.test_alert);
|
udp.send_message(req.body.test_alert);
|
||||||
res.redirect('/test_alert');
|
res.redirect('/adm_run_alert');
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /edit_users
|
// Benutzer editieren
|
||||||
app.get('/edit_users', auth.ensureAdmin, function(req, res) {
|
app.get('/adm_edit_users', auth.ensureAdmin, function (req, res) {
|
||||||
sql.db_get_users(function(data) {
|
sql.db_user_get_all(function (data) {
|
||||||
res.render('edit_users', {
|
res.render('admin/adm_edit_users', {
|
||||||
|
public: app_cfg.public,
|
||||||
title: 'Benutzer und Rechte verwalten',
|
title: 'Benutzer und Rechte verwalten',
|
||||||
user: req.user,
|
user: req.user,
|
||||||
users: data,
|
users: data,
|
||||||
error: req.flash("errorMessage"),
|
error: req.flash('errorMessage'),
|
||||||
success: req.flash("successMessage")
|
success: req.flash('successMessage')
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/edit_users', auth.ensureAdmin, function(req, res) {
|
app.post('/adm_edit_users', auth.ensureAdmin, function (req, res) {
|
||||||
if (req.user && req.user.permissions == "admin") {
|
if (req.user && req.user.permissions == "admin") {
|
||||||
switch (req.body["modal_method"]) {
|
switch (req.body["modal_method"]) {
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
@ -161,59 +366,72 @@ module.exports = function(app, sql, app_cfg, passport, auth, udp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.redirect('/edit_users');
|
res.redirect('/adm_edit_users');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// get /login
|
/* ###################### */
|
||||||
app.get('/login', function(req, res) {
|
/* ##### Testseiten ##### */
|
||||||
res.render('login', {
|
/* ###################### */
|
||||||
title: 'Login',
|
|
||||||
|
// Wachalarm-Uhr testen
|
||||||
|
app.get('/test_clock', function (req, res) {
|
||||||
|
res.render('tests/test_clock', {
|
||||||
|
public: app_cfg.public,
|
||||||
|
title: 'Test Uhr',
|
||||||
user: req.user
|
user: req.user
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/login', passport.authenticate('local', {
|
// Alarmmonitor testen
|
||||||
failureRedirect: '/login'
|
app.get('/test_wachalarm', function (req, res) {
|
||||||
}), function(req, res) {
|
res.render('tests/test_wachalarm', {
|
||||||
if(req.body.rememberme){
|
public: app_cfg.public,
|
||||||
// der Benutzer muss sich fuer 5 Jahre nicht anmelden
|
title: 'Test Wachalarm',
|
||||||
req.session.cookie.maxAge = 5 * 365 * 24 * 60 * 60 * 1000;
|
user: req.user
|
||||||
};
|
});
|
||||||
res.redirect('/');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/login_ip', passport.authenticate('ip', {
|
// Rueckmeldung testen
|
||||||
failureRedirect: '/login'
|
app.get('/test_rueckmeldung', function (req, res) {
|
||||||
}), function(req, res) {
|
res.render('tests/test_rueckmeldung', {
|
||||||
// der Benutzer muss sich fuer 5 Jahre nicht anmelden
|
public: app_cfg.public,
|
||||||
req.session.cookie.maxAge = 5 * 365 * 24 * 60 * 60 * 1000;
|
title: 'Test Einsatz-Rückmeldung',
|
||||||
res.redirect('/');
|
user: req.user
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/logout', function(req, res) {
|
// Dashboard testen
|
||||||
req.session.destroy(function(err) {
|
app.get('/test_dashboard', function (req, res) {
|
||||||
res.redirect('/');
|
res.render('tests/test_dashboard', {
|
||||||
})
|
public: app_cfg.public,
|
||||||
|
title: 'Test Dashboard',
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// catch 404 and forward to error handler
|
/* ######################## */
|
||||||
app.use(function(req, res, next) {
|
/* ##### Fehlerseiten ##### */
|
||||||
|
/* ######################## */
|
||||||
|
|
||||||
|
// 404 abfangen und an error handler weiterleiten
|
||||||
|
app.use(function (req, res, next) {
|
||||||
var err = new Error('Seite nicht gefunden!');
|
var err = new Error('Seite nicht gefunden!');
|
||||||
err.status = 404;
|
err.status = 404;
|
||||||
next(err);
|
next(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
// error handler
|
// error handler
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function (err, req, res, next) {
|
||||||
// set locals, only providing error in development
|
// set locals, only providing error in development
|
||||||
res.locals.message = err.message;
|
res.locals.message = err.message;
|
||||||
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
res.locals.error = app_cfg.global.development ? err : {};
|
||||||
// render the error page
|
// render the error page
|
||||||
res.status(err.status || 500);
|
res.status(err.status || 500);
|
||||||
res.render('error', {
|
res.render('error', {
|
||||||
|
public: app_cfg.public,
|
||||||
user: req.user
|
user: req.user
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
237
server/saver.js
Executable file
237
server/saver.js
Executable file
@ -0,0 +1,237 @@
|
|||||||
|
module.exports = function (app_cfg, sql, waip, uuidv4, io, remote_api) {
|
||||||
|
|
||||||
|
// Module laden
|
||||||
|
const turf = require('@turf/turf');
|
||||||
|
|
||||||
|
// Variablen festlegen
|
||||||
|
var uuid_pattern = new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$', 'i');
|
||||||
|
|
||||||
|
// Speichern eines neuen Einsatzes
|
||||||
|
function save_new_waip(waip_data, remote_addr, app_id) {
|
||||||
|
// ist JSON valide
|
||||||
|
validate_waip(waip_data, function (waip_json) {
|
||||||
|
if (waip_json) {
|
||||||
|
// Polygon erzeugen und zuweisen falls nicht vorhanden
|
||||||
|
if (!waip_json.ortsdaten.wgs84_area) {
|
||||||
|
var wgs_x = parseFloat(waip_json.ortsdaten.wgs84_x);
|
||||||
|
var wgs_y = parseFloat(waip_json.ortsdaten.wgs84_y);
|
||||||
|
var point = turf.point([wgs_y, wgs_x]);
|
||||||
|
var buffered = turf.buffer(point, 1, {
|
||||||
|
steps: app_cfg.global.circumcircle,
|
||||||
|
units: 'kilometers'
|
||||||
|
});
|
||||||
|
var bbox = turf.bbox(buffered);
|
||||||
|
var new_point = turf.randomPoint(1, {
|
||||||
|
bbox: bbox
|
||||||
|
});
|
||||||
|
var new_buffer = turf.buffer(new_point, 1, {
|
||||||
|
steps: app_cfg.global.circumcircle,
|
||||||
|
units: 'kilometers'
|
||||||
|
})
|
||||||
|
waip_json.ortsdaten.wgs84_area = new_buffer;
|
||||||
|
};
|
||||||
|
// pruefen, ob vielleicht schon ein Einsatz mit einer UUID gespeichert ist
|
||||||
|
sql.db_einsatz_get_uuid_by_enr(waip_json.einsatzdaten.nummer, function (waip_uuid) {
|
||||||
|
if (waip_uuid) {
|
||||||
|
// wenn ein Einsatz mit UUID schon vorhanden ist, dann diese setzten / ueberschreiben
|
||||||
|
waip_json.einsatzdaten.uuid = waip_uuid;
|
||||||
|
} else {
|
||||||
|
// uuid erzeugen und zuweisen falls nicht bereits in JSON vorhanden, oder falls keine korrekte uuid
|
||||||
|
if (!waip_json.einsatzdaten.uuid || !uuid_pattern.test(waip_json.einsatzdaten.uuid)) {
|
||||||
|
waip_json.einsatzdaten.uuid = uuidv4();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// nicht erwuenschte Daten ggf. enfernen (Datenschutzoption)
|
||||||
|
filter_api_data(waip_json, remote_addr, function (data_filtered) {
|
||||||
|
// Einsatz in DB Speichern
|
||||||
|
waip.waip_speichern(data_filtered);
|
||||||
|
sql.db_log('WAIP', 'Neuer Einsatz von ' + remote_addr + ' wird jetzt verarbeitet: ' + JSON.stringify(data_filtered));
|
||||||
|
});
|
||||||
|
// Einsatzdaten per API weiterleiten (entweder zum Server oder zum verbunden Client)
|
||||||
|
api_server_to_client_new_waip(waip_json, app_id);
|
||||||
|
api_client_to_server_new_waip(waip_json, app_id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sql.db_log('WAIP', 'Fehler: Einsatz von ' + remote_addr + ' nicht valide: ' + JSON.stringify(waip_data));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function save_new_rmld(data, remote_addr, app_id, callback) {
|
||||||
|
validate_rmld(data, function (valid) {
|
||||||
|
if (valid) {
|
||||||
|
// Rueckmeldung speichern und verteilen
|
||||||
|
sql.db_rmld_save(data, function (result) {
|
||||||
|
if (result) {
|
||||||
|
sql.db_log('RMLD', 'Rückmeldung von ' + remote_addr + ' erhalten und gespeichert: ' + JSON.stringify(data));
|
||||||
|
waip.rmld_verteilen_by_uuid(data.waip_uuid, data.rmld_uuid);
|
||||||
|
callback && callback(true);
|
||||||
|
} else {
|
||||||
|
sql.db_log('RMLD', 'Fehler beim speichern der Rückmeldung von ' + remote_addr + ': ' + JSON.stringify(data));
|
||||||
|
callback && callback(false);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// RMLD-Daten per API weiterleiten (entweder zum Server oder zum verbunden Client)
|
||||||
|
api_server_to_client_new_rmld(data, app_id);
|
||||||
|
api_client_to_server_new_rmld(data, app_id);
|
||||||
|
} else {
|
||||||
|
sql.db_log('RMLD', 'Fehler: Rückmeldung von ' + remote_addr + ' nicht valide: ' + JSON.stringify(waip_data));
|
||||||
|
callback && callback(false);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function validate_waip(data, callback) {
|
||||||
|
// TODO Validierung: Einsatzdaten auf Validität prüfen
|
||||||
|
|
||||||
|
// Typ ist NULL
|
||||||
|
if (data === null) {
|
||||||
|
callback && callback(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Typ ist undefined
|
||||||
|
if (data === undefined) {
|
||||||
|
callback && callback(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Typ ist String
|
||||||
|
if (data.constructor == String) {
|
||||||
|
// String versuchen in JSON umzuwandeln
|
||||||
|
try {
|
||||||
|
var tmp = JSON.parse(data);
|
||||||
|
callback && callback(tmp);
|
||||||
|
} catch (error) {
|
||||||
|
callback && callback(false);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// Typ ist Object
|
||||||
|
if (data.constructor === Object) {
|
||||||
|
// teste ob der String des Objects JSON-Konform ist
|
||||||
|
var text = JSON.stringify(data);
|
||||||
|
if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||||
|
//falls ja, dann versuche String in JSON zu parsen
|
||||||
|
try {
|
||||||
|
var tmp = JSON.parse(text);
|
||||||
|
callback && callback(tmp);
|
||||||
|
} catch (error) {
|
||||||
|
callback && callback(false);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
callback && callback(false);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Log
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
console.log('Validierung WAIP: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function validate_rmld(data, callback) {
|
||||||
|
// TODO Validierung: Rueckmeldung auf plausibilität
|
||||||
|
|
||||||
|
// Log
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
console.log('Validierung RMLD: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
|
||||||
|
callback && callback(true);
|
||||||
|
// SQL-Log
|
||||||
|
};
|
||||||
|
|
||||||
|
function api_server_to_client_new_waip(data, app_id) {
|
||||||
|
// Rückmeldung an verbundenen Client senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.api.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
io.of('/api').emit('from_server_to_client_new_waip', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Einsatz an Clients gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function api_server_to_client_new_rmld(data, app_id) {
|
||||||
|
// Rückmeldung an verbundenen Client senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.api.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
io.of('/api').emit('from_server_to_client_new_rmld', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Rückmeldung an Clients gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function api_client_to_server_new_waip(data, app_id) {
|
||||||
|
// Alarm an Remote-Server senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.endpoint.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
remote_api.emit('from_client_to_server_new_waip', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Neuen Wachalarm an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function api_client_to_server_new_rmld(data, app_id) {
|
||||||
|
// Rückmeldung an Remote-Server senden, falls funktion aktiviert
|
||||||
|
if (app_cfg.endpoint.enabled) {
|
||||||
|
// testen ob app_id auch eine uuid ist, falls nicht, eigene app_uuid setzen
|
||||||
|
if (!uuid_pattern.test(app_id)) {
|
||||||
|
app_id = app_cfg.global.app_id;
|
||||||
|
};
|
||||||
|
remote_api.emit('from_client_to_server_new_rmld', {
|
||||||
|
data: data,
|
||||||
|
app_id: app_id
|
||||||
|
});
|
||||||
|
sql.db_log('API', 'Rückmeldung an ' + app_cfg.endpoint.host + ' gesendet: ' + JSON.stringify(data));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function filter_api_data(data, remote_ip, callback) {
|
||||||
|
// unnoetige Zeichen aus socket_id entfernen, um diese als Dateinamen zu verwenden
|
||||||
|
if (app_cfg.filter.enabled) {
|
||||||
|
// Filter nur anwenden wenn Einsatzdaten von bestimmten IP-Adressen kommen
|
||||||
|
if (app_cfg.filter.on_message_from.includes(remote_ip)) {
|
||||||
|
var data_filtered = data;
|
||||||
|
// Schleife definieren
|
||||||
|
function loop_done(data_filtered) {
|
||||||
|
callback && callback(data_filtered);
|
||||||
|
};
|
||||||
|
var itemsProcessed = 0;
|
||||||
|
// nicht gewollte Daten entfernen
|
||||||
|
app_cfg.filter.remove_data.forEach(function (item, index, array) {
|
||||||
|
data_filtered.einsatzdaten[item] = '';
|
||||||
|
data_filtered.ortsdaten[item] = '';
|
||||||
|
// Schleife erhoehen
|
||||||
|
itemsProcessed++;
|
||||||
|
if (itemsProcessed === array.length) {
|
||||||
|
// Schleife beenden
|
||||||
|
loop_done(data_filtered);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback && callback(data);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
callback && callback(data);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
save_new_waip: save_new_waip,
|
||||||
|
save_new_rmld: save_new_rmld
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
90
server/socket.js
Executable file
90
server/socket.js
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
module.exports = function (io, sql, app_cfg, waip) {
|
||||||
|
|
||||||
|
// Socket.IO Alarmmonitor
|
||||||
|
|
||||||
|
var nsp_waip = io.of('/waip');
|
||||||
|
|
||||||
|
nsp_waip.on('connection', function (socket) {
|
||||||
|
// versuche Client-IP zu ermitteln
|
||||||
|
var client_ip = socket.handshake.headers["x-real-ip"] || socket.handshake.headers['x-forwarded-for'] || socket.request.connection.remoteAddress;
|
||||||
|
//zuerst Server-Version senden, damit der Client diese prueft und die Seite ggf. neu laedt
|
||||||
|
socket.emit('io.version', app_cfg.global.app_id);
|
||||||
|
// Aufruf des Alarmmonitors einer bestimmten Wache verarbeiten
|
||||||
|
socket.on('WAIP', function (wachen_id) {
|
||||||
|
sql.db_log('DEBUG', 'Alarmmonitor Nr. ' + wachen_id + ' von ' + client_ip + ' (' + socket.id + ') aufgerufen.');
|
||||||
|
// prüfen ob Wachenummer in der Datenbank hinterlegt ist
|
||||||
|
sql.db_wache_vorhanden(wachen_id, function (result) {
|
||||||
|
// wenn die Wachennummer vorhanden/plausibel dann weiter
|
||||||
|
if (result) {
|
||||||
|
// Socket-Room beitreiten
|
||||||
|
socket.join(wachen_id, function () {
|
||||||
|
// prüfen ob für diese Wache Einsätze vorhanden sind
|
||||||
|
sql.db_einsatz_ermitteln(wachen_id, socket, function (result_einsatz) {
|
||||||
|
if (result_einsatz) {
|
||||||
|
// nur den ersten Einsatz senden, falls mehrere vorhanden sind
|
||||||
|
var waip_id = result_einsatz[0].waip_einsaetze_ID;
|
||||||
|
sql.db_log('WAIP', 'Einsatz ' + waip_id + ' für Wache ' + wachen_id + ' vorhanden, wird jetzt an Client ' + socket.id + ' gesendet.');
|
||||||
|
//letzten Einsatz verteilen
|
||||||
|
waip.waip_verteilen(waip_id, socket, wachen_id);
|
||||||
|
//vorhandene Rückmeldungen verteilen
|
||||||
|
waip.rmld_verteilen_for_one_client(waip_id, socket, wachen_id);
|
||||||
|
} else {
|
||||||
|
sql.db_log('WAIP', 'Kein Einsatz für Wache ' + wachen_id + ' vorhanden, gehe in Standby');
|
||||||
|
// falls kein Einsatz vorhanden ist, dann Standby senden
|
||||||
|
socket.emit('io.standby', null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// in Statusüberischt speichern
|
||||||
|
sql.db_client_update_status(socket, null);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sql.db_log('ERROR', 'Fehler: Wachnnummer ' + wachen_id + 'nicht vorhanden!');
|
||||||
|
socket.emit('io.error', 'Fehler: Wachnnummer \'' + wachen_id + '\' nicht vorhanden!');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Disconnect
|
||||||
|
socket.on('disconnect', function () {
|
||||||
|
sql.db_log('DEBUG', 'Alarmmonitor von ' + client_ip + ' (' + socket.id + ') geschlossen.');
|
||||||
|
sql.db_client_delete(socket);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Socket.IO Dashboard
|
||||||
|
|
||||||
|
var nsp_dbrd = io.of('/dbrd');
|
||||||
|
|
||||||
|
nsp_dbrd.on('connection', function (socket) {
|
||||||
|
// versuche Client-IP zu ermitteln
|
||||||
|
var client_ip = socket.handshake.headers["x-real-ip"] || socket.handshake.headers['x-forwarded-for'] || socket.request.connection.remoteAddress;
|
||||||
|
//zuerst Server-Version senden, damit der Client diese prueft und die Seite ggf. neu laedt
|
||||||
|
socket.emit('io.version', app_cfg.global.app_id);
|
||||||
|
// Aufruf des Dashboards eines bestimmten Einsatzes verarbeiten
|
||||||
|
socket.on('dbrd', function (uuid) {
|
||||||
|
sql.db_log('DEBUG', 'Dashboard ' + uuid + ' von ' + client_ip + ' (' + socket.id + ') aufgerufen.');
|
||||||
|
// prüfen ob Dashboard/Einsatz vorhanden
|
||||||
|
sql.db_einsatz_check_uuid(uuid, function (dbrd_uuid) {
|
||||||
|
// wenn die Wachennummer vorhanden dann weiter
|
||||||
|
if (dbrd_uuid) {
|
||||||
|
// Socket-Room beitreiten
|
||||||
|
socket.join(dbrd_uuid.uuid, function () {
|
||||||
|
sql.db_log('DBRD', 'Einsatz ' + dbrd_uuid.uuid + ' für Dashboard ' + dbrd_uuid.uuid + ' vorhanden, wird jetzt an Client ' + socket.id + ' gesendet.');
|
||||||
|
//letzten Einsatz verteilen
|
||||||
|
waip.dbrd_verteilen(dbrd_uuid.uuid, socket);
|
||||||
|
// in Statusüberischt speichern
|
||||||
|
sql.db_client_update_status(socket, dbrd_uuid.uuid);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sql.db_log('ERROR', 'Fehler: Dashboard ' + uuid + 'nicht (mehr) vorhanden!');
|
||||||
|
socket.emit('io.error', 'Fehler: Dashboard \'' + uuid + '\' nicht (mehr) vorhanden!');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Disconnect
|
||||||
|
socket.on('disconnect', function (uuid) {
|
||||||
|
sql.db_log('DEBUG', 'Dashboard ' + uuid + ' von ' + client_ip + ' (' + socket.id + ') geschlossen.');
|
||||||
|
sql.db_client_delete(socket);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
@ -1,13 +1,11 @@
|
|||||||
module.exports = function (fs, bcrypt, app_cfg) {
|
module.exports = function (fs, bcrypt, app_cfg) {
|
||||||
|
|
||||||
// TODO: gegen better-sqlite3 ersetzen
|
|
||||||
|
|
||||||
// Datenbank einrichten
|
// Datenbank einrichten
|
||||||
const sqlite3 = require('sqlite3').verbose();
|
const sqlite3 = require('sqlite3').verbose();
|
||||||
var dbFile = app_cfg.global.database;
|
var dbFile = app_cfg.global.database;
|
||||||
var dbExists = fs.existsSync(dbFile);
|
var dbExists = fs.existsSync(dbFile);
|
||||||
|
|
||||||
// Datenbank erstellen
|
// Datenbank erstellen, falls nicht vorhanden
|
||||||
var db = new sqlite3.Database(dbFile, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
|
var db = new sqlite3.Database(dbFile, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
@ -28,8 +26,9 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
db.serialize(function () {
|
db.serialize(function () {
|
||||||
// Einsatz-Tabelle erstellen
|
// Einsatz-Tabelle erstellen
|
||||||
db.run(`CREATE TABLE waip_einsaetze (
|
db.run(`CREATE TABLE waip_einsaetze (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
zeitstempel DATETIME DEFAULT CURRENT_TIMESTAMP,
|
uuid TEXT,
|
||||||
|
zeitstempel DATETIME DEFAULT (DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME')),
|
||||||
einsatznummer TEXT,
|
einsatznummer TEXT,
|
||||||
alarmzeit TEXT,
|
alarmzeit TEXT,
|
||||||
einsatzart TEXT,
|
einsatzart TEXT,
|
||||||
@ -43,10 +42,12 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
objektnr TEXT,
|
objektnr TEXT,
|
||||||
objektart TEXT,
|
objektart TEXT,
|
||||||
wachenfolge INTEGER,
|
wachenfolge INTEGER,
|
||||||
|
sonstiger_ort TEXT,
|
||||||
wgs84_x TEXT,
|
wgs84_x TEXT,
|
||||||
wgs84_y TEXT)`);
|
wgs84_y TEXT,
|
||||||
|
wgs84_area TEXT,
|
||||||
|
UNIQUE (id, uuid))`);
|
||||||
// Einsatzmittel-Tabelle erstellen
|
// Einsatzmittel-Tabelle erstellen
|
||||||
// TODO: Erweitern um Status, Staerke, AGT
|
|
||||||
db.run(`CREATE TABLE waip_einsatzmittel (
|
db.run(`CREATE TABLE waip_einsatzmittel (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
waip_einsaetze_ID INTEGER NOT NULL,
|
waip_einsaetze_ID INTEGER NOT NULL,
|
||||||
@ -70,10 +71,18 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
name_kreis TEXT,
|
name_kreis TEXT,
|
||||||
wgs84_x TEXT,
|
wgs84_x TEXT,
|
||||||
wgs84_y TEXT)`);
|
wgs84_y TEXT)`);
|
||||||
|
// History-Tabelle erstellen
|
||||||
|
db.run(`CREATE TABLE waip_history (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
waip_uuid TEXT,
|
||||||
|
socket_id TEXT,
|
||||||
|
uuid_einsatz_grunddaten TEXT,
|
||||||
|
uuid_em_alarmiert TEXT,
|
||||||
|
uuid_em_weitere TEXT)`);
|
||||||
// Client-Tabelle erstellen
|
// Client-Tabelle erstellen
|
||||||
db.run(`CREATE TABLE waip_clients (
|
db.run(`CREATE TABLE waip_clients (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
connect_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
connect_time DATETIME DEFAULT (DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME')),
|
||||||
socket_id TEXT,
|
socket_id TEXT,
|
||||||
client_ip TEXT,
|
client_ip TEXT,
|
||||||
room_name TEXT,
|
room_name TEXT,
|
||||||
@ -85,11 +94,18 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
// Rueckmelde-Tabelle erstellen
|
// Rueckmelde-Tabelle erstellen
|
||||||
db.run(`CREATE TABLE waip_response (
|
db.run(`CREATE TABLE waip_response (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
waip_einsaetze_id INTEGER NOT NULL,
|
waip_uuid TEXT,
|
||||||
einsatzkraft TEXT,
|
rmld_uuid TEXT,
|
||||||
maschinist TEXT,
|
alias TEXT,
|
||||||
fuehrungskraft TEXT,
|
einsatzkraft INTEGER,
|
||||||
atemschutz TEXT)`);
|
maschinist INTEGER,
|
||||||
|
fuehrungskraft INTEGER,
|
||||||
|
agt INTEGER,
|
||||||
|
set_time DATETIME,
|
||||||
|
arrival_time DATETIME,
|
||||||
|
wache_id INTEGER,
|
||||||
|
wache_nr INTEGER,
|
||||||
|
wache_name TEXT)`);
|
||||||
// Benutzer-Tabelle erstellen
|
// Benutzer-Tabelle erstellen
|
||||||
db.run(`CREATE TABLE waip_users (
|
db.run(`CREATE TABLE waip_users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -98,18 +114,46 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
permissions TEXT,
|
permissions TEXT,
|
||||||
ip_address TEXT)`);
|
ip_address TEXT)`);
|
||||||
// Einstellungs-Tabelle für Benutzer erstellen
|
// Einstellungs-Tabelle für Benutzer erstellen
|
||||||
db.run(`CREATE TABLE waip_configs (
|
db.run(`CREATE TABLE waip_user_config (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
user_id INTEGER,
|
user_id INTEGER,
|
||||||
reset_counter INTEGER)`);
|
reset_counter INTEGER,
|
||||||
|
display_options TEXT,
|
||||||
|
sound_options TEXT,
|
||||||
|
FOREIGN KEY(user_id) REFERENCES waip_users(id))`);
|
||||||
// Ersetzungs-Tabelle fuer Einsatzmittelnamen erstellen
|
// Ersetzungs-Tabelle fuer Einsatzmittelnamen erstellen
|
||||||
db.run(`CREATE TABLE waip_ttsreplace (
|
db.run(`CREATE TABLE waip_ttsreplace (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
einsatzmittel_typ TEXT,
|
einsatzmittel_typ TEXT,
|
||||||
einsatzmittel_rufname TEXT)`);
|
einsatzmittel_rufname TEXT)`);
|
||||||
|
// Vermittlungs-Tabelle erstellen
|
||||||
|
db.run(`CREATE TABLE waip_vmtl (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
waip_wachenname TEXT,
|
||||||
|
vmtl_typ TEXT,
|
||||||
|
vmtl_account_name TEXT,
|
||||||
|
vmtl_account_group TEXT,
|
||||||
|
vmtl_history TEXT)`);
|
||||||
|
// Twitter-Account-Tabelle erstellen
|
||||||
|
db.run(`CREATE TABLE waip_tw_accounts (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
tw_screen_name TEXT,
|
||||||
|
tw_consumer_key TEXT,
|
||||||
|
tw_consumer_secret TEXT,
|
||||||
|
tw_access_token_key TEXT,
|
||||||
|
tw_access_token_secret TEXT)`);
|
||||||
|
// Export-Tabelle erstellen
|
||||||
|
db.run(`CREATE TABLE waip_export (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
export_typ TEXT,
|
||||||
|
export_name TEXT,
|
||||||
|
export_text TEXT,
|
||||||
|
export_filter TEXT,
|
||||||
|
export_recipient TEXT)`);
|
||||||
|
// Log erstellen
|
||||||
db.run(`CREATE TABLE waip_log (
|
db.run(`CREATE TABLE waip_log (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
log_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
log_time DATETIME DEFAULT (DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME')),
|
||||||
log_typ TEXT,
|
log_typ TEXT,
|
||||||
log_text TEXT)`);
|
log_text TEXT)`);
|
||||||
// Default-Wachen speichern
|
// Default-Wachen speichern
|
||||||
@ -117,24 +161,26 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
nr_wache, nr_traeger, nr_kreis, name_wache, name_traeger, name_kreis, wgs84_x, wgs84_y)
|
nr_wache, nr_traeger, nr_kreis, name_wache, name_traeger, name_kreis, wgs84_x, wgs84_y)
|
||||||
VALUES
|
VALUES
|
||||||
(0,\'0\',0,\'Global - Alle Einsätze\',\'Global\',\'Global\',\'0\',\'0\'),
|
(0,\'0\',0,\'Global - Alle Einsätze\',\'Global\',\'Global\',\'0\',\'0\'),
|
||||||
(520101,\'01\',52,\'CB FW Cottbus 1\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7329037496\',\'14.3377829699\'),
|
(520101,\'01\',52,\'CB FW Cottbus 1\',\'Stadt Cottbus - Berufsfeuerwehr\',\'Stadt Cottbus\',\'51.7329037496\',\'14.3377829699\'),
|
||||||
(520201,\'02\',52,\'CB FW Cottbus 2\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7654389234\',\'14.3352138763\'),
|
(520201,\'02\',52,\'CB FW Cottbus 2\',\'Stadt Cottbus - Berufsfeuerwehr\',\'Stadt Cottbus\',\'51.7654389234\',\'14.3352138763\'),
|
||||||
(521101,\'11\',52,\'CB FW Branitz\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7363607074\',\'14.3673504518\'),
|
(520301,\'03\',52,\'CB FW Cottbus 3\',\'Stadt Cottbus - Berufsfeuerwehr\',\'Stadt Cottbus\',\'51.743946\',\'14.320619\'),
|
||||||
(521102,\'11\',52,\'CB FW Dissenchen\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7628368787\',\'14.3925021325\'),
|
(521101,\'11\',52,\'CB FW Branitz\',\'Stadt Cottbus - Löschbezirk 1\',\'Stadt Cottbus\',\'51.7363607074\',\'14.3673504518\'),
|
||||||
(521103,\'11\',52,\'CB FW Kahren\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7226384039\',\'14.409874149\'),
|
(521102,\'11\',52,\'CB FW Dissenchen\',\'Stadt Cottbus - Löschbezirk 1\',\'Stadt Cottbus\',\'51.7628368787\',\'14.3925021325\'),
|
||||||
(521104,\'11\',52,\'CB FW Kiekebusch\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7241108468\',\'14.3624851518\'),
|
(521103,\'11\',52,\'CB FW Kahren\',\'Stadt Cottbus - Löschbezirk 1\',\'Stadt Cottbus\',\'51.7226384039\',\'14.409874149\'),
|
||||||
(521201,\'12\',52,\'CB FW Merzdorf\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7791567132\',\'14.3860451556\'),
|
(521104,\'11\',52,\'CB FW Kiekebusch\',\'Stadt Cottbus - Löschbezirk 1\',\'Stadt Cottbus\',\'51.7241108468\',\'14.3624851518\'),
|
||||||
(521202,\'12\',52,\'CB FW Sandow\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7656727968\',\'14.3352466545\'),
|
(521201,\'12\',52,\'CB FW Merzdorf\',\'Stadt Cottbus - Löschbezirk 2\',\'Stadt Cottbus\',\'51.7791567132\',\'14.3860451556\'),
|
||||||
(521203,\'12\',52,\'CB FW Saspow\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7887535908\',\'14.356240843\'),
|
(521202,\'12\',52,\'CB FW Sandow\',\'Stadt Cottbus - Löschbezirk 2\',\'Stadt Cottbus\',\'51.7656727968\',\'14.3352466545\'),
|
||||||
(521204,\'12\',52,\'CB FW Willmersdorf\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.8057039156\',\'14.3803709656\'),
|
(521203,\'12\',52,\'CB FW Saspow\',\'Stadt Cottbus - Löschbezirk 2\',\'Stadt Cottbus\',\'51.7887535908\',\'14.356240843\'),
|
||||||
(521301,\'13\',52,\'CB FW Döbbrick\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.8173690763\',\'14.3421287282\'),
|
(521204,\'12\',52,\'CB FW Willmersdorf\',\'Stadt Cottbus - Löschbezirk 2\',\'Stadt Cottbus\',\'51.8057039156\',\'14.3803709656\'),
|
||||||
(521302,\'13\',52,\'CB FW Schmellwitz\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.784034245\',\'14.3351144771\'),
|
(521301,\'13\',52,\'CB FW Döbbrick\',\'Stadt Cottbus - Löschbezirk 3\',\'Stadt Cottbus\',\'51.8173690763\',\'14.3421287282\'),
|
||||||
(521303,\'13\',52,\'CB FW Sielow\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7994083121\',\'14.3041128045\'),
|
(521302,\'13\',52,\'CB FW Schmellwitz\',\'Stadt Cottbus - Löschbezirk 3\',\'Stadt Cottbus\',\'51.784034245\',\'14.3351144771\'),
|
||||||
(521304,\'13\',52,\'CB FW Ströbitz\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.754401066\',\'14.3010033167\'),
|
(521303,\'13\',52,\'CB FW Sielow\',\'Stadt Cottbus - Löschbezirk 3\',\'Stadt Cottbus\',\'51.7994083121\',\'14.3041128045\'),
|
||||||
(521401,\'14\',52,\'CB FW Gallinchen\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.710035337\',\'14.3533658895\'),
|
(521304,\'13\',52,\'CB FW Ströbitz\',\'Stadt Cottbus - Löschbezirk 3\',\'Stadt Cottbus\',\'51.754401066\',\'14.3010033167\'),
|
||||||
(521402,\'14\',52,\'CB FW Groß Gaglow\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7125349362\',\'14.3200961957\'),
|
(521401,\'14\',52,\'CB FW Gallinchen\',\'Stadt Cottbus - Löschbezirk 4\',\'Stadt Cottbus\',\'51.710035337\',\'14.3533658895\'),
|
||||||
(521403,\'14\',52,\'CB FW Madlow\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7204777791\',\'14.3457788456\'),
|
(521402,\'14\',52,\'CB FW Groß Gaglow\',\'Stadt Cottbus - Löschbezirk 4\',\'Stadt Cottbus\',\'51.7125349362\',\'14.3200961957\'),
|
||||||
(521404,\'14\',52,\'CB FW Sachsendorf\',\'Stadt Cottbus\',\'Stadt Cottbus\',\'51.7328922537\',\'14.3192552006\'),
|
(521403,\'14\',52,\'CB FW Madlow\',\'Stadt Cottbus - Löschbezirk 4\',\'Stadt Cottbus\',\'51.7204777791\',\'14.3457788456\'),
|
||||||
|
(521404,\'14\',52,\'CB FW Sachsendorf\',\'Stadt Cottbus - Löschbezirk 4\',\'Stadt Cottbus\',\'51.7328922537\',\'14.3192552006\'),
|
||||||
|
(521501,\'15\',52,\'CB FW Gerätehaus Süd\',\'Stadt Cottbus - Gerätehäuser\',\'Stadt Cottbus\',\'51.718385\',\'14.337278\'),
|
||||||
(610101,\'01\',61,\'LDS FW Lübben\',\'Stadt Lübben\',\'Landkreis Dahme-Spreewald\',\'51.9430718379\',\'13.8955064944\'),
|
(610101,\'01\',61,\'LDS FW Lübben\',\'Stadt Lübben\',\'Landkreis Dahme-Spreewald\',\'51.9430718379\',\'13.8955064944\'),
|
||||||
(610102,\'01\',61,\'LDS FW Lubolz\',\'Stadt Lübben\',\'Landkreis Dahme-Spreewald\',\'51.9631954482\',\'13.8277078818\'),
|
(610102,\'01\',61,\'LDS FW Lubolz\',\'Stadt Lübben\',\'Landkreis Dahme-Spreewald\',\'51.9631954482\',\'13.8277078818\'),
|
||||||
(610104,\'01\',61,\'LDS FW Neuendorf (Lübben)\',\'Stadt Lübben\',\'Landkreis Dahme-Spreewald\',\'51.9080633268\',\'13.8557762577\'),
|
(610104,\'01\',61,\'LDS FW Neuendorf (Lübben)\',\'Stadt Lübben\',\'Landkreis Dahme-Spreewald\',\'51.9080633268\',\'13.8557762577\'),
|
||||||
@ -311,6 +357,7 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
(619002,\'90\',61,\'LDS RW Bestensee\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.2393402333\',\'13.6651219943\'),
|
(619002,\'90\',61,\'LDS RW Bestensee\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.2393402333\',\'13.6651219943\'),
|
||||||
(619004,\'90\',61,\'LDS RW Königs Wusterhausen\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.3038264488\',\'13.6298907439\'),
|
(619004,\'90\',61,\'LDS RW Königs Wusterhausen\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.3038264488\',\'13.6298907439\'),
|
||||||
(619005,\'90\',61,\'LDS RW Schulzendorf\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.3595783918\',\'13.6008186158\'),
|
(619005,\'90\',61,\'LDS RW Schulzendorf\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.3595783918\',\'13.6008186158\'),
|
||||||
|
(619008,\'90\',61,\'LDS RW Bindow\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.283327\',\'13.743823\'),
|
||||||
(619009,\'90\',61,\'LDS RW Golßen\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'51.9799257518\',\'13.5771941984\'),
|
(619009,\'90\',61,\'LDS RW Golßen\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'51.9799257518\',\'13.5771941984\'),
|
||||||
(619012,\'90\',61,\'LDS RW Luckau\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'51.8504295155\',\'13.7130790573\'),
|
(619012,\'90\',61,\'LDS RW Luckau\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'51.8504295155\',\'13.7130790573\'),
|
||||||
(619015,\'90\',61,\'LDS RW Goyatz\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.014304731\',\'14.1786723155\'),
|
(619015,\'90\',61,\'LDS RW Goyatz\',\'Rettungswachen Dahme-Spreewald\',\'Landkreis Dahme-Spreewald\',\'52.014304731\',\'14.1786723155\'),
|
||||||
@ -778,10 +825,11 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
db.run(`INSERT OR REPLACE INTO waip_ttsreplace (
|
db.run(`INSERT OR REPLACE INTO waip_ttsreplace (
|
||||||
einsatzmittel_typ, einsatzmittel_rufname)
|
einsatzmittel_typ, einsatzmittel_rufname)
|
||||||
VALUES
|
VALUES
|
||||||
(\'10\',\'ELW\'),
|
(\'10\',\'KDOW\'),
|
||||||
(\'11\',\'ELW\'),
|
(\'11\',\'ELW\'),
|
||||||
|
(\'12\',\'ELW 2\'),
|
||||||
(\'14\',\'KDOW\'),
|
(\'14\',\'KDOW\'),
|
||||||
(\'19\',\'MTW\'),
|
(\'19\',\'MTF\'),
|
||||||
(\'20\',\'Tanklöschfahrzeug\'),
|
(\'20\',\'Tanklöschfahrzeug\'),
|
||||||
(\'21\',\'Tanklöschfahrzeug\'),
|
(\'21\',\'Tanklöschfahrzeug\'),
|
||||||
(\'22\',\'Vorauslöschfahrzeug\'),
|
(\'22\',\'Vorauslöschfahrzeug\'),
|
||||||
@ -789,13 +837,14 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
(\'24\',\'Tanklöschfahrzeug\'),
|
(\'24\',\'Tanklöschfahrzeug\'),
|
||||||
(\'25\',\'Großtanklöschfahrzeug\'),
|
(\'25\',\'Großtanklöschfahrzeug\'),
|
||||||
(\'26\',\'Tanklöschfahrzeug\'),
|
(\'26\',\'Tanklöschfahrzeug\'),
|
||||||
|
(\'27\',\'Tanklöschfahrzeug\'),
|
||||||
(\'29\',\'Großtanklöschfahrzeug\'),
|
(\'29\',\'Großtanklöschfahrzeug\'),
|
||||||
(\'30\',\'Drehleiter\'),
|
(\'30\',\'Drehleiter\'),
|
||||||
(\'31\',\'Drehleiter\'),
|
(\'31\',\'Drehleiter\'),
|
||||||
(\'32\',\'Drehleiter\'),
|
(\'32\',\'Drehleiter\'),
|
||||||
(\'33\',\'Drehleiter\'),
|
(\'33\',\'Drehleiter\'),
|
||||||
(\'34\',\'Hubarbeitsbühne\'),
|
(\'34\',\'Hubarbeitsbühne\'),
|
||||||
(\'35\',\'Drehleiter\'),
|
(\'35\',\'Gelenkmast\'),
|
||||||
(\'36\',\'Teleskopmast\'),
|
(\'36\',\'Teleskopmast\'),
|
||||||
(\'37\',\'Teleskopmast \'),
|
(\'37\',\'Teleskopmast \'),
|
||||||
(\'38\',\'Hubretter\'),
|
(\'38\',\'Hubretter\'),
|
||||||
@ -808,28 +857,40 @@ module.exports = function (fs, bcrypt, app_cfg) {
|
|||||||
(\'46\',\'Löschfahrzeug\'),
|
(\'46\',\'Löschfahrzeug\'),
|
||||||
(\'47\',\'TSF\'),
|
(\'47\',\'TSF\'),
|
||||||
(\'48\',\'TSF\'),
|
(\'48\',\'TSF\'),
|
||||||
|
(\'49\',\'Speziallöschfahrzeug\'),
|
||||||
(\'51\',\'Rüstwagen\'),
|
(\'51\',\'Rüstwagen\'),
|
||||||
(\'52\',\'Rüstwagen\'),
|
(\'52\',\'Rüstwagen\'),
|
||||||
(\'59\',\'Rüstwagen\'),
|
(\'53\',\'Rüstwagen\'),
|
||||||
(\'59\',\'Gerätewagen\'),
|
(\'59\',\'Gerätewagen\'),
|
||||||
|
(\'61\',\'Schlauchwagen\'),
|
||||||
|
(\'62\',\'Schlauchwagen\'),
|
||||||
|
(\'63\',\'Schlauchwagen\'),
|
||||||
|
(\'64\',\'Schlauchtransportwagen\'),
|
||||||
|
(\'65\',\'Wechsellader\'),
|
||||||
|
(\'66\',\'Wechsellader\'),
|
||||||
|
(\'67\',\'Wechsellader\'),
|
||||||
(\'69\',\'TSA\'),
|
(\'69\',\'TSA\'),
|
||||||
|
(\'76\',\'Krad\'),
|
||||||
|
(\'78\',\'Löschboot\'),
|
||||||
(\'79\',\'Mehrzweckboot\'),
|
(\'79\',\'Mehrzweckboot\'),
|
||||||
(\'82\',\'NEF\'),
|
(\'82\',\'NEF\'),
|
||||||
(\'83\',\'RTW\'),
|
(\'83\',\'RTW\'),
|
||||||
(\'85\',\'KTW\'),
|
(\'85\',\'KTW\'),
|
||||||
(\'88\',\'Rettungsboot\')`);
|
(\'88\',\'Rettungsboot\'),
|
||||||
|
(\'91\',\'Gerätewagen Dekontamination Personal\')`);
|
||||||
// Benutzer-Tabelle mit Standard-Admin befuellen
|
// Benutzer-Tabelle mit Standard-Admin befuellen
|
||||||
bcrypt.hash(app_cfg.global.defaultpass, app_cfg.global.saltRounds, function (err, hash) {
|
bcrypt.hash(app_cfg.global.defaultpass, app_cfg.global.saltRounds, function (err, hash) {
|
||||||
db.run(`INSERT INTO waip_users ( user, password, permissions, ip_address ) VALUES( ?, ?, 'admin', ? )`,
|
db.run(`INSERT INTO waip_users ( user, password, permissions, ip_address ) VALUES( ?, ?, 'admin', ? )`,
|
||||||
app_cfg.global.defaultuser, hash, app_cfg.global.defaultuserip, function (err) {
|
app_cfg.global.defaultuser, hash, app_cfg.global.defaultuserip,
|
||||||
if (err) {
|
function (err) {
|
||||||
console.error(err.message);
|
if (err) {
|
||||||
};
|
console.error(err.message);
|
||||||
});
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
|
|
||||||
};
|
};
|
||||||
1518
server/sql_qry.js
Normal file → Executable file
1518
server/sql_qry.js
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -1,45 +1,30 @@
|
|||||||
module.exports = function(app_cfg, waip_io, sql) {
|
module.exports = function (app_cfg, sql, saver) {
|
||||||
|
|
||||||
// Module laden
|
// Module laden
|
||||||
var dgram = require('dgram');
|
var dgram = require('dgram');
|
||||||
var udp_server = dgram.createSocket('udp4');
|
var udp_server = dgram.createSocket('udp4');
|
||||||
|
|
||||||
// Funktion um zu pruefen, ob Nachricht im JSON-Format ist
|
|
||||||
function isValidJSON(text) {
|
|
||||||
try {
|
|
||||||
JSON.parse(text);
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// UDP-Server für Schnittstelle starten
|
// UDP-Server für Schnittstelle starten
|
||||||
udp_server.bind(app_cfg.global.udpport);
|
udp_server.bind(app_cfg.global.udpport);
|
||||||
udp_server.on('listening', function() {
|
udp_server.on('listening', function () {
|
||||||
var address = udp_server.address();
|
var address = udp_server.address();
|
||||||
sql.db_log('Anwendung', 'UDP Server auf ' + address.address + ':' + address.port + ' gestartet.');
|
sql.db_log('Anwendung', 'UDP Server auf ' + address.address + ':' + address.port + ' gestartet.');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Warten auf Einsatzdaten
|
// Warten auf Einsatzdaten
|
||||||
udp_server.on('message', function(message, remote) {
|
udp_server.on('message', function (message, remote) {
|
||||||
if (isValidJSON(message)) {
|
saver.save_new_waip(message.toString('utf8'), remote.address + ':' + remote.port, 'udp')
|
||||||
sql.db_log('WAIP', 'Neuer Einsatz von ' + remote.address + ':' + remote.port + ': ' + message);
|
|
||||||
waip_io.einsatz_speichern(message);
|
|
||||||
} else {
|
|
||||||
sql.db_log('Fehler-WAIP', 'Fehler: Einsatz von ' + remote.address + ':' + remote.port + ' Fehlerhaft: ' + message);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// UDP-Daten senden
|
||||||
function send_message(message) {
|
function send_message(message) {
|
||||||
udp_server.send(message, 0, message.length, app_cfg.global.udpport, 'localhost', function(err, bytes) {
|
udp_server.send(message, 0, message.length, app_cfg.global.udpport, 'localhost', function (err, bytes) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
sql.db_log('UDP-Testalarm an localhost Port ' + app_cfg.global.udpport + ' gesendet.');
|
sql.db_log('WAIP', 'UDP-Testalarm an localhost:' + app_cfg.global.udpport + ' gesendet.');
|
||||||
//client.close();
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
send_message: send_message
|
send_message: send_message
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
485
server/waip.js
Executable file
485
server/waip.js
Executable file
@ -0,0 +1,485 @@
|
|||||||
|
module.exports = function (io, sql, fs, brk, async, app_cfg) {
|
||||||
|
|
||||||
|
// Module laden
|
||||||
|
const {
|
||||||
|
parse
|
||||||
|
} = require('json2csv');
|
||||||
|
const nodemailer = require('nodemailer');
|
||||||
|
|
||||||
|
function waip_speichern(einsatz_daten) {
|
||||||
|
// Einsatzmeldung in Datenbank speichern und verteilen
|
||||||
|
sql.db_einsatz_speichern(einsatz_daten, function (waip_id) {
|
||||||
|
sql.db_log('DEBUG', 'Neuen Einsatz mit der ID ' + waip_id + ' gespeichert.');
|
||||||
|
// nach dem Speichern anhand der waip_id die beteiligten Wachennummern zum Einsatz ermitteln
|
||||||
|
sql.db_einsatz_get_rooms(waip_id, function (socket_rooms) {
|
||||||
|
// socket_rooms muss groesser als 1 sein, da sonst nur der Standard-Raum '0' vorhanden ist
|
||||||
|
if (socket_rooms.length > 1) {
|
||||||
|
socket_rooms.forEach(function (rooms) {
|
||||||
|
// fuer jede Wache(rooms.room) die verbundenen Sockets(Clients) ermitteln und den Einsatz verteilen
|
||||||
|
var room_sockets = io.nsps['/waip'].adapter.rooms[rooms.room];
|
||||||
|
if (typeof room_sockets !== 'undefined') {
|
||||||
|
Object.keys(room_sockets.sockets).forEach(function (socket_id) {
|
||||||
|
var socket = io.of('/waip').connected[socket_id];
|
||||||
|
waip_verteilen(waip_id, socket, rooms.room);
|
||||||
|
sql.db_log('WAIP', 'Einsatz ' + waip_id + ' wird an ' + socket.id + ' (' + rooms.room + ') gesendet');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// wenn kein Raum (keine Wache) ausser '0' zurueckgeliefert wird, dann Einsatz direkt wieder loeschen weil keine Wachen dazu hinterlegt
|
||||||
|
sql.db_log('Fehler-WAIP', 'Fehler: Keine Wache für den Einsatz mit der ID ' + waip_id + ' vorhanden! Einsatz wird gelöscht!');
|
||||||
|
sql.db_einsatz_loeschen(waip_id);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// pruefen ob für die beteiligten Wachen eine Verteiler-Liste hinterlegt ist, falls ja: Rueckmeldungs-Link senden
|
||||||
|
sql.db_vmtl_get_list(waip_id, function (list) {
|
||||||
|
if (list) {
|
||||||
|
brk.alert_vmtl_list(list, function (result) {
|
||||||
|
if (!result) {
|
||||||
|
sql.db_log('VMTL', 'Link zur Einsatz-Rückmeldung erfolgreich an Vermittler-Liste gesendet. ' + result);
|
||||||
|
} else {
|
||||||
|
sql.db_log('VMTL', 'Fehler beim senden des Links zur Einsatz-Rueckmeldung an die Vermittler-Liste: ' + result);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sql.db_log('VMTL', 'Keine Vermittler-Liste für Wachen im Einsatz ' + waip_id + ' hinterlegt. Rückmeldung wird nicht verteilt.');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function waip_verteilen(waip_id, socket, wachen_nr) {
|
||||||
|
// Einsatzdaten für eine Wache aus Datenbank laden und an Client verteilen
|
||||||
|
var user_obj = socket.request.user;
|
||||||
|
sql.db_einsatz_get_by_waipid(waip_id, wachen_nr, user_obj.id, function (einsatzdaten) {
|
||||||
|
if (einsatzdaten) {
|
||||||
|
// Berechtigung des Users ueberpruefen
|
||||||
|
sql.db_user_check_permission(user_obj, waip_id, function (valid) {
|
||||||
|
// Wenn nutzer nicht angemeldet, Daten entfernen
|
||||||
|
if (!valid) {
|
||||||
|
einsatzdaten.objekt = '';
|
||||||
|
einsatzdaten.besonderheiten = '';
|
||||||
|
einsatzdaten.strasse = '';
|
||||||
|
einsatzdaten.wgs84_x = '';
|
||||||
|
einsatzdaten.wgs84_y = '';
|
||||||
|
};
|
||||||
|
// pruefen ob Einsatz bereits genau so beim Client angezeigt wurde (Doppelalarmierung)
|
||||||
|
sql.db_einsatz_check_history(waip_id, einsatzdaten, socket.id, function (result) {
|
||||||
|
if (!result) {
|
||||||
|
// Einsatz an Client senden
|
||||||
|
socket.emit('io.new_waip', einsatzdaten);
|
||||||
|
sql.db_log('WAIP', 'Einsatz ' + waip_id + ' fuer Wache ' + wachen_nr + ' an Socket ' + socket.id + ' gesendet.');
|
||||||
|
sql.db_client_update_status(socket, waip_id);
|
||||||
|
// Sound erstellen
|
||||||
|
tts_erstellen(app_cfg, socket.id, einsatzdaten, function (tts) {
|
||||||
|
if (tts) {
|
||||||
|
// Sound-Link senden
|
||||||
|
socket.emit('io.playtts', tts);
|
||||||
|
sql.db_log('WAIP', 'ttsfile: ' + tts);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Log das Einsatz explizit nicht an Client gesendet wurde
|
||||||
|
sql.db_log('WAIP', 'Einsatz ' + waip_id + ' fuer Wache ' + wachen_nr + ' nicht an Socket ' + socket.id + ' gesendet, da bereits angezeigt (Doppelalarmierung).');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// wenn keine Einsatzdaten, dann Standby senden
|
||||||
|
socket.emit('io.standby', null);
|
||||||
|
sql.db_log('WAIP', 'Kein Einsatz für Wache ' + wachen_nr + ' vorhanden, Standby an Socket ' + socket.id + ' gesendet.');
|
||||||
|
sql.db_client_update_status(socket, null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function rmld_verteilen_by_uuid(waip_uuid, rmld_uuid) {
|
||||||
|
// Einsatz-ID mittels Einsatz-UUID ermitteln, und Rueckmelung an alle relevanten Clients verteilen
|
||||||
|
sql.db_einsatz_get_waipid_by_uuid(waip_uuid, function (waip_id) {
|
||||||
|
// am Einsatz beteilite Socket-Räume ermitteln
|
||||||
|
sql.db_einsatz_get_rooms(waip_id, function (socket_rooms) {
|
||||||
|
if (socket_rooms) {
|
||||||
|
socket_rooms.forEach(function (row) {
|
||||||
|
// fuer jede Wache(row.room) die verbundenen Sockets(Clients) ermitteln und Standby senden
|
||||||
|
var room_sockets = io.nsps['/waip'].adapter.rooms[row.room];
|
||||||
|
if (typeof room_sockets !== 'undefined') {
|
||||||
|
Object.keys(room_sockets.sockets).forEach(function (socket_id) {
|
||||||
|
// wenn Raum zum Einsatz aufgerufen ist, dann Rueckmeldung aus DB laden und an diesen versenden
|
||||||
|
sql.db_rmld_get_by_rmlduuid(rmld_uuid, function (rmld_obj) {
|
||||||
|
if (rmld_obj) {
|
||||||
|
// Rückmeldung an Clients/Räume senden, wenn richtiger Einsatz angezeigt wird
|
||||||
|
sql.db_client_check_waip_id(socket_id, waip_id, function (same_id) {
|
||||||
|
if (same_id) {
|
||||||
|
var socket = io.of('/waip').connected[socket_id];
|
||||||
|
socket.emit('io.new_rmld', rmld_obj);
|
||||||
|
sql.db_log('RMLD', 'Rückmeldung ' + rmld_uuid + ' für den Einsatz mit der ID ' + waip_id + ' an Wache ' + row.room + ' gesendet.');
|
||||||
|
sql.db_log('DEBUG', 'Rückmeldung JSON: ' + JSON.stringify(rmld_obj));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// Dashboards ermitteln, welche den Einsatz geladen haben
|
||||||
|
sql.db_socket_get_dbrd(waip_id, function (dbrd_sockets) {
|
||||||
|
if (dbrd_sockets) {
|
||||||
|
// Rueckmeldung auslesen
|
||||||
|
sql.db_rmld_get_by_rmlduuid(rmld_uuid, function (rmld_obj) {
|
||||||
|
if (rmld_obj) {
|
||||||
|
// Rückmeldung an Dashboards senden
|
||||||
|
dbrd_sockets.forEach(function (row) {
|
||||||
|
var socket = io.of('/dbrd').connected[row.socket_id];
|
||||||
|
socket.emit('io.new_rmld', rmld_obj);
|
||||||
|
sql.db_log('RMLD', 'Rückmeldung ' + rmld_uuid + ' für den Einsatz mit der ID ' + waip_id + ' an Dashboard ' + waip_uuid + ' gesendet.');
|
||||||
|
sql.db_log('DEBUG', 'Rückmeldung JSON: ' + JSON.stringify(rmld_obj));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function rmld_verteilen_for_one_client(waip_id, socket, wachen_id) {
|
||||||
|
// Rueckmeldung an einen bestimmten Client senden
|
||||||
|
if (typeof socket.id !== 'undefined') {
|
||||||
|
sql.db_rmld_get_fuer_wache(waip_id, wachen_id, function (rmld_obj) {
|
||||||
|
console.log(rmld_obj);
|
||||||
|
if (rmld_obj) {
|
||||||
|
// Rueckmeldung nur an den einen Socket senden
|
||||||
|
socket.emit('io.new_rmld', rmld_obj);
|
||||||
|
sql.db_log('RMLD', 'Vorhandene Rückmeldungen an Socket ' + socket.id + ' gesendet.');
|
||||||
|
sql.db_log('DEBUG', 'Rückmeldung JSON: ' + JSON.stringify(rmld_obj));
|
||||||
|
} else {
|
||||||
|
sql.db_log('RMLD', 'Keine Rückmeldungen für Einsatz-ID' + waip_id + ' und Wachen-ID ' + wachen_id + ' vorhanden.');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function dbrd_verteilen(dbrd_uuid, socket) {
|
||||||
|
// Einsatzdaten an Dashboard senden
|
||||||
|
sql.db_einsatz_get_by_uuid(dbrd_uuid, function (einsatzdaten) {
|
||||||
|
if (einsatzdaten) {
|
||||||
|
sql.db_user_check_permission(socket.request.user, einsatzdaten.id, function (valid) {
|
||||||
|
if (!valid) {
|
||||||
|
delete einsatzdaten.objekt;
|
||||||
|
delete einsatzdaten.besonderheiten;
|
||||||
|
delete einsatzdaten.strasse;
|
||||||
|
delete einsatzdaten.wgs84_x;
|
||||||
|
delete einsatzdaten.wgs84_y;
|
||||||
|
};
|
||||||
|
socket.emit('io.Einsatz', einsatzdaten);
|
||||||
|
sql.db_log('DBRD', 'Einsatzdaten für Dashboard ' + dbrd_uuid + ' an Socket ' + socket.id + ' gesendet');
|
||||||
|
sql.db_client_update_status(socket, einsatzdaten.id);
|
||||||
|
});
|
||||||
|
// Rueckmeldungen auslesen
|
||||||
|
rmld_verteilen_for_one_client(einsatzdaten.id, socket, 0);
|
||||||
|
} else {
|
||||||
|
// Standby senden
|
||||||
|
// BUG hier kein standby senden, sonder nicht vorhanden
|
||||||
|
socket.emit('io.standby', null);
|
||||||
|
sql.db_log('DBRD', 'Der angefragte Einsatz ' + dbrd_uuid + ' ist nicht - oder nicht mehr - vorhanden!, Standby an Socket ' + socket.id + ' gesendet.');
|
||||||
|
sql.db_client_update_status(socket, null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO WAIP: Funktion um Clients remote "neuzustarten" (Seite neu laden), niedrige Prioritaet
|
||||||
|
|
||||||
|
function tts_erstellen(app_cfg, socket_id, einsatzdaten, callback) {
|
||||||
|
// unnoetige Zeichen aus socket_id entfernen, um diese als Dateinamen zu verwenden
|
||||||
|
var id = socket_id.replace(/\W/g, '');
|
||||||
|
// Pfade der Sound-Dateien defeinieren
|
||||||
|
var wav_tts = process.cwd() + app_cfg.global.soundpath + id + '.wav';
|
||||||
|
var mp3_tmp = process.cwd() + app_cfg.global.soundpath + id + '_tmp.mp3';
|
||||||
|
var mp3_tts = process.cwd() + app_cfg.global.soundpath + id + '.mp3';
|
||||||
|
var mp3_url = app_cfg.global.mediapath + id + '.mp3';
|
||||||
|
// unterscheiden des Alarmgongs nach Einsatzart
|
||||||
|
if (einsatzdaten.einsatzart == "Brandeinsatz" || einsatzdaten.einsatzart == "Hilfeleistungseinsatz") {
|
||||||
|
var mp3_bell = process.cwd() + app_cfg.global.soundpath + 'bell_long.mp3';
|
||||||
|
} else {
|
||||||
|
var mp3_bell = process.cwd() + app_cfg.global.soundpath + 'bell_short.mp3';
|
||||||
|
};
|
||||||
|
// Zusammensetzen der Sprachansage
|
||||||
|
async.map(JSON.parse(einsatzdaten.em_alarmiert), sql.db_tts_einsatzmittel, function (err, einsatzmittel) {
|
||||||
|
// Grunddaten
|
||||||
|
var tts_text = einsatzdaten.einsatzart + ', ' + einsatzdaten.stichwort;
|
||||||
|
if (einsatzdaten.objekt) {
|
||||||
|
var tts_text = tts_text + '. ' + einsatzdaten.objekt + ', ' + einsatzdaten.ort + ', ' + einsatzdaten.ortsteil;
|
||||||
|
} else {
|
||||||
|
var tts_text = tts_text + '. ' + einsatzdaten.ort + ', ' + einsatzdaten.ortsteil;
|
||||||
|
};
|
||||||
|
// Einsatzmittel
|
||||||
|
tts_text = tts_text + '. Für ' + einsatzmittel.join(", ");
|
||||||
|
// Unterscheidung nach Sondersignal
|
||||||
|
if (einsatzdaten.sondersignal == 1) {
|
||||||
|
tts_text = tts_text + ', mit Sondersignal';
|
||||||
|
} else {
|
||||||
|
tts_text = tts_text + ', ohne Sonderrechte';
|
||||||
|
};
|
||||||
|
// Abschluss
|
||||||
|
tts_text = tts_text + '. Ende der Durchsage!';
|
||||||
|
// ungewollte zeichen aus Sprachansage entfernen
|
||||||
|
tts_text = tts_text.replace(/:/g, " ");
|
||||||
|
tts_text = tts_text.replace(/\//g, " ");
|
||||||
|
tts_text = tts_text.replace(/-/g, " ");
|
||||||
|
// Sprachansage als mp3 erstellen
|
||||||
|
switch (process.platform) {
|
||||||
|
// Windows
|
||||||
|
case 'win32':
|
||||||
|
// Powershell
|
||||||
|
var proc = require('child_process');
|
||||||
|
var commands = [
|
||||||
|
// TTS-Schnittstelle von Windows ansprechen
|
||||||
|
'Add-Type -AssemblyName System.speech;' +
|
||||||
|
'$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;' +
|
||||||
|
// Ausgabedatei und Sprachtext
|
||||||
|
'$speak.SetOutputToWaveFile(\"' + wav_tts + '\");' +
|
||||||
|
'$speak.Speak(\"' + tts_text + '\");' +
|
||||||
|
'$speak.Dispose();' +
|
||||||
|
// speak.wav in mp3 umwandeln
|
||||||
|
'ffmpeg -nostats -hide_banner -loglevel 0 -y -i ' + wav_tts + ' -vn -ar 44100 -ac 2 -ab 128k -f mp3 ' + mp3_tmp + ';' +
|
||||||
|
// Gong und Ansage zu einer mp3 zusammensetzen
|
||||||
|
'ffmpeg -nostats -hide_banner -loglevel 0 -y -i \"concat:' + mp3_bell + '|' + mp3_tmp + '\" -acodec copy ' + mp3_tts + ';' +
|
||||||
|
'rm ' + wav_tts + ';' +
|
||||||
|
'rm ' + mp3_tmp + ';'
|
||||||
|
];
|
||||||
|
var options = {
|
||||||
|
shell: true
|
||||||
|
};
|
||||||
|
var childD = proc.spawn('powershell', commands);
|
||||||
|
childD.stdin.setEncoding('ascii');
|
||||||
|
childD.stderr.setEncoding('ascii');
|
||||||
|
childD.stderr.on('data', function (data) {
|
||||||
|
sql.db_log('Fehler-TTS', data);
|
||||||
|
callback && callback(null);
|
||||||
|
});
|
||||||
|
childD.on('exit', function () {
|
||||||
|
callback && callback(mp3_url);
|
||||||
|
});
|
||||||
|
childD.stdin.end();
|
||||||
|
break;
|
||||||
|
// LINUX
|
||||||
|
case 'linux':
|
||||||
|
// bash
|
||||||
|
var proc = require('child_process');
|
||||||
|
var commands = [
|
||||||
|
// TTS-Schnittstelle SVOX PicoTTS
|
||||||
|
'-c', `
|
||||||
|
pico2wave --lang=de-DE --wave=` + wav_tts + ` \"` + tts_text + `\"
|
||||||
|
ffmpeg -nostats -hide_banner -loglevel 0 -y -i ` + wav_tts + ` -vn -ar 44100 -ac 2 -ab 128k -f mp3 ` + mp3_tmp + `
|
||||||
|
ffmpeg -nostats -hide_banner -loglevel 0 -y -i \"concat:` + mp3_bell + `|` + mp3_tmp + `\" -acodec copy ` + mp3_tts + `
|
||||||
|
rm ` + wav_tts + `
|
||||||
|
rm ` + mp3_tmp
|
||||||
|
];
|
||||||
|
var options = {
|
||||||
|
shell: true
|
||||||
|
};
|
||||||
|
if (app_cfg.global.development) {
|
||||||
|
console.log(commands);
|
||||||
|
};
|
||||||
|
var childD = proc.spawn('/bin/sh', commands);
|
||||||
|
childD.stdin.setEncoding('ascii');
|
||||||
|
childD.stderr.setEncoding('ascii');
|
||||||
|
childD.on('exit', function (code, signal) {
|
||||||
|
if (code > 0) {
|
||||||
|
sql.db_log('Fehler-TTS', 'Exit-Code ' + code + '; Fehler beim erstellen der TTS-Datei');
|
||||||
|
callback && callback(null);
|
||||||
|
} else {
|
||||||
|
callback && callback(mp3_url);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
childD.stdin.end();
|
||||||
|
break;
|
||||||
|
// anderes OS
|
||||||
|
default:
|
||||||
|
sql.db_log('Fehler-TTS', 'TTS für dieses Server-Betriebssystem nicht verfügbar!');
|
||||||
|
callback && callback(null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
|
||||||
|
// (alle 10 Sekunden)
|
||||||
|
|
||||||
|
sql.db_socket_get_all_to_standby(function (socket_ids) {
|
||||||
|
// alle User-Einstellungen prüfen und ggf. Standby senden
|
||||||
|
if (socket_ids) {
|
||||||
|
socket_ids.forEach(function (row) {
|
||||||
|
var socket = io.of('/waip').connected[row.socket_id];
|
||||||
|
if (typeof socket !== 'undefined') {
|
||||||
|
socket.emit('io.standby', null);
|
||||||
|
socket.emit('io.stopaudio', null);
|
||||||
|
sql.db_log('WAIP', 'Standby an Socket ' + socket.id + ' gesendet');
|
||||||
|
sql.db_client_update_status(socket, null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
sql.db_einsatz_get_old(app_cfg.global.time_to_delete_waip, function (waip) {
|
||||||
|
// nach alten Einsaetzen suchen und diese ggf. loeschen
|
||||||
|
if (waip) {
|
||||||
|
sql.db_log('WAIP', 'Einsatz mit der ID ' + waip.id + ' ist veraltet und kann gelöscht werden.')
|
||||||
|
// Dashboards trennen, deren Einsatz geloescht wurde
|
||||||
|
sql.db_socket_get_dbrd(waip.id, function (socket_ids) {
|
||||||
|
// TODO TEST: Dashboard-Trennen-Funktion testen
|
||||||
|
if (socket_ids) {
|
||||||
|
socket_ids.forEach(function (row) {
|
||||||
|
var socket = io.of('/dbrd').connected[row.socket_id];
|
||||||
|
if (typeof socket !== 'undefined') {
|
||||||
|
socket.emit('io.deleted', null);
|
||||||
|
sql.db_log('DBRD', 'Dashboard mit dem Socket ' + socket.id + ' getrennt, da Einsatz gelöscht.');
|
||||||
|
sql.db_client_update_status(socket, null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// beteiligte Wachen zum Einsatz ermitteln
|
||||||
|
sql.db_einsatz_get_rooms(waip.id, function (data) {
|
||||||
|
if (data) {
|
||||||
|
data.forEach(function (row) {
|
||||||
|
// fuer jede Wache (row.room) die verbundenen Sockets(Clients) ermitteln und Standby senden
|
||||||
|
var room_sockets = io.nsps['/waip'].adapter.rooms[row.room];
|
||||||
|
if (typeof room_sockets !== 'undefined') {
|
||||||
|
Object.keys(room_sockets.sockets).forEach(function (socket_id) {
|
||||||
|
// Standby senden
|
||||||
|
var socket = io.of('/waip').connected[socket_id];
|
||||||
|
sql.db_client_check_waip_id(socket.id, waip.id, function (same_id) {
|
||||||
|
if (same_id) {
|
||||||
|
socket.emit('io.standby', null);
|
||||||
|
socket.emit('io.stopaudio', null);
|
||||||
|
sql.db_log('WAIP', 'Standby an Socket ' + socket.id + ' gesendet');
|
||||||
|
sql.db_client_update_status(socket, null);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
sql.db_rmld_get_for_export(waip.einsatznummer, waip.uuid, function (full_rmld) {
|
||||||
|
// beteiligte Wachen aus den Einsatz-Rueckmeldungen filtern
|
||||||
|
var arry_wachen = full_rmld.map(a => a.wache_nr);
|
||||||
|
sql.db_export_get_for_rmld(arry_wachen, function (export_data) {
|
||||||
|
// SQL gibt ist eine Schliefe (db.each), fuer jedes Ergebnis wird eine CSV/Mail erstellt
|
||||||
|
if (export_data) {
|
||||||
|
// je Export eine CSV erstellen, die nur die gewuenschten Rueckmeldungen enthaelt
|
||||||
|
var part_rmld = full_rmld.filter(obj => String(obj.wache_nr).startsWith(String(export_data.export_filter)));
|
||||||
|
// CSV-Spalten definieren
|
||||||
|
var csv_col = ['id', 'einsatznummer', 'waip_uuid', 'rmld_uuid', 'alias', 'einsatzkraft', 'maschinist', 'fuehrungskraft', 'agt', 'set_time', 'arrival_time', 'wache_id', 'wache_nr', 'wache_name'];
|
||||||
|
var opts = {
|
||||||
|
csv_col
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
var csv = parse(part_rmld, opts);
|
||||||
|
// CSV Dateiname und Pfad festlegen
|
||||||
|
var csv_filename = export_data.export_name.replace(/[|&;$%@"<>()+,]/g, '');
|
||||||
|
csv_filename = csv_filename.replace(/ /g, "_");
|
||||||
|
csv_filename = 'einsatz_' + part_rmld[0].einsatznummer + '_export_' + csv_filename + '.csv';
|
||||||
|
csv_path = process.cwd() + app_cfg.rmld.backup_path;
|
||||||
|
// CSV in Backup-Ordner speichern, falls aktiviert
|
||||||
|
if (app_cfg.rmld.backup_to_file) {
|
||||||
|
// Ordner erstellen
|
||||||
|
fs.mkdir(csv_path, {
|
||||||
|
recursive: true
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
sql.db_log('EXPORT', 'Fehler beim Erstellen des Backup-Ordners: ' + err);
|
||||||
|
};
|
||||||
|
// CSV speichern
|
||||||
|
fs.writeFile(csv_path + csv_filename, csv, function (err) {
|
||||||
|
if (err) {
|
||||||
|
sql.db_log('EXPORT', 'Fehler beim speichern der Export-CSV: ' + err);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// CSV per Mail versenden, falls aktiviert
|
||||||
|
if (app_cfg.rmld.backup_to_mail) {
|
||||||
|
// pruefen ob Mail plausibel ist
|
||||||
|
var validmail = /\S+@\S+\.\S+/;
|
||||||
|
if (validmail.test(export_data.export_recipient)) {
|
||||||
|
// Mail-Server
|
||||||
|
var transport = nodemailer.createTransport({
|
||||||
|
host: app_cfg.rmld.mailserver_host,
|
||||||
|
port: app_cfg.rmld.mailserver_port,
|
||||||
|
secure: app_cfg.rmld.secure_mail,
|
||||||
|
auth: {
|
||||||
|
user: app_cfg.rmld.mail_user,
|
||||||
|
pass: app_cfg.rmld.mail_pass
|
||||||
|
},
|
||||||
|
tls: {
|
||||||
|
rejectUnauthorized: app_cfg.rmld.unauthorized_mail
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var mail_message = {
|
||||||
|
from: 'Wachalarm-IP-Web <' + app_cfg.rmld.mail_from + '>',
|
||||||
|
to: export_data.export_recipient,
|
||||||
|
subject: 'Automatischer Export Wachalarm-IP-Web - ' + export_data.export_name + ' - Einsatz ' + part_rmld[0].einsatznummer,
|
||||||
|
html: 'Hallo,<br><br>anbei der automatische Export aller Einsatz-Rückmeldungen für den Einsatz ' + part_rmld[0].einsatznummer + '<br><br>Mit freundlichen Grüßen<br><br>' + app_cfg.public.company + '<br>',
|
||||||
|
attachments: [{
|
||||||
|
filename: csv_filename,
|
||||||
|
content: csv
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
transport.sendMail(mail_message, function (err, info) {
|
||||||
|
if (err) {
|
||||||
|
sql.db_log('EXPORT', 'Fehler beim senden der Export-Mail an ' + export_data.export_recipient + ': ' + err);
|
||||||
|
} else {
|
||||||
|
sql.db_log('EXPORT', 'Mail an ' + export_data.export_recipient + ' gesendet: ' + JSON.stringify(info));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sql.db_log('EXPORT', 'Fehler beim versenden der Export-Mail an ' + export_data.export_recipient + ' - keine richtige Mail-Adresse!');
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
sql.db_log('EXPORT', 'Fehler beim erstellen der Export-CSV: ' + err);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// alte Rueckmeldungen loeschen
|
||||||
|
sql.db_rmld_loeschen(waip.uuid);
|
||||||
|
});
|
||||||
|
// alten Einsatz loeschen
|
||||||
|
sql.db_einsatz_loeschen(waip.id);
|
||||||
|
sql.db_log('WAIP', 'Einsatz-Daten zu Einsatz ' + waip.id + ' gelöscht.');
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// loeschen alter Sounddaten nach alter (15min) und socket-id (nicht mehr verbunden)
|
||||||
|
fs.readdirSync(process.cwd() + app_cfg.global.soundpath).forEach(file => {
|
||||||
|
// nur die mp3s von alten clients loeschen
|
||||||
|
if (file.substring(0, 4) != 'bell' && file.substring(file.length - 3) == 'mp3' && file.substring(file.length - 8) != '_tmp.mp3') {
|
||||||
|
// Socket-ID aus Datei-Namen extrahieren
|
||||||
|
socket_name = file.substring(0, file.length - 4);
|
||||||
|
// Socket-ID anpassen, damit die SQL-Abfrage ein Ergebnis liefert
|
||||||
|
socket_name = socket_name.replace('waip', '/waip#');
|
||||||
|
sql.db_socket_get_by_id(socket_name, function (data) {
|
||||||
|
if (!data) {
|
||||||
|
fs.unlink(process.cwd() + app_cfg.global.soundpath + file, function (err) {
|
||||||
|
if (err) return sql.db_log('Fehler-WAIP', err);
|
||||||
|
sql.db_log('WAIP', 'Veraltete Sound-Datei ' + file + ' wurde gelöscht.');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return {
|
||||||
|
waip_speichern: waip_speichern,
|
||||||
|
waip_verteilen: waip_verteilen,
|
||||||
|
rmld_verteilen_for_one_client: rmld_verteilen_for_one_client,
|
||||||
|
rmld_verteilen_by_uuid: rmld_verteilen_by_uuid,
|
||||||
|
dbrd_verteilen: dbrd_verteilen
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,322 +0,0 @@
|
|||||||
module.exports = function(io, sql, async, app_cfg) {
|
|
||||||
|
|
||||||
// Socket.IO
|
|
||||||
io.on('connection', function(socket) {
|
|
||||||
sql.db_log('WAIP', 'Anwendung von ' + socket.request.connection.remoteAddress + ' (' + socket.id + ') geoeffnet');
|
|
||||||
io.sockets.to(socket.id).emit('io.version', app_cfg.global.app_id);
|
|
||||||
// disconnect
|
|
||||||
socket.on('disconnect', function() {
|
|
||||||
sql.db_log('WAIP', 'Alarmmonitor von ' + socket.request.connection.remoteAddress + ' (' + socket.id + ') geschlossen');
|
|
||||||
sql.db_client_delete(socket.id);
|
|
||||||
});
|
|
||||||
// Aufruf des Alarmmonitors einer bestimmten Wache verarbeiten
|
|
||||||
socket.on('wachen_id', function(wachen_id) {
|
|
||||||
sql.db_log('WAIP', 'Alarmmonitor Nr. ' + wachen_id + ' von ' + socket.request.connection.remoteAddress + ' (' + socket.id + ') aufgerufen');
|
|
||||||
// prüfen ob Wachenummer in der Datenbank hinterlegt ist
|
|
||||||
sql.db_wache_vorhanden(wachen_id,function(result) {
|
|
||||||
// wenn die Wachennummer vorhanden/plausibel dann weiter
|
|
||||||
if (result) {
|
|
||||||
// Socket-Room beitreiten
|
|
||||||
socket.join(wachen_id, function() {
|
|
||||||
// Socket-ID und Client-IP in der Datenbank speichern
|
|
||||||
sql.db_client_save(socket.id, socket.request.connection.remoteAddress, wachen_id);
|
|
||||||
// prüfen ob für diese Wache ein Einsatz vorhanden ist
|
|
||||||
sql.db_einsatz_vorhanden(wachen_id, socket.request.user.id, function(result_einsatz) {
|
|
||||||
if (result_einsatz) {
|
|
||||||
console.log(result_einsatz[0].waip_einsaetze_ID);
|
|
||||||
sql.db_log('WAIP', 'Einsatz ' + result_einsatz[0].waip_einsaetze_ID + ' fuer Wache ' + wachen_id + ' vorhanden');
|
|
||||||
//letzten Einsatz verteilen
|
|
||||||
einsatz_verteilen(result_einsatz[0].waip_einsaetze_ID, socket.id, wachen_id);
|
|
||||||
sql.db_update_client_status(socket, result_einsatz[0].waip_einsaetze_ID);
|
|
||||||
//vorhanden Rückmeldungen verteilen
|
|
||||||
sql.db_get_response(result_einsatz[0].waip_einsaetze_ID, function(result){
|
|
||||||
if (result) {
|
|
||||||
reuckmeldung_verteilen(result_einsatz[0].waip_einsaetze_ID, result);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sql.db_log('WAIP', 'Kein Einsatz fuer Wache ' + wachen_id + ' vorhanden, Standby');
|
|
||||||
//oder falls kein Einsatz vorhanden ist, dann
|
|
||||||
io.sockets.to(socket.id).emit('io.standby', null);
|
|
||||||
sql.db_update_client_status(socket, null);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sql.db_log('Fehler-WAIP', 'Fehler: Wachnnummer ' + wachen_id + 'nicht vorhanden');
|
|
||||||
io.sockets.to(socket.id).emit('io.error', 'Fehler: Wachnnummer \'' + wachen_id + '\' nicht vorhanden!');
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
socket.on('response', function(waip_id, ek, ma, fk, agt) {
|
|
||||||
var i_ek = ek ? 1 : 0;
|
|
||||||
var i_ma = ma ? 1 : 0;
|
|
||||||
var i_fk = fk ? 1 : 0;
|
|
||||||
var i_agt = agt ? 1 : 0;
|
|
||||||
sql.db_update_response(waip_id, i_ek, i_ma, i_fk, i_agt, function(result){
|
|
||||||
reuckmeldung_verteilen(waip_id, result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// TODO: socket.on(Version) um Server-Version abzugleichen
|
|
||||||
});
|
|
||||||
|
|
||||||
// Einsatzmeldung in Datenbank speichern
|
|
||||||
function einsatz_speichern(message) {
|
|
||||||
// Einsatzmeldung (JSON) speichern
|
|
||||||
sql.db_einsatz_speichern(JSON.parse(message), function(waip_id) {
|
|
||||||
// nach dem Speichern anhand der waip_id die beteiligten Wachennummern zum Einsatz ermitteln
|
|
||||||
sql.db_log('WAIP', 'DEBUG: ' + waip_id);
|
|
||||||
sql.db_get_einsatzwachen(waip_id, function(data) {
|
|
||||||
if (data) {
|
|
||||||
data.forEach(function(row) {
|
|
||||||
// fuer jede Wache(row.room) die verbundenen Sockets(Clients) ermitteln und Einsatz verteilen
|
|
||||||
var room_stockets = io.sockets.adapter.rooms[row.room];
|
|
||||||
if (typeof room_stockets !== 'undefined') {
|
|
||||||
Object.keys(room_stockets.sockets).forEach(function(socketId) {
|
|
||||||
einsatz_verteilen(waip_id, socketId, row.room);
|
|
||||||
sql.db_log('WAIP', 'Einsatz ' + waip_id + ' wird an ' + socketId + ' (' + row.room + ') gesendet');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sql.db_log('Fehler-WAIP', 'Fehler: Wache für waip_id ' + waip_id + ' nicht vorhanden!');
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Einsatz an Client verteilen
|
|
||||||
function einsatz_verteilen(waip_id, socket_id, wachen_nr) {
|
|
||||||
// Einsatzdaten für eine Wache aus Datenbank laden
|
|
||||||
sql.db_get_einsatzdaten(waip_id, wachen_nr, io.sockets.sockets[socket_id].request.user.id, function(einsatzdaten) {
|
|
||||||
if (einsatzdaten) {
|
|
||||||
// Berechtigung ueberpruefen
|
|
||||||
var permissions = io.sockets.sockets[socket_id].request.user.permissions;
|
|
||||||
sql.db_check_permission(permissions, waip_id, function(valid) {
|
|
||||||
//console.log(permissions + ' ' + wachen_nr);
|
|
||||||
//if (permissions == wachen_nr || permissions == 'admin') {} else {
|
|
||||||
if (!valid) {
|
|
||||||
einsatzdaten.objekt = '';
|
|
||||||
einsatzdaten.besonderheiten = '';
|
|
||||||
einsatzdaten.strasse = '';
|
|
||||||
einsatzdaten.wgs84_x = einsatzdaten.wgs84_x.substring(0, einsatzdaten.wgs84_x.indexOf('.') + 3);
|
|
||||||
einsatzdaten.wgs84_y = einsatzdaten.wgs84_y.substring(0, einsatzdaten.wgs84_y.indexOf('.') + 3);
|
|
||||||
};
|
|
||||||
// Einsatz senden
|
|
||||||
io.sockets.to(socket_id).emit('io.neuerEinsatz', einsatzdaten)
|
|
||||||
sql.db_log('WAIP', 'Einsatz ' + waip_id + ' fuer Wache ' + wachen_nr + ' an Socket ' + socket_id + ' gesendet');
|
|
||||||
sql.db_update_client_status(io.sockets.sockets[socket_id], waip_id);
|
|
||||||
// Sound erstellen
|
|
||||||
tts_erstellen(app_cfg, socket_id, einsatzdaten, function(tts) {
|
|
||||||
// Sound senden
|
|
||||||
sql.db_log('WAIP', 'ttsfile: ' + tts);
|
|
||||||
io.sockets.to(socket_id).emit('io.playtts', tts);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Standby senden
|
|
||||||
io.sockets.to(socket_id).emit('io.standby', null);
|
|
||||||
sql.db_log('WAIP', 'Kein Einsatz fuer Wache ' + wachen_nr + ' vorhanden, Standby an Socket ' + socket_id + ' gesendet..');
|
|
||||||
sql.db_update_client_status(io.sockets.sockets[socket_id], null);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function reuckmeldung_verteilen(waip_id, result) {
|
|
||||||
sql.db_get_einsatzwachen(waip_id, function(data) {
|
|
||||||
if (data) {
|
|
||||||
data.forEach(function(row) {
|
|
||||||
// fuer jede Wache(row.room) die verbundenen Sockets(Clients) ermitteln und Einsatz verteilen
|
|
||||||
var room_stockets = io.sockets.adapter.rooms[row.room];
|
|
||||||
if (typeof room_stockets !== 'undefined') {
|
|
||||||
Object.keys(room_stockets.sockets).forEach(function(socket_id) {
|
|
||||||
io.sockets.to(socket_id).emit('io.response', result)
|
|
||||||
sql.db_log('WAIP', 'Rückmeldung ' + result + ' an Socket ' + socket_id + ' gesendet');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sql.db_log('Fehler-WAIP', 'Fehler: Wache für waip_id ' + waip_id + ' nicht vorhanden, Rückmeldung konnte nicht verteilt werden!');
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function tts_erstellen(app_cfg, socket_id, einsatzdaten, callback) {
|
|
||||||
// unnoetige Zeichen aus socket_id entfernen
|
|
||||||
var id = socket_id.replace(/\W/g, '');
|
|
||||||
// Pfade der Sound-Dateien defeinieren
|
|
||||||
var wav_tts = process.cwd() + app_cfg.global.soundpath + id + '.wav';
|
|
||||||
var mp3_tmp = process.cwd() + app_cfg.global.soundpath + id + '_tmp.mp3';
|
|
||||||
var mp3_tts = process.cwd() + app_cfg.global.soundpath + id + '.mp3';
|
|
||||||
var mp3_url = app_cfg.global.mediapath + id + '.mp3';
|
|
||||||
// Unterscheiden des Alarmgongs nach Einsatzart
|
|
||||||
if (einsatzdaten.einsatzart == "Brandeinsatz" || einsatzdaten.einsatzart == "Hilfeleistungseinsatz") {
|
|
||||||
var mp3_bell = process.cwd() + app_cfg.global.soundpath + 'bell_long.mp3';
|
|
||||||
} else {
|
|
||||||
var mp3_bell = process.cwd() + app_cfg.global.soundpath + 'bell_short.mp3';
|
|
||||||
};
|
|
||||||
// Zusammensetzen der Sprachansage
|
|
||||||
async.map(JSON.parse(einsatzdaten.em_alarmiert), sql.db_tts_einsatzmittel, function(err, einsatzmittel) {
|
|
||||||
// Grunddaten
|
|
||||||
var tts_text = einsatzdaten.einsatzart + ', ' + einsatzdaten.stichwort;
|
|
||||||
if (einsatzdaten.objekt) {
|
|
||||||
var tts_text = tts_text + '. ' + einsatzdaten.objekt + ', ' + einsatzdaten.ort + ', ' + einsatzdaten.ortsteil;
|
|
||||||
} else {
|
|
||||||
var tts_text = tts_text + '. ' + einsatzdaten.ort + ', ' + einsatzdaten.ortsteil;
|
|
||||||
};
|
|
||||||
// Einsatzmittel
|
|
||||||
tts_text = tts_text + '. Für ' + einsatzmittel.join(", ");
|
|
||||||
// Unterscheidung nach Sondersignal
|
|
||||||
if (einsatzdaten.sondersignal == 1) {
|
|
||||||
tts_text = tts_text + ', mit Sondersignal';
|
|
||||||
} else {
|
|
||||||
tts_text = tts_text + ', ohne Sonderrechte';
|
|
||||||
};
|
|
||||||
// Abschluss
|
|
||||||
tts_text = tts_text + '. Ende der Durchsage!';
|
|
||||||
// ungewollte zeichen aus Sprachansage entfernen
|
|
||||||
tts_text = tts_text.replace(/:/g, " ");
|
|
||||||
tts_text = tts_text.replace(/\//g, " ");
|
|
||||||
tts_text = tts_text.replace(/-/g, " ");
|
|
||||||
// Sprachansage als mp3 erstellen
|
|
||||||
switch (process.platform) {
|
|
||||||
//if (process.platform === "win32") {
|
|
||||||
case 'win32':
|
|
||||||
// Powershell
|
|
||||||
var proc = require('child_process');
|
|
||||||
var commands = [
|
|
||||||
// TTS-Schnittstelle von Windows
|
|
||||||
'Add-Type -AssemblyName System.speech;' +
|
|
||||||
'$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;' +
|
|
||||||
// Ausgabedatei und Sprachtext
|
|
||||||
'$speak.SetOutputToWaveFile(\"' + wav_tts + '\");' +
|
|
||||||
'$speak.Speak(\"' + tts_text + '\");' +
|
|
||||||
'$speak.Dispose();' +
|
|
||||||
// speak.wav in mp3 umwandeln
|
|
||||||
'ffmpeg -nostats -hide_banner -loglevel 0 -y -i ' + wav_tts + ' -vn -ar 44100 -ac 2 -ab 128k -f mp3 ' + mp3_tmp + ';' +
|
|
||||||
// Gong und Ansage zu einer mp3 zusammensetzen
|
|
||||||
'ffmpeg -nostats -hide_banner -loglevel 0 -y -i \"concat:' + mp3_bell + '|' + mp3_tmp + '\" -acodec copy ' + mp3_tts + ';' +
|
|
||||||
'rm ' + wav_tts + ';' +
|
|
||||||
'rm ' + mp3_tmp + ';'
|
|
||||||
];
|
|
||||||
var options = {
|
|
||||||
shell: true
|
|
||||||
};
|
|
||||||
var childD = proc.spawn('powershell', commands);
|
|
||||||
childD.stdin.setEncoding('ascii');
|
|
||||||
childD.stderr.setEncoding('ascii');
|
|
||||||
childD.stderr.on('data', function(data) {
|
|
||||||
sql.db_log('Fehler-TTS', data);
|
|
||||||
callback && callback(null);
|
|
||||||
});
|
|
||||||
childD.on('exit', function() {
|
|
||||||
callback && callback(mp3_url);
|
|
||||||
});
|
|
||||||
childD.stdin.end();
|
|
||||||
break;
|
|
||||||
case 'linux':
|
|
||||||
// bash
|
|
||||||
var proc = require('child_process');
|
|
||||||
var commands = [
|
|
||||||
// TTS-Schnittstelle SVOX PicoTTS
|
|
||||||
'-c', `
|
|
||||||
pico2wave --lang=de-DE --wave=` + wav_tts + ` \"` + tts_text + `\"
|
|
||||||
ffmpeg -nostats -hide_banner -loglevel 0 -y -i ` + wav_tts + ` -vn -ar 44100 -ac 2 -ab 128k -f mp3 ` + mp3_tmp + `
|
|
||||||
ffmpeg -nostats -hide_banner -loglevel 0 -y -i \"concat:` + mp3_bell + `|` + mp3_tmp + `\" -acodec copy ` + mp3_tts + `
|
|
||||||
rm ` + wav_tts + `
|
|
||||||
rm ` + mp3_tmp
|
|
||||||
];
|
|
||||||
var options = {
|
|
||||||
shell: true
|
|
||||||
};
|
|
||||||
console.log(commands);
|
|
||||||
var childD = proc.spawn('/bin/sh', commands);
|
|
||||||
childD.stdin.setEncoding('ascii');
|
|
||||||
childD.stderr.setEncoding('ascii');
|
|
||||||
childD.stderr.on('data', function(data) {
|
|
||||||
sql.db_log('Fehler-TTS', data);
|
|
||||||
callback && callback(null);
|
|
||||||
});
|
|
||||||
childD.on('exit', function() {
|
|
||||||
callback && callback(mp3_url);
|
|
||||||
});
|
|
||||||
childD.stdin.end();
|
|
||||||
break;
|
|
||||||
// } else {
|
|
||||||
default:
|
|
||||||
sql.db_log('Fehler-TTS', 'TTS für dieses Server-Betriebssystem nicht verfügbar');
|
|
||||||
callback && callback(null);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Aufräumen (alle 10 Sekunden)
|
|
||||||
setInterval(function() {
|
|
||||||
// alle User-Einstellungen prüfen und ggf. Standby senden
|
|
||||||
sql.db_get_sockets_to_standby(function(socket_ids){
|
|
||||||
if (socket_ids) {
|
|
||||||
socket_ids.forEach(function(row) {
|
|
||||||
io.sockets.to(row.socket_id).emit('io.standby', null);
|
|
||||||
io.sockets.to(row.socket_id).emit('io.stopaudio', null);
|
|
||||||
sql.db_log('WAIP', 'Standby an Socket ' + row.socket_id + ' gesendet');
|
|
||||||
sql.db_update_client_status(io.sockets.sockets[row.socket_id], null);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// Nach alten Einsaetzen suchen und diese ggf. loeschen
|
|
||||||
sql.db_get_alte_einsaetze(app_cfg.global.time_to_delete_waip, function(waip_id) {
|
|
||||||
if (waip_id) {
|
|
||||||
sql.db_log('WAIP', 'Einsatz mit der ID ' + waip_id + ' ist veraltet und kann gelöscht werden.')
|
|
||||||
//beteiligte Wachen ermitteln
|
|
||||||
sql.db_get_einsatzwachen(waip_id, function(data) {
|
|
||||||
if (data) {
|
|
||||||
data.forEach(function(row) {
|
|
||||||
// fuer jede Wache(row.room) die verbundenen Sockets(Clients) ermitteln und Standby senden
|
|
||||||
var room_stockets = io.sockets.adapter.rooms[row.room];
|
|
||||||
if (typeof room_stockets !== 'undefined') {
|
|
||||||
Object.keys(room_stockets.sockets).forEach(function(socketId) {
|
|
||||||
// Standby senden
|
|
||||||
// TODO: Standby nur senden, wenn kein anderer (als der zu löschende) Einsatz angezeigt wird
|
|
||||||
sql.db_check_client_waipid(socketId, waip_id, function(same_id) {
|
|
||||||
if (same_id) {
|
|
||||||
io.sockets.to(socketId).emit('io.standby', null);
|
|
||||||
io.sockets.to(socketId).emit('io.stopaudio', null);
|
|
||||||
sql.db_log('WAIP', 'Standby an Socket ' + socketId + ' gesendet');
|
|
||||||
sql.db_update_client_status(io.sockets.sockets[socketId], null);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// Einsatz löschen
|
|
||||||
sql.db_log('WAIP', 'Einsatz ' + waip_id + ' wird gelöscht');
|
|
||||||
sql.db_einsatz_loeschen(waip_id);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// TODO: löschen alter Sounddaten nach alter (15min) und socket-id (nicht mehr verbunden)
|
|
||||||
// TODO: Löschen alter Einstze nach 24 h
|
|
||||||
// alte mp3s loeschen
|
|
||||||
const fs = require('fs');
|
|
||||||
fs.readdirSync(process.cwd() + app_cfg.global.soundpath).forEach(file => {
|
|
||||||
// nur die mp3s von alten clients loeschen
|
|
||||||
if (file.substring(0, 4) != 'bell' && file.substring(file.length - 3) == 'mp3' && file.substring(file.length - 8) != '_tmp.mp3') {
|
|
||||||
sql.db_get_socket_by_id(file.substring(0, file.length - 4), function(data) {
|
|
||||||
if (!data) {
|
|
||||||
fs.unlink(process.cwd() + app_cfg.global.soundpath + file, function(err) {
|
|
||||||
if (err) return sql.db_log('Fehler-WAIP', err);
|
|
||||||
sql.db_log('WAIP', file + ' wurde erfolgreich geloescht');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
// TODO: Funktion um Clients "neuzustarten" (Seite remote neu laden)
|
|
||||||
|
|
||||||
return {
|
|
||||||
einsatz_speichern: einsatz_speichern
|
|
||||||
};
|
|
||||||
};
|
|
||||||
19
views/about.pug
Normal file
19
views/about.pug
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
main(role='main')
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
.jumbotron.text-center
|
||||||
|
h1.display-1.text-danger.font-weight-bold.d-none.d-lg-block= public.app_name
|
||||||
|
h1.text-danger.font-weight-bold.d-lg-none= public.app_name
|
||||||
|
hr.my-4
|
||||||
|
.lead
|
||||||
|
h4.text-info Entwickelt von Robert Richter
|
||||||
|
p Alle Rechte vorbehalten
|
||||||
|
br
|
||||||
|
p.text-muted
|
||||||
|
| mehr Informationen unter
|
||||||
|
a(href="https://github.com/Robert-112/Wachalarm-IP-Web") https://github.com/Robert-112/Wachalarm-IP-Web
|
||||||
|
.display-4.text-muted.ion-logo-github
|
||||||
@ -1,7 +1,4 @@
|
|||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
append head
|
|
||||||
link(rel='stylesheet', href='/css/ionicons.min.css')
|
|
||||||
|
|
||||||
block content
|
block content
|
||||||
main(role='main')
|
main(role='main')
|
||||||
@ -42,7 +39,7 @@ block content
|
|||||||
p='IP-Adresse: ' + val.ip_address
|
p='IP-Adresse: ' + val.ip_address
|
||||||
.card-footer.text-right
|
.card-footer.text-right
|
||||||
button.btn.btn-primary.mx-2.ion-md-create(onclick='EditUser(this);', data-id=val.id, data-user=val.user, data-permissions=val.permissions, data-ip_address=val.ip_address) Bearbeiten
|
button.btn.btn-primary.mx-2.ion-md-create(onclick='EditUser(this);', data-id=val.id, data-user=val.user, data-permissions=val.permissions, data-ip_address=val.ip_address) Bearbeiten
|
||||||
form(action='/edit_users', method='POST', style='display:inline-block;')
|
form(action='/adm_edit_users', method='POST', style='display:inline-block;')
|
||||||
input(type='hidden', name='modal_method', value='DELETE')
|
input(type='hidden', name='modal_method', value='DELETE')
|
||||||
input(type='hidden', name='id', value=val.id)
|
input(type='hidden', name='id', value=val.id)
|
||||||
input(type='hidden', name='username', value=val.user)
|
input(type='hidden', name='username', value=val.user)
|
||||||
@ -56,7 +53,7 @@ block content
|
|||||||
button.close(type='button', data-dismiss='modal', aria-label='Close')
|
button.close(type='button', data-dismiss='modal', aria-label='Close')
|
||||||
span(aria-hidden='true') ×
|
span(aria-hidden='true') ×
|
||||||
.modal-body
|
.modal-body
|
||||||
form#formModal(action="/edit_users", method="POST", oninput='password2.setCustomValidity(password2.value != password.value ? "Passwörter stimmen nicht überein!" : "")')
|
form#formModal(action="/adm_edit_users", method="POST", oninput='password2.setCustomValidity(password2.value != password.value ? "Passwörter stimmen nicht überein!" : "")')
|
||||||
.form-group
|
.form-group
|
||||||
input#modal_method(type='hidden', name='modal_method', value='')
|
input#modal_method(type='hidden', name='modal_method', value='')
|
||||||
input#modal_id(type='hidden', name='modal_id', value='')
|
input#modal_id(type='hidden', name='modal_id', value='')
|
||||||
@ -1,7 +1,4 @@
|
|||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
append head
|
|
||||||
link(rel='stylesheet', href='/css/ionicons.min.css')
|
|
||||||
|
|
||||||
block content
|
block content
|
||||||
main(role='main')
|
main(role='main')
|
||||||
@ -19,7 +16,7 @@ block content
|
|||||||
.card.border-dark.mb-3.w-100
|
.card.border-dark.mb-3.w-100
|
||||||
.card-header Test-Alarm
|
.card-header Test-Alarm
|
||||||
.card-body.text-dark
|
.card-body.text-dark
|
||||||
form#test_alert1(action="/test_alert", method="POST")
|
form#test_alert1(action="/adm_run_alert", method="POST")
|
||||||
.form-group
|
.form-group
|
||||||
label(for='text_test_alert1') Alarmtext
|
label(for='text_test_alert1') Alarmtext
|
||||||
textarea#text_test_alert1.form-control(rows='5' type='text', name='test_alert') {"einsatzdaten":{"nummer":"0815","alarmzeit":"01.01.19&01:00","art":"Sonstiges","stichwort":"S:Testeinsatz","sondersignal":1,"besonderheiten":"DEMO Wachalarm-IP-Web - Testeinsatz","patient":""},"ortsdaten":{"ort":"Elsterwerda","ortsteil":"Biehla","strasse":"Haidaer Str. 47A","objekt":"","objektnr":"-1","objektart":"","wachfolge":"611302","wgs84_x":"52.471244","wgs84_y":"13.502943"},"alarmdaten":[{"typ":"ALARM","netzadresse":"","wachenname":"EE FW Elsterwerda","einsatzmittel":"FL EE 02/14-01","zeit_a":"18:41","zeit_b":"","zeit_c":""}]}
|
textarea#text_test_alert1.form-control(rows='5' type='text', name='test_alert') {"einsatzdaten":{"nummer":"0815","alarmzeit":"01.01.19&01:00","art":"Sonstiges","stichwort":"S:Testeinsatz","sondersignal":1,"besonderheiten":"DEMO Wachalarm-IP-Web - Testeinsatz","patient":""},"ortsdaten":{"ort":"Elsterwerda","ortsteil":"Biehla","strasse":"Haidaer Str. 47A","objekt":"","objektnr":"-1","objektart":"","wachfolge":"611302","wgs84_x":"52.471244","wgs84_y":"13.502943"},"alarmdaten":[{"typ":"ALARM","netzadresse":"","wachenname":"EE FW Elsterwerda","einsatzmittel":"FL EE 02/14-01","zeit_a":"18:41","zeit_b":"","zeit_c":""}]}
|
||||||
@ -1,10 +1,14 @@
|
|||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
append head
|
append head
|
||||||
link(rel='stylesheet', href='/css/datatables.min.css')
|
link(rel='stylesheet', href='/css/datatables.min.css')
|
||||||
script(src='/js/datatables.min.js')
|
script(src='/js/datatables.min.js')
|
||||||
script(src='/js/dataTables.bootstrap4.min.js')
|
script(src='/js/dataTables.bootstrap4.min.js')
|
||||||
|
|
||||||
|
// TODO: Seite mit aktiven Clients anpassen:
|
||||||
|
// - nicht zwingend als Tabelle, sondern eher als .col mit Buttons um Aktionen an Clients zu senden
|
||||||
|
// - einzelnen Client über Verwaltungsoberfläche neu laden lassen
|
||||||
|
|
||||||
block content
|
block content
|
||||||
main(role='main')
|
main(role='main')
|
||||||
.container
|
.container
|
||||||
@ -1,4 +1,4 @@
|
|||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
append head
|
append head
|
||||||
link(rel='stylesheet', href='/css/datatables.min.css')
|
link(rel='stylesheet', href='/css/datatables.min.css')
|
||||||
@ -1,4 +1,4 @@
|
|||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
block content
|
block content
|
||||||
main(role='main')
|
main(role='main')
|
||||||
@ -9,7 +9,8 @@ block content
|
|||||||
.col-12
|
.col-12
|
||||||
ol
|
ol
|
||||||
each val in dataSet
|
each val in dataSet
|
||||||
li= val.einsatzart + ', ' + val.stichwort + ', ' + val.ort + ' ' + val.ortsteil
|
li= val.einsatzart + ', ' + val.stichwort + ', ' + val.ort + ' ' + val.ortsteil
|
||||||
|
a(href="/rmld/" + val.uuid)= val.uuid
|
||||||
ul
|
ul
|
||||||
if val.a
|
if val.a
|
||||||
each val_a in (val.a).split(",")
|
each val_a in (val.a).split(",")
|
||||||
17
views/dbrd.pug
Executable file
17
views/dbrd.pug
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
append head
|
||||||
|
link(rel='stylesheet', href='/css/leaflet.css')
|
||||||
|
|
||||||
|
block content
|
||||||
|
include includes/modal_info
|
||||||
|
.container-fluid
|
||||||
|
include includes/master_dashboard
|
||||||
|
script(src='/socket.io/socket.io.js')
|
||||||
|
script(src='/js/leaflet.js')
|
||||||
|
script.
|
||||||
|
dbrd_uuid='#{dbrd_uuid}'
|
||||||
|
map_tile='#{map_tile}'
|
||||||
|
map_attribution='!{map_attribution}'
|
||||||
|
client_id="#{app_id}"
|
||||||
|
script(src='/js/client_dbrd.js')
|
||||||
@ -4,20 +4,11 @@ block content
|
|||||||
main(role='main')
|
main(role='main')
|
||||||
.container
|
.container
|
||||||
.row
|
.row
|
||||||
.col-12
|
.col
|
||||||
.card.border-warning
|
.jumbotron.text-center
|
||||||
.card-header
|
h1.display-1.font-weight-bold= error.status
|
||||||
h1= error.status
|
p.text-muted Es ist ein Fehler aufgetreten
|
||||||
.card-body
|
hr.my-4
|
||||||
.card-title
|
.lead
|
||||||
h5.ion-md-bug= " Fehler - " +message
|
h4.text-danger= message
|
||||||
pre.text-monospace
|
.display-4.text-muted.ion-ios-bug
|
||||||
|
|
|
||||||
| __/\\\\\\\\\\\\\\\____/\\\\\\\\\________/\\\\\\\\\___________/\\\\\_________/\\\\\\\\\_____
|
|
||||||
| _\/\\\///////////___/\\\///////\\\____/\\\///////\\\_______/\\\///\\\_____/\\\///////\\\___
|
|
||||||
| _\/\\\_____________\/\\\_____\/\\\___\/\\\_____\/\\\_____/\\\/__\///\\\__\/\\\_____\/\\\___
|
|
||||||
| _\/\\\\\\\\\\\_____\/\\\\\\\\\\\/____\/\\\\\\\\\\\/_____/\\\______\//\\\_\/\\\\\\\\\\\/____
|
|
||||||
| _\/\\\///////______\/\\\//////\\\____\/\\\//////\\\____\/\\\_______\/\\\_\/\\\//////\\\____
|
|
||||||
| _\/\\\_____________\/\\\____\//\\\___\/\\\____\//\\\___\//\\\______/\\\__\/\\\____\//\\\___
|
|
||||||
| _\/\\\_____________\/\\\_____\//\\\__\/\\\_____\//\\\___\///\\\__/\\\____\/\\\_____\//\\\__
|
|
||||||
| _\/\\\\\\\\\\\\\\\_\/\\\______\//\\\_\/\\\______\//\\\____\///\\\\\/_____\/\\\______\//\\\_
|
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
extends layout
|
|
||||||
|
|
||||||
block content
|
|
||||||
main(role='main')
|
|
||||||
.container.h-100
|
|
||||||
.row.justify-content-center.h-100.d-flex
|
|
||||||
.col-md-8
|
|
||||||
.card.text-center
|
|
||||||
h1.card-header Wachalarm-IP-Web
|
|
||||||
.card-body
|
|
||||||
p Entwickelt von Robert Richter
|
|
||||||
p Alle Rechte vorbehalten
|
|
||||||
br
|
|
||||||
p
|
|
||||||
| mehr Informationen unter
|
|
||||||
a(href="https://github.com/Robert-112/Wachalarm-IP-Web") https://github.com/Robert-112/Wachalarm-IP-Web
|
|
||||||
100
views/home.pug
100
views/home.pug
@ -3,67 +3,63 @@ extends layout
|
|||||||
block content
|
block content
|
||||||
main(role='main')
|
main(role='main')
|
||||||
.jumbotron
|
.jumbotron
|
||||||
.container
|
.container
|
||||||
h1.text-danger.display-3 Wachalarm-IP-Web
|
h1.text-danger.display-4= public.app_name
|
||||||
p Dieser Webdienst zeigt Wachalarme im Vollbild an (inkl. synthetischer Sprachdurchsage und Karte).
|
h5.text-muted © #{public.company}
|
||||||
p Nachfolgend können Sie aus einer der aufgeführten Wachen auswählen. Entsprechend Ihrer Berechtigungen werden Ihnen auf dem Alarmmonitor alle oder nur ausgewählte Einsatzdaten angezeigt.
|
hr
|
||||||
|
a Dieser Webdienst zeigt Wachalarme im Vollbild an (inkl. synthetischer Sprachdurchsage und Karte).
|
||||||
|
br
|
||||||
|
a Zusätzlich besteht für Einsatzkräfte die Möglichkeit zur einfachen Rückmeldung.
|
||||||
.container
|
.container
|
||||||
.row
|
.row
|
||||||
.col-md-12
|
.col-12
|
||||||
.card
|
.border-top.mx-3.mb-3
|
||||||
if !user
|
.col-12.col-md-4.d-flex.align-self-stretch.p-3
|
||||||
|
.card.w-100.h-100
|
||||||
|
.card-header.text-center
|
||||||
|
.display-2.ion-md-desktop
|
||||||
|
h4.text-danger Alarmmonitor
|
||||||
|
.card-body
|
||||||
|
p Zeigt Wachalarme inkl. eingehender Rückmeldungen im Vollbild an. Es können verschiedene Monitore ausgewählt werden.
|
||||||
|
.card-footer.text-center
|
||||||
|
a.btn.btn-outline-info.ion-md-arrow-round-forward(href='/waip/', role='button') Alarmmonitor aufrufen
|
||||||
|
.col-12.col-md-4.d-flex.align-self-stretch.p-3
|
||||||
|
.card.w-100.h-100.bg-dark
|
||||||
|
.card-header.text-center
|
||||||
|
.display-2.ion-md-clipboard
|
||||||
|
h4.text-danger Dashboard
|
||||||
|
.card-body
|
||||||
|
p Zeigt eine Gesamtübersicht pro Einsatz an und bietet detailierte Informationen über die alarmierten Kräfte inkl. deren Rückmeldungen.
|
||||||
|
.card-footer.text-center
|
||||||
|
a.btn.btn-outline-info.ion-md-arrow-round-forward(href='/dbrd/', role='button') Dashboard aufrufen
|
||||||
|
.col-12.col-md-4.d-flex.align-self-stretch.p-3
|
||||||
|
.card.w-100.h-100
|
||||||
|
.card-header.text-center
|
||||||
|
.display-2.ion-md-paper-plane
|
||||||
|
h4.text-warning Rückmeldung
|
||||||
|
.card-body
|
||||||
|
p Mithilfe der Rückmeldefunktion können Einsatzkräfte mitteilen ob und in welcher Funktion Sie am Einsatz teilnehmen.
|
||||||
|
p.text-muted Details zur Funktion erhalten Sie auf Anfrage bei der #{public.company}.
|
||||||
|
.col-12
|
||||||
|
.border-top.m-3
|
||||||
|
.col-12.p-3
|
||||||
|
if !user
|
||||||
|
.card.border-warning
|
||||||
.card-header
|
.card-header
|
||||||
h4.card-title.text-warning Sie sind nicht eingeloggt!
|
h4.card-title.text-warning Sie sind nicht angemeldet
|
||||||
.card-body
|
.card-body
|
||||||
p.card-text.text-muted Bitte melden Sie sich #[a(href="/login") hier] an.
|
p Auch ohne Anmeldung haben Sie Zugriff auf alle Funktionen, jedoch werden datenschutzrelevante Inhalte ausgeblendet.
|
||||||
else
|
p.text-muted Um mehr Funktionen nutzen zu können, melden Sie sich bitte #[a(href="/login") hier] an, sofern Sie über Zugangsdaten verfügen.
|
||||||
|
else
|
||||||
|
.card.bg-primary
|
||||||
.card-header
|
.card-header
|
||||||
h4.card-title.text-info='Sie sind als Nutzer \''+user.user+'\' angemeldet.'
|
h4.card-title.text-info='Sie sind als Nutzer \''+user.user+'\' angemeldet'
|
||||||
.card-body
|
.card-body
|
||||||
p.card-text Entsprechend Ihrer Berechtigungen haben Zugriff auf folgende Wachalarme:
|
p Entsprechend Ihrer Berechtigungen haben Sie vollen Zugriff auf folgende Wachalarme:
|
||||||
ul
|
ul
|
||||||
each val in user.permissions.split(',')
|
each val in user.permissions.split(',')
|
||||||
li
|
li
|
||||||
if user.permissions == 'admin'
|
if user.permissions == 'admin'
|
||||||
a.text-muted Sie sind Administrator und haben somit vollständigen Zugriff auf #[a(href="/waip/0") alle] Wachalarme
|
a Sie sind Administrator und haben somit vollständigen Zugriff auf #[a(href="/waip/0") alle] Wachalarme
|
||||||
else
|
else
|
||||||
a(href="/waip/" + val)= val
|
a(href="/waip/" + val)= val
|
||||||
.col-md-4.p-3
|
|
||||||
.card.h-100
|
|
||||||
.card-header
|
|
||||||
h1.text-info Wache
|
|
||||||
.card-body
|
|
||||||
p.text-muted Zeigt den Wachalarm einer der einzelnen Wache (z.B. Feuerwach, Rettungswache etc.) an.
|
|
||||||
.card-footer.text-right
|
|
||||||
.dropdown
|
|
||||||
button.btn.btn-info.dropdown-toggle(type='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
|
||||||
| bitte auswählen
|
|
||||||
.dropdown-menu
|
|
||||||
each item in list_wache
|
|
||||||
a.dropdown-item(href='/waip/'+ item.nr)= item.name
|
|
||||||
.col-md-4.p-3
|
|
||||||
.card.h-100
|
|
||||||
.card-header
|
|
||||||
h1.text-info Träger
|
|
||||||
.card-body
|
|
||||||
p.text-muted Zeigt alle Wachalarme der Wachen eines Trägers (Amt, amtsfreie Gemeinde, Stadt) an.
|
|
||||||
.card-footer.text-right
|
|
||||||
.dropdown
|
|
||||||
button.btn.btn-info.dropdown-toggle(type='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
|
||||||
| bitte auswählen
|
|
||||||
.dropdown-menu
|
|
||||||
each item in list_traeger
|
|
||||||
a.dropdown-item(href='/waip/'+ item.nr)= item.name
|
|
||||||
.col-md-4.p-3
|
|
||||||
.card.h-100
|
|
||||||
.card-header
|
|
||||||
h1.text-info Kreis
|
|
||||||
.card-body
|
|
||||||
p.text-muted Zeigt alle Wachalarme des gesamten Kreises (egal ob fü Feuerwehr oder Rettungsdienst) an.
|
|
||||||
.card-footer.text-right
|
|
||||||
.dropdown
|
|
||||||
button.btn.btn-info.dropdown-toggle(type='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
|
||||||
| bitte auswählen
|
|
||||||
.dropdown-menu
|
|
||||||
each item in list_kreis
|
|
||||||
a.dropdown-item(href='/waip/'+ item.nr)= item.name
|
|
||||||
|
|||||||
40
views/imprint.pug
Executable file
40
views/imprint.pug
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
main(role='main')
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
h1.display-1 Impressum
|
||||||
|
h2 Angaben gemäß § 5 TMG
|
||||||
|
p
|
||||||
|
| Robert Richter
|
||||||
|
br
|
||||||
|
| Am Mühlenteich 7
|
||||||
|
br
|
||||||
|
| 03099 Kolkwitz
|
||||||
|
br
|
||||||
|
h2 Kontakt
|
||||||
|
p
|
||||||
|
| Telefon: null eins fünf eins eins zwei vier fünf null acht vier sieben
|
||||||
|
br
|
||||||
|
| E-Mail: robertrichter87 [at] web.de
|
||||||
|
hr
|
||||||
|
h3 Haftung für Inhalte
|
||||||
|
p
|
||||||
|
| Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen.
|
||||||
|
p
|
||||||
|
| Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.
|
||||||
|
h3 Haftung für Links
|
||||||
|
p
|
||||||
|
| Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar.
|
||||||
|
p
|
||||||
|
| Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.
|
||||||
|
h3 Urheberrecht
|
||||||
|
p
|
||||||
|
| Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet.
|
||||||
|
p
|
||||||
|
| Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.
|
||||||
|
p.text-muted
|
||||||
|
| Quelle:
|
||||||
|
a(href='https://www.e-recht24.de/impressum-generator.html') https://www.e-recht24.de/impressum-generator.html
|
||||||
@ -1,3 +1,5 @@
|
|||||||
footer.footer
|
footer.footer
|
||||||
.container-fluid
|
.container-fluid
|
||||||
span.text-muted © Leitstelle Lausitz - #{new Date().getFullYear()}
|
.d-flex.justify-content-between
|
||||||
|
.span.text-muted.text-left © #{public.company} - #{new Date().getFullYear()}
|
||||||
|
.span.text-muted.text-right= public.version
|
||||||
|
|||||||
@ -1,36 +1,44 @@
|
|||||||
header
|
header
|
||||||
// Fixed navbar
|
// Fixed navbar
|
||||||
nav.navbar.navbar-expand-md.navbar-dark.bg-primary.fixed-top
|
nav.navbar.navbar-expand-lg.navbar-dark.bg-primary.fixed-top
|
||||||
a.navbar-brand(href='/') Wachalarm
|
a.navbar-brand(href='/')= public.app_name
|
||||||
button.navbar-toggler(type='button', data-toggle='collapse', data-target='#navbarCollapse', aria-controls='navbarColor01', aria-expanded='false', aria-label='Toggle navigation')
|
button.navbar-toggler(type='button', data-toggle='collapse', data-target='#navbarCollapse', aria-controls='navbarColor01', aria-expanded='false', aria-label='Toggle navigation')
|
||||||
span.navbar-toggler-icon
|
span.navbar-toggler-icon
|
||||||
#navbarCollapse.collapse.navbar-collapse
|
#navbarCollapse.collapse.navbar-collapse
|
||||||
ul.navbar-nav.mr-auto
|
ul.navbar-nav.mr-auto
|
||||||
li.nav-item(class=(title == 'Startseite') ? 'active' : null)
|
li.nav-item(class=(title == 'Startseite') ? 'active' : null)
|
||||||
a.nav-link.ion-md-home(href='/') Start
|
a.text-nowrap.nav-link.ion-md-home(href='/') Startseite
|
||||||
li.nav-item(class=(title == 'Alarmmonitor') ? 'active' : null)
|
li.nav-item(class=(title == 'Alarmmonitor') ? 'active' : null)
|
||||||
a.nav-link.ion-md-desktop(href='/waip') Alarmmonitor
|
a.text-nowrap.nav-link.ion-md-desktop(href='/waip') Alarmmonitor
|
||||||
li.nav-item(class=(title == 'Hilfe') ? 'active' : null)
|
li.nav-item(class=(title == 'Dashboard') ? 'active' : null)
|
||||||
a.nav-link.ion-md-help-buoy(href='/help') Hilfe
|
a.text-nowrap.nav-link.ion-md-clipboard(href='/dbrd') Dashboard
|
||||||
ul.navbar-nav.ml-auto
|
ul.navbar-nav.ml-auto
|
||||||
|
li.text-nowrap.nav-item.dropdown
|
||||||
|
a#navbarWeiteresDropdown.text-nowrap.nav-link.dropdown-toggle.ion-md-information-circle-outline(href='#', role='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
||||||
|
| Info
|
||||||
|
.dropdown-menu(aria-labelledby='navbarWeiteresDropdown')
|
||||||
|
a.text-nowrap.dropdown-item(href='/impressum') Impressum
|
||||||
|
a.text-nowrap.dropdown-item(href='/datenschutz') Datenschutzerkläung
|
||||||
|
.dropdown-divider
|
||||||
|
a.text-nowrap.dropdown-item(href='/about') Über diese Anwendung
|
||||||
if user
|
if user
|
||||||
if user.permissions == 'admin'
|
if user.permissions == 'admin'
|
||||||
li.nav-item.dropdown
|
li.text-nowrap.nav-item.dropdown
|
||||||
a#navbarDropdown.nav-link.dropdown-toggle(href='#', role='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
a#navbarAdminDropdown.text-nowrap.nav-link.dropdown-toggle.ion-md-build(href='#', role='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
||||||
| Administration
|
| Administration
|
||||||
.dropdown-menu(aria-labelledby='navbarDropdown')
|
.dropdown-menu(aria-labelledby='navbarAdminDropdown')
|
||||||
a.dropdown-item.ion-md-contacts(href='/edit_users') Benutzer und Rechte verwalten
|
a.text-nowrap.dropdown-item.ion-md-contacts(href='/adm_edit_users') Benutzer und Rechte verwalten
|
||||||
.dropdown-divider
|
.dropdown-divider
|
||||||
a.dropdown-item(href='/show_active_user') Verbundene PCs/Benutzer
|
a.text-nowrap.dropdown-item.ion-md-globe(href='/adm_show_clients') Verbundene PCs und Benutzer anzeigen
|
||||||
a.dropdown-item(href='/show_active_waip') laufende Einsätze
|
a.text-nowrap.dropdown-item.ion-md-list(href='/adm_show_missions') laufende Einsätze anzeigen
|
||||||
.dropdown-divider
|
.dropdown-divider
|
||||||
a.dropdown-item.text-danger.ion-md-warning(href='/test_alert') Test-Alarm
|
a.text-nowrap.dropdown-item.text-danger.ion-md-warning(href='/adm_run_alert') Test-Alarm versenden
|
||||||
a.dropdown-item.ion-md-document(href='/show_log') Log-Datei
|
a.text-nowrap.dropdown-item.ion-md-book(href='/adm_show_log') Log-Datei einsehen
|
||||||
li.nav-item.pr-3(class=(title == 'Einstellungen') ? 'active' : null)
|
li.nav-item.pr-3(class=(title == 'Einstellungen') ? 'active' : null)
|
||||||
a.ion-md-settings.nav-link(href='/config') Einstellungen
|
a.text-nowrap.ion-md-settings.nav-link(href='/config') Einstellungen
|
||||||
li.nav-item
|
li.nav-item
|
||||||
form(action='/logout', method='POST')
|
form(action='/logout', method='POST')
|
||||||
button.btn.btn-outline-warning.ion-md-log-out(type='submit')=' \''+user.user +'\' abmelden'
|
button.btn.btn-dark.text-nowrap.ion-md-log-out(type='submit')=' \''+user.user +'\' abmelden'
|
||||||
else
|
else
|
||||||
li.nav-item(class=(title == 'Login') ? 'active' : null)
|
li.nav-item(class=(title == 'Login') ? 'active' : null)
|
||||||
a.nav-link.ion-md-log-in(href='/login') Anmelden
|
a.text-nowrap.nav-link.ion-md-log-in(href='/login') Anmelden
|
||||||
|
|||||||
325
views/includes/master_dashboard.pug
Executable file
325
views/includes/master_dashboard.pug
Executable file
@ -0,0 +1,325 @@
|
|||||||
|
script(type='text/javascript', src='/js/vis-timeline.min.js')
|
||||||
|
link(rel='stylesheet', href='/css/vis-timeline.css')
|
||||||
|
style(type='text/css').
|
||||||
|
#visualization {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/*border: 1px solid lightgray;*/
|
||||||
|
}
|
||||||
|
.vis-item.ek {
|
||||||
|
background-color: #00bc8c;
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
.vis-item.ma {
|
||||||
|
background-color: #3498DB;
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
.vis-item.fk {
|
||||||
|
background-color: #adb5bd;
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
.vis-item.ek-agt {
|
||||||
|
background-color: #00bc8c;
|
||||||
|
border-color: #F39C12;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
.vis-item.ma-agt {
|
||||||
|
background-color: #3498DB;
|
||||||
|
border-color: #F39C12;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
.vis-item.fk-agt {
|
||||||
|
background-color: #adb5bd;
|
||||||
|
border-color: #F39C12;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
.vis-item, .vis-inner, .vis-time-axis .vis-text {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.vis-timeline {
|
||||||
|
/*border: 1px solid #444;*/
|
||||||
|
background: #303030;
|
||||||
|
}
|
||||||
|
.vis-time-axis .vis-grid.vis-minor {
|
||||||
|
border-color: #444;
|
||||||
|
}
|
||||||
|
.vis-current-time {
|
||||||
|
background: #E74C3C;
|
||||||
|
}
|
||||||
|
.vis-custom-time {
|
||||||
|
background: #3498DB;
|
||||||
|
}
|
||||||
|
/*.vis-custom-time > .vis-custom-time-marker*/
|
||||||
|
.vis-custom-time-marker {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
.vis-rolling-mode-btn:before {
|
||||||
|
content: "\2B8C";
|
||||||
|
}
|
||||||
|
.row
|
||||||
|
.col-12.d-flex.justify-content-between.flex-wrap
|
||||||
|
.d-flex.justify-content-start
|
||||||
|
.text-muted Alarmierung:
|
||||||
|
#einsatz_datum.text-muted.text-right 2345
|
||||||
|
.d-flex.justify-content-end
|
||||||
|
#dbrd_id.text-secondary 2341234345453
|
||||||
|
|
||||||
|
.row
|
||||||
|
//.col-12.text-center.p-3
|
||||||
|
h2.rounded.bg-danger Einsatzübersicht
|
||||||
|
.col-lg-4.col-12
|
||||||
|
.row.no-gutters
|
||||||
|
.col-10.mt-2
|
||||||
|
#einsatz_art.align-items-center.font-weight-bold.rounded.bg-secondary.p-3.mr-2
|
||||||
|
#einsatz_stichwort.ion-md-apps -Stichwort-
|
||||||
|
.col-2.mt-2
|
||||||
|
.align-items-center.justify-content-center.rounded.bg-secondary.text-info.p-3.text-center
|
||||||
|
#sondersignal.ion-md-apps
|
||||||
|
div.border-top.m-3
|
||||||
|
.row
|
||||||
|
.col-lg-12.col-md-6.col-12
|
||||||
|
.card.mt-2
|
||||||
|
.card-body.p-0
|
||||||
|
#map.rounded(style={height: '30em'})
|
||||||
|
div.border-top.m-3.d-md-none.d-lg-block
|
||||||
|
.col-lg-12.col-md-6.col-12
|
||||||
|
.card.mt-2
|
||||||
|
.card-header.bg-dark.px-3
|
||||||
|
.text-info.font-weight-bold Einsatzort
|
||||||
|
.card-body.p-0
|
||||||
|
ul#einsatzort_list.list-group.list-group-flush
|
||||||
|
li.list-group-item -Objekt-
|
||||||
|
li.list-group-item -Ort-
|
||||||
|
li.list-group-item -Orststeil-
|
||||||
|
li.list-group-item -Straße Hsnr-
|
||||||
|
li.list-group-item.text-warning -Besonderheiten-
|
||||||
|
div.border-top.mx-3.mt-3.mb-2.d-block.d-lg-none
|
||||||
|
|
||||||
|
|
||||||
|
//.col-12
|
||||||
|
div.border-top.my-3
|
||||||
|
.card.bg-secondary.mt-2
|
||||||
|
.card-header.bg-light.p-2
|
||||||
|
//h5.text-info.font-weight-bold CB FW Cottbus 1
|
||||||
|
div.border-top.my-3.border-warning
|
||||||
|
.card-body.p-1
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 00/00-00
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/00-00
|
||||||
|
div.p-2.badge.badge-warning 3
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB T-Dienst
|
||||||
|
div.p-2.badge.badge-danger 4
|
||||||
|
.card.bg-secondary.mt-2
|
||||||
|
.card-header.bg-light.p-2
|
||||||
|
h5.text-info.font-weight-bold CB FW Madlow
|
||||||
|
.card-body.p-1
|
||||||
|
p Alarmierte Einsatzmittel
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 12/00-00
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL SPN 00/00-00
|
||||||
|
div.p-2.badge.badge-info 1
|
||||||
|
.card.bg-secondary.mt-2
|
||||||
|
.card-header.bg-light.p-2
|
||||||
|
h5.text-info.font-weight-bold CB FW Cottbus 3
|
||||||
|
.card-body.p-1
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 KAT CB 00/00-00
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
//table.table.table-striped
|
||||||
|
tbody
|
||||||
|
tr
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL CB 00/00-00
|
||||||
|
div.badge.badge-success 2
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL CB 12/00-00
|
||||||
|
div.badge.badge-warning 3
|
||||||
|
tr
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL CB T-Dienst
|
||||||
|
div.badge.badge-danger 4
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div KAT CB 00/00-00
|
||||||
|
div.badge.badge-success 2
|
||||||
|
tr
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL SPN 00/00-00
|
||||||
|
div.badge.badge-info 1
|
||||||
|
.col-lg-8.col-12
|
||||||
|
.row.no-gutters
|
||||||
|
.col-12
|
||||||
|
//.card.bg-dark.mt-2
|
||||||
|
.card-header.bg-secondary.p-2
|
||||||
|
h5.text-danger.text-center Alarmierte Einsatzmittel
|
||||||
|
.card-body.p-1
|
||||||
|
.card.mt-2
|
||||||
|
table#table_einsatzmittel.table.table-hover
|
||||||
|
thead.table-borderless
|
||||||
|
tr
|
||||||
|
th(scope='col').text-info.pl-3 Wache
|
||||||
|
th(scope='col').text-info.pl-3 Einsatzmittel
|
||||||
|
tbody
|
||||||
|
tr
|
||||||
|
th(scope='row') CB FW Cottbus 1
|
||||||
|
td
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/82-01
|
||||||
|
div.p-2.badge.badge-warning 3
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/71-01
|
||||||
|
div.p-2.badge.badge-danger 4
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/85-01
|
||||||
|
div.p-2.badge.badge-info 1
|
||||||
|
tr
|
||||||
|
th(scope='row') CB FW Madlow
|
||||||
|
td
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 11/23-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 12/46-01
|
||||||
|
div.p-2.badge.badge-warning 3
|
||||||
|
//.card.bg-dark.mt-2
|
||||||
|
.card-header.bg-secondary.p-2
|
||||||
|
h5.text-danger.text-center Alarmierte Einsatzmittel
|
||||||
|
.card-body.p-1
|
||||||
|
.row
|
||||||
|
.col-3
|
||||||
|
div.border-right CB FW Cottbus 1
|
||||||
|
.col-9
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/82-01
|
||||||
|
div.p-2.badge.badge-warning 3
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/71-01
|
||||||
|
div.p-2.badge.badge-danger 4
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/85-01
|
||||||
|
div.p-2.badge.badge-info 2
|
||||||
|
.card-body.p-1
|
||||||
|
.row
|
||||||
|
.col-3
|
||||||
|
CB FW Madlow
|
||||||
|
.col-9
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 11/23-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-secondary.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 12/46-01
|
||||||
|
div.p-2.badge.badge-warning 3
|
||||||
|
div.border-top.m-3
|
||||||
|
.card
|
||||||
|
.card-header.bg-dark.px-3
|
||||||
|
.text-info.font-weight-bold Einsatzrückmeldungen
|
||||||
|
.card-body.p-2#rmld_container
|
||||||
|
.d-flex.fustify-content-between.font-weight-bold
|
||||||
|
.list-group.list-group-horizontal.text-center.w-100
|
||||||
|
.list-group-item.flex-fill.text-success
|
||||||
|
a#ek-counter 0
|
||||||
|
a EK
|
||||||
|
.list-group-item.flex-fill.text-info
|
||||||
|
a#ma-counter 0
|
||||||
|
a MA
|
||||||
|
.list-group-item.flex-fill.text-light
|
||||||
|
a#fk-counter 0
|
||||||
|
a FK
|
||||||
|
.list-group.text-center
|
||||||
|
.list-group-item.border.border-warning.flex-fill.text-warning
|
||||||
|
a#agt-counter 0
|
||||||
|
a AGT
|
||||||
|
//a.badge.badge-warning 2 AGT
|
||||||
|
.row
|
||||||
|
.col-4#pg-ek.pr-1
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-success(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100')
|
||||||
|
a(style='') 2min
|
||||||
|
//.progress.mt-1.border.border-warning(style='height: 20px;')
|
||||||
|
.progress-bar.progress-bar-striped.bg-success(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100')
|
||||||
|
h 2min
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-success.ion-md-checkmark-circle(role='progressbar', style='width: 100%', aria-valuenow='100', aria-valuemin='0', aria-valuemax='100')
|
||||||
|
.col-4#pg-ma.px-1
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-info(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100') 3min
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-info(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100') 1min
|
||||||
|
.col-4#pg-fk.pl-1
|
||||||
|
//.progress.mt-1.border.border-warning
|
||||||
|
.progress-bar.progress-bar-striped.bg-light(role='progressbar', style='width: 50%', aria-valuenow='50', aria-valuemin='0', aria-valuemax='100') 10min
|
||||||
|
.card-body.p-2
|
||||||
|
#visualization.border.rounded(style='background-color:white')
|
||||||
|
//div.border-top.m-3
|
||||||
|
//.card.bg-dark.mt-2
|
||||||
|
.card-header.bg-secondary.p-2
|
||||||
|
h5.text-danger.text-center CB FW Madlow
|
||||||
|
|
||||||
|
//.card-body.p-2
|
||||||
|
#visualization2.border.rounded(style='background-color:white')
|
||||||
|
//.card-body.p-2
|
||||||
|
.row
|
||||||
|
.col-10
|
||||||
|
#rueckmeldung.list-group.list-group-horizontal.text-center
|
||||||
|
a.list-group-item.list-group-item-warning.flex-fill.text-info 1 EK
|
||||||
|
a.list-group-item.list-group-item-light.flex-fill.text-danger 1 MA
|
||||||
|
a.list-group-item.list-group-item-light.flex-fill 0 FK
|
||||||
|
.col-2
|
||||||
|
a.bg-warning.rounded.text-dark 0 AGT
|
||||||
|
//.col-12
|
||||||
|
div.border-top.m-3
|
||||||
|
.card.bg-dark.mt-2
|
||||||
|
.card-header.bg-secondary.p-2
|
||||||
|
h5.text-center.text-warning Zusammenfassung
|
||||||
|
.card-body.p-1
|
||||||
|
#rueckmeldung.list-group.list-group-horizontal.text-center.font-weight-bold
|
||||||
|
h3.list-group-item.flex-fill.text-info 5 EK
|
||||||
|
h3.list-group-item.flex-fill.text-danger 2 MA
|
||||||
|
h3.list-group-item.flex-fill 0 FK
|
||||||
|
h3.list-group-item.list-group-item-light.flex-fill.text-dark 0 AGT
|
||||||
|
//button#rueckmeldung.btn.btn-danger.btn-lg.btn-block.ion-md-paper-plane(type='button') Rückmeldung senden
|
||||||
|
// TODO: zeitstrahl der den Ablauf anzeigt
|
||||||
|
.d-none
|
||||||
|
audio#audio(controls='')
|
||||||
|
source(src='', type='audio/mpeg')
|
||||||
|
|
||||||
148
views/includes/master_rueckmeldung.pug
Executable file
148
views/includes/master_rueckmeldung.pug
Executable file
@ -0,0 +1,148 @@
|
|||||||
|
.row.no-gutters
|
||||||
|
.col-12.d-flex.justify-content-between
|
||||||
|
p#einsatz_datum.text-muted 01.01.2020
|
||||||
|
p#einsatz_uhrzeit.text-muted.text-right 11:22:33
|
||||||
|
.col-10
|
||||||
|
case einsatzdaten.einsatzart
|
||||||
|
when 'Brandeinsatz'
|
||||||
|
.align-items-center.font-weight-bold.rounded.bg-danger.p-3.mr-2
|
||||||
|
.ion-md-flame #{' ' + einsatzdaten.stichwort}
|
||||||
|
when 'Hilfeleistungseinsatz'
|
||||||
|
.align-items-center.font-weight-bold.rounded.bg-info.p-3.mr-2
|
||||||
|
.ion-md-construct #{' ' + einsatzdaten.stichwort}
|
||||||
|
when 'Rettungseinsatz'
|
||||||
|
.align-items-center.font-weight-bold.rounded.bg-warning.p-3.mr-2
|
||||||
|
.ion-md-medkit #{' ' + einsatzdaten.stichwort}
|
||||||
|
when 'Krankentransport'
|
||||||
|
.align-items-center.font-weight-bold.rounded.bg-success.p-3.mr-2
|
||||||
|
.ion-md-medical #{' ' + einsatzdaten.stichwort}
|
||||||
|
when 'Sonstiges'
|
||||||
|
.align-items-center.font-weight-bold.rounded.bg-secondary.p-3.mr-2
|
||||||
|
.ion-md-information-circle #{' ' + einsatzdaten.stichwort}
|
||||||
|
default
|
||||||
|
.align-items-center.font-weight-bold.rounded.bg-light.p-3.mr-2
|
||||||
|
.ion-md-apps -Stichwort-
|
||||||
|
.col-2
|
||||||
|
.align-items-center.justify-content-center.rounded.bg-light.text-info.p-3
|
||||||
|
case einsatzdaten.sondersignal
|
||||||
|
when 1
|
||||||
|
.ion-md-notifications.text-center
|
||||||
|
when 0
|
||||||
|
.ion-md-notifications-off.text-center
|
||||||
|
default
|
||||||
|
.ion-md-apps.text-center
|
||||||
|
.col-12
|
||||||
|
div.border-top.m-3
|
||||||
|
.card.mt-2
|
||||||
|
.card-body.p-0
|
||||||
|
#map.rounded(style={height: '20em'})
|
||||||
|
.card-body.p-0
|
||||||
|
ul.list-group.list-group-flush
|
||||||
|
if einsatzdaten.objekt
|
||||||
|
li.list-group-item #{einsatzdaten.objekt}
|
||||||
|
if einsatzdaten.ort
|
||||||
|
li.list-group-item #{einsatzdaten.ort}
|
||||||
|
if einsatzdaten.ortsteil
|
||||||
|
li.list-group-item #{einsatzdaten.ortsteil}
|
||||||
|
if einsatzdaten.strasse
|
||||||
|
li.list-group-item #{einsatzdaten.strasse}
|
||||||
|
if einsatzdaten.besonderheiten
|
||||||
|
li.list-group-item.text-warning #{einsatzdaten.besonderheiten}
|
||||||
|
unless einsatzdaten
|
||||||
|
li.list-group-item -Objekt-
|
||||||
|
li.list-group-item -Ort-
|
||||||
|
li.list-group-item -Orststeil-
|
||||||
|
li.list-group-item -Straße Hsnr-
|
||||||
|
li.list-group-item.text-warning -Besonderheiten-
|
||||||
|
.col-12
|
||||||
|
div.border-top.m-3
|
||||||
|
.card.bg-secondary.mt-2
|
||||||
|
.card-header.bg-light.p-2
|
||||||
|
h5.text-danger.text-center Alarmierte Einsatzmittel
|
||||||
|
.card-body.p-1
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
each val in einsatzdaten.einsatzmittel
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 #{val.einsatzmittel}
|
||||||
|
unless val.status == null
|
||||||
|
case val.status
|
||||||
|
when '1'
|
||||||
|
div.p-2.badge.badge-info #{val.status}
|
||||||
|
when '2'
|
||||||
|
div.p-2.badge.badge-success #{val.status}
|
||||||
|
when '3'
|
||||||
|
div.p-2.badge.badge-warning #{val.status}
|
||||||
|
when '4'
|
||||||
|
div.p-2.badge.badge-danger #{val.status}
|
||||||
|
default
|
||||||
|
div.p-2.badge.badge-dark #{val.status}
|
||||||
|
//.col-12
|
||||||
|
div.border-top.my-3
|
||||||
|
.card.bg-secondary.mt-2
|
||||||
|
.card-header.bg-light.p-2
|
||||||
|
h5.text-info.font-weight-bold CB FW Cottbus 1
|
||||||
|
.card-body.p-1
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 00/00-00
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 01/00-00
|
||||||
|
div.p-2.badge.badge-warning 3
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB T-Dienst
|
||||||
|
div.p-2.badge.badge-danger 4
|
||||||
|
.card.bg-secondary.mt-2
|
||||||
|
.card-header.bg-light.p-2
|
||||||
|
h5.text-info.font-weight-bold CB FW Madlow
|
||||||
|
.card-body.p-1
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL CB 12/00-00
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 FL SPN 00/00-00
|
||||||
|
div.p-2.badge.badge-info 1
|
||||||
|
.card.bg-secondary.mt-2
|
||||||
|
.card-header.bg-light.p-2
|
||||||
|
h5.text-info.font-weight-bold CB FW Cottbus 3
|
||||||
|
.card-body.p-1
|
||||||
|
div.d-flex.flex-wrap.justify-content-between.align-items-center
|
||||||
|
div.flex-fill.rounded.bg-light.p-2.m-1
|
||||||
|
div.d-flex.justify-content-between
|
||||||
|
div.pr-2 KAT CB 00/00-00
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
//table.table.table-striped
|
||||||
|
tbody
|
||||||
|
tr
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL CB 00/00-00
|
||||||
|
div.badge.badge-success 2
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL CB 12/00-00
|
||||||
|
div.badge.badge-warning 3
|
||||||
|
tr
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL CB T-Dienst
|
||||||
|
div.badge.badge-danger 4
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div KAT CB 00/00-00
|
||||||
|
div.badge.badge-success 2
|
||||||
|
tr
|
||||||
|
th
|
||||||
|
div.d-flex.justify-content-between.align-items-center
|
||||||
|
div FL SPN 00/00-00
|
||||||
|
div.badge.badge-info 1
|
||||||
|
.col-12
|
||||||
|
div.border-top.m-3
|
||||||
|
button#rueckmeldung.btn.btn-danger.btn-lg.btn-block.ion-md-paper-plane(type='button') Rückmeldung senden
|
||||||
125
views/includes/master_wachalarm.pug
Normal file
125
views/includes/master_wachalarm.pug
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// BUG: Darstellung in Safari-Mobil fehlerhaft (generell Mobil, ggf. extra Darstellung)
|
||||||
|
#waiptableau
|
||||||
|
.row.no-gutters
|
||||||
|
#headline.col-12.d-flex.justify-content-between.py-1.text-muted
|
||||||
|
.btn-group.h-100.mr-1
|
||||||
|
label#replay.btn.btn-outline-light.m-0.py-0
|
||||||
|
.ion-md-play-circle
|
||||||
|
label#volume.btn.btn-outline-light.m-0.py-0
|
||||||
|
.ion-md-volume-high
|
||||||
|
#date-time || -Datum- - -Uhrzeit-
|
||||||
|
#wachenname.ion-md-business= data_wache || ' -Wachenname-'
|
||||||
|
//.col-6.h-5.d-flex.flex-row.align-items-center.justify-content-end.py-1.text-muted.tf_singleline
|
||||||
|
// TODO Information in Wachalarm-Bild ob alle Rechte, oder ob reduzierte Version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// BUG: Buttons für Sounds werden fehlerhaft dargestellt
|
||||||
|
//.col-6.h-5.d-flex.align-items-center.py-1.text-muted.tf_singleline
|
||||||
|
button#replay.btn.btn-outline-light.h-100.py-1
|
||||||
|
.ion-md-play-circle
|
||||||
|
button#volume.btn.btn-outline-light.h-100.mx-1
|
||||||
|
.ion-md-volume-high
|
||||||
|
#date-time
|
||||||
|
div -Datum- - -Uhrzeit-
|
||||||
|
//.col-6.h-5.d-flex.flex-row.align-items-center.justify-content-end.py-1.text-muted.tf_singleline
|
||||||
|
// TODO Information in Wachalarm-Bild ob alle Rechte, oder ob reduzierte Version
|
||||||
|
#wachenname.ion-md-business=data_wache || ' -Wachenname-'
|
||||||
|
.row.no-gutters.fullheight
|
||||||
|
.col-10.h-15.h-20_ls.pr-3
|
||||||
|
#einsatz_art.h-100.w-100.d-flex.align-items-center.font-weight-bold.p-3.rounded.bg-dark.tf_singleline
|
||||||
|
#einsatz_stichwort.ion-md-apps -Stichwort-
|
||||||
|
.col-2.h-15.h-20_ls.d-flex.align-items-center.justify-content-center.p-3.rounded.bg-dark.text-info.tf_singleline
|
||||||
|
#sondersignal.ion-md-apps
|
||||||
|
.col-12.col-5_ls.h-35.h-70_ls.pt-3_pt.ptr-3_ls
|
||||||
|
#map.h-100.rounded
|
||||||
|
.col-12.col-7_ls.h-45.h-70_ls
|
||||||
|
.row.no-gutters.h-100.pt-3
|
||||||
|
.col-12.h-20.h-100.w-100#rmld_container
|
||||||
|
// TODO: Rueckmedlung ohne Rueckmeldung ausbleden
|
||||||
|
.d-flex.fustify-content-between.font-weight-bold.h-30
|
||||||
|
.list-group.list-group-horizontal.text-center.w-100.h-100
|
||||||
|
.list-group-item.flex-fill.text-success.py-0.align-self-center
|
||||||
|
a#ek-counter 0
|
||||||
|
a EK
|
||||||
|
.list-group-item.flex-fill.text-info.py-0.align-self-center
|
||||||
|
a#ma-counter 0
|
||||||
|
a MA
|
||||||
|
.list-group-item.flex-fill.text-light.py-0.align-self-center
|
||||||
|
a#fk-counter 0
|
||||||
|
a FK
|
||||||
|
.list-group.list-group-horizontal.text-center.h-100
|
||||||
|
.list-group-item.flex-fill.rounded.border.border-warning.text-warning.py-0.align-self-center
|
||||||
|
a#agt-counter 0
|
||||||
|
a AGT
|
||||||
|
//a.badge.badge-warning 2 AGT
|
||||||
|
.row.h-70.pt-1
|
||||||
|
.col-4#pg-ek.pr-1
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-success(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100')
|
||||||
|
a(style='') 2min
|
||||||
|
//.progress.mt-1.border.border-warning(style='height: 20px;')
|
||||||
|
.progress-bar.progress-bar-striped.bg-success(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100')
|
||||||
|
h 2min
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-success.ion-md-checkmark-circle(role='progressbar', style='width: 100%', aria-valuenow='100', aria-valuemin='0', aria-valuemax='100')
|
||||||
|
.col-4#pg-ma.px-1
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-info(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100') 3min
|
||||||
|
//.progress.mt-1
|
||||||
|
.progress-bar.progress-bar-striped.bg-info(role='progressbar', style='width: 25%', aria-valuenow='25', aria-valuemin='0', aria-valuemax='100') 1min
|
||||||
|
.col-4#pg-fk.pl-1
|
||||||
|
//.progress.mt-1.border.border-warning
|
||||||
|
.progress-bar.progress-bar-striped.bg-light(role='progressbar', style='width: 50%', aria-valuenow='50', aria-valuemin='0', aria-valuemax='100') 10min
|
||||||
|
.col-6.h-60.d-flex.align-items-end.justify-content-start.tf_multiline
|
||||||
|
#ortsdaten.flex-fill -Objekt-
|
||||||
|
br
|
||||||
|
| -Ort-
|
||||||
|
br
|
||||||
|
| -Ortsteil-
|
||||||
|
br
|
||||||
|
| -Straße Hsnr-
|
||||||
|
//.col-6.h-65.d-flex.align-items-around.justify-content-end
|
||||||
|
#em_alarmiert.col-6.h-60.d-flex.flex-wrap.align-content-end
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB 01/42-01
|
||||||
|
div.p-2.badge.badge-success 2
|
||||||
|
div.rounded.bg-secondary.d-flex.justify-content-between.flex-fill.p-2.m-1
|
||||||
|
div.pr-2 FL CB Wachenname
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//ul#em_alarmiert.list-group
|
||||||
|
li.list-group-item.d-flex.justify-content-between.align-items-center -Einsatzmittel 1-
|
||||||
|
li.list-group-item.d-flex.justify-content-between.align-items-center -Einsatzmittel 2-
|
||||||
|
li.list-group-item.d-flex.justify-content-between.align-items-center -Einsatzmittel n-
|
||||||
|
// TODO: Status mit anzeigen (als .badge.badge-pill)
|
||||||
|
// TODO: auflistung vieler Fahrzeuge verbessern. flexfill
|
||||||
|
.col-12.h-5.d-flex.align-items-end.justify-content-center.text-muted.tf_singleline
|
||||||
|
#em_weitere -weiteres Einsatzmittel 1-, -weiteres Einsatzmittel 2-, -weiteres Einsatzmittel n-
|
||||||
|
.col-12.h-15.d-flex.align-items-center.rounded.bg-dark.font-weight-bold.text-info.tf_singleline
|
||||||
|
// TODO: Besonderheiten bei neuer Alarmierung neu in der größe angpassen
|
||||||
|
#besonderheiten -Besonderheiten-
|
||||||
|
.col-12.h-5.d-flex.align-items-end.justify-content-center.pt-3
|
||||||
|
.progress(style='height: 100%;').flex-fill
|
||||||
|
#hilfsfrist.progress-bar.progress-bar-striped.progress-bar-animated(role='progressbar', aria-valuenow='0', aria-valuemin='0', aria-valuemax='100', style='width: 0%')
|
||||||
|
audio#audio(controls='')
|
||||||
|
source(src='', type='audio/mpeg')
|
||||||
@ -1,35 +0,0 @@
|
|||||||
// Modal
|
|
||||||
#responseModal.modal.fade(tabindex='-1', role='dialog', aria-hidden='true')
|
|
||||||
.modal-dialog.modal-dialog-centered(role='document')
|
|
||||||
.modal-content
|
|
||||||
.modal-header
|
|
||||||
h3#responseModalTitle.modal-title.text-danger Einsatzrückmeldung
|
|
||||||
button.close(type='button', data-dismiss='modal', aria-label='Close')
|
|
||||||
span(aria-hidden='true') ×
|
|
||||||
#responseModalBody.modal-body
|
|
||||||
h4.text-info
|
|
||||||
| Aufgabenwahrnehmung
|
|
||||||
p Ich komme als:
|
|
||||||
.form-check
|
|
||||||
input#radios_res_ek.form-check-input(type='radio', name='radios_res', value='1')
|
|
||||||
label.form-check-label(for='radios_res_ek')
|
|
||||||
| Einsatzkraft
|
|
||||||
.form-check
|
|
||||||
input#radios_res_ma.form-check-input(type='radio', name='radios_res', value='1')
|
|
||||||
label.form-check-label(for='radios_res_ma')
|
|
||||||
| Maschinist
|
|
||||||
.form-check
|
|
||||||
input#radios_res_fk.form-check-input(type='radio', name='radios_res', value='1')
|
|
||||||
label.form-check-label(for='radios_res_fk')
|
|
||||||
| Führungskraft
|
|
||||||
br
|
|
||||||
p zum Einsatz.
|
|
||||||
hr
|
|
||||||
h4.text-info
|
|
||||||
| AGT
|
|
||||||
.form-check
|
|
||||||
input#cb_res_agt.form-check-input(type='checkbox', value='1')
|
|
||||||
label.form-check-label(for='cb_res_agt')
|
|
||||||
| Außerdem bin ich Atemschutzgeräteträger!
|
|
||||||
.modal-footer
|
|
||||||
button#send_response.btn.btn-warning(type='button', data-dismiss='modal') Senden
|
|
||||||
62
views/includes/modal_rmld.pug
Normal file
62
views/includes/modal_rmld.pug
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Modal
|
||||||
|
|
||||||
|
// if (!einsatzdaten) {
|
||||||
|
// var einsatzdaten = {};
|
||||||
|
// einsatzdaten.uuid = '0';
|
||||||
|
// einsatzdaten.wachen = {};
|
||||||
|
// einsatzdaten.wachen.waip_wachen_ID = 0;
|
||||||
|
// einsatzdaten.wachen.wachenname = '';
|
||||||
|
// }
|
||||||
|
|
||||||
|
#responseModal.modal.fade(tabindex='-1', role='dialog', aria-hidden='true')
|
||||||
|
.modal-dialog.modal-dialog-centered(role='document')
|
||||||
|
.modal-content
|
||||||
|
.modal-header
|
||||||
|
h3#responseModalTitle.modal-title.text-info Einsatzrückmeldung
|
||||||
|
button.close(type='button', data-dismiss='modal', aria-label='Close')
|
||||||
|
span(aria-hidden='true') ×
|
||||||
|
#responseModalBody.modal-body
|
||||||
|
form#send_response.was-validated(action=einsatzdaten.uuid, method="POST")
|
||||||
|
input(type="hidden" name="waip_uuid" value=einsatzdaten.uuid)
|
||||||
|
input(type="hidden" name="rmld_uuid" value=einsatzdaten.rmld_uuid)
|
||||||
|
.form-group
|
||||||
|
p.text-muted Ich komme als ...
|
||||||
|
.custom-control.custom-radio.form-control-lg
|
||||||
|
input#radios_res_ek.custom-control-input(type='radio', name='radio_efunction', value='ek', required='')
|
||||||
|
label.custom-control-label(for='radios_res_ek')
|
||||||
|
| Einsatzkraft
|
||||||
|
.custom-control.custom-radio.form-control-lg
|
||||||
|
input#radios_res_ma.custom-control-input(type='radio', name='radio_efunction', value='ma', required='')
|
||||||
|
label.custom-control-label(for='radios_res_ma')
|
||||||
|
| Maschinist
|
||||||
|
.custom-control.custom-radio.form-control-lg
|
||||||
|
input#radios_res_fk.custom-control-input(type='radio', name='radio_efunction', value='fk', required='')
|
||||||
|
label.custom-control-label(for='radios_res_fk')
|
||||||
|
| Führungskraft
|
||||||
|
.invalid-feedback wählen Sie eine Einsatzfunktion!
|
||||||
|
div.border-top.my-3
|
||||||
|
.form-group
|
||||||
|
.custom-control.custom-switch.form-control-lg
|
||||||
|
input#cb_res_agt.custom-control-input(type='checkbox', name='cb_agt', value='1')
|
||||||
|
label.custom-control-label.text-warning(for='cb_res_agt')
|
||||||
|
| und bin Atemschutzgeräteträger!
|
||||||
|
div.border-top.my-3
|
||||||
|
.form-group
|
||||||
|
label(for='eintreffzeit').text-muted in ungefähr ...
|
||||||
|
select#eintreffzeit.form-control.form-control-lg(name='eintreffzeit', required='')
|
||||||
|
option(value='') bitte Eintreffzeit wählen
|
||||||
|
option(value='5') 5 Minuten
|
||||||
|
option(value='10') 10 Minuten
|
||||||
|
option(value='15') 15 Minuten
|
||||||
|
option(value='20') 20 Minuten
|
||||||
|
.form-group
|
||||||
|
label(for='wachenauswahl').text-muted zur Wache ...
|
||||||
|
select#wachenauswahl.form-control.form-control-lg(name='wachenauswahl', required='')
|
||||||
|
option(value='') bitte Wache wählen
|
||||||
|
each val in einsatzdaten.wachen
|
||||||
|
option(value=val.waip_wachen_ID) #{val.wachenname}
|
||||||
|
//option(value='2') CB FW Cottbus 3
|
||||||
|
//option(value='3') CB FW Madlow
|
||||||
|
//option(value='4') CB FW Kieckebusch
|
||||||
|
.modal-footer
|
||||||
|
button.btn.btn-lg.btn-block.btn-warning.btn-outline-primary.p-3.ion-md-paper-plane(type='submit', form="send_response", value='submit') Rückmeldung absenden!
|
||||||
@ -1,46 +0,0 @@
|
|||||||
#waiptableau.fullheight.row.no-gutters
|
|
||||||
.col-6.h-5.d-flex.align-items-center.py-1.text-dark
|
|
||||||
button#replay.btn.btn-outline-dark.h-100.py-1.tf_singleline
|
|
||||||
.ion-md-play-circle
|
|
||||||
button#volume.btn.btn-outline-dark.h-100.mx-1.tf_singleline
|
|
||||||
.ion-md-volume-high
|
|
||||||
#date-time.
|
|
||||||
.tf_singleline -Datum- - -Uhrzeit-
|
|
||||||
.col-6.h-5.d-flex.flex-row.align-items-center.justify-content-end.py-1.text-dark.tf_singleline
|
|
||||||
#wachenname.ion-md-business=data_wache || ' -Wachenname-'
|
|
||||||
.col-10.h-15.h-20_ls.pr-3
|
|
||||||
#einsatz_art.h-100.w-100.d-flex.align-items-center.font-weight-bold.p-3.rounded.bg-light.tf_singleline
|
|
||||||
#einsatz_stichwort.ion-md-apps -Stichwort-
|
|
||||||
.col-2.h-15.h-20_ls.d-flex.align-items-center.justify-content-center.p-3.rounded.bg-light.text-info.tf_singleline
|
|
||||||
#sondersignal.ion-md-apps
|
|
||||||
.col-12.col-5_ls.h-35.h-70_ls.pt-3_pt.ptr-3_ls
|
|
||||||
#map.h-100.rounded
|
|
||||||
.col-12.col-7_ls.h-40.h-70_ls
|
|
||||||
.row.no-gutters.h-100.pt-3
|
|
||||||
.col-12.h-10.h-100.w-100
|
|
||||||
#rueckmeldung.list-group.list-group-horizontal.text-center.h-100.w-100
|
|
||||||
a.list-group-item.flex-fill.list-group-item-action.text-secondary.tf_singleline
|
|
||||||
.ion-md-paper-plane
|
|
||||||
.col-6.h-65.d-flex.align-items-end.justify-content-start.tf_multiline
|
|
||||||
#ortsdaten.flex-fill -Objekt-
|
|
||||||
br
|
|
||||||
| -Ort-
|
|
||||||
br
|
|
||||||
| -Ortsteil-
|
|
||||||
br
|
|
||||||
| -Straße Hsnr-
|
|
||||||
.col-6.h-65.d-flex.align-items-end.justify-content-end.tf_multiline
|
|
||||||
ul#em_alarmiert.list-group
|
|
||||||
li.list-group-item.d-flex.justify-content-between.align-items-center -Einsatzmittel 1-
|
|
||||||
li.list-group-item.d-flex.justify-content-between.align-items-center -Einsatzmittel 2-
|
|
||||||
li.list-group-item.d-flex.justify-content-between.align-items-center -Einsatzmittel n-
|
|
||||||
// TODO: Status mit anzeigen (als .badge.badge-pill)
|
|
||||||
.col-12.h-5.d-flex.align-items-end.justify-content-center.text-dark.tf_singleline
|
|
||||||
#em_weitere -weiteres Einsatzmittel 1-, -weiteres Einsatzmittel 2-, -weiteres Einsatzmittel n-
|
|
||||||
.col-12.h-20.d-flex.align-items-center.rounded.bg-light.font-weight-bold.text-info.tf_singleline
|
|
||||||
#besonderheiten -Besonderheiten-
|
|
||||||
.col-12.h-5.d-flex.align-items-end.justify-content-center.pt-3
|
|
||||||
.progress(style='height: 100%;').flex-fill
|
|
||||||
#hilfsfrist.progress-bar.progress-bar-striped.progress-bar-animated(role='progressbar', aria-valuenow='0', aria-valuemin='0', aria-valuemax='100', style='width: 0%')
|
|
||||||
audio#audio(controls='')
|
|
||||||
source(src='', type='audio/mpeg')
|
|
||||||
@ -2,6 +2,12 @@ extends layout
|
|||||||
|
|
||||||
block content
|
block content
|
||||||
main(role='main')
|
main(role='main')
|
||||||
|
// TODO: - Login verbessern:
|
||||||
|
// Login-Seite benötigt Fehlerrückmeldung (wie Nutzerverwaltung): falsches Kennwort, Nutzer nicht vorhanden etc.
|
||||||
|
// - Login/Logout protokollieren
|
||||||
|
// - fehlerhafte/doppelte Logins protokollieren
|
||||||
|
// - prüfen ob es sinnvoll ist, bereits eingeloggte User nicht mehr zulassen (Session prüfen)
|
||||||
|
// - bei fehlendem Login zur Login-Seite weiterleiten und nach dem Login die zuvor besuchte Seite anzeigen
|
||||||
.container
|
.container
|
||||||
.row
|
.row
|
||||||
.col-sm-9.col-md-7.col-lg-5.mx-auto
|
.col-sm-9.col-md-7.col-lg-5.mx-auto
|
||||||
@ -17,9 +23,9 @@ block content
|
|||||||
label(for='inputPassword') Passwort
|
label(for='inputPassword') Passwort
|
||||||
input#login-password.form-control(type='password' name='password' placeholder='Passwort' required='')
|
input#login-password.form-control(type='password' name='password' placeholder='Passwort' required='')
|
||||||
.form-group
|
.form-group
|
||||||
.form-check
|
.custom-control.custom-switch
|
||||||
input#rembemerme.form-check-input(type='checkbox' name='rememberme')
|
input#rembemerme.custom-control-input(type='checkbox' name='rememberme' checked='')
|
||||||
label.form-check-label.text-warning(for='rembemerme') Anmeldung dauerhaft speichern
|
label.custom-control-label.text-warning(for='rembemerme') Anmeldung dauerhaft speichern
|
||||||
button.btn.btn-lg.btn-primary.btn-block.text-uppercase(type='submit') Anmelden
|
button.btn.btn-lg.btn-primary.btn-block.text-uppercase(type='submit') Anmelden
|
||||||
.row
|
.row
|
||||||
.col-sm-9.col-md-7.col-lg-5.mx-auto
|
.col-sm-9.col-md-7.col-lg-5.mx-auto
|
||||||
|
|||||||
67
views/overviews/overview_dbrd.pug
Executable file
67
views/overviews/overview_dbrd.pug
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
extends ../layout
|
||||||
|
|
||||||
|
append head
|
||||||
|
link(rel='stylesheet', href='/css/leaflet.css')
|
||||||
|
|
||||||
|
block content
|
||||||
|
main(role='main')
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col-12.p-3
|
||||||
|
.card.bg-dark
|
||||||
|
.card-body.text-muted.text-center
|
||||||
|
h3 Dashboard-Übersicht
|
||||||
|
.col-12
|
||||||
|
div.border-top.m-3
|
||||||
|
.row
|
||||||
|
each val, index in dataSet
|
||||||
|
.col-12.col-xl-6.d-flex.align-self-stretch.p-3
|
||||||
|
.card.w-100
|
||||||
|
.card-header
|
||||||
|
case val.einsatzart
|
||||||
|
when 'Brandeinsatz'
|
||||||
|
h5.font-weight-bold.text-danger.ion-md-flame= ' ' + val.einsatzart + ' - ' + val.stichwort
|
||||||
|
when 'Hilfeleistungseinsatz'
|
||||||
|
h5.font-weight-bold.text-info.ion-md-construct= ' ' + val.einsatzart + ' - ' + val.stichwort
|
||||||
|
when 'Rettungseinsatz'
|
||||||
|
h5.font-weight-bold.text-warning.ion-md-medkit= ' ' + val.einsatzart + ' - ' + val.stichwort
|
||||||
|
when 'Krankentransport'
|
||||||
|
h5.font-weight-bold.text-success.ion-md-medical= ' ' + val.einsatzart + ' - ' + val.stichwort
|
||||||
|
default
|
||||||
|
h5.font-weight-bold.ion-md-information-circle= ' ' + val.einsatzart + ' - ' + val.stichwort
|
||||||
|
.card-body
|
||||||
|
if val.ortsteil
|
||||||
|
p= val.ort + ', ' + val.ortsteil
|
||||||
|
else
|
||||||
|
p= val.ort
|
||||||
|
.w-100.rounded( id='map' + val.uuid style='height:150px')
|
||||||
|
.card-footer.text-right
|
||||||
|
a.btn.btn-primary.mx-2.ion-md-arrow-round-forward(href='/dbrd/' + val.uuid, role='button') Dashboard aufrufen
|
||||||
|
else
|
||||||
|
.col-12.p-3
|
||||||
|
.card.bg-danger.w-100
|
||||||
|
.card-header
|
||||||
|
h5 Achtung
|
||||||
|
.card-body
|
||||||
|
div Aktuell sind keine Einsätze verfügbar. Bitte versuchen Sie es später erneut.
|
||||||
|
|
||||||
|
script(src='/js/leaflet.js')
|
||||||
|
script.
|
||||||
|
var data = !{JSON.stringify(dataSet).replace(/<\//g, '<\\/')}
|
||||||
|
for (var i in data) {
|
||||||
|
// Karte definieren
|
||||||
|
var map = L.map('map'+data[i].uuid, {
|
||||||
|
zoomControl: false
|
||||||
|
});
|
||||||
|
// Layer der Karte
|
||||||
|
mapLink = L.tileLayer(
|
||||||
|
'#{map_tile}', {
|
||||||
|
maxZoom: 12,
|
||||||
|
attribution: '!{map_attribution}'
|
||||||
|
}).addTo(map);
|
||||||
|
// Karte setzen
|
||||||
|
var geojson = L.geoJSON(JSON.parse(data[i].wgs84_area)).addTo(map);
|
||||||
|
map.fitBounds(geojson.getBounds());
|
||||||
|
map.setZoom(13);
|
||||||
|
};
|
||||||
|
|
||||||
64
views/overviews/overview_waip.pug
Executable file
64
views/overviews/overview_waip.pug
Executable file
@ -0,0 +1,64 @@
|
|||||||
|
extends ../layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
main(role='main')
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col-12.p-3
|
||||||
|
.card.bg-dark
|
||||||
|
.card-body.text-muted.text-center
|
||||||
|
h3 Alarmmonitor-Übersicht
|
||||||
|
.col-12
|
||||||
|
div.border-top.m-3
|
||||||
|
.row
|
||||||
|
.col-12.d-flex.align-self-stretch.p-3
|
||||||
|
.card.border-success.w-100.h-100
|
||||||
|
.card-header
|
||||||
|
h2.text-success Alle Wachalarme
|
||||||
|
.card-body
|
||||||
|
p Zeigt Ihnen alle Wachalarme der im System hinterlegten Wachen an. Entsprechend Ihrer Berechtigungen werden alle Informationen oder nur Teilinformationen angezeigt.
|
||||||
|
p Wollen Sie nur Alarme für einen bestimmten Bereich erhalten, wählen Sie bitte einen Alarmmonitor für die unten genannten Bereiche.
|
||||||
|
.card-footer.text-right
|
||||||
|
a.btn.btn-success.ion-md-arrow-round-forward(href='/waip/0', role='button') alle Wachalarme anzeigen
|
||||||
|
.col-12.col-md-4.d-flex.align-self-stretch.p-3
|
||||||
|
.card.w-100.h-100
|
||||||
|
.card-header
|
||||||
|
h3.text-info Alarmmonitor Wache
|
||||||
|
.card-body
|
||||||
|
p.text-muted Zeigt den Wachalarm einer einzelnen Wache (z.B. Feuerwache, Rettungswache etc.) an.
|
||||||
|
.card-footer.text-right
|
||||||
|
.dropdown
|
||||||
|
button.btn.btn-info.dropdown-toggle(type='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
||||||
|
| bitte auswählen
|
||||||
|
.dropdown-menu
|
||||||
|
each item in list_wachen
|
||||||
|
if item.typ == 'wache'
|
||||||
|
a.dropdown-item(href='/waip/'+ item.nr)= item.name
|
||||||
|
.col-12.col-md-4.d-flex.align-self-stretch.p-3
|
||||||
|
.card.w-100.h-100
|
||||||
|
.card-header
|
||||||
|
h3.text-info Alarmmonitor Träger
|
||||||
|
.card-body
|
||||||
|
p.text-muted Zeigt alle Wachalarme der Wachen eines Trägers (Amt, amtsfreie Gemeinde, Stadt) an.
|
||||||
|
.card-footer.text-right
|
||||||
|
.dropdown
|
||||||
|
button.btn.btn-info.dropdown-toggle(type='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
||||||
|
| bitte auswählen
|
||||||
|
.dropdown-menu
|
||||||
|
each item in list_wachen
|
||||||
|
if item.typ == 'traeger'
|
||||||
|
a.dropdown-item(href='/waip/'+ item.nr)= item.name
|
||||||
|
.col-12.col-md-4.d-flex.align-self-stretch.p-3
|
||||||
|
.card.w-100.h-100
|
||||||
|
.card-header
|
||||||
|
h3.text-info Alarmmonitor Kreis
|
||||||
|
.card-body
|
||||||
|
p.text-muted Zeigt alle Wachalarme des gesamten Kreises (egal ob fü Feuerwehr oder Rettungsdienst) an.
|
||||||
|
.card-footer.text-right
|
||||||
|
.dropdown
|
||||||
|
button.btn.btn-info.dropdown-toggle(type='button', data-toggle='dropdown', aria-haspopup='true', aria-expanded='false')
|
||||||
|
| bitte auswählen
|
||||||
|
.dropdown-menu
|
||||||
|
each item in list_wachen
|
||||||
|
if item.typ == 'kreis'
|
||||||
|
a.dropdown-item(href='/waip/'+ item.nr)= item.name
|
||||||
144
views/privacy.pug
Executable file
144
views/privacy.pug
Executable file
@ -0,0 +1,144 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
main(role='main')
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
h1.display-1 Datenschutzerklärung
|
||||||
|
h2 1. Datenschutz auf einen Blick
|
||||||
|
h3 Allgemeine Hinweise
|
||||||
|
p
|
||||||
|
| Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren personenbezogenen Daten passiert, wenn Sie diese Website besuchen. Personenbezogene Daten sind alle Daten, mit denen Sie persönlich identifiziert werden können. Ausführliche Informationen zum Thema Datenschutz entnehmen Sie unserer unter diesem Text aufgeführten Datenschutzerklärung.
|
||||||
|
h3 Datenerfassung auf dieser Website
|
||||||
|
p
|
||||||
|
strong Wer ist verantwortlich für die Datenerfassung auf dieser Website?
|
||||||
|
p
|
||||||
|
| Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen Kontaktdaten können Sie dem Impressum dieser Website entnehmen.
|
||||||
|
p
|
||||||
|
strong Wie erfassen wir Ihre Daten?
|
||||||
|
p
|
||||||
|
| Ihre Daten werden zum einen dadurch erhoben, dass Sie uns diese mitteilen. Hierbei kann es sich z. B. um Daten handeln, die Sie in ein Kontaktformular eingeben.
|
||||||
|
p
|
||||||
|
| Andere Daten werden automatisch oder nach Ihrer Einwilligung beim Besuch der Website durch unsere IT-Systeme erfasst. Das sind vor allem technische Daten (z. B. Internetbrowser, Betriebssystem oder Uhrzeit des Seitenaufrufs). Die Erfassung dieser Daten erfolgt automatisch, sobald Sie diese Website betreten.
|
||||||
|
p
|
||||||
|
strong Wofür nutzen wir Ihre Daten?
|
||||||
|
p
|
||||||
|
| Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der Website zu gewährleisten. Andere Daten können zur Analyse Ihres Nutzerverhaltens verwendet werden.
|
||||||
|
p
|
||||||
|
strong Welche Rechte haben Sie bezüglich Ihrer Daten?
|
||||||
|
p
|
||||||
|
| Sie haben jederzeit das Recht unentgeltlich Auskunft über Herkunft, Empfänger und Zweck Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben außerdem ein Recht, die Berichtigung oder Löschung dieser Daten zu verlangen. Wenn Sie eine Einwilligung zur Datenverarbeitung erteilt haben, können Sie diese Einwilligung jederzeit für die Zukunft widerrufen. Außerdem haben Sie das Recht, unter bestimmten Umständen die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Des Weiteren steht Ihnen ein Beschwerderecht bei der zuständigen Aufsichtsbehörde zu.
|
||||||
|
p
|
||||||
|
| Hierzu sowie zu weiteren Fragen zum Thema Datenschutz können Sie sich jederzeit unter der im Impressum angegebenen Adresse an uns wenden.
|
||||||
|
h2 2. Allgemeine Hinweise und Pflichtinformationen
|
||||||
|
h3 Datenschutz
|
||||||
|
p
|
||||||
|
| Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst. Wir behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie dieser Datenschutzerklärung.
|
||||||
|
p
|
||||||
|
| Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten erhoben. Personenbezogene Daten sind Daten, mit denen Sie persönlich identifiziert werden können. Die vorliegende Datenschutzerklärung erläutert, welche Daten wir erheben und wofür wir sie nutzen. Sie erläutert auch, wie und zu welchem Zweck das geschieht.
|
||||||
|
p
|
||||||
|
| Wir weisen darauf hin, dass die Datenübertragung im Internet (z. B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.
|
||||||
|
h3 Hinweis zur verantwortlichen Stelle
|
||||||
|
p Die verantwortliche Stelle für die Datenverarbeitung auf dieser Website ist:
|
||||||
|
p
|
||||||
|
| Robert Richter
|
||||||
|
br
|
||||||
|
| Am Mühlenteich 7
|
||||||
|
br
|
||||||
|
| 03099 Kolkwitz
|
||||||
|
p
|
||||||
|
| Telefon: null eins fünf eins eins zwei vier fünf null acht vier sieben
|
||||||
|
br
|
||||||
|
| E-Mail: robertrichter87 [at] web.de
|
||||||
|
p
|
||||||
|
| Verantwortliche Stelle ist die natürliche oder juristische Person, die allein oder gemeinsam mit anderen über die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten (z. B. Namen, E-Mail-Adressen o. Ä.) entscheidet.
|
||||||
|
h3 Widerruf Ihrer Einwilligung zur Datenverarbeitung
|
||||||
|
p
|
||||||
|
| Viele Datenverarbeitungsvorgänge sind nur mit Ihrer ausdrücklichen Einwilligung möglich. Sie können eine bereits erteilte Einwilligung jederzeit widerrufen. Dazu reicht eine formlose Mitteilung per E-Mail an uns. Die Rechtmäßigkeit der bis zum Widerruf erfolgten Datenverarbeitung bleibt vom Widerruf unberührt.
|
||||||
|
h3
|
||||||
|
| Widerspruchsrecht gegen die Datenerhebung in besonderen Fällen sowie gegen Direktwerbung (Art. 21 DSGVO)
|
||||||
|
p
|
||||||
|
| WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F DSGVO ERFOLGT, HABEN SIE JEDERZEIT DAS RECHT, AUS GRÜNDEN, DIE SICH AUS IHRER BESONDEREN SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER PERSONENBEZOGENEN DATEN WIDERSPRUCH EINZULEGEN; DIES GILT AUCH FÜR EIN AUF DIESE BESTIMMUNGEN GESTÜTZTES PROFILING. DIE JEWEILIGE RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE DIESER DATENSCHUTZERKLÄRUNG. WENN SIE WIDERSPRUCH EINLEGEN, WERDEN WIR IHRE BETROFFENEN PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES SEI DENN, WIR KÖNNEN ZWINGENDE SCHUTZWÜRDIGE GRÜNDE FÜR DIE VERARBEITUNG NACHWEISEN, DIE IHRE INTERESSEN, RECHTE UND FREIHEITEN ÜBERWIEGEN ODER DIE VERARBEITUNG DIENT DER GELTENDMACHUNG, AUSÜBUNG ODER VERTEIDIGUNG VON RECHTSANSPRÜCHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO).
|
||||||
|
p
|
||||||
|
| WERDEN IHRE PERSONENBEZOGENEN DATEN VERARBEITET, UM DIREKTWERBUNG ZU BETREIBEN, SO HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE VERARBEITUNG SIE BETREFFENDER PERSONENBEZOGENER DATEN ZUM ZWECKE DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH FÜR DAS PROFILING, SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE WIDERSPRECHEN, WERDEN IHRE PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT MEHR ZUM ZWECKE DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART. 21 ABS. 2 DSGVO).
|
||||||
|
h3 Beschwerderecht bei der zuständigen Aufsichtsbehörde
|
||||||
|
p
|
||||||
|
| Im Falle von Verstößen gegen die DSGVO steht den Betroffenen ein Beschwerderecht bei einer Aufsichtsbehörde, insbesondere in dem Mitgliedstaat ihres gewöhnlichen Aufenthalts, ihres Arbeitsplatzes oder des Orts des mutmaßlichen Verstoßes zu. Das Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher oder gerichtlicher Rechtsbehelfe.
|
||||||
|
h3 Recht auf Datenübertragbarkeit
|
||||||
|
p
|
||||||
|
| Sie haben das Recht, Daten, die wir auf Grundlage Ihrer Einwilligung oder in Erfüllung eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in einem gängigen, maschinenlesbaren Format aushändigen zu lassen. Sofern Sie die direkte Übertragung der Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist.
|
||||||
|
h3 SSL- bzw. TLS-Verschlüsselung
|
||||||
|
p
|
||||||
|
| Diese Seite nutzt aus Sicherheitsgründen und zum Schutz der Übertragung vertraulicher Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns als Seitenbetreiber senden, eine SSL- bzw. TLS-Verschlüsselung. Eine verschlüsselte Verbindung erkennen Sie daran, dass die Adresszeile des Browsers von „http://“ auf „https://“ wechselt und an dem Schloss-Symbol in Ihrer Browserzeile.
|
||||||
|
p
|
||||||
|
| Wenn die SSL- bzw. TLS-Verschlüsselung aktiviert ist, können die Daten, die Sie an uns übermitteln, nicht von Dritten mitgelesen werden.
|
||||||
|
h3 Auskunft, Löschung und Berichtigung
|
||||||
|
p
|
||||||
|
| Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen jederzeit das Recht auf unentgeltliche Auskunft über Ihre gespeicherten personenbezogenen Daten, deren Herkunft und Empfänger und den Zweck der Datenverarbeitung und ggf. ein Recht auf Berichtigung oder Löschung dieser Daten. Hierzu sowie zu weiteren Fragen zum Thema personenbezogene Daten können Sie sich jederzeit unter der im Impressum angegebenen Adresse an uns wenden.
|
||||||
|
h3 Recht auf Einschränkung der Verarbeitung
|
||||||
|
p
|
||||||
|
| Sie haben das Recht, die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Hierzu können Sie sich jederzeit unter der im Impressum angegebenen Adresse an uns wenden. Das Recht auf Einschränkung der Verarbeitung besteht in folgenden Fällen:
|
||||||
|
ul
|
||||||
|
li
|
||||||
|
| Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen Daten bestreiten, benötigen wir in der Regel Zeit, um dies zu überprüfen. Für die Dauer der Prüfung haben Sie das Recht, die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
|
||||||
|
li
|
||||||
|
| Wenn die Verarbeitung Ihrer personenbezogenen Daten unrechtmäßig geschah/geschieht, können Sie statt der Löschung die Einschränkung der Datenverarbeitung verlangen.
|
||||||
|
li
|
||||||
|
| Wenn wir Ihre personenbezogenen Daten nicht mehr benötigen, Sie sie jedoch zur Ausübung, Verteidigung oder Geltendmachung von Rechtsansprüchen benötigen, haben Sie das Recht, statt der Löschung die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
|
||||||
|
li
|
||||||
|
| Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben, muss eine Abwägung zwischen Ihren und unseren Interessen vorgenommen werden. Solange noch nicht feststeht, wessen Interessen überwiegen, haben Sie das Recht, die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
|
||||||
|
p
|
||||||
|
| Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten eingeschränkt haben, dürfen diese Daten – von ihrer Speicherung abgesehen – nur mit Ihrer Einwilligung oder zur Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen oder zum Schutz der Rechte einer anderen natürlichen oder juristischen Person oder aus Gründen eines wichtigen öffentlichen Interesses der Europäischen Union oder eines Mitgliedstaats verarbeitet werden.
|
||||||
|
h2 3. Datenerfassung auf dieser Website
|
||||||
|
h3 Cookies
|
||||||
|
p
|
||||||
|
| Unsere Internetseiten verwenden so genannte „Cookies“. Cookies sind kleine Textdateien und richten auf Ihrem Endgerät keinen Schaden an. Sie werden entweder vorübergehend für die Dauer einer Sitzung (Session-Cookies) oder dauerhaft (permanente Cookies) auf Ihrem Endgerät gespeichert. Session-Cookies werden nach Ende Ihres Besuchs automatisch gelöscht. Permanente Cookies bleiben auf Ihrem Endgerät gespeichert bis Sie diese selbst löschen oder eine automatische Lösung durch Ihren Webbrowser erfolgt.
|
||||||
|
p
|
||||||
|
| Teilweise können auch Cookies von Drittunternehmen auf Ihrem Endgerät gespeichert werden, wenn Sie unsere Seite betreten (Third-Party-Cookies). Diese ermöglichen uns oder Ihnen die Nutzung bestimmter Dienstleistungen des Drittunternehmens (z.B. Cookies zur Abwicklung von Zahlungsdienstleistungen).
|
||||||
|
p
|
||||||
|
| Cookies haben verschiedene Funktionen. Zahlreiche Cookies sind technisch notwendig, da bestimmte Webseitenfunktionen ohne diese nicht funktionieren würden (z.B. die Warenkorbfunktion oder die Anzeige von Videos). Andere Cookies dienen dazu das Nutzerverhalten auszuwerten oder Werbung anzuzeigen.
|
||||||
|
p
|
||||||
|
| Cookies, die zur Durchführung des elektronischen Kommunikationsvorgangs (notwendige Cookies) oder zur Bereitstellung bestimmter, von Ihnen erwünschter Funktionen (funktionale Cookies, z. B. für die Warenkorbfunktion) oder zur Optimierung der Webseite (z.B. Cookies zur Messung des Webpublikums) erforderlich sind, werden auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO gespeichert, sofern keine andere Rechtsgrundlage angegeben wird. Der Websitebetreiber hat ein berechtigtes Interesse an der Speicherung von Cookies zur technisch fehlerfreien und optimierten Bereitstellung seiner Dienste. Sofern eine Einwilligung zur Speicherung von Cookies abgefragt wurde, erfolgt die Speicherung der betreffenden Cookies ausschließlich auf Grundlage dieser Einwilligung (Art. 6 Abs. 1 lit. a DSGVO); die Einwilligung ist jederzeit widerrufbar.
|
||||||
|
p
|
||||||
|
| Sie können Ihren Browser so einstellen, dass Sie über das Setzen von Cookies informiert werden und Cookies nur im Einzelfall erlauben, die Annahme von Cookies für bestimmte Fälle oder generell ausschließen sowie das automatische Löschen der Cookies beim Schließen des Browsers aktivieren. Bei der Deaktivierung von Cookies kann die Funktionalität dieser Website eingeschränkt sein.
|
||||||
|
p
|
||||||
|
| Soweit Cookies von Drittunternehmen oder zu Analysezwecken eingesetzt werden, werden wir Sie hierüber im Rahmen dieser Datenschutzerklärung gesondert informieren und ggf. eine Einwilligung abfragen.
|
||||||
|
h3 Server-Log-Dateien
|
||||||
|
p
|
||||||
|
| Der Provider der Seiten erhebt und speichert automatisch Informationen in so genannten Server-Log-Dateien, die Ihr Browser automatisch an uns übermittelt. Dies sind:
|
||||||
|
ul
|
||||||
|
li Browsertyp und Browserversion
|
||||||
|
li verwendetes Betriebssystem
|
||||||
|
li Referrer URL
|
||||||
|
li Hostname des zugreifenden Rechners
|
||||||
|
li Uhrzeit der Serveranfrage
|
||||||
|
li IP-Adresse
|
||||||
|
p
|
||||||
|
| Eine Zusammenführung dieser Daten mit anderen Datenquellen wird nicht vorgenommen.
|
||||||
|
p
|
||||||
|
| Die Erfassung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Der Websitebetreiber hat ein berechtigtes Interesse an der technisch fehlerfreien Darstellung und der Optimierung seiner Website – hierzu müssen die Server-Log-Files erfasst werden.
|
||||||
|
h2 4. Plugins und Tools
|
||||||
|
h3 Google Web Fonts
|
||||||
|
p
|
||||||
|
| Diese Seite nutzt zur einheitlichen Darstellung von Schriftarten so genannte Web Fonts, die von Google bereitgestellt werden. Die Google Fonts sind lokal installiert. Eine Verbindung zu Servern von Google findet dabei nicht statt.
|
||||||
|
p
|
||||||
|
| Weitere Informationen zu Google Web Fonts finden Sie unter
|
||||||
|
a(href='https://developers.google.com/fonts/faq', target='_blank', rel='noopener noreferrer') https://developers.google.com/fonts/faq
|
||||||
|
| und in der Datenschutzerklärung von Google:
|
||||||
|
a(href='https://policies.google.com/privacy?hl=de', target='_blank', rel='noopener noreferrer') https://policies.google.com/privacy?hl=de
|
||||||
|
| .
|
||||||
|
h3 OpenStreetMap
|
||||||
|
p
|
||||||
|
| Wir nutzen den Kartendienst von OpenStreetMap (OSM). Anbieterin ist die Open-Street-Map Foundation (OSMF), 132 Maney Hill Road, Sutton Coldfield, West Midlands, B72 1JU, United Kingdom.
|
||||||
|
p
|
||||||
|
| Wenn Sie eine Website besuchen, auf der OpenStreetMap eingebunden ist, werden u. a. Ihre IP-Adresse und weitere Informationen über Ihr Verhalten auf dieser Website an die OSMF weitergeleitet. OpenStreetMap speichert hierzu unter Umständen Cookies in Ihrem Browser. Das sind Textdateien, die auf Ihrem Computer gespeichert werden und die eine Analyse der Benutzung der Website durch Sie ermöglichen. Sie können die Speicherung der Cookies durch eine entsprechende Einstellung Ihrer Browser-Software verhindern; wir weisen Sie jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website vollumfänglich werden nutzen können.
|
||||||
|
p
|
||||||
|
| Ferner kann Ihr Standort erfasst werden, wenn Sie dies in Ihren Geräteeinstellungen – z. B. auf Ihrem Handy – zugelassen haben. Der Anbieter dieser Seite hat keinen Einfluss auf diese Datenübertragung. Details entnehmen Sie der Datenschutzerklärung von OpenStreetMap unter folgendem Link:
|
||||||
|
a(href='https://wiki.osmfoundation.org/wiki/Privacy_Policy', target='_blank', rel='noopener noreferrer') https://wiki.osmfoundation.org/wiki/Privacy_Policy
|
||||||
|
| .
|
||||||
|
p
|
||||||
|
| Die Nutzung von OpenStreetMap erfolgt im Interesse einer ansprechenden Darstellung unserer Online-Angebote und einer leichten Auffindbarkeit der von uns auf der Website angegebenen Orte. Dies stellt ein berechtigtes Interesse im Sinne von Art. 6 Abs. 1 lit. f DSGVO dar. Sofern eine entsprechende Einwilligung abgefragt wurde (z. B. eine Einwilligung zur Speicherung von Cookies), erfolgt die Verarbeitung ausschließlich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit widerrufbar.
|
||||||
|
p.text-muted
|
||||||
|
| Quelle:
|
||||||
|
a(href='https://www.e-recht24.de') https://www.e-recht24.de
|
||||||
16
views/rmld.pug
Executable file
16
views/rmld.pug
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
append head
|
||||||
|
link(rel='stylesheet', href='/css/leaflet.css')
|
||||||
|
|
||||||
|
block content
|
||||||
|
include includes/modal_info
|
||||||
|
include includes/modal_rmld
|
||||||
|
.container-fluid
|
||||||
|
include includes/master_rueckmeldung
|
||||||
|
script.
|
||||||
|
map_tile='#{map_tile}'
|
||||||
|
map_attribution='!{map_attribution}'
|
||||||
|
var einsatzdaten_obj = !{JSON.stringify(einsatzdaten).replace(/<\//g, '<\\/')}
|
||||||
|
script(src='/js/leaflet.js')
|
||||||
|
script(src='/js/client_rmld.js')
|
||||||
@ -8,5 +8,5 @@ block content
|
|||||||
include includes/clock
|
include includes/clock
|
||||||
|
|
||||||
script(src='/js/textFit.min.js')
|
script(src='/js/textFit.min.js')
|
||||||
script(src='/js/waip.js')
|
script(src='/js/waip_client.js')
|
||||||
|
|
||||||
12
views/tests/test_dashboard.pug
Executable file
12
views/tests/test_dashboard.pug
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
extends /layout
|
||||||
|
|
||||||
|
append head
|
||||||
|
link(rel='stylesheet', href='/css/leaflet.css')
|
||||||
|
|
||||||
|
block content
|
||||||
|
//include includes/modal_response
|
||||||
|
.container-fluid
|
||||||
|
include /includes/master_dashboard
|
||||||
|
script(src='/js/leaflet.js')
|
||||||
|
script(src='/js/client_dbrd.js')
|
||||||
|
|
||||||
12
views/tests/test_rueckmeldung.pug
Executable file
12
views/tests/test_rueckmeldung.pug
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
extends layout
|
||||||
|
|
||||||
|
append head
|
||||||
|
link(rel='stylesheet', href='/css/leaflet.css')
|
||||||
|
|
||||||
|
block content
|
||||||
|
include includes/modal_rmld
|
||||||
|
.container-fluid
|
||||||
|
include includes/master_rueckmeldung
|
||||||
|
script(src='/js/leaflet.js')
|
||||||
|
script(src='/js/rueckmeldung_client.js')
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
append head
|
append head
|
||||||
link(rel='stylesheet', href='/css/ionicons.min.css')
|
link(rel='stylesheet', href='/css/ionicons.min.css')
|
||||||
@ -6,10 +6,9 @@ append head
|
|||||||
link(rel='stylesheet', href='/css/waip.css')
|
link(rel='stylesheet', href='/css/waip.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
include includes/modal_response
|
|
||||||
.container-fluid
|
.container-fluid
|
||||||
include includes/wachalarm
|
include ../includes/master_wachalarm
|
||||||
script(src='/js/leaflet.js')
|
script(src='/js/leaflet.js')
|
||||||
script(src='/js/textFit.min.js')
|
script(src='/js/textFit.min.js')
|
||||||
script(src='/js/waip.js')
|
script(src='/js/client_waip.js')
|
||||||
|
|
||||||
@ -1,7 +1,4 @@
|
|||||||
extends layout
|
extends ../layout
|
||||||
|
|
||||||
append head
|
|
||||||
link(rel='stylesheet', href='/css/ionicons.min.css')
|
|
||||||
|
|
||||||
block content
|
block content
|
||||||
main(role='main')
|
main(role='main')
|
||||||
@ -25,4 +22,6 @@ block content
|
|||||||
if(i+1 == reset_counter)
|
if(i+1 == reset_counter)
|
||||||
option(selected)= i+1
|
option(selected)= i+1
|
||||||
else
|
else
|
||||||
option= i+1
|
option= i+1
|
||||||
|
// TODO: anpassen der Durchsage je Benutzer, durch eigene Ersetzung und Reihenfolge
|
||||||
|
// TODO: Ausnahmen festlegen können, wann keine Musik abgespielt wird
|
||||||
@ -4,21 +4,22 @@ append head
|
|||||||
link(rel='stylesheet', href='/css/leaflet.css')
|
link(rel='stylesheet', href='/css/leaflet.css')
|
||||||
|
|
||||||
block content
|
block content
|
||||||
include includes/modal
|
include includes/modal_info
|
||||||
include includes/modal_response
|
//include includes/modal_rmld
|
||||||
.container-fluid
|
.container-fluid
|
||||||
#waipclock.d-none
|
#waipclock.d-none
|
||||||
include includes/clock
|
include includes/master_clock
|
||||||
#waiptableau.d-none
|
#waiptableau.d-none
|
||||||
include includes/wachalarm
|
include includes/master_wachalarm
|
||||||
|
|
||||||
script.
|
script.
|
||||||
var map_tile = !{JSON.stringify(map_tile).replace(/<\//g, '<\\/')}
|
map_tile='#{map_tile}'
|
||||||
var client_id = !{JSON.stringify(app_id).replace(/<\//g, '<\\/')}
|
map_attribution='!{map_attribution}'
|
||||||
|
client_id="#{app_id}"
|
||||||
script(src='/js/leaflet.js')
|
script(src='/js/leaflet.js')
|
||||||
script(src='/js/textFit.min.js')
|
script(src='/js/textFit.min.js')
|
||||||
script(src='/socket.io/socket.io.js')
|
script(src='/socket.io/socket.io.js')
|
||||||
script.
|
script.
|
||||||
wachen_id="#{wachen_id}"
|
wachen_id="#{wachen_id}"
|
||||||
waip_id=null
|
waip_id=null
|
||||||
script(src='/js/waip.js')
|
script(src='/js/client_waip.js')
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user