Commit 99954971 by Ooh-Ao

รายงาน

parent d83a0036
<app-page-header
[title]="'รายงานสรุปจำนวนพนักงานที่ติด GAP Competency'"
activeitem="รายงาน">
</app-page-header>
<section class="gap-wrap">
<header class="txt-center mb-8">
<h1 class="big-title">
รายงานสรุปจำนวนพนักงานที่ติด <span>GAP Competency</span>
</h1>
<h2 class="sub-title">แยกตามหน่วยงาน ฝ่ายการพยาบาล</h2>
<h3 class="date-title">ข้อมูล ณ วันที่ {{ dateInfo }}</h3>
</header>
<!-- ตารางหลัก -->
<div class="table-scroll">
<table class="gap-table">
<thead>
<tr class="head-row">
<th class="sticky-col">หน่วยงาน</th>
<th>พยาบาล</th>
<th>ผู้ช่วย<br />พยาบาล</th>
<th>เจ้าหน้าที่<br />พยาบาล</th>
<th>เจ้าหน้าที่<br />ธุรการ</th>
<th>ลูกจ้างประจำ</th>
<th>รวม</th>
<th class="reason-col">หมายเหตุ</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let r of rows" class="body-row">
<td class="sticky-col">{{ r.unit }}</td>
<td>{{ r.nurse }}</td>
<td>{{ r.asnNurse }}</td>
<td>{{ r.assistantNurse }}</td>
<td>{{ r.registrar }}</td>
<td>{{ r.clerk }}</td>
<td>{{ r.total }}</td>
<td class="reason-col">{{ r.reason || '' }}</td>
</tr>
<tr class="foot-row">
<td class="sticky-col">{{ grand.unit }}</td>
<td>{{ grand.nurse }}</td>
<td>{{ grand.asnNurse }}</td>
<td>{{ grand.assistantNurse }}</td>
<td>{{ grand.registrar }}</td>
<td>{{ grand.clerk }}</td>
<td>{{ grand.total }}</td>
<td class="reason-col"></td>
</tr>
</tbody>
</table>
</div>
</section>
/* ─── variables ─── */
$blue-50 : #eff6ff; $blue-600:#2563eb; $slate-600:#475569; $gray-50:#f8fafc;
$radius : .75rem; $shadow:0 14px 30px -18px rgba(0,0,0,.18);
/* ─── Layout ─── */
.gap-wrap{max-width:1200px;margin:auto;padding:2.2rem 1rem}
.txt-center{text-align:center}
/* ─── Headings ─── */
.big-title{font:700 1.9rem/1.3 'Inter',sans-serif;color:$slate-600;
span{color:$blue-600}}
.sub-title{font:600 1.35rem/1.25 'Inter',sans-serif;margin-top:.3rem;color:$blue-600}
.date-title{font:600 1rem/1.2 'Inter',sans-serif;margin-top:.4rem;color:$slate-600}
/* ─── Table ─── */
.table-scroll{overflow-x:auto;border-radius:$radius;box-shadow:$shadow}
.gap-table{width:100%;border-collapse:collapse;font-size:.9rem;text-align:center}
thead{background:$blue-600;color:#fff}
.head-row th{padding:.65rem .4rem;font-weight:600;white-space:nowrap}
tbody td{padding:.55rem .4rem}
.body-row:nth-child(odd){background:#fff}
.body-row:nth-child(even){background:$blue-50}
.body-row:hover{background:#dbeafe}
.foot-row{background:#d1d5db;font-weight:700}
.sticky-col{position:sticky;left:0;background:inherit;padding-left:.85rem;text-align:left}
/* reason col hide on <640px */
.reason-col{ @media(max-width:639px){display:none} }
import { Component } from '@angular/core';
interface Row {
unit: string;
nurse: number;
asnNurse: number;
assistantNurse: number;
registrar: number;
clerk: number;
total: number;
reason?: string;
}
@Component({
selector: 'app-report-com-3',
templateUrl: './report-com-3.component.html',
styleUrls: ['./report-com-3.component.scss']
})
export class ReportCom3Component {
dateInfo = '1 มิ.ย. 2568';
rows: Row[] = [
{ unit: 'หอรองรับกรณีฉุกเฉิน', nurse: 5, asnNurse: 1, assistantNurse: 1, registrar: 0, clerk: 0, total: 3 },
{ unit: 'หอผู้ป่วยเด็กเล็ก ชั้น1', nurse: 2, asnNurse: 1, assistantNurse: 1, registrar: 0, clerk: 0, total: 7 },
{ unit: 'หอผู้ป่วยเด็กโต ชั้น2', nurse: 8, asnNurse: 1, assistantNurse: 0, registrar: 0, clerk: 0, total: 9 },
{ unit: 'หอผู้ป่วยเด็กโต ชั้น3', nurse: 4, asnNurse: 0, assistantNurse: 1, registrar: 1, clerk: 0, total: 6 },
{ unit: 'ศูนย์เฝ้าระวัง', nurse: 0, asnNurse: 0, assistantNurse: 0, registrar: 0, clerk: 12, total: 12 },
{ unit: 'หน่วยจ่ายกลาง', nurse: 0, asnNurse: 0, assistantNurse: 4, registrar: 0, clerk: 2, total: 6 },
{ unit: 'ห้องคลอด', nurse: 9, asnNurse: 3, assistantNurse: 1, registrar: 0, clerk: 0, total: 13 },
{ unit: 'หน่วยอุบัติเหตุฉุกเฉิน', nurse: 10, asnNurse: 4, assistantNurse: 0, registrar: 1, clerk: 0, total: 15 },
{ unit: 'หอผู้ป่วยวิกฤติ', nurse: 3, asnNurse: 2, assistantNurse: 0, registrar: 1, clerk: 0, total: 6 },
{ unit: 'สำนักงานฝ่ายพยาบาล', nurse: 2, asnNurse: 0, assistantNurse: 0, registrar: 3, clerk: 0, total: 5 },
{ unit: 'หอผู้ป่วยเด็กเล็ก ชั้น1', nurse: 4, asnNurse: 0, assistantNurse: 0, registrar: 0, clerk: 0, total: 4 },
{ unit: 'หอผู้ป่วยเด็กโต ชั้น2', nurse: 5, asnNurse: 1, assistantNurse: 0, registrar: 0, clerk: 0, total: 6 },
{ unit: 'ห้องผ่าตัด', nurse: 5, asnNurse: 1, assistantNurse: 0, registrar: 0, clerk: 2, total: 8 }
];
get grand(): Row {
const g = { unit: 'รวม', nurse: 0, asnNurse: 0, assistantNurse: 0, registrar: 0, clerk: 0, total: 0 };
this.rows.forEach(r => {
g.nurse += r.nurse; g.asnNurse += r.asnNurse; g.assistantNurse += r.assistantNurse;
g.registrar += r.registrar; g.clerk += r.clerk; g.total += r.total;
});
return g;
}
}
<h2 class="page-title">
ภาพรวมผลประเมินการปฏิบัติงานขององค์กร ประจำปี 2568
</h2>
<div class="card-grid">
<!-- ── Chart Card ── -->
<div class="chart-card glass">
<div echarts [options]="chartOpt" class="chart"></div>
</div>
<!-- ── Table Card ── -->
<div class="table-card glass">
<table class="grade-table">
<thead>
<tr>
<th rowspan="2" class="sticky-col">ระดับ<br />U</th>
<th colspan="2">A</th><th colspan="2">B</th>
<th colspan="2">C</th><th colspan="2">D</th>
<th colspan="2">E</th>
<th colspan="2">รวม</th>
</tr>
<tr>
<ng-container *ngFor="let _ of [1,2,3,4,5,6]">
<th>คน</th><th>%</th>
</ng-container>
</tr>
</thead>
<tbody>
<tr *ngFor="let r of rows">
<td class="sticky-col">{{ r.level }}</td>
<td>{{ r.A }}</td><td></td>
<td>{{ r.B }}</td><td></td>
<td>{{ r.C }}</td><td></td>
<td>{{ r.D }}</td><td></td>
<td>{{ r.E }}</td><td></td>
<td>{{ r.sum }}</td><td>100</td>
</tr>
<tr class="grand">
<td class="sticky-col">{{ grand.level }}</td>
<td>{{ grand.A }}</td><td></td>
<td>{{ grand.B }}</td><td></td>
<td>{{ grand.C }}</td><td></td>
<td>{{ grand.D }}</td><td></td>
<td>{{ grand.E }}</td><td></td>
<td>{{ grand.sum }}</td><td>100</td>
</tr>
</tbody>
</table>
</div>
</div>
/* ---------- palette & misc ---------- */
$blue-50 : #eff6ff;
$blue-600: #2563eb;
$radius : 1rem;
$shadow : 0 14px 30px -18px rgba(0,0,0,.18);
$shadow-h: 0 20px 44px -20px rgba(0,0,0,.26);
/* ---------- headline ---------- */
.page-title{
text-align:center;
font:700 1.9rem/1.3 'Inter',sans-serif;
color:$blue-600; margin-bottom:1.6rem;
}
/* ---------- 2-col grid ---------- */
.card-grid{
display:grid; gap:1.25rem;
@media(min-width:768px){ grid-template-columns:360px 1fr }
}
/* ---------- glass card wrapper ---------- */
.glass{
position:relative; background:rgba(255,255,255,.6);
backdrop-filter:blur(10px) saturate(165%);
border-radius:$radius; box-shadow:$shadow; transition:.4s;
&:hover{
transform:translateY(-6px);
box-shadow:$shadow-h; background:#fff;
}
&::before{
content:''; position:absolute; inset:0; pointer-events:none;
border-radius:inherit; padding:1px;
background:linear-gradient(140deg,#3b82f6,#818cf8 50%,#a855f7);
mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
mask-composite:exclude; opacity:.45; transition:.35s;
}
&:hover::before{ opacity:.9; }
}
/* ---------- chart ---------- */
.chart-card{padding:1.5rem}
.chart{height:300px;width:100%}
/* ---------- table ---------- */
.table-card{padding:1rem 1.2rem;overflow:auto}
.grade-table{border-collapse:collapse;width:100%;font-size:.75rem;text-align:center}
th,td{padding:.35rem .4rem}
thead{background:$blue-600;color:#fff;font-weight:600}
tbody tr:nth-child(even){background:$blue-50}
.grand{background:#d1d5db;font-weight:700}
.sticky-col{position:sticky;left:0;background:inherit;font-weight:600;text-align:left;padding-left:.6rem}
/* scroll bar subtle */
.table-card::-webkit-scrollbar{height:.5rem}
.table-card::-webkit-scrollbar-thumb{background:#c4c4c4;border-radius:9999px}
import { Component } from '@angular/core';
import { EChartsOption } from 'echarts';
@Component({
selector: 'app-report-pms-1',
templateUrl: './report-pms-1.component.html',
styleUrls: ['./report-pms-1.component.scss']
})
export class ReportPms1Component {
// ── Mock chart data ──
chartOpt: EChartsOption = {
grid: { top: 20, left: 45, right: 10, bottom: 30 },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
data: ['A', 'B', 'C', 'D', 'E'],
axisLabel: { fontFamily: 'Inter', fontWeight: 600 }
},
yAxis: { type: 'value', splitLine: { show: false } },
series: [
{
name: 'จำนวนพนักงาน',
type: 'bar',
data: [1, 7, 5, 0, 0],
itemStyle: { color: '#1d4ed8', borderRadius: [4, 4, 0, 0] },
barWidth: '40%'
},
{
name: 'เทรนด์',
type: 'line',
data: [1, 7, 5, 0, 0],
smooth: true,
lineStyle: { width: 3, color: '#0ea5e9' },
symbolSize: 8,
itemStyle: { color: '#0ea5e9' }
}
]
};
// ── Mock table rows ──
rows = [
{ level: 'E4', A: 0, B: 0, C: 0, D: 0, E: 0, sum: 0 },
{ level: 'E3', A: 0, B: 0, C: 0, D: 0, E: 0, sum: 0 },
{ level: 'S3', A: 1, B: 25, C: 3, D: 75, E: 0, sum: 4 },
{ level: 'S2', A: 1, B: 25, C: 3, D: 75, E: 0, sum: 4 },
{ level: 'S1', A: 1, B: 0, C: 1, D: 50, E: 0, sum: 2 },
// ...
];
/** คำนวณ footer รวมอัตโนมัติ */
get grand() {
const g = { level: 'Total', A: 0, B: 0, C: 0, D: 0, E: 0, sum: 0 };
this.rows.forEach(r => {
g.A += r.A; g.B += r.B; g.C += r.C; g.D += r.D; g.E += r.E; g.sum += r.sum;
});
return g;
}
}
<h2 class="page-title">
ภาพรวมผลประเมินการปฏิบัติงานของหน่วยงาน ประจำปี 2568
</h2>
<div class="grid-wrap">
<!-- ── Chart ── -->
<div class="glass card-chart">
<div echarts [options]="chartOpt" class="chart"></div>
</div>
<!-- ── Table ── -->
<div class="glass card-table">
<table class="grade-table">
<thead>
<tr>
<th rowspan="2" class="stick">ระดับ<br />U</th>
<th colspan="2">A</th><th colspan="2">B</th>
<th colspan="2">C</th><th colspan="2">D</th>
<th colspan="2">E</th><th colspan="2">รวม</th>
</tr>
<tr>
<ng-container *ngFor="let _ of [1,2,3,4,5,6]">
<th>คน</th><th>%</th>
</ng-container>
</tr>
</thead>
<tbody>
<tr *ngFor="let r of rows">
<td class="stick">{{ r.level }}</td>
<td>{{ r.A }}</td><td></td>
<td>{{ r.B }}</td><td></td>
<td>{{ r.C }}</td><td></td>
<td>{{ r.D }}</td><td></td>
<td>{{ r.E }}</td><td></td>
<td>{{ r.sum }}</td><td>100</td>
</tr>
<tr class="foot">
<td class="stick">{{ grand.level }}</td>
<td>{{ grand.A }}</td><td></td>
<td>{{ grand.B }}</td><td></td>
<td>{{ grand.C }}</td><td></td>
<td>{{ grand.D }}</td><td></td>
<td>{{ grand.E }}</td><td></td>
<td>{{ grand.sum }}</td><td>100</td>
</tr>
</tbody>
</table>
</div>
</div>
/* palette */
$blue-50:#eff6ff;$blue-600:#2563eb;$slate-600:#475569;
$radius:.9rem;$shadow:0 14px 30px -18px rgba(0,0,0,.18);
$shadow-h:0 20px 46px -22px rgba(0,0,0,.28);
/* title */
.page-title{
text-align:center;
font:700 2rem/1.25 'Inter',sans-serif;
color:$blue-600;margin-bottom:1.8rem;
}
/* grid wrapper */
.grid-wrap{
display:grid;gap:1.4rem;
@media(min-width:768px){grid-template-columns:370px 1fr}
}
/* glass card */
.glass{
position:relative;background:rgba(255,255,255,.6);
backdrop-filter:blur(10px)saturate(170%);
border-radius:$radius;box-shadow:$shadow;transition:.4s;
&:hover{transform:translateY(-6px);box-shadow:$shadow-h;background:#fff}
&::before{
content:'';position:absolute;inset:0;border-radius:inherit;padding:1px;
background:linear-gradient(135deg,#3b82f6,#818cf8 50%,#a855f7);
mask:linear-gradient(#fff 0 0)content-box,linear-gradient(#fff 0 0);
mask-composite:exclude;opacity:.45;pointer-events:none;transition:.35s;
}
&:hover::before{opacity:.9}
}
/* chart */
.card-chart{padding:1.5rem}
.chart{height:320px;width:100%}
/* table */
.card-table{padding:1rem 1.25rem;overflow:auto}
.grade-table{width:100%;border-collapse:collapse;font-size:.8rem;text-align:center}
th,td{padding:.35rem .4rem}
thead{background:$blue-600;color:#fff;font-weight:600}
tbody tr:nth-child(even){background:$blue-50}
tbody tr:hover{background:#dbeafe}
.foot{background:#e5e7eb;font-weight:700}
.stick{position:sticky;left:0;background:inherit;text-align:left;padding-left:.6rem}
/* scroll subtle */
.card-table::-webkit-scrollbar{height:.55rem}
.card-table::-webkit-scrollbar-thumb{background:#c4c4c4;border-radius:9999px}
import { Component } from '@angular/core';
import { EChartsOption } from 'echarts';
interface Row {
level: string;
A: number; B: number; C: number; D: number; E: number;
sum: number;
}
@Component({
selector: 'app-report-pms-2',
templateUrl: './report-pms-2.component.html',
styleUrls: ['./report-pms-2.component.scss']
})
export class ReportPms2Component {
/* ===== Chart ===== */
chartOpt: EChartsOption = {
grid: { top: 18, left: 50, right: 8, bottom: 26 },
tooltip: { trigger: 'axis' },
xAxis: {
type: 'category',
data: ['A', 'B', 'C', 'D', 'E'],
axisLabel: { fontFamily: 'Inter', fontWeight: 600 }
},
yAxis: { type: 'value', splitLine: { show: false } },
series: [
{
name: 'จำนวนพนักงาน',
type: 'bar',
data: [1, 7, 5, 0, 0],
itemStyle: { color: '#1d4ed8', borderRadius: [4, 4, 0, 0] },
barWidth: '45%'
},
{
name: 'เทรนด์',
type: 'line',
data: [1, 7, 5, 0, 0],
smooth: true,
lineStyle: { width: 3, color: '#3b82f6' },
symbolSize: 8,
itemStyle: { color: '#3b82f6' }
}
]
};
/* ===== Table data (ตัวอย่าง) ===== */
rows: Row[] = [
{ level: 'S3', A: 1, B: 25, C: 3, D: 75, E: 0, sum: 4 },
{ level: 'S2', A: 1, B: 25, C: 3, D: 75, E: 0, sum: 4 },
{ level: 'S1', A: 1, B: 0, C: 1, D: 50, E: 0, sum: 2 },
{ level: 'E4', A: 0, B: 0, C: 0, D: 0, E: 0, sum: 0 },
// … (ข้อมูลจริงต่อได้)
];
get grand(): Row {
const g: Row = { level: 'Total', A: 0, B: 0, C: 0, D: 0, E: 0, sum: 0 };
this.rows.forEach(r => {
g.A += r.A; g.B += r.B; g.C += r.C; g.D += r.D; g.E += r.E; g.sum += r.sum;
});
return g;
}
}
<app-page-header [title]="title" activeitem="รายงาน"></app-page-header>
<section class="pp-wrap">
<table class="pp-table">
<thead>
<tr>
<th>รหัส</th>
<th>ชื่อ-นามสกุล</th>
<th>หน่วยงาน</th>
<th>ตำแหน่ง</th>
<th>ระดับ</th>
<th>เกรด</th>
<th>คะแนน</th>
<th>Corp.<br />KPI</th>
<th>Dep.<br />KPI</th>
<th>Ind.<br />KPI</th>
<th>Competency</th>
<th>Time<br />Attendance</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let r of rows">
<td>{{ r.code }}</td>
<td>{{ r.name }}</td>
<td>{{ r.unit }}</td>
<td>{{ r.position }}</td>
<td>{{ r.level }}</td>
<td>{{ r.grade }}</td>
<td>{{ r.score }}</td>
<td>{{ r.corp }}</td>
<td>{{ r.dep }}</td>
<td>{{ r.ind }}</td>
<td>{{ r.comp }}</td>
<td>{{ r.time }}</td>
</tr>
</tbody>
</table>
</section>
/* palette & radius */
$blue-50 : #eff6ff;
$blue-600: #2563eb;
$slate-600:#475569;
$radius : .75rem;
$shadow : 0 14px 30px -18px rgba(0,0,0,.18);
$shadow-h: 0 20px 46px -22px rgba(0,0,0,.24);
/* wrapper */
.pp-wrap{
max-width: 1250px;
margin-inline: auto;
padding: 2rem 1rem;
background: rgba(255,255,255,.6);
backdrop-filter: blur(10px) saturate(165%);
border-radius: $radius;
box-shadow: $shadow;
transition: .35s;
&:hover{ transform: translateY(-4px); box-shadow: $shadow-h; background:#fff }
}
/* table */
.pp-table{
width:100%; border-collapse: collapse; font-size:.82rem;
min-width:950px; /* ให้เลื่อนแนวนอนได้บนจอแคบ */
thead{
background:$blue-600;
color:#fff;
th{ padding:.55rem .6rem; font-weight:600; text-align:center; white-space:nowrap }
}
tbody td{ padding:.45rem .6rem; white-space:nowrap }
tbody tr:nth-child(even){ background:$blue-50 }
tbody tr:hover{ background:#dbeafe }
}
/* scroll subtle */
.pp-wrap{ overflow-x:auto }
.pp-wrap::-webkit-scrollbar{ height:.5rem }
.pp-wrap::-webkit-scrollbar-thumb{ background:#c4c4c4; border-radius:9999px }
import { Component } from '@angular/core';
interface Row {
code: string;
name: string;
unit: string;
position: string;
level: number;
grade: string;
score: number;
corp: number;
dep: number;
ind: number;
comp: number;
time: number;
}
@Component({
selector: 'app-report-pms-3',
......@@ -6,4 +20,19 @@ import { Component } from '@angular/core';
styleUrls: ['./report-pms-3.component.scss']
})
export class ReportPms3Component {
title = 'รายงานประเมินการปฏิบัติงานของพนักงานรายบุคคล ประจำปี 2568';
rows: Row[] = [
{ code:'10001', name:'กิรณา ทดสอบ', unit:'Marketing & Procurement', position:'Customer Key Account', level:7, grade:'B', score:83.53, corp:14.10, dep:18.80, ind:10.00, comp:22.00, time:4.73 },
{ code:'10002', name:'บรรณ ทดสอบ', unit:'Marketing & Procurement', position:'Senior Marketing Strategist', level:5, grade:'A', score:91.92, corp:10.60, dep:20.00, ind:10.00, comp:35.00, time:9.82 },
{ code:'10003', name:'ผล ทดสอบ', unit:'Marketing & Procurement', position:'Procurement Specialist', level:3, grade:'C', score:72.30, corp:14.10, dep:9.30, ind:12.30, comp:18.00, time:5.00 },
{ code:'10004', name:'ณัย ทดสอบ', unit:'Marketing & Procurement', position:'Marketing Analyst', level:6, grade:'C', score:72.70, corp:14.10, dep:11.20, ind:10.40, comp:18.00, time:5.00 },
{ code:'10005', name:'สคริช ทดสอบ', unit:'Marketing & Procurement', position:'Procurement Manager', level:2, grade:'C', score:71.98, corp:14.10, dep:17.10, ind:10.50, comp:18.00, time:4.45 },
{ code:'10006', name:'ฟ้า ทดสอบ', unit:'Marketing & Procurement', position:'Marketing Coordinator', level:3, grade:'B', score:83.50, corp:14.10, dep:9.80, ind:16.60, comp:24.00, time:5.00 },
{ code:'10007', name:'นารวิทย์ ทดสอบ', unit:'Marketing & Procurement', position:'Supply Chain Analyst', level:7, grade:'B', score:88.00, corp:10.60, dep:12.80, ind:13.60, comp:32.67, time:9.64 },
{ code:'10008', name:'อาทิตย์ ทดสอบ', unit:'Marketing & Procurement', position:'Brand Manager', level:2, grade:'B', score:89.10, corp:10.60, dep:14.80, ind:15.20, comp:32.67, time:10.00 },
{ code:'10009', name:'ไพโรจน์ ทดสอบ', unit:'Marketing & Procurement', position:'Category Manager', level:2, grade:'B', score:84.76, corp:10.60, dep:18.80, ind:11.20, comp:28.00, time:10.00 },
{ code:'10010', name:'เมฆา ทดสอบ', unit:'Marketing & Procurement', position:'Market Researcher', level:4, grade:'B', score:85.53, corp:10.60, dep:11.80, ind:17.00, comp:30.33, time:10.00 },
{ code:'10011', name:'เคม ทดสอบ', unit:'Marketing & Procurement', position:'Sourcing Specialist', level:5, grade:'C', score:71.03, corp:10.60, dep:10.90, ind:15.50, comp:18.67, time:9.82 }
];
}
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