This commit is contained in:
2024-12-13 11:43:32 +01:00
parent b8d00a24d0
commit 34f86fccd1
14 changed files with 539 additions and 295 deletions

View File

@@ -45,7 +45,7 @@
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "2kb", "maximumWarning": "2kb",
"maximumError": "4kb" "maximumError": "5kb"
} }
], ],
"fileReplacements": [ "fileReplacements": [

View File

@@ -60,17 +60,24 @@
class="inline-icon"></ion-icon> class="inline-icon"></ion-icon>
{{ aviso.dauer }} {{ aviso.dauer }}
</div> </div>
<div class="ion-text-center" <div class="ion-text-center"
appAutoFontSize appAutoFontSize
[maxFontSizePercentage]="33" [maxFontSizePercentage]="33"
[maxFontSize]="avisoTvSettings[0].kachelFontSizeDateTime"> [maxFontSize]="avisoTvSettings[0].kachelFontSizeDateTime"
<ion-icon name="person-outline"></ion-icon> [ngClass]="{'wechseltextdiv': displayMitarbeiterTexts[aviso.lkW_Nr] === 'BITTE KOMMEN / LÜTFEN GELIN'}">
{{ aviso.letzterMitarbeiter }}
<ion-icon name="person-outline"
[ngClass]="{'wechseltext': displayMitarbeiterTexts[aviso.lkW_Nr] === 'BITTE KOMMEN / LÜTFEN GELIN'}">
</ion-icon>
{{ displayMitarbeiterTexts[aviso.lkW_Nr] || aviso.letzterMitarbeiter }}
</div> </div>
</div> </div>
<div *ngIf="aviso.avisoTVHinweis" <div *ngIf="aviso.avisoTVHinweis"
[ngClass]="getImageClassButtomLeft(aviso.avisoTVHinweis)" [ngClass]="getImageClassButtomLeft(aviso.avisoTVHinweis)"
class="blinking-image bottom-left-image-problem"> class="blinking-image bottom-left-image-problem">
@@ -79,27 +86,42 @@
<div *ngIf="aviso.lkW_fertig && aviso.avisoTVHinweis == '' " class="bottom-left-image-round"> <div *ngIf="aviso.lkW_fertig && aviso.avisoTVHinweis == '' " class="bottom-left-image-round">
<img [src]="'assets/warnings/okRound.png'" alt="Aviso Hinweis" /> <img [src]="'assets/warnings/okRound.png'" alt="Aviso Hinweis" />
</div> </div>
<div *ngIf="standort === 'WAI'">
<div class="bottom-right-icon-im" *ngIf="aviso.imEx === 'IMPORT'">
<img src="assets/icon/import_icon.png" style="width: 0.7em; aspect-ratio: 10 / 12" /> </div>
<div class="bottom-right-icon-ex" *ngIf="aviso.imEx === 'EXPORT'">
<img src="assets/icon/import_icon.png" style="width: 0.7em; aspect-ratio: 10 / 12" /> </div>
</div>
</ng-container> </ng-container>
<ng-template #showAvisoHinweis>
<ng-template #showAvisoHinweis> <div class="flex-container-hinweis">
<div class="lkwnr" style="margin-top: 1%; margin-bottom: 1%"
<div class="flex-container-hinweis" > appAutoFontSize
<div class="lkwnr" style="margin-top: 1%; margin-bottom: 1%" [maxFontSizePercentage]="30">
appAutoFontSize {{ aviso.avisoTVHinweis }}
[maxFontSizePercentage]="30">
{{ aviso.avisoTVHinweis }}
</div>
<div class="ion-text-center">
<img [src]="getTvHinweisImgSrc(aviso.avisoTVHinweis)"
[ngClass]="getImageClass(aviso.avisoTVHinweis)"
alt="Aviso Hinweis" />
</div>
</div> </div>
</ng-template> <div class="ion-text-center">
<img [src]="getTvHinweisImgSrc(aviso.avisoTVHinweis)"
[ngClass]="getImageClass(aviso.avisoTVHinweis)"
alt="Aviso Hinweis" />
</div>
</div>
<div *ngIf="standort === 'WAI'">
<div class="bottom-right-icon" *ngIf="aviso.imEx === 'IMPORT'">
<ion-icon name="download-outline"></ion-icon>
</div>
<div class="bottom-right-icon" *ngIf="aviso.imEx === 'EXPORT'">
<ion-icon name="upload-outline"></ion-icon>
</div>
</div>
</ng-template>
</ion-card> </ion-card>
</div> </div>
<!-- ====================================================== <!-- ======================================================
@@ -122,25 +144,41 @@
<!-- ====================================================== <!-- ======================================================
Logobar mit Progress Bar Logobar mit Progress Bar
====================================================== --> ====================================================== -->
<ion-progress-bar [value]="progressBarValue"
class="custom-progress-bar"
buffer="1"></ion-progress-bar>
<ion-toolbar class="logobar"> <ion-toolbar class="logobar">
<span slot="start" class="title">
<!-- Start Slot -->
<span slot="start" class="title" style="margin-left:0.3%">
{{ currentDate | date: 'HH:mm:ss' }} <br /> {{ currentDate | date: 'HH:mm:ss' }} <br />
{{ currentDate | date: 'dd.MM.yyyy' }} {{ currentDate | date: 'dd.MM.yyyy' }}
</span> </span>
<ion-title class="ion-text-center title"> <!-- Logo und Icons Container -->
<div class="logo-and-icons">
<img [src]="'assets/Logos/' + avisoTvSettings[0].logo" class="logo" /> <img [src]="'assets/Logos/' + avisoTvSettings[0].logo" class="logo" />
</ion-title>
<span slot="end" class="title"> <!-- Bedingtes Div für WAI Standort -->
<div *ngIf="standort === 'WAI'" class="title legendecontainer">
<div class="div-import">
<img src="assets/icon/import_icon.png" style="width: 0.8em; aspect-ratio: 10 / 12" /> = IMPORT
</div>
<div class="div-export">
<img src="assets/icon/export_icon_1.png" style="width: 0.8em; aspect-ratio: 10 / 12" /> = EXPORT
</div>
</div>
</div>
<!-- End Slot -->
<span slot="end" class="title" style="margin-right:0.3%">
({{ totalArrivals }}) <br /> {{ currentPageIndex + 1 }} / {{ pages.length }} ({{ totalArrivals }}) <br /> {{ currentPageIndex + 1 }} / {{ pages.length }}
</span> </span>
<ion-progress-bar [value]="progressBarValue"
class="custom-progress-bar"
buffer="1"></ion-progress-bar>
</ion-toolbar> </ion-toolbar>
<!-- ====================================================== <!-- ======================================================
Footer mit Tabs Footer mit Tabs
====================================================== --> ====================================================== -->
@@ -148,17 +186,15 @@
<ng-container *ngFor="let setting of avisoTvTextSettings; let i = index"> <ng-container *ngFor="let setting of avisoTvTextSettings; let i = index">
<ng-container *ngIf="setting.isActive && settingDisplayData[i]?.nonEmptyFixeZeilen?.length"> <ng-container *ngIf="setting.isActive && settingDisplayData[i]?.nonEmptyFixeZeilen?.length">
<ion-item lines="none" class="no-border-item"> <ion-item lines="none" class="no-border-item">
<div [innerHTML]="settingDisplayData[i].nonEmptyFixeZeilen[settingDisplayData[i].currentDivIndex]?.sanitizedHtml" <div [innerHTML]="settingDisplayData[i].nonEmptyFixeZeilen[settingDisplayData[i].currentDivIndex].sanitizedHtml"
appAutoFontSize autoResizeText
[minFontSize]="12" [style.text-align]="settingDisplayData[i].nonEmptyFixeZeilen[settingDisplayData[i].currentDivIndex].textAlign"
[maxFontSize]="24"
[style.text-align]="settingDisplayData[i].nonEmptyFixeZeilen[settingDisplayData[i].currentDivIndex]?.textAlign"
class="htmltext responsive-title"> class="htmltext responsive-title">
</div> </div>
</ion-item> </ion-item>
<div class="tabs-container" <div class="tabs-container"
style="display: flex; justify-content: center; background-color:white;"> style="display: flex; justify-content: center; background-color:transparent;">
<div class="custom-segment"> <div class="custom-segment">
<button *ngFor="let item of settingDisplayData[i].nonEmptyFixeZeilen; let j = index" <button *ngFor="let item of settingDisplayData[i].nonEmptyFixeZeilen; let j = index"
(click)="settingDisplayData[i].currentDivIndex = j" (click)="settingDisplayData[i].currentDivIndex = j"

View File

@@ -44,14 +44,13 @@ div {
.card-number { .card-number {
position: absolute; position: absolute;
top: 5px; top: 2%;
left: 5px; left: 0.1%;
font-size: calc(var(--tile-height-vh) * 0.18); font-size: calc(var(--tile-height-vh) * 0.14);
font-weight: bold; font-weight: bold;
background-color: transparent; background-color: transparent;
padding: 2px 5px; padding: 0.1% 2%;
border-radius: 3px; color: #003680;
color: #003680;
} }
/* ====================================================== /* ======================================================
@@ -83,22 +82,26 @@ ion-title {
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;
display:flex;
align-items:center;
justify-content:center;
} }
/* ====================================================== /* ======================================================
Icons Icons
====================================================== */ ====================================================== */
ion-icon { .grid-container ion-icon {
vertical-align: middle; vertical-align: middle;
font-size: calc(var(--tile-height-vh) * 0.15); font-size: calc(var(--tile-height-vh) * 0.15);
margin-right: -3px; margin-right: -3px;
margin-left: 0.1em; margin-left: 0.1em;
margin-bottom:0.1em; margin-bottom: 0.1em;
} }
/* ====================================================== /* ======================================================
Statusklassen Statusklassen
====================================================== */ ====================================================== */
@@ -122,8 +125,8 @@ ion-icon {
@keyframes fadeIn { @keyframes fadeIn {
from { from {
opacity: 0; opacity: 1;
transform: scale(0.95); transform: scale(0.3);
} }
to { to {
@@ -157,6 +160,9 @@ ion-icon {
.logobar { .logobar {
max-height: 12vh; max-height: 12vh;
display: flex;
align-items: center;
justify-content: space-between;
} }
@@ -178,8 +184,8 @@ ion-icon {
.bottom-left-image-round img { .bottom-left-image-round img {
position: absolute; position: absolute;
width: 11%; width: 8%;
aspect-ratio: 10 / 9; aspect-ratio: 9.5 / 9;
bottom: 2%; bottom: 2%;
left: 1%; left: 1%;
} }
@@ -256,6 +262,7 @@ ion-icon {
.custom-progress-bar { .custom-progress-bar {
--progress-background: #003680; --progress-background: #003680;
width: 100%;
} }
/* ====================================================== /* ======================================================
@@ -267,7 +274,6 @@ ion-icon {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
row-gap: var(--tile-row-gap); row-gap: var(--tile-row-gap);
} }
@@ -283,3 +289,164 @@ ion-icon {
} }
.tabs-container {
position: absolute;
bottom: var(--text-flagge-bottom);
left: var(--text-flagge-left);
z-index: 10;
}
.bottom-right-icon-im {
position: absolute;
bottom: 0.1%;
right: 2%;
font-size: calc(var(--tile-height-vh) * 0.15);
color: #003680;
}
.bottom-right-icon-ex {
position: absolute;
bottom: 0.1%;
right: 2.5%;
font-size: calc(var(--tile-height-vh) * 0.15);
color: #ee7621;
}
.logo-and-icons {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
}
.legendecontainer {
display: flex;
position: absolute;
margin-left: 55%;
flex-direction: column;
}
.div-import {
color: #003680;
}
.div-export {
margin-bottom:0%;
color: #ee7621;
}
.wechseltext {
visibility: hidden;
}
.wechseltextdiv {
margin-left:-9%;
}
@media only screen and (max-width: 768px) {
/* Grid-Container anpassen */
.grid-container {
grid-template-columns: 1fr; /* Eine Spalte */
row-gap: 1px; /* 20px * 0.8 */
column-gap: 1px; /* 20px * 0.8 */
padding: 8px; /* 10px * 0.8 */
}
.arrival-card {
height: 120px; /* Flexible Höhe bleibt unverändert */
padding: 8px; /* 10px * 0.8 */
margin-bottom: 8px; /* 10px * 0.8 */
}
.card-number {
font-size: 16px; /* 16px * 0.8 */
padding: 1.6% 2.4%; /* 2% * 0.8 und 3% * 0.8 */
}
/* Typografie anpassen */
ion-title {
font-size: 10px; /* 24px * 0.8 */
}
.title {
font-size: 20px; /* 16px * 0.8 */
}
.lkwnr {
font-size: 11px; /* 14px * 0.8 */
}
.htmltext {
height: auto;
padding: 8px; /* 10px * 0.8 */
}
.grid-container ion-icon {
font-size: 16px; /* 20px * 0.8 */
margin-right: 0;
margin-left: 0.16em; /* 0.2em * 0.8 */
margin-bottom: 0.16em; /* 0.2em * 0.8 */
}
.logo {
max-height: 8vh; /* 8vh * 0.8 */
}
.logobar {
max-height: 8vh; /* 10vh * 0.8 */
}
.bottom-left-image-problem img,
.bottom-left-image-passport img,
.bottom-left-image-round img {
width: 4%; /* 5% * 0.8 */
left: 4%; /* 5% * 0.8 */
}
.problem,
.passport {
width: 100%;
}
/* Benutzerdefinierte Segmente anpassen */
.custom-segment {
height: 40px; /* 50px * 0.8 */
}
.custom-segment-button {
min-width: 32px; /* 40px * 0.8 */
height: 24px; /* 30px * 0.8 */
padding: 3px; /* 4px * 0.8 */
font-size: 8px; /* 10px * 0.8 */
}
.tab-image {
width: 16px; /* 20px * 0.8 */
height: 14px; /* 18px * 0.8 */
}
/* Flex Container anpassen */
.flex-container {
row-gap: 1px; /* 20px * 0.8 */
}
.tabs-container {
bottom: 4%; /* 5% * 0.8 */
left: 4%; /* 5% * 0.8 */
}
.bottom-right-icon-im,
.bottom-right-icon-ex {
font-size: 14px; /* 18px * 0.8 */
}
.legendecontainer {
margin-left: 8%; /* 10% * 0.8 */
}
}

View File

@@ -5,26 +5,23 @@ import {
HostListener, HostListener,
ChangeDetectorRef, ChangeDetectorRef,
HostBinding, HostBinding,
ViewChildren,
QueryList,
ElementRef,
AfterViewInit, AfterViewInit,
Renderer2 Renderer2
} from '@angular/core'; } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { interval, Subject, throwError, lastValueFrom, Subscription } from 'rxjs'; import { interval, Subject, throwError, lastValueFrom, Subscription, of } from 'rxjs';
import { switchMap, takeUntil, distinctUntilChanged, tap, catchError, map, take, debounceTime } from 'rxjs/operators'; import { switchMap, takeUntil, distinctUntilChanged, tap, catchError, map, take } from 'rxjs/operators';
import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.service'; import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.service';
import { AvisoDto, TvSettings } from '../../services/aviso.dto'; import { AvisoDto, TvSettings } from '../../services/aviso.dto';
import { AvisoTvTextSettingsDto } from '../../services/aviso-tv-settings.dto'; import { AvisoTvTextSettingsDto } from '../../services/aviso-tv-settings.dto';
// Schnittstelle für die aufgelösten Daten vom Resolver
interface AvisoResolvedData { interface AvisoResolvedData {
avisoTvTextSettings: AvisoTvTextSettingsDto[]; avisoTvTextSettings: AvisoTvTextSettingsDto[];
avisoTvSettings: TvSettings[]; avisoTvSettings: TvSettings[];
arrivals: AvisoArrivalsResponse; arrivals: AvisoArrivalsResponse;
standortID: number;
} }
interface CssVariables { interface CssVariables {
@@ -35,13 +32,16 @@ interface CssVariables {
tileSeitenwechselInSek: string; tileSeitenwechselInSek: string;
textBalkenHeightVh: string; textBalkenHeightVh: string;
tileRowGapinPercent: string; tileRowGapinPercent: string;
flaggeLeft: string;
flaggeBottom: string;
} }
const ARRIVALS_INTERVAL_MS = 10000;
const TVTEXTSETTINGS_INTERVAL_MS = 60000; const TVTEXTSETTINGS_INTERVAL_MS = 60000;
const TVSETTINGS_INTERVAL_MS = 10000; const TVSETTINGS_INTERVAL_MS = 10000;
const TOGGLE_DIV_INTERVAL_MS = 5000; const TOGGLE_DIV_INTERVAL_MS = 5000;
const WECHSELTEXT = "BITTE KOMMEN / LÜTFEN GELIN"
interface StatusInfo { interface StatusInfo {
class: string; class: string;
icon: string; icon: string;
@@ -56,14 +56,13 @@ const STATUS_MAP: { [key: string]: StatusInfo } = {
'default': { class: 'status-default', icon: 'help-circle', color: 'medium', text: 'Unbekannt' } 'default': { class: 'status-default', icon: 'help-circle', color: 'medium', text: 'Unbekannt' }
}; };
// Neues Interface für die Anzeige der Fixzeilen
interface SettingDisplayData { interface SettingDisplayData {
nonEmptyFixeZeilen: { nonEmptyFixeZeilen: {
sanitizedHtml: SafeHtml; sanitizedHtml: SafeHtml;
textAlign: string; textAlign: string;
}[]; }[];
currentDivIndex: number; currentDivIndex: number;
isDivReady: boolean; // Flag zur Steuerung der Sichtbarkeit isDivReady: boolean;
} }
@Component({ @Component({
@@ -73,13 +72,14 @@ interface SettingDisplayData {
}) })
export class AvisoPage implements OnInit, OnDestroy, AfterViewInit { export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
// HostBindings für CSS-Variablen
@HostBinding('style.--tile-width-percent') tileWidthPercent = '50vw'; @HostBinding('style.--tile-width-percent') tileWidthPercent = '50vw';
@HostBinding('style.--tile-height-vh') tileHeightVh = '40vh'; @HostBinding('style.--tile-height-vh') tileHeightVh = '40vh';
@HostBinding('style.--tile-title-font-size') tileTitleFontSize = '5vh'; @HostBinding('style.--tile-title-font-size') tileTitleFontSize = '5vh';
@HostBinding('style.--tile-font-size-date-time') tileFontSizeDateTime = '5vh'; @HostBinding('style.--tile-font-size-date-time') tileFontSizeDateTime = '5vh';
@HostBinding('style.--text-balken-height-vh') textBalkenHeightVh = '10vh'; @HostBinding('style.--text-balken-height-vh') textBalkenHeightVh = '10vh';
@HostBinding('style.--tile-row-gap') tileRowGapinPercent = '10px'; @HostBinding('style.--tile-row-gap') tileRowGapinPercent = '10px';
@HostBinding('style.--text-flagge-left') flaggeLeft = '10px';
@HostBinding('style.--text-flagge-bottom') flaggeBottom = '10px';
progressBarValue: number = 0; progressBarValue: number = 0;
private progressBarSubscription: Subscription = new Subscription(); private progressBarSubscription: Subscription = new Subscription();
@@ -87,50 +87,47 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
currentDate: Date = new Date(); currentDate: Date = new Date();
private dateSubscription: Subscription = new Subscription(); private dateSubscription: Subscription = new Subscription();
// Standort- und Filterinformationen
standort = ''; standort = '';
standortID = 0; standortID = 0;
seiten = false; seiten = true;
onlyOK = false; onlyOK = false;
// Datenmodelle
arrivals: AvisoDto[] = []; arrivals: AvisoDto[] = [];
avisoTvTextSettings: AvisoTvTextSettingsDto[] = []; avisoTvTextSettings: AvisoTvTextSettingsDto[] = [];
avisoTvSettings: TvSettings[] = []; avisoTvSettings: TvSettings[] = [];
// Paginierung
pages: AvisoDto[][] = []; pages: AvisoDto[][] = [];
currentPageIndex = 0; currentPageIndex = 0;
tilesPerPage = 0; tilesPerPage = 0;
// Ladezustände
loadingArrivals = false; loadingArrivals = false;
loadingTextSettings = false; loadingTextSettings = false;
loadingTvSettings = false; loadingTvSettings = false;
// Gesamtanzahlen
totalArrivals = 0; totalArrivals = 0;
totalTextSettings = 0; totalTextSettings = 0;
// Fehlermeldungen
errorMessage = ''; errorMessage = '';
settingsErrorMessage = ''; settingsErrorMessage = '';
// Sonstige Variablen
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
private toggleDivInterval: any; private toggleDivInterval: any;
private currentCssVariables: CssVariables | null = null; private currentCssVariables: CssVariables | null = null;
// Neues Array für die Anzeige der Fixzeilen
settingDisplayData: SettingDisplayData[] = []; settingDisplayData: SettingDisplayData[] = [];
// Hinzugefügte Variablen für die Kachel-Umschaltung
avisoTimeouts: { [key: string]: any } = {}; avisoTimeouts: { [key: string]: any } = {};
avisoStates: { [key: string]: boolean } = {}; avisoStates: { [key: string]: boolean } = {};
// Dauer in Millisekunden displayMitarbeiterTexts: { [key: string]: string } = {};
contentDuration = 3000; // Zeit in ms, die der normale Inhalt angezeigt wird avisoOriginalLetzterMitarbeiter: { [key: string]: string } = {};
avisoHinweisDuration = 1500; // Zeit in ms, die der avisoTVHinweis Text angezeigt wird avisoMitarbeiterIntervals: { [key: string]: any } = {};
private MITARBEITER_INTERVAL_MS = 3000;
contentDuration = 3000;
avisoHinweisDuration = 1500;
pendingArrivals: AvisoDto[] | null = null;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -140,11 +137,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
private renderer: Renderer2 private renderer: Renderer2
) { } ) { }
/**
* Konvertiert eine Schriftgröße in verschiedene Einheiten zu Pixel.
* @param fontSize Die Schriftgröße als String (z.B. '12pt', '16px')
* @returns Die Schriftgröße in Pixel
*/
private convertToPx(fontSize: string): number { private convertToPx(fontSize: string): number {
if (fontSize.endsWith('pt')) { if (fontSize.endsWith('pt')) {
return parseFloat(fontSize) * 1.333; return parseFloat(fontSize) * 1.333;
@@ -157,8 +149,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
ngOnInit() { ngOnInit() {
this.currentDate = new Date(); this.currentDate = new Date();
// Aktualisieren Sie das Datum jede Sekunde
this.dateSubscription = interval(1000).subscribe(() => { this.dateSubscription = interval(1000).subscribe(() => {
this.currentDate = new Date(); this.currentDate = new Date();
}); });
@@ -173,95 +163,89 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.onlyOK = queryParams.get('onlyOK') === 'true'; this.onlyOK = queryParams.get('onlyOK') === 'true';
}); });
// Zugriff auf die vom Resolver bereitgestellten Daten
this.route.data.pipe(takeUntil(this.destroy$)).subscribe((resolvedData) => { this.route.data.pipe(takeUntil(this.destroy$)).subscribe((resolvedData) => {
const data = (resolvedData as any)['avisoData'] as AvisoResolvedData; const data = (resolvedData as any)['avisoData'] as AvisoResolvedData;
this.avisoTvTextSettings = data.avisoTvTextSettings; this.avisoTvTextSettings = data.avisoTvTextSettings;
this.avisoTvSettings = data.avisoTvSettings; this.avisoTvSettings = data.avisoTvSettings;
this.arrivals = data.arrivals.avisos; this.arrivals = data.arrivals.avisos;
console.log(this.arrivals);
this.totalArrivals = data.arrivals.totalCount; this.totalArrivals = data.arrivals.totalCount;
this.standortID = data.standortID;
// Avisos für Testzwecke modifizieren
this.arrivals.forEach(aviso => { this.arrivals.forEach(aviso => {
if (aviso.lkW_Nr === '34HG827') { if (aviso.lkW_fertig && aviso.avisoTVHinweis === "") {
aviso.lkW_Nr = '10AKN96310AKN96310AKN96310AKN963'; this.displayMitarbeiterTexts[aviso.lkW_Nr] = WECHSELTEXT;
} }
}); });
this.arrivals.forEach(aviso => {
if (aviso.lkW_Nr === 'OOLU9267058') { /* this.arrivals.forEach(aviso => {
if (aviso.lkW_Nr === '81ACY359') {
aviso.avisoTVHinweis = 'URGENT'; aviso.avisoTVHinweis = 'URGENT';
} }
}); });
*/
this.paginateArrivals(); this.paginateArrivals();
this.updateAvisoStatesAndCycles();
this.cdr.detectChanges(); this.cdr.detectChanges();
// Process the HTML settings
this.preprocessHtmlSettings(); this.preprocessHtmlSettings();
// Setzen der CSS-Variablen
this.setCSSVariables(); this.setCSSVariables();
// Starten der Div-Umschaltung
this.startDivToggle(); this.startDivToggle();
// Starten der Seitenrotation
this.paginateArrivals(); this.paginateArrivals();
this.startPageRotation(); this.startPageRotation();
// Starten der Aviso-Kachel-Umschaltung
this.updateAvisoStatesAndCycles(); this.updateAvisoStatesAndCycles();
// Nach dem Laden der Daten die Schriftgröße anpassen (falls nicht mehr benötigt)
// Da die Direktive jetzt die Schriftgröße anpasst, kann dieser Code eventuell entfernt werden
}); });
const ARRIVALS_INTERVAL_MS = (this.avisoTvSettings[0].seitenwechselInSek * 1000 / 2);
// Automatisches Aktualisieren der Arrivals alle 10 Sekunden
interval(ARRIVALS_INTERVAL_MS) interval(ARRIVALS_INTERVAL_MS)
.pipe( .pipe(
switchMap(() => { switchMap(() => {
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.onlyOK).pipe(
catchError((error) => {
this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.';
this.loadingArrivals = false;
return of({ avisos: [], totalCount: 0 });
})
);
}), }),
distinctUntilChanged((prev, curr) => this.arrivalsAreEqual(prev.avisos, curr.avisos)), distinctUntilChanged((prev, curr) => this.arrivalsAreEqual(prev.avisos, curr.avisos)),
takeUntil(this.destroy$) takeUntil(this.destroy$)
) )
.subscribe( .subscribe((data: AvisoArrivalsResponse) => {
(data: AvisoArrivalsResponse) => { this.loadingArrivals = false;
/* this.arrivals.forEach(aviso => {
if (aviso.lkW_Nr === '81ACY359') {
aviso.avisoTVHinweis = 'URGENT';
}
});*/
if (this.pages.length > 1) {
this.pendingArrivals = data.avisos;
this.totalArrivals = data.totalCount;
} else {
this.arrivals = data.avisos; this.arrivals = data.avisos;
this.totalArrivals = data.totalCount; this.totalArrivals = data.totalCount;
this.loadingArrivals = false;
this.arrivals.forEach(aviso => {
this.arrivals.forEach(aviso => {
if (aviso.lkW_Nr === '34HG827') {
aviso.lkW_Nr = '10AKN96310AKN96310AKN96310AKN963';
}
});
this.arrivals.forEach(aviso => {
if (aviso.lkW_Nr === 'OOLU9267058') {
aviso.avisoTVHinweis = 'URGENT';
}
});
});
this.paginateArrivals(); this.paginateArrivals();
this.updateAvisoStatesAndCycles();
this.cdr.detectChanges(); this.cdr.detectChanges();
this.arrivals.forEach(aviso => {
}, if (aviso.lkW_fertig && aviso.avisoTVHinweis === "") {
(error) => { if (!this.displayMitarbeiterTexts[aviso.lkW_Nr]) {
this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.'; this.displayMitarbeiterTexts[aviso.lkW_Nr] = WECHSELTEXT;
this.loadingArrivals = false; }
} else {
if (this.displayMitarbeiterTexts[aviso.lkW_Nr]) {
delete this.displayMitarbeiterTexts[aviso.lkW_Nr];
}
}
});
} }
); });
// Automatisches Aktualisieren der TV Settings alle 10 Sekunden
interval(TVSETTINGS_INTERVAL_MS) interval(TVSETTINGS_INTERVAL_MS)
.pipe( .pipe(
switchMap(() => this.loadAvisoTvSettings()), switchMap(() => this.loadAvisoTvSettings()),
@@ -269,7 +253,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
) )
.subscribe(); .subscribe();
// Automatisches Aktualisieren der TV Text Settings alle 60 Sekunden
interval(TVTEXTSETTINGS_INTERVAL_MS) interval(TVTEXTSETTINGS_INTERVAL_MS)
.pipe( .pipe(
switchMap(() => this.loadAvisoTvTextSettings()), switchMap(() => this.loadAvisoTvTextSettings()),
@@ -279,14 +262,18 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
ngAfterViewInit() { ngAfterViewInit() {
// Die Schriftgrößenanpassung wird jetzt von der Direktive übernommen
// Falls zusätzliche Initialisierungen erforderlich sind, können sie hier durchgeführt werden
} }
ngOnDestroy() { ngOnDestroy() {
this.destroy$.next(); this.destroy$.next();
this.destroy$.complete(); this.destroy$.complete();
Object.values(this.avisoMitarbeiterIntervals).forEach(intervalId => clearInterval(intervalId));
this.avisoMitarbeiterIntervals = {};
Object.values(this.avisoTimeouts).forEach(timeoutId => clearTimeout(timeoutId));
this.avisoTimeouts = {};
if (this.toggleDivInterval) { if (this.toggleDivInterval) {
clearInterval(this.toggleDivInterval); clearInterval(this.toggleDivInterval);
} }
@@ -298,21 +285,15 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
if (this.dateSubscription) { if (this.dateSubscription) {
this.dateSubscription.unsubscribe(); this.dateSubscription.unsubscribe();
} }
// Bereinigen der Aviso-Timer
Object.values(this.avisoTimeouts).forEach(timeoutId => clearTimeout(timeoutId));
} }
private startProgressBar(seitenwechselInSek: number): void { private startProgressBar(seitenwechselInSek: number): void {
// Falls eine vorherige Subscription existiert, beenden wir sie
if (this.progressBarSubscription) { if (this.progressBarSubscription) {
this.progressBarSubscription.unsubscribe(); this.progressBarSubscription.unsubscribe();
} }
// Setzen des Fortschrittswerts auf 0
this.progressBarValue = 0; this.progressBarValue = 0;
const progressBarIntervalMs = 100;
const progressBarIntervalMs = 100; // Aktualisierung alle 100ms
const totalSteps = Math.floor((seitenwechselInSek * 1000) / progressBarIntervalMs); const totalSteps = Math.floor((seitenwechselInSek * 1000) / progressBarIntervalMs);
this.progressBarSubscription = interval(progressBarIntervalMs) this.progressBarSubscription = interval(progressBarIntervalMs)
@@ -339,26 +320,23 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.settingDisplayData = this.avisoTvTextSettings.map((setting, index) => ({ this.settingDisplayData = this.avisoTvTextSettings.map((setting, index) => ({
nonEmptyFixeZeilen: this.getNonEmptyFixeZeilen(setting), nonEmptyFixeZeilen: this.getNonEmptyFixeZeilen(setting),
currentDivIndex: 0, currentDivIndex: 0,
isDivReady: true // Initialisieren auf true isDivReady: true
})); }));
} }
private getNonEmptyFixeZeilen(setting: AvisoTvTextSettingsDto) { private getNonEmptyFixeZeilen(setting: AvisoTvTextSettingsDto) {
const nonEmptyFixeZeilen = []; const nonEmptyFixeZeilen = [];
// Verarbeiten von fixeZeile1
if (setting.fixeZeile1) { if (setting.fixeZeile1) {
const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile1, setting); const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile1, setting);
nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign });
} }
// Verarbeiten von fixeZeile2
if (setting.fixeZeile2) { if (setting.fixeZeile2) {
const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile2, setting); const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile2, setting);
nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign });
} }
// Verarbeiten von fixeZeile3
if (setting.fixeZeile3) { if (setting.fixeZeile3) {
const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile3, setting); const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile3, setting);
nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign });
@@ -368,8 +346,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
private processHtml(html: string, setting: AvisoTvTextSettingsDto): { sanitizedHtml: SafeHtml; textAlign: string } { private processHtml(html: string, setting: AvisoTvTextSettingsDto): { sanitizedHtml: SafeHtml; textAlign: string } {
// Vermeide das Modifizieren des HTML-Inhalts, um die Formatierung zu erhalten
// Extrahiere text-align aus dem ersten Div
const parser = new DOMParser(); const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html'); const doc = parser.parseFromString(html, 'text/html');
const firstDiv = doc.querySelector('div'); const firstDiv = doc.querySelector('div');
@@ -384,7 +360,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
div.dataset['originalFontSizePx'] = fontSizePx.toString(); div.dataset['originalFontSizePx'] = fontSizePx.toString();
div.dataset['originalTextAlign'] = textAlign; div.dataset['originalTextAlign'] = textAlign;
} }
// Entferne die inline Schriftgröße und füge eine Klasse hinzu
div.style.fontSize = ''; div.style.fontSize = '';
div.classList.add('dynamic-font-size'); div.classList.add('dynamic-font-size');
}); });
@@ -406,6 +381,8 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
tileSeitenwechselInSek: `${settings.seitenwechselInSek}s`, tileSeitenwechselInSek: `${settings.seitenwechselInSek}s`,
textBalkenHeightVh: `${settings.textBalkenHeightInPercent}vh`, textBalkenHeightVh: `${settings.textBalkenHeightInPercent}vh`,
tileRowGapinPercent: `${settings.kachelRowGapInPercent}px`, tileRowGapinPercent: `${settings.kachelRowGapInPercent}px`,
flaggeLeft: `${settings.flaggeLeft}vw`,
flaggeBottom: `${settings.flaggeBottom}vh`,
}; };
if (this.currentCssVariables && this.hasCssVariablesChanged(newCssVariables)) { if (this.currentCssVariables && this.hasCssVariablesChanged(newCssVariables)) {
@@ -415,10 +392,8 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
Object.assign(this, newCssVariables); Object.assign(this, newCssVariables);
this.currentCssVariables = newCssVariables; this.currentCssVariables = newCssVariables;
console.log('CSS-Variablen gesetzt:', newCssVariables);
} else { } else {
console.warn('avisoTvSettings ist nicht verfügbar oder leer'); console.warn('Fehler CSS Variablen');
} }
} }
@@ -430,7 +405,7 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.loadingTvSettings = true; this.loadingTvSettings = true;
try { try {
const data: TvSettings[] = await lastValueFrom( const data: TvSettings[] = await lastValueFrom(
this.avisoService.getAvisoTvSettings(this.avisoTvTextSettings[0].standortID || this.standortID).pipe( this.avisoService.getAvisoTvSettings(this.standortID).pipe(
tap((data: TvSettings[]) => { tap((data: TvSettings[]) => {
this.avisoTvSettings = data; this.avisoTvSettings = data;
this.loadingTvSettings = false; this.loadingTvSettings = false;
@@ -440,6 +415,7 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
) )
); );
} catch { } catch {
// Fehler bereits behandelt
} }
} }
@@ -452,14 +428,13 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.avisoTvTextSettings = data; this.avisoTvTextSettings = data;
this.totalTextSettings = data.length; this.totalTextSettings = data.length;
this.loadingTextSettings = false; this.loadingTextSettings = false;
// Process the new HTML settings
this.preprocessHtmlSettings(); this.preprocessHtmlSettings();
}), }),
catchError((error: any) => this.handleSettingsError(error, 'TV Text Settings')) catchError((error: any) => this.handleSettingsError(error, 'TV Text Settings'))
) )
); );
} catch { } catch {
// Fehler wird bereits in handleSettingsError behandelt // Fehler bereits behandelt
} }
} }
@@ -478,17 +453,13 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.toggleDivInterval = setInterval(() => { this.toggleDivInterval = setInterval(() => {
this.settingDisplayData.forEach((data, index) => { this.settingDisplayData.forEach((data, index) => {
if (data.nonEmptyFixeZeilen.length > 1) { if (data.nonEmptyFixeZeilen.length > 1) {
// Setze das Flag auf false, um das aktuelle div zu verstecken
this.settingDisplayData[index].isDivReady = false; this.settingDisplayData[index].isDivReady = false;
// Aktualisiere den currentDivIndex
data.currentDivIndex = (data.currentDivIndex + 1) % data.nonEmptyFixeZeilen.length; data.currentDivIndex = (data.currentDivIndex + 1) % data.nonEmptyFixeZeilen.length;
} }
}); });
this.cdr.detectChanges(); this.cdr.detectChanges();
}, TOGGLE_DIV_INTERVAL_MS); }, TOGGLE_DIV_INTERVAL_MS);
} else { } else {
// Initialize currentDivIndex to 0 und setze isDivReady auf true
this.settingDisplayData.forEach((data, index) => { this.settingDisplayData.forEach((data, index) => {
data.currentDivIndex = 0; data.currentDivIndex = 0;
data.isDivReady = true; data.isDivReady = true;
@@ -496,7 +467,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
} }
// Status-Methoden mithilfe des STATUS_MAP
getStatusClass(status: number, lkwFertig: boolean, avisoTvhinweis: string): string { getStatusClass(status: number, lkwFertig: boolean, avisoTvhinweis: string): string {
if (lkwFertig && avisoTvhinweis == "") { if (lkwFertig && avisoTvhinweis == "") {
return STATUS_MAP['lkwfertig'].class; return STATUS_MAP['lkwfertig'].class;
@@ -530,22 +500,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
return STATUS_MAP[status.toString()]?.text || STATUS_MAP['default'].text; return STATUS_MAP[status.toString()]?.text || STATUS_MAP['default'].text;
} }
/**
* Gibt die CSS-Klasse basierend auf dem Position-Wert zurück.
* @param position Die Position (Top, Middle, Left, Right)
* @returns Eine CSS-Klassen-String
*/
getPositionClass(position: string): string {
const pos = position.toLowerCase();
const positionClasses: { [key: string]: string } = {
'top': 'position-top',
'middle': 'position-middle',
'left': 'position-left',
'right': 'position-right'
};
return positionClasses[pos] || '';
}
private reloadPageOnce(): void { private reloadPageOnce(): void {
if (!sessionStorage.getItem('pageReloaded')) { if (!sessionStorage.getItem('pageReloaded')) {
sessionStorage.setItem('pageReloaded', 'true'); sessionStorage.setItem('pageReloaded', 'true');
@@ -555,48 +509,56 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
} }
// Paginierung der Arrivals
private paginateArrivals(): void { private paginateArrivals(): void {
if (!this.avisoTvSettings || this.avisoTvSettings.length === 0) { if (!this.avisoTvSettings || this.avisoTvSettings.length === 0) {
return; return;
} }
const settings = this.avisoTvSettings[0]; const settings = this.avisoTvSettings[0];
const windowWidth = window.outerWidth; const windowWidth = window.innerWidth;
const windowHeight = window.outerHeight; const windowHeight = window.innerHeight;
const isMobileDevice = () => {
const mobileBreakpoint = 768;
return windowWidth <= mobileBreakpoint;
};
if (isMobileDevice()) {
this.pages = [this.arrivals];
this.tilesPerPage = this.arrivals.length;
this.currentPageIndex = 0;
return;
}
const allFixeZeilenEmpty = this.settingDisplayData.every(data => data.nonEmptyFixeZeilen.length === 0);
let effectiveTileHeightPercent = settings.kachelHeightInPercent;
let htmltextHeight = (settings.textBalkenHeightInPercent / 100) * windowHeight;
if (allFixeZeilenEmpty) {
htmltextHeight = 0;
}
const tileWidth = (settings.kachelWidthInPercent / 100) * windowWidth; const tileWidth = (settings.kachelWidthInPercent / 100) * windowWidth;
const tileHeight = (settings.kachelHeightInPercent / 100) * windowHeight; const tileHeight = (effectiveTileHeightPercent / 100) * windowHeight;
const logo = (10 / 100) * windowHeight;
// Definieren Sie separate horizontale und vertikale Gutter const logo = (10 / 100) * windowHeight;
const gutterHorizontal = (1 / 100) * windowHeight; const gutterHorizontal = (1 / 100) * windowHeight;
const gutterVertical = (1 / 100) * windowHeight; const gutterVertical = (1 / 100) * windowHeight;
const containerPadding = (0 / 100) * windowHeight; const containerPadding = (0 / 100) * windowHeight;
const containerPaddingTotal = containerPadding * 2; const containerPaddingTotal = containerPadding * 2;
// Berechnung der Spalten unter Verwendung von gutterHorizontal
const columns = Math.floor( const columns = Math.floor(
(windowWidth - containerPaddingTotal + gutterHorizontal) / (tileWidth + gutterHorizontal) (windowWidth - containerPaddingTotal + gutterHorizontal) / (tileWidth + gutterHorizontal)
) || 1; ) || 1;
// **Änderung beginnt hier**
const htmltext = (this.avisoTvTextSettings && this.avisoTvTextSettings.length > 0 && this.totalArrivals > 0)
? (settings.textBalkenHeightInPercent / 100) * windowHeight
: 0;
// **Änderung endet hier**
// Verfügbare Höhe für Kacheln unter Verwendung von gutterVertical
const availableHeightForTiles = const availableHeightForTiles =
windowHeight - windowHeight -
logo - logo -
htmltext - htmltextHeight -
containerPadding * 2 - containerPadding * 2 -
gutterVertical * (columns > 1 ? columns : 0); gutterVertical * (columns > 1 ? columns : 0);
// Berechnung der Reihen unter Verwendung von gutterVertical
const rows = Math.floor( const rows = Math.floor(
(availableHeightForTiles + gutterVertical) / (tileHeight + gutterVertical) (availableHeightForTiles + gutterVertical) / (tileHeight + gutterVertical)
) || 1; ) || 1;
@@ -614,44 +576,52 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
} }
// Automatisches Wechseln der Seiten alle seitenwechselInSek Sekunden // *** NEU *** Anpassung im startPageRotation(), um pendingArrivals einzuspielen
private startPageRotation(): void { private startPageRotation(): void {
if (!this.avisoTvSettings || this.avisoTvSettings.length === 0) { if (!this.avisoTvSettings || this.avisoTvSettings.length === 0) {
console.warn('avisoTvSettings ist nicht verfügbar oder leer'); console.warn('avisoTvSettings ist nicht verfügbar oder leer');
return; return;
} }
// Überprüfen, ob mehr als eine Seite vorhanden ist
if (this.pages.length <= 1) { if (this.pages.length <= 1) {
console.info('Nur eine Seite vorhanden. Automatischer Seitenwechsel wird nicht gestartet.'); console.info('Nur eine Seite vorhanden. Automatischer Seitenwechsel wird nicht gestartet.');
return; return;
} }
const seitenwechselInSek = this.avisoTvSettings[0].seitenwechselInSek; const seitenwechselInSek = this.avisoTvSettings[0].seitenwechselInSek;
console.log('Seitenwechselintervall (Sek):', seitenwechselInSek);
if (typeof seitenwechselInSek === 'number' && seitenwechselInSek > 0) { if (typeof seitenwechselInSek === 'number' && seitenwechselInSek > 0) {
const intervalMs = seitenwechselInSek * 1000; const intervalMs = seitenwechselInSek * 1000;
console.log('Seitenwechselintervall (ms):', intervalMs);
// Starten Sie den Fortschrittsbalken
this.startProgressBar(seitenwechselInSek); this.startProgressBar(seitenwechselInSek);
interval(intervalMs) interval(intervalMs)
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(() => { .subscribe(() => {
// *** NEU *** Hier prüfen wir, ob pendingArrivals vorliegen
if (this.pendingArrivals) {
this.arrivals = this.pendingArrivals;
this.pendingArrivals = null;
this.paginateArrivals();
// Aktualisierung der Mitarbeitertexte
this.arrivals.forEach(aviso => {
if (aviso.lkW_fertig && aviso.avisoTVHinweis === "") {
if (!this.displayMitarbeiterTexts[aviso.lkW_Nr]) {
this.displayMitarbeiterTexts[aviso.lkW_Nr] = WECHSELTEXT;
}
} else {
if (this.displayMitarbeiterTexts[aviso.lkW_Nr]) {
delete this.displayMitarbeiterTexts[aviso.lkW_Nr];
}
}
});
this.cdr.detectChanges();
}
if (this.pages.length > 1) { if (this.pages.length > 1) {
this.currentPageIndex = (this.currentPageIndex + 1) % this.pages.length; this.currentPageIndex = (this.currentPageIndex + 1) % this.pages.length;
console.log('Wechsel zu Seite:', this.currentPageIndex + 1);
this.cdr.detectChanges(); this.cdr.detectChanges();
// Fortschrittsbalken neu starten
this.startProgressBar(seitenwechselInSek); this.startProgressBar(seitenwechselInSek);
// Nach dem Seitenwechsel die Schriftgröße anpassen (nicht mehr notwendig)
// setTimeout(() => {
// this.adjustFontSize();
// }, 0);
} else { } else {
console.warn('Keine ausreichende Anzahl von Seiten zum Wechseln'); console.warn('Keine ausreichende Anzahl von Seiten zum Wechseln');
} }
@@ -661,23 +631,14 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
} }
/**
* Event Listener für Fenstergrößenänderungen, um die Paginierung anzupassen
*/
@HostListener('window:resize') @HostListener('window:resize')
onResizeHostListener(): void { onResizeHostListener(): 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 { private arrivalsAreEqual(a: AvisoDto[], b: AvisoDto[]): boolean {
if (a.length !== b.length) { if (a.length !== b.length) {
console.log(`Arrays haben unterschiedliche Längen: a.length = ${a.length}, b.length = ${b.length}`); console.log(`Array-Längen sind unterschiedlich: a.length = ${a.length}, b.length = ${b.length}`);
return false; return false;
} }
@@ -685,98 +646,180 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
const aItem = a[i]; const aItem = a[i];
const bItem = b[i]; const bItem = b[i];
if ( if (aItem.avisoID !== bItem.avisoID) {
aItem.avisoID !== bItem.avisoID || console.log(`Unterschied bei avisoID an Index ${i}: a.avisoID = ${aItem.avisoID}, b.avisoID = ${bItem.avisoID}`);
aItem.status !== bItem.status || return false;
aItem.lkW_Nr !== bItem.lkW_Nr || }
aItem.ankunft !== bItem.ankunft ||
aItem.dauer !== bItem.dauer || if (aItem.status !== bItem.status) {
aItem.letzterMitarbeiter !== bItem.letzterMitarbeiter || console.log(`Unterschied bei status an Index ${i}: a.status = ${aItem.status}, b.status = ${bItem.status}`);
aItem.weiterleitungTextTV !== bItem.weiterleitungTextTV || return false;
aItem.imEx !== bItem.imEx || }
aItem.zollDigitalEingereicht !== bItem.zollDigitalEingereicht ||
aItem.buero !== bItem.buero || if (aItem.lkW_Nr !== bItem.lkW_Nr) {
aItem.avisoTVHinweis !== bItem.avisoTVHinweis console.log(`Unterschied bei lkW_Nr an Index ${i}: a.lkW_Nr = ${aItem.lkW_Nr}, b.lkW_Nr = ${bItem.lkW_Nr}`);
) { return false;
console.log(`Unterschied bei Index ${i}:`); }
console.log(`a[${i}] =`, aItem);
console.log(`b[${i}] =`, bItem); if (aItem.ankunft !== bItem.ankunft) {
console.log(`Unterschiede:`); console.log(`Unterschied bei ankunft an Index ${i}: a.ankunft = ${aItem.ankunft}, b.ankunft = ${bItem.ankunft}`);
if (aItem.avisoID !== bItem.avisoID) console.log(` avisoID: ${aItem.avisoID} !== ${bItem.avisoID}`); return false;
if (aItem.status !== bItem.status) console.log(` status: ${aItem.status} !== ${bItem.status}`); }
if (aItem.lkW_Nr !== bItem.lkW_Nr) console.log(` lkW_Nr: ${aItem.lkW_Nr} !== ${bItem.lkW_Nr}`);
if (aItem.ankunft !== bItem.ankunft) console.log(` ankunft: ${aItem.ankunft} !== ${bItem.ankunft}`); if (aItem.dauer !== bItem.dauer) {
if (aItem.dauer !== bItem.dauer) console.log(` dauer: ${aItem.dauer} !== ${bItem.dauer}`); console.log(`Unterschied bei dauer an Index ${i}: a.dauer = ${aItem.dauer}, b.dauer = ${bItem.dauer}`);
if (aItem.letzterMitarbeiter !== bItem.letzterMitarbeiter) return false;
console.log(` letzterMitarbeiter: ${aItem.letzterMitarbeiter} !== ${bItem.letzterMitarbeiter}`); }
if (aItem.weiterleitungTextTV !== bItem.weiterleitungTextTV)
console.log(` weiterleitungTextTV: ${aItem.weiterleitungTextTV} !== ${bItem.weiterleitungTextTV}`); if (aItem.letzterMitarbeiter !== bItem.letzterMitarbeiter) {
if (aItem.imEx !== bItem.imEx) console.log(` imEx: ${aItem.imEx} !== ${bItem.imEx}`); console.log(`Unterschied bei letzterMitarbeiter an Index ${i}: a.letzterMitarbeiter = ${aItem.letzterMitarbeiter}, b.letzterMitarbeiter = ${bItem.letzterMitarbeiter}`);
if (aItem.zollDigitalEingereicht !== bItem.zollDigitalEingereicht) return false;
console.log(` zollDigitalEingereicht: ${aItem.zollDigitalEingereicht} !== ${bItem.zollDigitalEingereicht}`); }
if (aItem.buero !== bItem.buero) console.log(` buero: ${aItem.buero} !== ${bItem.buero}`);
if (aItem.avisoTVHinweis !== bItem.avisoTVHinweis) if (aItem.weiterleitungTextTV !== bItem.weiterleitungTextTV) {
console.log(` avisoTVHinweis: ${aItem.avisoTVHinweis} !== ${bItem.avisoTVHinweis}`); console.log(`Unterschied bei weiterleitungTextTV an Index ${i}: a.weiterleitungTextTV = ${aItem.weiterleitungTextTV}, b.weiterleitungTextTV = ${bItem.weiterleitungTextTV}`);
return false;
}
if (aItem.imEx !== bItem.imEx) {
console.log(`Unterschied bei imEx an Index ${i}: a.imEx = ${aItem.imEx}, b.imEx = ${bItem.imEx}`);
return false;
}
if (aItem.zollDigitalEingereicht !== bItem.zollDigitalEingereicht) {
console.log(`Unterschied bei zollDigitalEingereicht an Index ${i}: a.zollDigitalEingereicht = ${aItem.zollDigitalEingereicht}, b.zollDigitalEingereicht = ${bItem.zollDigitalEingereicht}`);
return false;
}
if (aItem.buero !== bItem.buero) {
console.log(`Unterschied bei buero an Index ${i}: a.buero = ${aItem.buero}, b.buero = ${bItem.buero}`);
return false;
}
if (aItem.avisoTVHinweis !== bItem.avisoTVHinweis) {
console.log(`Unterschied bei avisoTVHinweis an Index ${i}: a.avisoTVHinweis = ${aItem.avisoTVHinweis}, b.avisoTVHinweis = ${bItem.avisoTVHinweis}`);
return false; return false;
} }
} }
console.log("Die Arrays sind gleich."); console.log('Die beiden Arrays sind gleich.');
return true; return true;
} }
// Hinzugefügte Methode zum Verwalten der Aviso-Zyklen
private updateAvisoStatesAndCycles(): void { private updateAvisoStatesAndCycles(): void {
const currentKeys = new Set<string>(); const currentKeys = new Set<string>();
this.pages.forEach(page => {
page.forEach(aviso => { this.arrivals.forEach(aviso => {
const key = aviso.lkW_Nr; // Eindeutiger Schlüssel const key = aviso.lkW_Nr;
currentKeys.add(key); currentKeys.add(key);
if (aviso.avisoTVHinweis && !(key in this.avisoStates)) {
this.avisoStates[key] = true; // Initialer Zustand this.handleAvisoTVHinweis(aviso, key);
this.startAvisoCycle(key); this.handleLkwFertigAndTextToggle(aviso, key);
} else if (!aviso.avisoTVHinweis) {
// Falls kein Hinweis vorhanden ist, Zustand auf true setzen
this.avisoStates[key] = true;
}
});
}); });
// Bereinigen von Avisos, die nicht mehr vorhanden sind this.cleanupObsoleteEntries(currentKeys);
}
private handleAvisoTVHinweis(aviso: AvisoDto, key: string): void {
if (aviso.avisoTVHinweis) {
if (!(key in this.avisoStates)) {
this.avisoStates[key] = true;
this.startAvisoCycle(key);
console.log(`Started aviso cycle for key: ${key}`);
}
} else {
this.avisoStates[key] = true;
}
}
private handleLkwFertigAndTextToggle(aviso: AvisoDto, key: string): void {
if (aviso.lkW_fertig && aviso.avisoTVHinweis === "") {
if (!this.displayMitarbeiterTexts[key]) {
this.displayMitarbeiterTexts[key] = WECHSELTEXT;
console.log(`Initialized displayMitarbeiterTexts for key: ${key}`);
}
if (!this.avisoMitarbeiterIntervals[key]) {
this.avisoMitarbeiterIntervals[key] = setInterval(() => {
this.toggleMitarbeiterText(aviso, key);
}, this.MITARBEITER_INTERVAL_MS);
console.log(`Started text toggle interval for key: ${key}`);
}
} else {
this.clearMitarbeiterTextToggle(key);
}
}
private toggleMitarbeiterText(aviso: AvisoDto, key: string): void {
if (this.displayMitarbeiterTexts[key] === WECHSELTEXT) {
this.displayMitarbeiterTexts[key] = aviso.letzterMitarbeiter || 'Mitarbeiter nicht verfügbar';
} else {
this.displayMitarbeiterTexts[key] = WECHSELTEXT;
}
this.cdr.detectChanges();
}
private cleanupObsoleteEntries(currentKeys: Set<string>): void {
Object.keys(this.avisoStates).forEach(key => { Object.keys(this.avisoStates).forEach(key => {
if (!currentKeys.has(key)) { if (!currentKeys.has(key)) {
clearTimeout(this.avisoTimeouts[key]); clearTimeout(this.avisoTimeouts[key]);
delete this.avisoStates[key]; delete this.avisoStates[key];
delete this.avisoTimeouts[key]; delete this.avisoTimeouts[key];
console.log(`Cleaned up avisoStates and timeouts for key: ${key}`);
}
});
Object.keys(this.avisoMitarbeiterIntervals).forEach(key => {
if (!currentKeys.has(key)) {
clearInterval(this.avisoMitarbeiterIntervals[key]);
delete this.avisoMitarbeiterIntervals[key];
console.log(`Cleaned up Mitarbeiter-Interval for key: ${key}`);
}
});
Object.keys(this.displayMitarbeiterTexts).forEach(key => {
if (!currentKeys.has(key)) {
delete this.displayMitarbeiterTexts[key];
console.log(`Cleaned up displayMitarbeiterTexts for key: ${key}`);
} }
}); });
} }
private clearMitarbeiterTextToggle(key: string): void {
if (this.avisoMitarbeiterIntervals[key]) {
clearInterval(this.avisoMitarbeiterIntervals[key]);
delete this.avisoMitarbeiterIntervals[key];
console.log(`Cleared text toggle interval for key: ${key}`);
}
if (this.displayMitarbeiterTexts[key]) {
delete this.displayMitarbeiterTexts[key];
console.log(`Cleared displayMitarbeiterTexts for key: ${key}`);
}
}
private startAvisoCycle(key: string): void { private startAvisoCycle(key: string): void {
// Aviso mit diesem Schlüssel finden
const aviso = this.findAvisoByKey(key); const aviso = this.findAvisoByKey(key);
if (!aviso || !aviso.avisoTVHinweis) { if (!aviso || !aviso.avisoTVHinweis) {
return; return;
} }
if (this.avisoStates[key]) { if (this.avisoStates[key]) {
// Aktuell wird der normale Inhalt angezeigt
this.avisoTimeouts[key] = setTimeout(() => { this.avisoTimeouts[key] = setTimeout(() => {
this.avisoStates[key] = false; // Umschalten auf avisoTVHinweis Text this.avisoStates[key] = false;
this.startAvisoCycle(key); // Nächsten Zyklus starten this.startAvisoCycle(key);
this.cdr.detectChanges(); this.cdr.detectChanges();
}, this.contentDuration); }, this.contentDuration);
} else { } else {
// Aktuell wird der avisoTVHinweis Text angezeigt
this.avisoTimeouts[key] = setTimeout(() => { this.avisoTimeouts[key] = setTimeout(() => {
this.avisoStates[key] = true; // Umschalten auf normalen Inhalt this.avisoStates[key] = true;
this.startAvisoCycle(key); // Nächsten Zyklus starten this.startAvisoCycle(key);
this.cdr.detectChanges(); this.cdr.detectChanges();
}, this.avisoHinweisDuration); }, this.avisoHinweisDuration);
} }
} }
// Hilfsmethode zum Finden eines Aviso anhand des Schlüssels
private findAvisoByKey(key: string): AvisoDto | undefined { private findAvisoByKey(key: string): AvisoDto | undefined {
for (const page of this.pages) { for (const page of this.pages) {
for (const aviso of page) { for (const aviso of page) {
@@ -788,10 +831,9 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
return undefined; return undefined;
} }
// Neue Methode zur Entscheidung, welcher Inhalt angezeigt wird
shouldShowNormalContent(aviso: AvisoDto): boolean { shouldShowNormalContent(aviso: AvisoDto): boolean {
if (!aviso.avisoTVHinweis) { if (!aviso.avisoTVHinweis) {
return true; // Kein Hinweis vorhanden, immer normalen Inhalt anzeigen return true;
} }
return this.avisoStates[aviso.lkW_Nr]; return this.avisoStates[aviso.lkW_Nr];
} }
@@ -802,24 +844,16 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
'assets/flags/EN.gif', 'assets/flags/EN.gif',
'assets/flags/TR.gif', 'assets/flags/TR.gif',
]; ];
return images[index] || 'assets/imgs/DE.png'; return images[index] || 'assets/imgs/DE.png';
} }
/**
* Event Handler für das `resizeComplete` Event der Directive.
* Setzt das `isDivReady` Flag auf `true`, um das Div anzuzeigen.
* @param index Der Index des SettingDisplayData
*/
onResizeComplete(index: number): void { onResizeComplete(index: number): void {
this.settingDisplayData[index].isDivReady = true; this.settingDisplayData[index].isDivReady = true;
this.cdr.detectChanges(); this.cdr.detectChanges();
} }
getImageClass(hinweis: string): string { getImageClass(hinweis: string): string {
const lowercaseHinweis = hinweis.toLowerCase(); const lowercaseHinweis = hinweis.toLowerCase();
if (lowercaseHinweis === 'problem') { if (lowercaseHinweis === 'problem') {
return 'problem'; return 'problem';
} else if (lowercaseHinweis === 'passport') { } else if (lowercaseHinweis === 'passport') {
@@ -831,10 +865,8 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
} }
getImageClassButtomLeft(hinweis: string): string { getImageClassButtomLeft(hinweis: string): string {
const lowercaseHinweis = hinweis.toLowerCase(); const lowercaseHinweis = hinweis.toLowerCase();
if (lowercaseHinweis === 'problem') { if (lowercaseHinweis === 'problem') {
return 'bottom-left-image-problem'; return 'bottom-left-image-problem';
} else if (lowercaseHinweis === 'passport') { } else if (lowercaseHinweis === 'passport') {

View File

@@ -7,6 +7,7 @@ import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.servic
import { AvisoTvTextSettingsDto, TvSettings } from '../../services/aviso.dto'; import { AvisoTvTextSettingsDto, TvSettings } from '../../services/aviso.dto';
interface AvisoResolvedData { interface AvisoResolvedData {
standortID?: number;
avisoTvTextSettings: AvisoTvTextSettingsDto[]; avisoTvTextSettings: AvisoTvTextSettingsDto[];
avisoTvSettings: TvSettings[]; avisoTvSettings: TvSettings[];
arrivals: AvisoArrivalsResponse; arrivals: AvisoArrivalsResponse;
@@ -23,7 +24,6 @@ export class AvisoResolver implements Resolve<AvisoResolvedData> {
state: RouterStateSnapshot state: RouterStateSnapshot
): Observable<AvisoResolvedData> { ): Observable<AvisoResolvedData> {
const standort = route.queryParamMap.get('standort') || ''; const standort = route.queryParamMap.get('standort') || '';
const seiten = route.queryParamMap.get('seiten') === 'true';
const onlyOK = route.queryParamMap.get('onlyOK') === 'true'; const onlyOK = route.queryParamMap.get('onlyOK') === 'true';
if (!standort) { if (!standort) {
@@ -35,7 +35,7 @@ export class AvisoResolver implements Resolve<AvisoResolvedData> {
} as AvisoResolvedData); } as AvisoResolvedData);
} }
return this.avisoService.getStandortID(standort).pipe( return this.avisoService.getStandortID(standort).pipe(
catchError(error => { catchError(error => {
console.error('Fehler beim Abrufen der StandortID', error); console.error('Fehler beim Abrufen der StandortID', error);
return of(null); return of(null);
@@ -52,8 +52,8 @@ export class AvisoResolver implements Resolve<AvisoResolvedData> {
const standortID = result.standortID; const standortID = result.standortID;
return forkJoin({ return forkJoin({
avisoTvTextSettings: this.avisoService.getAvisoTvTextSettings(standort).pipe( avisoTvTextSettings: this.avisoService.getAvisoTvTextSettings(standort).pipe(
catchError(error => { catchError(error => {
console.error('Fehler beim Laden der TV Text Settings', error); console.error('Fehler beim Laden der TV Text Settings', error);
return of([] as AvisoTvTextSettingsDto[]); return of([] as AvisoTvTextSettingsDto[]);
@@ -65,13 +65,22 @@ export class AvisoResolver implements Resolve<AvisoResolvedData> {
return of([] as TvSettings[]); return of([] as TvSettings[]);
}) })
), ),
arrivals: this.avisoService.getArrivals(standort, seiten, onlyOK).pipe( arrivals: this.avisoService.getArrivals(standort, onlyOK).pipe(
catchError(error => { catchError(error => {
console.error('Fehler beim Laden der Arrivals', error); console.error('Fehler beim Laden der Arrivals', error);
return of({ avisos: [], totalCount: 0 } as AvisoArrivalsResponse); return of({ avisos: [], totalCount: 0 } as AvisoArrivalsResponse);
}) })
) )
}); }).pipe(
switchMap(data => {
return of({
standortID,
avisoTvTextSettings: data.avisoTvTextSettings,
avisoTvSettings: data.avisoTvSettings,
arrivals: data.arrivals
} as AvisoResolvedData);
})
);
}), }),
catchError(error => { catchError(error => {
console.error('Allgemeiner Fehler im Resolver', error); console.error('Allgemeiner Fehler im Resolver', error);

View File

@@ -11,6 +11,8 @@ export interface AvisoDto {
zollDigitalEingereicht: boolean; zollDigitalEingereicht: boolean;
buero: string; buero: string;
avisoTVHinweis: string; avisoTVHinweis: string;
displayText?: string;
} }
export interface TvSettings { export interface TvSettings {
@@ -25,6 +27,8 @@ export interface TvSettings {
textBalkenHeightInPercent: number; textBalkenHeightInPercent: number;
lineHeight: number; lineHeight: number;
logo: string; logo: string;
flaggeLeft: string;
flaggeBottom: string;
} }
export interface AvisoTvTextSettingsDto { export interface AvisoTvTextSettingsDto {

View File

@@ -6,14 +6,12 @@ import { AvisoDto, TvSettings } from './aviso.dto';
import { AvisoTvTextSettingsDto } from './aviso-tv-settings.dto'; import { AvisoTvTextSettingsDto } from './aviso-tv-settings.dto';
import { environment } from '../../environments/environment'; import { environment } from '../../environments/environment';
// Definiere die Response Interfaces
export interface AvisoArrivalsResponse { export interface AvisoArrivalsResponse {
avisos: AvisoDto[]; avisos: AvisoDto[];
totalCount: number; totalCount: number;
} }
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
@@ -30,10 +28,10 @@ export class AvisoService {
* @param onlyOK Gibt an, ob nur gültige Ankünfte zurückgegeben werden sollen. * @param onlyOK Gibt an, ob nur gültige Ankünfte zurückgegeben werden sollen.
* @returns Ein Observable von AvisoArrivalsResponse. * @returns Ein Observable von AvisoArrivalsResponse.
*/ */
getArrivals(standort: string, seiten: boolean = false, onlyOK: boolean = false): Observable<AvisoArrivalsResponse> { getArrivals(standort: string, onlyOK: boolean = false): Observable<AvisoArrivalsResponse> {
let params = new HttpParams() let params = new HttpParams()
.set('standort', standort) .set('standort', standort)
.set('seiten', seiten.toString()) .set('seiten', 'True')
.set('onlyOK', onlyOK.toString()); .set('onlyOK', onlyOK.toString());
return this.http.get<AvisoArrivalsResponse>(`${this.baseUrl}/Aviso/arrivals`, { params }) return this.http.get<AvisoArrivalsResponse>(`${this.baseUrl}/Aviso/arrivals`, { params })

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,4 +1,4 @@
export const environment = { export const environment = {
production: true, production: true,
baseUrl: 'https://avisotv.server.app.verag.ag/api/Aviso' baseUrl: 'https://avisotv.server.app.verag.ag/api'
}; };

View File

@@ -34,4 +34,4 @@
/* @import "@ionic/angular/css/palettes/dark.always.css"; */ /* @import "@ionic/angular/css/palettes/dark.always.css"; */
/* @import "@ionic/angular/css/palettes/dark.class.css"; */ /* @import "@ionic/angular/css/palettes/dark.class.css"; */
@import "@ionic/angular/css/palettes/dark.system.css"; //@import "@ionic/angular/css/palettes/dark.system.css";

View File

@@ -7,7 +7,7 @@
<base href="/" /> <base href="/" />
<meta name="color-scheme" content="light dark" /> <meta name="color-scheme" content="light" />
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="format-detection" content="telephone=no" /> <meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" /> <meta name="msapplication-tap-highlight" content="no" />
@@ -15,8 +15,8 @@
<link rel="icon" type="image/png" href="assets/icon/favicon.png" /> <link rel="icon" type="image/png" href="assets/icon/favicon.png" />
<!-- add to homescreen for ios --> <!-- add to homescreen for ios -->
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" /> <meta name="mobile-web-app-status-bar-style" content="black" />
</head> </head>
<body> <body>

View File

@@ -1,2 +0,0 @@
// For information on how to create your own theme, please see:
// http://ionicframework.com/docs/theming/