fixing layar loket dan status pasien
This commit is contained in:
No files matched your search
@@ -20,11 +20,11 @@
|
||||
</div>
|
||||
|
||||
<!-- Hero Section - Sedang Dipanggil -->
|
||||
<div v-if="currentCalledQueue" class="hero-queue">
|
||||
<div v-if="currentCalledQueue" class="hero-queue" :class="{ 'hero-pending': currentCalledQueue.status === 'pending' }">
|
||||
<div class="hero-content">
|
||||
<div class="hero-label">
|
||||
<v-icon size="32" color="white">mdi-bell-ring</v-icon>
|
||||
SEDANG DIPANGGIL
|
||||
{{ currentCalledQueue.status === 'pending' ? 'PENDING' : 'SEDANG DIPANGGIL' }}
|
||||
</div>
|
||||
<div class="hero-number">
|
||||
{{ currentCalledQueue.noAntrian.split(" |")[0] }}
|
||||
@@ -56,8 +56,10 @@
|
||||
<div class="queue-display">
|
||||
<!-- Current Queue -->
|
||||
<div v-if="clinic.currentQueue" class="current-queue-section">
|
||||
<div class="queue-status-label">SEKARANG</div>
|
||||
<div class="queue-number-large">
|
||||
<div class="queue-status-label" :class="{ 'status-pending': clinic.currentQueue.status === 'pending' }">
|
||||
{{ clinic.currentQueue.status === 'pending' ? 'PENDING' : 'SEKARANG' }}
|
||||
</div>
|
||||
<div class="queue-number-large" :class="{ 'queue-pending': clinic.currentQueue.status === 'pending' }">
|
||||
{{ clinic.currentQueue.noAntrian.split(" |")[0] }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,6 +72,7 @@
|
||||
v-for="queue in clinic.nextQueues.slice(0, 3)"
|
||||
:key="queue.no"
|
||||
class="next-number-badge"
|
||||
:class="{ 'badge-pending': queue.status === 'pending' }"
|
||||
>
|
||||
{{ queue.noAntrian.split(" |")[0] }}
|
||||
</div>
|
||||
@@ -84,6 +87,20 @@
|
||||
<v-icon size="40" color="grey-lighten-3">mdi-minus-circle-outline</v-icon>
|
||||
<div class="empty-text">Tidak Ada Antrian</div>
|
||||
</div>
|
||||
|
||||
<!-- Pending Queues (jika ada yang pending tapi tidak di current atau next) -->
|
||||
<div v-if="clinic.pendingQueues && clinic.pendingQueues.length > 0" class="pending-queues-section">
|
||||
<div class="pending-label">PENDING</div>
|
||||
<div class="pending-numbers-grid">
|
||||
<div
|
||||
v-for="queue in clinic.pendingQueues"
|
||||
:key="queue.no"
|
||||
class="pending-number-badge"
|
||||
>
|
||||
{{ queue.noAntrian.split(" |")[0] }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -176,7 +193,24 @@ let timeInterval = null;
|
||||
let refreshInterval = null;
|
||||
|
||||
const klinikPatients = computed(() => {
|
||||
return queueStore.getPatientsByStage("klinik").value.all;
|
||||
// Ambil pasien dengan processStage "klinik" (sudah check-in di loket)
|
||||
const klinikStagePatients = queueStore.getPatientsByStage("klinik").value.all;
|
||||
|
||||
// Juga ambil pasien dengan status "pending" yang processStage-nya masih "loket"
|
||||
// Ini adalah pasien yang di-pending di AdminLoket dan harus kembali ke kolom klinik
|
||||
const pendingFromLoket = queueStore.getPatientsByStage("loket").value.all
|
||||
.filter(p => p.status === "pending");
|
||||
|
||||
// Gabungkan dan pastikan tidak ada duplikat
|
||||
const allPatients = [...klinikStagePatients];
|
||||
pendingFromLoket.forEach(pendingPatient => {
|
||||
const exists = allPatients.find(p => p.no === pendingPatient.no);
|
||||
if (!exists) {
|
||||
allPatients.push(pendingPatient);
|
||||
}
|
||||
});
|
||||
|
||||
return allPatients;
|
||||
});
|
||||
|
||||
// Get kliniks based on screen configuration
|
||||
@@ -217,21 +251,33 @@ const displayedClinics = computed(() => {
|
||||
return timeA[0] * 60 + timeA[1] - (timeB[0] * 60 + timeB[1]);
|
||||
});
|
||||
|
||||
// Current queue: prioritaskan di-loket, lalu waiting, lalu pending (dengan card merah)
|
||||
const currentQueue =
|
||||
queues.find((q) => q.status === "di-loket") ||
|
||||
queues.find((q) => q.status === "waiting") ||
|
||||
queues.find((q) => q.status === "pending") ||
|
||||
null;
|
||||
|
||||
// Next queues: tampilkan semua yang bukan current queue, termasuk pending
|
||||
const nextQueues = queues.filter(
|
||||
(q) =>
|
||||
q.no !== currentQueue?.no &&
|
||||
(q.status === "waiting" || q.status === "di-loket")
|
||||
(q.status === "waiting" || q.status === "di-loket" || q.status === "pending")
|
||||
);
|
||||
|
||||
// Pending queues: pasien dengan status pending yang tidak di current atau next
|
||||
const pendingQueues = queues.filter(
|
||||
(q) =>
|
||||
q.status === "pending" &&
|
||||
q.no !== currentQueue?.no &&
|
||||
!nextQueues.find(nq => nq.no === q.no)
|
||||
);
|
||||
|
||||
return {
|
||||
name: klinik.name,
|
||||
currentQueue: currentQueue,
|
||||
nextQueues: nextQueues,
|
||||
pendingQueues: pendingQueues,
|
||||
totalQueues: queues.length,
|
||||
};
|
||||
});
|
||||
@@ -241,9 +287,19 @@ const currentCalledQueue = computed(() => {
|
||||
if (!screenData.value) return null;
|
||||
|
||||
const screenKlinikNames = screenKliniks.value.map(k => k.name);
|
||||
// Prioritaskan pasien yang sedang dipanggil (di-loket), lalu pending
|
||||
const calledQueues = klinikPatients.value
|
||||
.filter((p) => p.status === "di-loket" && screenKlinikNames.includes(p.klinik))
|
||||
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
|
||||
.filter((p) =>
|
||||
(p.status === "di-loket" || p.status === "pending") &&
|
||||
screenKlinikNames.includes(p.klinik)
|
||||
)
|
||||
.sort((a, b) => {
|
||||
// Prioritaskan di-loket dulu, lalu pending
|
||||
if (a.status === "di-loket" && b.status !== "di-loket") return -1;
|
||||
if (a.status !== "di-loket" && b.status === "di-loket") return 1;
|
||||
// Jika sama, sort by createdAt
|
||||
return new Date(b.createdAt) - new Date(a.createdAt);
|
||||
});
|
||||
|
||||
return calledQueues[0] || null;
|
||||
});
|
||||
@@ -396,6 +452,21 @@ onUnmounted(() => {
|
||||
box-shadow: 0 12px 32px rgba(224, 21, 7, 0.35);
|
||||
}
|
||||
|
||||
.hero-queue.hero-pending {
|
||||
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
|
||||
box-shadow: 0 12px 32px rgba(220, 38, 38, 0.5);
|
||||
animation: pending-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pending-pulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 12px 32px rgba(220, 38, 38, 0.5);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 12px 48px rgba(220, 38, 38, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
text-align: center;
|
||||
color: var(--color-neutral-100);
|
||||
@@ -511,6 +582,20 @@ onUnmounted(() => {
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.queue-status-label.status-pending {
|
||||
color: var(--color-danger-600);
|
||||
animation: pending-blink 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pending-blink {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.queue-number-large {
|
||||
font-size: 80px;
|
||||
font-weight: 900;
|
||||
@@ -520,6 +605,11 @@ onUnmounted(() => {
|
||||
letter-spacing: 4px;
|
||||
}
|
||||
|
||||
.queue-number-large.queue-pending {
|
||||
color: var(--color-danger-600);
|
||||
text-shadow: 0 2px 8px rgba(220, 38, 38, 0.4);
|
||||
}
|
||||
|
||||
.next-queues-section {
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
@@ -553,6 +643,12 @@ onUnmounted(() => {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.next-number-badge.badge-pending {
|
||||
background: var(--color-danger-600);
|
||||
box-shadow: 0 2px 8px rgba(220, 38, 38, 0.4);
|
||||
border: 2px solid var(--color-danger-700);
|
||||
}
|
||||
|
||||
.empty-queue {
|
||||
text-align: center;
|
||||
padding: 24px 0;
|
||||
@@ -565,6 +661,53 @@ onUnmounted(() => {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ========== PENDING QUEUES SECTION ========== */
|
||||
.pending-queues-section {
|
||||
text-align: center;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 2px solid var(--color-danger-200);
|
||||
}
|
||||
|
||||
.pending-label {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: var(--color-danger-600);
|
||||
margin-bottom: 8px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.pending-numbers-grid {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.pending-number-badge {
|
||||
background: var(--color-danger-600);
|
||||
color: var(--color-neutral-100);
|
||||
padding: 8px 16px;
|
||||
border-radius: 12px;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 2px 8px rgba(220, 38, 38, 0.4);
|
||||
border: 2px solid var(--color-danger-700);
|
||||
min-width: 60px;
|
||||
text-align: center;
|
||||
animation: pending-badge-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pending-badge-pulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 2px 8px rgba(220, 38, 38, 0.4);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 2px 12px rgba(220, 38, 38, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== FOOTER ========== */
|
||||
.tv-footer {
|
||||
background: linear-gradient(135deg, var(--color-secondary-600) 0%, var(--color-secondary-700) 100%);
|
||||
|
||||
@@ -218,15 +218,13 @@ const currentProcessingPatient = computed(() => {
|
||||
return queueStore.currentProcessingPatient?.loket || null
|
||||
})
|
||||
|
||||
// Get all patients with processStage "loket" and filter status "di-loket" (sudah check-in), "terlambat", dan "pending"
|
||||
// Get all patients with processStage "loket" and filter status "di-loket" (sudah check-in)
|
||||
// Hanya tampilkan nomor antrian yang sudah check-in dan berstatus "di-loket"
|
||||
const loketPatients = computed(() => {
|
||||
const allPatients = queueStore.getPatientsByStage('loket').value.all
|
||||
// Tampilkan antrian dengan status:
|
||||
// - "di-loket" (sudah check-in)
|
||||
// - "terlambat" (terlambat)
|
||||
// - "pending" (pending)
|
||||
// Jangan tampilkan status "waiting" atau "menunggu" (belum check-in)
|
||||
return allPatients.filter(p => p.status === 'di-loket' || p.status === 'terlambat' || p.status === 'pending')
|
||||
// Hanya tampilkan antrian dengan status "di-loket" (sudah check-in di admin loket)
|
||||
// Jangan tampilkan status "waiting", "menunggu", "terlambat", atau "pending"
|
||||
return allPatients.filter(p => p.status === 'di-loket')
|
||||
})
|
||||
|
||||
// Helper untuk mendapatkan waktu check-in atau waktu dipanggil
|
||||
@@ -248,60 +246,13 @@ const getCheckInTime = (patient) => {
|
||||
}
|
||||
|
||||
// Helper untuk mendapatkan nama klinik dari pasien
|
||||
// Jika patient.klinik tidak ada atau tidak valid, coba parse dari noAntrian
|
||||
// Membaca poli/klinik dari nomor antrian yang dibuat sebelumnya
|
||||
// Nomor antrian dibuat dengan kode klinik tertentu, jadi kita baca dari data pasien
|
||||
const getKlinikNameFromPatient = (patient) => {
|
||||
// Prioritas 1: Parse dari noAntrian (RA001 -> Radioterapi, AN001 -> Anak, dll)
|
||||
// Ini prioritas tertinggi karena noAntrian adalah sumber kebenaran
|
||||
if (patient.noAntrian) {
|
||||
const noAntrianPart = patient.noAntrian.split(' |')[0] // Ambil bagian sebelum " |"
|
||||
const match = noAntrianPart.match(/^([A-Z]+)/) // Extract prefix (RA, AN, EA, dll)
|
||||
if (match) {
|
||||
const kode = match[1]
|
||||
|
||||
// Mapping khusus untuk kode yang berbeda (RA -> RT untuk Radioterapi)
|
||||
// Cek semua kemungkinan kode di clinicStore
|
||||
let allClinics = []
|
||||
if (clinicStore.getAllClinics) {
|
||||
allClinics = typeof clinicStore.getAllClinics === 'function'
|
||||
? clinicStore.getAllClinics()
|
||||
: (clinicStore.getAllClinics.value || [])
|
||||
}
|
||||
|
||||
let matchedClinic = null
|
||||
|
||||
// Coba match langsung dengan kode
|
||||
matchedClinic = allClinics.find(c => c.kode === kode)
|
||||
|
||||
// Jika tidak match, coba mapping khusus
|
||||
if (!matchedClinic) {
|
||||
// Mapping khusus: RA -> RT (Radioterapi)
|
||||
if (kode === 'RA') {
|
||||
matchedClinic = allClinics.find(c => c.kode === 'RT' && c.name === 'RADIOTERAPI')
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedClinic && matchedClinic.name) {
|
||||
return matchedClinic.name.trim()
|
||||
}
|
||||
|
||||
// Fallback ke masterStore jika clinicStore tidak ada
|
||||
const klinikData = masterStore.getKlinikByKode ? masterStore.getKlinikByKode(kode) : null
|
||||
if (klinikData && klinikData.nama) {
|
||||
return klinikData.nama.trim()
|
||||
}
|
||||
|
||||
// Jika masih tidak match, coba dengan mapping RA -> RT
|
||||
if (kode === 'RA') {
|
||||
const rtData = masterStore.getKlinikByKode ? masterStore.getKlinikByKode('RT') : null
|
||||
if (rtData && rtData.nama) {
|
||||
return rtData.nama.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prioritas 2: Gunakan kodeKlinik jika ada
|
||||
// Prioritas 1: Gunakan kodeKlinik dari data pasien (dari nomor antrian yang dibuat sebelumnya)
|
||||
// Ini adalah sumber kebenaran karena kodeKlinik disimpan saat nomor antrian dibuat
|
||||
if (patient.kodeKlinik) {
|
||||
// Cari di clinicStore terlebih dahulu
|
||||
const clinic = clinicStore.getClinicByKode ? clinicStore.getClinicByKode(patient.kodeKlinik) : null
|
||||
if (clinic && clinic.name) {
|
||||
return clinic.name.trim()
|
||||
@@ -313,11 +264,47 @@ const getKlinikNameFromPatient = (patient) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Prioritas 3: Gunakan patient.klinik jika ada dan valid
|
||||
// Prioritas 2: Gunakan patient.klinik jika ada dan valid
|
||||
// Ini juga dari data pasien yang dibuat sebelumnya
|
||||
if (patient.klinik && patient.klinik.trim() !== '') {
|
||||
return patient.klinik.trim()
|
||||
}
|
||||
|
||||
// Prioritas 3: Coba parse dari noAntrian sebagai fallback
|
||||
// Catatan: Format nomor antrian adalah RA001, EA001, dll (R/E + Loket + nomor)
|
||||
// Kode klinik tidak langsung terlihat dari format ini, tapi kita coba match dengan kode yang ada
|
||||
if (patient.noAntrian) {
|
||||
const noAntrianPart = patient.noAntrian.split(' |')[0] // Ambil bagian sebelum " |"
|
||||
// Hapus prefix R/E dan Fast Track (F) jika ada
|
||||
const withoutPrefix = noAntrianPart.replace(/^[FR]?[RE]?/, '') // Hapus F, R, E di awal
|
||||
const match = withoutPrefix.match(/^([A-Z]+)/) // Extract kode loket/klinik (A, B, C, dll)
|
||||
|
||||
if (match) {
|
||||
const kode = match[1]
|
||||
|
||||
// Cek semua kemungkinan kode di clinicStore
|
||||
let allClinics = []
|
||||
if (clinicStore.getAllClinics) {
|
||||
allClinics = typeof clinicStore.getAllClinics === 'function'
|
||||
? clinicStore.getAllClinics()
|
||||
: (clinicStore.getAllClinics.value || [])
|
||||
}
|
||||
|
||||
// Coba match dengan kode klinik yang ada
|
||||
let matchedClinic = allClinics.find(c => c.kode === kode)
|
||||
|
||||
if (matchedClinic && matchedClinic.name) {
|
||||
return matchedClinic.name.trim()
|
||||
}
|
||||
|
||||
// Fallback ke masterStore
|
||||
const klinikData = masterStore.getKlinikByKode ? masterStore.getKlinikByKode(kode) : null
|
||||
if (klinikData && klinikData.nama) {
|
||||
return klinikData.nama.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: UMUM
|
||||
return 'UMUM'
|
||||
}
|
||||
@@ -451,14 +438,15 @@ const displayedClinics = computed(() => {
|
||||
sortedQueues.forEach((queue, index) => {
|
||||
if (processed.has(queue.no)) return
|
||||
|
||||
if (queue.status === 'di-loket' || queue.status === 'terlambat' || queue.status === 'pending') {
|
||||
// Hanya proses antrian dengan status 'di-loket' (sudah check-in)
|
||||
if (queue.status === 'di-loket') {
|
||||
const callTime = queue.lastCalledAt ? new Date(queue.lastCalledAt) : (queue.createdAt ? new Date(queue.createdAt) : null)
|
||||
if (callTime) {
|
||||
const group = [queue]
|
||||
processed.add(queue.no)
|
||||
|
||||
sortedQueues.forEach((otherQueue, otherIndex) => {
|
||||
if (otherIndex !== index && !processed.has(otherQueue.no) && (otherQueue.status === 'di-loket' || otherQueue.status === 'terlambat' || otherQueue.status === 'pending')) {
|
||||
if (otherIndex !== index && !processed.has(otherQueue.no) && otherQueue.status === 'di-loket') {
|
||||
const otherCallTime = otherQueue.lastCalledAt ? new Date(otherQueue.lastCalledAt) : (otherQueue.createdAt ? new Date(otherQueue.createdAt) : null)
|
||||
if (otherCallTime) {
|
||||
const timeDiff = Math.abs(callTime - otherCallTime)
|
||||
@@ -514,11 +502,10 @@ const displayedClinics = computed(() => {
|
||||
}
|
||||
} else {
|
||||
// Jika tidak ada di sortedQueues, gunakan langsung dari hero section
|
||||
// Pastikan pasien sesuai dengan filter (processStage 'loket')
|
||||
// Status bisa 'di-loket', 'terlambat', 'pending', atau 'waiting' (sudah dipanggil)
|
||||
// Pastikan pasien sesuai dengan filter (processStage 'loket' dan status 'di-loket')
|
||||
if (heroPatient.processStage === 'loket' &&
|
||||
heroPatient.status !== 'menunggu') {
|
||||
// Langsung gunakan pasien dari hero section karena sudah dipanggil
|
||||
heroPatient.status === 'di-loket') {
|
||||
// Langsung gunakan pasien dari hero section karena sudah dipanggil dan check-in
|
||||
currentQueue = heroPatient
|
||||
}
|
||||
}
|
||||
@@ -575,28 +562,21 @@ const displayedClinics = computed(() => {
|
||||
validatedCurrentQueue = null
|
||||
}
|
||||
|
||||
// Jika currentQueue berasal dari hero section (currentCalledQueue), tidak perlu filter status
|
||||
// karena pasien yang dipanggil di hero section sudah valid
|
||||
const isFromHero = currentCalledQueue.value &&
|
||||
(validatedCurrentQueue.no === currentCalledQueue.value.no ||
|
||||
validatedCurrentQueue.noAntrian === currentCalledQueue.value.noAntrian)
|
||||
|
||||
// Jika bukan dari hero section, pastikan status 'di-loket' (sudah check-in di admin loket)
|
||||
if (validatedCurrentQueue && !isFromHero && validatedCurrentQueue.status !== 'di-loket') {
|
||||
// Pastikan status selalu 'di-loket' (sudah check-in di admin loket)
|
||||
if (validatedCurrentQueue && validatedCurrentQueue.status !== 'di-loket') {
|
||||
validatedCurrentQueue = null
|
||||
}
|
||||
}
|
||||
|
||||
// Validasi allQueues: pastikan semua pasien benar-benar dari klinik ini
|
||||
// Ambil yang status 'di-loket', 'terlambat', atau 'pending' dan dipanggil dari admin loket
|
||||
// Hanya ambil yang status 'di-loket' (sudah check-in) dan dipanggil dari admin loket
|
||||
const validatedAllQueues = sortedQueues.filter(q => {
|
||||
// Pastikan:
|
||||
// 1. Status 'di-loket', 'terlambat', atau 'pending' (sudah dipanggil/di-loket di admin loket)
|
||||
// 1. Status 'di-loket' (sudah check-in di admin loket)
|
||||
// 2. processStage masih 'loket' (masih di admin loket, belum pindah ke klinik)
|
||||
// 3. Klinik-nya sesuai dengan card ini
|
||||
// 3. Klinik-nya sesuai dengan card ini (dibaca dari nomor antrian)
|
||||
const queueKlinik = getKlinikNameFromPatient(q)
|
||||
const isValidStatus = q.status === 'di-loket' || q.status === 'terlambat' || q.status === 'pending'
|
||||
return isValidStatus &&
|
||||
return q.status === 'di-loket' &&
|
||||
q.processStage === 'loket' &&
|
||||
queueKlinik === normalizedKlinikName
|
||||
})
|
||||
@@ -629,75 +609,24 @@ const isInTTSWindow = (queue) => {
|
||||
return remaining > 0
|
||||
}
|
||||
|
||||
// Current called queue - tiket yang sedang diproses di admin loket atau sedang dalam TTS window
|
||||
// Current called queue - tiket yang sedang diproses di admin loket
|
||||
// Nomor antrian menjadi "dipanggil" jika diproses pada AdminLoket
|
||||
const currentCalledQueue = computed(() => {
|
||||
// Prioritas 1: Pasien yang sedang diproses di admin loket
|
||||
// Prioritas 1: Pasien yang sedang diproses di admin loket (currentProcessingPatient)
|
||||
// Ini adalah pasien yang sedang dipanggil/diproses di AdminLoket
|
||||
if (currentProcessingPatient.value) {
|
||||
const processingPatient = currentProcessingPatient.value
|
||||
// Pastikan pasien memiliki noAntrian dan klinik
|
||||
if (processingPatient.noAntrian) {
|
||||
// Pastikan pasien memiliki noAntrian dan status 'di-loket' (sudah check-in)
|
||||
if (processingPatient.noAntrian && processingPatient.status === 'di-loket') {
|
||||
// Dapatkan nama klinik dari nomor antrian
|
||||
const klinikName = getKlinikNameFromPatient(processingPatient)
|
||||
return {
|
||||
...processingPatient,
|
||||
klinik: processingPatient.klinik || getKlinikNameFromPatient(processingPatient) || 'Klinik'
|
||||
klinik: klinikName || processingPatient.klinik || 'Klinik'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prioritas 2: Ambil semua tiket yang sudah dipanggil (status 'waiting')
|
||||
const allCalledQueues = queueStore.allPatients.filter(p =>
|
||||
p.status === 'waiting' && p.lastCalledAt
|
||||
)
|
||||
|
||||
// Filter berdasarkan pelayanan loket jika ada
|
||||
const targetLoketId = loketId.value
|
||||
let filteredQueues = allCalledQueues
|
||||
|
||||
if (targetLoketId && loketData.value) {
|
||||
const allowedPelayananCodes = loketData.value.pelayanan || []
|
||||
if (allowedPelayananCodes.length > 0) {
|
||||
filteredQueues = allCalledQueues.filter(patient => {
|
||||
const klinikName = patient.klinik || 'UMUM'
|
||||
const clinic = clinicStore.getClinicByName ? clinicStore.getClinicByName(klinikName) : null
|
||||
|
||||
if (clinic) {
|
||||
return allowedPelayananCodes.includes(clinic.kode)
|
||||
} else {
|
||||
const matchedKode = allowedPelayananCodes.find(kode => {
|
||||
const k = masterStore.getKlinikByKode ? masterStore.getKlinikByKode(kode) : null
|
||||
return k && k.nama === klinikName
|
||||
})
|
||||
return !!matchedKode
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Urutkan berdasarkan waktu panggilan (yang dipanggil duluan lebih dulu)
|
||||
const sortedByCallTime = filteredQueues.sort((a, b) => {
|
||||
const timeA = new Date(a.lastCalledAt || 0)
|
||||
const timeB = new Date(b.lastCalledAt || 0)
|
||||
return timeA - timeB
|
||||
})
|
||||
|
||||
// Cari tiket pertama yang masih dalam TTS window
|
||||
for (const queue of sortedByCallTime) {
|
||||
if (isInTTSWindow(queue)) {
|
||||
return {
|
||||
...queue,
|
||||
klinik: queue.klinik || 'Klinik'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Jika tidak ada yang dalam TTS window, ambil yang paling baru dipanggil
|
||||
if (sortedByCallTime.length > 0) {
|
||||
const latest = sortedByCallTime[sortedByCallTime.length - 1]
|
||||
return {
|
||||
...latest,
|
||||
klinik: latest.klinik || 'Klinik'
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
@@ -795,27 +724,37 @@ const getTimerText = (queue) => {
|
||||
return `${seconds}s`
|
||||
}
|
||||
|
||||
// Next 5 tickets to be called - tiket yang sudah dipanggil tapi menunggu giliran TTS
|
||||
// Next 5 tickets to be called - tiket yang sudah check-in (status 'di-loket') dan belum diproses
|
||||
const nextTicketsToCall = computed(() => {
|
||||
// Ambil semua tiket yang sudah dipanggil (status 'waiting')
|
||||
const allCalledQueues = queueStore.allPatients.filter(p =>
|
||||
p.status === 'waiting' && p.lastCalledAt
|
||||
// Ambil semua tiket yang sudah check-in (status 'di-loket') dan processStage 'loket'
|
||||
const allDiLoketQueues = loketPatients.value.filter(p =>
|
||||
p.status === 'di-loket' && p.processStage === 'loket'
|
||||
)
|
||||
|
||||
// Filter berdasarkan pelayanan loket jika ada
|
||||
const targetLoketId = loketId.value
|
||||
let filteredQueues = allCalledQueues
|
||||
let filteredQueues = allDiLoketQueues
|
||||
|
||||
if (targetLoketId && loketData.value) {
|
||||
const allowedPelayananCodes = loketData.value.pelayanan || []
|
||||
if (allowedPelayananCodes.length > 0) {
|
||||
filteredQueues = allCalledQueues.filter(patient => {
|
||||
const klinikName = patient.klinik || 'UMUM'
|
||||
filteredQueues = allDiLoketQueues.filter(patient => {
|
||||
// Dapatkan nama klinik dari nomor antrian
|
||||
const klinikName = getKlinikNameFromPatient(patient)
|
||||
const clinic = clinicStore.getClinicByName ? clinicStore.getClinicByName(klinikName) : null
|
||||
|
||||
if (clinic) {
|
||||
return allowedPelayananCodes.includes(clinic.kode)
|
||||
} else {
|
||||
// Coba match dengan kode dari nomor antrian
|
||||
if (patient.noAntrian) {
|
||||
const noAntrianPart = patient.noAntrian.split(' |')[0]
|
||||
const match = noAntrianPart.match(/^([A-Z]+)/)
|
||||
if (match) {
|
||||
const kodeFromNoAntrian = match[1]
|
||||
return allowedPelayananCodes.includes(kodeFromNoAntrian)
|
||||
}
|
||||
}
|
||||
const matchedKode = allowedPelayananCodes.find(kode => {
|
||||
const k = masterStore.getKlinikByKode ? masterStore.getKlinikByKode(kode) : null
|
||||
return k && k.nama === klinikName
|
||||
@@ -826,23 +765,21 @@ const nextTicketsToCall = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
// Urutkan berdasarkan waktu panggilan (yang dipanggil duluan lebih dulu)
|
||||
const sortedByCallTime = filteredQueues.sort((a, b) => {
|
||||
const timeA = new Date(a.lastCalledAt || 0)
|
||||
const timeB = new Date(b.lastCalledAt || 0)
|
||||
return timeA - timeB
|
||||
// Urutkan berdasarkan waktu check-in (yang check-in duluan lebih dulu)
|
||||
const sortedByCheckIn = filteredQueues.sort((a, b) => {
|
||||
const checkInA = getCheckInTime(a)
|
||||
const checkInB = getCheckInTime(b)
|
||||
return checkInA - checkInB
|
||||
})
|
||||
|
||||
// Exclude current called queue (yang sedang dalam TTS window)
|
||||
// Exclude current called queue (yang sedang diproses)
|
||||
const currentCalledNo = currentCalledQueue.value?.no
|
||||
const waitingForTTS = sortedByCallTime.filter(q => q.no !== currentCalledNo)
|
||||
const waitingForProcess = sortedByCheckIn.filter(q => q.no !== currentCalledNo)
|
||||
|
||||
// Ambil 5 tiket berikutnya yang sudah dipanggil tapi TTS-nya belum dimulai
|
||||
// (yang akan bergantian menjadi card utama ketika TTS selesai)
|
||||
return waitingForTTS.slice(0, 5).map(queue => ({
|
||||
// Ambil 5 tiket berikutnya yang sudah check-in tapi belum diproses
|
||||
return waitingForProcess.slice(0, 5).map(queue => ({
|
||||
...queue,
|
||||
isMultipleCall: true, // Semua di section ini adalah tiket yang sudah dipanggil
|
||||
klinik: queue.klinik || 'Klinik',
|
||||
klinik: getKlinikNameFromPatient(queue) || queue.klinik || 'Klinik',
|
||||
loket: queue.loket || 'Loket'
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -31,7 +31,7 @@ const getPelayananContohDariAnjungan = (anjunganItems) => {
|
||||
// Distribusi pelayanan ke beberapa loket sebagai contoh
|
||||
// Menggunakan data klinik yang tersedia dari master anjungan
|
||||
return {
|
||||
loket1: klinikAnjunganReguler.filter(k => ['RT', 'RM', 'TD'].includes(k)).length > 0
|
||||
loket1: klinikAnjunganReguler.filter(k => ['AN','RT', 'RM', 'TD'].includes(k)).length > 0
|
||||
? klinikAnjunganReguler.filter(k => ['RT', 'RM', 'TD'].includes(k))
|
||||
: klinikAnjunganReguler.slice(0, 3), // Ambil 3 pertama jika tidak ada match
|
||||
loket2: klinikAnjunganReguler.filter(k => ['JW', 'SR'].includes(k)).length > 0
|
||||
|
||||
Reference in New Issue
Block a user