Files
cpone_dashboard/cpone-dashboard/templates/abnormal/index.html
2026-04-30 14:27:01 +07:00

183 lines
7.0 KiB
HTML

{{define "title"}}Abnormal Monitoring — CpOne{{end}}
{{define "header-title"}}Abnormal Monitoring{{end}}
{{define "content"}}
{{$proj := .CurrentProject}}
{{$group := .Group}}
<section class="card p-5">
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div>
<p class="text-xs font-semibold uppercase tracking-widest text-brand-500">Ongoing Project</p>
<h2 class="mt-1 text-lg font-semibold text-slate-900">
{{if $proj.Label}}{{$proj.Label}}{{else}}MCU #{{$proj.McuID}}{{end}}
</h2>
<p class="mt-0.5 text-sm text-slate-500">
{{$proj.Number}} &bull; {{$proj.CorporateName}} &bull;
<span class="num">{{$proj.StartDate | fmtDate}}</span> &ndash; <span class="num">{{$proj.EndDate | fmtDate}}</span>
</p>
</div>
<a href="{{b "/projects"}}" class="rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-semibold text-slate-600 transition hover:border-brand-400 hover:text-brand-600">
Ganti project
</a>
</div>
</section>
<section class="card p-3">
<div class="flex flex-wrap items-center gap-2 text-sm">
<a href="{{b "/abnormal"}}"
class="rounded-xl px-4 py-2 font-semibold transition
{{if eq $group ""}}bg-brand-500 text-white{{else}}border border-brand-500 text-brand-500 hover:bg-brand-50{{end}}">
Semua Kelainan
</a>
{{range .Groups}}
<a href="{{b "/abnormal"}}?group={{. | urlquery}}"
class="rounded-xl px-4 py-2 font-semibold transition
{{if eq . $group}}bg-brand-500 text-white{{else}}border border-brand-500 text-brand-500 hover:bg-brand-50{{end}}">
{{.}}
</a>
{{end}}
</div>
</section>
<section class="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
<article class="card border-l-4 border-l-brand-400 p-4">
<p class="text-xs font-semibold uppercase tracking-widest text-slate-400">Total Peserta</p>
<p class="num mt-2 text-3xl font-semibold text-slate-900">{{.Summary.Total}}</p>
<p class="mt-1 text-xs text-slate-400">Peserta aktif dalam project</p>
</article>
<article class="card border-l-4 border-l-emerald-400 p-4">
<p class="text-xs font-semibold uppercase tracking-widest text-slate-400">Normal</p>
<p class="num mt-2 text-3xl font-semibold text-emerald-600">{{.Summary.Normal}}</p>
<p class="mt-1 text-xs text-slate-400">Tanpa temuan kelainan</p>
</article>
<article class="card border-l-4 border-l-red-400 p-4">
<p class="text-xs font-semibold uppercase tracking-widest text-slate-400">Abnormal</p>
<p class="num mt-2 text-3xl font-semibold text-red-500">{{.Summary.Abnormal}}</p>
<p class="mt-1 text-xs text-slate-400">
{{if eq $group ""}}Ada temuan kelainan{{else}}Kelainan: {{$group}}{{end}}
</p>
</article>
<article class="card border-l-4 border-l-amber-400 p-4">
<p class="text-xs font-semibold uppercase tracking-widest text-slate-400">Abnormal Rate</p>
<p class="num mt-2 text-3xl font-semibold text-amber-600">{{.Summary.AbnormalRate}}%</p>
<p class="mt-1 text-xs text-slate-400">Persentase dari total peserta</p>
</article>
</section>
<section class="grid gap-5 xl:grid-cols-2">
<article class="card p-5">
<p class="mb-3 text-sm font-semibold text-slate-700">Normal vs Abnormal</p>
<div id="staff-chart" class="h-72 w-full"></div>
</article>
<article class="card p-5">
<p class="mb-3 text-sm font-semibold text-slate-700">Distribusi Kelompok Usia</p>
<div id="age-chart" class="h-72 w-full"></div>
</article>
<article class="card p-5">
<p class="mb-3 text-sm font-semibold text-slate-700">Gender</p>
<div id="gender-chart" class="h-72 w-full"></div>
</article>
<article id="dept-wrap" class="card p-5">
<p class="mb-3 text-sm font-semibold text-slate-700">Departemen</p>
<div id="dept-chart" class="h-72 w-full"></div>
</article>
</section>
<script>
const staffData = {{.StaffJSON}};
const ageData = {{.AgeJSON}};
const genderData = {{.GenderJSON}};
const deptData = {{.DeptJSON}};
const normalColor = '#3b50a0';
const abnormalColor = '#EF4444';
const staffEl = document.getElementById('staff-chart');
const ageEl = document.getElementById('age-chart');
const genderEl = document.getElementById('gender-chart');
const deptEl = document.getElementById('dept-chart');
const deptWrap = document.getElementById('dept-wrap');
if (staffEl && typeof echarts !== 'undefined') {
const staffChart = echarts.init(staffEl);
staffChart.setOption({
color: [normalColor, abnormalColor],
tooltip: { trigger: 'item' },
legend: { bottom: 0 },
series: [{
type: 'pie',
radius: ['45%', '70%'],
itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 2 },
label: { formatter: '{b}: {c}' },
data: [
{ value: staffData.normal, name: 'Normal' },
{ value: staffData.abnormal, name: 'Abnormal' }
]
}]
});
window.addEventListener('resize', () => staffChart.resize());
}
if (ageEl && ageData && typeof echarts !== 'undefined') {
const ageChart = echarts.init(ageEl);
ageChart.setOption({
color: [abnormalColor],
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: 40, right: 20, top: 20, bottom: 30 },
xAxis: { type: 'category', data: ageData.labels },
yAxis: { type: 'value' },
series: [{ name: 'Abnormal', type: 'bar', data: ageData.abnormal, barMaxWidth: 48 }]
});
window.addEventListener('resize', () => ageChart.resize());
}
if (genderEl && genderData && typeof echarts !== 'undefined') {
const genderChart = echarts.init(genderEl);
genderChart.setOption({
color: [normalColor, abnormalColor],
tooltip: { trigger: 'item' },
legend: { bottom: 0 },
series: [{
type: 'pie',
radius: ['45%', '70%'],
itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 2 },
label: { formatter: '{b}: {c}' },
data: genderData.labels.map(function(l, i) {
return { name: l, value: genderData.abnormal[i] };
})
}]
});
window.addEventListener('resize', () => genderChart.resize());
}
if (deptEl && deptData && deptData.labels && deptData.labels.length > 0 && typeof echarts !== 'undefined') {
const deptChart = echarts.init(deptEl);
deptChart.setOption({
color: [normalColor],
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: 8, right: 24, top: 8, bottom: 8, containLabel: true },
xAxis: { type: 'value' },
yAxis: {
type: 'category',
data: deptData.labels.slice().reverse(),
axisLabel: { overflow: 'truncate', width: 160 }
},
series: [{
name: 'Abnormal',
type: 'bar',
data: deptData.abnormal.slice().reverse(),
barMaxWidth: 32,
label: { show: true, position: 'right' }
}]
});
window.addEventListener('resize', () => deptChart.resize());
} else if (deptWrap) {
deptWrap.classList.add('hidden');
}
</script>
{{end}}