Commit fa100049 by DESKTOP-E0VCCBD\zedan

update

parent 4a83b87f
......@@ -5,6 +5,81 @@
></app-page-header>
<div class="grid grid-cols-12 gap-x-6">
<div class="xl:col-span-12 col-span-12">
<div class="box mt-6">
<div class="box-header justify-between">
<div class="box-title">
กรุณาเลือก
<span
class="badge bg-light text-default rounded-full ms-1 text-[0.75rem] align-middle"
></span>
</div>
<div class="flex gap-4 flex-wrap">
<!-- Start Date -->
<div class="flex items-center gap-2">
<label for="startDate" class="whitespace-nowrap">Start Date:</label>
<input
type="date"[(ngModel)]="startDate"
id="startDate"
name="startDate"
class="border rounded px-2 py-1"
/>
</div>
<!-- End Date -->
<div class="flex items-center gap-2">
<label for="endDate" class="whitespace-nowrap">End Date:</label>
<input
type="date"[(ngModel)]="endDate"
id="endDate"
name="endDate"
class="border rounded px-2 py-1"
/>
</div>
<!-- Dropdown Checkbox -->
<div
class="relative inline-block"
(clickOutside)="isDropdownOpen = false"
>
<!-- Dropdown button -->
<button
(click)="toggleDropdown()"
class="border rounded px-4 py-2 bg-white shadow w-48 text-left"
>
{{ getSelectedLabel() }}
</button>
<!-- Dropdown content -->
<div
*ngIf="isDropdownOpen"
class="absolute z-10 mt-1 w-48 bg-white border rounded shadow"
>
<label
*ngFor="let project of projectList"
class="flex items-center px-4 py-2 hover:bg-gray-100"
>
<input
type="checkbox"
[value]="project"
[(ngModel)]="projectSelection[project.project_name]"
class="mr-2"
/>
{{ project.project_name }}
</label>
</div>
</div>
</div>
<div class="flex flex-wrap gap-2">
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-primary-full me-2" (click)="applyFilters()"
data-hs-overlay="#modal-detail"><i class="font-semibold align-middle"></i>Apply
</a>
</div>
</div>
</div>
</div>
<div class="xxxl:col-span-6 col-span-12">
<div class="grid grid-cols-12 gap-x-6">
<div class="xxl:col-span-4 md:col-span-6 col-span-12">
......@@ -31,11 +106,9 @@
<div class="flex-grow">
<div class="flex mb-1 items-start justify-between">
<h5 class="font-semibold mb-0 leading-none text-[1.25rem]">
256
{{ itemsList.length }}
</h5>
<div class="text-danger font-semibold">
<i class="ri-arrow-down-s-fill me-1 align-middle"></i>-1.05%
</div>
<div class="text-danger font-semibold"></div>
</div>
<p
class="mb-0 text-[0.625rem] opacity-[0.7] text-[#8c9097] dark:text-white/50 font-semibold"
......@@ -74,11 +147,9 @@
<div class="flex-grow">
<div class="flex mb-1 items-start justify-between">
<h5 class="font-semibold mb-0 leading-none text-[1.25rem]">
4,026
{{ projectList.length }}
</h5>
<div class="text-success font-semibold">
<i class="ri-arrow-up-s-fill me-1 align-middle"></i>+0.40%
</div>
<div class="text-success font-semibold"></div>
</div>
<p
class="mb-0 text-[0.625rem] opacity-[0.7] text-[#8c9097] dark:text-white/50 font-semibold"
......@@ -114,11 +185,9 @@
<div class="flex-grow">
<div class="flex mb-1 items-start justify-between">
<h5 class="font-semibold mb-0 leading-none text-[1.25rem]">
48
{{ equipmentList.length }}
</h5>
<div class="text-success font-semibold">
<i class="ri-arrow-up-s-fill me-1 align-middle"></i>+0.82%
</div>
<div class="text-success font-semibold"></div>
</div>
<p
class="mb-0 text-[0.625rem] opacity-[0.7] text-[#8c9097] dark:text-white/50 font-semibold"
......@@ -130,61 +199,25 @@
</div>
</div>
</div>
<div class="col-span-12">
<div class="box overflow-hidden">
<div class="box-header justify-between items-center flex-wrap gap-4">
<div class="box-title">จำนวนการยืมอุปกรณ์</div>
<div class="flex gap-4 flex-wrap">
<!-- Select: เดือน -->
<select>
<option value="">ALL</option>
<option value="">มกราคม</option>
<option value="">กุมภาพันธ์</option>
<option value="">มีนาคม</option>
<option value="">เมษายน</option>
</select>
<!-- Select: โปรเจค -->
<select>
<option value="">โปรเจคทั้งหมด</option>
<option value="">DPU001</option>
<option value="">DPU002</option>
<option value="">DPU003</option>
<option value="">DPU004</option>
</select>
<div class="inline-flex rounded-md shadow-sm" role="group" aria-label="Basic example">
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary">1M</button>
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary">3M</button>
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary">6M</button>
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary-full !rounded-s-none !text-white">1Y</button>
</div>
</div>
<div class="box-header">
<div class="box-title">จำนวนการยืม-คืนอุปกรณ์</div>
</div>
<div class="xl:col-span-12 col-span-12">
<div class="box">
<div class="box-body">
<div id="audienceReport">
<div id="line-chart-datalabels" class="chart-container">
<apx-chart
[series]="chartOptions.series"
[chart]="chartOptions.chart"
[yaxis]="chartOptions.yaxis"
[xaxis]="chartOptions.xaxis"
[labels]="chartOptions.labels"
[stroke]="chartOptions.stroke"
[plotOptions]="chartOptions.plotOptions"
[markers]="chartOptions.markers"
[fill]="chartOptions.fill"
[tooltip]="chartOptions.tooltip"
[legend]="chartOptions.legend"
[colors]="chartOptions.colors"
[series]="chartOptions9.series"
[chart]="chartOptions9.chart"
[xaxis]="chartOptions9.xaxis"
[stroke]="chartOptions9.stroke"
[colors]="chartOptions9.colors"
[dataLabels]="chartOptions9.dataLabels"
[legend]="chartOptions9.legend"
[markers]="chartOptions9.markers"
[grid]="chartOptions9.grid"
[yaxis]="chartOptions9.yaxis"
[title]="chartOptions9.title"
></apx-chart>
</div>
</div>
......@@ -192,8 +225,6 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-12 gap-x-6">
<!-- Candidates (Left Half) -->
......@@ -263,28 +294,163 @@
<!-- Line Chart (Right Half) -->
<div class="xxl:col-span-6 col-span-12">
<div class="box custom-box">
<div class="box-header">
<div class="box-title">แนวโน้มการยืม-คืนอุปกรณ์รายเดือน</div>
<div class="box-header justify-between items-center flex-wrap gap-4">
<div class="box-title">จำนวนอุปกรณ์คงเหลือ</div>
<div class="flex gap-4 flex-wrap">
<!-- Select: เดือน -->
<select>
<option value="">ALL</option>
<option value="">มกราคม</option>
<option value="">กุมภาพันธ์</option>
<option value="">มีนาคม</option>
<option value="">เมษายน</option>
</select>
<!-- Select: โปรเจค -->
<select>
<option value="">โปรเจคทั้งหมด</option>
<option value="">DPU001</option>
<option value="">DPU002</option>
<option value="">DPU003</option>
<option value="">DPU004</option>
</select>
<div
class="inline-flex rounded-md shadow-sm"
role="group"
aria-label="Basic example"
>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
1M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
3M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
6M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary-full !rounded-s-none !text-white"
>
1Y
</button>
</div>
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<div class="box">
<div class="box-body">
<div id="line-chart-datalabels" class="chart-container">
<div id="audienceReport">
<apx-chart
[series]="chartOptions9.series"
[chart]="chartOptions9.chart"
[xaxis]="chartOptions9.xaxis"
[stroke]="chartOptions9.stroke"
[colors]="chartOptions9.colors"
[dataLabels]="chartOptions9.dataLabels"
[legend]="chartOptions9.legend"
[markers]="chartOptions9.markers"
[grid]="chartOptions9.grid"
[yaxis]="chartOptions9.yaxis"
[title]="chartOptions9.title"
[series]="chartOptions.series"
[chart]="chartOptions.chart"
[yaxis]="chartOptions.yaxis"
[xaxis]="chartOptions.xaxis"
[labels]="chartOptions.labels"
[stroke]="chartOptions.stroke"
[plotOptions]="chartOptions.plotOptions"
[markers]="chartOptions.markers"
[fill]="chartOptions.fill"
[tooltip]="chartOptions.tooltip"
[legend]="chartOptions.legend"
[colors]="chartOptions.colors"
></apx-chart>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="xxl:col-span-6 col-span-12">
<div class="box custom-box">
<div class="box-header justify-between items-center flex-wrap gap-4">
<div class="box-title">จำนวนอุปกรณ์ทั้งหมด</div>
<div class="flex gap-4 flex-wrap">
<!-- Select: เดือน -->
<select>
<option value="">ALL</option>
<option value="">มกราคม</option>
<option value="">กุมภาพันธ์</option>
<option value="">มีนาคม</option>
<option value="">เมษายน</option>
</select>
<!-- Select: โปรเจค -->
<select>
<option value="">โปรเจคทั้งหมด</option>
<option value="">DPU001</option>
<option value="">DPU002</option>
<option value="">DPU003</option>
<option value="">DPU004</option>
</select>
<div
class="inline-flex rounded-md shadow-sm"
role="group"
aria-label="Basic example"
>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
1M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
3M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
6M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary-full !rounded-s-none !text-white"
>
1Y
</button>
</div>
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<div class="box">
<div class="box-body">
<div id="audienceReport">
<apx-chart
[series]="chartOptions.series"
[chart]="chartOptions.chart"
[yaxis]="chartOptions.yaxis"
[xaxis]="chartOptions.xaxis"
[labels]="chartOptions.labels"
[stroke]="chartOptions.stroke"
[plotOptions]="chartOptions.plotOptions"
[markers]="chartOptions.markers"
[fill]="chartOptions.fill"
[tooltip]="chartOptions.tooltip"
[legend]="chartOptions.legend"
[colors]="chartOptions.colors"
></apx-chart>
</div>
</div>
</div>
</div>
</div>
</div>
import { ChangeDetectorRef, Component, ElementRef, Renderer2 } from '@angular/core';
import { DashboardService } from './../../services/dashboard.service';
import { EquipmentService } from './../../services/equirement.service';
import { ProjectService } from './../../services/project.service';
import { UserService } from './../../services/user.service';
import { ChangeDetectorRef, Component, ElementRef, Renderer2, ViewChild } from '@angular/core';
import { RouterModule } from '@angular/router';
import ApexCharts from 'apexcharts'
import { SharedModule } from '../../../shared/shared.module';
import { NgApexchartsModule } from 'ng-apexcharts';
import { SimplebarAngularModule } from 'simplebar-angular';
import { CommonModule } from '@angular/common';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { NgSelectModule } from '@ng-select/ng-select';
import { FormsModule } from '@angular/forms';
import { MatPaginator } from '@angular/material/paginator';
import { FileItem, FileUploader, FileUploadModule, ParsedResponseHeaders } from 'ng2-file-upload';
import { UserProfileModel } from '../../models/user.model';
import { UserRoleModel } from '../../models/user-role-model';
import { TokenService } from '../../../shared/services/token.service';
import { environment } from '../../../../environments/environment';
import swal from 'sweetalert';
import { ProjectModel } from '../../models/project.model';
import { EquipmentModel } from '../../models/equipments.model';
import { DashboardModel } from '../../models/dasbord.model';
@Component({
selector: 'app-home-common',
standalone: true,
imports: [RouterModule, SharedModule, NgApexchartsModule, SimplebarAngularModule],
imports: [RouterModule, SharedModule, NgApexchartsModule, SimplebarAngularModule, CommonModule,
SharedModule,
TranslateModule,
NgSelectModule,
FormsModule,
MatPaginator,
FileUploadModule],
templateUrl: './home-common.component.html',
styleUrls: ['./home-common.component.css']
})
export class HomeCommonComponent {
@ViewChild('closeModal') public childModal?: ElementRef;
@ViewChild('modalDetail') public modalDetail?: ElementRef;
action = "new";
rawData: any[];
allSelected = false;
someSelected = false;
startDate: string = '';
endDate: string = '';
selectedProjects: string[] = [];
selectedEquipmentType: string = 'ALL';
isDropdownOpen = false;
projectSelection: { [key: string]: boolean } = {};
confirmPassword = ""
dashbordList:string[] = [];
equipmentList: EquipmentModel[] = []
projectList: ProjectModel[] = []
itemsList: UserProfileModel[] = []
filterList: UserProfileModel[] = []
selectModel: UserProfileModel = new UserProfileModel()
selectedItems = new Map<string, boolean>();
roleList: UserRoleModel[] = []
empList: UserProfileModel[] = []
descName = 'engName'
pageIndex = 0;
uploaderProfile: FileUploader | undefined;
uploadErrorMsg: string = "";
dashboardModel: DashboardModel
get searchTerm(): string {
return this._searchTerm;
}
set searchTerm(val: string) {
this.pageIndex = 0;
this.allSelected = false
this._searchTerm = val;
if (val != '') {
this.filterList = this.filter(val);
} else {
this.updatePagedItems()
}
}
_searchTerm = "";
chartOptions: any;
chartOptions1: any;
chartOptions2: any;
......@@ -33,6 +99,9 @@ export class HomeCommonComponent {
chart3options: any
chart2options: any
chart1options: any
public series: ApexAxisChartSeries = [];
public chart!: ApexChart;
public dataLabels!: ApexDataLabels;
......@@ -85,7 +154,8 @@ export class HomeCommonComponent {
type: 'datetime',
},
};
constructor(private el: ElementRef, private renderer: Renderer2, private cdr: ChangeDetectorRef) {
constructor(private el: ElementRef, private renderer: Renderer2, private cdr: ChangeDetectorRef, private userService: UserService, public translate: TranslateService, private tokenService: TokenService, private ProjectService: ProjectService, private EquipmentService: EquipmentService,private DashboardService:DashboardService) {
this.chartOptions9 = {
......@@ -707,5 +777,306 @@ export class HomeCommonComponent {
}
this.uploadConfig()
}
uploadConfig() {
this.uploaderProfile = new FileUploader({
url: environment.baseUrl + "/api/upload-image",
isHTML5: true,
authToken: this.tokenService.getToken()!,
});
this.uploaderProfile.onAfterAddingFile = (fileItem: FileItem) => {
fileItem.withCredentials = false;
this.uploadErrorMsg = "";
while (this.uploaderProfile!.queue.length > 1) {
this.uploaderProfile!.queue[0].remove();
}
if (fileItem.file.size > 5000000) {
this.uploadErrorMsg = "maximum file size 5mb.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
fileItem.isCancel = true;
return;
}
if (fileItem.file.type!.indexOf("image") === -1) {
this.uploadErrorMsg = "please upload image only.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
fileItem.isCancel = true;
return;
}
fileItem.upload();
};
this.uploaderProfile.onCompleteItem = (
item: FileItem,
response: string,
status: number,
headers: ParsedResponseHeaders
) => {
if (item.isSuccess) {
const res = JSON.parse(response);
console.log("res", res);
this.selectModel.picture = res.filename
swal(res.message, "บันทึกสำเร็จ", "success");
} else {
this.uploadErrorMsg = "cannot upload file.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
}
};
}
onProjectCheckboxChange(event: any) {
const value = event.target.value;
if (event.target.checked) {
this.selectedProjects.push(value);
} else {
this.selectedProjects = this.selectedProjects.filter(p => p !== value);
}
}
toggleDropdown() {
this.isDropdownOpen = !this.isDropdownOpen;
}
getSelectedLabel(): string {
const selectedIds = Object.keys(this.projectSelection).filter(
id => this.projectSelection[id]
);
if (selectedIds.length === 0) return 'เลือกโปรเจค';
if (selectedIds.length === this.projectList.length) return 'โปรเจคทั้งหมด';
// ดึงชื่อจริงจาก projectList
const selectedNames = this.projectList
.filter(project => selectedIds.includes(project.project_name))
.map(project => project.project_name);
return selectedNames.join(', ');
}
ngOnInit(): void {
this.userService.getLists().subscribe(result => {
this.itemsList = result
this.updatePagedItems()
})
this.ProjectService.getLists().subscribe(result => {
this.projectList = result
})
this.EquipmentService.getLists().subscribe(result => {
this.equipmentList = result
})
this.getDashbord
}
getDashbord(){
this.DashboardService.getDashboard().subscribe(result => {
this.dashboardModel = result
console.log(this.dashboardModel)
})
}
filter(v: string) {
return this.itemsList?.filter(
(x) =>
x.memberId?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.username?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.email?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.phoneNumber?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getRole()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getStatus()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getFullname()?.toLowerCase().indexOf(v.toLowerCase()) !== -1
);
}
delete(item: UserProfileModel) {
swal({
title: "Are you sure?",
text: "You won't be able to revert this!",
icon: "warning",
dangerMode: true,
buttons: ["Cancel", "Yes,Delete it!"],
})
.then((willDelete: any) => {
if (willDelete) {
this.userService.delete(item).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit()
})
}
});
}
new() {
this.action = 'add'
this.selectModel = new UserProfileModel()
}
view(item: UserProfileModel) {
this.action = 'edit'
this.confirmPassword = ''
this.selectModel = new UserProfileModel(item)
console.log(this.selectModel)
}
save() {
swal({
title: "Are you sure?",
text: "คุณต้องการบันทึกหรือไม่",
icon: "warning",
dangerMode: false,
buttons: ["Cancel", "Confirm"],
})
.then((willDelete: any) => {
if (willDelete) {
if (this.action == 'add') {
this.userService.save(this.selectModel).subscribe(result => {
console.log(result)
swal("Save Success!!", "บันทึกข้อมูลสมาชิก", "success");
this.ngOnInit()
this.childModal?.nativeElement.click()
})
} else if (this.action == 'edit') {
this.userService.update(this.selectModel).subscribe(result => {
console.log(result)
swal("Update Success!!", "บันทึกข้อมูลสมาชิก", "success");
this.ngOnInit()
this.childModal?.nativeElement.click()
})
}
}
});
}
applyFilters() {
const selectedProjects = Object.keys(this.projectSelection).filter(p => this.projectSelection[p]);
const filteredData = this.rawData.filter(item => {
return (!this.startDate || item.date >= this.startDate) &&
(!this.endDate || item.date <= this.endDate) &&
(selectedProjects.length === 0 || selectedProjects.includes(item.project_name)) &&
(this.selectedEquipmentType === 'ALL' || item.equipment_type === this.selectedEquipmentType);
});
}
updatePagedItems() {
const startIndex = this.pageIndex * 10;
const endIndex = startIndex + 10;
this.filterList = this.itemsList.slice(startIndex, endIndex);
}
toggleAll(event: any) {
this.allSelected = event.target.checked;
this.selectedItems.clear();
this.itemsList.forEach(item => {
this.selectedItems.set(item.memberId, this.allSelected);
});
this.someSelected = this.itemsList.some(item => this.selectedItems.get(item.memberId));
}
onCheckboxChange(memberId: string) {
const isSelected = this.selectedItems.get(memberId) || false;
this.selectedItems.set(memberId, !isSelected);
this.allSelected = this.itemsList.every(item => this.selectedItems.get(item.memberId));
this.someSelected = this.itemsList.some(item => this.selectedItems.get(item.memberId));
}
deleteSelect() {
let employeeInfo = '';
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
employeeInfo += `${this.translate.instant('Fullname')}: ${user.getFullname()}\n`;
}
}
});
swal({
title: "Are you sure?",
text: employeeInfo,
icon: "warning",
dangerMode: true,
buttons: ["Cancel", "Yes, Delete it!"],
})
.then((willDelete: any) => {
if (willDelete) {
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
this.userService.delete(user).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit();
});
}
}
});
}
});
}
adjustSelect(status: number) {
let title = "Are you sure?"
let employeeInfo = ''; // ตัวแปรสำหรับเก็บข้อมูลพนักงาน
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
employeeInfo += `${this.translate.instant('Fullname')}: ${user.getFullname()}\n`;
}
}
});
swal({
title: title,
text: employeeInfo,
icon: "warning",
dangerMode: false,
buttons: ["Cancel", "Confirm"],
})
.then((willDelete: any) => {
if (willDelete) {
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
user.status = status
this.userService.update(user).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit();
});
}
}
});
}
});
}
filterEmp(empId: string) {
this.selectModel = this.empList.filter(e => e.memberId == empId)[0]
}
}
......@@ -5,6 +5,49 @@
></app-page-header>
<div class="grid grid-cols-12 gap-x-6">
<div class="xl:col-span-12 col-span-12">
<div class="box mt-6">
<div class="box-header justify-between">
<div class="box-title">
<span
> กรุณาเลือก</span>
</div>
<div class="flex gap-4 flex-wrap">
<!-- Start Date -->
<div class="flex items-center gap-2">
<label for="startDate" class="whitespace-nowrap">Start Date:</label>
<input
type="date"[(ngModel)]="startDate"
id="startDate"
name="startDate"
class="border rounded px-2 py-1"
/>
</div>
<!-- End Date -->
<div class="flex items-center gap-2">
<label for="endDate" class="whitespace-nowrap">End Date:</label>
<input
type="date"[(ngModel)]="endDate"
id="endDate"
name="endDate"
class="border rounded px-2 py-1"
/>
</div>
</div>
<div class="flex flex-wrap gap-2">
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-primary-full me-2" (click)="applyFilters()"
data-hs-overlay="#modal-detail"><i class="font-semibold align-middle"></i>Apply
</a>
</div>
</div>
</div>
</div>
</div>
<div class="xxxl:col-span-6 col-span-12">
<div class="grid grid-cols-12 gap-x-6">
<div class="xxl:col-span-4 md:col-span-6 col-span-12">
......@@ -31,11 +74,9 @@
<div class="flex-grow">
<div class="flex mb-1 items-start justify-between">
<h5 class="font-semibold mb-0 leading-none text-[1.25rem]">
256
{{ itemsList.length }}
</h5>
<div class="text-danger font-semibold">
<i class="ri-arrow-down-s-fill me-1 align-middle"></i>-1.05%
</div>
<div class="text-danger font-semibold"></div>
</div>
<p
class="mb-0 text-[0.625rem] opacity-[0.7] text-[#8c9097] dark:text-white/50 font-semibold"
......@@ -74,16 +115,14 @@
<div class="flex-grow">
<div class="flex mb-1 items-start justify-between">
<h5 class="font-semibold mb-0 leading-none text-[1.25rem]">
4,026
{{ projectList.length }}
</h5>
<div class="text-success font-semibold">
<i class="ri-arrow-up-s-fill me-1 align-middle"></i>+0.40%
</div>
<div class="text-success font-semibold"></div>
</div>
<p
class="mb-0 text-[0.625rem] opacity-[0.7] text-[#8c9097] dark:text-white/50 font-semibold"
>
จำนวนพนักงานที่ยืม
จำนวนโปรเจคทั้งหมด
</p>
</div>
</div>
......@@ -114,11 +153,9 @@
<div class="flex-grow">
<div class="flex mb-1 items-start justify-between">
<h5 class="font-semibold mb-0 leading-none text-[1.25rem]">
48
{{ equipmentList.length }}
</h5>
<div class="text-success font-semibold">
<i class="ri-arrow-up-s-fill me-1 align-middle"></i>+0.82%
</div>
<div class="text-success font-semibold"></div>
</div>
<p
class="mb-0 text-[0.625rem] opacity-[0.7] text-[#8c9097] dark:text-white/50 font-semibold"
......@@ -130,51 +167,25 @@
</div>
</div>
</div>
<div class="col-span-12">
<div class="box overflow-hidden">
<div class="box-header justify-between items-center flex-wrap gap-4">
<div class="box-title">จำนวนการยืมอุปกรณ์</div>
<div class="flex gap-4 flex-wrap">
<select>
<option value="">ALL</option>
<option value="">มกราคม</option>
<option value="">กุมภาพันธ์</option>
<option value="">มีนาคม</option>
<option value="">เมษายน</option>
</select>
<div class="inline-flex rounded-md shadow-sm" role="group" aria-label="Basic example">
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary">1M</button>
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary">3M</button>
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary">6M</button>
<button type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary-full !rounded-s-none !text-white">1Y</button>
</div>
</div>
<div class="box-header">
<div class="box-title">จำนวนการยืม-คืนอุปกรณ์</div>
</div>
<div class="xl:col-span-12 col-span-12">
<div class="box">
<div class="box-body">
<div id="audienceReport">
<div id="line-chart-datalabels" class="chart-container">
<apx-chart
[series]="chartOptions.series"
[chart]="chartOptions.chart"
[yaxis]="chartOptions.yaxis"
[xaxis]="chartOptions.xaxis"
[labels]="chartOptions.labels"
[stroke]="chartOptions.stroke"
[plotOptions]="chartOptions.plotOptions"
[markers]="chartOptions.markers"
[fill]="chartOptions.fill"
[tooltip]="chartOptions.tooltip"
[legend]="chartOptions.legend"
[colors]="chartOptions.colors"
[series]="chartOptions9.series"
[chart]="chartOptions9.chart"
[xaxis]="chartOptions9.xaxis"
[stroke]="chartOptions9.stroke"
[colors]="chartOptions9.colors"
[dataLabels]="chartOptions9.dataLabels"
[legend]="chartOptions9.legend"
[markers]="chartOptions9.markers"
[grid]="chartOptions9.grid"
[yaxis]="chartOptions9.yaxis"
[title]="chartOptions9.title"
></apx-chart>
</div>
</div>
......@@ -182,9 +193,7 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-12 gap-x-6">
<!-- Candidates (Left Half) -->
<div class="xxl:col-span-6 col-span-12">
......@@ -253,28 +262,163 @@
<!-- Line Chart (Right Half) -->
<div class="xxl:col-span-6 col-span-12">
<div class="box custom-box">
<div class="box-header">
<div class="box-title">แนวโน้มการยืม-คืนอุปกรณ์รายเดือน</div>
<div class="box-header justify-between items-center flex-wrap gap-4">
<div class="box-title">จำนวนอุปกรณ์คงเหลือ</div>
<div class="flex gap-4 flex-wrap">
<!-- Select: เดือน -->
<select>
<option value="">ALL</option>
<option value="">มกราคม</option>
<option value="">กุมภาพันธ์</option>
<option value="">มีนาคม</option>
<option value="">เมษายน</option>
</select>
<!-- Select: โปรเจค -->
<select>
<option value="">โปรเจคทั้งหมด</option>
<option value="">DPU001</option>
<option value="">DPU002</option>
<option value="">DPU003</option>
<option value="">DPU004</option>
</select>
<div
class="inline-flex rounded-md shadow-sm"
role="group"
aria-label="Basic example"
>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
1M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
3M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
6M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary-full !rounded-s-none !text-white"
>
1Y
</button>
</div>
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<div class="box">
<div class="box-body">
<div id="line-chart-datalabels" class="chart-container">
<div id="audienceReport">
<apx-chart
[series]="chartOptions9.series"
[chart]="chartOptions9.chart"
[xaxis]="chartOptions9.xaxis"
[stroke]="chartOptions9.stroke"
[colors]="chartOptions9.colors"
[dataLabels]="chartOptions9.dataLabels"
[legend]="chartOptions9.legend"
[markers]="chartOptions9.markers"
[grid]="chartOptions9.grid"
[yaxis]="chartOptions9.yaxis"
[title]="chartOptions9.title"
[series]="chartOptions.series"
[chart]="chartOptions.chart"
[yaxis]="chartOptions.yaxis"
[xaxis]="chartOptions.xaxis"
[labels]="chartOptions.labels"
[stroke]="chartOptions.stroke"
[plotOptions]="chartOptions.plotOptions"
[markers]="chartOptions.markers"
[fill]="chartOptions.fill"
[tooltip]="chartOptions.tooltip"
[legend]="chartOptions.legend"
[colors]="chartOptions.colors"
></apx-chart>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="xxl:col-span-6 col-span-12">
<div class="box custom-box">
<div class="box-header justify-between items-center flex-wrap gap-4">
<div class="box-title">จำนวนอุปกรณ์ทั้งหมด</div>
<div class="flex gap-4 flex-wrap">
<!-- Select: เดือน -->
<select>
<option value="">ALL</option>
<option value="">มกราคม</option>
<option value="">กุมภาพันธ์</option>
<option value="">มีนาคม</option>
<option value="">เมษายน</option>
</select>
<!-- Select: โปรเจค -->
<select>
<option value="">โปรเจคทั้งหมด</option>
<option value="">DPU001</option>
<option value="">DPU002</option>
<option value="">DPU003</option>
<option value="">DPU004</option>
</select>
<div
class="inline-flex rounded-md shadow-sm"
role="group"
aria-label="Basic example"
>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
1M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
3M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary"
>
6M
</button>
<button
type="button"
class="ti-btn-group !border-0 !text-xs !py-2 !px-3 ti-btn-primary-full !rounded-s-none !text-white"
>
1Y
</button>
</div>
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<div class="box">
<div class="box-body">
<div id="audienceReport">
<apx-chart
[series]="chartOptions.series"
[chart]="chartOptions.chart"
[yaxis]="chartOptions.yaxis"
[xaxis]="chartOptions.xaxis"
[labels]="chartOptions.labels"
[stroke]="chartOptions.stroke"
[plotOptions]="chartOptions.plotOptions"
[markers]="chartOptions.markers"
[fill]="chartOptions.fill"
[tooltip]="chartOptions.tooltip"
[legend]="chartOptions.legend"
[colors]="chartOptions.colors"
></apx-chart>
</div>
</div>
</div>
</div>
</div>
</div>
import { CommonModule } from '@angular/common';
import { ChangeDetectorRef, Component, OnInit, Renderer2, ElementRef } from '@angular/core';
import { NgApexchartsModule } from 'ng-apexcharts';
import { DashboardService } from './../../services/dashboard.service';
import { EquipmentService } from './../../services/equirement.service';
import { ProjectService } from './../../services/project.service';
import { UserService } from './../../services/user.service';
import { ChangeDetectorRef, Component, ElementRef, Renderer2, ViewChild } from '@angular/core';
import { RouterModule } from '@angular/router';
import ApexCharts from 'apexcharts'
import { SharedModule } from '../../../shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { ActivatedRoute, Router } from '@angular/router';
import { CompanyService } from '../../services/company.service';
import { NgApexchartsModule } from 'ng-apexcharts';
import { SimplebarAngularModule } from 'simplebar-angular';
import { CommonModule } from '@angular/common';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { NgSelectModule } from '@ng-select/ng-select';
import { FormsModule } from '@angular/forms';
import { MatPaginator } from '@angular/material/paginator';
import { FileItem, FileUploader, FileUploadModule, ParsedResponseHeaders } from 'ng2-file-upload';
import { UserProfileModel } from '../../models/user.model';
import { UserRoleModel } from '../../models/user-role-model';
import { TokenService } from '../../../shared/services/token.service';
import { ProjectService } from '../../services/project.service';
import { environment } from '../../../../environments/environment';
import swal from 'sweetalert';
import { ProjectModel } from '../../models/project.model';
import { EquipmentModel } from '../../models/equipments.model';
import { DashboardModel } from '../../models/dasbord.model';
@Component({
selector: 'app-home-installer',
templateUrl: './home-installer.component.html',
standalone: true,
imports: [CommonModule, SharedModule, NgApexchartsModule, TranslateModule],
imports: [RouterModule, SharedModule, NgApexchartsModule, SimplebarAngularModule, CommonModule,
SharedModule,
TranslateModule,
NgSelectModule,
FormsModule,
MatPaginator,
FileUploadModule],
styleUrls: ['./home-installer.component.css']
})
export class HomeInstallerComponent {
@ViewChild('closeModal') public childModal?: ElementRef;
@ViewChild('modalDetail') public modalDetail?: ElementRef;
action = "new";
rawData: any[];
allSelected = false;
someSelected = false;
startDate: string = '';
endDate: string = '';
selectedProjects: string[] = [];
selectedEquipmentType: string = 'ALL';
isDropdownOpen = false;
projectSelection: { [key: string]: boolean } = {};
confirmPassword = ""
dashbordList:string[] = [];
equipmentList: EquipmentModel[] = []
projectList: ProjectModel[] = []
itemsList: UserProfileModel[] = []
filterList: UserProfileModel[] = []
selectModel: UserProfileModel = new UserProfileModel()
selectedItems = new Map<string, boolean>();
roleList: UserRoleModel[] = []
empList: UserProfileModel[] = []
descName = 'engName'
pageIndex = 0;
uploaderProfile: FileUploader | undefined;
uploadErrorMsg: string = "";
dashboardModel: DashboardModel
get searchTerm(): string {
return this._searchTerm;
}
set searchTerm(val: string) {
this.pageIndex = 0;
this.allSelected = false
this._searchTerm = val;
if (val != '') {
this.filterList = this.filter(val);
} else {
this.updatePagedItems()
}
}
_searchTerm = "";
chartOptions1:any;
chartOptions2:any;
chartOptions3:any
......@@ -88,7 +151,7 @@ public series: ApexAxisChartSeries = [];
type: 'datetime',
},
};
constructor(private el: ElementRef, private renderer: Renderer2,private cdr: ChangeDetectorRef) {
constructor(private el: ElementRef, private renderer: Renderer2, private cdr: ChangeDetectorRef, private userService: UserService, public translate: TranslateService, private tokenService: TokenService, private ProjectService: ProjectService, private EquipmentService: EquipmentService,private DashboardService:DashboardService) {
this.chartOptions9 = {
series: [
......@@ -754,6 +817,308 @@ public series: ApexAxisChartSeries = [];
}
this.uploadConfig()
}
uploadConfig() {
this.uploaderProfile = new FileUploader({
url: environment.baseUrl + "/api/upload-image",
isHTML5: true,
authToken: this.tokenService.getToken()!,
});
this.uploaderProfile.onAfterAddingFile = (fileItem: FileItem) => {
fileItem.withCredentials = false;
this.uploadErrorMsg = "";
while (this.uploaderProfile!.queue.length > 1) {
this.uploaderProfile!.queue[0].remove();
}
if (fileItem.file.size > 5000000) {
this.uploadErrorMsg = "maximum file size 5mb.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
fileItem.isCancel = true;
return;
}
if (fileItem.file.type!.indexOf("image") === -1) {
this.uploadErrorMsg = "please upload image only.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
fileItem.isCancel = true;
return;
}
fileItem.upload();
};
this.uploaderProfile.onCompleteItem = (
item: FileItem,
response: string,
status: number,
headers: ParsedResponseHeaders
) => {
if (item.isSuccess) {
const res = JSON.parse(response);
console.log("res", res);
this.selectModel.picture = res.filename
swal(res.message, "บันทึกสำเร็จ", "success");
} else {
this.uploadErrorMsg = "cannot upload file.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
}
};
}
onProjectCheckboxChange(event: any) {
const value = event.target.value;
if (event.target.checked) {
this.selectedProjects.push(value);
} else {
this.selectedProjects = this.selectedProjects.filter(p => p !== value);
}
}
toggleDropdown() {
this.isDropdownOpen = !this.isDropdownOpen;
}
getdasbord(){
this.DashboardService.getDashboard(this.startDate, this.endDate,)
.subscribe(data => {
console.log('Dashboard Data:', data);
});
}
getSelectedLabel(): string {
const selectedIds = Object.keys(this.projectSelection).filter(
id => this.projectSelection[id]
);
if (selectedIds.length === 0) return 'เลือกโปรเจค';
if (selectedIds.length === this.projectList.length) return 'โปรเจคทั้งหมด';
// ดึงชื่อจริงจาก projectList
const selectedNames = this.projectList
.filter(project => selectedIds.includes(project.project_name))
.map(project => project.project_name);
return selectedNames.join(', ');
}
ngOnInit(): void {
this.userService.getLists().subscribe(result => {
this.itemsList = result
this.updatePagedItems()
})
this.ProjectService.getLists().subscribe(result => {
this.projectList = result
})
this.EquipmentService.getLists().subscribe(result => {
this.equipmentList = result
})
this.DashboardService.getDashboard().subscribe(result => {
this.dashboardModel = result
console.log(this.dashboardModel)
})
}
filter(v: string) {
return this.itemsList?.filter(
(x) =>
x.memberId?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.username?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.email?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.phoneNumber?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getRole()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getStatus()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getFullname()?.toLowerCase().indexOf(v.toLowerCase()) !== -1
);
}
delete(item: UserProfileModel) {
swal({
title: "Are you sure?",
text: "You won't be able to revert this!",
icon: "warning",
dangerMode: true,
buttons: ["Cancel", "Yes,Delete it!"],
})
.then((willDelete: any) => {
if (willDelete) {
this.userService.delete(item).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit()
})
}
});
}
new() {
this.action = 'add'
this.selectModel = new UserProfileModel()
}
view(item: UserProfileModel) {
this.action = 'edit'
this.confirmPassword = ''
this.selectModel = new UserProfileModel(item)
console.log(this.selectModel)
}
save() {
swal({
title: "Are you sure?",
text: "คุณต้องการบันทึกหรือไม่",
icon: "warning",
dangerMode: false,
buttons: ["Cancel", "Confirm"],
})
.then((willDelete: any) => {
if (willDelete) {
if (this.action == 'add') {
this.userService.save(this.selectModel).subscribe(result => {
console.log(result)
swal("Save Success!!", "บันทึกข้อมูลสมาชิก", "success");
this.ngOnInit()
this.childModal?.nativeElement.click()
})
} else if (this.action == 'edit') {
this.userService.update(this.selectModel).subscribe(result => {
console.log(result)
swal("Update Success!!", "บันทึกข้อมูลสมาชิก", "success");
this.ngOnInit()
this.childModal?.nativeElement.click()
})
}
}
});
}
applyFilters() {
const selectedProjects = Object.keys(this.projectSelection).filter(p => this.projectSelection[p]);
// Filter your full data here
const filteredData = this.rawData.filter(item => {
return (!this.startDate || item.date >= this.startDate) &&
(!this.endDate || item.date <= this.endDate) &&
(selectedProjects.length === 0 || selectedProjects.includes(item.project_name)) &&
(this.selectedEquipmentType === 'ALL' || item.equipment_type === this.selectedEquipmentType);
});
}
updatePagedItems() {
const startIndex = this.pageIndex * 10;
const endIndex = startIndex + 10;
this.filterList = this.itemsList.slice(startIndex, endIndex);
}
toggleAll(event: any) {
this.allSelected = event.target.checked;
this.selectedItems.clear();
this.itemsList.forEach(item => {
this.selectedItems.set(item.memberId, this.allSelected);
});
this.someSelected = this.itemsList.some(item => this.selectedItems.get(item.memberId));
}
onCheckboxChange(memberId: string) {
const isSelected = this.selectedItems.get(memberId) || false;
this.selectedItems.set(memberId, !isSelected);
this.allSelected = this.itemsList.every(item => this.selectedItems.get(item.memberId));
this.someSelected = this.itemsList.some(item => this.selectedItems.get(item.memberId));
}
deleteSelect() {
let employeeInfo = '';
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
employeeInfo += `${this.translate.instant('Fullname')}: ${user.getFullname()}\n`;
}
}
});
swal({
title: "Are you sure?",
text: employeeInfo,
icon: "warning",
dangerMode: true,
buttons: ["Cancel", "Yes, Delete it!"],
})
.then((willDelete: any) => {
if (willDelete) {
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
this.userService.delete(user).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit();
});
}
}
});
}
});
}
adjustSelect(status: number) {
let title = "Are you sure?"
let employeeInfo = ''; // ตัวแปรสำหรับเก็บข้อมูลพนักงาน
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
employeeInfo += `${this.translate.instant('Fullname')}: ${user.getFullname()}\n`;
}
}
});
swal({
title: title,
text: employeeInfo,
icon: "warning",
dangerMode: false,
buttons: ["Cancel", "Confirm"],
})
.then((willDelete: any) => {
if (willDelete) {
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
user.status = status
this.userService.update(user).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit();
});
}
}
});
}
});
}
filterEmp(empId: string) {
this.selectModel = this.empList.filter(e => e.memberId == empId)[0]
}
}
export interface DashboardModel {
period: Period;
summary: Summary[];
monthly_trends: Monthlytrend[];
equipment_distribution: Equipmentdistribution[];
borrow_return_line: Monthlytrend[];
}
export interface Equipmentdistribution {
category: string;
count: number;
}
export interface Monthlytrend {
period: string;
borrowed: number;
returned: number;
}
export interface Summary {
label: string;
value: number;
change: number;
}
export interface Period {
start: string;
end: string;
}
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { map } from 'rxjs';
import { DashboardModel } from '../models/dasbord.model';
@Injectable({
providedIn: 'root'
})
export class DashboardService {
apiBaseUrl = 'http://localhost:8000/admin/admin/dashboard';
constructor(private http: HttpClient) {}
getDashboard(startDate?: string, endDate?: string, projectId?: string) {
let params = new HttpParams();
if (startDate) params = params.set('start_date', startDate);
if (endDate) params = params.set('end_date', endDate);
if (projectId) params = params.set('project_id', projectId);
return this.http.get<DashboardModel>(this.apiBaseUrl, { params });
}
}
import { ClickOutsideDirective } from './click-outside.directive';
describe('ClickOutsideDirective', () => {
it('should create an instance', () => {
const directive = new ClickOutsideDirective();
expect(directive).toBeTruthy();
});
});
import { Directive } from '@angular/core';
@Directive({
selector: '[appClickOutside]',
standalone: true
})
export class ClickOutsideDirective {
constructor() { }
}
File added
File added
File added
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment