integrasi cost management

This commit is contained in:
Fuzi_fauzia 2024-06-11 20:44:05 +07:00
parent 38c936b389
commit ad91c844d6
16 changed files with 1758 additions and 930 deletions

View File

@ -28,17 +28,17 @@
<div class="navbar-container content" [hidden]="isMobile && !showNavbar"> <div class="navbar-container content" [hidden]="isMobile && !showNavbar">
<div class="collapse navbar-collapse" id="navbar-mobile"> <div class="collapse navbar-collapse" id="navbar-mobile">
<ul class="nav navbar-nav mr-auto float-left"> <ul class="nav navbar-nav mr-auto float-left">
<li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-link-expand" <!-- <li class="nav-item d-none d-md-block"><a [routerLink]="" class="nav-link nav-link-expand"
(click)="toggleFullScreen()" *ngIf="maximize === 'on'"><i class="ficon feather ft-maximize"></i></a></li> (click)="toggleFullScreen()" *ngIf="maximize === 'on'"><i class="ficon feather ft-maximize"></i></a></li>
<li class="nav-item nav-search"><a [routerLink]="" class="nav-link nav-link-search" (click)="clickSearch()" <li class="nav-item nav-search"><a [routerLink]="" class="nav-link nav-link-search" (click)="clickSearch()"
*ngIf="search === 'on'"><i class="ficon feather ft-search"></i></a> *ngIf="search === 'on'"><i class="ficon feather ft-search"></i></a>
<div class="search-input" [ngClass]="{'open': isHeaderSearchOpen}"> <div class="search-input" [ngClass]="{'open': isHeaderSearchOpen}">
<input class="input" type="text" placeholder="Explore Modern..."> <input class="input" type="text" placeholder="Explore Modern...">
</div> </div>
</li> </li> -->
</ul> </ul>
<ul class="nav navbar-nav float-right"> <ul class="nav navbar-nav float-right">
<li class="dropdown-language nav-item" ngbDropdown *ngIf="internationalization === 'on'"> <!-- <li class="dropdown-language nav-item" ngbDropdown *ngIf="internationalization === 'on'">
<a [routerLink]="" class="dropdown-toggle nav-link" ngbDropdownToggle id="dropdown-flag"> <a [routerLink]="" class="dropdown-toggle nav-link" ngbDropdownToggle id="dropdown-flag">
<i class="flag-icon flag-icon-gb"></i><span class="selected-language"></span> <i class="flag-icon flag-icon-gb"></i><span class="selected-language"></span>
</a> </a>
@ -56,7 +56,7 @@
<i class="flag-icon flag-icon-de"></i> German <i class="flag-icon flag-icon-de"></i> German
</a> </a>
</div> </div>
</li> </li> -->
<li class="dropdown-notification nav-item dropdown" ngbDropdown *ngIf="notification === 'on'"> <li class="dropdown-notification nav-item dropdown" ngbDropdown *ngIf="notification === 'on'">
<a class="nav-link nav-link-label" ngbDropdownToggle> <a class="nav-link nav-link-label" ngbDropdownToggle>
<i class="ficon feather ft-bell"></i> <i class="ficon feather ft-bell"></i>
@ -133,7 +133,7 @@
href="javascript:void(0)">Read all notifications</a></li> href="javascript:void(0)">Read all notifications</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown-notification nav-item" ngbDropdown> <!-- <li class="dropdown-notification nav-item" ngbDropdown>
<a class="nav-link nav-link-label" ngbDropdownToggle *ngIf="email === 'on'"><i <a class="nav-link nav-link-label" ngbDropdownToggle *ngIf="email === 'on'"><i
class="ficon feather ft-mail"></i></a> class="ficon feather ft-mail"></i></a>
<ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu> <ul class="dropdown-menu-media dropdown-menu-right" ngbDropdownMenu>
@ -194,7 +194,7 @@
<li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center" <li class="dropdown-menu-footer"><a class="dropdown-item text-muted text-center"
href="javascript:void(0)">Read all messages</a></li> href="javascript:void(0)">Read all messages</a></li>
</ul> </ul>
</li> </li> -->
<li class="dropdown-user nav-item" ngbDropdown> <li class="dropdown-user nav-item" ngbDropdown>
<a class="nav-link dropdown-user-link" ngbDropdownToggle> <a class="nav-link dropdown-user-link" ngbDropdownToggle>

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +1,253 @@
:host ::ng-deep .donut-chart1 .ct-series-a .ct-slice-donut {
stroke: green;
stroke-width: 50px !important; :host ::ng-deep .donut-chart2 .ct-series-a .ct-slice-donut {
} stroke: #8a8a8a;
stroke-width: 20px !important;
:host ::ng-deep .donut-chart1 .ct-series-b .ct-slice-donut { }
stroke: yellow;
stroke-width: 50px !important; :host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut {
} stroke: #bef264;
stroke-width: 20px !important;
:host ::ng-deep .donut-chart1 .ct-series-c .ct-slice-donut { }
stroke: orange;
stroke-width: 50px !important; :host ::ng-deep .donut-chart2 {
} -webkit-filter: drop-shadow(0px 10px 11px rgba(187, 187, 187)) !important;
filter: drop-shadow(0px 10px 11px rgba(187, 187, 187));
:host ::ng-deep .donut-chart1 .ct-series-d .ct-slice-donut { }
stroke: red;
stroke-width: 50px !important; :host ::ng-deep .donut-chart2 .ct-label {
} fill: #111010;
color: rgba(0, 0, 0, 0.4);
:host ::ng-deep .donut-chart1 .ct-series-e .ct-slice-donut { font-size: 1.75rem;
stroke: darkred; line-height: 1;
stroke-width: 50px !important; }
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-point {
:host ::ng-deep .donut-chart2 .ct-series-a .ct-slice-donut { stroke: #bef264;
stroke: #8a8a8a; }
stroke-width: 20px !important;
} :host ::ng-deep .sp-line-total-cost .ct-series-a .ct-line {
stroke: #bef264;
:host ::ng-deep .donut-chart2 .ct-series-b .ct-slice-donut { }
stroke: #bef264;
stroke-width: 20px !important; :host ::ng-deep .sp-line-total-cost .ct-series-a .ct-area {
} fill: #bef264;
fill-opacity: 1;
:host ::ng-deep .donut-chart2 { }
-webkit-filter: drop-shadow(0px 10px 11px rgba(187, 187, 187)) !important;
filter: drop-shadow(0px 10px 11px rgba(187, 187, 187)); :host ::ng-deep .sp-line-total-cost .ct-point {
} stroke-width: 0px;
}
:host ::ng-deep .donut-chart2 .ct-label {
fill: #111010; .ct-chart-bar .ct-series .ct-bar {
color: rgba(0, 0, 0, 0.4); stroke-width: 20px !important; /* Atur lebar bar sesuai kebutuhan */
font-size: 1.75rem; }
line-height: 1;
} .ct-chart-bar .ct-label.ct-horizontal {
margin-left: -10px !important; /* Mengatur margin label horizontal */
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-point { margin-right: -10px !important;
stroke: #bef264; }
}
:host ::ng-deep .donut-chart3 .ct-series-a .ct-bar {
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-line { stroke: #cd560c;
stroke: #bef264; fill: none;
} stroke-width: 30px;
}
:host ::ng-deep .sp-line-total-cost .ct-series-a .ct-area {
fill: #bef264; :host ::ng-deep .donut-chart3 .ct-series-b .ct-bar {
fill-opacity: 1; stroke: #49cd0c;
} fill: none;
stroke-width: 30px;
:host ::ng-deep .sp-line-total-cost .ct-point { }
stroke-width: 0px;
} /* table */
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header .datatable-header-cell .datatable-header-cell-label {
font-family: inherit;
font-size: medium;
font-weight: bold;
color: #6B6F82;
}
:host ::ng-deep .ngx-datatable .datatable-row-center, .ngx-datatable .datatable-row-group, .ngx-datatable .datatable-row-right {
position: relative;
height: 50px !important;
}
:host ::ng-deep .datatable-icon-right:before {
font-family: 'icofont';
font-style: normal;
}
:host ::ng-deep .datatable-icon-skip:before {
font-family: 'icofont';
font-style: normal;
}
:host ::ng-deep .datatable-icon-left:before {
font-family: 'icofont';
font-style: normal;
}
:host ::ng-deep .datatable-icon-left:before {
content: "\2039";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-prev:before {
content: "\00AB";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-right:before {
content: "\203A";
font-size: x-large;
}
:host ::ng-deep .datatable-icon-skip:before {
content: "\00BB";
font-size: x-large;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-prev {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-skip {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-prev {
font-size: 16px;
line-height: 22px;
padding: 0px 09px;
background-color: #d4d2e7;
}
:host ::ng-deep .datatable-footer .datatable-pager ul li:not(.disabled).active a,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] ul[_ngcontent-c11] li[_ngcontent-c11]:not(.disabled):hover a[_ngcontent-c11] {
background-color: #d4d2e7;
font-weight: bold;
font-size: larger;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager a {
height: 32px;
min-width: 34px;
line-height: 22px;
padding: 0;
border-radius: 3px;
margin: 0 3px;
text-align: center;
vertical-align: top;
padding-top: 3px;
text-decoration: none;
vertical-align: bottom;
color: #7c8091;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 14px;
line-height: 9px;
padding: 0px 08px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-skip,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager .datatable-icon-prev,
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-right[_ngcontent-c11],
.ngx-datatable.bootstrap[_ngcontent-c11] .datatable-footer[_ngcontent-c11] .datatable-pager[_ngcontent-c11] .datatable-icon-prev[_ngcontent-c11] {
font-size: 0px;
line-height: 22px;
padding: 0px 09px;
background-color: #ffffff;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager ul li:not(.disabled):hover a {
background-color: #545454;
font-weight: bold;
color: white;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer .datatable-pager ul li:not(.disabled).active a,
.ngx-datatable.bootstrap .datatable-footer .datatable-pager ul li:not(.disabled):hover a {
background-color: #545454;
font-weight: bold;
color: white;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-footer {
background: #727e8e;
color: #ededed;
margin-top: -1px;
overflow: inherit;
}
:host ::ng-deep .ngx-datatable.bootstrap .datatable-header {
font-weight: bold;
height: unset !important;
overflow: inherit
}
:host ::ng-deep .ngx-datatable .datatable-footer .datatable-pager {
flex: 0 0 0%;
}
:host ::ng-deep .ngx-datatable .datatable-footer .datatable-pager .pager {
display: flex;
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
:host ::ng-deep .ngx-datatable .datatable-footer .selected-count .datatable-pager {
flex: 0 0 0%;
}
:host ::ng-deep .ngx-datatable {
display: -webkit-box;
}

View File

@ -9,7 +9,9 @@
<div class="col-lg-4 col-12"> <div class="col-lg-4 col-12">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h4 class="card-title text-center">Temperature and Humidity</h4> <h4 class="card-title text-center">
Comparison of Water and Electricity Costs
</h4>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="card-block"> <div class="card-block">
@ -30,35 +32,25 @@
<div class="col-lg-4 col-12"> <div class="col-lg-4 col-12">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h4 class="card-title text-center">Air Quality</h4> <h4 class="card-title text-center">
Comparison of Previous Month Costs
</h4>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="card-block"> <div class="card-block">
<div class="donut-chart1" style="height: 150px !important">
<x-chartist
*ngIf="donutChart1"
[data]="donutChart1.data"
[type]="donutChart1.type"
[options]="donutChart1.options"
[responsiveOptions]="donutChart1.responsiveOptions"
[events]="donutChart1.events"
></x-chartist>
</div>
<div <div
class="text-center" class="donut-chart3 text-center"
style=" style="height: 150px !important"
position: absolute;
top: 80%;
left: 50%;
transform: translate(-50%, -50%);
"
> >
<h3 <x-chartist
class="display-4 blue-grey darken-1" *ngIf="barChart"
style="font-size: 2em" [data]="barChart.data"
[type]="barChart.type"
[options]="barChart.options"
[responsiveOptions]="barChart.responsiveOptions"
[events]="barChart.events"
> >
76 % </x-chartist>
</h3>
</div> </div>
</div> </div>
</div> </div>
@ -67,7 +59,9 @@
<div class="col-lg-4 col-12"> <div class="col-lg-4 col-12">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h4 class="card-title text-center">Comparison of Actual Costs and Estimated Costs</h4> <h4 class="card-title text-center">
Comparison of Actual Costs and Estimated Costs
</h4>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="card-block"> <div class="card-block">
@ -75,30 +69,36 @@
<div class="flex-grow-1"> <div class="flex-grow-1">
<ngb-progressbar <ngb-progressbar
height="45px" height="45px"
type="danger" type="success"
[value]="89" [value]="dataCompAct?.est_cost"
[max]="dataCompAct?.real_cost"
></ngb-progressbar> ></ngb-progressbar>
</div> </div>
<div <div
class="ml-2 d-flex align-items-center" class="ml-2 d-flex align-items-center"
style="height: 20px" style="height: 20px"
> >
<span class="text-bold-600">1.234.242</span> <span class="text-bold-600">{{
dataCompAct?.est_cost
}}</span>
</div> </div>
</div> </div>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<div class="flex-grow-1"> <div class="flex-grow-1">
<ngb-progressbar <ngb-progressbar
height="45px" height="45px"
type="success" type="danger"
[value]="50" [value]="dataCompAct?.real_cost"
[max]="dataCompAct?.real_cost"
></ngb-progressbar> ></ngb-progressbar>
</div> </div>
<div <div
class="ml-2 d-flex align-items-center" class="ml-2 d-flex align-items-center"
style="height: 20px" style="height: 20px"
> >
<span class="text-bold-600">1.545.232</span> <span class="text-bold-600">{{
dataCompAct?.real_cost
}}</span>
</div> </div>
</div> </div>
</div> </div>
@ -107,6 +107,276 @@
</div> </div>
</div> </div>
</section> </section>
<section id="configuration">
<div class="row">
<div
class="col-12"
*blockUI="'zeroConfiguration'; message: 'Loading'"
>
<m-card>
<!-- <ng-container mCardHeaderTitle> Device Table </ng-container> -->
<ng-container mCardBody>
<div class="row mb-2">
<div class="col-3">
<div class="form-group">
<ng-select
[items]="dataBuildingList"
[searchable]="true"
bindLabel="name"
bindValue="id"
placeholder="Select Building"
[(ngModel)]="buildingSelected"
>
</ng-select>
</div>
</div>
<div class="col-3">
<div class="form-group">
<input
type="month"
class="form-control"
[(ngModel)]="dateSelected"
id="month12"
(focus)="focusElement('month12')"
/>
</div>
</div>
<div class="col-3">
<div class="form-group">
<ng-select
[items]="dataMasterCategori"
[searchable]="true"
bindLabel="name"
bindValue="id"
placeholder="Select Category"
[(ngModel)]="categorySelected"
>
</ng-select>
</div>
</div>
<div class="col-3">
<div class="d-flex">
<input
type="text"
class="form-control"
placeholder="Search..."
[(ngModel)]="searchTerm"
/>
<button
type="button"
class="btn btn-outline-success ml-2"
(click)="doFilter()"
>
<i class="la la-search"></i>
</button>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-4">
<div class="form-group">
<input
type="text"
class="form-control"
placeholder="Kwh"
[(ngModel)]="kwhTerm"
disabled
/>
</div>
</div>
<div class="col-4">
<div class="form-group">
<input
type="text"
class="form-control"
placeholder="Cost"
[(ngModel)]="costTerm"
disabled
/>
</div>
</div>
<div class="col-4">
<div class="d-flex justify-content-end">
<button
class="btn btn-secondary mr-2"
style="width: 100%"
(click)="syncData()"
>
<i
class="la la-spinner spinner"
*ngIf="spinnerActive"
></i>
<i class="la la-spinner" *ngIf="!spinnerActive"></i
>&nbsp;
<span>Syncing Data</span>
</button>
<button
class="btn btn-secondary"
style="width: 100%"
(click)="addFieldValue()"
>
<i class="feather ft-plus"></i
>&nbsp;
<span>Add Actual Cost</span>
</button>
</div>
</div>
</div>
<div class="card-dashboard">
<ngx-datatable
class="bootstrap table-bordered"
[limit]="5"
[rows]="data_cost"
[columnMode]="'force'"
[headerHeight]="50"
[footerHeight]="50"
[rowHeight]="50"
fxFlex="auto"
[scrollbarH]="true"
>
<ngx-datatable-column
name="#"
[flexGrow]="1"
[minWidth]="10"
>
<ng-template
ngx-datatable-cell-template
let-rowIndex="rowIndex"
>
{{ rowIndex + 1 }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="building"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span>Building</span>
</ng-template>
<ng-template
let-value="value"
ngx-datatable-cell-template
>
{{ value }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="categoryName"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span>Category</span>
</ng-template>
<ng-template
let-value="value"
ngx-datatable-cell-template
>
{{ value }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="estimationCost"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span>Estimation Cost</span>
</ng-template>
<ng-template
let-value="value"
ngx-datatable-cell-template
>
{{
value.toLocaleString("id-ID", {
style: "currency",
currency: "IDR"
})
}}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="totalUse"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span>Total Use</span>
</ng-template>
<ng-template
let-value="value"
ngx-datatable-cell-template
>
{{ value }} kWh
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="endDate"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span>Tanggal</span>
</ng-template>
<ng-template
let-value="value"
ngx-datatable-cell-template
>
{{ value | date : "MM/yyyy" }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="status_id"
[flexGrow]="1"
[minWidth]="90"
>
<ng-template ngx-datatable-header-template>
<span>Status</span>
</ng-template>
<ng-template
ngx-datatable-cell-template
let-value="value"
>
{{ value === 2 ? "Aktif" : "Tidak Aktif" }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column
name="Actions"
[flexGrow]="1"
[minWidth]="150"
>
<ng-template
ngx-datatable-cell-template
let-rowIndex="rowIndex"
let-row="row"
>
<button
class="btn btn-sm btn-warning mr-1"
(click)="editRow(row)"
>
<i class="ficon feather ft-edit"></i>
</button>
<button
class="btn btn-sm btn-danger"
(click)="deleteRow(row)"
>
<i class="ficon feather ft-trash-2"></i>
</button>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,50 +1,51 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from "@angular/core";
import { Router } from '@angular/router'; import { Router } from "@angular/router";
import { TableApiService } from 'src/app/_services/table-api.service'; import { TableApiService } from "src/app/_services/table-api.service";
import { BuildingService } from "../service/monitoring-api.service";
import { DatePipe } from "@angular/common";
import { CostManagementService } from "../service/cost-management.service";
import { NgbModal } from "@ng-bootstrap/ng-bootstrap";
import { ModalAddActualComponent } from "./modal-add-actual/modal-add-actual.component";
@Component({ @Component({
selector: 'app-cost-management', selector: "app-cost-management",
templateUrl: './cost-management.component.html', templateUrl: "./cost-management.component.html",
styleUrls: ['./cost-management.component.css'] styleUrls: ["./cost-management.component.css"],
}) })
export class CostManagementComponent implements OnInit{ export class CostManagementComponent implements OnInit {
public breadcrumb: any; public breadcrumb: any;
data: any; data: any;
filteredRows: any[]; filteredRows: any[];
data_cost: any;
searchTerm: string = ""; searchTerm: string = "";
kwhTerm: string = "";
costTerm: string = "";
rows: any = []; rows: any = [];
dataMasterCategori: any;
dataBuildingList: any;
public focucedElement = "";
spinnerActive = false;
spinnerActiveActual = false;
donutChart1: any;
donutChart2: any; donutChart2: any;
dataChart = {
donut: {
series: [50, 50],
labels: [],
},
};
dataChart2 = {
donut: {
series: [50, 50],
labels: [],
},
};
barChart: any; barChart: any;
dataBar = {
"Bar": { dateSelected: any;
"labels": [], buildingSelected: any;
"series": [ categorySelected: any;
[ dataComp: any;
80, dataCompPrev: any;
60 dataCompAct: any;
] storedData: any;
]
},
}
constructor( constructor(
private tableApiservice: TableApiService, private tableApiservice: TableApiService,
private router: Router private router: Router,
private monitoringApiService: BuildingService,
private costService: CostManagementService,
private datePipe: DatePipe,
private modalService: NgbModal
) {} ) {}
ngOnInit() { ngOnInit() {
@ -61,78 +62,223 @@ export class CostManagementComponent implements OnInit{
}, },
], ],
}; };
this.fetchData(); this.storedData = JSON.parse(localStorage.getItem("currentUser"));
this.buildingSelected = this.storedData.buildingId;
const currentDate = new Date();
this.dateSelected = currentDate.toISOString().slice(0, 7);
this.barChart = { this.fetchData(this.storedData.buildingId, this.dateSelected, this.categorySelected);
type: 'Bar', this.dataListMaster();
data: this.dataBar.Bar, this.dataListBuilding();
options: {
fullwidth: true,
axisX: {
showGrid: false,
showLabel: false,
offset: 100
},
axisY: {
showGrid: false,
showLabel: false
}
}
};
this.donutChart1 = { this.dataCompWaterElectCost(this.storedData.buildingId);
type: "Pie", this.dataCompPrevMonthCost(this.storedData.buildingId);
data: this.dataChart.donut, this.dataCompActEstCost(this.storedData.buildingId);
options: {
fullwidth: true,
height: "300px",
donut: true,
donutWidth: 70,
startAngle: 270,
total: 200,
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();
}
}
},
},
};
} }
fetchData() { fetchData(id, period, category) {
this.tableApiservice.getTableInitialisationData().subscribe((response) => { this.costService.getCostManagement(id, period, category).subscribe((response) => {
this.data = response; this.data = response.results.data;
this.filteredRows = this.data.rows; this.filteredRows = this.data;
this.kwhTerm = response.results.kwh;
this.costTerm = response.results.cost;
this.data_cost = this.filteredRows.map((item) => ({
building: item.name,
categoryName: item.category_name,
estimationCost: item.estimation_cost,
totalUse: item.total_use,
endDate: item.end_date,
statusId: item.status_id,
}));
}); });
} }
dataListMaster() {
this.monitoringApiService.getMasterListData().subscribe((data) => {
const dataCategory = data.data.find(
(item) => item.name === "master_category"
).headerDetailParam;
this.dataMasterCategori = dataCategory.filter(
(item) => item.status === "2"
);
});
}
dataListBuilding() {
this.monitoringApiService.getBuildingList().subscribe((data) => {
this.dataBuildingList = data.data.filter((item) => item.statusId === 2);
});
}
dataCompWaterElectCost(buildingId) {
this.costService.getCompWaterElectCost(buildingId).subscribe((data) => {
this.dataComp = data.data;
const dataChart2 = {
donut: {
series: [this.dataComp.elect, this.dataComp.water],
labels: [],
},
};
this.donutChart2 = {
type: "Pie",
data: 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();
}
}
},
},
};
// this.dataChart2.donut.labels = ["Water", "Electricity"];
});
}
dataCompPrevMonthCost(buildingId) {
this.costService.getCompPrevMonthCost(buildingId).subscribe((data) => {
this.dataCompPrev = data.data;
const randomValue = Math.floor(Math.random() * (100 - 50 + 1)) + 50;
const dataBar = {
Bar: {
labels: [[this.dataCompPrev[0].name], [this.dataCompPrev[1].name]],
series: [[randomValue], [this.dataCompPrev[1].value]],
},
};
this.barChart = {
type: "Bar",
data: dataBar.Bar,
options: {
fullwidth: true,
width: "100px",
height: "150px",
seriesBarDistance: 100,
axisX: {
showGrid: false,
showLabel: false,
offset: 5,
},
axisY: {
showGrid: false,
showLabel: false,
scaleMinSpace: 30,
},
classNames: {
bar: "ct-bar", // Menambahkan kelas CSS ke batang
},
},
responsiveOptions: [
[
"screen and (max-width: 640px)",
{
seriesBarDistance: 100,
axisX: {
labelInterpolationFnc: function (value) {
return value[0];
},
},
},
],
],
};
});
}
dataCompActEstCost(buildingId) {
this.costService.getCompActEstCost(buildingId).subscribe((data) => {
this.dataCompAct = data.data[0];
});
}
syncData() {
const dataDate = {
buildingId: this.buildingSelected,
periode: this.dateSelected,
};
this.spinnerActive = true;
this.costService.getSyncCost(dataDate).subscribe((data) => {
console.log(data);
});
setTimeout(() => {
this.spinnerActive = false;
this.fetchData(this.buildingSelected, this.dateSelected, this.categorySelected );
}, 3000);
}
actualData() {
this.spinnerActiveActual = true;
this.costService
.getRealCostByBuildingId(4, this.dateSelected)
.subscribe((data) => {
console.log(data.data[0]);
// this.costTerm = data.data[0].est_cost
});
setTimeout(() => {
this.spinnerActiveActual = false;
this.fetchData(this.buildingSelected, this.dateSelected, this.categorySelected );
}, 3000);
}
doFilter() {
const requestData = {
building: this.buildingSelected,
category: this.categorySelected,
date: this.dateSelected,
searchTerm: this.searchTerm,
};
this.fetchData(this.buildingSelected, this.dateSelected, this.categorySelected );
this.dataCompWaterElectCost(this.buildingSelected);
this.dataCompPrevMonthCost(this.buildingSelected);
this.dataCompActEstCost(this.buildingSelected);
}
addFieldValue() {
const modalRef = this.modalService.open(ModalAddActualComponent, {
size: "sm",
});
modalRef.componentInstance.newAttribute = {
id: null,
name: "",
};
modalRef.result.then(
(result) => {
if (result) {
this.rows.push(result);
this.rows = [...this.rows];
}
},
(reason) => {
console.log(`Dismissed: ${reason}`);
}
);
}
focusElement(focucedElement: any) {
this.focucedElement = focucedElement;
}
filterRows() { filterRows() {
if (!this.searchTerm) { if (!this.searchTerm) {
this.filteredRows = [...this.data.rows]; this.filteredRows = [...this.data.rows];
@ -147,8 +293,7 @@ export class CostManagementComponent implements OnInit{
const searchTermLC = this.searchTerm.toLowerCase(); const searchTermLC = this.searchTerm.toLowerCase();
return Object.values(row).some( return Object.values(row).some(
(value) => (value) =>
value !== null && value !== null && value.toString().toLowerCase().includes(searchTermLC)
value.toString().toLowerCase().includes(searchTermLC)
); );
} }
@ -169,4 +314,6 @@ export class CostManagementComponent implements OnInit{
onTouchStart(event: Event) { onTouchStart(event: Event) {
event.preventDefault(); // Add this if necessary event.preventDefault(); // Add this if necessary
} }
} }

View File

@ -1,5 +1,5 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule, DatePipe } from '@angular/common';
import { CostManagementComponent } from './cost-management.component'; import { CostManagementComponent } from './cost-management.component';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module'; import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
@ -15,13 +15,16 @@ import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { NgChartsModule } from 'ng2-charts'; import { NgChartsModule } from 'ng2-charts';
import { ChartistModule } from 'ng-chartist'; import { ChartistModule } from 'ng-chartist';
import { MatchHeightModule } from '../../partials/general/match-height/match-height.module';
import { ModalAddActualComponent } from './modal-add-actual/modal-add-actual.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
CostManagementComponent, CostManagementComponent,
AddEditCostComponent AddEditCostComponent,
ModalAddActualComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -36,6 +39,7 @@ import { ChartistModule } from 'ng-chartist';
NgxDatatableModule, NgxDatatableModule,
NgChartsModule, NgChartsModule,
ChartistModule, ChartistModule,
MatchHeightModule,
BlockUIModule.forRoot({ BlockUIModule.forRoot({
template: BlockTemplateComponent template: BlockTemplateComponent
}), }),
@ -60,6 +64,9 @@ import { ChartistModule } from 'ng-chartist';
data: { mode: 'view' } data: { mode: 'view' }
} }
]) ])
] ],
providers: [
DatePipe // Add DatePipe to providers
],
}) })
export class CostManagementModule { } export class CostManagementModule { }

