tv app
This commit is contained in:
@@ -1,19 +1,26 @@
|
|||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
|
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
|
||||||
|
import { AvisoResolver } from './pages/aviso/aviso.resolver'; // Importieren Sie den Resolver
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'home',
|
path: 'home',
|
||||||
loadChildren: () => import('./pages/home/home.module').then( m => m.HomePageModule)
|
loadChildren: () => import('./pages/home/home.module').then(m => m.HomePageModule)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'aviso',
|
path: 'aviso',
|
||||||
loadChildren: () => import('./pages/aviso/aviso.module').then( m => m.AvisoPageModule)
|
loadChildren: () => import('./pages/aviso/aviso.module').then(m => m.AvisoPageModule),
|
||||||
|
resolve: { avisoData: AvisoResolver } // Hinzufügen des Resolvers zur Route
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: 'aviso',
|
redirectTo: 'aviso',
|
||||||
pathMatch: 'full'
|
pathMatch: 'full'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '**',
|
||||||
|
redirectTo: 'aviso'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
import { AvisoPage } from './aviso.page';
|
import { AvisoPage } from './aviso.page';
|
||||||
|
import { AvisoResolver } from './aviso.resolver'; // Pfad anpassen
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: AvisoPage
|
component: AvisoPage,
|
||||||
|
resolve: { avisoData: AvisoResolver }
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -14,4 +16,4 @@ const routes: Routes = [
|
|||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class AvisoPageRoutingModule {}
|
export class AvisoPageRoutingModule { }
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { AvisoPage } from './aviso.page';
|
||||||
|
|
||||||
import { IonicModule } from '@ionic/angular';
|
import { IonicModule } from '@ionic/angular';
|
||||||
|
|
||||||
import { AvisoPageRoutingModule } from './aviso-routing.module';
|
import { AvisoPageRoutingModule } from './aviso-routing.module';
|
||||||
import { AutoResizeTextDirective } from '../../directives/auto-resize-text.directive';
|
import { AutoResizeTextDirective } from '../../directives/auto-resize-text.directive';
|
||||||
|
|
||||||
import { AvisoPage } from './aviso.page';
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
|
|
||||||
<ion-content fullscreen>
|
<ion-content fullscreen>
|
||||||
<!-- Titel für Arrivals -->
|
|
||||||
|
|
||||||
<ion-header>
|
<ion-header>
|
||||||
<ion-toolbar>
|
|
||||||
<ion-title class="ion-text-center">
|
|
||||||
Ankünfte ({{ totalArrivals }}) Seite {{ currentPageIndex + 1 }} von {{ pages.length }}
|
|
||||||
</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
|
|
||||||
<!-- Fehlernachricht anzeigen -->
|
<!-- Fehlernachricht anzeigen -->
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row *ngIf="errorMessage">
|
<ion-row *ngIf="errorMessage">
|
||||||
@@ -28,10 +24,14 @@
|
|||||||
</ion-grid>
|
</ion-grid>
|
||||||
|
|
||||||
<!-- Grid-Container für Arrivals Kacheln -->
|
<!-- Grid-Container für Arrivals Kacheln -->
|
||||||
<div class="grid-container" *ngIf="!loadingArrivals && pages.length > 0">
|
<div class="grid-container" *ngIf="!loadingArrivals && pages.length > 0">
|
||||||
<ion-card *ngFor="let aviso of pages[currentPageIndex]"
|
<ion-card *ngFor="let aviso of pages[currentPageIndex]; let i = index"
|
||||||
class="arrival-card"
|
class="arrival-card"
|
||||||
[ngClass]="getStatusClass(aviso.status)">
|
[ngClass]="getStatusClass(aviso.status, aviso.lkW_fertig)">
|
||||||
|
|
||||||
|
<!-- Nummerierung in der oberen linken Ecke -->
|
||||||
|
<div class="card-number">{{ getOverallIndex(i) }}</div>
|
||||||
|
|
||||||
<ion-card-header>
|
<ion-card-header>
|
||||||
<ion-card-title class="ion-text-center">
|
<ion-card-title class="ion-text-center">
|
||||||
<strong>{{ aviso.lkW_Nr }}</strong>
|
<strong>{{ aviso.lkW_Nr }}</strong>
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
<ion-icon [name]="getStatusIcon(aviso.status)"
|
<ion-icon [name]="getStatusIcon(aviso.status)"
|
||||||
[color]="getStatusColor(aviso.status)"></ion-icon>
|
[color]="getStatusColor(aviso.status)"></ion-icon>
|
||||||
{{ aviso.ankunft }}
|
{{ aviso.ankunft }}
|
||||||
<ion-icon name="hourglass-outline"></ion-icon>
|
<ion-icon name="hourglass-outline" [color]="getStatusColor(aviso.status)"></ion-icon>
|
||||||
{{ aviso.dauer }}
|
{{ aviso.dauer }}
|
||||||
</p>
|
</p>
|
||||||
<p class="ion-text-center">
|
<p class="ion-text-center">
|
||||||
@@ -56,6 +56,7 @@
|
|||||||
</ion-card>
|
</ion-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Nachricht, wenn keine Arrivals vorhanden sind -->
|
<!-- Nachricht, wenn keine Arrivals vorhanden sind -->
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row *ngIf="!loadingArrivals && arrivals.length === 0 && !errorMessage">
|
<ion-row *ngIf="!loadingArrivals && arrivals.length === 0 && !errorMessage">
|
||||||
@@ -70,27 +71,45 @@
|
|||||||
<!-- Bedingtes Textfeld für TV-Einstellungen -->
|
<!-- Bedingtes Textfeld für TV-Einstellungen -->
|
||||||
|
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
<ion-toolbar class="logobar">
|
||||||
|
<span slot="start" class="title">
|
||||||
|
|
||||||
|
{{ currentDate | date: 'HH:mm:ss' }} <br />
|
||||||
|
{{ currentDate | date: ' dd.MM.yyyy' }}
|
||||||
|
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<ion-title class="ion-text-center title">
|
||||||
|
<img [src]="'assets/Logos/' + avisoTvSettings[0].logo" class="logo">
|
||||||
|
</ion-title>
|
||||||
|
|
||||||
|
<span slot="end" class="title">({{ totalArrivals }}) <br /> {{ currentPageIndex + 1 }} / {{ pages.length }}</span>
|
||||||
|
<ion-progress-bar [value]="progressBarValue" class="custom-progress-bar" buffer="1"></ion-progress-bar>
|
||||||
|
</ion-toolbar>
|
||||||
<ion-footer>
|
<ion-footer>
|
||||||
<ng-container *ngFor="let setting of avisoTvSettings; let i = index">
|
<ng-container *ngFor="let setting of avisoTvTextSettings; let i = index">
|
||||||
<ng-container *ngIf="setting.isActive && setting.fixeZeile1">
|
<ng-container *ngIf="setting.isActive && settingDisplayData[i]?.nonEmptyFixeZeilen?.length">
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<!-- Erstes Div, wird angezeigt, wenn showFirstDiv true ist -->
|
<div [innerHTML]="settingDisplayData[i].nonEmptyFixeZeilen[settingDisplayData[i].currentDivIndex]?.sanitizedHtml"
|
||||||
<div *ngIf="showFirstDiv"
|
|
||||||
[innerHTML]="sanitizeHtml(setting.fixeZeile1 || '',i)"
|
|
||||||
autoResizeText
|
autoResizeText
|
||||||
[style.text-align]="getTextAlign(i)"
|
[style.text-align]="settingDisplayData[i].nonEmptyFixeZeilen[settingDisplayData[i].currentDivIndex]?.textAlign"
|
||||||
class="htmltext">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Zweites Div, wird angezeigt, wenn showFirstDiv false ist -->
|
|
||||||
<div *ngIf="!showFirstDiv"
|
|
||||||
[innerHTML]="sanitizeHtml(setting.fixeZeile2 || '',i)"
|
|
||||||
autoResizeText
|
|
||||||
[style.text-align]="getTextAlign(i)"
|
|
||||||
class="htmltext">
|
class="htmltext">
|
||||||
</div>
|
</div>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
<div style="display:flex;justify-content:center">
|
||||||
|
<div style="width:10vw">
|
||||||
|
<ion-segment [(ngModel)]="settingDisplayData[i].currentDivIndex"
|
||||||
|
class="custom-segment">
|
||||||
|
<ion-segment-button *ngFor="let item of settingDisplayData[i].nonEmptyFixeZeilen; let j = index"
|
||||||
|
[value]="j"
|
||||||
|
class="custom-segment-button">
|
||||||
|
|
||||||
|
</ion-segment-button>
|
||||||
|
</ion-segment>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
||||||
</ion-footer>
|
</ion-footer>
|
||||||
|
|||||||
@@ -1,89 +1,54 @@
|
|||||||
|
|
||||||
|
|
||||||
ion-content {
|
ion-content {
|
||||||
--background: #f0f0f0; /* Heller Hintergrund für besseren Kontrast */
|
--background: #f0f0f0; /* Heller Hintergrund für besseren Kontrast */
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-card {
|
|
||||||
background-color: #3880ff; /* Beispiel: Blaue Hintergrundfarbe */
|
|
||||||
color: white;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-card-content p {
|
|
||||||
font-size: 1.8em; /* Größere Schriftgröße für die Inhalte */
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-container {
|
.grid-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(15%, 1fr)); /* Feste Mindestbreite */
|
grid-template-columns: repeat(auto-fill, minmax(var(--tile-width-percent), 1fr));
|
||||||
gap: 1%; /* Abstand zwischen den Kacheln */
|
row-gap: 1vh;
|
||||||
padding: 0px; /* Optional: Innenabstand */
|
column-gap: 1vh;
|
||||||
justify-content: center; /* Zentriert die Kacheln */
|
padding: 0px;
|
||||||
}
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.arrival-card {
|
.arrival-card {
|
||||||
width: 95%; /* Feste Breite */
|
height: var(--tile-height-vh);
|
||||||
height: 24vh; /* Feste Höhe */
|
border-radius: 15px;
|
||||||
border-radius: 15px; /* Abgerundete Ecken für ein moderneres Aussehen */
|
|
||||||
transition: box-shadow 0.3s, transform 0.3s;
|
transition: box-shadow 0.3s, transform 0.3s;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0em;
|
||||||
|
box-sizing: border-box; /* Padding wird in der Höhe berücksichtigt */
|
||||||
|
animation: fadeIn 0.2s ease-in-out; /* Kürzere Animationsdauer */
|
||||||
}
|
}
|
||||||
|
|
||||||
.htmltext {
|
.htmltext {
|
||||||
height: 30vh;
|
height: var(--text-balken-height-vh);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
transition: box-shadow 0.3s, transform 0.3s;
|
transition: box-shadow 0.3s, transform 0.3s;
|
||||||
}
|
}
|
||||||
ion-content {
|
|
||||||
ion-grid.htmltext {
|
|
||||||
height: 30vh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
font-size: 1.2em; /* Größere Icons für bessere Sichtbarkeit */
|
font-size: calc(var(--tile-height-vh) * 0.18); /* Anpassung der Icon-Größe */
|
||||||
|
margin-right: 0.3em; /* Abstand zwischen Icon und Text */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Statusklassen */
|
/* Statusklassen */
|
||||||
.statusLKW_Erfasst {
|
.lkwfertig {
|
||||||
border-left: 10px solid #2dd36f; /* Grün */
|
border-left: 10px solid green;
|
||||||
}
|
background-color: #e6ffe6; /* Leicht grüner Hintergrund für "fertig" */
|
||||||
|
|
||||||
.statusLKW_Freigegeben {
|
|
||||||
border-left: 10px solid #3880ff; /* Blau */
|
|
||||||
}
|
|
||||||
|
|
||||||
.statusLKW_LKW_neu {
|
|
||||||
border-left: 10px solid #f78c40; /* Orange */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.statusLKW_LKW_neu,
|
||||||
.statusLKW_Ankunft {
|
.statusLKW_Ankunft {
|
||||||
border-left: 10px solid #f78c40; /* Orange */
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.statusLKW_Vorbereitet {
|
|
||||||
border-left: 10px solid #c8c8c8; /* Grau */
|
|
||||||
}
|
|
||||||
|
|
||||||
.statusLKW_Vorgeschrieben {
|
|
||||||
border-left: 10px solid #a259ff; /* Violett */
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-default {
|
|
||||||
border-left: 10px solid #c8c8c8; /* Grau */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animationen für Ankunftskarten */
|
/* Animationen für Ankunftskarten */
|
||||||
.arrival-card {
|
|
||||||
animation: fadeIn 0.5s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -96,54 +61,138 @@ ion-icon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1200px) {
|
/* Typografie */
|
||||||
|
ion-title {
|
||||||
|
font-size: calc(var(--tile-height-vh) * 0.24); /* 4% der Kachelhöhe */
|
||||||
|
font-weight: bold;
|
||||||
|
color: #003680;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: calc(var(--tile-height-vh) * 0.24); /* 4% der Kachelhöhe */
|
||||||
|
font-weight: bold;
|
||||||
|
color: #003680;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-card-title {
|
||||||
|
font-size: calc(var(--tile-height-vh) * 0.06); /* Erhöht auf 6% der Kachelhöhe */
|
||||||
|
margin: 0; /* Abstand unter dem Titel */
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap; /* Erlaubt Zeilenumbrüche */
|
||||||
|
overflow-wrap: normal; /* Bricht lange Wörter um */
|
||||||
|
color: #002050; /* Dunkleres Blau für besseren Kontrast */
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-card-content p {
|
||||||
|
font-size: calc(var(--tile-height-vh) * 0.04); /* Erhöht auf 4% der Kachelhöhe */
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap; /* Erlaubt Zeilenumbrüche */
|
||||||
|
overflow-wrap: normal; /* Bricht lange Wörter um */
|
||||||
|
line-height: 1.5; /* Verbesserte Lesbarkeit */
|
||||||
|
color: #333; /* Dunkle Schriftfarbe für besseren Kontrast */
|
||||||
|
}
|
||||||
|
|
||||||
|
.centered-content p {
|
||||||
|
margin-bottom: 0.5em; /* Abstand zwischen den Absätzen */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon-Text-Gruppe */
|
||||||
|
.icon-text-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-text-group ion-icon {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Geräte */
|
||||||
|
@media (max-width: 599px) {
|
||||||
|
.arrival-card {
|
||||||
|
height: auto; /* Höhe passt sich dem Inhalt an */
|
||||||
|
}
|
||||||
|
|
||||||
ion-card-title {
|
ion-card-title {
|
||||||
font-size: 3.5em;
|
font-size: calc(var(--tile-height-vh) * 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-card-content p {
|
ion-card-content p {
|
||||||
font-size: 2em;
|
font-size: calc(var(--tile-height-vh) * 0.05);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-text p {
|
/* Tablets */
|
||||||
font-size: 2em;
|
@media (min-width: 600px) and (max-width: 1199px) {
|
||||||
}
|
ion-card-title {
|
||||||
|
font-size: var(--tile-title-font-size);
|
||||||
|
}
|
||||||
|
|
||||||
.card-title {
|
ion-card-content p {
|
||||||
display: flex;
|
font-size: var(--tile-font-size-date-time);
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 2.5em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-title ion-icon {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-footer {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-top: 1px solid #c8c8c8;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-toolbar {
|
|
||||||
--padding-start: 0;
|
|
||||||
--padding-end: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-title {
|
|
||||||
font-size: 1.6em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #3880ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
ion-title {
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Desktops */
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
ion-card-title {
|
||||||
|
font-size: var(--tile-title-font-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-card-content p {
|
||||||
|
font-size: var(--tile-font-size-date-time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
max-height: calc(var(--tile-height-vh) * 0.40);
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logobar {
|
||||||
|
max-height: 10vh;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-progress-bar {
|
||||||
|
--progress-background: #003680; /* Fortschrittsfarbe (gefüllter Teil) */
|
||||||
|
--background: #e0e0e0; /* Hintergrundfarbe der Leiste */
|
||||||
|
--buffer-background: #003680; /* Hintergrundfarbe des Puffers */
|
||||||
|
}
|
||||||
|
.card-number {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: 5px;
|
||||||
|
font-size: calc(var(--tile-height-vh) * 0.18);
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
/* Versteckt die Buttons und zeigt nur den Indikator-Strich an */
|
||||||
|
.custom-segment-button {
|
||||||
|
--color: transparent; /* Text unsichtbar machen */
|
||||||
|
--background: #003680; /* Hintergrund des Buttons transparent */
|
||||||
|
min-height: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
width: 200px;
|
||||||
|
--indicator-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styling für das ion-segment */
|
||||||
|
.custom-segment {
|
||||||
|
--background: transparent;
|
||||||
|
height: 0.4vh;
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,383 +1,439 @@
|
|||||||
|
// src/app/pages/aviso/aviso.page.ts
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,OnInit,OnDestroy,HostListener,ChangeDetectorRef
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
HostListener,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
HostBinding
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.service';
|
|
||||||
import { AvisoDto } from '../../services/aviso.dto';
|
|
||||||
import { AvisoTvSettingsDto } from '../../services/aviso-tv-settings.dto';
|
|
||||||
import { ToastController } from '@ionic/angular';
|
|
||||||
import { interval, Subject } from 'rxjs';
|
|
||||||
import { switchMap, takeUntil, startWith } from 'rxjs/operators';
|
|
||||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||||
|
import { interval, Subject, throwError, lastValueFrom, Subscription } from 'rxjs';
|
||||||
|
import { switchMap, takeUntil, distinctUntilChanged, tap, catchError, map, take } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.service';
|
||||||
|
import { AvisoDto, TvSettings } from '../../services/aviso.dto';
|
||||||
|
import { AvisoTvTextSettingsDto } from '../../services/aviso-tv-settings.dto';
|
||||||
|
|
||||||
|
// Schnittstelle für die aufgelösten Daten vom Resolver
|
||||||
|
interface AvisoResolvedData {
|
||||||
|
avisoTvTextSettings: AvisoTvTextSettingsDto[];
|
||||||
|
avisoTvSettings: TvSettings[];
|
||||||
|
arrivals: AvisoArrivalsResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AvisoPageData {
|
||||||
|
avisoData: AvisoResolvedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CssVariables {
|
||||||
|
tileWidthPercent: string;
|
||||||
|
tileHeightVh: string;
|
||||||
|
tileTitleFontSize: string;
|
||||||
|
tileFontSizeDateTime: string;
|
||||||
|
tileSeitenwechselInSek: string;
|
||||||
|
textBalkenHeightVh: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ARRIVALS_INTERVAL_MS = 10000;
|
||||||
|
const TVTEXTSETTINGS_INTERVAL_MS = 60000;
|
||||||
|
const TVSETTINGS_INTERVAL_MS = 10000;
|
||||||
|
const TOGGLE_DIV_INTERVAL_MS = 5000;
|
||||||
|
|
||||||
|
interface StatusInfo {
|
||||||
|
class: string;
|
||||||
|
icon: string;
|
||||||
|
color: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const STATUS_MAP: { [key: string]: StatusInfo } = {
|
||||||
|
'3': { class: 'statusLKW_Ankunft', icon: 'time', color: 'medium', text: 'Ankunft' },
|
||||||
|
'lkwfertig': { class: 'lkwfertig', icon: 'time', color: 'warning', text: 'Ankunft' },
|
||||||
|
'default': { class: 'status-default', icon: 'help-circle', color: 'medium', text: 'Unbekannt' }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Neues Interface für die Anzeige der Fixzeilen
|
||||||
|
interface SettingDisplayData {
|
||||||
|
nonEmptyFixeZeilen: {
|
||||||
|
sanitizedHtml: SafeHtml;
|
||||||
|
textAlign: string;
|
||||||
|
}[];
|
||||||
|
currentDivIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-aviso',
|
selector: 'app-aviso',
|
||||||
templateUrl: './aviso.page.html',
|
templateUrl: './aviso.page.html',
|
||||||
styleUrls: ['./aviso.page.scss'],
|
styleUrls: ['./aviso.page.scss'],
|
||||||
})
|
})
|
||||||
export class AvisoPage implements OnInit, OnDestroy {
|
export class AvisoPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
// HostBindings für CSS-Variablen
|
||||||
standort: string = '';
|
@HostBinding('style.--tile-width-percent') tileWidthPercent = '30vw';
|
||||||
seiten: boolean = false;
|
@HostBinding('style.--tile-height-vh') tileHeightVh = '20vh';
|
||||||
onlyOK: boolean = false;
|
@HostBinding('style.--tile-title-font-size') tileTitleFontSize = '2vh';
|
||||||
|
@HostBinding('style.--tile-font-size-date-time') tileFontSizeDateTime = '1vh';
|
||||||
|
@HostBinding('style.--text-balken-height-vh') textBalkenHeightVh = '5vh';
|
||||||
|
|
||||||
|
progressBarValue: number = 0;
|
||||||
|
private progressBarSubscription: Subscription = new Subscription();
|
||||||
|
|
||||||
|
|
||||||
|
currentDate: Date = new Date();
|
||||||
|
private dateSubscription: Subscription = new Subscription();
|
||||||
|
|
||||||
|
// Standort- und Filterinformationen
|
||||||
|
standort = '';
|
||||||
|
standortID = 0;
|
||||||
|
seiten = false;
|
||||||
|
onlyOK = false;
|
||||||
|
|
||||||
// Datenmodelle
|
// Datenmodelle
|
||||||
arrivals: AvisoDto[] = [];
|
arrivals: AvisoDto[] = [];
|
||||||
avisoTvSettings: AvisoTvSettingsDto[] = []; // Neues Datenmodell
|
avisoTvTextSettings: AvisoTvTextSettingsDto[] = [];
|
||||||
|
avisoTvSettings: TvSettings[] = [];
|
||||||
|
|
||||||
// Paginierung
|
// Paginierung
|
||||||
pages: AvisoDto[][] = [];
|
pages: AvisoDto[][] = [];
|
||||||
currentPageIndex: number = 0;
|
currentPageIndex = 0;
|
||||||
tilesPerPage: number = 0;
|
tilesPerPage = 0;
|
||||||
|
|
||||||
// Ladezustand
|
// Ladezustände
|
||||||
loadingArrivals: boolean = false;
|
loadingArrivals = false;
|
||||||
loadingSettings: boolean = false; // Ladezustand für Einstellungen
|
loadingTextSettings = false;
|
||||||
|
loadingTvSettings = false;
|
||||||
|
|
||||||
// Gesamtanzahl
|
// Gesamtanzahlen
|
||||||
totalArrivals: number = 0;
|
totalArrivals = 0;
|
||||||
totalSettings: number = 0; // Gesamtanzahl für Einstellungen
|
totalTextSettings = 0;
|
||||||
|
|
||||||
// Fehlernachricht
|
// Fehlermeldungen
|
||||||
errorMessage: string = '';
|
errorMessage = '';
|
||||||
settingsErrorMessage: string = ''; // Fehlernachricht für Einstellungen
|
settingsErrorMessage = '';
|
||||||
|
|
||||||
// Subjects zum Beenden der Subscriptions
|
// Sonstige Variablen
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
private pageRotation$ = new Subject<void>(); // Optional, für separate Page Rotation
|
|
||||||
|
|
||||||
// Feste Kachelgrößen (entsprechend den CSS-Einstellungen)
|
|
||||||
private readonly tileWidth: number = 450; // in px
|
|
||||||
private readonly tileHeight: number = 100; // in px
|
|
||||||
private readonly gutter: number = 0; // Abstand zwischen den Kacheln in px
|
|
||||||
private readonly containerPadding: number = 0; // Innenabstand des Grid-Containers in px
|
|
||||||
public fontSettings: {textAlign: string}[] = [];
|
|
||||||
private toggleDivInterval: any;
|
private toggleDivInterval: any;
|
||||||
showFirstDiv: boolean = true;
|
private currentCssVariables: CssVariables | null = null;
|
||||||
|
|
||||||
|
// Neues Array für die Anzeige der Fixzeilen
|
||||||
|
settingDisplayData: SettingDisplayData[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private avisoService: AvisoService,
|
private avisoService: AvisoService,
|
||||||
private toastController: ToastController,
|
|
||||||
private cdr: ChangeDetectorRef,
|
private cdr: ChangeDetectorRef,
|
||||||
private sanitizer: DomSanitizer
|
private sanitizer: DomSanitizer
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitizes HTML, extracts font size and text align from span elements,
|
* Konvertiert eine Schriftgröße in verschiedene Einheiten zu Pixel.
|
||||||
* and stores them in dataset attributes and the fontSettings array.
|
* @param fontSize Die Schriftgröße als String (z.B. '12pt', '16px')
|
||||||
* @param html Das zu sanitizende HTML
|
* @returns Die Schriftgröße in Pixel
|
||||||
* @param index Index der Einstellung zur Zuordnung der Stilinformationen
|
*/
|
||||||
* @returns Sanitized HTML als SafeHtml
|
private convertToPx(fontSize: string): number {
|
||||||
*/
|
if (fontSize.endsWith('pt')) {
|
||||||
sanitizeHtml(html: string, index: number): SafeHtml {
|
return parseFloat(fontSize) * 1.333;
|
||||||
const parser = new DOMParser();
|
} else if (fontSize.endsWith('px')) {
|
||||||
const doc = parser.parseFromString(html, 'text/html');
|
return parseFloat(fontSize);
|
||||||
const spans = doc.querySelectorAll('div');
|
} else {
|
||||||
|
return parseFloat(fontSize);
|
||||||
spans.forEach(span => {
|
}
|
||||||
const fontSize = span.style.fontSize;
|
|
||||||
|
|
||||||
if (fontSize) {
|
|
||||||
|
|
||||||
let fontSizePx: number;
|
|
||||||
if (fontSize.endsWith('pt')) {
|
|
||||||
fontSizePx = parseFloat(fontSize) * 1.333; // Umrechnung von pt zu px
|
|
||||||
} else if (fontSize.endsWith('px')) {
|
|
||||||
fontSizePx = parseFloat(fontSize);
|
|
||||||
} else {
|
|
||||||
// Andere Einheiten oder Standardfall
|
|
||||||
fontSizePx = parseFloat(fontSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
const textAlign = span.style.textAlign || 'left';
|
|
||||||
|
|
||||||
// Speichern der ursprünglichen Schriftgröße und Textausrichtung
|
|
||||||
this.fontSettings[index] = {
|
|
||||||
textAlign: textAlign
|
|
||||||
};
|
|
||||||
|
|
||||||
// Speichern in dataset
|
|
||||||
span.dataset['originalFontSizePx'] = fontSizePx.toString();
|
|
||||||
span.dataset['originalTextAlign'] = textAlign;
|
|
||||||
|
|
||||||
// Debugging: Loggen der ursprünglichen Schriftgröße
|
|
||||||
console.log(`Original Font Size for span: "${span.textContent}" = ${fontSizePx}px`);
|
|
||||||
} else {
|
|
||||||
// Falls keine Schriftgröße definiert ist
|
|
||||||
console.log(`No inline font size found for span: "${span.textContent}"`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entfernen der Inline-Schriftgröße
|
|
||||||
span.style.fontSize = '';
|
|
||||||
|
|
||||||
// Hinzufügen der Klasse für die dynamische Anpassung
|
|
||||||
span.classList.add('dynamic-font-size');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Debugging: Loggen des bearbeiteten HTML
|
|
||||||
console.log('Processed HTML:', doc.body.innerHTML);
|
|
||||||
|
|
||||||
return this.sanitizer.bypassSecurityTrustHtml(doc.body.innerHTML);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTextAlign(index: number): string {
|
|
||||||
const settings = this.fontSettings[index];
|
|
||||||
return settings ? settings.textAlign : 'left';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.route.queryParams.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
this.currentDate = new Date();
|
||||||
this.standort = params['standort'] || 'SUB';
|
|
||||||
this.seiten = params['seiten'] === 'true' || false;
|
|
||||||
this.onlyOK = params['onlyOK'] === 'true' || false;
|
|
||||||
|
|
||||||
// Initiales Laden der Daten
|
|
||||||
this.loadArrivals();
|
|
||||||
this.loadAvisoTvSettings();
|
|
||||||
this.startDivToggle();
|
|
||||||
|
|
||||||
|
// Aktualisieren Sie das Datum jede Sekunde
|
||||||
|
this.dateSubscription = interval(1000).subscribe(() => {
|
||||||
|
this.currentDate = new Date();
|
||||||
});
|
});
|
||||||
|
|
||||||
interval(1000000) // 10000 Millisekunden = 10 Sekunden
|
this.route.paramMap.subscribe(params => {
|
||||||
|
this.standort = params.get('standort') || 'SUB';
|
||||||
|
this.standortID = parseInt(params.get('standortID') || '1', 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.route.queryParamMap.subscribe(queryParams => {
|
||||||
|
this.seiten = queryParams.get('seiten') === 'true';
|
||||||
|
this.onlyOK = queryParams.get('onlyOK') === 'true';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Zugriff auf die vom Resolver bereitgestellten Daten
|
||||||
|
this.route.data.pipe(takeUntil(this.destroy$)).subscribe((resolvedData) => {
|
||||||
|
const data = (resolvedData as any)['avisoData'] as AvisoResolvedData;
|
||||||
|
|
||||||
|
this.avisoTvTextSettings = data.avisoTvTextSettings;
|
||||||
|
this.avisoTvSettings = data.avisoTvSettings;
|
||||||
|
this.arrivals = data.arrivals.avisos;
|
||||||
|
this.totalArrivals = data.arrivals.totalCount;
|
||||||
|
|
||||||
|
// Process the HTML settings
|
||||||
|
this.preprocessHtmlSettings();
|
||||||
|
|
||||||
|
// Setzen der CSS-Variablen
|
||||||
|
this.setCSSVariables();
|
||||||
|
|
||||||
|
// Starten der Div-Umschaltung
|
||||||
|
this.startDivToggle();
|
||||||
|
|
||||||
|
// Starten der Seitenrotation
|
||||||
|
this.paginateArrivals();
|
||||||
|
this.startPageRotation();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Automatisches Aktualisieren der Arrivals alle 10 Sekunden
|
||||||
|
interval(ARRIVALS_INTERVAL_MS)
|
||||||
.pipe(
|
.pipe(
|
||||||
startWith(0), // Sofortiger Start ohne Warten
|
|
||||||
switchMap(() => {
|
switchMap(() => {
|
||||||
// Nur den Ladeindikator anzeigen, wenn keine Daten vorhanden sind
|
|
||||||
this.loadingArrivals = this.arrivals.length === 0;
|
this.loadingArrivals = this.arrivals.length === 0;
|
||||||
this.errorMessage = '';
|
this.errorMessage = '';
|
||||||
return this.avisoService.getArrivals(this.standort, this.seiten, this.onlyOK);
|
return this.avisoService.getArrivals(this.standort, this.seiten, this.onlyOK);
|
||||||
}),
|
}),
|
||||||
|
distinctUntilChanged((prev, curr) => this.arrivalsAreEqual(prev.avisos, curr.avisos)),
|
||||||
takeUntil(this.destroy$)
|
takeUntil(this.destroy$)
|
||||||
)
|
)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(data: AvisoArrivalsResponse) => { // Typisierung der empfangenen Daten
|
(data: AvisoArrivalsResponse) => {
|
||||||
console.log('Received arrivals data:', data); // Zum Debuggen
|
|
||||||
this.arrivals = data.avisos;
|
this.arrivals = data.avisos;
|
||||||
this.totalArrivals = data.totalCount;
|
this.totalArrivals = data.totalCount;
|
||||||
this.loadingArrivals = false;
|
this.loadingArrivals = false;
|
||||||
this.paginateArrivals();
|
this.paginateArrivals();
|
||||||
this.cdr.detectChanges(); // Manuelle Change Detection
|
this.cdr.detectChanges();
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
console.error('Fehler beim Laden der Arrivals:', error);
|
|
||||||
this.presentToast(`Fehler beim Laden der Arrivals: ${error}`);
|
|
||||||
this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.';
|
this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.';
|
||||||
this.loadingArrivals = false;
|
this.loadingArrivals = false;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Automatisches Aktualisieren der TV Settings alle 10 Sekunden
|
||||||
// Automatisches Aktualisieren der TV-Einstellungen alle 10 Sekunden
|
interval(TVSETTINGS_INTERVAL_MS)
|
||||||
interval(1000000) // 10000 Millisekunden = 10 Sekunden
|
|
||||||
.pipe(
|
.pipe(
|
||||||
startWith(0),
|
switchMap(() => this.loadAvisoTvSettings()),
|
||||||
switchMap(() => {
|
|
||||||
this.loadingSettings = this.avisoTvSettings.length === 0;
|
|
||||||
this.settingsErrorMessage = '';
|
|
||||||
return this.avisoService.getAvisoTvSettings(this.standort);
|
|
||||||
}),
|
|
||||||
takeUntil(this.destroy$)
|
takeUntil(this.destroy$)
|
||||||
)
|
)
|
||||||
.subscribe(
|
.subscribe();
|
||||||
(data: AvisoTvSettingsDto[]) => { // Typisierung als Array
|
|
||||||
console.log('Received TV settings data:', data);
|
|
||||||
this.avisoTvSettings = data;
|
|
||||||
this.totalSettings = data.length; // Setze totalSettings auf die Länge des Arrays
|
|
||||||
this.loadingSettings = false;
|
|
||||||
this.cdr.detectChanges(); // Manuelle Change Detection
|
|
||||||
|
|
||||||
// Debugging: Überprüfe jede Einstellung
|
// Automatisches Aktualisieren der TV Text Settings alle 60 Sekunden
|
||||||
this.avisoTvSettings.forEach(setting => {
|
interval(TVTEXTSETTINGS_INTERVAL_MS)
|
||||||
console.log(`Setting ID: ${setting.tvTextBezeichnungID}, isActive: ${setting.isActive}, position: ${setting.position}, fixeZeile1: ${setting.fixeZeile1}`);
|
.pipe(
|
||||||
});
|
switchMap(() => this.loadAvisoTvTextSettings()),
|
||||||
},
|
takeUntil(this.destroy$)
|
||||||
(error) => {
|
)
|
||||||
console.error('Fehler beim Laden der TV Settings:', error);
|
.subscribe();
|
||||||
this.presentToast(`Fehler beim Laden der TV Settings: ${error}`);
|
|
||||||
this.settingsErrorMessage = 'Fehler beim Laden der TV Settings. Bitte versuche es später erneut.';
|
|
||||||
this.loadingSettings = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Starte die Page Rotation einmal nach dem Initialen Laden
|
|
||||||
// Optional: Falls du separate Subjects für Page Rotation verwendest
|
|
||||||
// this.startPageRotation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private startProgressBar(seitenwechselInSek: number): void {
|
||||||
|
// Falls eine vorherige Subscription existiert, beenden wir sie
|
||||||
|
if (this.progressBarSubscription) {
|
||||||
|
this.progressBarSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setzen des Fortschrittswerts auf 0
|
||||||
|
this.progressBarValue = 0;
|
||||||
|
|
||||||
|
const progressBarIntervalMs = 100; // Aktualisierung alle 100ms
|
||||||
|
const totalSteps = Math.floor((seitenwechselInSek * 1000) / progressBarIntervalMs);
|
||||||
|
|
||||||
|
this.progressBarSubscription = interval(progressBarIntervalMs)
|
||||||
|
.pipe(
|
||||||
|
take(totalSteps),
|
||||||
|
map((step) => (step + 1) / totalSteps),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
)
|
||||||
|
.subscribe((progress) => {
|
||||||
|
this.progressBarValue = progress;
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getOverallIndex(i: number): number {
|
||||||
|
let count = 0;
|
||||||
|
for (let j = 0; j < this.currentPageIndex; j++) {
|
||||||
|
count += this.pages[j].length;
|
||||||
|
}
|
||||||
|
return count + i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private preprocessHtmlSettings() {
|
||||||
|
this.settingDisplayData = this.avisoTvTextSettings.map((setting, index) => {
|
||||||
|
const nonEmptyFixeZeilen = [];
|
||||||
|
|
||||||
|
// Verarbeiten von fixeZeile1
|
||||||
|
if (setting.fixeZeile1) {
|
||||||
|
const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile1, index);
|
||||||
|
nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verarbeiten von fixeZeile2
|
||||||
|
if (setting.fixeZeile2) {
|
||||||
|
const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile2, index);
|
||||||
|
nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verarbeiten von fixeZeile3
|
||||||
|
if (setting.fixeZeile3) {
|
||||||
|
const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile3, index);
|
||||||
|
nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign });
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
nonEmptyFixeZeilen,
|
||||||
|
currentDivIndex: 0
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private processHtml(html: string, index: number): { sanitizedHtml: SafeHtml; textAlign: string } {
|
||||||
|
// Vermeide das Modifizieren des HTML-Inhalts, um die Formatierung zu erhalten
|
||||||
|
const sanitizedHtml = this.sanitizer.bypassSecurityTrustHtml(html);
|
||||||
|
|
||||||
|
// Extrahiere text-align aus dem ersten Div
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const doc = parser.parseFromString(html, 'text/html');
|
||||||
|
const firstDiv = doc.querySelector('div');
|
||||||
|
let textAlign = 'left';
|
||||||
|
if (firstDiv) {
|
||||||
|
textAlign = firstDiv.style.textAlign || 'left';
|
||||||
|
}
|
||||||
|
return { sanitizedHtml, textAlign };
|
||||||
|
}
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
// Beenden aller Subscriptions, um Speicherlecks zu vermeiden
|
|
||||||
this.destroy$.next();
|
this.destroy$.next();
|
||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
|
|
||||||
// Beende auch die Page Rotation Subscription, falls du separate Subjects verwendest
|
if (this.toggleDivInterval) {
|
||||||
// this.pageRotation$.next();
|
clearInterval(this.toggleDivInterval);
|
||||||
// this.pageRotation$.complete();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (this.progressBarSubscription) {
|
||||||
* Lädt die Ankünfte (Arrivals) von der API.
|
this.progressBarSubscription.unsubscribe();
|
||||||
*/
|
}
|
||||||
loadArrivals() {
|
|
||||||
this.loadingArrivals = true;
|
|
||||||
this.avisoService
|
|
||||||
.getArrivals(this.standort, this.seiten, this.onlyOK)
|
|
||||||
.pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe(
|
|
||||||
(data: AvisoArrivalsResponse) => {
|
|
||||||
console.log('Received arrivals data:', data);
|
|
||||||
this.arrivals = data.avisos;
|
|
||||||
this.totalArrivals = data.totalCount;
|
|
||||||
this.loadingArrivals = false;
|
|
||||||
this.paginateArrivals();
|
|
||||||
this.cdr.detectChanges();
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.error('Fehler beim Laden der Arrivals:', error);
|
|
||||||
this.presentToast(`Fehler beim Laden der Arrivals: ${error}`);
|
|
||||||
this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.';
|
|
||||||
this.loadingArrivals = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (this.dateSubscription) {
|
||||||
* Lädt die Aviso TV Einstellungen von der API.
|
this.dateSubscription.unsubscribe();
|
||||||
*/
|
|
||||||
loadAvisoTvSettings() {
|
|
||||||
this.loadingSettings = true;
|
|
||||||
this.avisoService
|
|
||||||
.getAvisoTvSettings(this.standort)
|
|
||||||
.pipe(takeUntil(this.destroy$))
|
|
||||||
.subscribe(
|
|
||||||
(data: AvisoTvSettingsDto[]) => { // Typisierung als Array
|
|
||||||
console.log('Received TV settings data:', data); // Zum Debuggen
|
|
||||||
this.avisoTvSettings = data;
|
|
||||||
this.totalSettings = data.length; // Setze totalSettings auf die Länge des Arrays
|
|
||||||
this.loadingSettings = false;
|
|
||||||
this.cdr.detectChanges(); // Manuelle Change Detection
|
|
||||||
showFirstDiv: true // Initialisiere alle auf true
|
|
||||||
|
|
||||||
// Debugging: Überprüfe jede Einstellung
|
|
||||||
this.avisoTvSettings.forEach(setting => {
|
|
||||||
console.log(`Setting ID: ${setting.tvTextBezeichnungID}, isActive: ${setting.isActive}, position: ${setting.position}, fixeZeile1: ${setting.fixeZeile1}`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
console.error('Fehler beim Laden der TV Settings:', error);
|
|
||||||
this.presentToast(`Fehler beim Laden der TV Settings: ${error}`);
|
|
||||||
this.settingsErrorMessage = 'Fehler beim Laden der TV Settings. Bitte versuche es später erneut.';
|
|
||||||
this.loadingSettings = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
startDivToggle() {
|
|
||||||
this.toggleDivInterval = setInterval(() => {
|
|
||||||
this.showFirstDiv = !this.showFirstDiv;
|
|
||||||
this.cdr.detectChanges(); // Manuelle Change Detection, falls nötig
|
|
||||||
}, 5000); // 5000 Millisekunden = 5 Sekunden
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Lädt Arrivals und TV-Einstellungen basierend auf aktuellen Filtern.
|
|
||||||
*/
|
|
||||||
applyFilters() {
|
|
||||||
this.loadArrivals();
|
|
||||||
this.loadAvisoTvSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Zeigt eine Toast-Nachricht an.
|
|
||||||
* @param message Die Nachricht, die angezeigt werden soll.
|
|
||||||
*/
|
|
||||||
async presentToast(message: string) {
|
|
||||||
const toast = await this.toastController.create({
|
|
||||||
message: message,
|
|
||||||
duration: 3000,
|
|
||||||
position: 'bottom',
|
|
||||||
});
|
|
||||||
toast.present();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methoden zur Bestimmung von Statusklassen und -farben
|
|
||||||
getStatusClass(status: number): string {
|
|
||||||
switch (status) {
|
|
||||||
case 0:
|
|
||||||
return 'statusLKW_Erfasst';
|
|
||||||
case 1:
|
|
||||||
return 'statusLKW_Freigegeben';
|
|
||||||
case 2:
|
|
||||||
return 'statusLKW_LKW_neu';
|
|
||||||
case 3:
|
|
||||||
return 'statusLKW_Ankunft';
|
|
||||||
case 4:
|
|
||||||
return 'statusLKW_Vorbereitet';
|
|
||||||
case 5:
|
|
||||||
return 'statusLKW_Vorgeschrieben';
|
|
||||||
default:
|
|
||||||
return 'status-default';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private setCSSVariables(): void {
|
||||||
|
if (this.avisoTvSettings && this.avisoTvSettings.length > 0) {
|
||||||
|
const settings = this.avisoTvSettings[0];
|
||||||
|
const newCssVariables: CssVariables = {
|
||||||
|
tileWidthPercent: `${settings.kachelWidthInPercent}vw`,
|
||||||
|
tileHeightVh: `${settings.kachelHeightInPercent}vh`,
|
||||||
|
tileTitleFontSize: `${settings.kachelFontSizeLkwNummer}vh`,
|
||||||
|
tileFontSizeDateTime: `${settings.kachelFontSizeDateTime}vh`,
|
||||||
|
tileSeitenwechselInSek: `${settings.seitenwechselInSek}s`,
|
||||||
|
textBalkenHeightVh: `${settings.textBalkenHeightInPercent}vh`,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.currentCssVariables && this.hasCssVariablesChanged(newCssVariables)) {
|
||||||
|
this.reloadPageOnce();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, newCssVariables);
|
||||||
|
this.currentCssVariables = newCssVariables;
|
||||||
|
} else {
|
||||||
|
console.warn('avisoTvSettings ist nicht verfügbar oder leer');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasCssVariablesChanged(newVars: CssVariables): boolean {
|
||||||
|
return Object.keys(newVars).some(key => (newVars as any)[key] !== (this.currentCssVariables as any)[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadAvisoTvSettings(): Promise<void> {
|
||||||
|
this.loadingTvSettings = true;
|
||||||
|
try {
|
||||||
|
const data: TvSettings[] = await lastValueFrom(
|
||||||
|
this.avisoService.getAvisoTvSettings(this.avisoTvTextSettings[0]?.standortID || this.standortID).pipe(
|
||||||
|
tap((data: TvSettings[]) => {
|
||||||
|
this.avisoTvSettings = data;
|
||||||
|
this.loadingTvSettings = false;
|
||||||
|
this.setCSSVariables();
|
||||||
|
}),
|
||||||
|
catchError((error: any) => this.handleSettingsError(error, 'TV Settings'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
// Fehler wird bereits in handleSettingsError behandelt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadAvisoTvTextSettings(): Promise<void> {
|
||||||
|
this.loadingTextSettings = true;
|
||||||
|
try {
|
||||||
|
const data: AvisoTvTextSettingsDto[] = await lastValueFrom(
|
||||||
|
this.avisoService.getAvisoTvTextSettings(this.standort).pipe(
|
||||||
|
tap((data: AvisoTvTextSettingsDto[]) => {
|
||||||
|
this.avisoTvTextSettings = data;
|
||||||
|
this.totalTextSettings = data.length;
|
||||||
|
this.loadingTextSettings = false;
|
||||||
|
// Process the new HTML settings
|
||||||
|
this.preprocessHtmlSettings();
|
||||||
|
}),
|
||||||
|
catchError((error: any) => this.handleSettingsError(error, 'TV Text Settings'))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
// Fehler wird bereits in handleSettingsError behandelt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSettingsError(error: any, context: string) {
|
||||||
|
console.error(`Fehler beim Laden der ${context}:`, error);
|
||||||
|
this.settingsErrorMessage = `Fehler beim Laden der ${context}. Bitte versuche es später erneut.`;
|
||||||
|
this.loadingTvSettings = false;
|
||||||
|
this.loadingTextSettings = false;
|
||||||
|
return throwError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private startDivToggle(): void {
|
||||||
|
const shouldToggle = this.settingDisplayData.some(data => data.nonEmptyFixeZeilen.length > 1);
|
||||||
|
|
||||||
|
if (shouldToggle) {
|
||||||
|
this.toggleDivInterval = setInterval(() => {
|
||||||
|
this.settingDisplayData.forEach(data => {
|
||||||
|
if (data.nonEmptyFixeZeilen.length > 1) {
|
||||||
|
data.currentDivIndex = (data.currentDivIndex + 1) % data.nonEmptyFixeZeilen.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}, TOGGLE_DIV_INTERVAL_MS);
|
||||||
|
} else {
|
||||||
|
// Initialize currentDivIndex to 0
|
||||||
|
this.settingDisplayData.forEach(data => data.currentDivIndex = 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status-Methoden mithilfe des STATUS_MAP
|
||||||
|
getStatusClass(status: number, lkwFertig: boolean): string {
|
||||||
|
if (lkwFertig) {
|
||||||
|
return STATUS_MAP['lkwfertig'].class;
|
||||||
|
}
|
||||||
|
return STATUS_MAP[status.toString()]?.class || STATUS_MAP['default'].class;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getStatusIcon(status: number): string {
|
getStatusIcon(status: number): string {
|
||||||
switch (status) {
|
return STATUS_MAP[status.toString()]?.icon || STATUS_MAP['default'].icon;
|
||||||
case 0:
|
|
||||||
return 'checkmark-circle'; // Erfasst
|
|
||||||
case 1:
|
|
||||||
return 'checkmark-circle'; // Freigegeben
|
|
||||||
case 2:
|
|
||||||
return 'help-circle'; // LKW n.e.
|
|
||||||
case 3:
|
|
||||||
return 'time'; // Ankunft
|
|
||||||
case 4:
|
|
||||||
return 'construct'; // Vorbereitet
|
|
||||||
case 5:
|
|
||||||
return 'bookmarks'; // Vorgeschrieben
|
|
||||||
default:
|
|
||||||
return 'help-circle'; // Unbekannt
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatusColor(status: number): string {
|
getStatusColor(status: number): string {
|
||||||
switch (status) {
|
return STATUS_MAP[status.toString()]?.color || STATUS_MAP['default'].color;
|
||||||
case 0:
|
|
||||||
return 'success'; // Erfasst - Grün
|
|
||||||
case 1:
|
|
||||||
return 'primary'; // Freigegeben - Blau
|
|
||||||
case 2:
|
|
||||||
return 'warning'; // LKW n.e. - Gelb/Orange
|
|
||||||
case 3:
|
|
||||||
return 'warning'; // Ankunft - Gelb/Orange
|
|
||||||
case 4:
|
|
||||||
return 'secondary'; // Vorbereitet - Grau
|
|
||||||
case 5:
|
|
||||||
return 'tertiary'; // Vorgeschrieben - Violett
|
|
||||||
default:
|
|
||||||
return 'medium'; // Unbekannt - Grau
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatusText(status: number): string {
|
getStatusText(status: number): string {
|
||||||
switch (status) {
|
return STATUS_MAP[status.toString()]?.text || STATUS_MAP['default'].text;
|
||||||
case 0:
|
|
||||||
return 'Erfasst';
|
|
||||||
case 1:
|
|
||||||
return 'Freigegeben';
|
|
||||||
case 2:
|
|
||||||
return 'LKW n.e.';
|
|
||||||
case 3:
|
|
||||||
return 'Ankunft';
|
|
||||||
case 4:
|
|
||||||
return 'Vorbereitet';
|
|
||||||
case 5:
|
|
||||||
return 'Vorgeschrieben';
|
|
||||||
default:
|
|
||||||
return 'Unbekannt';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -386,99 +442,155 @@ export class AvisoPage implements OnInit, OnDestroy {
|
|||||||
* @returns Eine CSS-Klassen-String
|
* @returns Eine CSS-Klassen-String
|
||||||
*/
|
*/
|
||||||
getPositionClass(position: string): string {
|
getPositionClass(position: string): string {
|
||||||
const pos = position.toLowerCase(); // Konvertiere zu Kleinbuchstaben
|
const pos = position.toLowerCase();
|
||||||
switch (pos) {
|
const positionClasses: { [key: string]: string } = {
|
||||||
case 'top':
|
'top': 'position-top',
|
||||||
return 'position-top';
|
'middle': 'position-middle',
|
||||||
case 'middle':
|
'left': 'position-left',
|
||||||
return 'position-middle';
|
'right': 'position-right'
|
||||||
case 'left':
|
};
|
||||||
return 'position-left';
|
return positionClasses[pos] || '';
|
||||||
case 'right':
|
}
|
||||||
return 'position-right';
|
|
||||||
default:
|
private reloadPageOnce(): void {
|
||||||
return '';
|
if (!sessionStorage.getItem('pageReloaded')) {
|
||||||
|
sessionStorage.setItem('pageReloaded', 'true');
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
sessionStorage.removeItem('pageReloaded');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paginierung der Arrivals
|
// Paginierung der Arrivals
|
||||||
paginateArrivals() {
|
private paginateArrivals(): void {
|
||||||
// Berechnung der verfügbaren Breite und Höhe
|
if (!this.avisoTvSettings || this.avisoTvSettings.length === 0) {
|
||||||
const windowWidth = window.innerWidth;
|
return;
|
||||||
const windowHeight = window.innerHeight;
|
|
||||||
// Definiere die Prozentsätze für Layout-Parameter
|
|
||||||
const titleHeightPercent = 5; // z.B. 10% der Fensterhöhe
|
|
||||||
const htmltextPercent = this.totalArrivals > 0 ? 30 : 0;
|
|
||||||
|
|
||||||
const containerPaddingPercent = 0; // z.B. 5% der Fensterbreite
|
|
||||||
const gutterPercent = 1;
|
|
||||||
const tileWidthPercent = 15; // z.B. 20% der Fensterbreite
|
|
||||||
const tileHeightPercent = 23; // z.B. 25% der Fensterhöhe
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const containerPadding = (containerPaddingPercent / 100) * windowWidth;
|
|
||||||
const gutter = (gutterPercent / 100) * windowWidth;
|
|
||||||
const tileWidth = (tileWidthPercent / 100) * windowWidth;
|
|
||||||
const tileHeight = (tileHeightPercent / 100) * windowHeight;
|
|
||||||
|
|
||||||
// Berechnung der verfügbaren Breite für die Kacheln
|
|
||||||
const containerPaddingTotal = containerPadding * 2; // Links und rechts
|
|
||||||
const columns = Math.floor((windowWidth - containerPaddingTotal + gutter) / (tileWidth + gutter));
|
|
||||||
|
|
||||||
// Berechnung der verfügbaren Höhe für die Kacheln
|
|
||||||
const titleHeight = (titleHeightPercent / 100) * windowHeight;
|
|
||||||
let htmltext = 0;
|
|
||||||
if (this.totalArrivals > 0) {
|
|
||||||
htmltext = (htmltextPercent / 100) * windowHeight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const availableHeightForTiles = windowHeight - htmltext - titleHeight - containerPadding * 2 - gutter * (columns > 1 ? columns : 0);
|
const settings = this.avisoTvSettings[0];
|
||||||
|
const windowWidth = window.outerWidth;
|
||||||
|
const windowHeight = window.outerHeight;
|
||||||
|
|
||||||
// Berechnung der maximal möglichen Kacheln pro Spalte
|
const tileWidth = (settings.kachelWidthInPercent / 100) * windowWidth;
|
||||||
const rows = Math.floor((availableHeightForTiles + gutter) / (tileHeight + gutter));
|
const tileHeight = (settings.kachelHeightInPercent / 100) * windowHeight;
|
||||||
|
const logo = (10 / 100) * windowHeight;
|
||||||
|
|
||||||
|
// Definieren Sie separate horizontale und vertikale Gutter
|
||||||
|
const gutterHorizontal = (1 / 100) * windowHeight;
|
||||||
|
const gutterVertical = (1 / 100) * windowHeight;
|
||||||
|
|
||||||
|
const containerPadding = (0 / 100) * windowHeight;
|
||||||
|
|
||||||
|
const containerPaddingTotal = containerPadding * 2;
|
||||||
|
|
||||||
|
// Berechnung der Spalten unter Verwendung von gutterHorizontal
|
||||||
|
const columns = Math.floor(
|
||||||
|
(windowWidth - containerPaddingTotal + gutterHorizontal) / (tileWidth + gutterHorizontal)
|
||||||
|
) || 1;
|
||||||
|
|
||||||
|
const htmltext = this.totalArrivals > 0 ? (settings.textBalkenHeightInPercent / 100) * windowHeight : 0;
|
||||||
|
|
||||||
|
// Verfügbare Höhe für Kacheln unter Verwendung von gutterVertical
|
||||||
|
const availableHeightForTiles =
|
||||||
|
windowHeight -
|
||||||
|
logo -
|
||||||
|
htmltext -
|
||||||
|
containerPadding * 2 -
|
||||||
|
gutterVertical * (columns > 1 ? columns : 0);
|
||||||
|
|
||||||
|
// Berechnung der Reihen unter Verwendung von gutterVertical
|
||||||
|
const rows = Math.floor(
|
||||||
|
(availableHeightForTiles + gutterVertical) / (tileHeight + gutterVertical)
|
||||||
|
) || 1;
|
||||||
|
|
||||||
// Berechnung der Kacheln pro Seite
|
|
||||||
this.tilesPerPage = columns * rows;
|
this.tilesPerPage = columns * rows;
|
||||||
|
|
||||||
// Sicherstellen, dass mindestens eine Kachel pro Seite angezeigt wird
|
|
||||||
this.tilesPerPage = this.tilesPerPage > 0 ? this.tilesPerPage : 1;
|
this.tilesPerPage = this.tilesPerPage > 0 ? this.tilesPerPage : 1;
|
||||||
|
|
||||||
console.log('Columns:', columns);
|
|
||||||
console.log('Rows:', rows);
|
|
||||||
console.log('Tiles per Page:', this.tilesPerPage);
|
|
||||||
|
|
||||||
// Aufteilung der Arrivals in Seiten
|
|
||||||
this.pages = [];
|
this.pages = [];
|
||||||
for (let i = 0; i < this.arrivals.length; i += this.tilesPerPage) {
|
for (let i = 0; i < this.arrivals.length; i += this.tilesPerPage) {
|
||||||
this.pages.push(this.arrivals.slice(i, i + this.tilesPerPage));
|
this.pages.push(this.arrivals.slice(i, i + this.tilesPerPage));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset der aktuellen Seite, wenn nötig
|
|
||||||
if (this.currentPageIndex >= this.pages.length) {
|
if (this.currentPageIndex >= this.pages.length) {
|
||||||
this.currentPageIndex = 0;
|
this.currentPageIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Total Pages:', this.pages.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Automatisches Wechseln der Seiten alle 10 Sekunden
|
|
||||||
startPageRotation() {
|
// Automatisches Wechseln der Seiten alle seitenwechselInSek Sekunden
|
||||||
interval(10000) // 10000 Millisekunden = 10 Sekunden
|
private startPageRotation(): void {
|
||||||
.pipe(takeUntil(this.destroy$))
|
if (!this.avisoTvSettings || this.avisoTvSettings.length === 0) {
|
||||||
.subscribe(() => {
|
console.warn('avisoTvSettings ist nicht verfügbar oder leer');
|
||||||
if (this.pages.length > 0) {
|
return;
|
||||||
this.currentPageIndex = (this.currentPageIndex + 1) % this.pages.length;
|
}
|
||||||
console.log('Wechsel zu Seite:', this.currentPageIndex + 1);
|
|
||||||
}
|
const seitenwechselInSek = this.avisoTvSettings[0].seitenwechselInSek;
|
||||||
});
|
console.log('Seitenwechselintervall (Sek):', seitenwechselInSek);
|
||||||
|
|
||||||
|
if (typeof seitenwechselInSek === 'number' && seitenwechselInSek > 0) {
|
||||||
|
const intervalMs = seitenwechselInSek * 1000;
|
||||||
|
console.log('Seitenwechselintervall (ms):', intervalMs);
|
||||||
|
|
||||||
|
// Starten Sie den Fortschrittsbalken
|
||||||
|
this.startProgressBar(seitenwechselInSek);
|
||||||
|
|
||||||
|
interval(intervalMs)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(() => {
|
||||||
|
if (this.pages.length > 0) {
|
||||||
|
this.currentPageIndex = (this.currentPageIndex + 1) % this.pages.length;
|
||||||
|
console.log('Wechsel zu Seite:', this.currentPageIndex + 1);
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
|
||||||
|
// Fortschrittsbalken neu starten
|
||||||
|
this.startProgressBar(seitenwechselInSek);
|
||||||
|
} else {
|
||||||
|
console.warn('Keine Seiten verfügbar zum Wechseln');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn('seitenwechselInSek ist ungültig:', seitenwechselInSek);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event Listener für Fenstergrößenänderungen, um die Paginierung anzupassen
|
* Event Listener für Fenstergrößenänderungen, um die Paginierung anzupassen
|
||||||
*/
|
*/
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize')
|
||||||
onResize(event: Event) {
|
onResize(): void {
|
||||||
this.paginateArrivals();
|
this.paginateArrivals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vergleicht zwei Arrivals-Arrays, um festzustellen, ob sie gleich sind.
|
||||||
|
* @param a Erstes Arrivals-Array
|
||||||
|
* @param b Zweites Arrivals-Array
|
||||||
|
* @returns `true`, wenn beide Arrays gleich sind, ansonsten `false`
|
||||||
|
*/
|
||||||
|
private arrivalsAreEqual(a: AvisoDto[], b: AvisoDto[]): boolean {
|
||||||
|
if (a.length !== b.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
if (
|
||||||
|
a[i].avisoID !== b[i].avisoID ||
|
||||||
|
a[i].status !== b[i].status ||
|
||||||
|
a[i].lkW_Nr !== b[i].lkW_Nr ||
|
||||||
|
a[i].ankunft !== b[i].ankunft ||
|
||||||
|
a[i].dauer !== b[i].dauer ||
|
||||||
|
a[i].letzterMitarbeiter !== b[i].letzterMitarbeiter ||
|
||||||
|
a[i].weiterleitungTextTV !== b[i].weiterleitungTextTV ||
|
||||||
|
a[i].imEx !== b[i].imEx ||
|
||||||
|
a[i].zollDigitalEingereicht !== b[i].zollDigitalEingereicht ||
|
||||||
|
a[i].buero !== b[i].buero ||
|
||||||
|
a[i].avisoTVHinweis !== b[i].avisoTVHinweis
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
52
src/app/pages/aviso/aviso.resolver.ts
Normal file
52
src/app/pages/aviso/aviso.resolver.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// src/app/resolvers/aviso.resolver.ts
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { Observable, forkJoin, of } from 'rxjs';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.service';
|
||||||
|
import { AvisoTvTextSettingsDto, TvSettings } from '../../services/aviso.dto';
|
||||||
|
|
||||||
|
interface AvisoResolvedData {
|
||||||
|
avisoTvTextSettings: AvisoTvTextSettingsDto[];
|
||||||
|
avisoTvSettings: TvSettings[];
|
||||||
|
arrivals: AvisoArrivalsResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class AvisoResolver implements Resolve<AvisoResolvedData> {
|
||||||
|
constructor(private avisoService: AvisoService) { }
|
||||||
|
|
||||||
|
resolve(
|
||||||
|
route: ActivatedRouteSnapshot,
|
||||||
|
state: RouterStateSnapshot
|
||||||
|
): Observable<AvisoResolvedData> {
|
||||||
|
const standort = route.paramMap.get('standort') || 'SUB';
|
||||||
|
const seiten = route.queryParamMap.get('seiten') === 'true';
|
||||||
|
const onlyOK = route.queryParamMap.get('onlyOK') === 'true';
|
||||||
|
const standortID = parseInt(route.paramMap.get('standortID') || '1', 10);
|
||||||
|
|
||||||
|
return forkJoin({
|
||||||
|
avisoTvTextSettings: this.avisoService.getAvisoTvTextSettings(standort).pipe(
|
||||||
|
catchError(error => {
|
||||||
|
console.error('Fehler beim Laden der TV Text Settings', error);
|
||||||
|
return of([]);
|
||||||
|
})
|
||||||
|
),
|
||||||
|
avisoTvSettings: this.avisoService.getAvisoTvSettings(standortID).pipe(
|
||||||
|
catchError(error => {
|
||||||
|
console.error('Fehler beim Laden der TV Settings', error);
|
||||||
|
return of([]);
|
||||||
|
})
|
||||||
|
),
|
||||||
|
arrivals: this.avisoService.getArrivals(standort, seiten, onlyOK).pipe(
|
||||||
|
catchError(error => {
|
||||||
|
console.error('Fehler beim Laden der Arrivals', error);
|
||||||
|
return of({ avisos: [], totalCount: 0 });
|
||||||
|
})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export interface AvisoTvSettingsDto {
|
export interface AvisoTvTextSettingsDto {
|
||||||
tvTextBezeichnungID: number;
|
tvTextBezeichnungID: number;
|
||||||
standortID: number;
|
standortID: number;
|
||||||
tvTextBezeichnung: string;
|
tvTextBezeichnung: string;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export interface AvisoDto {
|
|||||||
avisoID: number;
|
avisoID: number;
|
||||||
status: number;
|
status: number;
|
||||||
lkW_Nr: string;
|
lkW_Nr: string;
|
||||||
|
lkW_fertig: boolean;
|
||||||
ankunft: string | null;
|
ankunft: string | null;
|
||||||
dauer: string;
|
dauer: string;
|
||||||
letzterMitarbeiter: string;
|
letzterMitarbeiter: string;
|
||||||
@@ -11,3 +12,40 @@ export interface AvisoDto {
|
|||||||
buero: string;
|
buero: string;
|
||||||
avisoTVHinweis: string;
|
avisoTVHinweis: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TvSettings {
|
||||||
|
TvSettingID: number;
|
||||||
|
StandortID: number;
|
||||||
|
kachelWidthInPercent: number;
|
||||||
|
kachelHeightInPercent: number;
|
||||||
|
kachelFontSizeLkwNummer: number;
|
||||||
|
kachelFontSizeDateTime: number;
|
||||||
|
seitenwechselInSek: number;
|
||||||
|
textBalkenHeightInPercent: number;
|
||||||
|
logo: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvisoTvTextSettingsDto {
|
||||||
|
tvTextBezeichnungID: number;
|
||||||
|
standortID: number;
|
||||||
|
tvTextBezeichnung: string;
|
||||||
|
standort: string;
|
||||||
|
position: string;
|
||||||
|
fixeZeile1?: string;
|
||||||
|
fixeZeile2?: string;
|
||||||
|
fixeZeile3?: string;
|
||||||
|
art?: string;
|
||||||
|
startDate?: string | null;
|
||||||
|
endDate?: string | null;
|
||||||
|
startTime?: string | null;
|
||||||
|
endTime?: string | null;
|
||||||
|
isRecurring: boolean;
|
||||||
|
isMonday: boolean;
|
||||||
|
isTuesday: boolean;
|
||||||
|
isWednesday: boolean;
|
||||||
|
isThursday: boolean;
|
||||||
|
isFriday: boolean;
|
||||||
|
isSaturday: boolean;
|
||||||
|
isSunday: boolean;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { Injectable } from '@angular/core';
|
|||||||
import { HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http';
|
import { HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http';
|
||||||
import { Observable, throwError } from 'rxjs';
|
import { Observable, throwError } from 'rxjs';
|
||||||
import { catchError, tap } from 'rxjs/operators';
|
import { catchError, tap } from 'rxjs/operators';
|
||||||
import { AvisoDto } from './aviso.dto'; // Importiere das Interface
|
import { AvisoDto, TvSettings } from './aviso.dto'; // Importiere das Interface
|
||||||
import { AvisoTvSettingsDto } from './aviso-tv-settings.dto'; // Importiere das neue Interface
|
import { AvisoTvTextSettingsDto } from './aviso-tv-settings.dto'; // Importiere das neue Interface
|
||||||
|
|
||||||
// Definiere die Response Interfaces
|
// Definiere die Response Interfaces
|
||||||
export interface AvisoArrivalsResponse {
|
export interface AvisoArrivalsResponse {
|
||||||
@@ -45,10 +45,18 @@ export class AvisoService {
|
|||||||
/**
|
/**
|
||||||
* Holt die Aviso TV Einstellungen basierend auf dem übergebenen Standort.
|
* Holt die Aviso TV Einstellungen basierend auf dem übergebenen Standort.
|
||||||
* @param standort Standort zur Filterung der Einstellungen.
|
* @param standort Standort zur Filterung der Einstellungen.
|
||||||
* @returns Ein Observable von AvisoTvSettingsDto[].
|
* @returns Ein Observable von AvisoTvTextSettingsDto[].
|
||||||
*/
|
*/
|
||||||
getAvisoTvSettings(standort: string): Observable<AvisoTvSettingsDto[]> {
|
getAvisoTvTextSettings(standort: string): Observable<AvisoTvTextSettingsDto[]> {
|
||||||
return this.http.get<AvisoTvSettingsDto[]>(`${this.baseUrl}/${standort}`)
|
return this.http.get<AvisoTvTextSettingsDto[]>(`${this.baseUrl}/${standort}`)
|
||||||
|
.pipe(
|
||||||
|
tap(data => console.log('AvisoService received TV Text settings data:', data)), // Logge die empfangenen Daten
|
||||||
|
catchError(this.handleError)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAvisoTvSettings(standortID: number): Observable<TvSettings[]> {
|
||||||
|
return this.http.get<TvSettings[]>(`${this.baseUrl}/AvisoTvSettings/Standort/${standortID}`)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(data => console.log('AvisoService received TV settings data:', data)), // Logge die empfangenen Daten
|
tap(data => console.log('AvisoService received TV settings data:', data)), // Logge die empfangenen Daten
|
||||||
catchError(this.handleError)
|
catchError(this.handleError)
|
||||||
|
|||||||
BIN
src/assets/Logos/verag.png
Normal file
BIN
src/assets/Logos/verag.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Reference in New Issue
Block a user