Commit 8e8e7ae4 by Nattana Chaiyamat

แปลภาษา หน้าจอใหม่ jobgrade jobgradegroup jobfamily

parent 066553f0
{
"turboConsoleLog.logMessagePrefix": "🥷🏿"
}
\ No newline at end of file
......@@ -38,6 +38,24 @@
(click)="currentPath = 5;pathTitle = ['menu.Organization','menu.JobDescription','JobLevelJL']">
{{'JobLevelJL' | translate}}
</a>
<a class="text-base font-medium hs-tab-active:text-lg hs-tab-active:font-bold hs-tab-active:border-secondary hs-tab-active:text-secondary pb-3 px-1 inline-flex items-center gap-2 border-b-[3px] border-transparent whitespace-nowrap text-gray-500 dark:text-white/70 hover:text-secondary"
href="javascript:void(0);" id="underline-item-6" data-hs-tab="#underline-6"
aria-controls="underline-6"
(click)="currentPath = 6;pathTitle = ['menu.Organization','menu.JobDescription','JobFamily']">
{{'JobFamily' | translate}}
</a>
<a class="text-base font-medium hs-tab-active:text-lg hs-tab-active:font-bold hs-tab-active:border-secondary hs-tab-active:text-secondary pb-3 px-1 inline-flex items-center gap-2 border-b-[3px] border-transparent whitespace-nowrap text-gray-500 dark:text-white/70 hover:text-secondary"
href="javascript:void(0);" id="underline-item-7" data-hs-tab="#underline-7"
aria-controls="underline-7"
(click)="currentPath = 7;pathTitle = ['menu.Organization','menu.JobDescription','JobGradeGroup']">
{{'JobGradeGroup' | translate}}
</a>
<a class="text-base font-medium hs-tab-active:text-lg hs-tab-active:font-bold hs-tab-active:border-secondary hs-tab-active:text-secondary pb-3 px-1 inline-flex items-center gap-2 border-b-[3px] border-transparent whitespace-nowrap text-gray-500 dark:text-white/70 hover:text-secondary"
href="javascript:void(0);" id="underline-item-8" data-hs-tab="#underline-8"
aria-controls="underline-8"
(click)="currentPath = 8;pathTitle = ['menu.Organization','menu.JobDescription','JobGrade']">
{{'JobGrade' | translate}}
</a>
</nav>
</div>
<div class="mt-3 px-2rem !-mt-3 pt-50px">
......@@ -60,6 +78,18 @@
aria-labelledby="underline-item-5">
<app-employee-level></app-employee-level>
</div>
<div *ngIf="currentPath == 6" id="underline-6" class="hidden" role="tabpanel"
aria-labelledby="underline-item-6">
<app-job-family></app-job-family>
</div>
<div *ngIf="currentPath == 7" id="underline-7" class="hidden" role="tabpanel"
aria-labelledby="underline-item-7">
<app-job-grade-group></app-job-grade-group>
</div>
<div *ngIf="currentPath == 8" id="underline-8" class="hidden" role="tabpanel"
aria-labelledby="underline-item-8">
<app-job-grade></app-job-grade>
</div>
</div>
</div>
</div>
\ No newline at end of file
<div class="w-full min-height-50px mb-10px justify-between items-center">
<div class="flex justify-end">
<div class="px-1">
<div class="relative shadow-md">
<input type="text" class="ti-form-input ltr:pl-11 rtl:pr-11 focus:z-10 "
[placeholder]="'SearchByNoOrName' | translate" [(ngModel)]="search">
<div
class="absolute inset-y-0 ltr:left-0 rtl:right-0 flex items-center pointer-events-none z-20 ltr:pl-4 rtl:pr-4">
<i class="ri-search-line text-gray"></i>
</div>
</div>
</div>
<div class="px-1">
<button type="button"
class=" h-45px ti-btn ti-btn bg-pink-500/10 text-pink-500 hover:text-white hover:bg-pink-500 ring-offset-white focus:ring-pink-500 dark:focus:ring-offset-white/10 h-10 m-0 shadow-md"
data-hs-overlay="#job-family-component-upload-modal"
(click)="fileInput.value = '';selectedFile=null;selectedFileName = 'กรุณาเลือกไฟล์'">
<i class="ti ti-file-plus"></i>
{{'Import' | translate}}
</button>
</div>
<div class="px-1">
<button type="button" class="ti-btn ti-btn-soft-secondary h-45px m-0 shadow-md"
(click)="currentModal='add';selectPosition();openDialog()">
<i class="ri-add-line"></i>
{{'Add' | translate}}
</button>
</div>
<div class="px-1">
<button href="javascript:void(0);" class="ti-btn ti-btn-soft-danger h-45px m-0 shadow-md"
(click)="currentModal='delete';selectPosition();deletePosition()">
<i class="ri-delete-bin-6-line"></i>
{{'Delete' | translate}}
</button>
</div>
</div>
</div>
<div class="page px-rem">
<app-datagrid-syncfution [searchSettings]="searchSettings" [searchText]="search" [dataSource]="position.dataList"
[columns]="columns" [selectedItems]="selectedItems"
(sendSelectData)="currentModal='edit';selectPosition($event);openDialog()"
(sendSelectedItems)="onSelectItemChange($event)">
</app-datagrid-syncfution>
</div>
<ng-template #jobFamilyModal let-modal>
<h3 mat-dialog-title>
{{(currentModal=='add'?'AddJobFamily':'EditJobFamily') | translate}}
</h3>
<div class="w-full flex justify-end mb-1rem">
<div class="absolute flex">
<div class="px-1">
<button type="button" class="ti-btn ti-btn-soft-indigo h-45px m-0 shadow-md" (click)="selectPosition()">
<i class="ti ti-eraser text-base"></i>
{{'Clear' |translate}}
</button>
</div>
</div>
</div>
<mat-dialog-content>
<label for="input-label" class="ti-form-label mt-2rem">
{{'JobFamilyCode' | translate}}
<span class="text-danger">
*
<ng-container *ngIf="currentModal=='add'&&checkPrimary()">
{{'DuplicateJobFamilyCode' | translate}}
</ng-container>
</span></label>
<input type="text" id="input-label" class="ti-form-input w-1/2 "
[ngClass]="{'bg-input-readonly':currentModal=='edit'}" [readonly]="currentModal=='edit'"
[(ngModel)]="position.select.positionId">
<label for="detail_th" class="ti-form-label mt-2rem">{{'JobFamilyNameThai' | translate}}<span
class="text-danger">*</span></label>
<input type="text" id="detail_th" class="ti-form-input h-16" [(ngModel)]="position.select.tdesc">
<label for="detail_eng" class="ti-form-label mt-2rem">{{'JobFamilyNameEng' | translate}}<span
class="text-danger">*</span></label>
<input type="text" id="detail_eng" class="ti-form-input h-16" [(ngModel)]="position.select.edesc">
<label for="detail_short" class="ti-form-label mt-2rem">{{'JobFamilyAbbr' | translate}}<span
class="text-danger">*</span></label>
<input type="text" id="detail_short" class="ti-form-input h-16" [(ngModel)]="position.select.edesc">
<div class="grid grid-cols-12 gap-x-6 mt-2rem">
<label class="col-span-3 ti-form-label text-primary mt-2 align-center">{{'Image' |
translate}}</label>
<div class="flex flex-row col-span-5" style="align-items: end;">
<div style="width: 10rem;">
<div *ngIf="imgLoading" class="ti-spinner w-8 h-8 text-secondary mx-1" role="status"
aria-label="loading" style="height: 9rem;width: 9rem;">
<span class="sr-only">Loading...</span>
</div>
<!-- [src]="employee.select.picture?getImg(employee.select.picture):'./assets/img/users/defaultperson.jpg'" -->
<img *ngIf="!imgLoading" [src]="'./assets/img/users/defaultperson.jpg'"
(error)="onImageError($event)" class="rounded-full ring-4 ring-white/10 mx-auto object-cover"
id="profile-img" alt="profile-img" style="height: 10rem;width: 10rem;">
</div>
<div *ngIf="!imgLoading" class="relative" style="margin-left:-30px">
<i class="ri ri-pencil-line cursor-pointer" (click)="fileImg.click()"></i>
<input #fileImg id="fileImg" type="file" (change)="onImgSelected($event)" hidden>
<i class="ri-delete-bin-6-line text-danger cursor-pointer"></i>
<!-- (click)="employee.select.picture = ''"> -->
</div>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button type="button" mat-button [mat-dialog-close]
class="hs-dropdown-toggle ti-btn ti-border font-medium bg-white text-gray-700 shadow-sm align-middle hover:bg-gray-50 focus:ring-offset-white focus:ring-primary dark:bg-bgdark dark:hover:bg-black/20 dark:border-white/10 dark:text-white/70 dark:hover:text-white dark:focus:ring-offset-white/10">
{{'Back' | translate}}
</button>
<button type="button" class="ti-btn ti-btn-success" mat-button (click)="addPosition()"
[class.ti-btn-disabled]="!position.select.positionId||!position.select.tdesc||(currentModal=='add'&&checkPrimary())"
[disabled]="!position.select.positionId||!position.select.tdesc||(currentModal=='add'&&checkPrimary())">
{{'SaveData' | translate}}
</button>
</mat-dialog-actions>
</ng-template>
<div id="job-family-component-upload-modal" class="hs-overlay hidden ti-modal">
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out rounded-md">
<div class="ti-modal-header bg-primary !rounded-none !rounded-t-sm">
<h5 class="text-xxl font-bold text-white">
{{'ImportJobFamily' | translate}}
</h5>
</div>
<div class="ti-modal-body max-h-full overflow-hidden ti-modal-content !rounded-t-none !rounded-b-sm">
<h1 class="mt-2" style="text-align: center;">{{'File' | translate}}</h1>
<div class="mt-2 p-2">
<div class="flex rounded-md">
<input #fileInput id="fileInput" type="file" (change)="onFileSelected($event)" hidden>
<input type="text" [value]="selectedFileName | translate" readonly (click)="fileInput.click()"
class="ti-form-input rounded-none ltr:rounded-l-md rtl:rounded-r-md focus:z-10 cursor-pointer">
<button type="button" (click)="fileInput.click()"
class="inline-flex flex-shrink-0 justify-center items-center h-[2.875rem] w-[2.875rem] ltr:rounded-r-md rtl:rounded-l-md border border-transparent font-semibold bg-secondary text-white hover:bg-secondary focus:z-10 focus:outline-none focus:ring-0 focus:ring-secondary transition-all text-sm">
<i class="ti ti-upload"></i>
</button>
</div>
<div class="flex justify-center mt-2rem ">
<h1 class="cursor-pointer justify-center -mb-px inline-flex items-center gap-2 font-weight-500 font-size-12px
text-center text-secondary border-secondary border-b-2 align-items-end" (click)="downloadFile()">
{{'DownloadSampleFile' | translate}}</h1>
</div>
<div class="flex justify-center mt-2rem mb-1rem space-x-4">
<button type="submit" class="ti-btn ti-btn-secondary"
data-hs-overlay="#job-family-component-upload-modal" [class.ti-btn-disabled]="!selectedFile"
(click)="uploadFile()" [disabled]="!selectedFile" [disabled]="!selectedFile">
{{'Upload' | translate}}
</button>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ColumnModel } from '@syncfusion/ej2-grids';
import { ToastrService } from 'ngx-toastr';
import { MyPositionModel, PositionModel } from 'src/app/shared/model/position.model';
import { FileService } from 'src/app/shared/services/file.service';
import { PositionService } from 'src/app/shared/services/position.service';
import Swal from 'sweetalert2';
@Component({
selector: 'app-job-family',
templateUrl: './job-family.component.html',
styleUrls: ['./job-family.component.scss']
})
export class JobFamilyComponent implements OnInit {
selectedFile: File | null = null;
selectedFileName: string = 'selectedFileName';
currentModal: 'add' | 'edit' | 'delete' = 'add'
position: { loading: boolean, select: PositionModel, dataList: PositionModel[] } = { loading: false, select: new MyPositionModel(), dataList: [] }
columns: ColumnModel[] = [{
field: "positionId",
headerText: "JobFamilyCode",
type: "string",
isPrimaryKey: true,
},
{
field: "tdesc",
headerText: "JobFamilyNameThai",
type: "string"
},
{
field: "edesc",
headerText: "JobFamilyNameEng",
type: "string"
}]
searchSettings = {
fields: ['positionId', 'tdesc', 'edesc'],
operator: 'contains',
ignoreCase: false
};
search = ''
selectedItems: { key: string, count: number, data: Map<string, boolean> } = { key: '', count: 0, data: new Map<string, boolean>() };
@ViewChild("jobFamilyModal") jobFamilyModal: any;
dialogRef: any
selectedImg: File | null = null;
imgLoading = false
constructor(private positionService: PositionService,
private toastr: ToastrService,
private cdr: ChangeDetectorRef,
private fileService: FileService,
private dialog: MatDialog
) { }
ngOnInit(): void {
this.getPositionList()
}
openDialog() {
this.dialogRef = this.dialog.open(this.jobFamilyModal, {
width: '500px',
})
}
closeDialog() {
this.dialogRef.close()
}
onFileSelected(event: any) {
this.selectedFile = event.target.files.length > 0 ? event.target.files[0] : null;
this.selectedFileName = this.selectedFile?.name || "selectedFileName"
}
uploadFile() {
// if (!this.selectedFile) {
// alert('กรุณาเลือกไฟล์ก่อนอัปโหลด')
// return
// }
// const formData = new FormData();
// formData.append('file', this.selectedFile);
// this.position.loading = true
// this.fileService.uploadExcel(formData, 'mposition').subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges();
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges();
// }
// })
}
downloadFile() {
// const fileName = 'IMPORT_MPOSITION.xlsx'
// this.fileService.downloadTemplate(fileName).subscribe({
// next: response => {
// const url = window.URL.createObjectURL(response);
// const a = document.createElement("a");
// a.href = url;
// a.download = fileName;
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
// window.URL.revokeObjectURL(url);
// }, error: error => {
// this.showAlert(error.message, 'error')
// }
// })
}
getPositionList() {
this.position.loading = true
this.selectedItems.data.clear()
this.positionService.getList().subscribe({
next: response => {
this.position.dataList = response.map(x => {
this.selectedItems.data.set(x.positionId, false)
return new MyPositionModel(x)
})
this.selectedItems.key = 'positionId'
this.selectedItems.count = 0
this.position.loading = false
this.cdr.detectChanges();
}, error: error => {
this.position.loading = false
console.error('Error fetching employee types:', error);
this.cdr.detectChanges()
}
})
}
selectPosition(position?: PositionModel) {
if (position) {
this.position.select = new MyPositionModel(position)
} else if (this.currentModal == 'add') {
this.position.select = new MyPositionModel()
} else if (this.currentModal == 'edit') {
this.position.select = new MyPositionModel({ positionId: this.position.select.positionId })
}
}
addPosition() {
// Swal.fire({
// icon: 'question',
// title: 'แจ้งเตือน',
// text: 'ยืนยันการบันทึกข้อมูลหรือไม่',
// showCancelButton: true,
// confirmButtonText: 'ยืนยัน',
// }).then((result) => {
// if (result.isConfirmed) {
// this.position.loading = true
// this.positionService.post(this.position.select).subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// this.closeDialog()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// this.closeDialog()
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// this.closeDialog()
// }
// })
// }
// })
}
deletePosition() {
// if (this.numSelectItem() == 0) {
// this.showAlert('กรุณาเลือกข้อมูลที่จะลบ', 'error')
// return
// }
// Swal.fire({
// icon: 'question',
// title: 'แจ้งเตือน',
// text: 'ยืนยันการลบข้อมูลหรือไม่',
// showCancelButton: true,
// confirmButtonText: 'ลบข้อมูล',
// }).then((result) => {
// if (result.isConfirmed) {
// this.position.loading = true
// const selectedKeys = Array.from(this.selectedItems.data.keys());
// const body = this.position.dataList.filter(x => selectedKeys.includes(x.positionId) && this.selectedItems.data.get(x.positionId)).map(x => new MyPositionModel(x))
// this.positionService.delete(body).subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// }
// })
// }
// })
}
showAlert(text: string, type: 'success' | 'error') {
Swal.fire({
icon: type,
title: 'แจ้งเตือน',
text: text,
showCancelButton: false,
confirmButtonText: 'ยืนยัน',
})
}
checkPrimary() {
return this.position.dataList.find(x => x.positionId == this.position.select.positionId)
}
numSelectItem() {
const selectedKeys = Array.from(this.selectedItems.data.keys());
const num = this.position.dataList.filter(x => selectedKeys.includes(x.positionId) && this.selectedItems.data.get(x.positionId)).length
return num
}
onSelectItemChange(arg: any) {
this.selectedItems = arg
}
onImgSelected(event: any) {
this.selectedImg = event.target.files.length > 0 ? event.target.files[0] : null;
this.uploadImg()
}
uploadImg() {
if (this.selectedImg) {
this.imgLoading = true
const formData = new FormData();
formData.append('file', this.selectedImg);
this.fileService.uploadImg(formData).subscribe({
next: response => {
if (response.success) {
this.showAlert(response.message, 'success')
// this.employee.select.picture = response.resultObject
} else {
this.showAlert(response.message, 'error')
// this.employee.select.picture = ''
}
this.imgLoading = false
this.cdr.detectChanges()
}, error: error => {
this.showAlert(error.message, 'error')
// this.employee.select.picture = ''
this.imgLoading = false
this.cdr.detectChanges()
}
})
}
}
getImg(text: string) {
return this.fileService.getImg(text)
}
onImageError(event: Event) {
const imgElement = event.target as HTMLImageElement;
imgElement.src = './assets/img/users/defaultperson.jpg';
}
}
<div class="w-full min-height-50px mb-10px justify-between items-center">
<div class="flex justify-end">
<div class="px-1">
<div class="relative shadow-md">
<input type="text" class="ti-form-input ltr:pl-11 rtl:pr-11 focus:z-10 "
[placeholder]="'SearchByNoOrName' | translate" [(ngModel)]="search">
<div
class="absolute inset-y-0 ltr:left-0 rtl:right-0 flex items-center pointer-events-none z-20 ltr:pl-4 rtl:pr-4">
<i class="ri-search-line text-gray"></i>
</div>
</div>
</div>
<div class="px-1">
<button type="button"
class=" h-45px ti-btn ti-btn bg-pink-500/10 text-pink-500 hover:text-white hover:bg-pink-500 ring-offset-white focus:ring-pink-500 dark:focus:ring-offset-white/10 h-10 m-0 shadow-md"
data-hs-overlay="#job-grade-group-component-upload-modal"
(click)="fileInput.value = '';selectedFile=null;selectedFileName = 'กรุณาเลือกไฟล์'">
<i class="ti ti-file-plus"></i>
{{'Import' | translate}}
</button>
</div>
<div class="px-1">
<button type="button" class="ti-btn ti-btn-soft-secondary h-45px m-0 shadow-md"
(click)="currentModal='add';selectPosition();openDialog()">
<i class="ri-add-line"></i>
{{'Add' | translate}}
</button>
</div>
<div class="px-1">
<button href="javascript:void(0);" class="ti-btn ti-btn-soft-danger h-45px m-0 shadow-md"
(click)="currentModal='delete';selectPosition();deletePosition()">
<i class="ri-delete-bin-6-line"></i>
{{'Delete' | translate}}
</button>
</div>
</div>
</div>
<div class="page px-rem">
<app-datagrid-syncfution [searchSettings]="searchSettings" [searchText]="search" [dataSource]="position.dataList"
[columns]="columns" [selectedItems]="selectedItems"
(sendSelectData)="currentModal='edit';selectPosition($event);openDialog()"
(sendSelectedItems)="onSelectItemChange($event)">
</app-datagrid-syncfution>
</div>
<ng-template #jobGradeGroupModal let-modal>
<h3 mat-dialog-title>
{{(currentModal=='add'?'AddJobGradeGroup':'EditJobGradeGroup') | translate}}
</h3>
<div class="w-full flex justify-end mb-1rem">
<div class="absolute flex">
<div class="px-1">
<button type="button" class="ti-btn ti-btn-soft-indigo h-45px m-0 shadow-md" (click)="selectPosition()">
<i class="ti ti-eraser text-base"></i>
{{'Clear' |translate}}
</button>
</div>
</div>
</div>
<mat-dialog-content>
<label for="input-label" class="ti-form-label mt-2rem">
{{'JobGradeGroupCode' | translate}}
<span class="text-danger">
*
<ng-container *ngIf="currentModal=='add'&&checkPrimary()">
{{'DuplicateJobGradeGroupCode' | translate}}
</ng-container>
</span></label>
<input type="text" id="input-label" class="ti-form-input w-1/2 "
[ngClass]="{'bg-input-readonly':currentModal=='edit'}" [readonly]="currentModal=='edit'"
[(ngModel)]="position.select.positionId">
<label for="detail_th" class="ti-form-label mt-2rem">{{'JobGradeGroupDescThai' | translate}}<span
class="text-danger">*</span></label>
<input type="text" id="detail_th" class="ti-form-input h-16" [(ngModel)]="position.select.tdesc">
<label for="detail_eng" class="ti-form-label mt-2rem">{{'JobGradeGroupDescEng' | translate}}</label>
<input type="text" id="detail_eng" class="ti-form-input h-16" [(ngModel)]="position.select.edesc">
</mat-dialog-content>
<mat-dialog-actions align="end">
<button type="button" mat-button [mat-dialog-close]
class="hs-dropdown-toggle ti-btn ti-border font-medium bg-white text-gray-700 shadow-sm align-middle hover:bg-gray-50 focus:ring-offset-white focus:ring-primary dark:bg-bgdark dark:hover:bg-black/20 dark:border-white/10 dark:text-white/70 dark:hover:text-white dark:focus:ring-offset-white/10">
{{'Back' | translate}}
</button>
<button type="button" class="ti-btn ti-btn-success" mat-button (click)="addPosition()"
[class.ti-btn-disabled]="!position.select.positionId||!position.select.tdesc||(currentModal=='add'&&checkPrimary())"
[disabled]="!position.select.positionId||!position.select.tdesc||(currentModal=='add'&&checkPrimary())">
{{'SaveData' | translate}}
</button>
</mat-dialog-actions>
</ng-template>
<div id="job-grade-group-component-upload-modal" class="hs-overlay hidden ti-modal">
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out rounded-md">
<div class="ti-modal-header bg-primary !rounded-none !rounded-t-sm">
<h5 class="text-xxl font-bold text-white">
{{'ImportJobGradeGroup' | translate}}
</h5>
</div>
<div class="ti-modal-body max-h-full overflow-hidden ti-modal-content !rounded-t-none !rounded-b-sm">
<h1 class="mt-2" style="text-align: center;">{{'File' | translate}}</h1>
<div class="mt-2 p-2">
<div class="flex rounded-md">
<input #fileInput id="fileInput" type="file" (change)="onFileSelected($event)" hidden>
<input type="text" [value]="selectedFileName | translate" readonly (click)="fileInput.click()"
class="ti-form-input rounded-none ltr:rounded-l-md rtl:rounded-r-md focus:z-10 cursor-pointer">
<button type="button" (click)="fileInput.click()"
class="inline-flex flex-shrink-0 justify-center items-center h-[2.875rem] w-[2.875rem] ltr:rounded-r-md rtl:rounded-l-md border border-transparent font-semibold bg-secondary text-white hover:bg-secondary focus:z-10 focus:outline-none focus:ring-0 focus:ring-secondary transition-all text-sm">
<i class="ti ti-upload"></i>
</button>
</div>
<div class="flex justify-center mt-2rem ">
<h1 class="cursor-pointer justify-center -mb-px inline-flex items-center gap-2 font-weight-500 font-size-12px
text-center text-secondary border-secondary border-b-2 align-items-end" (click)="downloadFile()">
{{'DownloadSampleFile' | translate}}</h1>
</div>
<div class="flex justify-center mt-2rem mb-1rem space-x-4">
<button type="submit" class="ti-btn ti-btn-secondary"
data-hs-overlay="#job-grade-group-component-upload-modal"
[class.ti-btn-disabled]="!selectedFile" (click)="uploadFile()" [disabled]="!selectedFile"
[disabled]="!selectedFile">
{{'Upload' | translate}}
</button>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ColumnModel } from '@syncfusion/ej2-grids';
import { ToastrService } from 'ngx-toastr';
import { MyPositionModel, PositionModel } from 'src/app/shared/model/position.model';
import { FileService } from 'src/app/shared/services/file.service';
import { PositionService } from 'src/app/shared/services/position.service';
import Swal from 'sweetalert2';
@Component({
selector: 'app-job-grade-group',
templateUrl: './job-grade-group.component.html',
styleUrls: ['./job-grade-group.component.scss']
})
export class JobGradeGroupComponent implements OnInit {
selectedFile: File | null = null;
selectedFileName: string = 'selectedFileName';
currentModal: 'add' | 'edit' | 'delete' = 'add'
position: { loading: boolean, select: PositionModel, dataList: PositionModel[] } = { loading: false, select: new MyPositionModel(), dataList: [] }
columns: ColumnModel[] = [{
field: "positionId",
headerText: "JobGradeGroupCode",
type: "string",
isPrimaryKey: true,
},
{
field: "tdesc",
headerText: "JobGradeGroupDescThai",
type: "string"
},
{
field: "edesc",
headerText: "JobGradeGroupDescEng",
type: "string"
}]
searchSettings = {
fields: ['positionId', 'tdesc', 'edesc'],
operator: 'contains',
ignoreCase: false
};
search = ''
selectedItems: { key: string, count: number, data: Map<string, boolean> } = { key: '', count: 0, data: new Map<string, boolean>() };
@ViewChild("jobGradeGroupModal") jobGradeGroupModal: any;
dialogRef: any
constructor(private positionService: PositionService,
private toastr: ToastrService,
private cdr: ChangeDetectorRef,
private fileService: FileService,
private dialog: MatDialog
) { }
ngOnInit(): void {
this.getPositionList()
}
openDialog() {
this.dialogRef = this.dialog.open(this.jobGradeGroupModal, {
width: '500px',
})
}
closeDialog() {
this.dialogRef.close()
}
onFileSelected(event: any) {
this.selectedFile = event.target.files.length > 0 ? event.target.files[0] : null;
this.selectedFileName = this.selectedFile?.name || "selectedFileName"
}
uploadFile() {
// if (!this.selectedFile) {
// alert('กรุณาเลือกไฟล์ก่อนอัปโหลด')
// return
// }
// const formData = new FormData();
// formData.append('file', this.selectedFile);
// this.position.loading = true
// this.fileService.uploadExcel(formData, 'mposition').subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges();
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges();
// }
// })
}
downloadFile() {
// const fileName = 'IMPORT_MPOSITION.xlsx'
// this.fileService.downloadTemplate(fileName).subscribe({
// next: response => {
// const url = window.URL.createObjectURL(response);
// const a = document.createElement("a");
// a.href = url;
// a.download = fileName;
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
// window.URL.revokeObjectURL(url);
// }, error: error => {
// this.showAlert(error.message, 'error')
// }
// })
}
getPositionList() {
this.position.loading = true
this.selectedItems.data.clear()
this.positionService.getList().subscribe({
next: response => {
this.position.dataList = response.map(x => {
this.selectedItems.data.set(x.positionId, false)
return new MyPositionModel(x)
})
this.selectedItems.key = 'positionId'
this.selectedItems.count = 0
this.position.loading = false
this.cdr.detectChanges();
}, error: error => {
this.position.loading = false
console.error('Error fetching employee types:', error);
this.cdr.detectChanges()
}
})
}
selectPosition(position?: PositionModel) {
if (position) {
this.position.select = new MyPositionModel(position)
} else if (this.currentModal == 'add') {
this.position.select = new MyPositionModel()
} else if (this.currentModal == 'edit') {
this.position.select = new MyPositionModel({ positionId: this.position.select.positionId })
}
}
addPosition() {
// Swal.fire({
// icon: 'question',
// title: 'แจ้งเตือน',
// text: 'ยืนยันการบันทึกข้อมูลหรือไม่',
// showCancelButton: true,
// confirmButtonText: 'ยืนยัน',
// }).then((result) => {
// if (result.isConfirmed) {
// this.position.loading = true
// this.positionService.post(this.position.select).subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// this.closeDialog()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// this.closeDialog()
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// this.closeDialog()
// }
// })
// }
// })
}
deletePosition() {
// if (this.numSelectItem() == 0) {
// this.showAlert('กรุณาเลือกข้อมูลที่จะลบ', 'error')
// return
// }
// Swal.fire({
// icon: 'question',
// title: 'แจ้งเตือน',
// text: 'ยืนยันการลบข้อมูลหรือไม่',
// showCancelButton: true,
// confirmButtonText: 'ลบข้อมูล',
// }).then((result) => {
// if (result.isConfirmed) {
// this.position.loading = true
// const selectedKeys = Array.from(this.selectedItems.data.keys());
// const body = this.position.dataList.filter(x => selectedKeys.includes(x.positionId) && this.selectedItems.data.get(x.positionId)).map(x => new MyPositionModel(x))
// this.positionService.delete(body).subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// }
// })
// }
// })
}
showAlert(text: string, type: 'success' | 'error') {
Swal.fire({
icon: type,
title: 'แจ้งเตือน',
text: text,
showCancelButton: false,
confirmButtonText: 'ยืนยัน',
})
}
checkPrimary() {
return this.position.dataList.find(x => x.positionId == this.position.select.positionId)
}
numSelectItem() {
const selectedKeys = Array.from(this.selectedItems.data.keys());
const num = this.position.dataList.filter(x => selectedKeys.includes(x.positionId) && this.selectedItems.data.get(x.positionId)).length
return num
}
onSelectItemChange(arg: any) {
this.selectedItems = arg
}
}
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ColumnModel } from '@syncfusion/ej2-grids';
import { ToastrService } from 'ngx-toastr';
import { MyPositionModel, PositionModel } from 'src/app/shared/model/position.model';
import { FileService } from 'src/app/shared/services/file.service';
import { PositionService } from 'src/app/shared/services/position.service';
import Swal from 'sweetalert2';
@Component({
selector: 'app-job-grade',
templateUrl: './job-grade.component.html',
styleUrls: ['./job-grade.component.scss']
})
export class JobGradeComponent implements OnInit {
selectedFile: File | null = null;
selectedFileName: string = 'selectedFileName';
currentModal: 'add' | 'edit' | 'delete' = 'add'
position: { loading: boolean, select: PositionModel, dataList: PositionModel[] } = { loading: false, select: new MyPositionModel(), dataList: [] }
columns: ColumnModel[] = [{
field: "positionId",
headerText: "JobGradeCode",
type: "string",
isPrimaryKey: true,
},
{
field: "tdesc",
headerText: "JobGradeDescThai",
type: "string"
},
{
field: "edesc",
headerText: "JobGradeDescEng",
type: "string"
}]
searchSettings = {
fields: ['positionId', 'tdesc', 'edesc'],
operator: 'contains',
ignoreCase: false
};
search = ''
selectedItems: { key: string, count: number, data: Map<string, boolean> } = { key: '', count: 0, data: new Map<string, boolean>() };
@ViewChild("jobGradeModal") jobGradeModal: any;
dialogRef: any
@ViewChild('jobGradeGroupModal') jobGradeGroupModal: any
jobGradeGroupDialogRef: any
constructor(private positionService: PositionService,
private toastr: ToastrService,
private cdr: ChangeDetectorRef,
private fileService: FileService,
private dialog: MatDialog
) { }
ngOnInit(): void {
this.getPositionList()
}
openDialog() {
this.dialogRef = this.dialog.open(this.jobGradeModal, {
width: '500px',
})
}
closeDialog() {
this.dialogRef.close()
}
onFileSelected(event: any) {
this.selectedFile = event.target.files.length > 0 ? event.target.files[0] : null;
this.selectedFileName = this.selectedFile?.name || "selectedFileName"
}
uploadFile() {
// if (!this.selectedFile) {
// alert('กรุณาเลือกไฟล์ก่อนอัปโหลด')
// return
// }
// const formData = new FormData();
// formData.append('file', this.selectedFile);
// this.position.loading = true
// this.fileService.uploadExcel(formData, 'mposition').subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges();
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges();
// }
// })
}
downloadFile() {
// const fileName = 'IMPORT_MPOSITION.xlsx'
// this.fileService.downloadTemplate(fileName).subscribe({
// next: response => {
// const url = window.URL.createObjectURL(response);
// const a = document.createElement("a");
// a.href = url;
// a.download = fileName;
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
// window.URL.revokeObjectURL(url);
// }, error: error => {
// this.showAlert(error.message, 'error')
// }
// })
}
getPositionList() {
this.position.loading = true
this.selectedItems.data.clear()
this.positionService.getList().subscribe({
next: response => {
this.position.dataList = response.map(x => {
this.selectedItems.data.set(x.positionId, false)
return new MyPositionModel(x)
})
this.selectedItems.key = 'positionId'
this.selectedItems.count = 0
this.position.loading = false
this.cdr.detectChanges();
}, error: error => {
this.position.loading = false
console.error('Error fetching employee types:', error);
this.cdr.detectChanges()
}
})
}
selectPosition(position?: PositionModel) {
if (position) {
this.position.select = new MyPositionModel(position)
} else if (this.currentModal == 'add') {
this.position.select = new MyPositionModel()
} else if (this.currentModal == 'edit') {
this.position.select = new MyPositionModel({ positionId: this.position.select.positionId })
}
}
addPosition() {
// Swal.fire({
// icon: 'question',
// title: 'แจ้งเตือน',
// text: 'ยืนยันการบันทึกข้อมูลหรือไม่',
// showCancelButton: true,
// confirmButtonText: 'ยืนยัน',
// }).then((result) => {
// if (result.isConfirmed) {
// this.position.loading = true
// this.positionService.post(this.position.select).subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// this.closeDialog()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// this.closeDialog()
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// this.closeDialog()
// }
// })
// }
// })
}
deletePosition() {
// if (this.numSelectItem() == 0) {
// this.showAlert('กรุณาเลือกข้อมูลที่จะลบ', 'error')
// return
// }
// Swal.fire({
// icon: 'question',
// title: 'แจ้งเตือน',
// text: 'ยืนยันการลบข้อมูลหรือไม่',
// showCancelButton: true,
// confirmButtonText: 'ลบข้อมูล',
// }).then((result) => {
// if (result.isConfirmed) {
// this.position.loading = true
// const selectedKeys = Array.from(this.selectedItems.data.keys());
// const body = this.position.dataList.filter(x => selectedKeys.includes(x.positionId) && this.selectedItems.data.get(x.positionId)).map(x => new MyPositionModel(x))
// this.positionService.delete(body).subscribe({
// next: response => {
// if (response.success) {
// this.showAlert(response.message, 'success')
// this.getPositionList()
// } else {
// this.showAlert(response.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// }
// }, error: error => {
// this.showAlert(error.message, 'error')
// this.position.loading = false
// this.cdr.detectChanges()
// }
// })
// }
// })
}
showAlert(text: string, type: 'success' | 'error') {
Swal.fire({
icon: type,
title: 'แจ้งเตือน',
text: text,
showCancelButton: false,
confirmButtonText: 'ยืนยัน',
})
}
checkPrimary() {
return this.position.dataList.find(x => x.positionId == this.position.select.positionId)
}
numSelectItem() {
const selectedKeys = Array.from(this.selectedItems.data.keys());
const num = this.position.dataList.filter(x => selectedKeys.includes(x.positionId) && this.selectedItems.data.get(x.positionId)).length
return num
}
onSelectItemChange(arg: any) {
this.selectedItems = arg
}
openJobGradeGroupDialog() {
this.jobGradeGroupDialogRef = this.dialog.open(this.jobGradeGroupModal, {
width: '800px',
})
}
}
......@@ -211,6 +211,9 @@ import { TranslateModule } from '@ngx-translate/core';
import { ReportCompetencySummaryComponent } from '../report-component/report-com/report-competency-summary/report-competency-summary.component';
import { JobDescriptionEmpComponent } from '../job-description-emp/job-description-emp.component';
import { CompetencyMappingComponent } from '../competency-mapping/competency-mapping.component';
import { JobFamilyComponent } from '../company-components/job-description/job-family/job-family.component';
import { JobGradeComponent } from '../company-components/job-description/job-grade/job-grade.component';
import { JobGradeGroupComponent } from '../company-components/job-description/job-grade-group/job-grade-group.component';
export const MY_DATE_FORMATS = {
parse: {
......@@ -361,7 +364,10 @@ export class CustomDateAdapter extends NativeDateAdapter {
SettingIndividualKpiSupervisorComponent,
JobDescriptionEmpComponent,
MoneyInputDirective,
CompetencyMappingComponent
CompetencyMappingComponent,
JobFamilyComponent,
JobGradeComponent,
JobGradeGroupComponent
], imports: [
TranslateModule,
CommonModule,
......
......@@ -20,9 +20,9 @@
</ng-container>
<div class="flex justify-around !items-center border bg-white p-2 text-right"
style="border-radius:20px;width: 100px;margin-left: auto;--tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity));">
<i title="แสดงทั้งหมด" class="bg-white cursor-pointer border ti ti-chevron-down"
<i [title]="'ShowAll' | translate" class="bg-white cursor-pointer border ti ti-chevron-down"
style="padding: 1px;border-radius:5px;font-size:27px" (click)="allBiOpen(true)"></i>
<i title="ปิดทั้งหมด" class="bg-white cursor-pointer border ti ti-chevron-up"
<i [title]="'HideAll' | translate" class="bg-white cursor-pointer border ti ti-chevron-up"
style="padding: 1px;border-radius:5px;font-size:27px" (click)="allBiOpen(false)"></i>
</div>
</div>
......@@ -56,7 +56,7 @@
<thead class="border-b border-gray-200">
<tr style="height:35px">
<th scope="col">Behavior Indicator (BI)</th>
<th scope="col">เครื่องมือ
<th scope="col">{{'Tools' | translate}}
<div class="hs-tooltip ti-main-tooltip [--trigger:hover]">
<a class="hs-tooltip-toggle ti-main-tooltip-toggle" href="javascript:;">
<i class="ti ti-help-circle"></i>
......@@ -75,7 +75,7 @@
</th>
<ng-container *ngIf="evaluaterId==evaluateeId&&!complete">
<th scope="col" style="width:500px">
คะแนน
{{'TargetDegree' | translate}}
<div class="hs-tooltip ti-main-tooltip [--trigger:hover]">
<a class="hs-tooltip-toggle ti-main-tooltip-toggle" href="javascript:;">
<i class="ti ti-help-circle"></i>
......@@ -111,7 +111,7 @@
</ng-container>
<ng-container *ngIf="evaluaterId!=evaluateeId||complete">
<th scope="col" style="width:325px">
คะแนน
{{'TargetDegree' | translate}}
<div class="hs-tooltip ti-main-tooltip [--trigger:hover]">
<a class="hs-tooltip-toggle ti-main-tooltip-toggle" href="javascript:;">
<i class="ti ti-help-circle"></i>
......@@ -216,24 +216,21 @@
style=" border-radius:20px"
(click)="scrollToMenu(appraisalCompentencyFilter().length);allBiOpen(!biOpen.get('สรุป'),'สรุป')">
<span style="padding-left:50px">
สรุป
</span>
&nbsp;
<span>
คะแนนประเมิน
{{'Summary' | translate}}
</span>
</button>
<ng-container *ngIf="biOpen.get('สรุป')">
<div class="pb-1rem px-2rem">
<div class="py-2 grid grid-cols-11">
<div class="col-span-8" style="font-size: 1rem;font-weight: 500; border-radius:20px">ระดับความสามารถ (Target
Degree)</div>
<div class="col-span-8" style="font-size: 1rem;font-weight: 500; border-radius:20px">
{{'TargetDegree' | translate}}
</div>
<div class="col-span-3 grid grid-cols-5">
<div class="col-span-1 text-center" *ngFor="let item of [5,4,3,2,1]">{{item}}</div>
</div>
</div>
<div class="py-2 grid grid-cols-11">
<div class="col-span-8">รวมจำนวนเครื่องหมายแต่ละช่อง (1)</div>
<div class="col-span-8">{{'TallyOfMarksPerRatingLevel1' | translate}}</div>
<div class="col-span-3 grid grid-cols-5">
<!-- <div class="col-span-1 text-center">
{{appraisalCompentencyList[appraisalCompentencyIndex].masfromEvaluationAssessment1List[0].weightScore7Boss}}
......@@ -259,7 +256,7 @@
</div>
</div>
<div class="py-2 grid grid-cols-11">
<div class="col-span-8">ตัวคูณคะแนนในแต่ละช่อง (2)</div>
<div class="col-span-8">{{'ScoreMultiplierPerLevel2' | translate}}</div>
<div class="col-span-3 grid grid-cols-5">
<!-- <div class="col-span-1 text-center">{{setting.data.settingScore7}}</div>
<div class="col-span-1 text-center">{{setting.data.settingScore6}}</div> -->
......@@ -271,14 +268,14 @@
</div>
</div>
<div class="py-2 grid grid-cols-11">
<div class="col-span-8">ถ่วงน้ำหนักผลรวม 1X2</div>
<div class="col-span-8">{{'WeightedScore1x2' | translate}}</div>
<div class="col-span-3 grid grid-cols-5">
<div class="col-span-1 text-center" *ngFor="let item of [5,4,3,2,1]">{{calWeightScoreBoss(item)}}
</div>
</div>
</div>
<div class="py-2 grid grid-cols-11">
<div class="col-span-8 font-semibold" style=" border-radius:20px">คะแนนรวมหลังถ่วงน้ำหนัก
<div class="col-span-8 font-semibold" style=" border-radius:20px">{{'TotalWeightedScore' | translate}}
</div>
<div class="col-span-3 grid grid-cols-1">
<div class="col-span-5 text-center text-indigo-600 font-semibold">
......@@ -287,7 +284,7 @@
</div>
</div>
<div class="py-2 grid grid-cols-11">
<div class="col-span-8 font-semibold" style=" border-radius:20px">คะแนนเฉลี่ยคิดเป็น
<div class="col-span-8 font-semibold" style=" border-radius:20px">{{'FinalAverageScore' | translate}}
</div>
<div class="col-span-3 grid grid-cols-1">
<div class="col-span-5 text-center text-indigo-600 font-semibold">
......@@ -302,17 +299,17 @@
<thead class="height-50px">
<tr class="font-size-12px">
<ng-container
*ngFor="let item of ['เกณฑ์การให้คะแนนการประเมิน','ผลประเมิน (A)','สรุปผล Gap'];let f = first ;let l = last">
*ngFor="let item of ['CompetencyRatingScale','AssessmentResultA','GapResultEva'];let f = first ;let l = last">
<th scope="col" [attr.rowspan]="f?'1':'2'" [attr.colspan]="f?'2':'1'"
class="relative px-10px py-10px bg-soft-secondary text-primary !text-center">
<span class="font-size-12px font-weight-700 ">{{ item }}</span>
<span class="font-size-12px font-weight-700 ">{{ item | translate}}</span>
</th>
</ng-container>
</tr>
<tr class="font-size-12px">
<ng-container *ngFor="let item of ['เกณฑ์การให้คะแนน','เงื่อนไข']">
<ng-container *ngFor="let item of ['RatingCriteria','Conditions']">
<th scope="col" class="relative px-10px py-10px bg-soft-secondary text-primary !text-center">
{{item}}
{{ item | translate}}
</th>
</ng-container>
</tr>
......@@ -322,12 +319,12 @@
(mouseleave)="hoveredCode2 = null" [ngClass]="{ 'table-hover2': 'true' === hoveredCode2 }">
<td class="align-start" rowspan="2">
<div *ngFor="let item2 of item.score">
<span>{{item2}} </span><br>
<span>{{item2 | translate}} </span><br>
</div>
</td>
<td class="align-start" rowspan="2">
<div *ngFor="let item2 of item.condition">
<span>{{item2}} </span><br>
<span>{{item2 | translate}} </span><br>
</div>
</td>
<td class="align-start text-center text-indigo-600 font-semibold">
......
......@@ -52,8 +52,8 @@ export class PmsCompetencyComponent {
score: string[],
condition: string[]
}[] = [{
score: ["หากได้คะแนน 90 - 100% ถือว่า Gap +1", "หากได้คะแนน 80 - 89% ถือว่า ไม่มี Gap", "หากได้คะแนน 60 - 79% ถือว่า Gap - 1", "หากได้คะแนน 40 - 59% ถือว่า Gap -2", "หากได้คะแนน 0 - 39% ถือว่า Gap - 3"],
condition: ["1.หากได้คะแนนสูงกว่า 80% แต่มี 3 2 หรือ 1 ด้วย ถือว่า Gap -1", "2.หากได้คะแนนต่ำกว่า 80% แต่มี 4 และ 5 ให้คิด Gap ตาม %", "3.คะแนนต่ำกว่า 80% แต่มี 2 และ 1 ให้คิด Gap ตาม %"],
score: ["IfScore90to100", "IfScore80to89", "IfScore60to79", "IfScore40to59", "IfScore0to39"],
condition: ["Condition1", "Condition2", "Condition3"],
}]
scoreDescriptions = [
'',
......
......@@ -9,6 +9,7 @@ import Swal from 'sweetalert2';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { environment } from 'src/environments/environment';
import { FileService } from 'src/app/shared/services/file.service';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'app-pms-form-employee',
......@@ -16,7 +17,7 @@ import { FileService } from 'src/app/shared/services/file.service';
styleUrls: ['./pms-form-employee.component.scss']
})
export class PmsFormEmployeeComponent {
@Input() currentTap = "ข้อมูลการประเมิน"
@Input() currentTap = "EvaluationInfo"
firstCurrentTap = ""
@Input() evaluateeId = ""
@Input() evaluaterId = ""
......@@ -78,11 +79,11 @@ export class PmsFormEmployeeComponent {
@ViewChild('scrollContainer') scrollContainer!: ElementRef;
menuList: { text: string, link: string }[] = [
{ text: 'ข้อมูลการประเมิน', link: 'info' },
{ text: 'แบบประเมินสมรรถนะ', link: 'com' },
{ text: 'ประเมินผลการปฏิบัติงาน', link: 'kpi' },
{ text: 'สรุปคะแนนและข้อเสนอแนะ', link: 'kpi-sum' },
{ text: 'แผนพัฒนาบุคลากร', link: 'idp' }]
{ text: 'EvaluationInfo', link: 'info' },
{ text: 'CompetencyEva', link: 'com' },
{ text: 'Performance', link: 'kpi' },
{ text: 'SummaryAndFeedback', link: 'kpi-sum' },
{ text: 'IDP', link: 'idp' }]
constructor(
private router: Router,
......@@ -91,6 +92,7 @@ export class PmsFormEmployeeComponent {
private cdr: ChangeDetectorRef,
private tokenService: TokenService,
private route: ActivatedRoute,
private translateService: TranslateService,
private fileService: FileService
) {
}
......@@ -102,17 +104,17 @@ export class PmsFormEmployeeComponent {
currentStepText = () => {
if (this.compentency.data) {
if (this.compentency.data.apsassessy.employeeId == this.evaluaterId) {
return "ผู้รับการประเมิน"
return "Appraisee"
} else if (this.compentency.data.apsapprove1.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 1"
return "Approver1Eva"
} else if (this.compentency.data.apsapprove2.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 2"
return "Approver2Eva"
} else if (this.compentency.data.apsapprove3.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 3"
return "Approver3Eva"
} else if (this.compentency.data.apsapprove4.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 4"
return "Approver4Eva"
} else if (this.compentency.data.apsapprove5.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 5"
return "Approver5Eva"
}
}
return ""
......@@ -120,17 +122,17 @@ export class PmsFormEmployeeComponent {
currentStepTextShow = () => {
if (this.compentency.data) {
if (this.compentency.data.apsassessy.employeeId == this.evaluaterId) {
return "ผู้ประเมิน"
return "Assessor"
} else if (this.compentency.data.apsapprove1.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 1"
return "Approver1Eva"
} else if (this.compentency.data.apsapprove2.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 2"
return "Approver2Eva"
} else if (this.compentency.data.apsapprove3.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 3"
return "Approver3Eva"
} else if (this.compentency.data.apsapprove4.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 4"
return "Approver4Eva"
} else if (this.compentency.data.apsapprove5.employeeId == this.evaluaterId) {
return "ผู้อนุมัติลำดับที่ 5"
return "Approver5Eva"
}
}
return ""
......@@ -153,13 +155,13 @@ export class PmsFormEmployeeComponent {
statusCompetencyText = (status: string) => {
if (status === "no access") {
return "ยังไม่ถึงขั้นตอนดำเนินการ"
return "NotStarted"
} else if (status === "pending") {
return "รอดำเนินการ"
return "Pending"
} else if (status === "evaluating") {
return "อยู่ระหว่างดำเนินการ"
return "InProgress"
} else if (status === "completed") {
return "ดำเนินการเสร็จสิ้น"
return "Completed"
} else if (status === "rejected") {
return "ส่งกลับ"
} else {
......@@ -298,15 +300,15 @@ export class PmsFormEmployeeComponent {
this.route.paramMap.subscribe((params: ParamMap) => {
const pathLink = params.get('part')
if (pathLink == 'info') {
this.firstCurrentTap = 'ข้อมูลการประเมิน'
this.firstCurrentTap = 'EvaluationInfo'
} else if (pathLink == 'com') {
this.firstCurrentTap = 'แบบประเมินสมรรถนะ'
this.firstCurrentTap = 'CompetencyEva'
} else if (pathLink?.includes('kpi-sum')) {
this.firstCurrentTap = 'สรุปคะแนนและข้อเสนอแนะ'
this.firstCurrentTap = 'SummaryAndFeedback'
} else if (pathLink?.includes('kpi')) {
this.firstCurrentTap = 'ประเมินผลการปฏิบัติงาน'
this.firstCurrentTap = 'Performance'
} else if (pathLink == 'idp') {
this.firstCurrentTap = 'แผนพัฒนาบุคลากร'
this.firstCurrentTap = 'IDP'
}
});
this.companyId = this.tokenService.getUser()?.companyid || ""
......@@ -333,10 +335,10 @@ export class PmsFormEmployeeComponent {
this.selectDataList(this.compentency.dataList[0])
}
this.compentency.loading = false
this.cdr.detectChanges()
this.cdr.markForCheck()
}, error: error => {
this.compentency.loading = false
this.cdr.detectChanges()
this.cdr.markForCheck()
}
})
}
......@@ -344,21 +346,27 @@ export class PmsFormEmployeeComponent {
selectDataList(data: CompetencyModel) {
this.compentency.originalData = this.deepClone(data)
this.compentency.data = this.deepClone(data)
this.menuList = [
{ text: 'EvaluationInfo', link: 'info' },
{ text: 'CompetencyEva', link: 'com' },
{ text: 'Performance', link: 'kpi' },
{ text: 'SummaryAndFeedback', link: 'kpi-sum' },
{ text: 'IDP', link: 'idp' }]
const checkMenu = Array.from({ length: 7 }, (_, i) => i + 1)
.filter(i => (this.compentency.data?.pms?.[`part${i}Detail` as keyof Pms] as any)?.length).length
if (!checkMenu) {
this.menuList.splice(2, 1)
}
this.complete = this.compentency.data?.statusType == 'complete'
this.cdr.detectChanges()
this.cdr.markForCheck()
if (this.compentency.data) {
this.currentTap = this.firstCurrentTap || "ข้อมูลการประเมิน"
this.currentTap = this.firstCurrentTap || "EvaluationInfo"
this.firstCurrentTap = ''
this.compentency.data.commentAll.sort((a, b) => new Date(b.commentDate).getTime() - new Date(a.commentDate).getTime());
this.canSave = this.compentency.data.statusType == "pending" || this.compentency.data.statusType == "evaluating"
this.canDraft = +this.compentency.data.currentStep <= 1 && (this.compentency.data.statusType == "pending" || this.compentency.data.statusType == "evaluating")
this.canEdit = +this.compentency.data.currentStep <= 1 && (this.compentency.data.statusType == "pending" || this.compentency.data.statusType == "evaluating")
this.cdr.detectChanges()
this.cdr.markForCheck()
}
}
......@@ -368,10 +376,10 @@ export class PmsFormEmployeeComponent {
next: response => {
this.evaluatee.data = new MyEmployeeModel(response)
this.evaluatee.loading = false
this.cdr.detectChanges()
this.cdr.markForCheck()
}, error: error => {
this.evaluatee.loading = false
this.cdr.detectChanges()
this.cdr.markForCheck()
}
})
}
......@@ -624,6 +632,10 @@ export class PmsFormEmployeeComponent {
'!competency[].masfromEvaluationAssessment1List[].weightScore5',
'!competency[].masfromEvaluationAssessment1List[].weightedTotal',
'!competency[].masfromEvaluationAssessment1List[].averageScore',
'!competency[].masfromEvaluationAssessment1List[].weightScore6Boss',
'!competency[].masfromEvaluationAssessment1List[].weightScore7Boss',
'!competency[].masfromEvaluationAssessment1List[].scoreGab',
'!competency[].masfromEvaluationAssessment1List[].scoreGabBoss',
'pms',
'!pms.gradeScore',
'!pms.apsassessyDate',
......@@ -645,7 +657,7 @@ export class PmsFormEmployeeComponent {
this.compentency.data,
this.compentency.originalData,
ignorePart
);
);
if (diffs.mini.length) {
Swal.fire({
icon: 'warning',
......@@ -786,4 +798,8 @@ export class PmsFormEmployeeComponent {
imgElement.src = './assets/img/users/defaultperson.jpg';
}
translateText(th?: string, en?: string) {
return this.translateService.getCurrentLang() == 'th' ? (th || '') : (en || '')
}
}
......@@ -3,28 +3,28 @@
<button type="button"
class="p-4 w-full bg-gradient-to-r from-primary to-secondary text-white text-left font-semibold"
style="border-radius:20px" (click)="menuClose.set('Compentency',!menuClose.get('Compentency'))">
รายละเอียดประเมินสมรรถนะ (Compentency)
{{'CompetencyDetail' | translate}}
</button>
</div>
<ng-container *ngIf="!menuClose.get('Compentency')">
<table style="table-layout: fixed; width: 100%;">
<thead class="border-b border-gray-200">
<tr style="height:35px">
<th scope="col">แบบการประเมิน</th>
<th scope="col text-center">วันที่เริ่มต้น</th>
<th scope="col text-center">วันที่สิ้นสุด</th>
<th scope="col">{{'EvaluationForm' | translate}}</th>
<th scope="col text-center">{{'StartDate'| translate}}</th>
<th scope="col text-center">{{'EndDate' | translate}}</th>
<ng-container *ngIf="evaluaterId==evaluateeId&&!complete">
<th scope="col text-center">คะแนนเฉลี่ย</th>
<th scope="col text-center">ผล GAP</th>
<th scope="col text-center">{{'AverageScore' | translate}}</th>
<th scope="col text-center">{{'GapResult'| translate}}</th>
</ng-container>
<ng-container *ngIf="evaluaterId!=evaluateeId||complete">
<th scope="col text-center">คะแนนเฉลี่ยตนเอง
</th>
<th scope="col text-center">คะแนนเฉลี่ย</th>
<th scope="col text-center">{{'AverageScore' | translate}}</th>
<th scope="col text-center">ผล GAP ตนเอง</th>
<th scope="col text-center">ผล GAP</th>
<th scope="col text-center">{{'GapResult' | translate}}</th>
</ng-container>
<th scope="col text-center">การจัดการ</th>
<th scope="col text-center">{{'Action' | translate}}</th>
</tr>
</thead>
<tbody>
......@@ -84,25 +84,25 @@
<button type="button"
class="p-4 w-full bg-gradient-to-r from-primary to-secondary text-white text-left font-semibold"
style="border-radius:20px" (click)="menuClose.set('PMS',!menuClose.get('PMS'))">
รายละเอียดประเมินผลการปฏิบัติงาน (PMS)
{{'PerformanceManagementSystem(PMS)' | translate}}
</button>
</div>
<ng-container *ngIf="appraisalPms&&!menuClose.get('PMS')">
<table style="table-layout: fixed; width: 100%;">
<thead class="border-b border-gray-200">
<tr style="height:35px">
<th scope="col">แบบการประเมิน</th>
<th scope="col text-center">วันที่เริ่มต้น</th>
<th scope="col text-center">วันที่สิ้นสุด</th>
<th scope="col">{{'EvaluationForm' | translate}}</th>
<th scope="col text-center">{{'StartDate'| translate}}</th>
<th scope="col text-center">{{'EndDate' | translate}}</th>
<ng-container *ngIf="evaluaterId==evaluateeId&&!complete">
<th scope="col text-center">ผลการประเมิน</th>
<th scope="col text-center">{{'EvaluationResult'| translate}}</th>
</ng-container>
<ng-container *ngIf="evaluaterId!=evaluateeId||complete">
<th scope="col text-center">ผลการประเมินตนเอง</th>
<th scope="col text-center">ผลการประเมิน</th>
<th scope="col text-center">{{'EvaluationResult' | translate}}</th>
</ng-container>
<th scope="col text-center">เกรด</th>
<th scope="col text-center">การจัดการ</th>
<th scope="col text-center">{{'Grade' | translate}}</th>
<th scope="col text-center">{{'Action' | translate}}</th>
</tr>
</thead>
<tbody>
......
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Competency, Pms } from 'src/app/shared/model/competency.model';
@Component({
......@@ -27,6 +28,8 @@ export class PmsInformationComponent {
@Output() sendCurrentPart: EventEmitter<any> = new EventEmitter<any>();
tableHover: Map<string, boolean> = new Map<string, boolean>()
menuClose: Map<string, boolean> = new Map<string, boolean>()
constructor(private translateService: TranslateService) { }
statusButtonClass = (status: string) => {
if (status === "no access") {
return "ti-btn-soft-mute"
......@@ -44,15 +47,33 @@ export class PmsInformationComponent {
}
formatThaiDate(dateStr?: string): string {
if (!dateStr) return ''
if (this.translateService.getCurrentLang() == 'th') {
const months = [
'', 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน',
'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'
];
const [year, month, day] = dateStr.split('-').map(Number);
const thaiYear = year + 543;
const thaiMonth = months[month];
return `${day} ${thaiMonth} ${thaiYear}`;
} else {
return this.formatEngDate(dateStr)
}
}
formatEngDate(dateStr?: string): string {
if (!dateStr) return '';
const months = [
'', 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน',
'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'
'', 'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
const [year, month, day] = dateStr.split('-').map(Number);
const thaiYear = year + 543;
const thaiMonth = months[month];
const engMonth = months[month];
return `${day} ${thaiMonth} ${thaiYear}`;
return `${day} ${engMonth} ${year}`;
}
}
......@@ -35,7 +35,7 @@ export class PmsKpiComponent {
@Input() inforWeight: Map<string, string> = new Map<string, string>()
data8List: Part8Model[] = [{
id: 1,
evaluationFactor: "Part 1 : ประเมินผลการปฏิบัติงานตามนโยบายบริษัท (Corporate KPI)",
evaluationFactor: "PART 1 : ประเมินผลการปฏิบัติงานตามนโยบายบริษัท (Corporate KPI)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
......@@ -44,7 +44,7 @@ export class PmsKpiComponent {
netScore: 0,
}, {
id: 2,
evaluationFactor: "Part 2 : ประเมินผลการปฏิบัติงานประจำ (Department KPI)",
evaluationFactor: "PART 2 : ประเมินตัวชี้วัดของหน่วยงาน (Department KPI)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
......@@ -53,7 +53,7 @@ export class PmsKpiComponent {
netScore: 0,
}, {
id: 3,
evaluationFactor: "Part 3 : ประเมินผลการปฏิบัติงานประจำ (Individual KPI)",
evaluationFactor: "PART 3 : ประเมินตัวชี้วัดรายบุคคล (Individual KPI)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
......@@ -62,7 +62,7 @@ export class PmsKpiComponent {
netScore: 0,
}, {
id: 4,
evaluationFactor: "Part 4 : ประเมินผลสมรรถนะที่สนับสนุนการปฏิบัติงาน (Competency)",
evaluationFactor: "PART 4 : ประเมินผลสมรรถนะที่สนับสนุนการปฏิบัติงาน (Competency)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
......@@ -71,7 +71,7 @@ export class PmsKpiComponent {
netScore: 0,
}, {
id: 5,
evaluationFactor: "Part 5 : อัตราการเข้างาน (Time Attendance)",
evaluationFactor: "PART 5 : อัตราการเข้างาน (Time Attendance)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
......@@ -80,7 +80,7 @@ export class PmsKpiComponent {
netScore: 0,
}, {
id: 6,
evaluationFactor: "Part 6 : งานที่ได้รับมอบหมายเพิ่มเติม (Cross Functional Project Assignment)",
evaluationFactor: "PART 6 : งานที่ได้รับมอบหมายเพิ่มเติม (Cross Functional Project Assignment)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
......@@ -89,7 +89,7 @@ export class PmsKpiComponent {
netScore: 0,
}, {
id: 7,
evaluationFactor: "Part 7 : กิจกรรมพิเศษ (Special Activities)",
evaluationFactor: "PART 7 : กิจกรรมพิเศษ (Special Activities)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
......@@ -126,7 +126,72 @@ export class PmsKpiComponent {
private route: ActivatedRoute
) {
}
resetData8List() {
this.data8List = [{
id: 1,
evaluationFactor: "Part 1 : ประเมินผลการปฏิบัติงานตามนโยบายบริษัท (Corporate KPI)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
netScoreBoss: 0,
scoreObtained: 0,
netScore: 0,
}, {
id: 2,
evaluationFactor: "Part 2 : ประเมินผลการปฏิบัติงานประจำ (Department KPI)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
netScoreBoss: 0,
scoreObtained: 0,
netScore: 0,
}, {
id: 3,
evaluationFactor: "Part 3 : ประเมินผลการปฏิบัติงานประจำ (Individual KPI)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
netScoreBoss: 0,
scoreObtained: 0,
netScore: 0,
}, {
id: 4,
evaluationFactor: "Part 4 : ประเมินผลสมรรถนะที่สนับสนุนการปฏิบัติงาน (Competency)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
netScoreBoss: 0,
scoreObtained: 0,
netScore: 0,
}, {
id: 5,
evaluationFactor: "Part 5 : อัตราการเข้างาน (Time Attendance)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
netScoreBoss: 0,
scoreObtained: 0,
netScore: 0,
}, {
id: 6,
evaluationFactor: "Part 6 : งานที่ได้รับมอบหมายเพิ่มเติม (Cross Functional Project Assignment)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
netScoreBoss: 0,
scoreObtained: 0,
netScore: 0,
}, {
id: 7,
evaluationFactor: "Part 7 : กิจกรรมพิเศษ (Special Activities)",
rawScore: 100,
factors: 0,
scoreObtainedBoss: 0,
netScoreBoss: 0,
scoreObtained: 0,
netScore: 0,
}]
}
getTargetDetailValue(item: any): string {
const targetDetail = ['', 'targetEdetail', 'targetDdetail', 'targetCdetail', 'targetBdetail', 'targetAdetail']
const index = this.partScore.get(item.groupAssessment1.pmsTopic.pmsTopicId) ?? item.scoreTopicExpectation;
......@@ -141,11 +206,12 @@ export class PmsKpiComponent {
}
ngOnInit(): void {
this.partOpen.clear()
this.resetData8List()
const menuList = Array.from({ length: 7 }, (_, i) => i + 1)
.filter(i => (this.appraisalPms?.[`part${i}Detail` as keyof Pms] as any)?.length)
.map(i => `PART ${i}`)
this.data8List = this.data8List.filter(e => menuList.some(e2 => e.id == +e2.replace('PART ', '')))
if (this.currentTap == 'ประเมินผลการปฏิบัติงาน') {
if (this.currentTap == 'Performance') {
this.partShow = menuList
} else {
if (this.data8List.length) {
......@@ -165,11 +231,12 @@ export class PmsKpiComponent {
ngOnChanges(changes: SimpleChanges): void {
if (changes['currentTap']?.currentValue || changes['appraisalPms']?.currentValue) {
this.partOpen.clear()
this.resetData8List()
const menuList = Array.from({ length: 7 }, (_, i) => i + 1)
.filter(i => (this.appraisalPms?.[`part${i}Detail` as keyof Pms] as any)?.length)
.map(i => `PART ${i}`)
this.data8List = this.data8List.filter(e => menuList.some(e2 => e.id == +e2.replace('PART ', '')))
if (this.currentTap == 'ประเมินผลการปฏิบัติงาน') {
if (this.currentTap == 'Performance') {
this.partShow = menuList
} else {
if (this.data8List.length) {
......@@ -181,6 +248,7 @@ export class PmsKpiComponent {
this.partShow.forEach(x => {
this.partOpen.set(x, false)
})
this.getAppraisalPmsForm()
this.allFormRemain()
this.sendScorePart()
......@@ -651,9 +719,9 @@ export class PmsKpiComponent {
if (this.appraisalPms) {
const gradeScore = this.groupGrade.dataList.find(item => Math.ceil(+this.calNetScoreBoss()) >= item.gradeMinScore && Math.ceil(+this.calNetScoreBoss()) <= item.gradeMaxScore);
const scoreBoss = this.data8List.map((x, i) => ({ text: x.evaluationFactor.match(/Part\s*\d+/)?.[0].toUpperCase(), score: this.numberFixed2(x.netScoreBoss) }))
.concat([{ text: "สุทธิ", score: this.calNetScoreBoss() + '' }, { text: "Grade", score: gradeScore?.gradeDetail || '' }])
.concat([{ text: "NetScore", score: this.calNetScoreBoss() + '' }, { text: "Grade", score: gradeScore?.gradeDetail || '' }])
const score = this.data8List.map((x, i) => ({ text: x.evaluationFactor.match(/Part\s*\d+/)?.[0].toUpperCase(), score: this.numberFixed2(x.netScore) }))
.concat([{ text: "สุทธิ", score: this.calNetScore() + '' }, { text: "Grade", score: gradeScore?.gradeDetail || '' }])
.concat([{ text: "NetScore", score: this.calNetScore() + '' }, { text: "Grade", score: gradeScore?.gradeDetail || '' }])
this.scorePartBoss.emit(scoreBoss)
this.scorePart.emit(score)
}
......
......@@ -43,6 +43,7 @@ import {
import { GroupSettingsModel, FilterSettingsModel, ColumnModel } from '@syncfusion/ej2-angular-grids';
import { DataManager, Query } from '@syncfusion/ej2-data';
import { L10n, setCulture } from '@syncfusion/ej2-base';
import { TranslateService } from '@ngx-translate/core';
setCulture('th-TH');
@Component({
selector: 'app-supervisor-evaluation',
......@@ -85,13 +86,13 @@ export class SupervisorEvaluationComponent {
}
statusCompetencyText = (status: string) => {
if (status === "no access") {
return "ยังไม่ถึงขั้นตอนดำเนินการ"
return "NotStarted"
} else if (status === "pending") {
return "รอดำเนินการ"
return "Pending"
} else if (status === "evaluating") {
return "อยู่ระหว่างดำเนินการ"
return "InProgress"
} else if (status === "completed") {
return "ดำเนินการเสร็จสิ้น"
return "Completed"
} else if (status === "rejected") {
return "ส่งกลับ"
} else {
......@@ -119,7 +120,7 @@ export class SupervisorEvaluationComponent {
searchSettings: {
fields: [
'employeeId',
'thFullName',
'fullName',
'position',
'statusIdp',
'sumScore',
......@@ -136,7 +137,7 @@ export class SupervisorEvaluationComponent {
filterSettings: FilterSettingsModel = { type: 'Excel' };
selectionOptions: SelectionSettingsModel = { checkboxOnly: true };
groupSettings: GroupSettingsModel = { allowReordering: true, showGroupedColumn: true, showDropArea: false };
toolbarOptions: ToolbarItems[] = ['Print', 'ExcelExport', 'CsvExport'];
toolbarOptions: any[] = ['Print', 'ExcelExport', 'CsvExport'];
editSettings? = { allowEditing: true, mode: 'Batch' };
loadingIndicator: LoadingIndicatorModel = { indicatorType: 'Shimmer' };
query: Query = new Query().addParams('dataCount', '1000');
......@@ -157,13 +158,38 @@ export class SupervisorEvaluationComponent {
aggregatesMin: any[] = [];
aggregatesMax: any[] = [];
locale = 'th-TH'
constructor(private appraisalService: AppraisalService,
private fileService: FileService,
private translateService: TranslateService,
private cdr: ChangeDetectorRef) {
this.locale = this.translateService.getCurrentLang() == 'th' ? 'th-TH' : 'en-US'
this.translateService.onLangChange.subscribe((event) => {
if (event.lang === 'th') {
setCulture('th-TH');
this.locale = 'th-TH'
} else if (event.lang === 'en') {
setCulture('en-US');
this.locale = 'en-US'
}
this.toolbarOptions = [
{ text: this.translateService.instant('Print'), prefixIcon: 'e-print', id: 'Print' },
{ text: this.translateService.instant('ExcelExport'), prefixIcon: 'e-excelexport', id: 'ExcelExport' },
{ text: this.translateService.instant('CSVExport'), prefixIcon: 'e-csvexport', id: 'CsvExport' }
];
if (this.subordinate.select?.showPms) {
this.setSyncfutionDataList()
this.searchDataGrid(this.search)
this.cdr.markForCheck()
}
});
}
ngOnInit(): void {
this.formEvaluation.evaluaterId = this.decodeJWT(sessionStorage.getItem("accessToken") || '').employeeid
this.getBossList()
}
getBossList() {
this.syncfution = {
......@@ -171,7 +197,7 @@ export class SupervisorEvaluationComponent {
searchSettings: {
fields: [
'employeeId',
'thFullName',
'fullName',
'position',
'statusIdp',
'sumScore',
......@@ -183,28 +209,44 @@ export class SupervisorEvaluationComponent {
columns: []
}
this.appraisalService.getBossList().subscribe({
next: response => {
next: async response => {
this.subordinate.dataList = JSON.parse(JSON.stringify(response))
this.cdr.detectChanges()
this.cdr.markForCheck()
if (this.subordinate.dataList.length) {
this.subordinate.select = JSON.parse(JSON.stringify(this.subordinate.dataList[0]))
this.setSyncfution()
this.setEcharts()
this.cdr.detectChanges()
}
this.searchDataGrid(this.search)
const grid = await this.waitForGrid();
if (grid) {
this.searchDataGrid(this.search)
}
this.cdr.markForCheck()
}, error: error => {
this.cdr.detectChanges()
this.cdr.markForCheck()
}
})
}
waitForGrid(): Promise<GridComponent> {
return new Promise(resolve => {
const check = () => {
if (this.grid) resolve(this.grid);
else setTimeout(check, 50); // ตรวจสอบซ้ำทุก 50ms
};
check();
});
}
setSyncfution() {
this.syncfution = {
dataList: [],
searchSettings: {
fields: [
'employeeId',
'thFullName',
'fullName',
'position',
'statusIdp',
'sumScore',
......@@ -220,38 +262,38 @@ export class SupervisorEvaluationComponent {
this.syncfution.columns =
[{
field: "employeeId",
headerText: "รหัสพนักงาน",
headerText: "EmployeeCode",
type: "string",
isPrimaryKey: true,
},
{
field: "thFullName",
headerText: "ชื่อพนักงาน",
field: "fullName",
headerText: "EmployeeName",
type: "string"
},
{
field: "position",
headerText: "ตำเเหน่งงาน",
headerText: "Position",
type: "string"
},
{
field: "statusType",
headerText: "ประเมิน",
headerText: "Status",
type: "string"
},
{
field: "sumScore",
headerText: "ผลประเมิน",
headerText: "Result",
type: "string"
},
{
field: "grade",
headerText: "เกรด",
headerText: "Grade",
type: "string"
},
{
field: "apsapproveType",
headerText: "สถานะผู้ประเมิน",
headerText: "AppraiserStatus",
type: "string"
}]
}
......@@ -261,16 +303,17 @@ export class SupervisorEvaluationComponent {
if (this.subordinate.select?.showPms) {
this.syncfution.dataList = this.subordinate.select.masfromevaluationassessment.map(e => ({
employeeId: e.apsassessy.employeeId,
thFullName: e.apsassessy.thFullName,
position: e.apsassessy.position.tdesc,
fullName: this.translateText(e.apsassessy.thFullName, e.apsassessy.engFullName),
position: this.translateText(e.apsassessy.position.tdesc, e.apsassessy.position.edesc),
statusType: this.statusCompetencyText(e.statusIdp.statusType),
statusIdp: e.statusIdp,
sumScore: e.sumScore,
grade: e.grade,
apsapproveType: e.apsapproveType.tdesc,
apsapproveType: this.translateText(e.apsapproveType.tdesc, e.apsapproveType.edesc),
apsassessy: e.apsassessy,
masfromStatusType: e.masfromStatusType
}))
this.cdr.markForCheck()
}
}
selectDataList(data?: AppraisalSubordinateModel) {
......@@ -278,8 +321,8 @@ export class SupervisorEvaluationComponent {
this.subordinate.select = JSON.parse(JSON.stringify(data))
this.setSyncfutionDataList()
this.setEcharts()
this.cdr.detectChanges()
this.searchDataGrid(this.search)
this.cdr.markForCheck()
}
subordinateAll() {
......@@ -429,7 +472,7 @@ export class SupervisorEvaluationComponent {
this.formEvaluation.evaluationRoundId = evaluationRoundId
this.formEvaluation.masfromStatusType = masfromStatusType || ''
this.formEvaluation.allCompetencyTypeId = data.typeList
this.cdr.detectChanges()
this.cdr.markForCheck()
}
}
......@@ -593,7 +636,7 @@ export class SupervisorEvaluationComponent {
footerTemplate: 'Sum: ${Sum}'
});
}
this.cdr.detectChanges()
this.cdr.markForCheck()
}
else if (selectedAgg === 'count') {
this.aggregatesCount.push({
......@@ -644,9 +687,9 @@ export class SupervisorEvaluationComponent {
}));
this.grid?.csvExport({ columns: exportColumns as Column[] });
} else if (args.item.id === 'Grid_print') {
this.cdr.detectChanges()
this.cdr.markForCheck()
setTimeout(() => {
this.cdr.detectChanges()
this.cdr.markForCheck()
}, 1000)
}
}
......@@ -654,4 +697,8 @@ export class SupervisorEvaluationComponent {
checkSubordinate(employeeId: string) {
return this.subordinate.select?.masfromevaluationassessment.find(x => x.apsassessy.employeeId == employeeId)
}
translateText(th?: string, en?: string) {
return this.translateService.getCurrentLang() == 'th' ? (th || '') : (en || '')
}
}
......@@ -715,11 +715,11 @@
</a> -->
<a routerLink="/ess/my-skill-x-module" class="ti-dropdown-item cursor-pointer">
<i class="ti ti-home text-lg"></i>
หน้าหลัก
{{'Home' | translate}}
</a>
<a routerLink="/ess/profile" class="ti-dropdown-item">
<i class="ti ti-user-circle text-lg"></i>
ข้อมูลพนักงาน
{{'Profile' | translate}}
</a>
<!-- <a *ngIf="!router.url.includes('/self-evaluation')" (click)="onNextPartClick('/self-evaluation')"
class="ti-dropdown-item cursor-pointer">
......@@ -733,7 +733,7 @@
</a> -->
<a (click)="onNextPartClick('dashboard/projects')" class="ti-dropdown-item cursor-pointer">
<i class="ti ti-settings text-lg"></i>
หน้าผู้ดูแลระบบ
{{'AdminSettings' | translate}}
</a>
<!-- <a routerLink="/dashboard/crypto" class="ti-dropdown-item">
<i class="ti ti-wallet text-lg"></i>
......@@ -741,7 +741,7 @@
</a> -->
<a (click)="logOut()" routerLink="/auth/login" class="ti-dropdown-item">
<i class="ti ti-logout text-lg"></i>
Log Out
{{'LogOut' | translate}}
</a>
</div>
</div>
......
......@@ -95,7 +95,7 @@ export class NavService implements OnDestroy {
getCustomerMenu() {
return [
{
title: 'ประเมินตนเอง',
title: 'SelfEvaluate',
type: 'link',
selected: false,
active: false,
......@@ -109,7 +109,7 @@ export class NavService implements OnDestroy {
// ],
},
{
title: 'ประเมินโดยหัวหน้า',
title: 'SupervisorEvaluate',
type: 'link',
selected: false,
active: false,
......
......@@ -229,5 +229,166 @@
"SubSection4DescThai": "Sub Section 4 Desc. (Thai)",
"SubSection4DescEng": "Sub Section 4 Desc. (Eng)",
"CompetencyFactorsSetting": "Competency Factors Setting",
"JobLevel(JL)": "Job Level (JL)"
"JobLevel(JL)": "Job Level (JL)",
"JobFamily": "Job Family",
"JobFamilyCode": "Job Family Code",
"JobFamilyNameThai": "Job Family Name (Thai)",
"JobFamilyNameEng": "Job Family Name (Eng)",
"JobFamilyAbbr": "Job Family Abbr.",
"AddJobFamily": "Add Job Family",
"EditJobFamily": "Edit Job Family",
"DuplicateJobFamilyCode": "Duplicate Job Family Code",
"ImportJobFamily": "Import Job Family",
"Image": "Image",
"JobGrade": "Job Grade",
"JobGradeCode": "Job Grade Code",
"DuplicateJobGradeCode": "Duplicate Job Grade Code",
"JobGradeDescThai": "Job Grade Desc. (Thai)",
"JobGradeDescEng": "Job Grade Desc. (Eng)",
"AddJobGrade": "Add Job Grade",
"EditJobGrade": "Edit Job Grade",
"ImportJobGrade": "Import Job Grade",
"JobGradeGroup": "Job Grade Group",
"JobGradeGroupCode": "Job Grade Group Code",
"JobGradeGroupDescThai": "Job Grade Group Desc. (Thai)",
"JobGradeGroupDescEng": "Job Grade Group Desc. (Eng)",
"AddJobGradeGroup": "Add Job Grade Group",
"EditJobGradeGroup": "Edit Job Grade Group",
"ImportJobGradeGroup": "Import Job Grade Group",
"Home": "Home",
"Profile": "Profile",
"AdminSettings": "Admin Settings",
"LogOut": "Log Out",
"SelfEvaluate": "Self-Evaluate",
"SupervisorEvaluate": "Supervisor Evaluate",
"AnnualEvaluation": "Annual Evaluation",
"EvaluatorStatus": "Evaluator Status",
"Approver1Eva": "Approver 1",
"Approver2Eva": "Approver 2",
"Approver3Eva": "Approver 3",
"Approver4Eva": "Approver 4",
"Approver5Eva": "Approver 5",
"EvaluationInfo": "Evaluation Info.",
"CompetencyEva": "Competency",
"Performance": "Performance",
"SummaryAndFeedback": "Summary and Feedback",
"IDP": "IDP",
"CompetencyDetail": "Competency",
"EvaluationForm": "Evaluation Form",
"AverageScore": "Average Score",
"GapResult": "Gap Result",
"PerformanceManagementSystem(PMS)": "Performance Management System (PMS)",
"EvaluationResult": "Evaluation Result",
"Grade": "Grade",
"EmployeeInformation": "Employee Information",
"NameSurname": "Name-Surname",
"Email": "E-mail",
"StatusEva": "Status",
"NotStarted": "Not Started",
"Pending": "Pending",
"InProgress": "In Progress",
"Completed": "Completed",
"Appraisee": "Appraisee",
"Approver1To5": "Evaluator Status : Approver 1-5",
"Timeline": "Timeline",
"CommentHere": "Comment Here",
"Confirm": "Confirm",
"SaveDraft": "Save Draft",
"Assessor": "Assessor",
"ShowAll": "Show All",
"HideAll": "Hide All",
"WeightedScoreByTargetDegree": "Weighted Score by Target Degree",
"AvgScore": "Avg. Score",
"Gap": "Gap",
"Tools": "Tools",
"Summary": "Summary",
"TargetDegree": "Target Degree",
"TallyOfMarksPerRatingLevel1": "Tally of Marks per rating Level (1)",
"ScoreMultiplierPerLevel2": "Score Multiplier per Level (2)",
"WeightedScore1x2": "Weighted Score (1x2)",
"TotalWeightedScore": "Total Weighted Score",
"FinalAverageScore": "Final Average Score",
"CompetencyRatingScale": "Competency Rating Scale",
"RatingCriteria": "Rating Criteria",
"IfScore90to100": "If the score is between 90 - 100% = Gap +1",
"IfScore80to89": "If the score is between 80 - 89% = No Gap",
"IfScore60to79": "If the score is between 60 - 79% = Gap – 1",
"IfScore40to59": "If the score is between 40 - 59% = Gap -2",
"IfScore0to39": "If the score is between 0 - 39% = Gap – 3",
"Conditions": "Conditions",
"Condition1": "1. If the total score exceeds 80% but contains any rating of 3, 2, or 1, the final outcome is Gap -1.",
"Condition2": "2. If the total score is below 80% but contains any rating of 4 or 5, the Gap is determined by the percentage score.",
"Condition3": "3. If the total score is below 80% but contains any rating of 2 or 1, the Gap is determined by the percentage score.",
"AssessmentResultA": "Assessment Result",
"GapResultEva": "Gap Result",
"EvaluationSummary": "Evaluation Summary",
"NetScore": "Net Score",
"PART 1 : ประเมินผลการปฏิบัติงานตามนโยบายบริษัท (Corporate KPI)": "Corporate KPI",
"PART 2 : ประเมินตัวชี้วัดของหน่วยงาน (Department KPI)": "Department KPI",
"PART 3 : ประเมินตัวชี้วัดรายบุคคล (Individual KPI)": "Individual KPI",
"PART 4 : ประเมินผลสมรรถนะที่สนับสนุนการปฏิบัติงาน (Competency)": "Competency",
"PART 5 : อัตราการเข้างาน (Time Attendance)": "Time Attendance",
"PART 6 : งานที่ได้รับมอบหมายเพิ่มเติม (Cross Functional Project Assignment)": "Cross Functional Project Assignment",
"PART 7 : กิจกรรมพิเศษ (Special Activities)": "Special Activities",
"PerformanceIndicator": "Performance Indicator",
"Detail": "Detail",
"TargetDegreeKpi": "Target Degree",
"RawScore": "Raw Score",
"SumOfWeights": "Sum of Weights",
"AchievedScore": "Achieved Score",
"RawScorePercent": "Raw Score %",
"FactorPercent": "Factor %",
"AchievedScorePercent": "Achieved Score %",
"CompetencyPart4": "Competency",
"TimeAttendancePart5": "Time Attendance",
"CrossFunctionalProjectAssignment": "Cross Functional Project Assignment",
"SpecialActivities": "Special Activities",
"PART 8 : สรุปผลการปฏิบัติงาน (Summary)": "PART 8 : Summary",
"EvaluationFactor": "Evaluation Factor",
"RawScore%": "Raw Score %",
"Factor%": "Factor %",
"AchievedScore%": "Achieved Score %",
"NetScorePart8": "Net Score",
"SummaryPart8": "Summary",
"PART 9 : name": "PART 9 : EMPLOYEE STRENGTHS , WEAKNESSES AND PLAN TO IMPROVED",
"EMPLOYEE STRENGTHS AND ACCOMPLISHMENTS": "EMPLOYEE STRENGTHS AND ACCOMPLISHMENTS",
"Suggested Learning Topics": "Suggested Learning Topics",
"PERFORMANCE AREAS WHICH NEED IMPROVEMENT": "PERFORMANCE AREAS WHICH NEED IMPROVEMENT",
"Suggested Learning Topics2": "Suggested Learning Topics",
"PLAN OF ACTION TOWARD IMPROVED PERFORMANCE": "PLAN OF ACTION TOWARD IMPROVED PERFORMANCE",
"Suggested Learning Topics3": "Suggested Learning Topics",
"PART 10 : คำชมหรือรางวัลที่ได้รับ (Conversation, Feedback, Recognise : CFR)": "PART 10 : Conversation, Feedback, Recognise : CFR",
"Subordinate": "Subordinate",
"CompletedEmployees": "Completed",
"TotalEmployees": "Total",
"Approval": "Approval",
"ApprovedEmployees": "Approved",
"EmployeesEva": "Employees",
"PmsOverview": "PMS Overview",
"GradeA": "Grade A",
"GradeB": "Grade B",
"GradeC": "Grade C",
"GradeD": "Grade D",
"GradeE": "Grade E",
"SubordinateList": "Subordinate List",
"ApproveAll": "Approve All",
"Result": "Result",
"AppraiserStatus": "Appraiser Status",
"JobPosition": "Position",
"DirectReportScore%": "Direct Report's Score %",
"DirectReportNetScore": "Direct Report's Net Score",
"Part1GeneralInformation": "Part 1: General Information",
"SubordinatePart": "Subordinate",
"Supervisor": "Supervisor",
"Section2DevelopmentPlan": "Section 2: Development Plan",
"RemarkHRTraining": "Remark : HR-provided training must comply with the criteria set by the Head Office.",
"StandardIDP": "Standard IDP",
"RevisedIDP": "Revised IDP",
"CompetencyPart": "Competency",
"BehaviorIndicatorsBIs": "Behavior Indicators : BIs",
"AssessmentToolsPart": "Assessment Tools",
"CDR": "CDR",
"DevelopmentPeriod": "Development Period",
"Job": "Job",
"DivisionPart9": "Division"
}
\ No newline at end of file
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