View File

@ -0,0 +1,56 @@
/* modal-add-edit.component.css */
::ng-deep .modal-backdrop.show {
z-index: auto !important;
}
::ng-deep .input-group-append .btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-radius: 0;
border-left: 0;
flex-grow: 0;
border-left: 1px solid #ced4da;
padding: 0.375rem 0.75rem;
}
::ng-deep .input-group {
display: flex;
flex-wrap: nowrap; /* Prevents wrapping of the items */
align-items: center;
}
::ng-deep .form-control {
flex-grow: 1; /* Ensures select takes up available space */
padding-right: 0.5rem;
}
::ng-deep .input-group select,
::ng-deep .input-group .input-group-append .btn {
padding-right: 5px; /* Adjust padding if necessary */
}
::ng-deep .input-group .form-control {
margin-right: 2px; /* Adjust margin to make space */
}
.form-group {
margin-bottom: 1rem;
}
.form-control {
display: block;
width: 100%;
height: calc(1.5em + 0.75rem + 2px);
padding: 0.375rem 0.75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #495057;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: 0.25rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

View File

@ -0,0 +1,31 @@
<div class="modal-header">
<!-- <h4 class="modal-title">Add New Row</h4> -->
<button type="button" class="close" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form [formGroup]="myForm">
<div class="form-group">
<label for="name">Name:</label>
<input
type="text"
class="form-control"
id="name"
formControlName="name"
/>
</div>
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
(click)="activeModal.dismiss('Cross click')"
>
Close
</button>
<button type="button" class="btn btn-primary" (click)="addRow()">
Save Changes
</button>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ModalAddActualComponent } from './modal-add-actual.component';
describe('ModalAddActualComponent', () => {
let component: ModalAddActualComponent;
let fixture: ComponentFixture<ModalAddActualComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ModalAddActualComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ModalAddActualComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,29 @@
import { Component, Input } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-modal-add-actual',
templateUrl: './modal-add-actual.component.html',
styleUrls: ['./modal-add-actual.component.css']
})
export class ModalAddActualComponent {
@Input() newAttribute: any = {};
myForm: FormGroup;
constructor(public activeModal: NgbActiveModal, private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.myForm = this.fb.group({
name: ['', Validators.required],
});
}
addRow() {
if (this.myForm.valid) {
this.activeModal.close(this.myForm.value);
}
}
}

