Commit d829e571 by Nattana Chaiyamat

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

parent bb296e71
...@@ -72,8 +72,8 @@ export class ManageUserComponent { ...@@ -72,8 +72,8 @@ export class ManageUserComponent {
} }
decodeJWT(token: string) { decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload let base64Url = token.split('.')[1];
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join('')); }).join(''));
......
...@@ -60,8 +60,8 @@ export class RolePermissionConfigComponent { ...@@ -60,8 +60,8 @@ export class RolePermissionConfigComponent {
this.getConfigList() this.getConfigList()
} }
decodeJWT(token: string) { decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload let base64Url = token.split('.')[1];
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join('')); }).join(''));
......
...@@ -75,8 +75,8 @@ export class SetAPasswordComponent { ...@@ -75,8 +75,8 @@ export class SetAPasswordComponent {
} }
decodeJWT(token: string) { decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload let base64Url = token.split('.')[1];
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join('')); }).join(''));
......
...@@ -82,8 +82,8 @@ export class UserSettingsComponent { ...@@ -82,8 +82,8 @@ export class UserSettingsComponent {
} }
decodeJWT(token: string) { decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload let base64Url = token.split('.')[1];
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join('')); }).join(''));
......
...@@ -672,8 +672,8 @@ export class SubEmployeeRegistrationComponent { ...@@ -672,8 +672,8 @@ export class SubEmployeeRegistrationComponent {
} }
decodeJWT(token: string) { decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload let base64Url = token.split('.')[1];
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join('')); }).join(''));
......
import { ViewportScroller } from '@angular/common'; 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 { Competency, MasfromEvaluationAssessment2List } from 'src/app/shared/model/competency.model';
import { EmployeeModel, MyEmployeeModel } from 'src/app/shared/model/employee.model'; import { EmployeeModel, MyEmployeeModel } from 'src/app/shared/model/employee.model';
import { SettingAssessmentModel, MySettingAssessmentModel } from 'src/app/shared/model/setting-assessment.model'; import { SettingAssessmentModel, MySettingAssessmentModel } from 'src/app/shared/model/setting-assessment.model';
...@@ -13,7 +13,9 @@ import Swal from 'sweetalert2'; ...@@ -13,7 +13,9 @@ import Swal from 'sweetalert2';
styleUrls: ['./pms-competency.component.scss'] styleUrls: ['./pms-competency.component.scss']
}) })
export class PmsCompetencyComponent { export class PmsCompetencyComponent {
@Input() fCurrentPart = ""
currentPart = "" currentPart = ""
@Input() canSave = false
@Input() evaluateeId = "" @Input() evaluateeId = ""
@Input() evaluaterId = "" @Input() evaluaterId = ""
@Input() appraisalCompentencyList: Competency[] = [] @Input() appraisalCompentencyList: Competency[] = []
...@@ -24,9 +26,12 @@ export class PmsCompetencyComponent { ...@@ -24,9 +26,12 @@ export class PmsCompetencyComponent {
@Output() compentencyScore: EventEmitter<any> = new EventEmitter<any>(); @Output() compentencyScore: EventEmitter<any> = new EventEmitter<any>();
@Output() compentencyWeightScore: EventEmitter<any> = new EventEmitter<any>(); @Output() compentencyWeightScore: EventEmitter<any> = new EventEmitter<any>();
@Output() compentencyGap: 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() canEdit = false
@Input() currentStep = "" @Input() currentStep = ""
@Input() dateIso = "" @Input() dateIso = ""
@Input() currentTap = ""
hoveredCode: string | null = null; hoveredCode: string | null = null;
hoveredCode2: string | null = null; hoveredCode2: string | null = null;
...@@ -53,6 +58,8 @@ export class PmsCompetencyComponent { ...@@ -53,6 +58,8 @@ export class PmsCompetencyComponent {
biScore: Map<string, number> = new Map<string, number>() biScore: Map<string, number> = new Map<string, number>()
@ViewChild('scrollContainer') scrollContainer!: ElementRef; @ViewChild('scrollContainer') scrollContainer!: ElementRef;
inforWeight: Map<string, string> = new Map<string, string>()
inforGap: Map<string, string> = new Map<string, string>()
constructor(private appraisalService: AppraisalService, constructor(private appraisalService: AppraisalService,
private employeeService: EmployeeService, private employeeService: EmployeeService,
private cdr: ChangeDetectorRef, private cdr: ChangeDetectorRef,
...@@ -62,12 +69,20 @@ export class PmsCompetencyComponent { ...@@ -62,12 +69,20 @@ export class PmsCompetencyComponent {
} }
ngOnInit(): void { ngOnInit(): void {
if (this.appraisalCompentencyList.length) { 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.getAppraisalCompentencyForm(0)
this.getSettingList() this.getSettingList()
this.getEvaluatee() 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() { getEvaluatee() {
this.evaluatee.loading = true this.evaluatee.loading = true
...@@ -99,7 +114,12 @@ export class PmsCompetencyComponent { ...@@ -99,7 +114,12 @@ export class PmsCompetencyComponent {
getAppraisalCompentencyForm(index: number) { getAppraisalCompentencyForm(index: number) {
if (this.appraisalCompentencyList.length) { if (this.appraisalCompentencyList.length) {
this.appraisalCompentencyIndex = index 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.biOpen.clear()
this.appraisalCompentencyFilter().forEach((x, i) => { this.appraisalCompentencyFilter().forEach((x, i) => {
this.biOpen.set(x.groupAssessment1.competencyIndicatorsCourses1Mini.competencyIndicatorsCourses0.competencyTopic.competencyTopicId, false) this.biOpen.set(x.groupAssessment1.competencyIndicatorsCourses1Mini.competencyIndicatorsCourses0.competencyTopic.competencyTopicId, false)
...@@ -270,6 +290,7 @@ export class PmsCompetencyComponent { ...@@ -270,6 +290,7 @@ export class PmsCompetencyComponent {
this.inFormRemain(data) this.inFormRemain(data)
).filter(data => data != 0).length ).filter(data => data != 0).length
this.allFormRemain() this.allFormRemain()
this.allWeightGap()
return remain return remain
} }
allFormRemain() { allFormRemain() {
...@@ -285,6 +306,14 @@ export class PmsCompetencyComponent { ...@@ -285,6 +306,14 @@ export class PmsCompetencyComponent {
this.compentencyForm.emit(this.appraisalCompentencyList) this.compentencyForm.emit(this.appraisalCompentencyList)
this.compentencyFormRemain.emit(remain) 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) { allBiOpen(status: boolean, part?: string) {
this.biOpen.forEach((_, key) => { this.biOpen.forEach((_, key) => {
......
.hover-visible {
.hover-show {
opacity: 0;
}
}
.hover-visible:hover {
.hover-show {
opacity: 1;
}
}
...@@ -18,12 +18,11 @@ export class PmsFormEmployeeComponent { ...@@ -18,12 +18,11 @@ export class PmsFormEmployeeComponent {
@Input() evaluaterId = "" @Input() evaluaterId = ""
@Input() evaluationForm: 'self' | 'sup' = "self" @Input() evaluationForm: 'self' | 'sup' = "self"
evaluatee: { loading: boolean, data: EmployeeModel } = { loading: false, data: new MyEmployeeModel() } evaluatee: { loading: boolean, data: EmployeeModel } = { loading: false, data: new MyEmployeeModel() }
currentPart = ""
@Output() sendReturnPath: EventEmitter<any> = new EventEmitter<any>(); @Output() sendReturnPath: EventEmitter<any> = new EventEmitter<any>();
starRate = 5; starRate = 5;
url1 = ''; url1 = '';
url2 = ''; url2 = '';
selectedItems = []; selectedItems = [];
dropdownSettings = {}; dropdownSettings = {};
...@@ -39,8 +38,7 @@ export class PmsFormEmployeeComponent { ...@@ -39,8 +38,7 @@ export class PmsFormEmployeeComponent {
{ id: '5', itemName: 'Bootstrap' }, { id: '5', itemName: 'Bootstrap' },
]; ];
compentency: { loading: boolean, originalData?: CompetencyModel, data?: CompetencyModel, dataList: CompetencyModel[] } = { loading: false, data: undefined, dataList: [] }
compentency: { loading: boolean, data?: CompetencyModel, dataList: CompetencyModel[] } = { loading: false, data: undefined, dataList: [] }
canSave = false canSave = false
canEdit = false canEdit = false
canDraft = false canDraft = false
...@@ -54,8 +52,25 @@ export class PmsFormEmployeeComponent { ...@@ -54,8 +52,25 @@ export class PmsFormEmployeeComponent {
compentencyWeightScore = "" compentencyWeightScore = ""
compentencyGap = "" compentencyGap = ""
inforWeight: Map<string, string> = new Map<string, string>()
inforGap: Map<string, string> = new Map<string, string>()
kpiScorePart: { text: string, score: 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 = () => { currentStepText = () => {
if (this.compentency.data) { if (this.compentency.data) {
if (this.compentency.data.apsassessy.employeeId == this.evaluaterId) { if (this.compentency.data.apsassessy.employeeId == this.evaluaterId) {
...@@ -223,24 +238,11 @@ export class PmsFormEmployeeComponent { ...@@ -223,24 +238,11 @@ export class PmsFormEmployeeComponent {
year: 'numeric' year: 'numeric'
}); });
}; };
hasPushedState = false;
companyId = ""
handleBack = (event: PopStateEvent) => { handleBack = (event: PopStateEvent) => {
this.returnPath() this.returnPath()
this.router.navigate(['/supervisor-evaluation']); this.router.navigate(['/supervisor-evaluation']);
}; };
constructor(
private router: Router,
private employeeService: EmployeeService,
private appraisalService: AppraisalService,
private cdr: ChangeDetectorRef,
private tokenService: TokenService
) {
}
ngOnDestroy() { ngOnDestroy() {
window.removeEventListener('popstate', this.handleBack); window.removeEventListener('popstate', this.handleBack);
...@@ -280,7 +282,9 @@ export class PmsFormEmployeeComponent { ...@@ -280,7 +282,9 @@ export class PmsFormEmployeeComponent {
} }
selectDataList(data: CompetencyModel) { 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) { if (this.compentency.data) {
this.currentTap = "ข้อมูลการประเมิน" this.currentTap = "ข้อมูลการประเมิน"
this.compentency.data.commentAll.sort((a, b) => new Date(b.commentDate).getTime() - new Date(a.commentDate).getTime()); this.compentency.data.commentAll.sort((a, b) => new Date(b.commentDate).getTime() - new Date(a.commentDate).getTime());
...@@ -425,7 +429,7 @@ export class PmsFormEmployeeComponent { ...@@ -425,7 +429,7 @@ export class PmsFormEmployeeComponent {
type StepKey = 'apsassessy' | 'apsapprove1' | 'apsapprove2' | 'apsapprove3' | 'apsapprove4' | 'apsapprove5'; type StepKey = 'apsassessy' | 'apsapprove1' | 'apsapprove2' | 'apsapprove3' | 'apsapprove4' | 'apsapprove5';
const steps: 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 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) { if (approveStatus === '3' && stepIndex >= 2) {
const prevKey: StepKey = steps[stepIndex - 1]; const prevKey: StepKey = steps[stepIndex - 1];
updatedData[prevKey] = { updatedData[prevKey] = {
...@@ -531,4 +535,162 @@ export class PmsFormEmployeeComponent { ...@@ -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-container *ngTemplateOutlet="idpEvaluation"></ng-container>
<ng-template #idpEvaluation> <ng-template #idpEvaluation>
<ng-container *ngIf="appraisalIdp"> <ng-container *ngIf="appraisalIdp">
<div style="height: 46vh;overflow-y: auto;"> <div style="overflow-y: auto;" [ngStyle]="{'height': canSave?'calc(100vh - 414px)':'calc(100vh - 285pxpx)'}">
<div class="pb-2rem px-2rem"> <div class="pb-2rem">
<div class="font-size-18px font-weight-700 text-primary"> <div class="font-size-18px font-weight-700 text-primary">
แผนพัฒนาบุคคลากรรายบุคคล แผนพัฒนาบุคคลากรรายบุคคล
</div> </div>
</div> </div>
<div class="pb-2rem px-2rem"> <div class="pb-2rem">
<div class="font-size-18px font-weight-700 text-gray-500"> <div class="font-size-18px font-weight-700 text-gray-500">
ส่วนที่ 1: ข้อมูลทั่วไป ส่วนที่ 1: ข้อมูลทั่วไป
</div> </div>
</div> </div>
<div class="pb-2rem px-2rem"> <div class="pb-2rem">
<div class="grid grid-cols-6"> <div class="grid grid-cols-6">
<div class="col-span-6 grid grid-cols-6"> <div class="col-span-6 grid grid-cols-6">
<div class="col-span-3 border p-2 pb-4"> <div class="col-span-3 border p-2 pb-4">
...@@ -84,12 +84,12 @@ ...@@ -84,12 +84,12 @@
</div> </div>
</div> </div>
</div> </div>
<div class="pb-2rem px-2rem"> <div class="pb-2rem">
<div class="font-size-18px font-weight-700 text-gray-500"> <div class="font-size-18px font-weight-700 text-gray-500">
ส่วนที่ 2: แนวทางการพัฒนา ส่วนที่ 2: แนวทางการพัฒนา
</div> </div>
</div> </div>
<div class="py-1rem px-2rem"> <div class="py-1rem">
<div class="py-2 grid grid-cols-6 gap-3"> <div class="py-2 grid grid-cols-6 gap-3">
<div class="col-span-6">หมายเหตุ : กรณี HR จัดอบรมให้ต้องเป็นไปตามเกณฑ์ที่ส่วนกลางกำหนดขึ้น</div> <div class="col-span-6">หมายเหตุ : กรณี HR จัดอบรมให้ต้องเป็นไปตามเกณฑ์ที่ส่วนกลางกำหนดขึ้น</div>
<div class="col-span-6 grid grid-cols-6 gap-2"> <div class="col-span-6 grid grid-cols-6 gap-2">
...@@ -126,7 +126,7 @@ ...@@ -126,7 +126,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="pb-2rem px-2rem"> <div class="pb-2rem">
<div class=" rounded-top-0.65rem"> <div class=" rounded-top-0.65rem">
<table class="ti-custom-table ti-custom-table-head ti-custom-table-hover2"> <table class="ti-custom-table ti-custom-table-head ti-custom-table-hover2">
<thead class="height-50px"> <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 { MatDialog } from '@angular/material/dialog';
import { Idp } from 'src/app/shared/model/competency.model'; import { Idp } from 'src/app/shared/model/competency.model';
import { CompetencycourseMiniModel, MyCompetencycourseMiniModel } from 'src/app/shared/model/competencycourse-mini.model'; import { CompetencycourseMiniModel, MyCompetencycourseMiniModel } from 'src/app/shared/model/competencycourse-mini.model';
...@@ -19,6 +19,7 @@ interface table { ...@@ -19,6 +19,7 @@ interface table {
styleUrls: ['./pms-idp.component.scss'] styleUrls: ['./pms-idp.component.scss']
}) })
export class PmsIdpComponent { export class PmsIdpComponent {
@Input() canSave = false
@Input() pathTitle: string[] = [] @Input() pathTitle: string[] = []
@Input() evaluationRoundId = "" @Input() evaluationRoundId = ""
@Input() evaluateeId = "" @Input() evaluateeId = ""
...@@ -31,6 +32,7 @@ export class PmsIdpComponent { ...@@ -31,6 +32,7 @@ export class PmsIdpComponent {
@Input() canEdit = false @Input() canEdit = false
@Input() dateIso = "" @Input() dateIso = ""
@Input() currentStep = "" @Input() currentStep = ""
@Input() currentTap = ""
@Output() idpForm: EventEmitter<any> = new EventEmitter<any>(); @Output() idpForm: EventEmitter<any> = new EventEmitter<any>();
competencycourse: { loading: boolean, data: CompetencycourseMiniModel[] } = { loading: false, data: [] } competencycourse: { loading: boolean, data: CompetencycourseMiniModel[] } = { loading: false, data: [] }
...@@ -54,6 +56,11 @@ export class PmsIdpComponent { ...@@ -54,6 +56,11 @@ export class PmsIdpComponent {
this.getFormIdp() this.getFormIdp()
this.getCompetencycourseMiniList() this.getCompetencycourseMiniList()
} }
ngOnChanges(changes: SimpleChanges): void {
if (changes['currentTap']?.currentValue||changes['appraisalIdp']?.currentValue) {
this.getFormIdp()
}
}
getCompetencycourseMiniList() { getCompetencycourseMiniList() {
this.competencycourse.loading = false this.competencycourse.loading = false
this.competencycourseService.getMiniList().subscribe({ 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({ @Component({
selector: 'app-pms-information', selector: 'app-pms-information',
...@@ -6,5 +7,44 @@ import { Component } from '@angular/core'; ...@@ -6,5 +7,44 @@ import { Component } from '@angular/core';
styleUrls: ['./pms-information.component.scss'] styleUrls: ['./pms-information.component.scss']
}) })
export class PmsInformationComponent { 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 @@ ...@@ -9,7 +9,7 @@
(click)="scrollToMenu(currentTap == 'ประเมินผลการปฏิบัติงาน'?('menu-part-'+(i+1)):('menu-part-'+(i+8)));currentPart=item;toggleAllParts(true,item)" (click)="scrollToMenu(currentTap == 'ประเมินผลการปฏิบัติงาน'?('menu-part-'+(i+1)):('menu-part-'+(i+8)));currentPart=item;toggleAllParts(true,item)"
style="border-radius:20px;width: 100px" style="border-radius:20px;width: 100px"
[ngClass]="{'!bg-primary text-white':currentPart==item}"> [ngClass]="{'!bg-primary text-white':currentPart==item}">
{{item}} <span class="leading-none">{{ item }}</span>
<ng-container *ngIf="currentTap == 'ประเมินผลการปฏิบัติงาน'"> <ng-container *ngIf="currentTap == 'ประเมินผลการปฏิบัติงาน'">
<ng-container *ngIf="remainList()[i]>=0"> <ng-container *ngIf="remainList()[i]>=0">
&nbsp; &nbsp;
...@@ -26,15 +26,16 @@ ...@@ -26,15 +26,16 @@
</ng-container> </ng-container>
<div class="flex justify-around !items-center border bg-white p-2 text-right" <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));"> 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" style="padding: 1px;border-radius:5px;font-size:27px"
(click)="toggleAllParts(true);currentPart=''"></i> (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" style="padding: 1px;border-radius:5px;font-size:27px"
(click)="toggleAllParts(false);currentPart=''"></i> (click)="toggleAllParts(false);currentPart=''"></i>
</div> </div>
</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="currentTap=='ประเมินผลการปฏิบัติงาน'">
<ng-container *ngIf="appraisalPms?.part1Detail?.length then part1 else noData"></ng-container> <ng-container *ngIf="appraisalPms?.part1Detail?.length then part1 else noData"></ng-container>
<ng-container *ngIf="appraisalPms?.part2Detail?.length then part2 else noData"></ng-container> <ng-container *ngIf="appraisalPms?.part2Detail?.length then part2 else noData"></ng-container>
......
...@@ -27,6 +27,7 @@ export interface LevelStarModel { ...@@ -27,6 +27,7 @@ export interface LevelStarModel {
styleUrls: ['./pms-kpi.component.scss'] styleUrls: ['./pms-kpi.component.scss']
}) })
export class PmsKpiComponent { export class PmsKpiComponent {
@Input() canSave = false
data8List: Part8Model[] = [{ data8List: Part8Model[] = [{
id: 1, id: 1,
evaluationFactor: "Part 1 : ประเมินผลการปฏิบัติงานตามนโยบายบริษัท (Corporate KPI)", evaluationFactor: "Part 1 : ประเมินผลการปฏิบัติงานตามนโยบายบริษัท (Corporate KPI)",
...@@ -114,11 +115,6 @@ export class PmsKpiComponent { ...@@ -114,11 +115,6 @@ export class PmsKpiComponent {
const key = targetDetail[index ?? 0] as keyof Part5Detail; const key = targetDetail[index ?? 0] as keyof Part5Detail;
return item[key]; return item[key];
} }
// ngOnChanges(changes: SimpleChanges): void {
// if (changes['evaluateeId']?.currentValue || changes['evaluaterId']?.currentValue) {
// this.toggleAllParts(this.evaluateeId == this.evaluaterId)
// }
// }
ngOnInit(): void { ngOnInit(): void {
this.partOpen.clear() 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 = 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 { ...@@ -128,8 +124,20 @@ export class PmsKpiComponent {
this.getPmsGroupGradeList() this.getPmsGroupGradeList()
this.getAppraisalPmsForm() this.getAppraisalPmsForm()
this.allFormRemain() 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() { getAppraisalPmsForm() {
this.data8List.forEach((x, i) => { this.data8List.forEach((x, i) => {
if (x.id == 1 && this.appraisalPms?.part1Percentage) { if (x.id == 1 && this.appraisalPms?.part1Percentage) {
...@@ -527,7 +535,8 @@ export class PmsKpiComponent { ...@@ -527,7 +535,8 @@ export class PmsKpiComponent {
sendScorePart() { sendScorePart() {
if (this.appraisalPms) { 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) this.scorePart.emit(score)
} }
} }
......
<ng-container *ngIf="!onEdit"> <ng-container *ngIf="!onEdit">
<!-- <app-page-header [pathTitle]="pathTitle"></app-page-header> -->
<ng-container *ngTemplateOutlet="selfEvaluation"></ng-container> <ng-container *ngTemplateOutlet="selfEvaluation"></ng-container>
</ng-container> </ng-container>
<ng-template #selfEvaluation> <ng-template #selfEvaluation>
......
...@@ -95,8 +95,8 @@ export class SupervisorEvaluationComponent { ...@@ -95,8 +95,8 @@ export class SupervisorEvaluationComponent {
} }
decodeJWT(token: string) { decodeJWT(token: string) {
let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload let base64Url = token.split('.')[1];
let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join('')); }).join(''));
......
...@@ -164,8 +164,8 @@ export class SidebarComponent { ...@@ -164,8 +164,8 @@ export class SidebarComponent {
} }
// decodeJWT(token: string) { // decodeJWT(token: string) {
// let base64Url = token.split('.')[1]; // ดึงส่วนที่เป็น Payload // let base64Url = token.split('.')[1];
// let base64 = base64Url.replace('-', '+').replace('_', '/'); // แก้ไข base64 ให้ถูกต้อง // let base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
// let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) { // let jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
// return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); // return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
// }).join('')); // }).join(''));
......
...@@ -25111,14 +25111,14 @@ div:where(.swal2-container) div:where(.swal2-validation-message) { ...@@ -25111,14 +25111,14 @@ div:where(.swal2-container) div:where(.swal2-validation-message) {
} }
.text-soft-secondary { .text-soft-secondary {
color: rgb(var(--color-secondary) / 0.1); color: rgb(var(--color-secondary) / 0.25);
} }
.text-soft-secondary:hover { .text-soft-secondary:hover {
color: rgb(var(--color-secondary)); color: rgb(var(--color-secondary));
} }
.\!text-soft-secondary { .\!text-soft-secondary {
color: rgb(var(--color-secondary) / 0.1) !important; color: rgb(var(--color-secondary) / 0.25) !important;
} }
.\!text-soft-secondary:hover { .\!text-soft-secondary:hover {
color: rgb(var(--color-secondary)) !important; 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