# Conflicts: # src/app/shared/services/alarm-sound.service.tspull/14/head
| @@ -40,7 +40,6 @@ export class CentralizedSecurityManagementComponent | |||
| private dialog: MatDialog, | |||
| private renderer: Renderer2, | |||
| private alarmSoundService$: AlarmSoundService, | |||
| private confirmDialogService$: ConfirmDialogService, | |||
| ) {} | |||
| ngOnInit() { | |||
| @@ -103,14 +102,11 @@ export class CentralizedSecurityManagementComponent | |||
| this.state2 = message.state2 === '0'; // 1 OFF // alarm 1h | |||
| this.state5 = message.state5 === '1'; // 1 ON, 0 OFF | |||
| this.isReady = message.ready === '1'; | |||
| this.alarmSoundService$.startAlarm( | |||
| this.state5, | |||
| this.isReady, | |||
| this.state1, | |||
| this.state2, | |||
| ); | |||
| this.alarmSoundService$.startAlarm(this.state5, this.isReady, this.state1, this.state2); | |||
| this.updateIcons(); | |||
| } | |||
| } | |||
| addIconsToMap(): void { | |||
| @@ -3,49 +3,38 @@ | |||
| <div class="card-state"> | |||
| <img src="assets/images/ground.png"> | |||
| <div class="state t2" id="State2"> | |||
| <div> | |||
| <div class="sensor-off" [class.sensor-on]="(state1 && state5 && isReady)"> | |||
| <img [src]="state5 ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png'" style="width: 30px; height: 30px"> | |||
| <div fxLayout="row"> | |||
| <div class="sensor-off" [class.sensor-on]="(state1 && state5 && status1)"> | |||
| <img [src]="(state5 && status1) ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png'" style="width: 30px; height: 30px"> | |||
| </div> | |||
| <a href="/overview/camera-stream" target="_blank"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/camera.png"> | |||
| </a> | |||
| <ng-container [ngTemplateOutlet]="camera"></ng-container> | |||
| </div> | |||
| <div *ngIf="(state1 && state5 && isReady)" class="alarm-text" | |||
| [ngClass]="{'alarm-text-on': (state1 && state5 && isReady) }">FIRE ALARM</div> | |||
| <div *ngIf="(state1 && state5 && status1)" class="alarm-text" | |||
| [ngClass]="{'alarm-text-on': (state1 && state5 && status1) }">FIRE ALARM</div> | |||
| </div> | |||
| <div class="state t3" id="State3"> | |||
| <div> | |||
| <div class="sensor-off" [class.sensor-on]="(state2 && state5 && isReady)"> | |||
| <img [src]="state5 ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png'" style="width: 30px; height: 30px"> | |||
| <div fxLayout="row"> | |||
| <div class="sensor-off" [class.sensor-on]="(state2 && state5 && status2)"> | |||
| <img [src]="(state5 && status2) ? 'assets/images/sensor-on.png' : 'assets/images/sensor-off.png'" style="width: 30px; height: 30px"> | |||
| </div> | |||
| <a href="/overview/camera-stream" target="_blank"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/camera.png"> | |||
| </a> | |||
| <ng-container [ngTemplateOutlet]="camera"></ng-container> | |||
| </div> | |||
| <div *ngIf="(state2 && state5 && isReady)" class="alarm-text" | |||
| [ngClass]="{'alarm-text-on': (state2 && state5 && isReady) }">FENCE ALARM</div> | |||
| <div *ngIf="(state2 && state5 && status2)" class="alarm-text" | |||
| [ngClass]="{'alarm-text-on': (state2 && state5 && status2) }">FENCE ALARM</div> | |||
| </div> | |||
| <div class="state t4" id="State4"> | |||
| <div> | |||
| <div class="state t4" id="State4" fxLayout="row" > | |||
| <img [src]="getImageSource()" style="width: 30px; height: 30px"> | |||
| <a href="/overview/camera-stream" target="_blank"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/camera.png"> | |||
| </a> | |||
| </div> | |||
| <ng-container [ngTemplateOutlet]="camera"></ng-container> | |||
| </div> | |||
| <div class="state t5 tooltip" id="State5" > | |||
| <div class="state t5 tooltip" id="State5" fxLayout="row"> | |||
| <img [src]="getImageSource()" style="width: 30px; height: 30px"> | |||
| <a href="/overview/camera-stream" target="_blank"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/camera.png"> | |||
| </a> | |||
| <ng-container [ngTemplateOutlet]="camera"></ng-container> | |||
| </div> | |||
| <div class="state t6 tooltip" id="State6"> | |||
| <div class="state t6 tooltip" id="State6" fxLayout="row"> | |||
| <img [src]="getImageSource()" style="width: 30px; height: 30px"> | |||
| <a href="/overview/camera-stream" target="_blank"> | |||
| <img style="width: 30px; height: 30px;" src="assets/images/camera.png"> | |||
| </a> | |||
| <ng-container [ngTemplateOutlet]="camera"></ng-container> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -53,3 +42,8 @@ | |||
| <button [disabled]="!isConnected" mat-flat-button color="{{switchArm ? 'accent' : 'primary'}}" (click)="toggleState1()">{{ switchArm ? 'DISARM' : 'ARM'}}</button> | |||
| </div> | |||
| </div> | |||
| <ng-template #camera> | |||
| <div (click)="openDialog()"> | |||
| <img style="width: 30px; height: 30px; cursor: pointer" src="assets/images/camera.png"> | |||
| </div> | |||
| </ng-template> | |||
| @@ -2,6 +2,9 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; | |||
| import {Subscription} from "rxjs"; | |||
| import {SocketService} from "../../../shared/services/socket.service"; | |||
| import {ToastrService} from "ngx-toastr"; | |||
| import {CameraDialogComponent} from "../../../shared/component/camera-dialog/camera-dialog.component"; | |||
| import {MatDialog} from "@angular/material/dialog"; | |||
| import { ConfirmDialogService } from '../../../shared/services/confirm-dialog.service'; | |||
| @Component({ | |||
| selector: 'app-security-system-details', | |||
| @@ -11,7 +14,9 @@ import {ToastrService} from "ngx-toastr"; | |||
| export class SecuritySystemDetailsComponent implements OnInit, OnDestroy { | |||
| isConnected = false; | |||
| state1 = false; | |||
| status1 = false; | |||
| state2 = false; | |||
| status2 = false; | |||
| state3 = ''; | |||
| state4 = ''; | |||
| state5 = false; | |||
| @@ -26,7 +31,9 @@ export class SecuritySystemDetailsComponent implements OnInit, OnDestroy { | |||
| constructor( | |||
| private socketService$: SocketService, | |||
| private toastr: ToastrService | |||
| private toastr: ToastrService, | |||
| private dialog: MatDialog, | |||
| private confirm$: ConfirmDialogService | |||
| ) {} | |||
| ngOnInit() { | |||
| @@ -74,7 +81,9 @@ export class SecuritySystemDetailsComponent implements OnInit, OnDestroy { | |||
| onMessage(message: any) { | |||
| if (message.id == '0' && message.type === 'get') { | |||
| this.state1 = message.state1 === '0'; // 1 OFF // alarm 12h | |||
| this.status1 = message.status1 === '1'; // 0 not, 1 ready, 2 error, 3 bypass | |||
| this.state2 = message.state2 === '0'; // 1 OFF // alarm 1h | |||
| this.status2 = message.status2 === '1'; // 0 not, 1 ready, 2 error, 3 bypass | |||
| this.state3 = message.state3 === '1' ? 'ON' : 'OFF'; | |||
| this.state4 = message.state4 === '1' ? 'ON' : 'OFF'; | |||
| this.state5 = message.state5 === '1'; // alarm 9h && 6h // 1 ON, 0 OFF | |||
| @@ -84,9 +93,23 @@ export class SecuritySystemDetailsComponent implements OnInit, OnDestroy { | |||
| this.switchWarning = message.state6 === '1';// alarm 9h && 6h // 1 ON, 0 OFF | |||
| this.isReady = message.ready === '1'; | |||
| if (message.ready === '0' && this.state5) { // not ready and ON arm | |||
| this.toastr.warning('System not ready', 'Warning', {timeOut: 5000}); | |||
| if ((message.status1 === '0' || message.status2 === '0') && this.state5) { // not ready and ON arm | |||
| const data = []; | |||
| if (message.status1 === '0'){ | |||
| data.push({key: 'status1', value: false}) | |||
| } | |||
| if (message.status2 === '0'){ | |||
| data.push({key: 'status2', value: false}) | |||
| } | |||
| this.confirm$.openDialog(data); | |||
| // this.toastr.warning('System not ready', 'Warning', {timeOut: 5000}); | |||
| } | |||
| } | |||
| } | |||
| openDialog(): void { | |||
| this.dialog.open(CameraDialogComponent, { | |||
| width: '80vw', | |||
| data: '', | |||
| }); | |||
| } | |||
| } | |||
| @@ -1,29 +1,11 @@ | |||
| <h2 mat-dialog-title style="border-bottom: solid 1px #eeeeee">CONFIRM TO IGNORE THE WARNING</h2> | |||
| <mat-dialog-content> | |||
| <section class="example-section"> | |||
| <span class="example-list-section"> | |||
| <mat-checkbox class="example-margin" | |||
| color="primary" | |||
| [checked]="allComplete" | |||
| [indeterminate]="someComplete()" | |||
| (change)="setAll($event.checked)"> | |||
| {{data.name}} | |||
| </mat-checkbox> | |||
| </span> | |||
| <span class="example-list-section"> | |||
| <ul> | |||
| <li *ngFor="let item of data.gateStatus"> | |||
| <mat-checkbox [(ngModel)]="item.ignore" | |||
| color="primary" | |||
| (ngModelChange)="updateAllComplete()"> | |||
| {{item.name}} | |||
| <h5 mat-dialog-title >CONFIRM TO IGNORE THE WARNING</h5> | |||
| <mat-dialog-content style="padding-bottom: 4px"> | |||
| <div *ngFor="let item of data"> | |||
| <mat-checkbox [(ngModel)]="item.value" (ngModelChange)="submitChange(item)" name="sensor"> | |||
| {{ (item.key == 'status1' ? 'Fire' : 'ff')}} | |||
| </mat-checkbox> | |||
| </li> | |||
| </ul> | |||
| </span> | |||
| </section> | |||
| </div> | |||
| </mat-dialog-content> | |||
| <mat-dialog-actions align="end"> | |||
| <button mat-button mat-dialog-close>Cancel</button> | |||
| <button mat-button mat-dialog-close style="background: #ff7723; color: #ffffff">Yes</button> | |||
| <button mat-button mat-dialog-close cdkFocusInitial>Close</button> | |||
| </mat-dialog-actions> | |||
| @@ -1,4 +1,10 @@ | |||
| ul { | |||
| list-style-type: none; | |||
| margin-top: 4px; | |||
| .mat-mdc-dialog-title { | |||
| border-bottom: solid 1px #eeeeee; | |||
| font-size: 14px; | |||
| color: #FFFFFF; | |||
| background: orange; | |||
| } | |||
| ::ng-deep.mdc-checkbox .mdc-checkbox__native-control:enabled:checked~.mdc-checkbox__background{ | |||
| background: orange !important; | |||
| border: orange !important; | |||
| } | |||
| @@ -8,51 +8,18 @@ import { MatDialogRef } from '@angular/material/dialog'; | |||
| }) | |||
| export class ConfirmDialogComponent { | |||
| constructor(public dialogRef: MatDialogRef<ConfirmDialogComponent>) {} | |||
| data = { | |||
| name: 'All', | |||
| ignore: false, | |||
| gateStatus: [ | |||
| data = [ | |||
| { | |||
| name: 'GATE A', | |||
| position: { latitude: 123.456, longitude: 456.789 }, | |||
| ignore: false, | |||
| key: 'status1', | |||
| value: false, | |||
| }, | |||
| { | |||
| name: 'GATE B', | |||
| position: { latitude: 111.222, longitude: 333.444 }, | |||
| ignore: false, | |||
| }, | |||
| { | |||
| name: 'GATE C', | |||
| position: { latitude: 222.333, longitude: 444.555 }, | |||
| ignore: false, | |||
| }, | |||
| ], | |||
| }; | |||
| allComplete: boolean = false; | |||
| updateAllComplete() { | |||
| this.allComplete = | |||
| this.data.gateStatus != null && | |||
| this.data.gateStatus.every((t) => t.ignore); | |||
| } | |||
| someComplete(): boolean { | |||
| if (this.data.gateStatus == null) { | |||
| return false; | |||
| } | |||
| return ( | |||
| this.data.gateStatus.filter((t) => t.ignore).length > 0 && | |||
| !this.allComplete | |||
| ); | |||
| } | |||
| setAll(completed: boolean) { | |||
| this.allComplete = completed; | |||
| if (this.data.gateStatus == null) { | |||
| return; | |||
| } | |||
| this.data.gateStatus.forEach((t) => (t.ignore = completed)); | |||
| { | |||
| name: 'status2', | |||
| value: false, | |||
| }, | |||
| ]; | |||
| submitChange(item: any): void{ | |||
| console.log(item); | |||
| // call socket here | |||
| } | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| import { ElementRef, Injectable } from '@angular/core'; | |||
| import { Injectable } from '@angular/core'; | |||
| @Injectable({ | |||
| providedIn: 'root', | |||
| @@ -7,47 +7,52 @@ export class AlarmSoundService { | |||
| private alertInterval: any; | |||
| private alertDuration: number = 10000; | |||
| private audio = new Audio(); | |||
| isPlay = false; | |||
| private isPlaying: boolean = false; | |||
| constructor() { | |||
| this.audio.src = 'assets/sound/alarm_5m.mp3'; | |||
| this.audio.load(); | |||
| this.audio.onended = () => { | |||
| // Khi phát hết âm thanh, đặt biến isPlaying về false | |||
| this.isPlaying = false; | |||
| }; | |||
| } | |||
| playSound(): void { | |||
| this.isPlay = true; | |||
| this.audio.play().catch((error) => { | |||
| console.error('Error playing audio:', error); | |||
| }); | |||
| if (!this.isPlaying) { | |||
| this.audio.play().then(() => { | |||
| this.isPlaying = true; | |||
| this.alertInterval = setInterval(() => { | |||
| this.stopAlarm(); | |||
| }, this.alertDuration); | |||
| }).catch((error) => { | |||
| console.error('Error playing audio:', error); | |||
| }); | |||
| } | |||
| } | |||
| stopSound(): void { | |||
| if (this.audio) { | |||
| this.audio.pause(); | |||
| this.audio.currentTime = 0; | |||
| this.isPlaying = false; | |||
| } | |||
| } | |||
| startAlarm( | |||
| state5: boolean, | |||
| isReady: boolean, | |||
| state1: boolean, | |||
| state2: boolean, | |||
| ): void { | |||
| if (state5 && isReady && (state1 || state2) && !this.isPlay) { | |||
| startAlarm( isTurnOn: boolean, isReady: boolean, fireArm: boolean, fenceArm: boolean): void { | |||
| if (isTurnOn && isReady && (fireArm || fenceArm)) { | |||
| //this.alertDuration = // setting time | |||
| this.playSound(); | |||
| this.alertInterval = setInterval(() => { | |||
| this.stopAlarm(); | |||
| }, this.alertDuration); | |||
| }else{ | |||
| this.stopAlarm(); | |||
| } | |||
| } | |||
| stopAlarm(): void { | |||
| this.stopSound(); | |||
| clearInterval(this.alertInterval); | |||
| this.isPlay = false; | |||
| if (this.alertInterval){ | |||
| clearInterval(this.alertInterval); | |||
| } | |||
| } | |||
| simulateClick(element: HTMLElement) { | |||
| element.click(); | |||
| } | |||
| } | |||
| @@ -11,7 +11,7 @@ export class ConfirmDialogService { | |||
| constructor(private dialog: MatDialog) {} | |||
| openDialog(): void { | |||
| openDialog(data: any[]): void { | |||
| if (!this.isDialogOpen) { | |||
| this.isDialogOpen = true; | |||
| const dialogRef = this.dialog.open(ConfirmDialogComponent); | |||