From 27209def4b2856ba6ca06bc0eef7bc309bc55108 Mon Sep 17 00:00:00 2001 From: bagus-arie05 Date: Mon, 12 Jan 2026 08:51:12 +0700 Subject: [PATCH] update klinik ruang dan status fast track --- components/features/queue/PatientCard.vue | 22 +- pages/AdminKlinikRuang/[kodeKlinik].vue | 324 +++++++++++++++------- pages/AdminLoket.vue | 8 +- 3 files changed, 246 insertions(+), 108 deletions(-) diff --git a/components/features/queue/PatientCard.vue b/components/features/queue/PatientCard.vue index 7c0f7c6..ec5724d 100644 --- a/components/features/queue/PatientCard.vue +++ b/components/features/queue/PatientCard.vue @@ -8,7 +8,10 @@ @@ -18,7 +21,7 @@
{{ patient.noAntrian.split(" |")[0] }}
{ return props.patient.status === 'diloket' || props.patient.status === 'pending'; }); +const isFastTrack = computed(() => { + const fastTrack = (props.patient.fastTrack ?? "").toString().trim().toUpperCase(); + return fastTrack === 'YA'; +}); + const handleCardClick = () => { if (isClickable.value) { emit('action', props.patient, 'proses'); @@ -161,6 +169,16 @@ const getStatusLabel = (status) => { transform: translateY(0); } } + + &.fast-track-card { + background: rgba(255, 230, 198, 0.35) !important; + border-color: rgba(255, 185, 95, 0.4); + + &:hover { + background: rgba(255, 230, 198, 0.45) !important; + border-color: rgba(255, 185, 95, 0.5); + } + } } .card-header { diff --git a/pages/AdminKlinikRuang/[kodeKlinik].vue b/pages/AdminKlinikRuang/[kodeKlinik].vue index d65d0c2..93470a8 100644 --- a/pages/AdminKlinikRuang/[kodeKlinik].vue +++ b/pages/AdminKlinikRuang/[kodeKlinik].vue @@ -38,16 +38,6 @@
- - mdi-bullhorn - Panggil Pemeriksaan Awal - -
- {{ patient.noAntrian?.split(" |")[0] || patient.barcode || '-' }} + +
+
+ {{ patient.noAntrian?.split(" |")[0] || patient.barcode || '-' }} +
+
+ + + mdi-check-circle + P.Awal + + + mdi-check-circle + Tindakan + +
-
- - - mdi-check-circle - Pemeriksaan Awal - - - - mdi-check-circle - Tindakan - - - - mdi-pause-circle - Pending - -
-
- - mdi-eye - Lihat Detail - - - mdi-swap-horizontal - Pindah Ruang - - - mdi-play - Proses - + + +
+ +
+ + mdi-eye + Lihat Detail + + + mdi-swap-horizontal + Pindah Ruang + + + mdi-bullhorn + Pemeriksaan Awal + + + mdi-play + Proses + +
@@ -602,15 +599,31 @@ const confirmPindahRuang = () => { selectedRuangBaru.value = null; }; -const handleCallPatientByTipe = (ruang, tipeLayanan) => { - const current = getCurrentProcessingForRoom(ruang); - if (!current || !current.no) { - showSnackbar('Tidak ada pasien yang sedang diproses', 'error'); +// Handle call patient from list (dari card pasien di daftar) +const handleCallPatientFromList = (ruang, patient, tipeLayanan) => { + if (!patient || !patient.no) { + showSnackbar('Pasien tidak valid', 'error'); return; } + // Pastikan pasien sudah diproses terlebih dahulu + const current = getCurrentProcessingForRoom(ruang); + if (!current || current.no !== patient.no) { + // Jika pasien belum diproses, proses dulu + const processResult = queueStore.processPatientKlinikRuang( + patient, + 'proses', + klinikData.value.kodeKlinik, + ruang.nomorRuang + ); + if (!processResult.success) { + showSnackbar(processResult.message, 'error'); + return; + } + } + // Update tipeLayanan pasien untuk tracking panggilan terakhir - const patientIndex = queueStore.allPatients.findIndex(p => p.no === current.no); + const patientIndex = queueStore.allPatients.findIndex(p => p.no === patient.no); if (patientIndex === -1) { showSnackbar('Pasien tidak ditemukan', 'error'); return; @@ -737,6 +750,50 @@ const getStatusLabel = (status) => { }; +// Handle call patient by tipe (untuk pasien yang sedang diproses) +const handleCallPatientByTipe = (ruang, tipeLayanan) => { + const current = getCurrentProcessingForRoom(ruang); + if (!current || !current.no) { + showSnackbar('Tidak ada pasien yang sedang diproses', 'error'); + return; + } + + // Update tipeLayanan pasien untuk tracking panggilan terakhir + const patientIndex = queueStore.allPatients.findIndex(p => p.no === current.no); + if (patientIndex === -1) { + showSnackbar('Pasien tidak ditemukan', 'error'); + return; + } + + // Update tracking panggilan berdasarkan tipeLayanan + // Update tipeLayanan pasien agar muncul di kolom yang sesuai di Anjungan + const updateData = { + ...queueStore.allPatients[patientIndex], + status: 'di-loket', + tipeLayanan: tipeLayanan, // Update tipeLayanan untuk display di Anjungan + lastCalledAt: new Date().toISOString(), + lastCalledTipeLayanan: tipeLayanan + }; + + // Set penanda panggilan sesuai tipeLayanan + if (tipeLayanan === 'Pemeriksaan Awal') { + updateData.calledPemeriksaanAwal = true; + } else if (tipeLayanan === 'Tindakan') { + updateData.calledTindakan = true; + } + + queueStore.allPatients[patientIndex] = updateData; + + // Update current processing (tetap 1 pasien, tidak dipisah per tipe) + const key = `klinik-ruang-${klinikData.value.kodeKlinik}-${ruang.nomorRuang}`; + queueStore.currentProcessingPatient[key] = queueStore.allPatients[patientIndex]; + + const patientCode = queueStore.allPatients[patientIndex].noAntrian?.split(" |")[0] || + queueStore.allPatients[patientIndex].barcode || + '-'; + showSnackbar(`Memanggil pasien ${patientCode} untuk ${tipeLayanan}`, 'success'); +}; + const handlePatientAction = (ruang, action) => { const current = getCurrentProcessingForRoom(ruang); if (!current) return; @@ -822,12 +879,16 @@ const paginatedAllPatients = (ruang) => { // Helper untuk menentukan class card berdasarkan status pasien const getPatientCardClass = (patient) => { const baseClass = 'patient-queue-item'; - // Pasien yang sudah digenerate/diproses & pending: warna berbeda - if (patient.tipeLayanan || patient.status === 'pending') { + // Pasien dengan status pending: warna merah + if (patient.status === 'pending') { + return `${baseClass} patient-queue-item-pending-status`; + } + // Pasien yang sudah digenerate/diproses: warna berbeda + if (patient.tipeLayanan || patient.calledPemeriksaanAwal || patient.calledTindakan) { return `${baseClass} patient-queue-item-processed`; } // Pasien yang perlu digenerate: warna default - return `${baseClass} patient-queue-item-pending`; + return `${baseClass} patient-queue-item-default`; }; @@ -1188,57 +1249,122 @@ onMounted(() => { display: flex; justify-content: space-between; align-items: center; - padding: 8px 12px; - border-radius: 6px; + padding: 10px 14px; + border-radius: 8px; transition: all 0.2s ease; - gap: 8px; + gap: 12px; + min-height: 56px; } -/* Pasien yang sudah digenerate/diproses & pending */ +/* Pasien dengan status pending: warna merah */ +.patient-queue-item-pending-status { + background: linear-gradient(135deg, #ffebee 0%, #ffcdd2 100%); + border: 2px solid #ef5350; +} + +.patient-queue-item-pending-status:hover { + background: linear-gradient(135deg, #ffcdd2 0%, #ef9a9a 100%); + border-color: #e53935; +} + +/* Pasien yang sudah digenerate/diproses */ .patient-queue-item-processed { - background: var(--color-primary-50); - border: 1px solid var(--color-primary-200); + background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%); + border: 1px solid #90caf9; } .patient-queue-item-processed:hover { - background: var(--color-primary-100); - border-color: var(--color-primary-400); + background: linear-gradient(135deg, #bbdefb 0%, #90caf9 100%); + border-color: #64b5f6; } -/* Pasien yang perlu digenerate */ -.patient-queue-item-pending { +/* Pasien default */ +.patient-queue-item-default { background: var(--color-neutral-100); border: 1px solid var(--color-neutral-300); } -.patient-queue-item-pending:hover { - background: var(--color-warning-100); - border-color: var(--color-warning-400); +.patient-queue-item-default:hover { + background: var(--color-neutral-200); + border-color: var(--color-neutral-400); +} + +/* Left Section: Number and Status */ +.patient-card-left { + display: flex; + flex-direction: column; + gap: 6px; + min-width: 100px; + flex-shrink: 0; } .patient-queue-number { - font-size: 14px; + font-size: 15px; font-weight: 700; color: var(--color-neutral-900); - min-width: 80px; + line-height: 1.2; } -.patient-queue-info { +.patient-queue-status-chips { display: flex; gap: 4px; align-items: center; + flex-wrap: wrap; +} + +.status-chip { + font-size: 10px !important; + height: 18px !important; + padding: 0 6px !important; +} + +.status-chip .v-icon { + font-size: 10px !important; + margin-right: 2px; +} + +/* Right Section: Actions */ +.patient-card-right { + display: flex; + align-items: center; flex: 1; + justify-content: flex-end; + min-width: 0; } .patient-queue-actions { display: flex; - gap: 8px; + gap: 6px; align-items: center; + flex-wrap: nowrap; } .patient-queue-actions .v-btn { text-transform: none; font-weight: 600; + flex-shrink: 0; +} + +.call-btn { + min-width: 130px; + font-size: 11px; + white-space: nowrap; +} + +.call-btn .v-icon { + margin-right: 4px; +} + +/* Responsive untuk card */ +@media (max-width: 1400px) { + .call-btn { + min-width: 100px; + font-size: 10px; + } + + .call-btn .v-icon { + margin-right: 2px; + } } @media (max-width: 1400px) { diff --git a/pages/AdminLoket.vue b/pages/AdminLoket.vue index 0eeadd5..24026a3 100644 --- a/pages/AdminLoket.vue +++ b/pages/AdminLoket.vue @@ -514,15 +514,11 @@ const buatAntreanKlinikRuang = async (klinikRuang, ruang) => { } .content-grid { - margin: 0; - width: 100%; - box-sizing: border-box; + margin: 0 -8px; } .content-grid > .v-col { padding: 8px; - box-sizing: border-box; - min-width: 0; /* Prevent flex item overflow */ } .content-grid > .v-col:first-child { @@ -570,8 +566,6 @@ const buatAntreanKlinikRuang = async (klinikRuang, ruang) => { position: sticky; top: 16px; align-self: flex-start; - max-height: calc(100vh - 32px); - overflow-y: auto; } .filters {