View File

@ -94,7 +94,7 @@
[items]="singleSelectArray" [items]="singleSelectArray"
[searchable]="true" [searchable]="true"
bindLabel="item_text" bindLabel="item_text"
placeholder="Select Month" placeholder="Select Type"
[(ngModel)]="singlebasicSelected" [(ngModel)]="singlebasicSelected"
> >
</ng-select> </ng-select>

View File

@ -67,16 +67,14 @@ export class DeviceComponent implements OnInit {
console.log(this.filteredRows); console.log(this.filteredRows);
this.totalOn = this.filteredRows.filter((row) => row.statusEntity.name.toLowerCase() === 'aktif').length this.totalOn = this.filteredRows.filter((row) => row.statusEntity.name.toLowerCase() === 'aktif').length
this.totalOff = this.filteredRows.filter((row) => row.statusEntity.name.toLowerCase() === 'nonaktif').length this.totalOff = this.filteredRows.filter((row) => row.statusEntity.name.toLowerCase() === 'nonaktif').length
// console.log(totalon);
}); });
} }
filterRows() { filterRows() {
if (!this.searchTerm) { if (!this.searchTerm) {
this.filteredRows = [...this.data.rows]; this.filteredRows = [...this.data.results.data];
} else { } else {
this.filteredRows = this.data.rows.filter((row) => this.filteredRows = this.data.results.data.filter((row) =>
this.rowContainsSearchTerm(row) this.rowContainsSearchTerm(row)
); );
} }
@ -135,14 +133,10 @@ export class DeviceComponent implements OnInit {
this.monitoringApiService.getSyncDeviceData().subscribe((res) => { this.monitoringApiService.getSyncDeviceData().subscribe((res) => {
console.log(res); console.log(res);
}); });
// Lakukan proses tambahan (misalnya, panggil API atau proses yang memakan waktu)
setTimeout(() => { setTimeout(() => {
// Selesaikan proses tambahan di sini
// Nonaktifkan spinner setelah proses selesai
this.spinnerActive = false; this.spinnerActive = false;
this.fetchData(); this.fetchData();
}, 3000); // Ganti 3000 dengan waktu yang sesuai dengan proses tambahan Anda (dalam milidetik) }, 3000);
} }
} }

View File

@ -83,7 +83,7 @@
<div class="row"> <div class="row">
<div class="col-12" *blockUI="'barCharts'; message: 'Loading'"> <div class="col-12" *blockUI="'barCharts'; message: 'Loading'">
<m-card [options]="options"> <m-card [options]="options">
<ng-container mCardHeaderTitle> Appointment </ng-container> <ng-container mCardHeaderTitle> </ng-container>
<ng-container mCardBody> <ng-container mCardBody>
<div class="z" style="display: block"> <div class="z" style="display: block">
<canvas <canvas

View File

@ -0,0 +1,71 @@
import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Observable } from "rxjs";
@Injectable({
providedIn: "root",
})
export class CostManagementService {
constructor(private http: HttpClient) {}
getCostManagement(id, period, category): Observable<any> {
const baseUrl = `https://kapi.absys.ninja/hemat/cost_management`;
const params = new URLSearchParams({
page: "1",
limit: "100",
building_id: id,
periode: period,
});
if (category) {
params.append("category_id", category);
}
const url = `${baseUrl}?${params.toString()}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
}
getCompWaterElectCost(id): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/cost_management/card/comp-water-elect-cost?building_id=${id}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
}
getCompPrevMonthCost(id): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/cost_management/card/comp-prev-month-cost?building_id=${id}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
}
getCompActEstCost(id): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/cost_management/card/comp-act-est-cost?building_id=${id}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
}
getSyncCost(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/cost_management/cost/sync`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.post<any>(url, data, { headers });
}
getRealCostByBuildingId(id: any, period: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/real-cost/get/byBuildingId?building_id=${id}&periode=${period}`;
const headers = new HttpHeaders({
"Content-Type": "application/json",
"x-api-key": "j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT",
});
return this.http.get<any>(url, { headers });
}
}

View File

@ -135,6 +135,15 @@ export class BuildingService {
return this.http.get<any>(url, { headers }); return this.http.get<any>(url, { headers });
} }
getCostManagement(page: number = 1, limit: number = 100, ): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/cost_management?page=${page}&limit=${limit}&building_id=4&periode=2024-06`;
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'x-api-key': 'j2yaYvPSQcsEEmHh3NEobfiXyyXmmnHT'
});
return this.http.get<any>(url, { headers });
}
postHeaderDetailParam(data: any): Observable<any> { postHeaderDetailParam(data: any): Observable<any> {
const url = `https://kapi.absys.ninja/hemat/header-detail-param`; const url = `https://kapi.absys.ninja/hemat/header-detail-param`;
const headers = new HttpHeaders({ const headers = new HttpHeaders({

View File

@ -122,6 +122,7 @@ export class LoginComponent implements OnInit {
// Store the user profile information // Store the user profile information
const userProfile = { const userProfile = {
displayName: this.loginForm.value.email, displayName: this.loginForm.value.email,
buildingId: 4
}; };
localStorage.setItem('currentUser', JSON.stringify(userProfile)); localStorage.setItem('currentUser', JSON.stringify(userProfile));