perubahan update sidebar dashboard monitoring dan antrean loket verifikasi

This commit is contained in:
Fanrouver
2026-01-21 14:52:15 +07:00
parent fde71116ff
commit bb71955576
5 changed files with 90 additions and 361 deletions
+1
View File
@@ -334,6 +334,7 @@ onMounted(async () => {
.sidebar-logo-container {
overflow: visible !important;
height: 80px !important;
:deep(.v-list-item__content) {
overflow: visible !important;
+25 -165
View File
@@ -468,13 +468,11 @@ const visitTrendData = ref({
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
pointRadius: 4,
pointHoverRadius: 6,
pointBackgroundColor: colors.primary[600],
pointBorderColor: '#fff',
pointBorderWidth: 2,
pointHoverBorderWidth: 3,
pointHoverBorderColor: colors.primary[900],
},
{
label: 'Pasien BPJS',
@@ -484,13 +482,11 @@ const visitTrendData = ref({
borderWidth: 3,
fill: true,
tension: 0.4,
pointRadius: 5,
pointHoverRadius: 8,
pointRadius: 4,
pointHoverRadius: 6,
pointBackgroundColor: colors.secondary[600],
pointBorderColor: '#fff',
pointBorderWidth: 2,
pointHoverBorderWidth: 3,
pointHoverBorderColor: colors.secondary[900],
}
]
});
@@ -509,9 +505,7 @@ const paymentStatusData = ref({
],
borderColor: '#fff',
borderWidth: 3,
hoverOffset: 20,
hoverBorderWidth: 4,
hoverBorderColor: '#000',
hoverOffset: 15,
}
]
});
@@ -531,14 +525,6 @@ const waitingTimeData = ref({
colors.secondary[500],
colors.success[500],
],
hoverBackgroundColor: [
colors.primary[600],
colors.secondary[600],
colors.success[600],
colors.primary[700],
colors.secondary[700],
colors.success[700],
],
borderColor: [
colors.primary[600],
colors.secondary[600],
@@ -549,7 +535,6 @@ const waitingTimeData = ref({
],
borderWidth: 2,
borderRadius: 8,
hoverBorderWidth: 3,
}
]
});
@@ -567,16 +552,8 @@ const attendanceData = ref({
colors.neutral[500],
colors.primary[300],
],
hoverBackgroundColor: [
colors.success[600],
colors.primary[600],
colors.secondary[600],
colors.neutral[700],
colors.primary[500],
],
borderColor: '#fff',
borderWidth: 2,
hoverBorderWidth: 3,
}
]
});
@@ -589,11 +566,6 @@ const areaChartOptions = ref({
duration: 1000,
easing: 'easeInOutQuart'
},
onHover: (event, activeElements) => {
if (event.native) {
event.native.target.style.cursor = activeElements.length > 0 ? 'pointer' : 'default';
}
},
plugins: {
legend: {
display: true,
@@ -615,43 +587,14 @@ const areaChartOptions = ref({
backgroundColor: 'rgba(255, 255, 255, 0.95)',
titleColor: colors.neutral[900],
bodyColor: colors.neutral[700],
borderColor: colors.primary,
borderWidth: 2,
padding: 16,
boxPadding: 8,
displayColors: true,
borderColor: colors.neutral[400],
borderWidth: 1,
padding: 12,
boxPadding: 6,
usePointStyle: true,
caretPadding: 15,
cornerRadius: 8,
xAlign: 'center',
yAlign: 'top',
animation: {
duration: 200,
easing: 'easeInOutQuart'
},
titleFont: {
size: 13,
weight: 'bold',
family: "'Inter', sans-serif"
},
bodyFont: {
size: 12,
family: "'Inter', sans-serif"
},
callbacks: {
title: function(context) {
return `📈 ${context[0].label}`;
},
label: function(context) {
const value = context.parsed.y.toLocaleString('id-ID');
const percentage = ((context.parsed.y / Math.max(...context.dataset.data)) * 100).toFixed(0);
return [
`${context.dataset.label}: ${value} pasien`,
`Persentase: ${percentage}%`
];
},
afterLabel: function(context) {
return `Dataset: ${context.dataset.label}`;
return `${context.dataset.label}: ${context.parsed.y.toLocaleString('id-ID')} pasien`;
}
}
},
@@ -741,43 +684,18 @@ const doughnutOptions = ref({
backgroundColor: 'rgba(255, 255, 255, 0.95)',
titleColor: colors.neutral[900],
bodyColor: colors.neutral[700],
borderColor: colors.success,
borderWidth: 2,
padding: 16,
boxPadding: 8,
displayColors: true,
borderColor: colors.neutral[400],
borderWidth: 1,
padding: 12,
boxPadding: 6,
usePointStyle: true,
caretPadding: 15,
cornerRadius: 8,
xAlign: 'center',
yAlign: 'top',
animation: {
duration: 200,
easing: 'easeInOutQuart'
},
titleFont: {
size: 13,
weight: 'bold',
family: "'Inter', sans-serif"
},
bodyFont: {
size: 12,
family: "'Inter', sans-serif"
},
callbacks: {
title: function(context) {
return `💳 Status Pembayaran`;
},
label: function(context) {
const label = context.label || '';
const value = context.parsed;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = ((value / total) * 100).toFixed(1);
return [
`${label}: ${value.toLocaleString('id-ID')}`,
`Persentase: ${percentage}%`,
`Total: ${total.toLocaleString('id-ID')}`
];
return `${label}: ${value.toLocaleString('id-ID')} (${percentage}%)`;
}
}
}
@@ -793,11 +711,6 @@ const horizontalBarOptions = ref({
duration: 1000,
easing: 'easeInOutQuart'
},
onHover: (event, activeElements) => {
if (event.native) {
event.native.target.style.cursor = activeElements.length > 0 ? 'pointer' : 'default';
}
},
plugins: {
legend: {
display: false
@@ -807,42 +720,14 @@ const horizontalBarOptions = ref({
backgroundColor: 'rgba(255, 255, 255, 0.95)',
titleColor: colors.neutral[900],
bodyColor: colors.neutral[700],
borderColor: colors.secondary,
borderWidth: 2,
padding: 16,
boxPadding: 8,
displayColors: true,
borderColor: colors.neutral[400],
borderWidth: 1,
padding: 12,
boxPadding: 6,
usePointStyle: true,
caretPadding: 15,
cornerRadius: 8,
xAlign: 'center',
yAlign: 'top',
animation: {
duration: 200,
easing: 'easeInOutQuart'
},
titleFont: {
size: 13,
weight: 'bold',
family: "'Inter', sans-serif"
},
bodyFont: {
size: 12,
family: "'Inter', sans-serif"
},
callbacks: {
title: function(context) {
return `⏱️ ${context[0].label}`;
},
label: function(context) {
const waitTime = context.parsed.x;
let status = '✅ Cepat';
if (waitTime > 30) status = '⚠️ Sedang';
if (waitTime > 60) status = '🔴 Lama';
return [
`Waktu tunggu: ${waitTime} menit`,
`Status: ${status}`
];
return `Waktu tunggu: ${context.parsed.x} menit`;
}
}
},
@@ -910,43 +795,18 @@ const polarAreaOptions = ref({
backgroundColor: 'rgba(255, 255, 255, 0.95)',
titleColor: colors.neutral[900],
bodyColor: colors.neutral[700],
borderColor: colors.primary,
borderWidth: 2,
padding: 16,
boxPadding: 8,
displayColors: true,
borderColor: colors.neutral[400],
borderWidth: 1,
padding: 12,
boxPadding: 6,
usePointStyle: true,
caretPadding: 15,
cornerRadius: 8,
xAlign: 'center',
yAlign: 'top',
animation: {
duration: 200,
easing: 'easeInOutQuart'
},
titleFont: {
size: 13,
weight: 'bold',
family: "'Inter', sans-serif"
},
bodyFont: {
size: 12,
family: "'Inter', sans-serif"
},
callbacks: {
title: function(context) {
return `👤 Tingkat Kehadiran`;
},
label: function(context) {
const label = context.label || '';
const value = context.parsed.r;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = ((value / total) * 100).toFixed(1);
return [
`${label}: ${value.toLocaleString('id-ID')}`,
`Persentase: ${percentage}%`,
`Total: ${total.toLocaleString('id-ID')}`
];
return `${label}: ${value.toLocaleString('id-ID')} (${percentage}%)`;
}
}
}
+13 -9
View File
@@ -410,7 +410,8 @@ $font-weight-semibold: 600;
display: flex;
align-items: center;
justify-content: space-between;
padding: 32px;
padding: 16px 28px;
height: 80px;
color: $neutral-100;
}
@@ -421,15 +422,18 @@ $font-weight-semibold: 600;
.header-icon {
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
padding: 16px;
margin-right: 20px;
border-radius: 12px;
padding: 12px;
margin-right: 16px;
backdrop-filter: blur(10px);
display: flex;
align-items: center;
justify-content: center;
}
.page-title {
font-size: 36px;
line-height: 44px;
font-size: 32px;
line-height: 40px;
font-weight: $font-weight-semibold;
margin: 0;
color: $neutral-100;
@@ -437,10 +441,10 @@ $font-weight-semibold: 600;
}
.page-subtitle {
margin: 4px 0 0 0;
margin: 2px 0 0 0;
opacity: 0.9;
font-size: 16px;
line-height: 24px;
font-size: 15px;
line-height: 22px;
font-weight: $font-weight-regular;
color: $neutral-100;
}
+26 -102
View File
@@ -1,43 +1,19 @@
<template>
<v-container>
<v-card>
<!-- Header -->
<div class="page-header">
<div class="header-content">
<div class="header-left">
<div class="header-icon">
<v-icon size="32" color="white">mdi-account-details</v-icon>
</div>
<div class="header-text">
<h2 class="page-title">Informasi Pasien</h2>
<p class="page-subtitle">{{ currentDate }} - Detail Data Pasien</p>
</div>
</div>
<div class="header-stats">
<v-chip
v-if="patient.status"
color="white"
variant="flat"
class="stat-chip mr-2"
>
<v-icon start size="16">mdi-progress-check</v-icon>
{{ patient.status }}
</v-chip>
<v-btn
color="white"
elevation="0"
class="btn-back"
@click="$router.go(-1)"
>
<v-icon left size="20">mdi-arrow-left</v-icon>
Kembali
</v-btn>
</div>
</div>
</div>
<div>
<!-- Compact Header -->
<PageHeader
icon="mdi-account-details"
title="Informasi Pasien"
:subtitle="currentDate"
:show-add-button="false"
theme="primary"
/>
<!-- Content -->
<v-card-text class="content-section">
<div class="monitoring-detail-container">
<!-- Main Content -->
<v-card class="detail-card" elevation="0">
<!-- Content -->
<v-card-text class="content-section pa-4">
<v-card class="mb-6 patient-info-card" elevation="0">
<v-row class="align-center mb-4">
<v-col cols="12" md="8">
@@ -122,12 +98,14 @@
</v-row>
</v-card-text>
</v-card>
</v-container>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import PageHeader from '@/components/common/PageHeader.vue';
definePageMeta({
middleware:['auth']
@@ -289,79 +267,25 @@ $font-weight-semibold: 600;
// ============================================
// PAGE HEADER
// ============================================
.page-header {
background: linear-gradient(135deg, $primary-600 0%, $primary-700 100%);
border-radius: 16px 16px 0 0;
box-shadow: 0 4px 16px rgba(58, 97, 201, 0.2);
}
/* Header styles are now handled by PageHeader component */
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32px;
color: $neutral-100;
}
.header-left {
display: flex;
align-items: center;
}
.header-icon {
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
.monitoring-detail-container {
background: var(--color-neutral-300);
min-height: 100vh;
padding: 16px;
margin-right: 20px;
backdrop-filter: blur(10px);
}
.page-title {
font-size: 36px;
line-height: 44px;
font-weight: $font-weight-semibold;
margin: 0;
color: $neutral-100;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.page-subtitle {
margin: 4px 0 0 0;
opacity: 0.9;
font-size: 16px;
line-height: 24px;
font-weight: $font-weight-regular;
color: $neutral-100;
}
.header-stats {
display: flex;
align-items: center;
gap: 8px;
}
.stat-chip {
color: $primary-600 !important;
font-weight: $font-weight-semibold;
font-size: 14px;
line-height: 20px;
}
.btn-back {
font-weight: $font-weight-semibold;
text-transform: none;
letter-spacing: 0.5px;
font-size: 16px;
line-height: 24px;
color: $primary-600 !important;
.detail-card {
border-radius: 12px;
border: 1px solid var(--color-neutral-500);
background: var(--color-neutral-100);
}
// ============================================
// CONTENT SECTION
// ============================================
.content-section {
padding: 24px !important;
background: $neutral-100;
background: var(--color-neutral-100);
}
.patient-info-card {
+25 -85
View File
@@ -1,37 +1,19 @@
<template>
<v-container>
<v-card>
<!-- Header -->
<div class="page-header">
<div class="header-content">
<div class="header-left">
<div class="header-icon">
<v-icon size="32" color="white">mdi-shield-check</v-icon>
</div>
<div class="header-text">
<h2 class="page-title">Verifikasi Akun</h2>
<p class="page-subtitle">{{ currentDate }} - Manajemen Pasien Digital</p>
</div>
</div>
<div class="header-stats">
<v-chip color="white" variant="flat" class="stat-chip mr-2">
<v-icon start size="16">mdi-account-group</v-icon>
{{ patients.length }} User
</v-chip>
<v-chip color="white" variant="flat" class="stat-chip mr-2">
<v-icon start size="16">mdi-clock-alert</v-icon>
{{ unverifiedPatients.length }} Pending
</v-chip>
<v-chip color="white" variant="flat" class="stat-chip">
<v-icon start size="16">mdi-check-decagram</v-icon>
{{ verifiedPatients.length }} Terverifikasi
</v-chip>
</div>
</div>
</div>
<div>
<!-- Compact Header -->
<PageHeader
icon="mdi-shield-check"
title="Verifikasi Akun"
:subtitle="currentDate"
:show-add-button="false"
theme="primary"
/>
<!-- Search & Content -->
<v-card-text>
<div class="verification-container">
<!-- Main Content -->
<v-card class="verification-card" elevation="0">
<!-- Search & Content -->
<v-card-text class="pa-4">
<!-- Search & Filter -->
<div class="search-filter-section">
<div class="section-label">DATA PASIEN</div>
@@ -147,13 +129,15 @@
/>
</template>
</QRVerificationDialog>
</v-container>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useDisplay } from 'vuetify';
import QrcodeVue from 'qrcode.vue';
import PageHeader from '@/components/common/PageHeader.vue';
import QRVerificationDialog from '@/components/verification/QRVerificationDialog.vue';
definePageMeta({
@@ -323,62 +307,18 @@ $font-weight-semibold: 600;
// ============================================
// PAGE HEADER
// ============================================
.page-header {
background: linear-gradient(135deg, $primary-600 0%, $primary-700 100%);
border-radius: 16px 16px 0 0;
box-shadow: 0 4px 16px rgba(58, 97, 201, 0.2);
}
/* Header styles are now handled by PageHeader component */
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32px;
color: $neutral-100;
}
.header-left {
display: flex;
align-items: center;
}
.header-icon {
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
.verification-container {
background: var(--color-neutral-300);
min-height: 100vh;
padding: 16px;
margin-right: 20px;
backdrop-filter: blur(10px);
}
.page-title {
font-size: 36px;
line-height: 44px;
font-weight: $font-weight-semibold;
margin: 0;
color: $neutral-100;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.page-subtitle {
margin: 4px 0 0 0;
opacity: 0.9;
font-size: 16px;
line-height: 24px;
font-weight: $font-weight-regular;
color: $neutral-100;
}
.header-stats {
display: flex;
align-items: center;
gap: 8px;
}
.stat-chip {
color: $primary-600 !important;
font-weight: $font-weight-semibold;
font-size: 14px;
line-height: 20px;
.verification-card {
border-radius: 12px;
border: 1px solid var(--color-neutral-500);
background: var(--color-neutral-100);
}
.qr-code {