update flow klinik ruang, dan design consistency
This commit is contained in:
@@ -62,43 +62,66 @@
|
||||
<v-card-text class="pa-4">
|
||||
<!-- Current Processing Patient -->
|
||||
<div v-if="getCurrentProcessingForRoom(ruang)" class="current-patient-section mb-4">
|
||||
<div class="section-label-small mb-2">SEDANG DIPROSES</div>
|
||||
<div class="current-patient-header mb-2">
|
||||
<div class="section-label-small">SEDANG DIPROSES</div>
|
||||
<div class="action-icon-buttons">
|
||||
<v-tooltip text="Pending" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
class="action-icon-btn text-white"
|
||||
color="danger-600"
|
||||
variant="flat"
|
||||
size="small"
|
||||
@click="handlePatientAction(ruang, 'pending')"
|
||||
>
|
||||
<v-icon size="18">mdi-pause</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-tooltip text="Selesai" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn
|
||||
v-bind="props"
|
||||
class="action-icon-btn text-white"
|
||||
color="success-600"
|
||||
variant="flat"
|
||||
size="small"
|
||||
@click="handlePatientAction(ruang, 'selesai')"
|
||||
>
|
||||
<v-icon size="18">mdi-check</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="current-patient-info">
|
||||
<div class="patient-number-large">
|
||||
{{ getCurrentProcessingForRoom(ruang)?.noAntrian?.split(" |")[0] || '-' }}
|
||||
</div>
|
||||
<div class="patient-details">
|
||||
<div class="action-grid">
|
||||
<v-btn
|
||||
class="text-white"
|
||||
color="primary-600"
|
||||
variant="flat"
|
||||
size="small"
|
||||
@click="handleCallPatientByTipe(ruang, 'Pemeriksaan Awal')"
|
||||
>
|
||||
<v-icon start size="18">mdi-bullhorn</v-icon>
|
||||
Pemeriksaan Awal
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="text-white"
|
||||
color="secondary-600"
|
||||
variant="flat"
|
||||
size="small"
|
||||
:disabled="!getCurrentProcessingForRoom(ruang)?.calledPemeriksaanAwal"
|
||||
@click="handleCallPatientByTipe(ruang, 'Tindakan')"
|
||||
>
|
||||
<v-icon start size="18">mdi-bullhorn</v-icon>
|
||||
Panggil Tindakan
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="text-white"
|
||||
color="success-600"
|
||||
variant="flat"
|
||||
size="small"
|
||||
@click="handlePatientAction(ruang, 'selesai')"
|
||||
>
|
||||
<v-icon start size="18">mdi-check</v-icon>
|
||||
Selesai
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="text-white"
|
||||
color="danger-600"
|
||||
variant="flat"
|
||||
size="small"
|
||||
@click="handlePatientAction(ruang, 'pending')"
|
||||
>
|
||||
<v-icon start size="18">mdi-pause</v-icon>
|
||||
Pending
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -226,16 +249,6 @@
|
||||
<v-icon size="18">mdi-eye</v-icon>
|
||||
<v-tooltip activator="parent">Lihat Detail</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="text-white call-btn"
|
||||
color="primary-600"
|
||||
variant="flat"
|
||||
size="small"
|
||||
@click="handleCallPatientFromList(ruang, patient, 'Pemeriksaan Awal')"
|
||||
>
|
||||
<v-icon start size="16">mdi-bullhorn</v-icon>
|
||||
Pemeriksaan Awal
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="text-white"
|
||||
color="success-600"
|
||||
@@ -447,30 +460,85 @@
|
||||
</div>
|
||||
|
||||
<!-- Pilih Klinik Ruang (untuk Pindah Klinik dan Konsultasi) -->
|
||||
<div v-else class="klinik-ruang-selection-list">
|
||||
<div
|
||||
v-for="klinikRuangOption in getAllKlinikRuangOptions()"
|
||||
:key="`${klinikRuangOption.kodeKlinik}-${klinikRuangOption.nomorRuang}`"
|
||||
class="klinik-ruang-selection-card"
|
||||
:class="{
|
||||
'klinik-ruang-selection-card-selected': selectedKlinikRuangBaru?.kodeKlinik === klinikRuangOption.kodeKlinik && selectedKlinikRuangBaru?.nomorRuang === klinikRuangOption.nomorRuang,
|
||||
'klinik-ruang-selection-card-disabled': klinikRuangOption.kodeKlinik === selectedPatientForKelola?.kodeKlinik && klinikRuangOption.nomorRuang === selectedPatientForKelola?.nomorRuang
|
||||
}"
|
||||
@click="!(klinikRuangOption.kodeKlinik === selectedPatientForKelola?.kodeKlinik && klinikRuangOption.nomorRuang === selectedPatientForKelola?.nomorRuang) && (selectedKlinikRuangBaru = klinikRuangOption)"
|
||||
>
|
||||
<div class="klinik-ruang-selection-content">
|
||||
<div class="klinik-ruang-selection-name">{{ klinikRuangOption.namaKlinik }}</div>
|
||||
<div class="klinik-ruang-selection-room">{{ klinikRuangOption.namaRuang }} (R.{{ klinikRuangOption.nomorRuang }})</div>
|
||||
<v-chip
|
||||
v-if="klinikRuangOption.kodeKlinik === selectedPatientForKelola?.kodeKlinik && klinikRuangOption.nomorRuang === selectedPatientForKelola?.nomorRuang"
|
||||
size="x-small"
|
||||
color="neutral-500"
|
||||
class="mt-2"
|
||||
>
|
||||
Saat Ini
|
||||
</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<v-text-field
|
||||
v-model="klinikRuangSearch"
|
||||
placeholder="Cari Klinik Ruang..."
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details
|
||||
class="mb-4"
|
||||
clearable
|
||||
/>
|
||||
|
||||
<v-expansion-panels class="expansion-panels">
|
||||
<v-expansion-panel
|
||||
v-for="klinikRuang in filteredKlinikRuang"
|
||||
:key="klinikRuang.kodeKlinik"
|
||||
class="expansion-panel"
|
||||
>
|
||||
<v-expansion-panel-title class="expansion-title">
|
||||
<div class="expansion-header">
|
||||
<v-chip size="small" color="secondary-600" class="mr-2">
|
||||
{{ klinikRuang.kodeKlinik }}
|
||||
</v-chip>
|
||||
<span class="body-2 text-semibold">{{ klinikRuang.namaKlinik }}</span>
|
||||
</div>
|
||||
<template #actions>
|
||||
<v-chip size="x-small" variant="outlined">
|
||||
{{ klinikRuang.ruangList?.length || 0 }} Ruang
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-expansion-panel-title>
|
||||
|
||||
<v-expansion-panel-text>
|
||||
<div class="ruang-list">
|
||||
<div
|
||||
v-for="ruang in klinikRuang.ruangList"
|
||||
:key="ruang.nomorRuang"
|
||||
class="ruang-item"
|
||||
:class="{
|
||||
'ruang-item-selected': selectedKlinikRuangBaru?.kodeKlinik === klinikRuang.kodeKlinik && selectedKlinikRuangBaru?.nomorRuang === ruang.nomorRuang,
|
||||
'ruang-item-disabled': klinikRuang.kodeKlinik === selectedPatientForKelola?.kodeKlinik && ruang.nomorRuang === selectedPatientForKelola?.nomorRuang
|
||||
}"
|
||||
@click="!(klinikRuang.kodeKlinik === selectedPatientForKelola?.kodeKlinik && ruang.nomorRuang === selectedPatientForKelola?.nomorRuang) && (selectedKlinikRuangBaru = { kodeKlinik: klinikRuang.kodeKlinik, namaKlinik: klinikRuang.namaKlinik, nomorRuang: ruang.nomorRuang, namaRuang: ruang.namaRuang, nomorScreen: ruang.nomorScreen })"
|
||||
>
|
||||
<v-icon color="secondary-600" size="20">mdi-door</v-icon>
|
||||
<div class="ruang-info">
|
||||
<span class="body-3 text-semibold">Ruang {{ ruang.nomorRuang }} - {{ ruang.namaRuang }}</span>
|
||||
<span class="caption-2 text-muted">Screen: {{ ruang.nomorScreen }}</span>
|
||||
</div>
|
||||
<div class="ruang-actions">
|
||||
<v-chip
|
||||
v-if="klinikRuang.kodeKlinik === selectedPatientForKelola?.kodeKlinik && ruang.nomorRuang === selectedPatientForKelola?.nomorRuang"
|
||||
size="x-small"
|
||||
color="neutral-500"
|
||||
variant="outlined"
|
||||
class="mr-2"
|
||||
>
|
||||
Saat Ini
|
||||
</v-chip>
|
||||
<v-icon
|
||||
v-if="selectedKlinikRuangBaru?.kodeKlinik === klinikRuang.kodeKlinik && selectedKlinikRuangBaru?.nomorRuang === ruang.nomorRuang"
|
||||
size="20"
|
||||
color="primary-600"
|
||||
>
|
||||
mdi-check-circle
|
||||
</v-icon>
|
||||
<v-icon
|
||||
v-else
|
||||
size="20"
|
||||
color="neutral-600"
|
||||
>
|
||||
mdi-chevron-right
|
||||
</v-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
@@ -612,8 +680,7 @@
|
||||
<span class="detail-label">Fast Track</span>
|
||||
<v-chip
|
||||
size="small"
|
||||
:color="selectedPatientDetail.fastTrack === 'YA' ? 'danger-600' : 'neutral-500'"
|
||||
variant="flat"
|
||||
variant="outlined"
|
||||
class="detail-chip"
|
||||
>
|
||||
{{ selectedPatientDetail.fastTrack === 'YA' ? 'Ya' : 'Tidak' }}
|
||||
@@ -801,6 +868,7 @@ const sortOptions = ref({});
|
||||
const searchPatientQuery = ref('');
|
||||
const showFilterDialog = ref({});
|
||||
const filterOptions = ref({});
|
||||
const klinikRuangSearch = ref('');
|
||||
|
||||
// Initialize filter options for each room
|
||||
const initializeFilterOptions = (ruang) => {
|
||||
@@ -1075,6 +1143,7 @@ const closeKelolaPasienDialog = () => {
|
||||
selectedRuangBaru.value = null;
|
||||
selectedKlinikRuangBaru.value = null;
|
||||
searchPatientQuery.value = '';
|
||||
klinikRuangSearch.value = '';
|
||||
};
|
||||
|
||||
// Get all available klinik ruang options (for pindah klinik and konsultasi)
|
||||
@@ -1097,6 +1166,43 @@ const getAllKlinikRuangOptions = () => {
|
||||
return options;
|
||||
};
|
||||
|
||||
// Get klinik ruang data grouped by klinik (for expansion panels)
|
||||
const klinikRuangList = computed(() => {
|
||||
return masterStore.ruangData || [];
|
||||
});
|
||||
|
||||
// Filtered klinik ruang based on search query
|
||||
const filteredKlinikRuang = computed(() => {
|
||||
if (!klinikRuangSearch.value) return klinikRuangList.value;
|
||||
|
||||
const searchLower = klinikRuangSearch.value.toLowerCase();
|
||||
return klinikRuangList.value
|
||||
.map(klinikRuang => {
|
||||
// Check if klinik name or code matches
|
||||
const klinikMatches =
|
||||
klinikRuang.namaKlinik?.toLowerCase().includes(searchLower) ||
|
||||
klinikRuang.kodeKlinik?.toLowerCase().includes(searchLower);
|
||||
|
||||
// Filter ruangList based on search
|
||||
const filteredRuangList = klinikRuang.ruangList?.filter(ruang =>
|
||||
ruang.namaRuang?.toLowerCase().includes(searchLower) ||
|
||||
ruang.nomorRuang?.toString().includes(searchLower) ||
|
||||
ruang.nomorScreen?.toString().includes(searchLower)
|
||||
) || [];
|
||||
|
||||
// Return klinik if klinik matches or has matching ruang
|
||||
if (klinikMatches || filteredRuangList.length > 0) {
|
||||
return {
|
||||
...klinikRuang,
|
||||
ruangList: klinikMatches ? klinikRuang.ruangList : filteredRuangList
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.filter(k => k !== null && k.ruangList && k.ruangList.length > 0);
|
||||
});
|
||||
|
||||
const confirmPindahRuang = () => {
|
||||
if (!selectedRuangBaru.value || !selectedPatientForKelola.value) {
|
||||
showSnackbar('Pilih ruang tujuan', 'error');
|
||||
@@ -1849,11 +1955,43 @@ onMounted(() => {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.current-patient-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.action-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action-icon-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action-icon-btn {
|
||||
min-width: 40px !important;
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
padding: 0 !important;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.action-icon-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.action-icon-btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
.action-grid .v-btn {
|
||||
@@ -2098,6 +2236,11 @@ onMounted(() => {
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.body-3 {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.caption-2 {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
@@ -2436,7 +2579,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.action-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@@ -2449,6 +2592,12 @@ onMounted(() => {
|
||||
.action-grid .v-btn .v-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.action-icon-btn {
|
||||
min-width: 36px !important;
|
||||
width: 36px !important;
|
||||
height: 36px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
@@ -2500,7 +2649,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.action-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@@ -2514,6 +2663,26 @@ onMounted(() => {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.action-icon-btn {
|
||||
min-width: 32px !important;
|
||||
width: 32px !important;
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
.action-icon-btn .v-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.action-icon-btn {
|
||||
min-width: 32px !important;
|
||||
width: 32px !important;
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
.action-icon-btn .v-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.patient-queue-actions {
|
||||
gap: 4px;
|
||||
flex-wrap: nowrap;
|
||||
@@ -2847,68 +3016,96 @@ onMounted(() => {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* Klinik Ruang Selection Styles */
|
||||
.klinik-ruang-selection-list {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
/* Klinik Ruang Selection Styles - Expansion Panels */
|
||||
.expansion-panels {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.expansion-panel {
|
||||
background: var(--color-neutral-100);
|
||||
border: 1px solid var(--color-neutral-400);
|
||||
border-radius: 12px !important;
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.expansion-panel::before {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.expansion-title {
|
||||
background: var(--color-neutral-100);
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.expansion-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ruang-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-card {
|
||||
.ruang-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
background: var(--color-neutral-100);
|
||||
border: 2px solid var(--color-neutral-300);
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
background: var(--color-neutral-300);
|
||||
border: 1px solid var(--color-neutral-400);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-card:hover:not(.klinik-ruang-selection-card-disabled) {
|
||||
background: var(--color-neutral-200);
|
||||
.ruang-item:hover:not(.ruang-item-disabled) {
|
||||
border-color: var(--color-primary-400);
|
||||
background: rgba(58, 97, 201, 0.1);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-card-selected {
|
||||
background: var(--color-primary-100);
|
||||
border-color: var(--color-primary-600);
|
||||
box-shadow: 0 2px 8px rgba(255, 152, 0, 0.2);
|
||||
.ruang-item:active:not(.ruang-item-disabled) {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-card-disabled {
|
||||
.ruang-item-selected {
|
||||
background: var(--color-primary-100);
|
||||
border-color: var(--color-primary-600);
|
||||
box-shadow: 0 2px 8px rgba(58, 97, 201, 0.2);
|
||||
}
|
||||
|
||||
.ruang-item-disabled {
|
||||
background: var(--color-neutral-200);
|
||||
border-color: var(--color-neutral-400);
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-card-disabled:hover {
|
||||
.ruang-item-disabled:hover {
|
||||
transform: none;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
border-color: var(--color-neutral-400);
|
||||
background: var(--color-neutral-200);
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-content {
|
||||
.ruang-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-name {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 600;
|
||||
color: var(--color-neutral-900);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.klinik-ruang-selection-room {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--color-neutral-600);
|
||||
.ruang-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* Filter and Sort Actions */
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
variant="flat"
|
||||
size="large"
|
||||
block
|
||||
class="btn-view"
|
||||
class="btn-view text-white"
|
||||
>
|
||||
<v-icon left>mdi-eye</v-icon>
|
||||
Tampilkan
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<div class="footer-stats-bar">
|
||||
<div class="stat-item">
|
||||
<div class="stat-icon stat-icon-total">
|
||||
<v-icon size="32" color="success-600">mdi-format-list-numbered</v-icon>
|
||||
<v-icon size="32" color="primary-600">mdi-format-list-numbered</v-icon>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ statistics.total }}</div>
|
||||
@@ -104,7 +104,7 @@
|
||||
|
||||
<div class="stat-item">
|
||||
<div class="stat-icon stat-icon-waiting">
|
||||
<v-icon size="32" color="success-600">mdi-clock-alert-outline</v-icon>
|
||||
<v-icon size="32" color="primary-600">mdi-clock-alert-outline</v-icon>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ statistics.waiting }}</div>
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
<div class="stat-item">
|
||||
<div class="stat-icon stat-icon-active">
|
||||
<v-icon size="32" color="success-600">mdi-account-check</v-icon>
|
||||
<v-icon size="32" color="primary-600">mdi-account-check</v-icon>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ statistics.active }}</div>
|
||||
@@ -125,7 +125,7 @@
|
||||
</div>
|
||||
|
||||
<div class="footer-message">
|
||||
<v-icon size="24" color="success-600" class="mr-2">mdi-information</v-icon>
|
||||
<v-icon size="24" color="primary-600" class="mr-2">mdi-information</v-icon>
|
||||
<span>Harap perhatikan nomor antrian Anda di layar</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -620,11 +620,11 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, var(--color-success-600) 0%, var(--color-success-700) 100%);
|
||||
background: linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-primary-700) 100%);
|
||||
border-radius: 16px;
|
||||
padding: 24px 40px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 8px 24px rgba(0, 146, 98, 0.3);
|
||||
box-shadow: 0 8px 24px rgba(33, 150, 243, 0.3);
|
||||
}
|
||||
|
||||
.header-left {
|
||||
@@ -701,12 +701,13 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
|
||||
/* ========== HERO CALL SECTION ========== */
|
||||
.hero-call-section {
|
||||
background: linear-gradient(135deg, var(--color-danger-600) 0%, var(--color-danger-700) 100%);
|
||||
background: linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-primary-700) 100%);
|
||||
border-radius: 20px;
|
||||
padding: 32px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
box-shadow: 0 12px 32px rgba(224, 21, 7, 0.35);
|
||||
box-shadow: 0 12px 32px rgba(33, 150, 243, 0.35);
|
||||
animation: pulse-highlight 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.call-label {
|
||||
@@ -729,6 +730,7 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
letter-spacing: 8px;
|
||||
line-height: 1;
|
||||
text-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||
animation: number-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.call-clinic {
|
||||
@@ -749,17 +751,17 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
|
||||
.clinic-box {
|
||||
background: var(--color-neutral-100);
|
||||
border: 2px solid var(--color-success-200);
|
||||
border: 2px solid var(--color-primary-200);
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0, 146, 98, 0.12);
|
||||
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.12);
|
||||
min-height: 240px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.clinic-header-bar {
|
||||
background: linear-gradient(135deg, var(--color-success-600) 0%, var(--color-success-700) 100%);
|
||||
background: linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-primary-700) 100%);
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -797,7 +799,7 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
background: var(--color-success-100);
|
||||
background: var(--color-primary-50);
|
||||
}
|
||||
|
||||
.tipe-layanan-section {
|
||||
@@ -807,12 +809,12 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
.tipe-label {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: var(--color-success-700);
|
||||
color: var(--color-primary-700);
|
||||
margin-bottom: 12px;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
padding: 8px 12px;
|
||||
background: var(--color-success-200);
|
||||
background: var(--color-primary-200);
|
||||
border-radius: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -837,7 +839,7 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
.current-label {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--color-success-600);
|
||||
color: var(--color-primary-600);
|
||||
margin-bottom: 8px;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
@@ -874,13 +876,13 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
}
|
||||
|
||||
.next-item {
|
||||
background: var(--color-success-600);
|
||||
background: var(--color-primary-600);
|
||||
color: var(--color-neutral-100);
|
||||
padding: 8px 16px;
|
||||
border-radius: 12px;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 2px 8px rgba(0, 146, 98, 0.25);
|
||||
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.25);
|
||||
letter-spacing: 1px;
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
@@ -891,13 +893,13 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
/* ========== FOOTER STATS ========== */
|
||||
.footer-stats-bar {
|
||||
background: var(--color-neutral-100);
|
||||
border: 2px solid var(--color-success-200);
|
||||
border: 2px solid var(--color-primary-200);
|
||||
border-radius: 16px;
|
||||
padding: 20px 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 32px;
|
||||
box-shadow: 0 4px 12px rgba(0, 146, 98, 0.12);
|
||||
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.12);
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
@@ -917,11 +919,11 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
|
||||
.stat-icon-total,
|
||||
.stat-icon-waiting {
|
||||
background: var(--color-success-200);
|
||||
background: var(--color-primary-200);
|
||||
}
|
||||
|
||||
.stat-icon-active {
|
||||
background: var(--color-success-200);
|
||||
background: var(--color-primary-200);
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
@@ -947,7 +949,7 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
.stat-divider {
|
||||
width: 2px;
|
||||
height: 60px;
|
||||
background: var(--color-success-200);
|
||||
background: var(--color-primary-200);
|
||||
}
|
||||
|
||||
.footer-message {
|
||||
@@ -1247,6 +1249,25 @@ watch(anjunganClientId, (newClientId, oldClientId) => {
|
||||
}
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes pulse-highlight {
|
||||
0%, 100% {
|
||||
box-shadow: 0 12px 32px rgba(33, 150, 243, 0.35);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 12px 48px rgba(33, 150, 243, 0.55);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes number-pulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent text selection */
|
||||
* {
|
||||
user-select: none;
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
<div class="klinik-selection-container">
|
||||
<div class="selection-header">
|
||||
<div class="header-icon">
|
||||
<v-icon size="64" color="white">mdi-door-open</v-icon>
|
||||
<img
|
||||
src="/Rumah_Sakit_Umum_Daerah_Dr._Saiful_Anwar.webp"
|
||||
alt="RSUD Logo"
|
||||
class="header-logo"
|
||||
/>
|
||||
</div>
|
||||
<div class="header-content">
|
||||
<h1 class="main-title">Pilih Klinik Ruang</h1>
|
||||
@@ -19,7 +23,7 @@
|
||||
@click="navigateToKlinik(klinik.kodeKlinik)"
|
||||
>
|
||||
<div class="klinik-card-header">
|
||||
<v-icon size="32" color="success">mdi-hospital-building</v-icon>
|
||||
<v-icon size="32" color="primary">mdi-hospital-building</v-icon>
|
||||
<div class="klinik-info">
|
||||
<h3 class="klinik-name">{{ klinik.namaKlinik }}</h3>
|
||||
<p class="klinik-code">{{ klinik.kodeKlinik }}</p>
|
||||
@@ -28,7 +32,7 @@
|
||||
|
||||
<div class="klinik-ruang-preview">
|
||||
<div class="ruang-count">
|
||||
<v-icon size="18" color="success">mdi-door</v-icon>
|
||||
<v-icon size="18" color="primary">mdi-door</v-icon>
|
||||
<span>{{ klinik.ruangList.length }} Ruang</span>
|
||||
</div>
|
||||
<div class="ruang-tags">
|
||||
@@ -52,7 +56,7 @@
|
||||
|
||||
<div class="klinik-card-footer">
|
||||
<v-btn
|
||||
color="success"
|
||||
color="primary"
|
||||
variant="flat"
|
||||
size="large"
|
||||
block
|
||||
@@ -70,7 +74,7 @@
|
||||
<h3>Tidak Ada Klinik dengan Ruang Tersedia</h3>
|
||||
<p>Silakan tambah ruang klinik terlebih dahulu di halaman master</p>
|
||||
<v-btn
|
||||
color="success"
|
||||
color="primary"
|
||||
variant="flat"
|
||||
@click="navigateToSettings"
|
||||
class="mt-4"
|
||||
@@ -181,24 +185,32 @@ const navigateToSettings = () => {
|
||||
}
|
||||
|
||||
.selection-header {
|
||||
background: linear-gradient(135deg, var(--color-success-600) 0%, var(--color-success-700) 100%);
|
||||
background: linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-primary-700) 100%);
|
||||
border-radius: 20px;
|
||||
padding: 40px;
|
||||
margin-bottom: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 32px;
|
||||
box-shadow: 0 8px 24px rgba(0, 146, 98, 0.3);
|
||||
box-shadow: 0 8px 24px rgba(33, 150, 243, 0.3);
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20px;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header-logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: contain;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
@@ -207,17 +219,15 @@ const navigateToSettings = () => {
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 48px;
|
||||
font-size: 40px;
|
||||
font-weight: 800;
|
||||
margin: 0;
|
||||
letter-spacing: 2px;
|
||||
color: var(--color-neutral-100);
|
||||
line-height: 1.2;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin: 8px 0 0 0;
|
||||
color: var(--color-neutral-100);
|
||||
@@ -246,8 +256,8 @@ const navigateToSettings = () => {
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(0, 146, 98, 0.2);
|
||||
border-color: var(--color-success-600);
|
||||
box-shadow: 0 8px 24px rgba(33, 150, 243, 0.2);
|
||||
border-color: var(--color-primary-600);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +298,7 @@ const navigateToSettings = () => {
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--color-success-600);
|
||||
color: var(--color-primary-600);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@@ -299,8 +309,8 @@ const navigateToSettings = () => {
|
||||
}
|
||||
|
||||
.chip-preview {
|
||||
background-color: var(--color-success-300) !important;
|
||||
color: var(--color-success-700) !important;
|
||||
background-color: var(--color-primary-300) !important;
|
||||
color: var(--color-primary-700) !important;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
<div class="loket-selection-container">
|
||||
<div class="selection-header">
|
||||
<div class="header-icon">
|
||||
<v-icon size="64" color="white">mdi-view-dashboard</v-icon>
|
||||
<img
|
||||
src="/Rumah_Sakit_Umum_Daerah_Dr._Saiful_Anwar.webp"
|
||||
alt="RSUD Logo"
|
||||
class="header-logo"
|
||||
/>
|
||||
</div>
|
||||
<div class="header-content">
|
||||
<h1 class="main-title">Pilih Layar Antrian Loket</h1>
|
||||
@@ -56,7 +60,7 @@
|
||||
variant="flat"
|
||||
size="large"
|
||||
block
|
||||
class="btn-view"
|
||||
class="btn-view text-white"
|
||||
>
|
||||
<v-icon left>mdi-eye</v-icon>
|
||||
Tampilkan
|
||||
@@ -174,13 +178,21 @@ const getKlinikName = (kode) => {
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20px;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header-logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: contain;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
@@ -189,17 +201,15 @@ const getKlinikName = (kode) => {
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 48px;
|
||||
font-size: 40px;
|
||||
font-weight: 800;
|
||||
margin: 0;
|
||||
letter-spacing: 2px;
|
||||
color: var(--color-neutral-100);
|
||||
line-height: 1.2;
|
||||
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 20px;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
margin: 8px 0 0 0;
|
||||
color: var(--color-neutral-100);
|
||||
|
||||
@@ -30,28 +30,48 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabs -->
|
||||
<v-card-text class="tabs-section">
|
||||
<v-tabs
|
||||
v-model="activeTab"
|
||||
color="primary"
|
||||
align-tabs="start"
|
||||
show-arrows
|
||||
class="status-tabs"
|
||||
<!-- Status Filter Section -->
|
||||
<v-card-text class="filter-section-top">
|
||||
<div class="section-label">DATA PASIEN</div>
|
||||
|
||||
<v-chip-group
|
||||
v-model="activeTab"
|
||||
mandatory
|
||||
class="status-filter"
|
||||
>
|
||||
<v-tab value="all" @click="filterByStatus('all')">
|
||||
Semua Pasien <v-badge color="grey-lighten-1" :content="totalCount" inline class="ml-2"></v-badge>
|
||||
</v-tab>
|
||||
<v-tab value="Menunggu Poli" @click="filterByStatus('Menunggu Poli')">
|
||||
Menunggu Poli <v-badge color="orange-lighten-1" :content="waitingCount" inline class="ml-2"></v-badge>
|
||||
</v-tab>
|
||||
<v-tab value="Diperiksa Dokter" @click="filterByStatus('Diperiksa Dokter')">
|
||||
Diperiksa Dokter <v-badge color="green-lighten-1" :content="examiningCount" inline class="ml-2"></v-badge>
|
||||
</v-tab>
|
||||
<v-tab value="Selesai Pelayanan" @click="filterByStatus('Selesai Pelayanan')">
|
||||
Selesai Pelayanan <v-badge color="blue-lighten-1" :content="doneCount" inline class="ml-2"></v-badge>
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<v-chip
|
||||
value="all"
|
||||
:class="{ 'active-chip': activeTab === 'all' }"
|
||||
@click="filterByStatus('all')"
|
||||
>
|
||||
<v-icon start size="16">mdi-account-group</v-icon>
|
||||
Semua Pasien ({{ totalCount }})
|
||||
</v-chip>
|
||||
<v-chip
|
||||
value="Menunggu Poli"
|
||||
:class="{ 'active-chip': activeTab === 'Menunggu Poli' }"
|
||||
@click="filterByStatus('Menunggu Poli')"
|
||||
>
|
||||
<v-icon start size="16">mdi-clock-outline</v-icon>
|
||||
Menunggu Poli ({{ waitingCount }})
|
||||
</v-chip>
|
||||
<v-chip
|
||||
value="Diperiksa Dokter"
|
||||
:class="{ 'active-chip': activeTab === 'Diperiksa Dokter' }"
|
||||
@click="filterByStatus('Diperiksa Dokter')"
|
||||
>
|
||||
<v-icon start size="16">mdi-doctor</v-icon>
|
||||
Diperiksa Dokter ({{ examiningCount }})
|
||||
</v-chip>
|
||||
<v-chip
|
||||
value="Selesai Pelayanan"
|
||||
:class="{ 'active-chip': activeTab === 'Selesai Pelayanan' }"
|
||||
@click="filterByStatus('Selesai Pelayanan')"
|
||||
>
|
||||
<v-icon start size="16">mdi-check-circle</v-icon>
|
||||
Selesai Pelayanan ({{ doneCount }})
|
||||
</v-chip>
|
||||
</v-chip-group>
|
||||
</v-card-text>
|
||||
|
||||
<!-- Filter Section -->
|
||||
@@ -62,9 +82,11 @@
|
||||
<v-text-field
|
||||
label="No. RM"
|
||||
v-model="filters.rm_number"
|
||||
prepend-inner-icon="mdi-card-account-details"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details
|
||||
clearable
|
||||
class="input-field"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
@@ -72,18 +94,21 @@
|
||||
<v-text-field
|
||||
label="No. Antrean"
|
||||
v-model="filters.queue_number"
|
||||
prepend-inner-icon="mdi-numeric"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details
|
||||
type="number"
|
||||
clearable
|
||||
class="input-field"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="2">
|
||||
<v-col cols="12" sm="3">
|
||||
<v-select
|
||||
label="Layanan"
|
||||
v-model="filters.service"
|
||||
:items="['Klinik Jiwa', 'Radiologi', 'Fisioterapi', 'Klinik Umum']"
|
||||
prepend-inner-icon="mdi-hospital-building"
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details
|
||||
@@ -93,7 +118,6 @@
|
||||
</v-col>
|
||||
<v-col cols="12" sm="2">
|
||||
<v-btn
|
||||
color="success"
|
||||
block
|
||||
height="40"
|
||||
@click="applyFilters"
|
||||
@@ -104,6 +128,18 @@
|
||||
Cari
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="2">
|
||||
<v-btn
|
||||
block
|
||||
height="40"
|
||||
@click="resetFilters"
|
||||
class="btn-reset"
|
||||
variant="outlined"
|
||||
>
|
||||
<v-icon left size="18">mdi-refresh</v-icon>
|
||||
Reset
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-card-text>
|
||||
@@ -117,11 +153,24 @@
|
||||
class="elevation-0 data-table"
|
||||
:search="currentSearchTerm"
|
||||
>
|
||||
<template v-slot:item.no="{ index }">
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.status="{ item }">
|
||||
<v-chip :color="getStatusColor(item.status)" size="small" class="font-weight-medium status-chip" label>
|
||||
<v-chip
|
||||
size="small"
|
||||
:class="getStatusChipClass(item.status)"
|
||||
>
|
||||
<v-icon
|
||||
:icon="getStatusIcon(item.status)"
|
||||
size="14"
|
||||
class="mr-1"
|
||||
></v-icon>
|
||||
{{ item.status }}
|
||||
</v-chip>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.aksi="{ item }">
|
||||
<v-btn
|
||||
size="small"
|
||||
@@ -133,10 +182,12 @@
|
||||
Lihat
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<template v-slot:no-data>
|
||||
<v-alert :value="true" color="info" icon="mdi-information-outline">
|
||||
Tidak ada data pasien untuk ditampilkan.
|
||||
</v-alert>
|
||||
<div class="pa-8 text-center">
|
||||
<v-icon size="48" color="grey-lighten-1" class="mb-2">mdi-information-outline</v-icon>
|
||||
<p class="text-body-1 text-grey-darken-1">Tidak ada data pasien untuk ditampilkan.</p>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-card-text>
|
||||
@@ -179,12 +230,13 @@ const currentSearchTerm = ref('');
|
||||
|
||||
// Table Headers
|
||||
const headers = [
|
||||
{ title: 'No. RM', key: 'rm_number' },
|
||||
{ title: 'Nama', key: 'name' },
|
||||
{ title: 'No. Antrean', key: 'queue_number' },
|
||||
{ title: 'Layanan', key: 'service' },
|
||||
{ title: 'Status', key: 'status' },
|
||||
{ title: 'Aksi', key: 'aksi', sortable: false },
|
||||
{ title: 'No', key: 'no', sortable: false, width: '60px' },
|
||||
{ title: 'No. RM', key: 'rm_number', sortable: true },
|
||||
{ title: 'Nama', key: 'name', sortable: true },
|
||||
{ title: 'No. Antrean', key: 'queue_number', sortable: true, width: '120px' },
|
||||
{ title: 'Layanan', key: 'service', sortable: true },
|
||||
{ title: 'Status', key: 'status', sortable: true, width: '180px' },
|
||||
{ title: 'Aksi', key: 'aksi', sortable: false, width: '120px' },
|
||||
];
|
||||
|
||||
// Mock Patient Data
|
||||
@@ -230,6 +282,17 @@ const applyFilters = () => {
|
||||
activeTab.value = 'all';
|
||||
};
|
||||
|
||||
// Reset all filters
|
||||
const resetFilters = () => {
|
||||
filters.value.rm_number = '';
|
||||
filters.value.qr_code = '';
|
||||
filters.value.queue_number = '';
|
||||
filters.value.service = null;
|
||||
currentSearchTerm.value = '';
|
||||
filteredPatientList.value = ALL_PATIENTS_DATA;
|
||||
activeTab.value = 'all';
|
||||
};
|
||||
|
||||
// 2. Logic Filter Status (saat tab ditekan)
|
||||
const filterByStatus = (status) => {
|
||||
// Pastikan status tab diperbarui
|
||||
@@ -277,12 +340,20 @@ const paginatedPatients = computed(() => {
|
||||
|
||||
// === UTILITIES & NAVIGATION ===
|
||||
|
||||
// Utility function to set color based on status
|
||||
const getStatusColor = (status) => {
|
||||
if (status === 'Diperiksa Dokter') return 'green-darken-1';
|
||||
if (status === 'Menunggu Poli') return 'orange-darken-1';
|
||||
if (status === 'Selesai Pelayanan') return 'blue-darken-2';
|
||||
return 'grey';
|
||||
// Utility function to set chip class based on status
|
||||
const getStatusChipClass = (status) => {
|
||||
if (status === 'Diperiksa Dokter') return 'chip-success';
|
||||
if (status === 'Menunggu Poli') return 'chip-warning';
|
||||
if (status === 'Selesai Pelayanan') return 'chip-primary';
|
||||
return 'chip-neutral';
|
||||
};
|
||||
|
||||
// Utility function to set icon based on status
|
||||
const getStatusIcon = (status) => {
|
||||
if (status === 'Diperiksa Dokter') return 'mdi-doctor';
|
||||
if (status === 'Menunggu Poli') return 'mdi-clock-outline';
|
||||
if (status === 'Selesai Pelayanan') return 'mdi-check-circle';
|
||||
return 'mdi-help-circle';
|
||||
};
|
||||
|
||||
// Function to navigate to the detailed patient information page
|
||||
@@ -386,26 +457,53 @@ $font-weight-semibold: 600;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// TABS SECTION
|
||||
// FILTER SECTION TOP
|
||||
// ============================================
|
||||
.tabs-section {
|
||||
padding: 24px 24px 0 24px !important;
|
||||
.filter-section-top {
|
||||
padding: 24px 24px 16px 24px !important;
|
||||
background: $neutral-100;
|
||||
}
|
||||
|
||||
.status-tabs {
|
||||
font-family: $font-family-base;
|
||||
.section-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
color: $neutral-600;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.v-tab.v-tab--selected {
|
||||
.status-filter {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-filter .v-chip {
|
||||
font-size: 12px;
|
||||
font-weight: $font-weight-semibold;
|
||||
height: 32px;
|
||||
border: 1px solid $neutral-500;
|
||||
background: $neutral-100;
|
||||
color: $neutral-600;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: $neutral-300;
|
||||
}
|
||||
}
|
||||
|
||||
.status-filter .v-chip.active-chip {
|
||||
background: $primary-600;
|
||||
color: $neutral-100;
|
||||
border-color: $primary-600;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// FILTER SECTION
|
||||
// ============================================
|
||||
.filter-section {
|
||||
padding: 24px !important;
|
||||
padding: 0 24px 24px 24px !important;
|
||||
background: $neutral-100;
|
||||
}
|
||||
|
||||
@@ -422,12 +520,29 @@ $font-weight-semibold: 600;
|
||||
}
|
||||
|
||||
.btn-search {
|
||||
background-color: $success-600 !important;
|
||||
background-color: $primary-600 !important;
|
||||
color: $neutral-100 !important;
|
||||
text-transform: none;
|
||||
font-weight: $font-weight-semibold;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
&:hover {
|
||||
background-color: $primary-700 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-reset {
|
||||
border-color: $neutral-600 !important;
|
||||
color: $neutral-800 !important;
|
||||
text-transform: none;
|
||||
font-weight: $font-weight-semibold;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
&:hover {
|
||||
background-color: $neutral-300 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
@@ -435,21 +550,70 @@ $font-weight-semibold: 600;
|
||||
// ============================================
|
||||
.data-table {
|
||||
font-family: $font-family-base;
|
||||
|
||||
:deep(.v-data-table__th) {
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $neutral-800;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
:deep(.v-data-table__td) {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: $neutral-900;
|
||||
}
|
||||
}
|
||||
|
||||
.status-chip {
|
||||
// ============================================
|
||||
// CHIPS
|
||||
// ============================================
|
||||
.chip-success {
|
||||
background-color: $success-600 !important;
|
||||
color: $neutral-100 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.chip-warning {
|
||||
background-color: #F59E0B !important;
|
||||
color: $neutral-100 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.chip-primary {
|
||||
background-color: $primary-600 !important;
|
||||
color: $neutral-100 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.chip-neutral {
|
||||
background-color: $neutral-600 !important;
|
||||
color: $neutral-100 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// BUTTONS
|
||||
// ============================================
|
||||
.btn-view {
|
||||
background-color: $success-600 !important;
|
||||
background-color: $primary-600 !important;
|
||||
color: $neutral-100 !important;
|
||||
text-transform: none;
|
||||
font-weight: $font-weight-semibold;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
&:hover {
|
||||
background-color: $primary-700 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<div class="hak-akses-page pa-4">
|
||||
<v-breadcrumbs :items="breadcrumbs" class="pl-0 mb-4">
|
||||
<template v-slot:divider>
|
||||
<v-icon icon="mdi-chevron-right"></v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
<!-- Dialog for Add/Edit Form -->
|
||||
<v-dialog
|
||||
v-model="showAddEditDialog"
|
||||
|
||||
@@ -1,20 +1,5 @@
|
||||
<template>
|
||||
<div class="user-login-page pa-4">
|
||||
<!-- Display Authentication Info for context -->
|
||||
<div class="mb-4 pa-3 bg-blue-grey-lighten-5 rounded-lg text-caption">
|
||||
User Status:
|
||||
<v-chip :color="currentUserData ? 'green' : 'red'" size="small" class="ml-2 mr-1">
|
||||
{{ currentUserData ? 'Authenticated' : 'Unauthenticated' }}
|
||||
</v-chip>
|
||||
(Username: <strong>{{ currentUserData?.namaUser || currentUserData?.namaLengkap || 'N/A' }}</strong>)
|
||||
</div>
|
||||
|
||||
<v-breadcrumbs :items="breadcrumbs" class="pl-0">
|
||||
<template #divider>
|
||||
<v-icon icon="mdi-chevron-right"></v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
|
||||
<v-alert
|
||||
v-if="fetchError"
|
||||
type="error"
|
||||
|
||||
@@ -31,22 +31,96 @@
|
||||
</div>
|
||||
|
||||
<!-- Search & Content -->
|
||||
<v-card-text class="pa-0">
|
||||
<!-- Search & Tabs -->
|
||||
<VerificationSearchTabs
|
||||
v-model:search-query="search"
|
||||
v-model:selected-tab="filterStatus"
|
||||
:all-count="patients.length"
|
||||
:pending-count="unverifiedPatients.length"
|
||||
:verified-count="verifiedPatients.length"
|
||||
/>
|
||||
<v-card-text>
|
||||
<!-- Search & Filter -->
|
||||
<div class="search-filter-section">
|
||||
<div class="section-label">DATA PASIEN</div>
|
||||
|
||||
<!-- Status Filter Chips -->
|
||||
<v-chip-group
|
||||
v-model="filterStatus"
|
||||
mandatory
|
||||
class="status-filter mb-3"
|
||||
>
|
||||
<v-chip
|
||||
:value="0"
|
||||
:class="{ 'active-chip': filterStatus === 0 }"
|
||||
>
|
||||
<v-icon start size="16">mdi-account-group</v-icon>
|
||||
Semua ({{ patients.length }})
|
||||
</v-chip>
|
||||
<v-chip
|
||||
:value="1"
|
||||
:class="{ 'active-chip': filterStatus === 1 }"
|
||||
>
|
||||
<v-icon start size="16">mdi-clock-alert</v-icon>
|
||||
Belum Verifikasi ({{ unverifiedPatients.length }})
|
||||
</v-chip>
|
||||
<v-chip
|
||||
:value="2"
|
||||
:class="{ 'active-chip': filterStatus === 2 }"
|
||||
>
|
||||
<v-icon start size="16">mdi-check-decagram</v-icon>
|
||||
Terverifikasi ({{ verifiedPatients.length }})
|
||||
</v-chip>
|
||||
</v-chip-group>
|
||||
|
||||
<!-- Patient List -->
|
||||
<PatientVerificationList
|
||||
:patients="filteredPatients"
|
||||
:empty-message="noDataText"
|
||||
@verify="openDaftarModal"
|
||||
/>
|
||||
<!-- Search Field -->
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
placeholder="Cari nama atau No. RM..."
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details
|
||||
clearable
|
||||
class="search-field"
|
||||
></v-text-field>
|
||||
</div>
|
||||
|
||||
<!-- Data Table -->
|
||||
<v-data-table
|
||||
:headers="headers"
|
||||
:items="filteredPatients"
|
||||
:items-per-page="10"
|
||||
class="elevation-0 data-table"
|
||||
>
|
||||
<template v-slot:item.no="{ index }">
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
|
||||
<template v-slot:item.status="{ item }">
|
||||
<v-chip
|
||||
size="small"
|
||||
:class="item.status === 'Terverifikasi' ? 'chip-success' : 'chip-warning'"
|
||||
>
|
||||
<v-icon
|
||||
:icon="item.status === 'Terverifikasi' ? 'mdi-check-circle' : 'mdi-clock-alert'"
|
||||
size="14"
|
||||
class="mr-1"
|
||||
></v-icon>
|
||||
{{ item.status }}
|
||||
</v-chip>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.telepon="{ item }">
|
||||
<span v-if="item.telepon">{{ item.telepon }}</span>
|
||||
<v-chip v-else size="small" class="chip-neutral">Belum diisi</v-chip>
|
||||
</template>
|
||||
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
v-if="item.status === 'Belum Terverifikasi'"
|
||||
size="small"
|
||||
@click="openDaftarModal(item)"
|
||||
variant="flat"
|
||||
class="btn-verify"
|
||||
>
|
||||
<v-icon size="16" left>mdi-qrcode-scan</v-icon>
|
||||
Verifikasi
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
@@ -80,8 +154,6 @@
|
||||
import { ref, computed } from 'vue';
|
||||
import { useDisplay } from 'vuetify';
|
||||
import QrcodeVue from 'qrcode.vue';
|
||||
import VerificationSearchTabs from '@/components/verification/VerificationSearchTabs.vue';
|
||||
import PatientVerificationList from '@/components/verification/PatientVerificationList.vue';
|
||||
import QRVerificationDialog from '@/components/verification/QRVerificationDialog.vue';
|
||||
|
||||
definePageMeta({
|
||||
@@ -90,6 +162,17 @@ definePageMeta({
|
||||
|
||||
const display = useDisplay();
|
||||
|
||||
// Table Headers
|
||||
const headers = ref([
|
||||
{ title: 'No', value: 'no', sortable: false, width: '60px' },
|
||||
{ title: 'Nama Pasien', value: 'nama', sortable: true },
|
||||
{ title: 'No. RM', value: 'rm', sortable: true },
|
||||
{ title: 'Alamat', value: 'alamat', sortable: false },
|
||||
{ title: 'No. Telepon', value: 'telepon', sortable: false },
|
||||
{ title: 'Status', value: 'status', sortable: true, width: '180px' },
|
||||
{ title: 'Actions', value: 'actions', sortable: false, width: '200px' },
|
||||
]);
|
||||
|
||||
// Data
|
||||
const patients = ref([
|
||||
{ nama: 'Budi Santoso', rm: '00123456', alamat: 'Jl. Melati No. 10', telepon: '', status: 'Belum Terverifikasi' },
|
||||
@@ -114,12 +197,6 @@ const currentDate = computed(() => {
|
||||
return `${days[now.getDay()]}, ${now.getDate()} ${months[now.getMonth()]} ${now.getFullYear()}`;
|
||||
});
|
||||
|
||||
const noDataText = computed(() =>
|
||||
search.value
|
||||
? 'Tidak ada data pasien yang cocok dengan pencarian.'
|
||||
: 'Tidak ada pasien dengan status ini.'
|
||||
);
|
||||
|
||||
const unverifiedPatients = computed(() =>
|
||||
patients.value.filter((p) => p.status === 'Belum Terverifikasi')
|
||||
);
|
||||
@@ -309,6 +386,126 @@ $font-weight-semibold: 600;
|
||||
display: block;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// SEARCH & FILTER SECTION
|
||||
// ============================================
|
||||
.search-filter-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-label {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
color: $neutral-600;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.status-filter {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-filter .v-chip {
|
||||
font-size: 12px;
|
||||
font-weight: $font-weight-semibold;
|
||||
height: 32px;
|
||||
border: 1px solid $neutral-500;
|
||||
background: $neutral-100;
|
||||
color: $neutral-600;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: $neutral-300;
|
||||
}
|
||||
}
|
||||
|
||||
.status-filter .v-chip.active-chip {
|
||||
background: $primary-600;
|
||||
color: $neutral-100;
|
||||
border-color: $primary-600;
|
||||
}
|
||||
|
||||
.search-field {
|
||||
max-width: 400px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// DATA TABLE
|
||||
// ============================================
|
||||
.data-table {
|
||||
font-family: $font-family-base;
|
||||
|
||||
:deep(.v-data-table__th) {
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $neutral-800;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
:deep(.v-data-table__td) {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: $neutral-900;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// CHIPS
|
||||
// ============================================
|
||||
.chip-success {
|
||||
background-color: #009262 !important;
|
||||
color: $neutral-100 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.chip-success-outline {
|
||||
border: 1px solid #009262;
|
||||
background-color: transparent !important;
|
||||
color: #009262 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.chip-warning {
|
||||
background-color: #F59E0B !important;
|
||||
color: $neutral-100 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.chip-neutral {
|
||||
background-color: $neutral-600 !important;
|
||||
color: $neutral-100 !important;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// BUTTONS
|
||||
// ============================================
|
||||
.btn-verify {
|
||||
background-color: $primary-600 !important;
|
||||
color: $neutral-100 !important;
|
||||
text-transform: none;
|
||||
font-weight: $font-weight-semibold;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
&:hover {
|
||||
background-color: $primary-700 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// RESPONSIVE
|
||||
// ============================================
|
||||
|
||||
Reference in New Issue
Block a user