This commit is contained in:
2024-12-23 09:58:28 +01:00
parent 34f86fccd1
commit cbbb2329bb
3 changed files with 192 additions and 268 deletions

View File

@@ -4,7 +4,6 @@
Header Header
====================================================== --> ====================================================== -->
<ion-header> <ion-header>
</ion-header> </ion-header>
<!-- ====================================================== <!-- ======================================================
@@ -35,11 +34,15 @@
<ion-card *ngFor="let aviso of pages[currentPageIndex]; let i = index" <ion-card *ngFor="let aviso of pages[currentPageIndex]; let i = index"
class="arrival-card" class="arrival-card"
[ngClass]="getStatusClass(aviso.status, aviso.lkW_fertig, aviso.avisoTVHinweis)"> [ngClass]="getStatusClass(aviso.status, aviso.lkW_fertig, aviso.avisoTVHinweis)">
<!-- Nummer links oben (Kachel-Index in der aktuellen Seite) -->
<div class="card-number">{{ getOverallIndex(i) }}</div> <div class="card-number">{{ getOverallIndex(i) }}</div>
<!-- Wenn kein Hinweis oder 'shouldShowNormalContent' == true -> normaler Inhalt -->
<ng-container *ngIf="shouldShowNormalContent(aviso); else showAvisoHinweis"> <ng-container *ngIf="shouldShowNormalContent(aviso); else showAvisoHinweis">
<div class="flex-container"> <div class="flex-container">
<!-- LKW-Nummer -->
<div class="lkwnr" <div class="lkwnr"
appAutoFontSize appAutoFontSize
[maxFontSizePercentage]="34" [maxFontSizePercentage]="34"
@@ -47,55 +50,80 @@
{{ aviso.lkW_Nr }} {{ aviso.lkW_Nr }}
</div> </div>
<!-- Datum / Zeit / Dauer -->
<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]="getStatusIcon(aviso.status)" <ion-icon [name]="getStatusIcon(aviso.status)"
[color]="getStatusColor(aviso.status)" [color]="getStatusColor(aviso.status)"
class="inline-icon"></ion-icon> class="inline-icon">
</ion-icon>
{{ aviso.ankunft }} {{ aviso.ankunft }}
<ion-icon name="hourglass-outline" <ion-icon name="hourglass-outline"
[color]="getStatusColor(aviso.status)" [color]="getStatusColor(aviso.status)"
class="inline-icon"></ion-icon> class="inline-icon">
</ion-icon>
{{ aviso.dauer }} {{ aviso.dauer }}
</div> </div>
<!-- Mitarbeiter / Wechseltext (nur bei fertigem LKW ohne Hinweis) -->
<div class="ion-text-center" <div class="ion-text-center"
appAutoFontSize appAutoFontSize
[maxFontSizePercentage]="33" [maxFontSizePercentage]="33"
[maxFontSize]="avisoTvSettings[0].kachelFontSizeDateTime" [maxFontSize]="avisoTvSettings[0].kachelFontSizeDateTime"
[ngClass]="{'wechseltextdiv': displayMitarbeiterTexts[aviso.lkW_Nr] === 'BITTE KOMMEN / LÜTFEN GELIN'}"> [ngClass]="{'wechseltextdiv': toggleWechselText && aviso.lkW_fertig && !aviso.avisoTVHinweis}">
<!-- Icon -->
<ion-icon name="person-outline" <ion-icon name="person-outline"
[ngClass]="{'wechseltext': displayMitarbeiterTexts[aviso.lkW_Nr] === 'BITTE KOMMEN / LÜTFEN GELIN'}"> [ngClass]="{'wechseltext': toggleWechselText && aviso.lkW_fertig && !aviso.avisoTVHinweis}">
</ion-icon> </ion-icon>
{{ displayMitarbeiterTexts[aviso.lkW_Nr] || aviso.letzterMitarbeiter }}
<!-- Wenn LKW fertig und KEIN Hinweis => Text wechseln -->
<ng-container *ngIf="aviso.lkW_fertig && !aviso.avisoTVHinweis; else noToggleText">
{{
toggleWechselText
? 'BITTE KOMMEN / LÜTFEN GELIN'
: (aviso.letzterMitarbeiter || 'Mitarbeiter nicht verfügbar')
}}
</ng-container>
<!-- Fallback: normaler Mitarbeiter-Text -->
<ng-template #noToggleText>
{{ aviso.letzterMitarbeiter }}
</ng-template>
</div> </div>
</div> </div>
<!-- Hinweis-Bildchen (Passport, Problem etc.) -->
<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">
<img [src]="getTvHinweisImgSrc(aviso.avisoTVHinweis)" alt="Aviso Hinweis" /> <img [src]="getTvHinweisImgSrc(aviso.avisoTVHinweis)" alt="Aviso Hinweis" />
</div> </div>
<!-- LKW fertig + kein Hinweis => OK-Badge -->
<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="Fertig / OK" />
</div> </div>
<!-- Zusätzliche IM/EX-Icons (Standort 'WAI') -->
<div *ngIf="standort === 'WAI'"> <div *ngIf="standort === 'WAI'">
<div class="bottom-right-icon-im" *ngIf="aviso.imEx === 'IMPORT'"> <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> <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'"> <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> <img src="assets/icon/import_icon.png"
style="width: 0.7em; aspect-ratio: 10 / 12" />
</div>
</div> </div>
</ng-container> </ng-container>
<!-- ======================================================
ELSE: Hinweis-Anzeige
====================================================== -->
<ng-template #showAvisoHinweis> <ng-template #showAvisoHinweis>
<div class="flex-container-hinweis"> <div class="flex-container-hinweis">
<div class="lkwnr" style="margin-top: 1%; margin-bottom: 1%" <div class="lkwnr" style="margin-top: 1%; margin-bottom: 1%"
@@ -110,6 +138,7 @@
</div> </div>
</div> </div>
<!-- IM/EX-Icons bei Hinweisen (nur Standort 'WAI') -->
<div *ngIf="standort === 'WAI'"> <div *ngIf="standort === 'WAI'">
<div class="bottom-right-icon" *ngIf="aviso.imEx === 'IMPORT'"> <div class="bottom-right-icon" *ngIf="aviso.imEx === 'IMPORT'">
<ion-icon name="download-outline"></ion-icon> <ion-icon name="download-outline"></ion-icon>
@@ -120,12 +149,10 @@
</div> </div>
</ng-template> </ng-template>
</ion-card> </ion-card>
</div> </div>
<!-- ====================================================== <!-- ======================================================
Nachricht bei fehlenden Arrivals Keine Ankünfte
====================================================== --> ====================================================== -->
<ion-grid> <ion-grid>
<ion-row *ngIf="!loadingArrivals && arrivals.length === 0 && !errorMessage"> <ion-row *ngIf="!loadingArrivals && arrivals.length === 0 && !errorMessage">
@@ -136,18 +163,15 @@
</ion-col> </ion-col>
</ion-row> </ion-row>
</ion-grid> </ion-grid>
<!-- Bedingtes Textfeld für TV-Einstellungen -->
</ion-content> </ion-content>
<!-- ====================================================== <!-- ======================================================
Logobar mit Progress Bar Logobar mit Progress Bar
====================================================== --> ====================================================== -->
<ion-progress-bar [value]="progressBarValue" <ion-progress-bar [value]="progressBarValue"
class="custom-progress-bar" class="custom-progress-bar"
buffer="1"></ion-progress-bar> buffer="1">
</ion-progress-bar>
<ion-toolbar class="logobar"> <ion-toolbar class="logobar">
<!-- Start Slot --> <!-- Start Slot -->
@@ -160,25 +184,26 @@
<div class="logo-and-icons"> <div class="logo-and-icons">
<img [src]="'assets/Logos/' + avisoTvSettings[0].logo" class="logo" /> <img [src]="'assets/Logos/' + avisoTvSettings[0].logo" class="logo" />
<!-- Bedingtes Div für WAI Standort --> <!-- Legende für WAI (Import / Export) -->
<div *ngIf="standort === 'WAI'" class="title legendecontainer"> <div *ngIf="standort === 'WAI'" class="title legendecontainer">
<div class="div-import"> <div class="div-import">
<img src="assets/icon/import_icon.png" style="width: 0.8em; aspect-ratio: 10 / 12" /> = IMPORT <img src="assets/icon/import_icon.png"
</div> style="width: 0.8em; aspect-ratio: 10 / 12" /> = IMPORT
<div class="div-export">
<img src="assets/icon/export_icon_1.png" style="width: 0.8em; aspect-ratio: 10 / 12" /> = EXPORT
</div>
</div> </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> </div>
<!-- End Slot --> <!-- End Slot -->
<span slot="end" class="title" style="margin-right:0.3%"> <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-toolbar> </ion-toolbar>
<!-- ====================================================== <!-- ======================================================
Footer mit Tabs Footer mit Tabs
====================================================== --> ====================================================== -->

View File

@@ -40,7 +40,8 @@ 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" //Wechseltext
const WECHSELTEXT = "BITTE KOMMEN / LÜTFEN GELIN";
interface StatusInfo { interface StatusInfo {
class: string; class: string;
@@ -87,6 +88,8 @@ 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();
private durationSubscription: Subscription = new Subscription();
standort = ''; standort = '';
standortID = 0; standortID = 0;
seiten = true; seiten = true;
@@ -114,20 +117,23 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
private toggleDivInterval: any; private toggleDivInterval: any;
private currentCssVariables: CssVariables | null = null; private currentCssVariables: CssVariables | null = null;
settingDisplayData: SettingDisplayData[] = []; // NEU: Für den globalen Wechseltext
public toggleWechselText: boolean = false;
avisoTimeouts: { [key: string]: any } = {}; private GLOBAL_WECHSELTEXT_INTERVAL: any;
avisoStates: { [key: string]: boolean } = {};
displayMitarbeiterTexts: { [key: string]: string } = {};
avisoOriginalLetzterMitarbeiter: { [key: string]: string } = {};
avisoMitarbeiterIntervals: { [key: string]: any } = {};
private MITARBEITER_INTERVAL_MS = 3000;
// Zeiten für Hint-/Normal-Anzeige
contentDuration = 3000; contentDuration = 3000;
avisoHinweisDuration = 1500; avisoHinweisDuration = 1500;
pendingArrivals: AvisoDto[] | null = null; // Anzeigedaten für die Fixe-Zeilen im oberen Bereich
settingDisplayData: SettingDisplayData[] = [];
// Zustände für AVISOs (z.B. ob normaler Inhalt vs. Warnhinweis gezeigt wird)
avisoTimeouts: { [key: string]: any } = {};
avisoStates: { [key: string]: boolean } = {};
// Falls neue Arrivals schon geladen, aber noch nicht aktiv
pendingArrivals: AvisoDto[] | null = null;
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@@ -148,11 +154,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
ngOnInit() { ngOnInit() {
this.currentDate = new Date();
this.dateSubscription = interval(1000).subscribe(() => {
this.currentDate = new Date();
});
this.route.paramMap.subscribe(params => { this.route.paramMap.subscribe(params => {
this.standort = params.get('standort') || ''; this.standort = params.get('standort') || '';
}); });
@@ -163,42 +164,28 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.onlyOK = queryParams.get('onlyOK') === 'true'; this.onlyOK = queryParams.get('onlyOK') === 'true';
}); });
this.route.data.pipe(takeUntil(this.destroy$)).subscribe((resolvedData) => { this.route.data
const data = (resolvedData as any)['avisoData'] as AvisoResolvedData; .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;
this.standortID = data.standortID;
this.avisoTvTextSettings = data.avisoTvTextSettings; this.paginateArrivals();
this.avisoTvSettings = data.avisoTvSettings; this.cdr.detectChanges();
this.arrivals = data.arrivals.avisos; this.preprocessHtmlSettings();
console.log(this.arrivals); this.setCSSVariables();
this.totalArrivals = data.arrivals.totalCount; this.startDivToggle();
this.standortID = data.standortID; this.paginateArrivals();
this.startPageRotation();
this.arrivals.forEach(aviso => { this.updateAvisoStatesAndCycles();
if (aviso.lkW_fertig && aviso.avisoTVHinweis === "") {
this.displayMitarbeiterTexts[aviso.lkW_Nr] = WECHSELTEXT;
}
}); });
// Arrivals zyklisch neu laden
/* this.arrivals.forEach(aviso => { const ARRIVALS_INTERVAL_MS = (this.avisoTvSettings[0]?.seitenwechselInSek * 1000 / 2) || 5000;
if (aviso.lkW_Nr === '81ACY359') {
aviso.avisoTVHinweis = 'URGENT';
}
});
*/
this.paginateArrivals();
this.cdr.detectChanges();
this.preprocessHtmlSettings();
this.setCSSVariables();
this.startDivToggle();
this.paginateArrivals();
this.startPageRotation();
this.updateAvisoStatesAndCycles();
});
const ARRIVALS_INTERVAL_MS = (this.avisoTvSettings[0].seitenwechselInSek * 1000 / 2);
interval(ARRIVALS_INTERVAL_MS) interval(ARRIVALS_INTERVAL_MS)
.pipe( .pipe(
switchMap(() => { switchMap(() => {
@@ -217,35 +204,21 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
) )
.subscribe((data: AvisoArrivalsResponse) => { .subscribe((data: AvisoArrivalsResponse) => {
this.loadingArrivals = false; this.loadingArrivals = false;
/* this.arrivals.forEach(aviso => {
if (aviso.lkW_Nr === '81ACY359') {
aviso.avisoTVHinweis = 'URGENT';
}
});*/
if (this.pages.length > 1) { if (this.pages.length > 1) {
// Bei mehreren Seiten erst mit dem nächsten Seitenwechsel übernehmen
this.pendingArrivals = data.avisos; this.pendingArrivals = data.avisos;
this.totalArrivals = data.totalCount; this.totalArrivals = data.totalCount;
} else { } else {
// Bei nur einer Seite direkt übernehmen
this.arrivals = data.avisos; this.arrivals = data.avisos;
this.totalArrivals = data.totalCount; this.totalArrivals = data.totalCount;
this.paginateArrivals(); this.paginateArrivals();
this.cdr.detectChanges(); this.cdr.detectChanges();
this.updateAvisoStatesAndCycles();
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];
}
}
});
} }
}); });
// TV Settings laden
interval(TVSETTINGS_INTERVAL_MS) interval(TVSETTINGS_INTERVAL_MS)
.pipe( .pipe(
switchMap(() => this.loadAvisoTvSettings()), switchMap(() => this.loadAvisoTvSettings()),
@@ -253,12 +226,31 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
) )
.subscribe(); .subscribe();
// TV Text Settings laden
interval(TVTEXTSETTINGS_INTERVAL_MS) interval(TVTEXTSETTINGS_INTERVAL_MS)
.pipe( .pipe(
switchMap(() => this.loadAvisoTvTextSettings()), switchMap(() => this.loadAvisoTvTextSettings()),
takeUntil(this.destroy$) takeUntil(this.destroy$)
) )
.subscribe(); .subscribe();
// Sekündliche Uhrzeit
this.currentDate = new Date();
this.dateSubscription = interval(1000).subscribe(() => {
this.currentDate = new Date();
});
// Dauerberechnung aller Arrivals
this.updateDurations();
this.durationSubscription = interval(60000).subscribe(() => {
this.updateDurations();
});
// Globaler Wechseltext für alle fertigen LKWs ohne Hinweis
this.GLOBAL_WECHSELTEXT_INTERVAL = setInterval(() => {
this.toggleWechselText = !this.toggleWechselText;
this.cdr.detectChanges();
}, 3000);
} }
ngAfterViewInit() { ngAfterViewInit() {
@@ -268,30 +260,61 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.destroy$.next(); this.destroy$.next();
this.destroy$.complete(); this.destroy$.complete();
Object.values(this.avisoMitarbeiterIntervals).forEach(intervalId => clearInterval(intervalId)); // Zeitgeber aufräumen
this.avisoMitarbeiterIntervals = {};
Object.values(this.avisoTimeouts).forEach(timeoutId => clearTimeout(timeoutId)); Object.values(this.avisoTimeouts).forEach(timeoutId => clearTimeout(timeoutId));
this.avisoTimeouts = {}; this.avisoTimeouts = {};
if (this.toggleDivInterval) { if (this.toggleDivInterval) {
clearInterval(this.toggleDivInterval); clearInterval(this.toggleDivInterval);
} }
if (this.progressBarSubscription) { if (this.progressBarSubscription) {
this.progressBarSubscription.unsubscribe(); this.progressBarSubscription.unsubscribe();
} }
if (this.dateSubscription) { if (this.dateSubscription) {
this.dateSubscription.unsubscribe(); this.dateSubscription.unsubscribe();
} }
if (this.durationSubscription) {
this.durationSubscription.unsubscribe();
}
if (this.GLOBAL_WECHSELTEXT_INTERVAL) {
clearInterval(this.GLOBAL_WECHSELTEXT_INTERVAL);
}
}
// Dauer (h/m) berechnen
private updateDurations(): void {
const currentYear = new Date().getFullYear();
const currentDate = new Date();
this.arrivals.forEach(aviso => {
if (aviso.ankunft) {
const [tagMonat, uhrzeit] = aviso.ankunft.split(' ');
const [tag, monat] = tagMonat.split('.');
const [stunden, minuten] = uhrzeit.split(':');
const arrivalDate = new Date(
currentYear,
parseInt(monat) - 1,
parseInt(tag),
parseInt(stunden),
parseInt(minuten)
);
const diffMs = currentDate.getTime() - arrivalDate.getTime();
if (diffMs >= 0) {
const diffMinutes = Math.floor(diffMs / 60000);
const hours = Math.floor(diffMinutes / 60);
const mins = diffMinutes % 60;
aviso.dauer = `${hours}h ${mins}m`;
} else {
aviso.dauer = '0h 0m';
}
}
});
this.cdr.detectChanges();
} }
private startProgressBar(seitenwechselInSek: number): void { private startProgressBar(seitenwechselInSek: number): void {
if (this.progressBarSubscription) { if (this.progressBarSubscription) {
this.progressBarSubscription.unsubscribe(); this.progressBarSubscription.unsubscribe();
} }
this.progressBarValue = 0; this.progressBarValue = 0;
const progressBarIntervalMs = 100; const progressBarIntervalMs = 100;
const totalSteps = Math.floor((seitenwechselInSek * 1000) / progressBarIntervalMs); const totalSteps = Math.floor((seitenwechselInSek * 1000) / progressBarIntervalMs);
@@ -356,7 +379,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
if (fontSize) { if (fontSize) {
const fontSizePx = this.convertToPx(fontSize); const fontSizePx = this.convertToPx(fontSize);
textAlign = div.style.textAlign || 'left'; textAlign = div.style.textAlign || 'left';
div.dataset['originalFontSizePx'] = fontSizePx.toString(); div.dataset['originalFontSizePx'] = fontSizePx.toString();
div.dataset['originalTextAlign'] = textAlign; div.dataset['originalTextAlign'] = textAlign;
} }
@@ -389,7 +411,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
this.reloadPageOnce(); this.reloadPageOnce();
return; return;
} }
Object.assign(this, newCssVariables); Object.assign(this, newCssVariables);
this.currentCssVariables = newCssVariables; this.currentCssVariables = newCssVariables;
} else { } else {
@@ -404,7 +425,7 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
private async loadAvisoTvSettings(): Promise<void> { private async loadAvisoTvSettings(): Promise<void> {
this.loadingTvSettings = true; this.loadingTvSettings = true;
try { try {
const data: TvSettings[] = await lastValueFrom( await lastValueFrom(
this.avisoService.getAvisoTvSettings(this.standortID).pipe( this.avisoService.getAvisoTvSettings(this.standortID).pipe(
tap((data: TvSettings[]) => { tap((data: TvSettings[]) => {
this.avisoTvSettings = data; this.avisoTvSettings = data;
@@ -422,7 +443,7 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
private async loadAvisoTvTextSettings(): Promise<void> { private async loadAvisoTvTextSettings(): Promise<void> {
this.loadingTextSettings = true; this.loadingTextSettings = true;
try { try {
const data: AvisoTvTextSettingsDto[] = await lastValueFrom( await lastValueFrom(
this.avisoService.getAvisoTvTextSettings(this.standort).pipe( this.avisoService.getAvisoTvTextSettings(this.standort).pipe(
tap((data: AvisoTvTextSettingsDto[]) => { tap((data: AvisoTvTextSettingsDto[]) => {
this.avisoTvTextSettings = data; this.avisoTvTextSettings = data;
@@ -448,7 +469,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
private startDivToggle(): void { private startDivToggle(): void {
const shouldToggle = this.settingDisplayData.some(data => data.nonEmptyFixeZeilen.length > 1); const shouldToggle = this.settingDisplayData.some(data => data.nonEmptyFixeZeilen.length > 1);
if (shouldToggle) { if (shouldToggle) {
this.toggleDivInterval = setInterval(() => { this.toggleDivInterval = setInterval(() => {
this.settingDisplayData.forEach((data, index) => { this.settingDisplayData.forEach((data, index) => {
@@ -468,7 +488,7 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
} }
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;
} else if (avisoTvhinweis != "") { } else if (avisoTvhinweis != "") {
return STATUS_MAP['fehlt'].class; return STATUS_MAP['fehlt'].class;
@@ -487,9 +507,11 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
return "assets/warnings/passport.png"; return "assets/warnings/passport.png";
} }
else if (avisotvhinweis.toLowerCase() == "problem") { else if (avisotvhinweis.toLowerCase() == "problem") {
return "assets/warnings/urgent.png" return "assets/warnings/urgent.png";
}
else {
return "assets/warnings/urgent.png";
} }
else { return "assets/warnings/urgent.png" }
} }
getStatusColor(status: number): string { getStatusColor(status: number): string {
@@ -513,7 +535,6 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
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.innerWidth; const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
@@ -524,6 +545,7 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
}; };
if (isMobileDevice()) { if (isMobileDevice()) {
// Keine Mehrseiten-Darstellung bei kleinen Geräten
this.pages = [this.arrivals]; this.pages = [this.arrivals];
this.tilesPerPage = this.arrivals.length; this.tilesPerPage = this.arrivals.length;
this.currentPageIndex = 0; this.currentPageIndex = 0;
@@ -548,10 +570,12 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
const containerPadding = (0 / 100) * windowHeight; const containerPadding = (0 / 100) * windowHeight;
const containerPaddingTotal = containerPadding * 2; const containerPaddingTotal = containerPadding * 2;
// Anzahl Spalten
const columns = Math.floor( const columns = Math.floor(
(windowWidth - containerPaddingTotal + gutterHorizontal) / (tileWidth + gutterHorizontal) (windowWidth - containerPaddingTotal + gutterHorizontal) / (tileWidth + gutterHorizontal)
) || 1; ) || 1;
// Platz für Zeilen berechnen
const availableHeightForTiles = const availableHeightForTiles =
windowHeight - windowHeight -
logo - logo -
@@ -574,20 +598,18 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
if (this.currentPageIndex >= this.pages.length) { if (this.currentPageIndex >= this.pages.length) {
this.currentPageIndex = 0; this.currentPageIndex = 0;
} }
this.updateAvisoStatesAndCycles();
} }
// *** 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;
} }
if (this.pages.length <= 1) { if (this.pages.length <= 1) {
console.info('Nur eine Seite vorhanden. Automatischer Seitenwechsel wird nicht gestartet.'); // Nur eine Seite
return; return;
} }
const seitenwechselInSek = this.avisoTvSettings[0].seitenwechselInSek; const seitenwechselInSek = this.avisoTvSettings[0].seitenwechselInSek;
if (typeof seitenwechselInSek === 'number' && seitenwechselInSek > 0) { if (typeof seitenwechselInSek === 'number' && seitenwechselInSek > 0) {
const intervalMs = seitenwechselInSek * 1000; const intervalMs = seitenwechselInSek * 1000;
@@ -596,25 +618,11 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
interval(intervalMs) interval(intervalMs)
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
.subscribe(() => { .subscribe(() => {
// *** NEU *** Hier prüfen wir, ob pendingArrivals vorliegen // Neue Arrivals erst beim Seitenwechsel übernehmen
if (this.pendingArrivals) { if (this.pendingArrivals) {
this.arrivals = this.pendingArrivals; this.arrivals = this.pendingArrivals;
this.pendingArrivals = null; this.pendingArrivals = null;
this.paginateArrivals(); 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(); this.cdr.detectChanges();
} }
@@ -638,165 +646,53 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
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(`Array-Längen sind unterschiedlich: a.length = ${a.length}, b.length = ${b.length}`);
return false; return false;
} }
for (let i = 0; i < a.length; i++) { for (let i = 0; i < a.length; i++) {
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.letzterMitarbeiter !== bItem.letzterMitarbeiter ||
if (aItem.status !== bItem.status) { aItem.imEx !== bItem.imEx ||
console.log(`Unterschied bei status an Index ${i}: a.status = ${aItem.status}, b.status = ${bItem.status}`); aItem.buero !== bItem.buero ||
return false; aItem.avisoTVHinweis !== bItem.avisoTVHinweis
} ) {
if (aItem.lkW_Nr !== bItem.lkW_Nr) {
console.log(`Unterschied bei lkW_Nr an Index ${i}: a.lkW_Nr = ${aItem.lkW_Nr}, b.lkW_Nr = ${bItem.lkW_Nr}`);
return false;
}
if (aItem.ankunft !== bItem.ankunft) {
console.log(`Unterschied bei ankunft an Index ${i}: a.ankunft = ${aItem.ankunft}, b.ankunft = ${bItem.ankunft}`);
return false;
}
if (aItem.dauer !== bItem.dauer) {
console.log(`Unterschied bei dauer an Index ${i}: a.dauer = ${aItem.dauer}, b.dauer = ${bItem.dauer}`);
return false;
}
if (aItem.letzterMitarbeiter !== bItem.letzterMitarbeiter) {
console.log(`Unterschied bei letzterMitarbeiter an Index ${i}: a.letzterMitarbeiter = ${aItem.letzterMitarbeiter}, b.letzterMitarbeiter = ${bItem.letzterMitarbeiter}`);
return false;
}
if (aItem.weiterleitungTextTV !== bItem.weiterleitungTextTV) {
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 beiden Arrays sind gleich.');
return true; return true;
} }
private updateAvisoStatesAndCycles(): void { private updateAvisoStatesAndCycles(): void {
const currentKeys = new Set<string>(); const currentKeys = new Set<string>();
this.arrivals.forEach(aviso => { this.arrivals.forEach(aviso => {
const key = aviso.lkW_Nr; const key = aviso.lkW_Nr;
currentKeys.add(key); currentKeys.add(key);
if (aviso.avisoTVHinweis) {
this.handleAvisoTVHinweis(aviso, key); // Hat das Aviso einen Hinweis, dann abwechseln
this.handleLkwFertigAndTextToggle(aviso, key); if (!(key in this.avisoStates)) {
this.avisoStates[key] = true;
this.startAvisoCycle(key);
}
} else {
// Kein Hinweis => immer normal
this.avisoStates[key] = true;
}
}); });
this.cleanupObsoleteEntries(currentKeys); // Alte Keys entfernen
}
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 {
@@ -804,7 +700,7 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
if (!aviso || !aviso.avisoTVHinweis) { if (!aviso || !aviso.avisoTVHinweis) {
return; return;
} }
// "true" => normaler Inhalt, "false" => Hinweis
if (this.avisoStates[key]) { if (this.avisoStates[key]) {
this.avisoTimeouts[key] = setTimeout(() => { this.avisoTimeouts[key] = setTimeout(() => {
this.avisoStates[key] = false; this.avisoStates[key] = false;
@@ -831,6 +727,8 @@ export class AvisoPage implements OnInit, OnDestroy, AfterViewInit {
return undefined; return undefined;
} }
// Falls kein Hinweis: immer "normalen" Content,
// sonst Umschalten zwischen normal und Hinweis
shouldShowNormalContent(aviso: AvisoDto): boolean { shouldShowNormalContent(aviso: AvisoDto): boolean {
if (!aviso.avisoTVHinweis) { if (!aviso.avisoTVHinweis) {
return true; return true;

View File

@@ -100,4 +100,5 @@ export class AvisoService {
catchError(this.handleError) catchError(this.handleError)
); );
} }
} }