Commit d829e571 by Nattana Chaiyamat

ประเมินตนเอง

parent bb296e71
......@@ -72,8 +72,8 @@ export class ManageUserComponent {
}
decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง
let base64Url = token.split('.')[1];
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
......
......@@ -60,8 +60,8 @@ export class RolePermissionConfigComponent {
this.getConfigList()
}
decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง
let base64Url = token.split('.')[1];
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
......
......@@ -75,8 +75,8 @@ export class SetAPasswordComponent {
}
decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง
let base64Url = token.split('.')[1];
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
......
......@@ -82,8 +82,8 @@ export class UserSettingsComponent {
}
decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง
let base64Url = token.split('.')[1];
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
......
......@@ -672,8 +672,8 @@ export class SubEmployeeRegistrationComponent {
}
decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง
let base64Url = token.split('.')[1];
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
......
import { ViewportScroller } from '@angular/common';
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { Competency, MasfromEvaluationAssessment2List } from 'src/app/shared/model/competency.model';
import { EmployeeModel, MyEmployeeModel } from 'src/app/shared/model/employee.model';
import { SettingAssessmentModel, MySettingAssessmentModel } from 'src/app/shared/model/setting-assessment.model';
......@@ -13,7 +13,9 @@ import Swal from 'sweetalert2';
styleUrls: ['./pms-competency.component.scss']
})
export class PmsCompetencyComponent {
@Input() fCurrentPart = ""
currentPart = ""
@Input() canSave = false
@Input() evaluateeId = ""
@Input() evaluaterId = ""
@Input() appraisalCompentencyList: Competency[] = []
......@@ -24,9 +26,12 @@ export class PmsCompetencyComponent {
@Output() compentencyScore: EventEmitter<any> = new EventEmitter<any>();
@Output() compentencyWeightScore: EventEmitter<any> = new EventEmitter<any>();
@Output() compentencyGap: EventEmitter<any> = new EventEmitter<any>();
@Output() sendInforWeight: EventEmitter<any> = new EventEmitter<any>();
@Output() sendInforGap: EventEmitter<any> = new EventEmitter<any>();
@Input() canEdit = false
@Input() currentStep = ""
@Input() dateIso = ""
@Input() currentTap = ""
hoveredCode: string | null = null;
hoveredCode2: string | null = null;
......@@ -53,6 +58,8 @@ export class PmsCompetencyComponent {
biScore: Map<string, number> = new Map<string, number>()
@ViewChild('scrollContainer') scrollContainer!: ElementRef;
inforWeight: Map<string, string> = new Map<string, string>()
inforGap: Map<string, string> = new Map<string, string>()
constructor(private appraisalService: AppraisalService,
private employeeService: EmployeeService,
private cdr: ChangeDetectorRef,
......@@ -62,12 +69,20 @@ export class PmsCompetencyComponent {
}
ngOnInit(): void {
if (this.appraisalCompentencyList.length) {
this.currentPart = this.currentPart == '' ? this.appraisalCompentencyList[0].comType : this.currentPart
this.currentPart = this.fCurrentPart == '' ? this.appraisalCompentencyList[0].comType : this.fCurrentPart
}
this.getAppraisalCompentencyForm(0)
this.getSettingList()
this.getEvaluatee()
}
ngOnChanges(changes: SimpleChanges): void {
if (changes['currentTap']?.currentValue||changes['appraisalCompentencyList']?.currentValue) {
if (this.appraisalCompentencyList.length) {
this.currentPart = this.fCurrentPart == '' ? this.appraisalCompentencyList[0].comType : this.fCurrentPart
}
this.getAppraisalCompentencyForm(0)
}
}
getEvaluatee() {
this.evaluatee.loading = true
......@@ -99,7 +114,12 @@ export class PmsCompetencyComponent {
getAppraisalCompentencyForm(index: number) {
if (this.appraisalCompentencyList.length) {
this.appraisalCompentencyIndex = index
this.currentPart = this.appraisalCompentencyList[this.appraisalCompentencyIndex].comType
if (this.fCurrentPart) {
this.currentPart = this.fCurrentPart
this.fCurrentPart = ''
} else {
this.currentPart = this.appraisalCompentencyList[this.appraisalCompentencyIndex].comType
}
this.biOpen.clear()
this.appraisalCompentencyFilter().forEach((x, i) => {
this.biOpen.set(x.groupAssessment1.competencyIndicatorsCourses1Mini.competencyIndicatorsCourses0.competencyTopic.competencyTopicId, false)
......@@ -270,6 +290,7 @@ export class PmsCompetencyComponent {
this.inFormRemain(data)
).filter(data => data != 0).length
this.allFormRemain()
this.allWeightGap()
return remain
}
allFormRemain() {
......@@ -285,6 +306,14 @@ export class PmsCompetencyComponent {
this.compentencyForm.emit(this.appraisalCompentencyList)
this.compentencyFormRemain.emit(remain)
}
allWeightGap() {
this.appraisalCompentencyList.forEach(x => {
this.inforWeight.set(x.comType, x.masfromEvaluationAssessment1lList[0].averageScore + '')
this.inforGap.set(x.comType, this.calGap(x.masfromEvaluationAssessment1lList[0].averageScore) ?? '')
})
this.sendInforWeight.emit(this.inforWeight)
this.sendInforGap.emit(this.inforGap)
}
allBiOpen(status: boolean, part?: string) {
this.biOpen.forEach((_, key) => {
......
.hover-visible {
.hover-show {
opacity: 0;
}
}
.hover-visible:hover {
.hover-show {
opacity: 1;
}
}
......@@ -18,12 +18,11 @@ export class PmsFormEmployeeComponent {
@Input() evaluaterId = ""
@Input() evaluationForm: 'self' | 'sup' = "self"
evaluatee: { loading: boolean, data: EmployeeModel } = { loading: false, data: new MyEmployeeModel() }
currentPart = ""
@Output() sendReturnPath: EventEmitter<any> = new EventEmitter<any>();
starRate = 5;
url1 = '';
url2 = '';
selectedItems = [];
dropdownSettings = {};
......@@ -39,8 +38,7 @@ export class PmsFormEmployeeComponent {
{ id: '5', itemName: 'Bootstrap' },
];
compentency: { loading: boolean, data?: CompetencyModel, dataList: CompetencyModel[] } = { loading: false, data: undefined, dataList: [] }
compentency: { loading: boolean, originalData?: CompetencyModel, data?: CompetencyModel, dataList: CompetencyModel[] } = { loading: false, data: undefined, dataList: [] }
canSave = false
canEdit = false
canDraft = false
......@@ -54,8 +52,25 @@ export class PmsFormEmployeeComponent {
compentencyWeightScore = ""
compentencyGap = ""
inforWeight: Map<string, string> = new Map<string, string>()
inforGap: Map<string, string> = new Map<string, string>()
kpiScorePart: { text: string, score: string }[] = []
menuClose: Map<string, boolean> = new Map<string, boolean>()
hasPushedState = false;
companyId = ""
constructor(
private router: Router,
private employeeService: EmployeeService,
private appraisalService: AppraisalService,
private cdr: ChangeDetectorRef,
private tokenService: TokenService
) {
}
currentStepText = () => {
if (this.compentency.data) {
if (this.compentency.data.apsassessy.employeeId == this.evaluaterId) {
......@@ -223,24 +238,11 @@ export class PmsFormEmployeeComponent {
year: 'numeric'
});
};
hasPushedState = false;
companyId = ""
handleBack = (event: PopStateEvent) => {
this.returnPath()
this.router.navigate(['/supervisor-evaluation']);
};
constructor(
private router: Router,
private employeeService: EmployeeService,
private appraisalService: AppraisalService,
private cdr: ChangeDetectorRef,
private tokenService: TokenService
) {
}
ngOnDestroy() {
window.removeEventListener('popstate', this.handleBack);
......@@ -280,7 +282,9 @@ export class PmsFormEmployeeComponent {
}
selectDataList(data: CompetencyModel) {
this.compentency.data = JSON.parse(JSON.stringify(data))
this.compentency.originalData = this.deepClone(data)
this.compentency.data = this.deepClone(data)
this.cdr.detectChanges()
if (this.compentency.data) {
this.currentTap = "ข้อมูลการประเมิน"
this.compentency.data.commentAll.sort((a, b) => new Date(b.commentDate).getTime() - new Date(a.commentDate).getTime());
......@@ -425,7 +429,7 @@ export class PmsFormEmployeeComponent {
type StepKey = 'apsassessy' | 'apsapprove1' | 'apsapprove2' | 'apsapprove3' | 'apsapprove4' | 'apsapprove5';
const steps: StepKey[] = ['apsassessy', 'apsapprove1', 'apsapprove2', 'apsapprove3', 'apsapprove4', 'apsapprove5'];
const stepIndex = parseInt(this.compentency.data.currentStep, 10);
const updatedData = JSON.parse(JSON.stringify(this.compentency.data));
const updatedData = this.deepClone(this.compentency.data)
if (approveStatus === '3' && stepIndex >= 2) {
const prevKey: StepKey = steps[stepIndex - 1];
updatedData[prevKey] = {
......@@ -531,4 +535,162 @@ export class PmsFormEmployeeComponent {
}
}
}
changeForm(item: CompetencyModel) {
const ignorePart = [
'competency',
'!competency[].apsassessy',
'!competency[].apsapprove1',
'!competency[].apsapprove2',
'!competency[].apsapprove3',
'!competency[].apsapprove4',
'!competency[].apsapprove5',
'!competency[].masfromEvaluationAssessment1lList[].apsassessyDate',
'!competency[].masfromEvaluationAssessment1lList[].apsapprove1Date',
'!competency[].masfromEvaluationAssessment1lList[].apsapprove2Date',
'!competency[].masfromEvaluationAssessment1lList[].apsapprove3Date',
'!competency[].masfromEvaluationAssessment1lList[].apsapprove4Date',
'!competency[].masfromEvaluationAssessment1lList[].apsapprove5Date',
'!competency[].masfromEvaluationAssessment1lList[].numberCheck1',
'!competency[].masfromEvaluationAssessment1lList[].numberCheck2',
'!competency[].masfromEvaluationAssessment1lList[].numberCheck3',
'!competency[].masfromEvaluationAssessment1lList[].numberCheck4',
'!competency[].masfromEvaluationAssessment1lList[].numberCheck5',
'!competency[].masfromEvaluationAssessment1lList[].weightedTotal',
'!competency[].masfromEvaluationAssessment1lList[].averageScore',
'pms',
'!pms.gradeScore',
'!pms.apsassessyDate',
'!pms.apsapprove1Date',
'!pms.apsapprove2Date',
'!pms.apsapprove3Date',
'!pms.apsapprove4Date',
'!pms.apsapprove5Date',
'!pms.netScore',
'!pms.part1SumScore',
'!pms.part2SumScore',
'!pms.part3SumScore',
'!pms.part4SumScore',
'!pms.part5SumScore',
'!pms.part6SumScore',
'!pms.part7SumScore',
]
const diffs = this.findDifferencesInclude(
this.compentency.data,
this.compentency.originalData,
ignorePart
);
if (diffs.mini.length) {
Swal.fire({
icon: 'warning',
title: 'มีการประเมินโดยที่ยังไม่มีการบันทึก',
text: 'คุณต้องการเปลี่ยนรอบการประเมินหรือไม่',
showCancelButton: true,
confirmButtonText: 'ยืนยัน',
cancelButtonText: 'ยกเลิก',
customClass: {
title: '!swal2-title-mt-20px',
actions: '!swal2-actions-mt-20px',
confirmButton: '!swal2-button-bg-green',
cancelButton: '!swal2-button-bg-gray',
},
}).then((result) => {
if (result.isConfirmed) {
this.selectDataList(item)
} else if (result.dismiss === Swal.DismissReason.cancel) {
}
})
} else {
this.selectDataList(item)
}
}
deepClone(obj: any) {
return JSON.parse(JSON.stringify(obj));
}
findDifferencesInclude(
obj1: any,
obj2: any,
rawPaths: string[] = [''],
prefix = ''
): { full: string[]; mini: string[] } {
const full: string[] = [];
const mini: string[] = [];
const includePaths = rawPaths.filter(p => !p.startsWith('!'));
const excludePaths = rawPaths
.filter(p => p.startsWith('!'))
.map(p => p.slice(1));
// แปลง excludePaths เป็น regex สำหรับตรวจสอบ
const excludePatterns = excludePaths.map(p => {
const pattern = p.replace(/\./g, '\\.').replace(/\[\]/g, '\\[\\d+\\]');
return new RegExp(`^${pattern}`);
});
const isExcluded = (path: string) => excludePatterns.some(r => r.test(path));
const isIncluded = (path: string) => {
if (includePaths.length === 0) return true;
return includePaths.some(inc => path.startsWith(inc));
};
// ฟังก์ชันช่วยสร้าง path ใหม่
const makePath = (base: string, key: string | number) =>
base ? (typeof key === 'number' ? `${base}[${key}]` : `${base}.${key}`) : String(key);
// เช็คกรณี array
if (Array.isArray(obj1) && Array.isArray(obj2)) {
const maxLength = Math.max(obj1.length, obj2.length);
for (let i = 0; i < maxLength; i++) {
const fullPath = makePath(prefix, i);
if (isExcluded(fullPath) || !isIncluded(fullPath)) continue;
const val1 = obj1[i];
const val2 = obj2[i];
if (val1 === val2) continue;
if (val1 && val2 && typeof val1 === 'object' && typeof val2 === 'object') {
const diffs = this.findDifferencesInclude(val1, val2, rawPaths, fullPath);
full.push(...diffs.full);
mini.push(...diffs.mini);
} else {
full.push(`${fullPath}: ${JSON.stringify(val1)} !== ${JSON.stringify(val2)}`);
const cleanFieldName = String(i);
mini.push(`${cleanFieldName}: ${JSON.stringify(val1)} !== ${JSON.stringify(val2)}`);
}
}
return { full, mini };
}
// กรณี object
const keys = new Set([
...(obj1 && typeof obj1 === 'object' ? Object.keys(obj1) : []),
...(obj2 && typeof obj2 === 'object' ? Object.keys(obj2) : []),
]);
for (const key of keys) {
const fullPath = makePath(prefix, key);
if (isExcluded(fullPath) || !isIncluded(fullPath)) continue;
const val1 = obj1?.[key];
const val2 = obj2?.[key];
if (val1 === val2) continue;
const bothAreObjects = val1 && val2 && typeof val1 === 'object' && typeof val2 === 'object';
if (bothAreObjects) {
const diffs = this.findDifferencesInclude(val1, val2, rawPaths, fullPath);
full.push(...diffs.full);
mini.push(...diffs.mini);
} else {
full.push(`${fullPath}: ${JSON.stringify(val1)} !== ${JSON.stringify(val2)}`);
const fieldName = String(key).replace(/\[\d+\]/g, '');
mini.push(`${fieldName}: ${JSON.stringify(val1)} !== ${JSON.stringify(val2)}`);
}
}
return { full, mini };
}
}
\ No newline at end of file
<ng-container *ngTemplateOutlet="idpEvaluation"></ng-container>
<ng-template #idpEvaluation>
<ng-container *ngIf="appraisalIdp">
<div style="height: 46vh;overflow-y: auto;">
<div class="pb-2rem px-2rem">
<div style="overflow-y: auto;" [ngStyle]="{'height': canSave?'calc(100vh - 414px)':'calc(100vh - 285pxpx)'}">
<div class="pb-2rem">
<div class="font-size-18px font-weight-700 text-primary">
แผนพัฒนาบุคคลากรรายบุคคล
</div>
</div>
<div class="pb-2rem px-2rem">
<div class="pb-2rem">
<div class="font-size-18px font-weight-700 text-gray-500">
ส่วนที่ 1: ข้อมูลทั่วไป
</div>
</div>
<div class="pb-2rem px-2rem">
<div class="pb-2rem">
<div class="grid grid-cols-6">
<div class="col-span-6 grid grid-cols-6">
<div class="col-span-3 border p-2 pb-4">
......@@ -84,12 +84,12 @@
</div>
</div>
</div>
<div class="pb-2rem px-2rem">
<div class="pb-2rem">
<div class="font-size-18px font-weight-700 text-gray-500">
ส่วนที่ 2: แนวทางการพัฒนา
</div>
</div>
<div class="py-1rem px-2rem">
<div class="py-1rem">
<div class="py-2 grid grid-cols-6 gap-3">
<div class="col-span-6">หมายเหตุ : กรณี HR จัดอบรมให้ต้องเป็นไปตามเกณฑ์ที่ส่วนกลางกำหนดขึ้น</div>
<div class="col-span-6 grid grid-cols-6 gap-2">
......@@ -126,7 +126,7 @@
</div>
</div>
</div>
<div class="pb-2rem px-2rem">
<div class="pb-2rem">
<div class=" rounded-top-0.65rem">
<table class="ti-custom-table ti-custom-table-head ti-custom-table-hover2">
<thead class="height-50px">
......
import { ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { ChangeDetectorRef, Component, EventEmitter, Input, Output, SimpleChanges, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Idp } from 'src/app/shared/model/competency.model';
import { CompetencycourseMiniModel, MyCompetencycourseMiniModel } from 'src/app/shared/model/competencycourse-mini.model';
......@@ -19,6 +19,7 @@ interface table {
styleUrls: ['./pms-idp.component.scss']
})
export class PmsIdpComponent {
@Input() canSave = false
@Input() pathTitle: string[] = []
@Input() evaluationRoundId = ""
@Input() evaluateeId = ""
......@@ -31,6 +32,7 @@ export class PmsIdpComponent {
@Input() canEdit = false
@Input() dateIso = ""
@Input() currentStep = ""
@Input() currentTap = ""
@Output() idpForm: EventEmitter<any> = new EventEmitter<any>();
competencycourse: { loading: boolean, data: CompetencycourseMiniModel[] } = { loading: false, data: [] }
......@@ -54,6 +56,11 @@ export class PmsIdpComponent {
this.getFormIdp()
this.getCompetencycourseMiniList()
}
ngOnChanges(changes: SimpleChanges): void {
if (changes['currentTap']?.currentValue||changes['appraisalIdp']?.currentValue) {
this.getFormIdp()
}
}
getCompetencycourseMiniList() {
this.competencycourse.loading = false
this.competencycourseService.getMiniList().subscribe({
......
<p>pms-information works!</p>
<div class="flex flex-col gap-2" style="overflow-y: auto;"
[ngStyle]="{'height': canSave?'calc(100vh - 414px)':'calc(100vh - 285px)'}">
<div class="flex">
<button type="button" class="p-4 w-full bg-secondary text-white text-left" style="border-radius:20px"
(click)="menuClose.set('Compentency',!menuClose.get('Compentency'))">
รายละเอียดประเมินสมรรถนะ (Compentency)
</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 text-center">คะแนนเฉลี่ย</th>
<th scope="col text-center">ผล GAP</th>
<th scope="col text-center">การจัดการ</th>
</tr>
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalCompentencyList; let i=index">
<tr class="border-b border-gray-200">
<td class="py-2" style="vertical-align: top">
{{item.masfromEvaluationAssessment1lList[0].competencyType.tdesc}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{formatThaiDate(item.masfromEvaluationRound.apsPeriodStart)}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{formatThaiDate(item.masfromEvaluationRound.apsPeriodEnd)}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{inforWeight.get(item.comType) !=='null'?inforWeight.get(item.comType): ''}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{inforGap.get(item.comType)!=='null'?inforGap.get(item.comType): ''}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
<div class="flex justify-center">
<button type="button" class="ti-btn rounded-sm"
[class]="statusButtonClass(statusType)"
(click)="sendCurrentTap.emit('แบบประเมินสมรรถนะ');sendCurrentPart.emit(statusType)"
style="height: 15px; width: 45px; font-size: 12px; display: flex; align-items: center; justify-content: center;margin-left:4px;">
{{item.comType}}
</button>
</div>
</td>
</tr>
</ng-container>
</tbody>
</table>
</ng-container>
<div class="flex" *ngIf="appraisalPms">
<button type="button" class="p-4 w-full bg-secondary text-white text-left" style="border-radius:20px"
(click)="menuClose.set('PMS',!menuClose.get('PMS'))">
รายละเอียดประเมินผลการปฏิบัติงาน (PMS)
</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 text-center">ผลการประเมิน</th>
<th scope="col text-center">เกรด</th>
<th scope="col text-center">การจัดการ</th>
</tr>
</thead>
<tbody>
<tr class="border-b border-gray-200">
<td class="py-2" style="vertical-align: top">
{{kpiName}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{formatThaiDate(appraisalPms.pmsMasfromEvaluationRoundModel.apsPeriodStart)}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{formatThaiDate(appraisalPms.pmsMasfromEvaluationRoundModel.apsPeriodEnd)}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{kpiScore}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
{{kpiGrade}}
</td>
<td class="py-2 text-center" style="vertical-align: top">
<div class="flex justify-center">
<button type="button" class="ti-btn rounded-sm" [class]="statusButtonClass(statusType)"
(click)="sendCurrentTap.emit('ประเมินผลการปฏิบัติงาน');sendCurrentPart.emit(statusType)"
style="height: 15px; width: 45px; font-size: 12px; display: flex; align-items: center; justify-content: center;margin-left:4px;">
PMS
</button>
</div>
</td>
</tr>
</tbody>
</table>
</ng-container>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Competency, Pms } from 'src/app/shared/model/competency.model';
@Component({
selector: 'app-pms-information',
......@@ -6,5 +7,44 @@ import { Component } from '@angular/core';
styleUrls: ['./pms-information.component.scss']
})
export class PmsInformationComponent {
@Input() canSave = false
@Input() statusType = ''
@Input() inforWeight: Map<string, string> = new Map<string, string>()
@Input() inforGap: Map<string, string> = new Map<string, string>()
@Input() appraisalCompentencyList: Competency[] = []
@Input() appraisalPms?: Pms
@Input() kpiScore: string = ""
@Input() kpiGrade: string = ""
@Input() kpiName: string = ""
@Output() sendCurrentTap: EventEmitter<any> = new EventEmitter<any>();
@Output() sendCurrentPart: EventEmitter<any> = new EventEmitter<any>();
menuClose: Map<string, boolean> = new Map<string, boolean>()
statusButtonClass = (status: string) => {
if (status === "no access") {
return "ti-btn-soft-mute"
} else if (status === "pending") {
return "ti-btn-soft-secondary"
} else if (status === "evaluating") {
return "ti-btn-soft-warning"
} else if (status === "completed") {
return "ti-btn-soft-success"
} else if (status === "rejected") {
return "ti-btn-soft-danger"
} else {
return ""
}
}
formatThaiDate(dateStr?: string): string {
if (!dateStr) return ''
const months = [
'', 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน',
'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'
];
const [year, month, day] = dateStr.split('-').map(Number);
const thaiYear = year + 543;
const thaiMonth = months[month];
return `${day} ${thaiMonth} ${thaiYear}`;
}
}
......@@ -9,7 +9,7 @@
(click)="scrollToMenu(currentTap == 'ประเมินผลการปฏิบัติงาน'?('menu-part-'+(i+1)):('menu-part-'+(i+8)));currentPart=item;toggleAllParts(true,item)"
style="border-radius:20px;width: 100px"
[ngClass]="{'!bg-primary text-white':currentPart==item}">
{{item}}
<span class="leading-none">{{ item }}</span>
<ng-container *ngIf="currentTap == 'ประเมินผลการปฏิบัติงาน'">
<ng-container *ngIf="remainList()[i]>=0">
&nbsp;
......@@ -26,15 +26,16 @@
</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 class="bg-white cursor-pointer border ti ti-chevron-down"
<i title="แสดงทั้งหมด" class="bg-white cursor-pointer border ti ti-chevron-down"
style="padding: 1px;border-radius:5px;font-size:27px"
(click)="toggleAllParts(true);currentPart=''"></i>
<i class="bg-white cursor-pointer border ti ti-chevron-up"
<i title="ปิดทั้งหมด" class="bg-white cursor-pointer border ti ti-chevron-up"
style="padding: 1px;border-radius:5px;font-size:27px"
(click)="toggleAllParts(false);currentPart=''"></i>
</div>
</div>
<div #scrollContainer class="flex flex-col gap-2" style="height:40vh;overflow-y: auto;">
<div #scrollContainer class="flex flex-col gap-2" style="overflow-y: auto;"
[ngStyle]="{'height': canSave?'calc(100vh - 471px)':'calc(100vh - 342px)'}">
<ng-container *ngIf="currentTap=='ประเมินผลการปฏิบัติงาน'">
<ng-container *ngIf="appraisalPms?.part1Detail?.length then part1 else noData"></ng-container>
<ng-container *ngIf="appraisalPms?.part2Detail?.length then part2 else noData"></ng-container>
......
......@@ -27,6 +27,7 @@ export interface LevelStarModel {
styleUrls: ['./pms-kpi.component.scss']
})
export class PmsKpiComponent {
@Input() canSave = false
data8List: Part8Model[] = [{
id: 1,
evaluationFactor: "Part 1 : ประเมินผลการปฏิบัติงานตามนโยบายบริษัท (Corporate KPI)",
......@@ -114,11 +115,6 @@ export class PmsKpiComponent {
const key = targetDetail[index ?? 0] as keyof Part5Detail;
return item[key];
}
// ngOnChanges(changes: SimpleChanges): void {
// if (changes['evaluateeId']?.currentValue || changes['evaluaterId']?.currentValue) {
// this.toggleAllParts(this.evaluateeId == this.evaluaterId)
// }
// }
ngOnInit(): void {
this.partOpen.clear()
this.partShow = this.currentTap == 'ประเมินผลการปฏิบัติงาน' ? ['PART 1', 'PART 2', 'PART 3', 'PART 4', 'PART 5', 'PART 6', 'PART 7'] : ['PART 8', 'PART 9', 'PART 10']
......@@ -128,8 +124,20 @@ export class PmsKpiComponent {
this.getPmsGroupGradeList()
this.getAppraisalPmsForm()
this.allFormRemain()
this.sendScorePart()
}
ngOnChanges(changes: SimpleChanges): void {
if (changes['currentTap']?.currentValue || changes['appraisalPms']?.currentValue) {
this.partOpen.clear()
this.partShow = this.currentTap == 'ประเมินผลการปฏิบัติงาน' ? ['PART 1', 'PART 2', 'PART 3', 'PART 4', 'PART 5', 'PART 6', 'PART 7'] : ['PART 8', 'PART 9', 'PART 10']
this.partShow.forEach(x => {
this.partOpen.set(x, false)
})
this.getAppraisalPmsForm()
this.allFormRemain()
this.sendScorePart()
}
}
getAppraisalPmsForm() {
this.data8List.forEach((x, i) => {
if (x.id == 1 && this.appraisalPms?.part1Percentage) {
......@@ -527,7 +535,8 @@ export class PmsKpiComponent {
sendScorePart() {
if (this.appraisalPms) {
const score = this.data8List.map((x, i) => ({ text: "PART " + (i + 1), score: this.numberFixed2(x.netScore) })).concat([{ text: "สุทธิ", score: this.calNetScore() + '' }, { text: "Grade", score: this.appraisalPms.gradeScore }])
const gradeScore = this.groupGrade.dataList.find(item => Math.ceil(+this.calNetScore()) >= item.gradeMinScore && Math.ceil(+this.calNetScore()) <= item.gradeMaxScore);
const score = this.data8List.map((x, i) => ({ text: "PART " + (i + 1), score: this.numberFixed2(x.netScore) })).concat([{ text: "สุทธิ", score: this.calNetScore() + '' }, { text: "Grade", score: gradeScore?.gradeDetail || '' }])
this.scorePart.emit(score)
}
}
......
<ng-container *ngIf="!onEdit">
<!-- <app-page-header [pathTitle]="pathTitle"></app-page-header> -->
<ng-container *ngTemplateOutlet="selfEvaluation"></ng-container>
</ng-container>
<ng-template #selfEvaluation>
......
......@@ -95,8 +95,8 @@ export class SupervisorEvaluationComponent {
}
decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง
let base64Url = token.split('.')[1];
let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
......
......@@ -164,8 +164,8 @@ export class SidebarComponent {
}
// decodeJWT(token: string) {
// let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload
// let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง
// let base64Url = token.split('.')[1];
// let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
// let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
// return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
// }).join(''));
......
......@@ -25111,14 +25111,14 @@ div:where(.swal2-container) div:where(.swal2-validation-message) {
}
.text-soft-secondary {
color: rgb(var(--color-secondary) / 0.1);
color: rgb(var(--color-secondary) / 0.25);
}
.text-soft-secondary:hover {
color: rgb(var(--color-secondary));
}
.\!text-soft-secondary {
color: rgb(var(--color-secondary) / 0.1) !important;
color: rgb(var(--color-secondary) / 0.25) !important;
}
.\!text-soft-secondary:hover {
color: rgb(var(--color-secondary)) !important;
......
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