integrasi dashboard energy monitoring
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<div class="media d-flex">
|
||||
<div class="media-body text-left">
|
||||
<h5>Electricity</h5>
|
||||
<h3 class="danger">278 Kwh</h3>
|
||||
<h3 class="danger">{{ topCard?.kwh_consumption }} Kwh</h3>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<i class="icon-energy danger font-large-2 float-right"></i>
|
||||
@@ -29,7 +29,7 @@
|
||||
<div class="media d-flex">
|
||||
<div class="media-body text-left">
|
||||
<h5>Water</h5>
|
||||
<h3 class="success">156</h3>
|
||||
<h3 class="success">{{ topCard?.water_consumption }}</h3>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<i
|
||||
@@ -48,7 +48,7 @@
|
||||
<div class="media d-flex">
|
||||
<div class="media-body text-left">
|
||||
<h5>Device</h5>
|
||||
<h3 class="warning">{{ device }}</h3>
|
||||
<h3 class="warning">{{ topCard?.total_device }}</h3>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<i class="icon-bulb warning font-large-2 float-right"></i>
|
||||
@@ -65,7 +65,7 @@
|
||||
<div class="media d-flex">
|
||||
<div class="media-body text-left">
|
||||
<h5>Room</h5>
|
||||
<h3 class="info">{{ room }}</h3>
|
||||
<h3 class="info">{{ topCard?.total_room }}</h3>
|
||||
</div>
|
||||
<div class="align-self-center">
|
||||
<i class="icon-map info font-large-2 float-right"></i>
|
||||
@@ -82,10 +82,7 @@
|
||||
<section id="chartjs-bar-charts">
|
||||
<div class="row">
|
||||
<div class="col-12" *blockUI="'barCharts'; message: 'Loading'">
|
||||
<m-card
|
||||
[options]="options"
|
||||
(reloadFunction)="reloadBarCharts($event)"
|
||||
>
|
||||
<m-card [options]="options">
|
||||
<ng-container mCardHeaderTitle> Appointment </ng-container>
|
||||
<ng-container mCardBody>
|
||||
<div class="z" style="display: block">
|
||||
@@ -113,12 +110,17 @@
|
||||
<div class="col-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title text-center">Air Quality</h4>
|
||||
<h4 class="card-title text-center">Summary Cost</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-block">
|
||||
<div class="text-center" style="height: 150px !important">
|
||||
<h2 class="font-large-3 text-bold-400">Rp 1.253.634.234</h2>
|
||||
<h2 class="font-large-3 text-bold-400">
|
||||
{{
|
||||
summaryCost?.summary_cost
|
||||
| currency : "Rp " : "symbol" : "1.0-0"
|
||||
}}
|
||||
</h2>
|
||||
<p class="blue-grey lighten-2 mb-0 mt-2">
|
||||
Based on the estimated costs you have
|
||||
</p>
|
||||
@@ -158,7 +160,7 @@
|
||||
class="display-4 blue-grey darken-1"
|
||||
style="font-size: 2em"
|
||||
>
|
||||
76 %
|
||||
{{ airQuality }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
@@ -189,81 +191,27 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="col-6" *ngFor="let item of deviceCategory?.usesd">
|
||||
<div class="card overflow-hidden">
|
||||
<div class="card-content">
|
||||
<div class="card-body cleartfix">
|
||||
<div class="media align-items-stretch mb-2">
|
||||
<div class="align-self-center">
|
||||
<i class="icon-energy background-round info font-large-2 mr-2"></i>
|
||||
<i
|
||||
class="icon-bulb background-round info font-large-2 mr-2"
|
||||
></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<p>
|
||||
General Lighting
|
||||
<span class="float-right text-bold-600">89%</span>
|
||||
{{ item.category_device }}
|
||||
<span class="float-right text-bold-600"
|
||||
>{{ item.value }}%</span
|
||||
>
|
||||
</p>
|
||||
<ngb-progressbar
|
||||
height="7px"
|
||||
type="danger"
|
||||
[value]="90"
|
||||
></ngb-progressbar>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="media align-items-stretch mt-2">
|
||||
<div class="align-self-center">
|
||||
<i class="icon-energy background-round info font-large-2 mr-2"></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<p>
|
||||
Accent Lighting
|
||||
<span class="float-right text-bold-600">89%</span>
|
||||
</p>
|
||||
<ngb-progressbar
|
||||
height="7px"
|
||||
type="danger"
|
||||
[value]="90"
|
||||
></ngb-progressbar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="card overflow-hidden">
|
||||
<div class="card-content">
|
||||
<div class="card-body cleartfix">
|
||||
<div class="media align-items-stretch mb-2">
|
||||
<div class="align-self-center">
|
||||
<i class="icon-layers background-round info font-large-2 mr-2"></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<p>
|
||||
Floor Lighting
|
||||
<span class="float-right text-bold-600">89%</span>
|
||||
</p>
|
||||
<ngb-progressbar
|
||||
height="7px"
|
||||
type="danger"
|
||||
[value]="90"
|
||||
></ngb-progressbar>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="media align-items-stretch mt-2">
|
||||
<div class="align-self-center">
|
||||
<i class="icon-bulb background-round info font-large-2 mr-2"></i>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<p>
|
||||
Last Lighting
|
||||
<span class="float-right text-bold-600">89%</span>
|
||||
</p>
|
||||
<ngb-progressbar
|
||||
height="7px"
|
||||
type="danger"
|
||||
[value]="90"
|
||||
[value]="item.value"
|
||||
></ngb-progressbar>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { BuildingService } from "../../service/monitoring-api.service";
|
||||
import * as chartsData from "./data";
|
||||
import * as Chartist from 'chartist';
|
||||
import { Component, ElementRef, ViewChild } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { ChartOptions, ChartType, ChartDataset } from "chart.js";
|
||||
import { EnergyMonitoringService } from "../../service/energy-monitoring.service";
|
||||
import { CurrencyPipe } from "@angular/common";
|
||||
|
||||
@Component({
|
||||
selector: "app-detail",
|
||||
templateUrl: "./detail.component.html",
|
||||
styleUrls: ["./detail.component.css"],
|
||||
providers: [CurrencyPipe],
|
||||
})
|
||||
export class DetailComponent {
|
||||
data: any;
|
||||
@@ -16,21 +16,18 @@ export class DetailComponent {
|
||||
breadcrumb: any;
|
||||
donutChart1: any;
|
||||
donutChart2: any;
|
||||
sparklineArea: any
|
||||
|
||||
dataChart = {
|
||||
"donut": {
|
||||
"series": [20, 20, 20, 20, 20],
|
||||
"labels": []
|
||||
}
|
||||
}
|
||||
donut: {
|
||||
series: [20, 20, 20, 20, 20],
|
||||
},
|
||||
};
|
||||
|
||||
dataChart2 = {
|
||||
"donut": {
|
||||
"series": [50, 50],
|
||||
"labels": []
|
||||
}
|
||||
}
|
||||
donut: {
|
||||
series: [50, 50],
|
||||
},
|
||||
};
|
||||
|
||||
// chart bar
|
||||
public barChartOptions: ChartOptions = {
|
||||
@@ -41,13 +38,14 @@ export class DetailComponent {
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
beginAtZero: true
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
public barChartLabels: string[] = [];
|
||||
public barChartType: ChartType = "bar";
|
||||
public barChartLegend = true;
|
||||
|
||||
public barChartData: ChartDataset[] = [
|
||||
{
|
||||
data: [],
|
||||
@@ -74,9 +72,9 @@ export class DetailComponent {
|
||||
categoryPercentage: 0.5,
|
||||
},
|
||||
{
|
||||
type: "line", // override the default type
|
||||
type: "line",
|
||||
data: [],
|
||||
label: "Appointment",
|
||||
label: "Weekly Kwh Average",
|
||||
backgroundColor: "rgba(0,255,255,0)",
|
||||
borderColor: "#1e9ff2",
|
||||
fill: false,
|
||||
@@ -85,6 +83,23 @@ export class DetailComponent {
|
||||
pointBorderWidth: 2,
|
||||
pointHoverBorderWidth: 2,
|
||||
pointRadius: 4,
|
||||
tension: 0.3,
|
||||
spanGaps: true
|
||||
},
|
||||
{
|
||||
type: "line",
|
||||
data: [],
|
||||
label: "Weekly Water Average",
|
||||
backgroundColor: "rgba(0,255,255,0)",
|
||||
borderColor: "#1e9ff2",
|
||||
fill: false,
|
||||
pointBorderColor: "#1e9ff2",
|
||||
pointBackgroundColor: "#FFF",
|
||||
pointBorderWidth: 2,
|
||||
pointHoverBorderWidth: 2,
|
||||
pointRadius: 4,
|
||||
tension: 0.3,
|
||||
spanGaps: true
|
||||
},
|
||||
];
|
||||
//..........................
|
||||
@@ -94,34 +109,52 @@ export class DetailComponent {
|
||||
water: any;
|
||||
device: any;
|
||||
room: any;
|
||||
topCard: any;
|
||||
summaryCost: any;
|
||||
airQuality: any;
|
||||
temperature: any;
|
||||
deviceCategory: any;
|
||||
chartKwhWater: any;
|
||||
//......
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private monitoringApiService: BuildingService
|
||||
private energyMonitoringService: EnergyMonitoringService,
|
||||
private currencyPipe: CurrencyPipe
|
||||
) {}
|
||||
|
||||
get formattedSummaryCost(): string {
|
||||
return this.currencyPipe.transform(
|
||||
this.summaryCost.summary_cost,
|
||||
"IDR",
|
||||
"symbol",
|
||||
"1.0-0"
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.data.subscribe((data) => {
|
||||
this.mode = data.mode;
|
||||
});
|
||||
this.breadcrumbLink();
|
||||
this.generateChartLabelsAndData();
|
||||
|
||||
this.route.params.subscribe((params) => {
|
||||
const buildingId = params["id"];
|
||||
if (buildingId) {
|
||||
this.fetchData(buildingId);
|
||||
this.devicePerBuilding(buildingId);
|
||||
this.dataEnergyMonitoringTopCard(buildingId);
|
||||
this.dataEnergyMonitoringSummary(buildingId);
|
||||
this.dataEnergyMonitoringSAir(buildingId);
|
||||
this.dataEnergyMonitoringSTemperature(buildingId);
|
||||
this.dataEnergyDeviceCategory(buildingId);
|
||||
this.dataEnergyChartKwhWater(buildingId);
|
||||
}
|
||||
});
|
||||
|
||||
this.donutChart1 = {
|
||||
type: 'Pie',
|
||||
type: "Pie",
|
||||
data: this.dataChart.donut,
|
||||
options: {
|
||||
fullwidth: true,
|
||||
height: '300px',
|
||||
height: "300px",
|
||||
donut: true,
|
||||
donutWidth: 70,
|
||||
startAngle: 270,
|
||||
@@ -129,37 +162,6 @@ export class DetailComponent {
|
||||
showLabel: true,
|
||||
},
|
||||
};
|
||||
|
||||
this.donutChart2 = {
|
||||
type: 'Pie',
|
||||
data: this.dataChart2.donut,
|
||||
options: {
|
||||
chartPadding: 0,
|
||||
fullwidth: true,
|
||||
height: '150px',
|
||||
donut: true,
|
||||
showLabel: true,
|
||||
startAngle: 0,
|
||||
labelInterpolationFnc: function (value) {
|
||||
const total = 82;
|
||||
return total + 'C';
|
||||
}
|
||||
},
|
||||
events: {
|
||||
draw(data: any): void {
|
||||
if (data.type === 'label') {
|
||||
if (data.index === 0) {
|
||||
data.element.attr({
|
||||
dx: data.element.root().width() / 2,
|
||||
dy: data.element.root().height() / 2
|
||||
});
|
||||
} else {
|
||||
data.element.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
breadcrumbLink() {
|
||||
@@ -201,41 +203,140 @@ export class DetailComponent {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
generateChartLabelsAndData() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth();
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
const date = new Date(year, month, day);
|
||||
this.barChartLabels.push(date.toISOString().split("T")[0]); // Format YYYY-MM-DD
|
||||
|
||||
// Example data generation, replace with your actual data logic
|
||||
this.barChartData[0].data?.push(Math.floor(Math.random() * 100));
|
||||
this.barChartData[1].data?.push(Math.floor(Math.random() * 100));
|
||||
this.barChartData[2].data?.push(Math.floor(Math.random() * 100));
|
||||
}
|
||||
}
|
||||
|
||||
//integrasi
|
||||
fetchData(buildingId) {
|
||||
this.monitoringApiService
|
||||
.getRoomByBuildingId(buildingId)
|
||||
dataEnergyMonitoringTopCard(buildingId) {
|
||||
this.energyMonitoringService
|
||||
.getDashboardTopCard(buildingId)
|
||||
.subscribe((res) => {
|
||||
this.room = res.resp.map((entry) => entry.roomEntity).length;
|
||||
this.topCard = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
devicePerBuilding(buildingId) {
|
||||
this.monitoringApiService
|
||||
.listDevicePerBuilding(buildingId)
|
||||
dataEnergyMonitoringSummary(buildingId) {
|
||||
this.energyMonitoringService
|
||||
.getDashboardSummary(buildingId)
|
||||
.subscribe((res) => {
|
||||
this.device = res.resp.reduce(
|
||||
(sum, item) => sum + item.total_device,
|
||||
0
|
||||
);
|
||||
this.summaryCost = res.data;
|
||||
});
|
||||
}
|
||||
dataEnergyMonitoringSAir(buildingId) {
|
||||
this.energyMonitoringService
|
||||
.getDashboardAirQuality(buildingId)
|
||||
.subscribe((res) => {
|
||||
this.airQuality = res.data;
|
||||
});
|
||||
}
|
||||
dataEnergyMonitoringSTemperature(buildingId) {
|
||||
this.energyMonitoringService
|
||||
.getDashboardTemperature(buildingId)
|
||||
.subscribe((res) => {
|
||||
this.temperature = res.data;
|
||||
this.donutChart2 = {
|
||||
type: "Pie",
|
||||
data: this.dataChart2.donut,
|
||||
options: {
|
||||
chartPadding: 0,
|
||||
fullwidth: true,
|
||||
height: "150px",
|
||||
donut: true,
|
||||
showLabel: true,
|
||||
startAngle: 0,
|
||||
labelInterpolationFnc: (value) => {
|
||||
const total = this.temperature;
|
||||
return total + "°C";
|
||||
},
|
||||
},
|
||||
events: {
|
||||
draw: (data: any) => {
|
||||
if (data.type === "label") {
|
||||
if (data.index === 0) {
|
||||
data.element.attr({
|
||||
dx: data.element.root().width() / 2,
|
||||
dy: data.element.root().height() / 2,
|
||||
});
|
||||
} else {
|
||||
data.element.remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
dataEnergyDeviceCategory(buildingId) {
|
||||
this.energyMonitoringService
|
||||
.getDashboardDeviceCategory(buildingId)
|
||||
.subscribe((res) => {
|
||||
this.deviceCategory = res.data[0];
|
||||
});
|
||||
}
|
||||
dataEnergyChartKwhWater(buildingId) {
|
||||
this.energyMonitoringService
|
||||
.getDashboardChartKwhWater(buildingId)
|
||||
.subscribe((res) => {
|
||||
this.chartKwhWater = res.data;
|
||||
this.barChartData[0].data = [];
|
||||
this.barChartData[1].data = [];
|
||||
this.chartKwhWater.forEach((entry) => {
|
||||
this.barChartData[0].data.push(entry.kwh);
|
||||
this.barChartData[1].data.push(entry.water);
|
||||
this.barChartLabels.push(entry.day);
|
||||
});
|
||||
|
||||
const weeklyKwh = this.aggregateKwhWeekly(this.chartKwhWater);
|
||||
const weeklyWater = this.aggregateWaterWeekly(this.chartKwhWater);
|
||||
|
||||
// Populate Appointment data at every multiple of 7
|
||||
let weekIndex = 0;
|
||||
for (let i = 0; i < this.barChartData[0].data.length; i++) {
|
||||
if (i % 7 === 6 && weekIndex < weeklyKwh.length) {
|
||||
this.barChartData[2].data[i] = weeklyKwh[weekIndex++];
|
||||
} else {
|
||||
this.barChartData[2].data[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
let weekIndexWater = 0;
|
||||
for (let i = 0; i < this.barChartData[0].data.length; i++) {
|
||||
if (i % 7 === 6 && weekIndexWater < weeklyWater.length) {
|
||||
this.barChartData[3].data[i] = weeklyWater[weekIndexWater++];
|
||||
} else {
|
||||
this.barChartData[3].data[i] = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
aggregateKwhWeekly(data: any[]): number[] {
|
||||
const weeks = [];
|
||||
let weekSum = 0;
|
||||
let dayCount = 0;
|
||||
|
||||
data.forEach((entry, index) => {
|
||||
weekSum += entry.kwh;
|
||||
dayCount++;
|
||||
if (dayCount === 7 || index === data.length - 1) {
|
||||
weeks.push(weekSum);
|
||||
weekSum = 0;
|
||||
dayCount = 0;
|
||||
}
|
||||
});
|
||||
|
||||
return weeks;
|
||||
}
|
||||
aggregateWaterWeekly(data: any[]): number[] {
|
||||
const weeks = [];
|
||||
let weekSum = 0;
|
||||
let dayCount = 0;
|
||||
|
||||
data.forEach((entry, index) => {
|
||||
weekSum += entry.water;
|
||||
dayCount++;
|
||||
if (dayCount === 7 || index === data.length - 1) {
|
||||
weeks.push(weekSum);
|
||||
weekSum = 0;
|
||||
dayCount = 0;
|
||||
}
|
||||
});
|
||||
|
||||
return weeks;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user