si-klinik/sk-klinik.my.id/resources/views/livewire/admin/manage-antrean.blade.php

696 lines
36 KiB
PHP

<div class="space-y-6">
{{-- CSS Khusus untuk Print --}}
<style>
@media print {
/* Atur ukuran kertas ke 58mm */
@page {
margin: 0;
size: 58mm auto;
/* Lebar 58mm, tinggi otomatis sesuai konten */
}
body {
width: 58mm;
margin: 0;
padding: 0;
}
/* Pembungkus utama tiket agar pas di 58mm */
#printable-ticket {
width: 100% !important;
padding: 2mm !important;
/* Margin kecil agar tidak mepet fisik printer */
box-sizing: border-box;
}
/* Ukuran font angka antrean untuk 58mm (Jangan terlalu besar agar tidak pecah/offset) */
.queue-number-print {
font-size: 40pt !important;
/* Diperkecil dari 80pt agar muat di 58mm */
line-height: 1 !important;
font-weight: 900 !important;
margin: 10px 0 !important;
}
/* Sembunyikan elemen dashboard */
body>*:not(#ticket-print-wrapper) {
display: none !important;
}
}
</style>
{{-- Header Section --}}
<div
class="flex md:flex-row flex-col md:justify-between md:items-end gap-4 pb-6 border-zinc-100 dark:border-zinc-800 border-b">
<div>
<flux:heading size="xl" class="!font-black uppercase tracking-tight">Kelola Antrean</flux:heading>
<flux:subheading>
<span class="flex items-center gap-2">
<flux:icon.calendar class="size-4" />
{{ \Carbon\Carbon::parse($search_date)->translatedFormat('l, d F Y') }}
</span>
</flux:subheading>
</div>
<div class="flex flex-wrap gap-2">
<flux:button wire:click="openWalkInModal" variant="filled" color="green" icon="user-plus">
Pasien Baru (Walk-in)
</flux:button>
<flux:button wire:click="callNext" variant="primary" icon="chevron-double-right">
Panggil Selanjutnya
</flux:button>
</div>
</div>
{{-- Panel Kontrol & Filter --}}
<div
class="gap-4 grid grid-cols-1 xl:grid-cols-12 bg-zinc-50 dark:bg-zinc-900/40 shadow-sm p-5 border border-zinc-200 dark:border-zinc-800 rounded-2xl">
{{-- Grup 1: Filter Poli/Dokter --}}
<div class="space-y-2 xl:col-span-5">
<flux:label icon="funnel" class="font-bold text-[10px] text-zinc-400 uppercase tracking-widest">Filter Poli
/ Dokter</flux:label>
{{-- Hapus variant="listbox" karena itu fitur Pro --}}
<flux:select wire:model.live="filter_doctor">
<option value="">Semua Dokter (Poli Umum)</option>
@foreach ($doctors as $doc)
<option value="{{ $doc->id }}">{{ $doc->name }}</option>
@endforeach
</flux:select>
</div>
{{-- Grup 2: Panggil Manual --}}
<div class="space-y-2 xl:col-span-3">
<flux:label icon="megaphone" class="font-bold text-[10px] text-zinc-400 uppercase tracking-widest">Panggil
Nomor Manual</flux:label>
<div class="flex gap-2">
<flux:input type="number" wire:model="target_number" placeholder="No." class="w-24" />
<flux:button wire:click="callSpecificNumber" variant="ghost" icon="megaphone" class="flex-1">Panggil
</flux:button>
</div>
</div>
{{-- Grup 3: Filter Tanggal --}}
<div class="space-y-2 xl:col-span-4">
<flux:label icon="calendar" class="font-bold text-[10px] text-zinc-400 uppercase tracking-widest">Ganti
Tanggal Data</flux:label>
<flux:input type="date" wire:model.live="search_date" icon="calendar" />
</div>
</div>
{{-- 1. HERO SECTION: SEKARANG DIPANGGIL --}}
<div class="w-full">
@if ($currentCalling)
<div
class="relative bg-zinc-900 shadow-2xl border border-zinc-800 rounded-3xl overflow-hidden transition-all">
<div class="flex md:flex-row flex-col">
<div class="flex-1 p-8 md:p-12">
<div class="flex items-center gap-3 mb-6">
<span class="relative flex w-3 h-3">
<span
class="inline-flex absolute bg-orange-400 opacity-75 rounded-full w-full h-full animate-ping"></span>
<span class="inline-flex relative bg-orange-500 rounded-full w-3 h-3"></span>
</span>
<flux:badge color="orange" variant="solid"
class="font-bold text-[10px] uppercase tracking-widest">Sedang Dipanggil</flux:badge>
@if ($currentCalling->doctor)
<flux:badge color="blue" variant="flat"
class="font-bold text-[10px] uppercase tracking-wider">
{{ $currentCalling->doctor->name }}
</flux:badge>
@endif
</div>
<h1 class="mb-4 font-black text-white text-5xl md:text-6xl leading-tight tracking-tighter">
{{ $currentCalling->patient->name }}
</h1>
<div
class="flex items-center gap-2 font-medium text-zinc-400 text-sm uppercase tracking-widest">
<flux:icon.building-office class="size-4" />
{{ $currentCalling->serviceCategory->name ?? 'Ruang Pemeriksaan' }}
</div>
<div class="flex flex-wrap gap-4 mt-10">
<flux:button wire:click="recall({{ $currentCalling->id }})" variant="primary" size="sm" icon="arrow-path">
PANGGIL ULANG
</flux:button>
<flux:button wire:click="startMedicalRecord({{ $currentCalling->id }})" variant="danger"
size="sm" icon="check">
SELESAIKAN PEMERIKSAAN
</flux:button>
</div>
</div>
{{-- Box Nomor Antrean Besar --}}
<div class="flex flex-col justify-center items-center bg-blue-600 p-10 md:min-w-[320px]">
<span class="mb-2 font-bold text-blue-100 text-xs uppercase tracking-[0.3em]">No. Antrean</span>
<span class="font-black tabular-nums text-[10rem] text-white leading-none tracking-tighter">
{{ str_pad($currentCalling->queue_number, 2, '0', STR_PAD_LEFT) }}
</span>
</div>
</div>
</div>
@else
<div
class="flex flex-col justify-center items-center bg-zinc-50/50 dark:bg-zinc-900/20 py-20 border-2 border-zinc-200 dark:border-zinc-800 border-dashed rounded-3xl">
<div class="bg-zinc-100 dark:bg-zinc-800 shadow-inner mb-4 p-5 rounded-full">
<flux:icon.megaphone class="size-10 text-zinc-300" />
</div>
<flux:heading class="text-zinc-400">Belum Ada Pasien Yang Dipanggil</flux:heading>
<flux:subheading>Silakan klik "Panggil Selanjutnya" atau pilih pasien di tabel bawah.</flux:subheading>
</div>
@endif
</div>
{{-- 2. STATS SECTION --}}
<div class="gap-4 grid grid-cols-1 md:grid-cols-3">
<flux:card class="flex items-center gap-4 bg-white dark:bg-zinc-900 shadow-sm py-5 border-none">
<div class="bg-blue-50 dark:bg-blue-900/20 shadow-sm p-3 rounded-xl text-blue-600">
<flux:icon.users class="size-6" />
</div>
<div>
<p class="font-bold text-[10px] text-zinc-400 uppercase tracking-widest">Total Antrean</p>
<p class="mt-1 font-black tabular-nums text-3xl leading-none">{{ $stats['total'] }}</p>
</div>
</flux:card>
<flux:card
class="flex items-center gap-4 bg-white dark:bg-zinc-900 shadow-sm py-5 border-l-4 border-l-yellow-400 border-none">
<div class="bg-yellow-50 dark:bg-yellow-900/20 shadow-sm p-3 rounded-xl text-yellow-600">
<flux:icon.clock class="size-6" />
</div>
<div>
<p class="font-bold text-[10px] text-zinc-400 uppercase tracking-widest">Menunggu</p>
<p class="mt-1 font-black tabular-nums text-3xl leading-none">{{ $stats['waiting'] }}</p>
</div>
</flux:card>
<flux:card
class="flex items-center gap-4 bg-white dark:bg-zinc-900 shadow-sm py-5 border-l-4 border-l-green-500 border-none">
<div class="bg-green-50 dark:bg-green-900/20 shadow-sm p-3 rounded-xl text-green-600">
<flux:icon.check-circle class="size-6" />
</div>
<div>
<p class="font-bold text-[10px] text-zinc-400 uppercase tracking-widest">Selesai</p>
<p class="mt-1 font-black tabular-nums text-green-600 text-3xl leading-none">{{ $stats['finished'] }}
</p>
</div>
</flux:card>
</div>
{{-- 3. TABLE SECTION DENGAN TAB --}}
<flux:card class="bg-white dark:bg-zinc-900 shadow-sm !p-0 border-zinc-200 dark:border-zinc-800 overflow-hidden">
<div class="flex md:flex-row flex-col justify-between md:items-center gap-4 px-6 pt-6">
<div x-data="{ tab: @entangle('current_tab') }" class="flex bg-zinc-100 dark:bg-zinc-800 p-1 rounded-lg w-fit">
<!-- Tombol Aktif -->
<button @click="tab = 'active'; $wire.set('current_tab', 'active')"
:class="tab === 'active' ? 'bg-white dark:bg-zinc-700 shadow-sm text-zinc-900 dark:text-white' : 'text-zinc-500 hover:text-zinc-700'"
class="flex items-center gap-2 px-4 py-1.5 rounded-md font-medium text-sm transition-all">
<flux:icon.clock class="size-4" />
Aktif
</button>
<!-- Tombol Selesai -->
<button @click="tab = 'finished'; $wire.set('current_tab', 'finished')"
:class="tab === 'finished' ? 'bg-white dark:bg-zinc-700 shadow-sm text-zinc-900 dark:text-white' : 'text-zinc-500 hover:text-zinc-700'"
class="flex items-center gap-2 px-4 py-1.5 rounded-md font-medium text-sm transition-all">
<flux:icon.check-circle class="size-4" />
Selesai
</button>
<!-- Tombol Batal -->
<button @click="tab = 'cancelled'; $wire.set('current_tab', 'cancelled')"
:class="tab === 'cancelled' ? 'bg-white dark:bg-zinc-700 shadow-sm text-zinc-900 dark:text-white' : 'text-zinc-500 hover:text-zinc-700'"
class="flex items-center gap-2 px-4 py-1.5 rounded-md font-medium text-sm transition-all">
<flux:icon.x-circle class="size-4" />
Batal
</button>
</div>
<div class="text-zinc-400 text-xs italic">
Menampilkan antrean pada hari terpilih
</div>
</div>
<flux:table class="mt-4">
<flux:table.columns>
<flux:table.column class="w-20">No</flux:table.column>
<flux:table.column>Pasien</flux:table.column>
<flux:table.column class="hidden lg:table-cell">Dokter & Poli</flux:table.column>
<flux:table.column class="hidden md:table-cell">Keluhan</flux:table.column>
<flux:table.column>Status</flux:table.column>
<flux:table.column align="end">Aksi</flux:table.column>
</flux:table.columns>
<flux:table.rows>
@forelse ($appointments as $app)
<flux:table.row :key="$app->id"
class="{{ $app->status === 'calling' ? 'bg-blue-50/40 dark:bg-blue-900/10' : '' }}">
<flux:table.cell>
<span
class="text-2xl font-black tracking-tighter tabular-nums {{ $app->status === 'calling' ? 'text-blue-600' : 'text-zinc-400' }}">
{{ str_pad($app->queue_number, 2, '0', STR_PAD_LEFT) }}
</span>
</flux:table.cell>
<flux:table.cell>
<div class="font-bold text-zinc-900 dark:text-white leading-tight">
{{ $app->patient->name }}</div>
<div
class="flex items-center gap-1 mt-1 font-semibold text-[10px] text-zinc-400 uppercase">
<flux:icon.clock class="size-3" />
{{ $app->created_at->format('H:i') }} WIB
</div>
</flux:table.cell>
<flux:table.cell class="hidden lg:table-cell">
<div class="font-bold text-zinc-800 dark:text-zinc-200 text-xs">
{{ $app->doctor->name ?? '-' }}</div>
<div class="font-medium text-[10px] text-zinc-500 uppercase">
{{ $app->serviceCategory->name ?? '-' }}</div>
</flux:table.cell>
<flux:table.cell class="hidden md:table-cell">
<p class="max-w-[180px] text-zinc-500 text-xs truncate italic">
"{{ $app->notes ?? '-' }}"
</p>
</flux:table.cell>
<flux:table.cell>
@php
$statusInfo = match ($app->status) {
'waiting' => ['color' => 'yellow', 'label' => 'MENUNGGU'],
'calling' => ['color' => 'orange', 'label' => 'DIPANGGIL'],
'skipped' => ['color' => 'red', 'label' => 'TERLAMBAT'],
'finished' => ['color' => 'green', 'label' => 'SELESAI'],
'cancelled' => ['color' => 'zinc', 'label' => 'BATAL'],
default => ['color' => 'zinc', 'label' => strtoupper($app->status)],
};
@endphp
<flux:badge size="sm" :color="$statusInfo['color']" variant="flat"
class="font-black text-[9px] tracking-widest">
{{ $statusInfo['label'] }}
</flux:badge>
</flux:table.cell>
<flux:table.cell align="end">
<div class="flex justify-end gap-1">
@if ($app->status == 'waiting' || $app->status == 'skipped')
<flux:button wire:click="updateStatus({{ $app->id }}, 'calling')"
icon="megaphone" size="sm" variant="ghost" tooltip="Panggil" />
@endif
@if ($app->status == 'calling')
<flux:button wire:click="recall({{ $app->id }})" icon="arrow-path"
size="sm" variant="ghost" class="text-orange-500"
tooltip="Panggil Ulang" />
<flux:button wire:click="startMedicalRecord({{ $app->id }})" icon="check"
size="sm" variant="ghost" class="text-green-600" tooltip="Selesai" />
@endif
<flux:dropdown>
<flux:button variant="ghost" size="sm" icon="ellipsis-horizontal" />
<flux:menu>
<flux:menu.item wire:click="showTicketModal({{ $app->id }})"
icon="printer">Lihat / Cetak Tiket</flux:menu.item>
<flux:menu.item wire:click="undoStatus({{ $app->id }})"
icon="arrow-uturn-left">Kembalikan ke Status Tunggu</flux:menu.item>
<flux:menu.item wire:click="skipAndNext({{ $app->id }})" icon="forward">
Lewati (Panggil Berikutnya)</flux:menu.item>
<flux:menu.separator />
<flux:menu.item wire:click="updateStatus({{ $app->id }}, 'cancelled')"
icon="x-mark" variant="danger">Batalkan Antrean</flux:menu.item>
</flux:menu>
</flux:dropdown>
</div>
</flux:table.cell>
</flux:table.row>
@empty
<flux:table.row>
<flux:table.cell colspan="6" class="py-16 text-zinc-400 text-center">
Tidak ada data antrean pada kategori ini.
</flux:table.cell>
</flux:table.row>
@endforelse
</flux:table.rows>
</flux:table>
<div class="bg-zinc-50/50 dark:bg-zinc-900/50 p-4 border-zinc-100 dark:border-zinc-800 border-t">
{{ $appointments->links() }}
</div>
</flux:card>
{{-- MODAL TIKET DIGITAL --}}
<flux:modal name="ticket-modal" class="!p-0 max-w-sm overflow-hidden">
@if ($selectedAppointment)
<div id="ticket-print-wrapper"> {{-- Pembungkus Tambahan --}}
<div id="printable-ticket" class="bg-white text-zinc-900">
{{-- Bagian Header Tiket --}}
<div class="bg-black p-6 text-white text-center">
<div class="font-black text-xl tracking-tighter">ANTREAN</div>
<p class="text-[10px] uppercase">{{ $site->name }}</p>
</div>
<div class="p-10 border-zinc-200 border-b-2 border-dashed text-center">
<span class="font-bold text-zinc-500 text-xs uppercase">Nomor Antrean</span>
<div class="queue-number-print">
{{ str_pad($selectedAppointment->queue_number, 2, '0', STR_PAD_LEFT) }}
</div>
<div class="inline-block bg-zinc-100 px-4 py-1 rounded-full font-black text-[10px] uppercase">
{{ $selectedAppointment->serviceCategory->name ?? 'UMUM' }}
</div>
</div>
<div class="space-y-2 p-8 text-sm">
<div class="flex justify-between">
<span class="text-zinc-500">Pasien:</span>
<span class="font-bold">{{ $selectedAppointment->patient->name }}</span>
</div>
<div class="flex justify-between">
<span class="text-zinc-500">Poli:</span>
<span class="font-bold">{{ $selectedAppointment->doctor->name ?? '-' }}</span>
</div>
</div>
</div>
</div>
{{-- Footer Modal (Akan otomatis hilang karena CSS print di atas) --}}
<div class="flex gap-2 bg-zinc-50 p-4 border-t no-print">
<flux:button variant="ghost" class="flex-1" x-on:click="Flux.modal('ticket-modal').close()">Tutup
</flux:button>
<flux:button variant="primary" icon="printer" class="flex-1 font-bold" onclick="printTicket()">
Cetak Tiket
</flux:button>
</div>
@endif
</flux:modal>
{{-- MODAL WALK-IN (Pendaftaran Baru) --}}
<flux:modal name="walkin-modal" class="md:min-w-[500px]">
<div class="space-y-6">
<div>
<flux:heading size="sm" class="!font-black">Pendaftaran Pasien Walk-in</flux:heading>
<flux:subheading>Daftarkan pasien yang datang langsung tanpa janji temu sebelumnya.</flux:subheading>
</div>
<div class="gap-4 grid">
{{-- Pilih Pasien --}}
<div class="space-y-2">
<flux:label>Cari & Pilih Pasien</flux:label>
{{-- Input untuk mengetik nama/NIK --}}
<flux:input wire:model.live.debounce.500ms="search_patient_name" icon="magnifying-glass"
placeholder="Ketik Nama atau NIK pasien..." />
{{-- Dropdown yang isinya terfilter otomatis --}}
<flux:select wire:model="walkin_patient_id" label="Pilih Pasien">
<option value="">-- Pilih Pasien Berdasarkan Nama/NIK --</option>
@foreach ($patients as $user)
<option value="{{ $user->patient->id }}">
{{ $user->name }} | NIK: {{ $user->patient->nik }}
</option>
@endforeach
</flux:select>
@if ($search_patient_name)
<div class="font-medium text-[10px] text-blue-600 italic">
Menampilkan hasil pencarian untuk: "{{ $search_patient_name }}"
</div>
@endif
@error('walkin_patient_id')
<span class="text-red-500 text-xs">{{ $message }}</span>
@enderror
</div>
<div class="gap-4 grid grid-cols-1 md:grid-cols-2">
{{-- Pilih Dokter --}}
<flux:select wire:model="walkin_doctor_id" label="Dokter Spesialis / Umum">
<flux:select.option value="">Pilih Dokter</flux:select.option>
@foreach ($doctors as $doc)
<flux:select.option value="{{ $doc->id }}">{{ $doc->name }}</flux:select.option>
@endforeach
</flux:select>
{{-- Pilih Poli --}}
<flux:select wire:model="walkin_service_id" label="Poli / Layanan">
<flux:select.option value="">Pilih Layanan</flux:select.option>
@foreach ($services as $service)
<flux:select.option value="{{ $service->id }}">{{ $service->name }}</flux:select.option>
@endforeach
</flux:select>
</div>
<flux:textarea wire:model="walkin_notes" label="Keluhan Utama / Catatan Medis Singkat"
placeholder="Misal: Demam tinggi sejak tadi malam..." rows="3" />
</div>
<div class="flex justify-end gap-2 pt-4 border-zinc-100 dark:border-zinc-800 border-t">
<flux:button variant="ghost" class="font-bold" x-on:click="Flux.modal('walkin-modal').close()">
Batalkan</flux:button>
<flux:button wire:click="saveWalkIn" variant="primary" class="px-6 font-bold">Daftarkan & Cetak
Antrean</flux:button>
</div>
</div>
</flux:modal>
{{-- MODAL REKAM MEDIS (FORM PEMERIKSAAN DOKTER) --}}
<flux:modal name="medical-record-modal" class="md:min-w-[600px]">
<div class="space-y-6">
<div>
<flux:heading size="lg" class="!font-black text-emerald-600 dark:text-emerald-400 uppercase">Input Rekam Medis Pasien</flux:heading>
<flux:subheading>Masukkan catatan klinis dan diagnosa sebelum menyelesaikan pemeriksaan.</flux:subheading>
</div>
@if ($currentExamining)
<div class="gap-4 grid">
{{-- Ringkasan Pendaftaran Pasien --}}
<div class="space-y-1 bg-zinc-50 dark:bg-zinc-800/50 p-4 border border-zinc-200 dark:border-zinc-700 rounded-xl text-sm">
<div><span class="text-zinc-400">Nama Pasien:</span> <strong class="text-zinc-800 dark:text-zinc-200">{{ $currentExamining->patient->name }}</strong></div>
<div><span class="text-zinc-400">Poli / Dokter:</span> <span class="font-medium">{{ $currentExamining->serviceCategory->name ?? '-' }} / {{ $currentExamining->doctor->name ?? '-' }}</span></div>
<div><span class="text-zinc-400">Keluhan Awal Pendaftaran:</span> <span class="text-zinc-500 italic">"{{ $currentExamining->notes ?? 'Tidak ada' }}"</span></div>
</div>
{{-- Inputs Rekam Medis --}}
<flux:textarea wire:model="symptoms" label="Keluhan Utama / Hasil Anamnesis Pasien (Symptoms)" placeholder="Masukkan keluhan fisik aktual pasien saat diperiksa..." rows="3" required />
<flux:input wire:model="diagnosis" label="Hasil Diagnosa Penyakit (Diagnosis)" placeholder="Contoh: Gastritis Akut / ISPA" required />
<flux:textarea wire:model="treatment" label="Tindakan Medis / Resep Obat (Treatment)" placeholder="Contoh: Paracetamol 500mg 3x1, Omeprazole 20mg 2x1 sebelum makan" rows="3" />
<flux:textarea wire:model="doctor_notes" label="Catatan Tambahan Dokter" placeholder="Contoh: Kurangi makanan pedas dan kopi, kontrol kembali jika 3 hari belum membaik." rows="2" />
</div>
@endif
<div class="flex justify-end gap-2 pt-4 border-zinc-100 dark:border-zinc-800 border-t">
<flux:button variant="ghost" class="font-bold" x-on:click="Flux.modal('medical-record-modal').close()">Kembali</flux:button>
<flux:button wire:click="saveMedicalRecord" variant="primary" color="green" class="px-6 font-bold" icon="check">Simpan & Selesaikan Pemeriksaan</flux:button>
</div>
</div>
</flux:modal>
@script
<script>
// 1. Logic Suara (Text-to-Speech)
window.addEventListener('play-calling-sound', event => {
window.speechSynthesis.cancel();
const text =
`Nomor antrean ${event.detail.number}. Atas nama ${event.detail.name}. Harap menuju ${event.detail.poli}.`;
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'id-ID';
utterance.rate = 0.85;
utterance.pitch = 1.0;
window.speechSynthesis.speak(utterance);
});
// 2. Fungsi Cetak dari Modal (Manual)
window.printTicket = function() {
const ticketElement = document.getElementById('printable-ticket');
if (!ticketElement) return;
const ticketContent = ticketElement.innerHTML;
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
const doc = iframe.contentWindow.document;
doc.open();
doc.write(`
<html>
<head>
<style>
/* Reset Dasar */
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
box-sizing: border-box;
}
body {
font-family: 'Courier New', Courier, monospace; /* Font struk klasik lebih terbaca */
margin: 0;
padding: 0;
width: 48mm; /* Area cetak efektif printer 58mm biasanya 48mm */
}
@page { margin: 0; size: 58mm auto; }
/* Styling konten agar rapat */
.text-center { text-align: center; }
.font-black { font-weight: 900; }
.text-xl { font-size: 14pt; }
.queue-number-print { font-size: 45pt; margin: 5px 0; }
.border-dashed { border-bottom: 1px dashed #000; padding-bottom: 5px; margin-bottom: 5px; }
</style>
</head>
<body>
<div style="width: 100%; padding: 5px;">
${ticketContent}
</div>
<script>
window.onload = function() {
window.print();
setTimeout(() => { window.frameElement.remove(); }, 100);
}
<\/script>
</body>
</html>
`);
doc.close();
}
// 3. Logic Cetak Otomatis Setelah Simpan (Walk-in)
window.addEventListener('print-after-save', event => {
// SEBELUMNYA: const data = event.detail;
// UBAH MENJADI: Ambil isi property 'data' yang dikirim dari backend
const data = event.detail.data;
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
const doc = iframe.contentWindow.document;
doc.open();
doc.write(`
<html>
<head>
<title>Cetak Antrean</title>
<style>
/* Reset untuk Printer Thermal */
* {
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
box-sizing: border-box;
color: black !important;
}
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
width: 58mm; /* Ukuran kertas fisik */
}
@page {
margin: 0;
size: 58mm auto;
}
/* Container Utama (Area Cetak +/- 48mm) */
.ticket-container {
width: 100%;
padding: 5px;
text-align: center;
}
/* Header Hitam */
.header {
background: black !important;
color: white !important;
padding: 10px 5px;
border-radius: 4px;
margin-bottom: 10px;
}
.header h1 { margin: 0; font-size: 16pt; letter-spacing: 2px; }
.header p { margin: 0; font-size: 7pt; text-transform: uppercase; }
/* Nomor Antrean */
.label-no { font-size: 8pt; font-weight: bold; text-transform: uppercase; color: #666; }
.number { font-size: 50pt; font-weight: 900; margin: 5px 0; line-height: 1; }
/* Poli / Layanan */
.service-badge {
display: inline-block;
border: 1px solid black;
padding: 2px 8px;
border-radius: 10px;
font-size: 9pt;
font-weight: bold;
margin-bottom: 15px;
}
/* Detail Pasien */
.details {
border-top: 1px dashed black;
padding-top: 8px;
font-size: 9pt;
text-align: left;
}
.row { display: flex; justify-content: space-between; margin-bottom: 4px; }
.row span:first-child { color: #333; }
.row span:last-child { font-weight: bold; text-align: right; }
.footer {
margin-top: 15px;
font-size: 7pt;
font-style: italic;
line-height: 1.2;
}
</style>
</head>
<body>
<div class="ticket-container">
<div class="header">
<h1>ANTREAN</h1>
<p>{{ $site->name }}</p>
</div>
<div class="label-no">Nomor Antrean</div>
<div class="number">\${data.number}</div>
<div class="service-badge">\${data.poli}</div>
<div class="details">
<div class="row">
<span>PASIEN</span>
<span>\${data.name}</span>
</div>
<div class="row">
<span>DOKTER</span>
<span>\${data.doctor}</span>
</div>
<div class="row">
<span>WAKTU</span>
<span>\${data.date}</span>
</div>
</div>
<div class="footer">
"Mohon simpan tiket ini dan tunggu hingga nomor Anda dipanggil."
</div>
</div>
<script>
window.onload = function() {
setTimeout(() => {
window.print();
window.frameElement.remove();
}, 300);
};
<\/script>
</body>
</html>
`);
doc.close();
});
</script>
@endscript
</div>