Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mySkill-x
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
angular
mySkill-x
Commits
17cb7f81
Commit
17cb7f81
authored
Jun 01, 2025
by
Ooh-Ao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard
parent
abb883fb
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
182 additions
and
59 deletions
+182
-59
dashboard-evaluation.component.html
...ts/dashboard/projects/dashboard-evaluation.component.html
+28
-50
dashboard-evaluation.component.scss
...ts/dashboard/projects/dashboard-evaluation.component.scss
+126
-0
dashboard-evaluation.component.ts
...ents/dashboard/projects/dashboard-evaluation.component.ts
+28
-9
No files found.
src/app/components/dashboard/projects/dashboard-evaluation.component.html
View file @
17cb7f81
<app-page-header
[
title
]="'
Dashboard
Appraisal
'"
activeitem=
"Home"
>
<app-page-header
[
title
]="'
Dashboard
Appraisal
'"
activeitem=
"Home"
>
</app-page-header>
<div
class=
"
container mx-auto px-4 py-8 space-y-8
"
>
<div
class=
"
dashboard
"
>
<!-- ░░ Row #1 – KPI Cards ░░ -->
<div
class=
"grid gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5"
>
<ng-container
*
ngFor=
"let card of kpiCards; trackBy: trackByLabel"
>
<div
class=
"bg-white rounded-2xl shadow transition
motion-safe:hover:-translate-y-1 hover:shadow-xl p-6
flex items-center gap-4"
>
<!-- icon -->
<div
class=
"w-14 h-14 flex items-center justify-center rounded-full"
[
ngClass
]="
card
.
color
"
>
<i
class=
"text-sky-700 text-xl"
[
ngClass
]="
card
.
icon
"
></i>
<!-- ░ Row 1 – KPI ░ -->
<div
class=
"kpi-grid"
>
<ng-container
*
ngFor=
"let card of kpiCards"
>
<div
class=
"kpi-card"
>
<div
class=
"kpi-icon"
[
ngStyle
]="{'
background
'
:
card
.
bg
}"
>
<i
[
ngClass
]="
card
.
icon
"
></i>
</div>
<!-- value -->
<div
class=
"flex-1 text-right"
>
<p
class=
"text-sm text-gray-500 whitespace-nowrap"
>
{{ card.label }}
</p>
<p
class=
"text-2xl font-bold text-gray-800"
>
{{ card.value | number }}
</p>
<span
class=
"text-xs font-semibold"
[
ngClass
]="
card
.
change
>
= 0 ? 'text-green-600' : 'text-red-600'">
<div
class=
"kpi-text"
>
<p
class=
"kpi-label"
>
{{ card.label }}
</p>
<p
class=
"kpi-number"
>
{{ card.value | number }}
</p>
<span
class=
"kpi-rate"
[
ngClass
]="
card
.
change
>
= 0 ? 'text-up' : 'text-down'">
{{ card.change | number:'1.0-2' }}%
</span>
</div>
...
...
@@ -29,21 +21,15 @@
</ng-container>
</div>
<!-- ░░ Row #2 – Bar per Department ░░ -->
<div
class=
"bg-white rounded-2xl shadow transition
motion-safe:hover:-translate-y-1 hover:shadow-xl p-6"
>
<h2
class=
"font-semibold text-slate-600 mb-4"
>
{{ 'dashboard.deptChart' }}
</h2>
<div
echarts
class=
"h-[350px] w-full"
[
options
]="
deptScoreOption
"
[
autoResize
]="
true
"
></div>
<!-- ░ Row 2 – Bar Chart ░ -->
<div
class=
"glass-card"
>
<h2
class=
"section-head"
>
การประเมินตามแผนก
</h2>
<div
echarts
class=
"chart-xl"
[
options
]="
deptScoreOption
"
></div>
</div>
<!-- ░░ Row #3 – Mini-Charts (3 cols on md+) ░░ -->
<div
class=
"grid gap-6 md:grid-cols-3"
>
<!-- Donut -->
<div
class=
"bg-white rounded-2xl shadow transition
<!-- ░ Row 3 – Mini Charts ░ -->
<div
class=
"mini-grid"
>
<div
class=
"glass-card bg-white rounded-2xl shadow transition
motion-safe:hover:-translate-y-1 hover:shadow-xl p-6 flex flex-col items-center"
>
<div
echarts
class=
"h-[220px] w-full"
[
options
]="
summaryDonutOption
"
[
autoResize
]="
true
"
></div>
<p
class=
"mt-3 text-sm text-gray-500"
>
...
...
@@ -51,8 +37,7 @@
</p>
</div>
<!-- Year compare -->
<div
class=
"bg-white rounded-2xl shadow transition
<div
class=
" glass-card bg-white rounded-2xl shadow transition
motion-safe:hover:-translate-y-1 hover:shadow-xl p-6"
>
<h3
class=
"text-sm font-medium text-gray-600 mb-2"
>
{{ 'dashboard.yearCompare' }}
...
...
@@ -60,8 +45,7 @@
<div
echarts
class=
"h-[220px] w-full"
[
options
]="
yearlyCompareOption
"
[
autoResize
]="
true
"
></div>
</div>
<!-- Level distribution -->
<div
class=
"bg-white rounded-2xl shadow transition
<div
class=
"glass-card bg-white rounded-2xl shadow transition
motion-safe:hover:-translate-y-1 hover:shadow-xl p-6"
>
<h3
class=
"text-sm font-medium text-gray-600 mb-2"
>
{{ 'dashboard.levelDist' }}
...
...
@@ -70,11 +54,9 @@
</div>
</div>
<!-- ░░ Row #4 – Tables (stack → 2-cols on lg) ░░ -->
<div
class=
"grid gap-6 lg:grid-cols-2"
>
<!-- pending table -->
<div
class=
"bg-white rounded-2xl shadow overflow-hidden transition
<!-- ░ Row 4 – Tables ░ -->
<div
class=
"tbl-grid"
>
<div
class=
"glass-card bg-white rounded-2xl shadow overflow-hidden transition
motion-safe:hover:-translate-y-1 hover:shadow-xl"
>
<h2
class=
"px-6 py-3 bg-slate-50 border-b font-semibold text-slate-600"
>
{{ 'dashboard.todoList' }}
...
...
@@ -90,8 +72,7 @@
</tr>
</thead>
<tbody>
<tr
*
ngFor=
"let row of pendingList"
class=
"odd:bg-white even:bg-slate-50 hover:bg-sky-50"
>
<tr
*
ngFor=
"let row of pendingList"
class=
"odd:bg-white even:bg-slate-50 hover:bg-sky-50"
>
<td
class=
"px-6 py-3"
>
{{ row.employee }}
</td>
<td
class=
"px-6 py-3"
>
{{ row.evaluator }}
</td>
<td
class=
"px-6 py-3"
>
{{ row.round }}
</td>
...
...
@@ -103,8 +84,7 @@
</div>
<!-- top-score table -->
<div
class=
"bg-white rounded-2xl shadow overflow-hidden transition
<div
class=
"glass-card bg-white rounded-2xl shadow overflow-hidden transition
motion-safe:hover:-translate-y-1 hover:shadow-xl"
>
<h2
class=
"px-6 py-3 bg-slate-50 border-b font-semibold text-slate-600"
>
{{ 'dashboard.topScore' }}
...
...
@@ -121,13 +101,11 @@
</tr>
</thead>
<tbody>
<tr
*
ngFor=
"let row of topScoreList"
class=
"odd:bg-white even:bg-slate-50 hover:bg-sky-50"
>
<tr
*
ngFor=
"let row of topScoreList"
class=
"odd:bg-white even:bg-slate-50 hover:bg-sky-50"
>
<td
class=
"px-6 py-3"
>
{{ row.employee }}
</td>
<td
class=
"px-6 py-3 font-semibold text-slate-700"
>
{{ row.score }}
</td>
<td
class=
"px-6 py-3"
>
<span
class=
"px-2 py-0.5 rounded text-white"
[
ngClass
]="{
<span
class=
"px-2 py-0.5 rounded text-white"
[
ngClass
]="{
'
bg-emerald-600
'
:
row
.
grade =
==
'
S
',
'
bg-sky-600
'
:
row
.
grade =
==
'
A
',
'
bg-amber-600
'
:
row
.
grade =
==
'
B
'
...
...
src/app/components/dashboard/projects/dashboard-evaluation.component.scss
View file @
17cb7f81
/* ───── Tailwind-like tokens ───── */
$gray-50
:
#f8fafc
;
$gray-100
:
#f1f5f9
;
$gray-500
:
#64748b
;
$gray-600
:
#475569
;
$gray-700
:
#334155
;
$blue-50
:
#eff6ff
;
$blue-100
:
#dbeafe
;
$blue-600
:
#2563eb
;
$radius-sm
:
.5rem
;
//≈ rounded-lg
$radius-lg
:
1rem
;
//≈ rounded-2xl
$shadow
:
0
12px
28px
-14px
rgba
(
0
,
0
,
0
,.
18
);
$shadow-h
:
0
18px
42px
-16px
rgba
(
0
,
0
,
0
,.
24
);
$dur
:
.35s
;
$ease
:
cubic-bezier
(
.4
,
0
,.
2
,
1
);
/* ───── Wrapper ───── */
.dashboard
{
max-width
:
1500px
;
margin-inline
:
auto
;
padding
:
2rem
1rem
;
display
:
flex
;
flex-direction
:
column
;
gap
:
2rem
;
}
/* ───── KPI grid ───── */
.kpi-grid
{
display
:
grid
;
gap
:
1rem
;
@media
(
min-width
:
640px
){
grid-template-columns
:
repeat
(
2
,
1fr
);
}
@media
(
min-width
:
768px
){
grid-template-columns
:
repeat
(
3
,
1fr
);
}
@media
(
min-width
:
1024px
){
grid-template-columns
:
repeat
(
5
,
1fr
);
}
}
/* KPI card */
.kpi-card
{
display
:flex
;
gap
:
1rem
;
align-items
:center
;
padding
:
1
.5rem
;
background
:
#fff
;
border-radius
:
$radius-lg
;
box-shadow
:
$shadow
;
transition
:transform
$
dur
$
ease
,
box-shadow
$
dur
$
ease
;
&
:hover
{
transform
:translateY
(
-4px
)
;
box-shadow
:
$shadow-h
;
}
}
.kpi-icon
{
width
:
3
.5rem
;
height
:
3
.5rem
;
display
:flex
;
align-items
:center
;
justify-content
:center
;
border-radius
:
9999px
;
color
:
#fff
;
}
.kpi-text
{
text-align
:right
;
flex
:
1
;
}
.kpi-label
{
font-size
:
.8rem
;
color
:
$gray-500
;
white-space
:nowrap
;
}
.kpi-number
{
font
:
700
1
.5rem
/
1
'Inter'
,
sans-serif
;
color
:
$gray-700
;
}
.kpi-rate
{
font-size
:
.65rem
;
font-weight
:
600
;
}
.text-up
{
color
:
#059669
;
}
/* emerald-600 */
.text-down
{
color
:
#b91c1c
;
}
/* red-700 */
/* ───── universal glass card ───── */
.glass-card
{
position
:relative
;
padding
:
2rem
;
border-radius
:
$radius-lg
;
background
:rgba
(
255
,
255
,
255
,
.55
)
;
backdrop-filter
:blur
(
9px
)
saturate
(
160
%
)
;
box-shadow
:
$shadow
;
transition
:transform
$
dur
$
ease
,
box-shadow
$
dur
$
ease
,
background
$
dur
;
/* glow border */
&
:
:
before
{
content
:
''
;
position
:absolute
;
inset
:
0
;
border-radius
:inherit
;
padding
:
1px
;
background
:linear-gradient
(
140deg
,
#38bdf8
,
#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
:opacity
$
dur
;
}
&
:hover
{
transform
:translateY
(
-6px
)
;
background
:
#fff
;
box-shadow
:
$shadow-h
;
&
:
:
before
{
opacity
:
.9
;
}
}
}
/* headings */
.section-head
{
font-weight
:
600
;
color
:
$gray-600
;
margin-bottom
:
1rem
;
}
.mini-head
{
font-weight
:
500
;
color
:
$gray-600
;
margin-bottom
:
.6rem
;
font-size
:
.9rem
;
}
.mini-cap
{
margin-top
:
.75rem
;
font-size
:
.85rem
;
color
:
$gray-500
;
}
/* charts */
.chart-xl
{
height
:
350px
;
width
:
100%
;
}
.mini-grid
{
display
:grid
;
gap
:
1
.5rem
;
@media
(
min-width
:
768px
){
grid-template-columns
:repeat
(
3
,
1fr
)
;
}
}
.mini-card
{
@extend
.glass-card
;
display
:flex
;
flex-direction
:column
;
align-items
:center
;
}
/* ───── tables ───── */
.tbl-grid
{
display
:grid
;
gap
:
1
.5rem
;
@media
(
min-width
:
1024px
){
grid-template-columns
:repeat
(
2
,
1fr
)
;
}
}
.table-card
{
@extend
.glass-card
;
overflow-x
:auto
;
}
.table-head
{
background
:
$gray-50
;
padding
:
.9rem
1
.5rem
;
font-weight
:
600
;
color
:
$gray-600
;
border-bottom
:
1px
solid
#e2e8f0
;
}
/* zebra & hover row */
table
{
width
:
100%
;
font-size
:
.875rem
;
thead
{
background
:
$gray-50
;
color
:
$gray-500
;
}
tbody
tr
:nth-child
(
odd
)
{
background
:
#fff
;
}
tbody
tr
:nth-child
(
even
)
{
background
:
$gray-100
;
}
tbody
tr
:hover
{
background
:
$blue-50
;
}
}
src/app/components/dashboard/projects/dashboard-evaluation.component.ts
View file @
17cb7f81
...
...
@@ -32,12 +32,31 @@ interface TopScore {
export
class
DashboardEvaluationComponent
implements
OnInit
{
/* ========== KPI Cards (mock) ========== */
kpiCards
:
KpiCard
[]
=
[
{
label
:
'ประเมินเสร็จสิ้น'
,
value
:
1
_293
,
change
:
1.35
,
icon
:
'heroicons-outline:check-circle'
,
color
:
'bg-emerald-100'
},
{
label
:
'กำลังประเมิน'
,
value
:
853
,
change
:
0.82
,
icon
:
'heroicons-outline:pencil-square'
,
color
:
'bg-amber-100'
},
{
label
:
'ยังไม่ประเมิน'
,
value
:
625
,
change
:
-
2.11
,
icon
:
'heroicons-outline:clipboard'
,
color
:
'bg-rose-100'
},
{
label
:
'ผลประเมินต่ำสุด'
,
value
:
4
,
change
:
2.78
,
icon
:
'heroicons-outline:trending-down'
,
color
:
'bg-sky-100'
},
{
label
:
'ผลประเมินสูงสุด'
,
value
:
12
,
change
:
12.05
,
icon
:
'heroicons-outline:trending-up'
,
color
:
'bg-purple-100'
}
kpiCards
=
[
{
label
:
'ประเมินเสร็จสิ้น'
,
value
:
1293
,
change
:
1.35
,
icon
:
'ti ti-layout-grid'
,
bg
:
'linear-gradient(135deg,#2563eb,#1d4ed8)'
},
{
label
:
'กำลังประเมิน'
,
value
:
853
,
change
:
0.82
,
icon
:
'ti ti-clipboard-check'
,
bg
:
'linear-gradient(135deg,#0ea5e9,#0284c7)'
},
{
label
:
'ยังไม่ประเมิน'
,
value
:
625
,
change
:
-
1.12
,
icon
:
'ti ti-clock'
,
bg
:
'linear-gradient(135deg,#9333ea,#7e22ce)'
},
{
label
:
'ผลต่ำสุด'
,
value
:
4
,
change
:
2.78
,
icon
:
'ti ti-arrow-big-down-line'
,
bg
:
'linear-gradient(135deg,#ef4444,#b91c1c)'
},
{
label
:
'ผลสูงสุด'
,
value
:
12
,
change
:
12.05
,
icon
:
'ti ti-arrow-big-up-line'
,
bg
:
'linear-gradient(135deg,#22c55e,#15803d)'
}
];
/* ========== Chart Options (mock) ========== */
...
...
@@ -98,7 +117,7 @@ export class DashboardEvaluationComponent implements OnInit {
type
:
'category'
,
data
:
[
'ทรัพยากรบุคคล'
,
'การเงิน/บัญชี'
,
'การตลาด'
,
'ฝ่ายขาย'
,
'ไอที'
,
'ฝ่ายผลิต'
,
'ลูกค้าสัมพันธ์'
'ฝ่ายขาย'
,
'ไอที'
,
'ฝ่ายผลิต'
,
'ลูกค้าสัมพันธ์'
],
axisLabel
:
{
rotate
:
25
,
color
:
'#6B7280'
}
},
...
...
@@ -110,7 +129,7 @@ export class DashboardEvaluationComponent implements OnInit {
label
:
{
show
:
true
,
position
:
'top'
},
data
:
[
{
value
:
88
,
value
:
88
,
itemStyle
:
{
color
:
'#00CFE8'
,
// สีของ "ทรัพยากรบุคคล"
borderRadius
:
[
6
,
6
,
0
,
0
],
...
...
@@ -203,7 +222,7 @@ export class DashboardEvaluationComponent implements OnInit {
{
name
:
'A'
,
type
:
'bar'
,
stack
:
'total'
,
data
:
[
40
],
itemStyle
:
{
color
:
'#9af0f5'
}
},
{
name
:
'B'
,
type
:
'bar'
,
stack
:
'total'
,
data
:
[
30
],
itemStyle
:
{
color
:
'#34bdeb'
}
},
{
name
:
'C'
,
type
:
'bar'
,
stack
:
'total'
,
data
:
[
10
],
itemStyle
:
{
color
:
'#3090C7'
}
},
{
name
:
'D'
,
type
:
'bar'
,
stack
:
'total'
,
data
:
[
5
],
itemStyle
:
{
color
:
'#659EC7'
}
}
{
name
:
'D'
,
type
:
'bar'
,
stack
:
'total'
,
data
:
[
5
],
itemStyle
:
{
color
:
'#659EC7'
}
}
]
};
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment