215 lines
5.4 KiB
Vue
215 lines
5.4 KiB
Vue
<template>
|
|
<div class="loket-container">
|
|
<!-- Compact Header -->
|
|
<PageHeader
|
|
icon="mdi-view-dashboard"
|
|
title="Admin Loket"
|
|
:subtitle="currentDate"
|
|
:show-add-button="false"
|
|
theme="primary"
|
|
/>
|
|
|
|
<!-- Main Content Grid -->
|
|
<v-row class="content-grid" dense>
|
|
<!-- Left Column: Current Patient & Queue Actions -->
|
|
<v-col cols="12" md="5">
|
|
<!-- Current Patient Card -->
|
|
<CurrentPatientCard
|
|
:patient="currentProcessingPatient"
|
|
@action="handlePatientAction"
|
|
@change-klinik="showChangeKlinikDialog = true"
|
|
/>
|
|
|
|
<!-- Queue Actions Card -->
|
|
<QueueActionsCard
|
|
class="mt-3"
|
|
:total-quota="150"
|
|
:used-quota="quotaUsed"
|
|
:has-next="!!nextPatient"
|
|
@call="handleCall"
|
|
/>
|
|
|
|
<!-- Create Queue Buttons -->
|
|
<div class="create-buttons mt-3">
|
|
<v-btn
|
|
color="primary-600"
|
|
variant="flat"
|
|
block
|
|
size="large"
|
|
class="mb-2"
|
|
@click="showKlinikDialog = true"
|
|
>
|
|
<v-icon start size="20">mdi-hospital-building</v-icon>
|
|
Buat Antrean Klinik
|
|
</v-btn>
|
|
<v-btn
|
|
color="secondary-600"
|
|
variant="flat"
|
|
block
|
|
size="large"
|
|
class="text-white"
|
|
@click="openPenunjangDialog()"
|
|
>
|
|
<v-icon start size="20">mdi-clipboard-pulse</v-icon>
|
|
Buat Antrean Penunjang
|
|
</v-btn>
|
|
</div>
|
|
</v-col>
|
|
|
|
<!-- Right Column: Patient Table -->
|
|
<v-col cols="12" md="7">
|
|
<PatientDataTable
|
|
:items="allPatients"
|
|
v-model:selected-status="selectedStatus"
|
|
v-model:search-query="searchQuery"
|
|
:di-loket-count="(diLoketPatients || []).length"
|
|
:terlambat-count="(terlambatPatients || []).length"
|
|
:pending-count="(pendingPatients || []).length"
|
|
@action="handleTableAction"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Klinik Dialog -->
|
|
<SelectionDialog
|
|
v-model="showKlinikDialog"
|
|
title="Pilih Klinik"
|
|
:items="filteredKliniks"
|
|
v-model:search-query="klinikSearch"
|
|
search-placeholder="Cari klinik..."
|
|
@select="selectKlinik"
|
|
/>
|
|
|
|
<!-- Penunjang Dialog -->
|
|
<SelectionDialog
|
|
v-model="showPenunjangDialog"
|
|
title="Pilih Penunjang"
|
|
:items="filteredPenunjangs"
|
|
v-model:search-query="penunjangSearch"
|
|
search-placeholder="Cari penunjang..."
|
|
@select="selectPenunjang"
|
|
/>
|
|
|
|
<!-- Change Klinik Dialog -->
|
|
<SelectionDialog
|
|
v-model="showChangeKlinikDialog"
|
|
title="Ubah Klinik"
|
|
:items="filteredChangeKliniks"
|
|
v-model:search-query="changeKlinikSearch"
|
|
search-placeholder="Cari klinik..."
|
|
@select="changeKlinik"
|
|
/>
|
|
|
|
<!-- Snackbar -->
|
|
<AppSnackbar
|
|
v-model="snackbar"
|
|
:message="snackbarText"
|
|
:color="snackbarColor"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from "vue";
|
|
import { useQueue } from "@/composables/useQueue";
|
|
import PageHeader from "@/components/common/PageHeader.vue";
|
|
import CurrentPatientCard from "@/components/features/queue/CurrentPatientCard.vue";
|
|
import QueueActionsCard from "@/components/features/queue/QueueActionsCard.vue";
|
|
import PatientDataTable from "@/components/features/queue/TabelPatientData.vue";
|
|
import SelectionDialog from "@/components/common/SelectionDialog.vue";
|
|
import AppSnackbar from "@/components/common/AppSnackbar.vue";
|
|
|
|
const {
|
|
snackbar,
|
|
snackbarText,
|
|
snackbarColor,
|
|
showKlinikDialog,
|
|
showPenunjangDialog,
|
|
showChangeKlinikDialog,
|
|
klinikSearch,
|
|
penunjangSearch,
|
|
changeKlinikSearch,
|
|
currentProcessingPatient,
|
|
diLoketPatients,
|
|
terlambatPatients,
|
|
pendingPatients,
|
|
nextPatient,
|
|
quotaUsed,
|
|
filteredKliniks,
|
|
filteredPenunjangs,
|
|
filteredChangeKliniks,
|
|
callNext,
|
|
callMultiplePatients,
|
|
processPatient,
|
|
selectKlinik,
|
|
selectPenunjang,
|
|
openPenunjangDialog,
|
|
changeKlinik,
|
|
} = useQueue("loket");
|
|
|
|
const currentDate = ref(
|
|
new Date().toLocaleDateString("id-ID", {
|
|
weekday: "long",
|
|
day: "numeric",
|
|
month: "long",
|
|
year: "numeric",
|
|
})
|
|
);
|
|
|
|
const selectedStatus = ref("all");
|
|
const searchQuery = ref("");
|
|
|
|
// Combine all patients with status
|
|
const allPatients = computed(() => {
|
|
const diLoket = (diLoketPatients.value || []).map(p => ({ ...p, status: 'diloket' }));
|
|
const terlambat = (terlambatPatients.value || []).map(p => ({ ...p, status: 'terlambat' }));
|
|
const pending = (pendingPatients.value || []).map(p => ({ ...p, status: 'pending' }));
|
|
|
|
return [...diLoket, ...terlambat, ...pending];
|
|
});
|
|
|
|
const handlePatientAction = (action) => {
|
|
if (currentProcessingPatient.value) {
|
|
processPatient(currentProcessingPatient.value, action);
|
|
}
|
|
};
|
|
|
|
const handleCall = (count) => {
|
|
if (count === 1) {
|
|
callNext();
|
|
} else {
|
|
callMultiplePatients(count);
|
|
}
|
|
};
|
|
|
|
const handleTableAction = (item, action) => {
|
|
processPatient(item, action);
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.loket-container {
|
|
background: var(--color-neutral-300);
|
|
min-height: 100vh;
|
|
padding: 16px;
|
|
}
|
|
|
|
.content-grid {
|
|
margin: 0 -8px;
|
|
}
|
|
|
|
.content-grid > .v-col {
|
|
padding: 8px;
|
|
}
|
|
|
|
.create-buttons .v-btn {
|
|
text-transform: none;
|
|
font-weight: 600;
|
|
}
|
|
|
|
@media (max-width: 960px) {
|
|
.loket-container {
|
|
padding: 12px;
|
|
}
|
|
}
|
|
</style> |