Commit ba9980ae by Nattana Chaiyamat

หน้าหัวหน้า ข้อมูลพนักงาน หน้าหลัก

parent 3ac40eaf
......@@ -52,6 +52,7 @@ import { ReportCom3Component } from '../report-component/report-com/report-com-3
import { ReportPms1Component } from '../report-component/report-pms/report-pms-1/report-pms-1.component';
import { ReportPms2Component } from '../report-component/report-pms/report-pms-2/report-pms-2.component';
import { ReportPms3Component } from '../report-component/report-pms/report-pms-3/report-pms-3.component';
import { EssProfileComponent } from '../ess-profile/ess-profile.component';
......@@ -75,7 +76,9 @@ const routes: Routes = [
// myComponent
{ path: "ess/profile", component: EssProfileComponent },
{ path: "ess/self-evaluation", title: 'ประเมินตนเอง', component: SelfEvaluationComponent },
{ path: "ess/self-evaluation/:part", title: 'ประเมินตนเอง', component: SelfEvaluationComponent },
{ path: "admin/day-type-registry", title: 'ประเมินตนเอง', component: DayTypeRegistryComponent },
{ path: "admin/company-registration", title: 'ทะเบียนบริษัท', component: CompanyRegistrationComponent },
{ path: "admin/job-description", title: 'ข้อมูลลักษณะงาน', component: JobDescriptionComponent },
......
......@@ -186,6 +186,7 @@ import { ReportCom3Component } from '../report-component/report-com/report-com-3
import { ReportPms1Component } from '../report-component/report-pms/report-pms-1/report-pms-1.component';
import { ReportPms2Component } from '../report-component/report-pms/report-pms-2/report-pms-2.component';
import { ReportPms3Component } from '../report-component/report-pms/report-pms-3/report-pms-3.component';
import { EssProfileComponent } from '../ess-profile/ess-profile.component';
export const MY_DATE_FORMATS = {
parse: {
......@@ -328,7 +329,8 @@ export class CustomDateAdapter extends NativeDateAdapter {
ReportCom3Component,
ReportPms1Component,
ReportPms2Component,
ReportPms3Component
ReportPms3Component,
EssProfileComponent
],
imports: [
CommonModule,
......
<header class="flex flex-col items-center gap-3 text-center">
<!-- โลโก้ -->
<img src="./assets/img/brand-logos/mySkill-x.png"
alt="mySkillX"
class="h-32 w-auto" />
<img src="./assets/img/brand-logos/mySkill-x.png" alt="mySkillX" class="h-32 w-auto" />
<!-- บรรทัดใหญ่ -->
......@@ -17,12 +14,10 @@
<!-- ◀︎ HERO -->
<aside class="hero-card bp-glow shrink-0 self-center lg:self-start">
<img src="assets/img/logos/HRD/1.png"
alt="Performance illustration"
class="hero-img" />
<img src="assets/img/logos/HRD/1.png" alt="Performance illustration" class="hero-img" />
<h4 class="hero-label">One X</h4>
<h3 class="hero-title">Performance &<br/>Competency</h3>
<h3 class="hero-title">Performance &<br />Competency</h3>
<button routerLink="/dashboard/projects" class="hero-btn">Dashboard</button>
......@@ -35,11 +30,50 @@
<section class="flex-grow">
<div class="grid gap-6 grid-cols-2 sm:grid-cols-3 md:grid-cols-4
xl:grid-cols-4 auto-rows-[150px]">
<div *ngFor="let m of modules" class="sub-card aspect-square" routerLink="/ess/self-evaluation">
<p class="sub-title">{{ m.title }}</p>
</div>
<ng-container *ngFor="let m of modules; let i = index">
<div *ngIf="m.route" class="sub-card aspect-square flex-col" [routerLink]="m.route"
style="justify-content: start ;align-items: start;">
<div class="flex" style="margin-bottom:6rem;margin-top:1rem">
<span
class="flex align-items-center justify-content-center rounded-circle text-white bg-primary text-left"
style="font-weight: 600;font-size: 1.5rem;">
{{i+1}}
</span>
</div>
<div class="flex">
<div class="sub-title2 text-left" [innerHTML]="m.title"></div>
</div>
</div>
<div *ngIf="m.file" class="sub-card aspect-square flex-col" (click)="openReport(m.file)"
style="justify-content: start ;align-items: start;">
<div class="flex " style="margin-bottom:6rem;margin-top:1rem">
<span
class="flex align-items-center justify-content-center rounded-circle text-white bg-primary text-left"
style="font-weight: 600;font-size: 1.5rem;">
{{i+1}}
</span>
</div>
<div class="flex">
<div class="sub-title2 text-left" [innerHTML]="m.title"></div>
</div>
</div>
<div *ngIf="!m.route&&!m.file" class="sub-card aspect-square flex-col"
style="justify-content: start ;align-items: start;">
<div class="flex " style="margin-bottom:6rem;margin-top:1rem">
<span
class="flex align-items-center justify-content-center rounded-circle text-white bg-primary text-left"
style="font-weight: 600;font-size: 1.5rem;">
{{i+1}}
</span>
</div>
<div class="flex">
<div class="sub-title2 text-left" [innerHTML]="m.title"></div>
</div>
</div>
</ng-container>
</div>
</section>
</div>
</main>
</main>
\ No newline at end of file
/* ===== base variables ===== */
$size-card : 150px; // ( ≥1280px จะขยายเป็น 170 )
$col-hero : 280px; // ความกว้างคอลัมน์ซ้าย
$gap-main : 2.5rem;
$size-card : 150px; // ( ≥1280px จะขยายเป็น 170 )
$col-hero : 280px; // ความกว้างคอลัมน์ซ้าย
$gap-main : 2.5rem;
$radius-main : 28px;
$radius-sub : 20px;
$dur : .35s;
$easing : cubic-bezier(.4,0,.2,1);
$shadow-base : 0 14px 30px -12px rgba(0,0,0,.18);
$shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
$radius-sub : 20px;
$dur : .35s;
$easing : cubic-bezier(.4, 0, .2, 1);
$shadow-base : 0 14px 30px -12px rgba(0, 0, 0, .18);
$shadow-deep : 0 20px 42px -16px rgba(0, 0, 0, .24);
/* ===== wrapper ===== */
.wrapper { max-width: 1400px; margin: 0 auto; padding: 3rem 1.25rem; margin-top: 5rem; }
.wrapper {
max-width: 1400px;
margin: 0 auto;
padding: 3rem 1.25rem;
margin-top: 5rem;
}
/* ===== GRID ชั้นแรก ===== */
.page-grid {
......@@ -18,7 +23,8 @@ $shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
gap: $gap-main;
grid-template-columns: $col-hero 1fr;
@media (max-width: 1023px) { /* < lg : 1 คอลัมน์ */
@media (max-width: 1023px) {
/* < lg : 1 คอลัมน์ */
grid-template-columns: 1fr;
}
}
......@@ -26,7 +32,7 @@ $shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
/* ===== HERO CARD (คงเดิม – ตัด flex ออก) ===== */
.hero-card {
width: 100%;
max-width: 280px; // ไม่เกินจอ desktop
max-width: 280px; // ไม่เกินจอ desktop
box-sizing: border-box;
padding-inline: clamp(1rem, 4vw, 1.75rem);
padding-block: 2rem 3rem;
......@@ -41,7 +47,10 @@ $shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
gap: 1.3rem;
transition: transform $dur $easing, box-shadow $dur $easing;
&:hover { transform: translateY(-6px); box-shadow: $shadow-deep; }
&:hover {
transform: translateY(-6px);
box-shadow: $shadow-deep;
}
/* glow */
&.bp-glow::before {
......@@ -49,42 +58,75 @@ $shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
position: absolute;
inset: -3px;
border-radius: inherit;
background: linear-gradient(135deg,#4f46e5,#ec4899 60%,#f59e0b);
background: linear-gradient(135deg, #4f46e5, #ec4899 60%, #f59e0b);
filter: blur(34px);
opacity: .17;
z-index: -1;
transition: opacity $dur;
}
&:hover.bp-glow::before { opacity: .27; }
&:hover.bp-glow::before {
opacity: .27;
}
}
@media (max-width: 639px) {
.hero-img {
max-width: 68%;
}
}
.hero-img {
width: 10rem;
}
.hero-label {
font: 600 .95rem/1.2 'Inter', sans-serif;
color: #3b82f6;
}
.hero-title {
font: 700 1.5rem/1.3 'Inter', sans-serif;
color: #1e3a8a;
}
@media (max-width: 639px){
.hero-img { max-width: 68%; }
.hero-btn {
@apply bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-full px-10 py-2 transition;
}
.back-link {
position: absolute;
left: 1.75rem;
bottom: 1rem;
font-size: .9rem;
color: #64748b;
transition: color .25s;
&:hover {
color: #3b82f6;
}
}
.hero-img { width: 10rem; }
.hero-label { font: 600 .95rem/1.2 'Inter',sans-serif; color:#3b82f6; }
.hero-title { font: 700 1.5rem/1.3 'Inter',sans-serif; color:#1e3a8a; }
.hero-btn { @apply bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-full px-10 py-2 transition; }
.back-link { position: absolute; left: 1.75rem; bottom: 1rem; font-size: .9rem; color:#64748b; transition: color .25s;
&:hover { color:#3b82f6; } }
/* ===== GRID ชั้นสอง – เมนูย่อย 2 แถวพอดี ===== */
.sub-grid {
display: grid;
grid-auto-flow: column; /* เติมแนวนอนก่อน */
grid-template-rows: repeat(2,$size-card);
grid-auto-flow: column;
/* เติมแนวนอนก่อน */
grid-template-rows: repeat(2, $size-card);
grid-auto-columns: $size-card;
gap: 1.5rem;
place-content: start;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
/* ≥1280px ขยายการ์ด */
@media (min-width: 1280px) {
grid-template-rows: repeat(2,170px);
grid-template-rows: repeat(2, 170px);
grid-auto-columns: 170px;
}
/* มือถือ: 2 คอลัมน์เสมอ */
@media (max-width: 639px) {
grid-template-rows: repeat(2,46vw);
grid-template-rows: repeat(2, 46vw);
grid-auto-columns: 46vw;
}
}
......@@ -94,25 +136,32 @@ $shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
aspect-ratio: 1 / 1;
position: relative;
border-radius: $radius-sub;
background: rgba(255,255,255,.5); /* glass */
background: rgba(255, 255, 255, .5);
/* glass */
backdrop-filter: blur(9px) saturate(170%);
box-shadow: 0 8px 18px -10px rgba(71,85,105,.25);
display: flex; align-items: center; justify-content: center;
text-align: center; padding: 1rem;
cursor: pointer; user-select: none;
box-shadow: 0 8px 18px -10px rgba(71, 85, 105, .25);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 1rem;
cursor: pointer;
user-select: none;
transition: transform .45s $easing, box-shadow .45s $easing, background .45s;
/* gradient rim */
&::before {
content: '';
position: absolute; inset: 0;
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
// background: linear-gradient(160deg,#60a5fa,#818cf8 50%,#a855f7);
background: linear-gradient(135deg,#4f46e5,#ec4899 60%,#f59e0b);
background: linear-gradient(135deg, #4f46e5, #ec4899 60%, #f59e0b);
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask-composite: exclude;
opacity: .45; transition: opacity .4s;
opacity: .45;
transition: opacity .4s;
}
&:hover {
......@@ -120,9 +169,12 @@ $shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
transform: translateY(-7px) rotateX(5deg) rotateY(-3deg);
box-shadow: $shadow-deep;
&::before { opacity: .9; }
&::before {
opacity: .9;
}
}
}
.sub-title {
font-weight: 600;
font-size: .9rem;
......@@ -131,3 +183,12 @@ $shadow-deep : 0 20px 42px -16px rgba(0,0,0,.24);
pointer-events: none;
word-break: break-word;
}
.sub-title2 {
font-weight: 600;
font-size: 1.5rem;
line-height: 2.25rem;
color: #2563eb;
pointer-events: none;
word-break: break-word;
}
\ No newline at end of file
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
interface SubModule {
title: string;
title: SafeHtml;
route?: string;
file?: string;
}
@Component({
selector: 'app-employee-self-service',
......@@ -9,18 +11,28 @@ interface SubModule {
styleUrls: ['./employee-self-service.component.scss']
})
export class EmployeeSelfServiceComponent {
// ▶︎ ภาพทางซ้าย (ปรับ path ตามจริง)
// ▶︎ ภาพทางซ้าย (ปรับ path ตามจริง)
heroImg = 'assets/illustrations/performance.svg';
// ▶︎ เมนูย่อย (ฝั่งขวา)
modules: SubModule[] = [
{ title: 'ประเมิน Competency & PMS' },
{ title: 'JD' },
{ title: 'Gap Analysis' },
{ title: 'Profile' },
{ title: 'Skill Map' },
{ title: 'Competency Base Pay' },
{ title: 'CDR' },
{ title: 'IDP' }
{ title: this.sanitizer.bypassSecurityTrustHtml('ประเมิน<p>Competency & PMS'), route: '/ess/self-evaluation' },
{ title: this.sanitizer.bypassSecurityTrustHtml('Job Description<p>รายละเอียดของงาน'), file: '2._JD.pdf' },
{ title: this.sanitizer.bypassSecurityTrustHtml('Gap Analysis<p>การวิเคราะห์ Gap'), file: '3._Gap_analysis.pdf' },
{ title: this.sanitizer.bypassSecurityTrustHtml('Profile<p>ข้อมูลพนักงาน'), route: '/ess/profile' },
{ title: this.sanitizer.bypassSecurityTrustHtml('Skill Map<p>ทักษะที่จำเป็นสำหรับแต่ละตำแหน่งงาน'), file: '5._skill_map.pdf' },
{ title: this.sanitizer.bypassSecurityTrustHtml('CDR : Competency Dictionary Roadmap<p>หลักสูตรฝึกอบรมตามระบบสมรรถนะ'), file: '6._CDR.pdf' },
{ title: this.sanitizer.bypassSecurityTrustHtml('IDP : Individual Development Plan<p>แผนพัฒนารายบุคคล'), route: '/ess/self-evaluation/IDP' },
{ title: this.sanitizer.bypassSecurityTrustHtml('Competency Base Pay<p>ค่าความสามารถพิเศษ') }
];
constructor(private sanitizer: DomSanitizer) {
}
openReport(file: string) {
const url = 'assets/reports/' + file;
window.open(url, '_blank');
}
}
.bg-gradient-custom {
background: linear-gradient(135deg, #4f46e5, #ec4899 60%, #f59e0b);
-webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
mask-size: 100% 100%;
mask-repeat: no-repeat;
}
\ No newline at end of file
import { ViewportScroller } from '@angular/common';
import { ChangeDetectorRef, Component } from '@angular/core';
import { EmployeeModel, MyEmployeeModel } from 'src/app/shared/model/employee.model';
import { MyStatusModel, StatusModel } from 'src/app/shared/model/status.model';
import { EmpStatusService } from 'src/app/shared/services/emp-status.service';
import { EmployeeService } from 'src/app/shared/services/employee.service';
import { environment } from 'src/environments/environment';
@Component({
selector: 'app-ess-profile',
templateUrl: './ess-profile.component.html',
styleUrls: ['./ess-profile.component.scss'],
})
export class EssProfileComponent {
employee: { loading: boolean, data: EmployeeModel } = { loading: false, data: new MyEmployeeModel() }
url = environment.baseUrl
empStatus: { loading: boolean, dataList: StatusModel[] } = { loading: false, dataList: [] }
constructor(
private employeeService: EmployeeService,
private empStatusService: EmpStatusService,
private cdr: ChangeDetectorRef,
private viewScroller: ViewportScroller,
) {
document.querySelector('#maincontent')?.classList.remove('main-content');
}
ngOnInit(): void {
this.viewScroller.scrollToPosition([0, 0]);
this.getEmpStatusList()
this.getProfileMini()
}
getProfileMini() {
this.employee.loading = true
this.employeeService.getProfileMini().subscribe({
next: response => {
this.employee.data = new MyEmployeeModel(response);
this.employee.loading = false;
this.cdr.detectChanges()
},
error: error => {
this.employee.loading = false;
this.cdr.detectChanges()
}
});
}
getEmpStatusList() {
this.empStatus.loading = false
this.empStatusService.getList().subscribe({
next: response => {
this.empStatus.dataList = response.map((x: any) => new MyStatusModel(x))
this.empStatus.loading = false
this.cdr.detectChanges()
}, error: error => {
this.empStatus.loading = false
this.cdr.detectChanges()
}
})
}
findEmpStatus(text: string) {
return this.empStatus.dataList.find(e => e.statusCode == text)?.tdesc || ''
}
reverseDate(text: string) {
return text.split('-').reverse().join('-')
}
}
......@@ -102,7 +102,10 @@
<tbody>
<ng-container
*ngFor="let bi of item2.groupAssessment1.competencyIndicatorsCourses1Mini.behavioralIndicatorsList;let i2 = index;let f = first">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(bi.behavioralIndicators,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(bi.behavioralIndicators)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">{{bi.behavioralIndicators}}</td>
<td class="py-2 text-center text-indigo-600 font-semibold" style="vertical-align: top">
{{bi.assessmentId}}</td>
......
......@@ -35,6 +35,7 @@ export class PmsCompetencyComponent {
hoveredCode: string | null = null;
hoveredCode2: string | null = null;
tableHover: Map<string, boolean> = new Map<string, boolean>()
setting: { loading: boolean, data: SettingAssessmentModel } = { loading: false, data: new MySettingAssessmentModel() }
checkSheet: {
......
......@@ -48,7 +48,8 @@
<div class="box shadow-md hover:shadow-xl transition m-0" style="border-radius:20px">
<div class="box-body py-2">
<div class="flex flex-col items-center gap-3">
<img [src]="evaluationForm=='sup' ? './assets/img/users/woman2.png' : './assets/img/users/man.PNG'"
<img
[src]="evaluatee.data.picture?url+'/employee/image/'+evaluatee.data.picture:'./assets/img/users/defaultperson.jpg'"
class="h-24 w-24 rounded-full ring-4 ring-primary object-cover" alt="profile-img" />
<ng-container *ngIf="kpiScorePart[kpiScorePart.length-1].score as grade">
<div class="flex gap-1">
......@@ -61,28 +62,6 @@
<span class="text-sm font-semibold text-gray-700">GRADE: {{ grade }}</span>
</ng-container>
</div>
<!-- <div class="flex flex-row gap-2"
[ngStyle]="{'justify-content':kpiScorePart[kpiScorePart.length-1].score?'space-between':'center'}">
<div
[ngClass]="{'w-full': !kpiScorePart[kpiScorePart.length-1].score,'w-1/2':kpiScorePart[kpiScorePart.length-1].score}">
<img [src]="evaluationForm=='sup'?'./assets/img/users/woman2.png':'./assets/img/users/man.PNG'"
class="w-24 h-24 rounded-full ring-4 ring-white/10 mx-auto" id="profile-img"
alt="profile-img" />
</div>
<div *ngIf="kpiScorePart[kpiScorePart.length-1].score" class="w-1/2 flex flex-col justify-center"
style="align-self: center;">
<div class="flex-1 flex flex-row gap-1 justify-center">
<div *ngFor="let item of [1,2,3,4,5]">
<i class="ti" style="font-size:20px"
[ngClass]="item <= gradeStar(kpiScorePart[kpiScorePart.length-1].score) ? 'ti-star-filled text-warning' : 'ti-star text-gray-300'"></i>
</div>
</div>
<div class="flex-1 text-center">
{{kpiScorePart[kpiScorePart.length-1].score ? ("GRADE : " +
kpiScorePart[kpiScorePart.length-1].score) : ''}}
</div>
</div>
</div> -->
</div>
</div>
</div>
......@@ -422,11 +401,7 @@
<div class="box-header">
<div class="flex flex-row gap-2">
<ng-container
*ngFor="let item of ['ข้อมูลการประเมิน'+
currentPart,'แบบประเมินสมรรถนะ'+
currentPart,'ประเมินผลการปฏิบัติงาน'+
currentPart,'สรุปคะแนนและข้อเสนอแนะ'+
currentPart,'แผนพัฒนาบุคลากร'+currentPart]">
*ngFor="let item of ['ข้อมูลการประเมิน','แบบประเมินสมรรถนะ','ประเมินผลการปฏิบัติงาน','สรุปคะแนนและข้อเสนอแนะ','แผนพัฒนาบุคลากร']">
<button type="button" class="flex-1 flex flex-row border bg-white p-2 justify-center"
style="border-radius:20px"
(click)="currentTap=item;(currentTap=='ประเมินผลการปฏิบัติงาน'||currentTap=='สรุปคะแนนและข้อเสนอแนะ'?currentPart='':null)"
......
......@@ -6,6 +6,8 @@ import { AppraisalService } from 'src/app/shared/services/appraisal.service';
import { EmployeeService } from 'src/app/shared/services/employee.service';
import { TokenService } from 'src/app/shared/services/token.service';
import Swal from 'sweetalert2';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { environment } from 'src/environments/environment';
@Component({
selector: 'app-pms-form-employee',
......@@ -14,6 +16,7 @@ import Swal from 'sweetalert2';
})
export class PmsFormEmployeeComponent {
@Input() currentTap = "ข้อมูลการประเมิน"
firstCurrentTap = ""
@Input() evaluateeId = ""
@Input() evaluaterId = ""
@Input() evaluationForm: 'self' | 'sup' = "self"
......@@ -21,6 +24,7 @@ export class PmsFormEmployeeComponent {
currentPart = ""
@Output() sendReturnPath: EventEmitter<any> = new EventEmitter<any>();
starRate = 5;
url = environment.baseUrl
url1 = '';
url2 = '';
......@@ -71,7 +75,8 @@ export class PmsFormEmployeeComponent {
private employeeService: EmployeeService,
private appraisalService: AppraisalService,
private cdr: ChangeDetectorRef,
private tokenService: TokenService
private tokenService: TokenService,
private route: ActivatedRoute
) {
}
......@@ -271,6 +276,11 @@ export class PmsFormEmployeeComponent {
}
ngOnInit() {
this.route.paramMap.subscribe((params: ParamMap) => {
if (params.get('part') == 'IDP') {
this.firstCurrentTap = 'แผนพัฒนาบุคลากร'
}
});
this.companyId = this.tokenService.getUser()?.companyid || ""
this.dateIso = this.currentDate.toISOString();
this.getEvaluatee()
......@@ -308,7 +318,8 @@ export class PmsFormEmployeeComponent {
this.compentency.data = this.deepClone(data)
this.cdr.detectChanges()
if (this.compentency.data) {
this.currentTap = "ข้อมูลการประเมิน"
this.currentTap = this.firstCurrentTap || "ข้อมูลการประเมิน"
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")
......@@ -731,4 +742,5 @@ export class PmsFormEmployeeComponent {
}
}, 0);
}
}
\ No newline at end of file
......@@ -20,7 +20,10 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalCompentencyList; let i=index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(item.masfromEvaluationAssessment1lList[0].competencyType.tdesc,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.masfromEvaluationAssessment1lList[0].competencyType.tdesc)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.masfromEvaluationAssessment1lList[0].competencyType.tdesc}}
</td>
......@@ -70,7 +73,9 @@
</tr>
</thead>
<tbody>
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200" (mouseenter)="tableHover.set(kpiName,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(kpiName)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{kpiName}}
</td>
......
......@@ -18,6 +18,7 @@ export class PmsInformationComponent {
@Input() kpiName: string = ""
@Output() sendCurrentTap: EventEmitter<any> = new EventEmitter<any>();
@Output() sendCurrentPart: EventEmitter<any> = new EventEmitter<any>();
tableHover: Map<string, boolean> = new Map<string, boolean>()
menuClose: Map<string, boolean> = new Map<string, boolean>()
statusButtonClass = (status: string) => {
if (status === "no access") {
......
......@@ -80,7 +80,10 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalPms?.part1Detail;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(item.groupAssessment1.pmsTopic.indicatorsDetail,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.groupAssessment1.pmsTopic.indicatorsDetail)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.groupAssessment1.pmsTopic.indicatorsDetail}}</td>
<td class="py-2 text-center" style="vertical-align: top">{{item.weight}}</td>
......@@ -261,7 +264,10 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalPms?.part2Detail;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(item.groupAssessment1.pmsTopic.indicatorsDetail,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.groupAssessment1.pmsTopic.indicatorsDetail)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.groupAssessment1.pmsTopic.indicatorsDetail}}</td>
<td class="py-2 text-center" style="vertical-align: top">{{item.weight}}</td>
......@@ -442,7 +448,10 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalPms?.part3Detail;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(item.groupAssessment1.pmsTopic.indicatorsDetail,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.groupAssessment1.pmsTopic.indicatorsDetail)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.groupAssessment1.pmsTopic.indicatorsDetail}}</td>
<td class="py-2 text-center" style="vertical-align: top">{{item.weight}}</td>
......@@ -622,7 +631,10 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalPms?.part4Detail;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(item.competencyType.tdesc,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.competencyType.tdesc)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.competencyType.tdesc}}</td>
<td class="py-2 text-center" style="vertical-align: top">{{item.competencyType.weight}}
......@@ -725,7 +737,9 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalPms?.part5Detail;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200" (mouseenter)="tableHover.set(item.tdesc,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.tdesc)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.tdesc}}
</td>
......@@ -884,7 +898,10 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalPms?.part6Detail;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(item.groupAssessment1.pmsTopic.tdesc,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.groupAssessment1.pmsTopic.tdesc)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.groupAssessment1.pmsTopic.tdesc}}</td>
<td class="py-2 text-center" style="vertical-align: top">{{item.weight}}</td>
......@@ -1065,7 +1082,10 @@
</thead>
<tbody>
<ng-container *ngFor="let item of appraisalPms?.part7Detail;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200"
(mouseenter)="tableHover.set(item.groupAssessment1.pmsTopic.tdesc,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.groupAssessment1.pmsTopic.tdesc)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.groupAssessment1.pmsTopic.tdesc}}</td>
<td class="py-2 text-center" style="vertical-align: top">{{item.weight}}</td>
......@@ -1245,7 +1265,9 @@
</thead>
<tbody>
<ng-container *ngFor="let item of data8List;let i = index">
<tr class="border-b border-gray-200">
<tr class="border-b border-gray-200" (mouseenter)="tableHover.set(item.evaluationFactor,true)"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background':tableHover.get(item.evaluationFactor)?'#f1f5f9':'#ffffff'}">
<td class="py-2" style="vertical-align: top">
{{item.evaluationFactor}}
</td>
......
......@@ -97,7 +97,7 @@ export class PmsKpiComponent {
groupGrade: { loading: boolean, dataList: CompetencyGradeModel[] } = { loading: false, dataList: [] }
@ViewChild('scrollContainer') scrollContainer!: ElementRef;
@Output() scrollToMenuId: EventEmitter<any> = new EventEmitter<any>();
tableHover: Map<string, boolean> = new Map<string, boolean>()
constructor(private appraisalService: AppraisalService,
private pmsGroupGradeService: PmsGroupGradeService,
private employeeService: EmployeeService,
......
......@@ -88,7 +88,8 @@ export class SelfEvaluationComponent implements OnInit {
this.allCompetencyTypeId = this.appraisalCompentency.dataList[0].masfromEvaluationAssessment1.map(x => ({
statusType: "",
competencyTypeId: x.competencyType.competencyTypeId,
shortName: x.competencyType.shortName
shortName: x.competencyType.shortName,
averageScore: x.averageScore + ''
}))
this.selectAppraisalCompentency(this.appraisalCompentency.dataList[0])
}
......
......@@ -679,46 +679,20 @@
</div> -->
<div class="header-profile hs-dropdown ti-dropdown" data-hs-dropdown-placement="bottom-right">
<button id="dropdown-profile" type="button"
class="hs-dropdown-toggle ti-dropdown-toggle gap-2 p-0 flex-shrink-0 h-8 w-8 rounded-full shadow-none focus:ring-gray-400 text-xs dark:focus:ring-white/10">
<!-- <img *ngIf="employeeProfile?.picture && employeeProfile.picture !== ''; else defaultImage"
class="inline-block rounded-full ring-2 h-full !ring-transparent"
[src]="employeeProfile.picture"
alt="Image Description"
(error)="onImageError($event)"/>
<ng-template #defaultImage>
<img
class="inline-block rounded-full ring-2 h-full !ring-transparent"
src="./assets/img/users/defaultperson.jpg"
alt="Image Description" />
</ng-template> -->
<img class="inline-block rounded-full ring-2 h-full !ring-transparent" src="./assets/img/users/man.PNG"
alt="Image Description" />
class="hs-dropdown-toggle ti-dropdown-toggle gap-2 p-0 flex-shrink-0 rounded-full shadow-none focus:ring-gray-400 text-xs">
<img class="avatar shadow-none rounded-full !ring-transparent object-cover h-8 w-8"
[src]="employeeProfile.picture?url+'/employee/image/'+employeeProfile.picture:'./assets/img/users/defaultperson.jpg'">
</button>
<div class="hs-dropdown-menu ti-dropdown-menu border-0 w-[20rem]" aria-labelledby="dropdown-profile">
<div class="ti-dropdown-header !bg-primary flex items-center space-x-3">
<div class="flex-shrink-0">
<!-- <img class="avatar shadow-none rounded-full h-full !ring-transparent" src="./assets/img/users/profile2.jpg"
alt="profile-img" /> -->
<!-- <img *ngIf="employeeProfile?.picture && employeeProfile.picture !== ''; else defaultImage"
class="inline-block rounded-full ring-2 h-12 w-12 !ring-transparent"
[src]="employeeProfile.picture"
alt="Image Description"
(error)="onImageError($event)"/>
<ng-template #defaultImage>
<img
class="inline-block rounded-full ring-2 h-12 w-12 !ring-transparent"
src="./assets/img/users/defaultperson.jpg"
alt="Image Description" />
</ng-template> -->
<img class="avatar shadow-none rounded-full !ring-transparent" src="./assets/img/users/man.PNG"
alt="Image Description" />
<img class="avatar shadow-none rounded-full !ring-transparent object-cover"
[src]="employeeProfile.picture?url+'/employee/image/'+employeeProfile.picture:'./assets/img/users/defaultperson.jpg'">
</div>
<div>
<p class="ti-dropdown-header-title !text-white">
{{this.employeeProfile.thFullName?this.employeeProfile.thFullName:''}}
<p class=" ti-dropdown-header-title !text-white">
{{employeeProfile.thFullName?employeeProfile.thFullName:''}}
</p>
<p class="ti-dropdown-header-content !text-white/50 " style="font-size: 12px;">
{{tokenService.getUserData().position?tokenService.getUserData().position.tdesc:'-'}}
......@@ -726,11 +700,7 @@
</div>
</div>
<div class="mt-2 ti-dropdown-divider">
<!-- <a routerLink="/profile/home" class="ti-dropdown-item">
<i class="ti ti-user-circle text-lg"></i>
Profile
</a>
<a routerLink="/mail/mail" class="ti-dropdown-item">
<!-- <a routerLink="/mail/mail" class="ti-dropdown-item">
<i class="ti ti-inbox text-lg"></i>
Inbox
</a>
......@@ -738,10 +708,14 @@
<i class="ti ti-clipboard-check text-lg"></i>
Task Manager
</a> -->
<a routerLink="/ess/my-skill-x-module" class="ti-dropdown-item cursor-pointer">
<a routerLink="/ess/my-skill-x-module" class="ti-dropdown-item cursor-pointer">
<i class="ti ti-home text-lg"></i>
หน้าหลัก
</a>
<a routerLink="/ess/profile" class="ti-dropdown-item">
<i class="ti ti-user-circle text-lg"></i>
ข้อมูลพนักงาน
</a>
<!-- <a *ngIf="!router.url.includes('/self-evaluation')" (click)="onNextPartClick('/self-evaluation')"
class="ti-dropdown-item cursor-pointer">
<i class="ti ti-settings text-lg"></i>
......@@ -769,7 +743,7 @@
</div>
<div class="header-name">
<span class="dark:text-black/30 text-black text-center">
{{this.employeeProfile.thFullName?this.employeeProfile.thFullName:''}} </span>
{{employeeProfile.thFullName?employeeProfile.thFullName:''}} </span>
</div>
</div>
</div>
......@@ -920,4 +894,4 @@
</div>
</div>
</div>
<!-- ========== END Search Modal ========== -->
<!-- ========== END Search Modal ========== -->
\ No newline at end of file
......@@ -6,6 +6,8 @@ import { TokenService } from '../../services/token.service';
import { EmployeeService } from '../../services/employee.service';
import { EmployeeModel, MyEmployeeModel } from '../../model/employee.model';
import { ActivatedRoute, Router } from '@angular/router';
import { environment } from 'src/environments/environment';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-header',
......@@ -15,6 +17,7 @@ import { ActivatedRoute, Router } from '@angular/router';
export class HeaderComponent {
employeeProfile: EmployeeModel = new MyEmployeeModel();
url = environment.baseUrl
constructor(public navServices: NavService,
private authService: AuthService,
public tokenService: TokenService,
......@@ -22,10 +25,13 @@ export class HeaderComponent {
private elementRef: ElementRef,
public router: Router,
private route: ActivatedRoute,
private navService: NavService) {
private navService: NavService, private http: HttpClient) {
this.getEvaluatee();
}
imageUrl = ''
getEvaluatee() {
this.employeeProfile = new MyEmployeeModel(JSON.parse(sessionStorage.getItem('employeeProfile') || '{}'));
if (this.employeeProfile?.employeeId == undefined || this.employeeProfile?.employeeId == null || this.employeeProfile?.employeeId == '') {
......
......@@ -92,7 +92,7 @@ export class SidebarComponent {
this.currentUrl = this.router.url
this.isESSRoute = this.currentUrl.includes('/ess');
this.isAdminRoute = this.currentUrl.includes('/admin');
this.showSideMenu = this.currentUrl.includes('my-skill-x-module') || this.currentUrl.includes('employee-self-service')
this.showSideMenu = this.currentUrl.includes('my-skill-x-module') || this.currentUrl.includes('employee-self-service') || this.currentUrl.includes('ess/profile')
if (this.showSideMenu) {
const html: any = this.elementRef.nativeElement.ownerDocument.documentElement;;
html.style = '';
......@@ -131,7 +131,6 @@ export class SidebarComponent {
switcherArrowFn();
checkHoriMenu();
if (document.documentElement.getAttribute('data-nav-layout') == 'horizontal' && window.innerWidth > 992) {
console.log('Horizontal menu detected');
this.closeNavActive()
}
......@@ -162,7 +161,7 @@ export class SidebarComponent {
// Update the boolean values
this.isESSRoute = this.currentUrl.includes('/ess');
this.isAdminRoute = this.currentUrl.includes('/admin');
this.showSideMenu = this.currentUrl.includes('my-skill-x-module') || this.currentUrl.includes('employee-self-service')
this.showSideMenu = this.currentUrl.includes('my-skill-x-module') || this.currentUrl.includes('employee-self-service') || this.currentUrl.includes('ess/profile')
if (this.showSideMenu) {
const html: any = this.elementRef.nativeElement.ownerDocument.documentElement;;
html.style = '';
......
......@@ -13,7 +13,7 @@ export interface Masfromevaluationassessment {
masfromStatusType: MasfromStatusType
apsapproveType: ApsapproveType
apsassessy: Apsassessy
gread: string
grade: string
sumScore: number
typeList: TypeList[]
statusIdp: {
......@@ -62,6 +62,8 @@ export interface Apsassessy {
endWorkDate: string
thFullName: string
engFullName: string
picture: string
pictureBytes: string
}
export interface Prefix {
......@@ -150,4 +152,5 @@ export interface TypeList {
statusType: string
competencyTypeId: string
shortName: string
averageScore: string
}
\ No newline at end of file
......@@ -44,4 +44,11 @@ export class AppraisalService {
postPms(body: AppraisalPmsFormModel): Observable<AlertModel> {
return this.http.post<AlertModel>(this.urlApi + "/pms", body)
}
postBossApproveAll(body: {
masFromEvaluationRoundId: string,
employeeId: string[]
}): Observable<AlertModel> {
return this.http.post<AlertModel>(this.urlApi + "/approveAll", body)
}
}
\ No newline at end of file
......@@ -57,4 +57,7 @@ export class EmployeeService {
};
return this.http.delete<AlertModel>(this.baseUrlapi + "/profile-delete", options)
}
getProfileMini(): Observable<EmployeeModel> {
return this.http.get<EmployeeModel>(this.baseUrlapi + "/profile/mini")
}
}
......@@ -4285,6 +4285,9 @@ select option:focus {
.w-1\/2 {
width: 50%;
}
.w-1\/3 {
width: 33.33%;
}
.w-1\/4 {
width: 25%;
}
......
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