diff --git a/components/features/queue/CurrentPatientCard.vue b/components/features/queue/CurrentPatientCard.vue index 8784b17..1e70028 100644 --- a/components/features/queue/CurrentPatientCard.vue +++ b/components/features/queue/CurrentPatientCard.vue @@ -86,23 +86,6 @@
{{ patient.klinik }} | {{ patient.pembayaran }}
- -
- - mdi-skip-next - Panggil Berikutnya - -
- (Gunakan jika lupa klik Selesai pada pasien ini) -
-
diff --git a/components/features/queue/PatientCard.vue b/components/features/queue/PatientCard.vue index 3ccae8e..5ff70ad 100644 --- a/components/features/queue/PatientCard.vue +++ b/components/features/queue/PatientCard.vue @@ -11,7 +11,7 @@ :class="{ 'clickable-card': isClickable, 'fast-track-card': isFastTrack && !isCurrentlyProcessing, - 'processing-card': isCurrentlyProcessing + 'processing-card': isCurrentlyProcessing || patient.status === 'diproses' }" @click="handleCardClick" v-bind="isClickable ? tooltipProps : {}" diff --git a/pages/AdminLoket/[id].vue b/pages/AdminLoket/[id].vue index c560d94..6ec730b 100644 --- a/pages/AdminLoket/[id].vue +++ b/pages/AdminLoket/[id].vue @@ -221,6 +221,78 @@ + + + + + +
+ + Konfirmasi Ganti Pasien +
+ +
+ + +
+ Ganti Antrean Aktif +
+ +
+ +
+
DARI (AKTIF)
+
+
{{ currentProcessingPatient?.noAntrian?.split(" |")[0] || '-' }}
+
Sedang Diproses
+
+
+ +
+ mdi-chevron-double-right +
+ + +
+
KE (BARU)
+
+
{{ pendingReplaceItem ? pendingReplaceItem.noAntrian.split(" |")[0] : (nextPatient ? nextPatient.noAntrian.split(" |")[0] : 'Berikutnya') }}
+
Siap Diproses
+
+
+
+ +
+ Apakah anda yakin ingin mengganti antrian yang aktif saat ini? +
+
+ + + + + + Batal + + + Ya, Ganti Pasien + + +
+
+ { if (!newValue) { @@ -790,6 +867,11 @@ const handleCall = async (count) => { }; const handleTableAction = async (item, action) => { + if (action === "proses") { + confirmAndProcess(item, action); + return; + } + await processPatient(item, action); // Real-time broadcast after process @@ -805,11 +887,43 @@ const handleTableAction = async (item, action) => { }; const handleProcessNext = () => { - processNextQueue(); - // Real-time broadcast after process next + confirmAndProcess(null, "next"); +}; + +const confirmAndProcess = (item, action) => { + if (currentProcessingPatient.value) { + pendingReplaceItem.value = item; + pendingReplaceAction.value = action; + showConfirmReplaceDialog.value = true; + } else { + executeProcess(item, action); + } +}; + +const executeProcess = async (item, action) => { + if (action === "next") { + processNextQueue(); + } else { + await processPatient(item, action); + // If action is process, auto-call the patient after a short delay + if (action === "proses") { + setTimeout(() => { + handleCallPatient(); + }, 300); + } + } + + // Real-time broadcast after process broadcastUpdate(); }; +const handleConfirmReplace = () => { + executeProcess(pendingReplaceItem.value, pendingReplaceAction.value); + showConfirmReplaceDialog.value = false; + pendingReplaceItem.value = null; + pendingReplaceAction.value = null; +}; + const { sendViaPost } = useWebSocket(); const broadcastUpdate = async (callData = null) => { @@ -1332,6 +1446,101 @@ const buatAntreanKlinikRuang = async (klinikRuang, ruang) => { sans-serif; } +.dialog-header-blue { + background-color: var(--color-primary-600) !important; + color: white !important; +} + +.header-icon-wrapper { + background: rgba(255, 255, 255, 0.2); + padding: 12px; + border-radius: 12px; + backdrop-filter: blur(4px); +} + +.header-title { + font-size: 20px; + font-weight: 700; + line-height: 1.2; +} + +.header-subtitle { + font-size: 13px; + opacity: 0.9; + font-weight: 500; +} + +.dialog-content-premium { + background: var(--color-neutral-100); +} + +.comparison-container { + display: flex; + align-items: center; + gap: 12px; + background: var(--color-neutral-200); + padding: 16px; + border-radius: 16px; + border: 1px solid var(--color-neutral-400); +} + +.comparison-item { + flex: 1; + display: flex; + flex-direction: column; + gap: 8px; +} + +.item-label { + font-size: 10px; + font-weight: 800; + color: var(--color-neutral-600); + letter-spacing: 0.05em; +} + +.item-card { + background: white; + padding: 12px; + border-radius: 12px; + border: 1px solid var(--color-neutral-400); + box-shadow: 0 2px 4px rgba(0,0,0,0.05); + text-align: center; +} + +.item-number { + font-size: 24px; + font-weight: 800; + line-height: 1; + margin-bottom: 4px; + + &.text-danger-700 { + color: var(--color-danger-700) !important; + } + + &.text-primary-600 { + color: var(--color-primary-600) !important; + } +} + +.item-status { + font-size: 11px; + color: var(--color-neutral-700); + font-weight: 600; +} + +.comparison-arrow { + display: flex; + align-items: center; + justify-content: center; +} + +.confirm-text { + font-size: 15px; + color: var(--color-neutral-800); + font-weight: 500; + line-height: 1.5; +} + .headline-5 { font-size: 18px; line-height: 24px;