perbaikan loket
This commit is contained in:
@@ -30,6 +30,10 @@
|
||||
</div>
|
||||
<div class="call-number">{{ currentCalledQueue.noAntrian.split(' |')[0] }}</div>
|
||||
<div class="call-klinik">{{ currentCalledQueue.klinik || 'Klinik' }}</div>
|
||||
<div v-if="currentMultipleCallsTimer" class="call-timer-main">
|
||||
<v-icon size="20" color="white">mdi-timer</v-icon>
|
||||
<span>{{ currentMultipleCallsTimer }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Multiple Calls Cards (Small) on the right -->
|
||||
@@ -61,13 +65,14 @@
|
||||
class="next-ticket-card"
|
||||
:class="{
|
||||
'is-multiple-call': ticket.isMultipleCall,
|
||||
'highlight-called': isCalled(ticket)
|
||||
'highlight-called': isCalled(ticket),
|
||||
'is-next-in-queue': idx === 0 && !isCalled(ticket)
|
||||
}"
|
||||
>
|
||||
<div class="next-ticket-number">{{ ticket.noAntrian.split(' |')[0] }}</div>
|
||||
<div class="next-ticket-klinik">{{ ticket.klinik || 'Klinik' }}</div>
|
||||
<div v-if="ticket.loket" class="next-ticket-loket">{{ ticket.loket }}</div>
|
||||
<div v-if="ticket.isMultipleCall && getTimerText(ticket)" class="next-ticket-timer">
|
||||
<div v-if="getTimerText(ticket)" class="next-ticket-timer">
|
||||
<v-icon size="14" color="warning">mdi-timer</v-icon>
|
||||
<span>{{ getTimerText(ticket) }}</span>
|
||||
</div>
|
||||
@@ -94,14 +99,18 @@
|
||||
<!-- Queue Content -->
|
||||
<div class="klinik-content">
|
||||
<!-- Current Serving Queue (Large) -->
|
||||
<div v-if="klinik.currentQueue" class="current-serving-section">
|
||||
<div class="current-serving-section">
|
||||
<div class="current-label">SEDANG DILAYANI</div>
|
||||
<div
|
||||
v-if="klinik.currentQueue"
|
||||
class="current-number-large"
|
||||
:class="{ 'highlight-called': isCalled(klinik.currentQueue) }"
|
||||
>
|
||||
{{ klinik.currentQueue.noAntrian.split(' |')[0] }}
|
||||
</div>
|
||||
<div v-else class="current-waiting-text">
|
||||
MENUNGGU PANGGILAN
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- All Queues Grid (Small) - Shows all queues including current and multiple calls -->
|
||||
@@ -117,7 +126,9 @@
|
||||
:class="{
|
||||
'is-current': queue.no === klinik.currentQueue?.no,
|
||||
'is-multiple': klinik.multipleCalls?.some(mc => mc.no === queue.no),
|
||||
'highlight-called': isCalled(queue)
|
||||
'highlight-called': isCalled(queue),
|
||||
'is-terlambat': queue.status === 'terlambat',
|
||||
'is-pending': queue.status === 'pending'
|
||||
}"
|
||||
>
|
||||
{{ queue.noAntrian.split(' |')[0] }}
|
||||
@@ -207,15 +218,15 @@ const currentProcessingPatient = computed(() => {
|
||||
return queueStore.currentProcessingPatient?.loket || null
|
||||
})
|
||||
|
||||
// Get all patients with processStage "loket" and filter status "waiting" (sudah dipanggil), "di-loket" (sudah check-in), dan "pending"
|
||||
// Get all patients with processStage "loket" and filter status "di-loket" (sudah check-in), "terlambat", dan "pending"
|
||||
const loketPatients = computed(() => {
|
||||
const allPatients = queueStore.getPatientsByStage('loket').value.all
|
||||
// Tampilkan antrian dengan status:
|
||||
// - "waiting" (sudah dipanggil oleh admin loket, sudah muncul di AntrianLoket, bisa check-in)
|
||||
// - "di-loket" (sudah check-in)
|
||||
// - "terlambat" (terlambat)
|
||||
// - "pending" (pending)
|
||||
// Jangan tampilkan status "menunggu" (belum dipanggil)
|
||||
return allPatients.filter(p => p.status === 'waiting' || p.status === 'di-loket' || p.status === 'pending')
|
||||
// Jangan tampilkan status "waiting" atau "menunggu" (belum check-in)
|
||||
return allPatients.filter(p => p.status === 'di-loket' || p.status === 'terlambat' || p.status === 'pending')
|
||||
})
|
||||
|
||||
// Helper untuk mendapatkan waktu check-in atau waktu dipanggil
|
||||
@@ -236,6 +247,81 @@ const getCheckInTime = (patient) => {
|
||||
return new Date(patient.createdAt || 0)
|
||||
}
|
||||
|
||||
// Helper untuk mendapatkan nama klinik dari pasien
|
||||
// Jika patient.klinik tidak ada atau tidak valid, coba parse dari noAntrian
|
||||
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
|
||||
if (patient.kodeKlinik) {
|
||||
const clinic = clinicStore.getClinicByKode ? clinicStore.getClinicByKode(patient.kodeKlinik) : null
|
||||
if (clinic && clinic.name) {
|
||||
return clinic.name.trim()
|
||||
}
|
||||
// Fallback ke masterStore
|
||||
const klinikData = masterStore.getKlinikByKode ? masterStore.getKlinikByKode(patient.kodeKlinik) : null
|
||||
if (klinikData && klinikData.nama) {
|
||||
return klinikData.nama.trim()
|
||||
}
|
||||
}
|
||||
|
||||
// Prioritas 3: Gunakan patient.klinik jika ada dan valid
|
||||
if (patient.klinik && patient.klinik.trim() !== '') {
|
||||
return patient.klinik.trim()
|
||||
}
|
||||
|
||||
// Fallback: UMUM
|
||||
return 'UMUM'
|
||||
}
|
||||
|
||||
// Display clinics with their queues - Group by klinik, filtered by loket pelayanan
|
||||
const displayedClinics = computed(() => {
|
||||
// Get pelayanan dari loket yang dipilih
|
||||
@@ -253,7 +339,8 @@ const displayedClinics = computed(() => {
|
||||
// Include currentProcessingPatient dalam list jika ada
|
||||
let allPatientsForDistribution = [...loketPatients.value]
|
||||
|
||||
if (currentProcessingPatient.value && (currentProcessingPatient.value.status === 'waiting' || currentProcessingPatient.value.status === 'di-loket' || currentProcessingPatient.value.status === 'pending')) {
|
||||
// Include currentProcessingPatient jika ada
|
||||
if (currentProcessingPatient.value) {
|
||||
const existsInList = allPatientsForDistribution.find(p => p.no === currentProcessingPatient.value.no)
|
||||
if (!existsInList) {
|
||||
allPatientsForDistribution.push(currentProcessingPatient.value)
|
||||
@@ -274,7 +361,9 @@ const displayedClinics = computed(() => {
|
||||
const clinicsMap = new Map()
|
||||
|
||||
allPatientsForDistribution.forEach(patient => {
|
||||
const klinikName = patient.klinik || 'UMUM'
|
||||
// Gunakan helper untuk mendapatkan nama klinik yang benar
|
||||
// Ini akan parse dari noAntrian jika patient.klinik tidak sesuai
|
||||
const klinikName = getKlinikNameFromPatient(patient)
|
||||
|
||||
// Jika ada filter pelayanan, cek apakah klinik ini ada di pelayanan loket
|
||||
if (shouldFilterByPelayanan) {
|
||||
@@ -287,17 +376,35 @@ const displayedClinics = computed(() => {
|
||||
if (!isAllowed) return // Skip jika tidak ada di pelayanan
|
||||
} else {
|
||||
// Jika tidak ditemukan di clinicStore, cek menggunakan masterStore
|
||||
const matchedKode = allowedPelayananCodes.find(kode => {
|
||||
// Juga cek dari noAntrian jika ada (RA001 -> RA -> Radioterapi)
|
||||
let matchedKode = allowedPelayananCodes.find(kode => {
|
||||
const k = masterStore.getKlinikByKode ? masterStore.getKlinikByKode(kode) : null
|
||||
return k && k.nama === klinikName
|
||||
})
|
||||
|
||||
// Jika belum match, coba parse dari noAntrian
|
||||
if (!matchedKode && patient.noAntrian) {
|
||||
const noAntrianPart = patient.noAntrian.split(' |')[0]
|
||||
const match = noAntrianPart.match(/^([A-Z]+)/)
|
||||
if (match) {
|
||||
const kodeFromNoAntrian = match[1]
|
||||
matchedKode = allowedPelayananCodes.find(kode => kode === kodeFromNoAntrian)
|
||||
}
|
||||
}
|
||||
|
||||
if (!matchedKode) return // Skip jika tidak match
|
||||
}
|
||||
}
|
||||
|
||||
// Pastikan pasien memiliki klinik yang valid sebelum di-group
|
||||
if (!klinikName || klinikName.trim() === '') {
|
||||
return // Skip jika klinik tidak valid
|
||||
}
|
||||
|
||||
if (!clinicsMap.has(klinikName)) {
|
||||
clinicsMap.set(klinikName, [])
|
||||
}
|
||||
// Pastikan pasien yang di-push memiliki klinik yang sesuai
|
||||
clinicsMap.get(klinikName).push(patient)
|
||||
})
|
||||
|
||||
@@ -344,14 +451,14 @@ const displayedClinics = computed(() => {
|
||||
sortedQueues.forEach((queue, index) => {
|
||||
if (processed.has(queue.no)) return
|
||||
|
||||
if (queue.status === 'waiting' || queue.status === 'di-loket') {
|
||||
if (queue.status === 'di-loket' || queue.status === 'terlambat' || queue.status === 'pending') {
|
||||
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 === 'waiting' || otherQueue.status === 'di-loket')) {
|
||||
if (otherIndex !== index && !processed.has(otherQueue.no) && (otherQueue.status === 'di-loket' || otherQueue.status === 'terlambat' || otherQueue.status === 'pending')) {
|
||||
const otherCallTime = otherQueue.lastCalledAt ? new Date(otherQueue.lastCalledAt) : (otherQueue.createdAt ? new Date(otherQueue.createdAt) : null)
|
||||
if (otherCallTime) {
|
||||
const timeDiff = Math.abs(callTime - otherCallTime)
|
||||
@@ -375,65 +482,223 @@ const displayedClinics = computed(() => {
|
||||
const allMultipleCalls = multipleCallGroups.flat()
|
||||
|
||||
// Current queue adalah yang sedang dilayani untuk klinik ini
|
||||
// Hanya ambil yang status 'di-loket' (yang sedang dilayani)
|
||||
// Prioritas 1: Pasien yang sedang dipanggil di hero section (currentCalledQueue) jika sesuai dengan klinik ini
|
||||
// Prioritas 2: Pasien yang status 'di-loket' (yang sedang dilayani)
|
||||
// PASTIKAN hanya mengambil dari pasien yang klinik-nya sesuai dengan card ini
|
||||
let currentQueue = null
|
||||
|
||||
// Cari yang sedang di-loket (sedang dilayani)
|
||||
const diLoketQueues = sortedQueues.filter(q => q.status === 'di-loket')
|
||||
if (diLoketQueues.length > 0) {
|
||||
// Ambil yang paling lama (berdasarkan waktu check-in atau createdAt)
|
||||
currentQueue = diLoketQueues.sort((a, b) => {
|
||||
const checkInA = getCheckInTime(a)
|
||||
const checkInB = getCheckInTime(b)
|
||||
return checkInA - checkInB // Yang lebih lama lebih dulu
|
||||
})[0]
|
||||
// Normalize nama klinik sekali di awal scope
|
||||
const normalizedKlinikName = klinikName.trim()
|
||||
|
||||
// Prioritas 1: Cek apakah pasien yang sedang dipanggil di hero section sesuai dengan klinik ini
|
||||
// Jika pasien dipanggil di hero section, tampilkan di "SEDANG DILAYANI" di card klinik yang sesuai
|
||||
// Filter berdasarkan nama klinik: jika RADIOTERAPI dipanggil, tampilkan di card RADIOTERAPI, dst
|
||||
if (currentCalledQueue.value) {
|
||||
const heroPatient = currentCalledQueue.value
|
||||
const heroKlinik = getKlinikNameFromPatient(heroPatient)
|
||||
|
||||
// Pastikan nama klinik dari hero section sesuai dengan card ini
|
||||
if (heroKlinik === normalizedKlinikName) {
|
||||
// Cari pasien di sortedQueues berdasarkan no, noAntrian, atau barcode
|
||||
const heroInQueues = sortedQueues.find(q =>
|
||||
q.no === heroPatient.no ||
|
||||
(q.noAntrian && heroPatient.noAntrian && q.noAntrian === heroPatient.noAntrian) ||
|
||||
(q.barcode && heroPatient.barcode && q.barcode === heroPatient.barcode)
|
||||
)
|
||||
|
||||
if (heroInQueues) {
|
||||
// Gunakan pasien dari sortedQueues (data lebih lengkap)
|
||||
// Pastikan pasien ini sesuai dengan filter (processStage 'loket')
|
||||
if (heroInQueues.processStage === 'loket') {
|
||||
currentQueue = heroInQueues
|
||||
}
|
||||
} 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 'pending-call' (sudah dipanggil)
|
||||
// Status 'waiting' tidak ditampilkan di antrian loket
|
||||
if (heroPatient.processStage === 'loket' &&
|
||||
heroPatient.status !== 'waiting' &&
|
||||
heroPatient.status !== 'menunggu') {
|
||||
// Langsung gunakan pasien dari hero section karena sudah dipanggil
|
||||
currentQueue = heroPatient
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prioritas 2: Cari yang sedang di-loket (sedang dilayani) dan pastikan klinik-nya sesuai
|
||||
// HANYA ambil yang dipanggil dari admin loket (processStage masih 'loket')
|
||||
// Gunakan helper untuk mendapatkan nama klinik yang benar dari pasien
|
||||
if (!currentQueue) {
|
||||
const diLoketQueues = sortedQueues.filter(q => {
|
||||
// Pastikan:
|
||||
// 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
|
||||
const patientKlinik = getKlinikNameFromPatient(q)
|
||||
return q.status === 'di-loket' &&
|
||||
q.processStage === 'loket' &&
|
||||
patientKlinik === normalizedKlinikName
|
||||
})
|
||||
|
||||
if (diLoketQueues.length > 0) {
|
||||
// Ambil yang paling lama (berdasarkan waktu check-in atau createdAt)
|
||||
currentQueue = diLoketQueues.sort((a, b) => {
|
||||
const checkInA = getCheckInTime(a)
|
||||
const checkInB = getCheckInTime(b)
|
||||
return checkInA - checkInB // Yang lebih lama lebih dulu
|
||||
})[0]
|
||||
}
|
||||
}
|
||||
|
||||
// Multiple calls untuk display - semua yang dipanggil bersamaan (termasuk yang sudah di-loket)
|
||||
const multipleCalls = allMultipleCalls.filter(q =>
|
||||
q.no !== currentQueue?.no || currentQueue?.status !== 'di-loket'
|
||||
)
|
||||
// Pastikan hanya dari klinik ini
|
||||
const multipleCalls = allMultipleCalls.filter(q => {
|
||||
// Pastikan dari klinik yang sama (gunakan helper untuk mendapatkan nama klinik yang benar)
|
||||
const queueKlinik = getKlinikNameFromPatient(q)
|
||||
if (queueKlinik !== normalizedKlinikName) return false
|
||||
// Exclude currentQueue jika ada
|
||||
return q.no !== currentQueue?.no || currentQueue?.status !== 'di-loket'
|
||||
})
|
||||
|
||||
// Validasi akhir: pastikan currentQueue benar-benar dari klinik ini dan dari admin loket
|
||||
let validatedCurrentQueue = currentQueue
|
||||
if (validatedCurrentQueue) {
|
||||
// Pastikan klinik-nya sesuai
|
||||
const queueKlinik = getKlinikNameFromPatient(validatedCurrentQueue)
|
||||
if (queueKlinik !== normalizedKlinikName) {
|
||||
// Jika tidak match, set ke null untuk menghindari menampilkan tiket yang salah
|
||||
validatedCurrentQueue = null
|
||||
}
|
||||
|
||||
// Pastikan processStage masih 'loket' (dipanggil dari admin loket)
|
||||
if (validatedCurrentQueue && validatedCurrentQueue.processStage !== 'loket') {
|
||||
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') {
|
||||
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
|
||||
const validatedAllQueues = sortedQueues.filter(q => {
|
||||
// Pastikan:
|
||||
// 1. Status 'di-loket', 'terlambat', atau 'pending' (sudah dipanggil/di-loket di admin loket)
|
||||
// 2. processStage masih 'loket' (masih di admin loket, belum pindah ke klinik)
|
||||
// 3. Klinik-nya sesuai dengan card ini
|
||||
const queueKlinik = getKlinikNameFromPatient(q)
|
||||
const isValidStatus = q.status === 'di-loket' || q.status === 'terlambat' || q.status === 'pending'
|
||||
return isValidStatus &&
|
||||
q.processStage === 'loket' &&
|
||||
queueKlinik === normalizedKlinikName
|
||||
})
|
||||
|
||||
return {
|
||||
name: klinikName,
|
||||
currentQueue: currentQueue,
|
||||
currentQueue: validatedCurrentQueue,
|
||||
multipleCalls: multipleCalls,
|
||||
allQueues: sortedQueues,
|
||||
totalQueues: sortedQueues.length
|
||||
allQueues: validatedAllQueues,
|
||||
totalQueues: validatedAllQueues.length
|
||||
}
|
||||
})
|
||||
|
||||
return clinics.sort((a, b) => a.name.localeCompare(b.name))
|
||||
})
|
||||
|
||||
// Current called queue - antrian yang sedang diproses atau paling baru dipanggil
|
||||
// Helper untuk cek apakah tiket masih dalam TTS window (15 detik)
|
||||
const isInTTSWindow = (queue) => {
|
||||
if (!queue) return false
|
||||
|
||||
const _ = currentTime.value // Force reactivity
|
||||
|
||||
const callTime = queue.lastCalledAt ? new Date(queue.lastCalledAt) :
|
||||
(queue.pendingCallAt ? new Date(queue.pendingCallAt) : null)
|
||||
if (!callTime) return false
|
||||
|
||||
const ttsDuration = 15000 // 15 detik
|
||||
const elapsed = Date.now() - callTime.getTime()
|
||||
const remaining = ttsDuration - elapsed
|
||||
|
||||
return remaining > 0
|
||||
}
|
||||
|
||||
// Current called queue - tiket yang sedang diproses di admin loket atau sedang dalam TTS window
|
||||
const currentCalledQueue = computed(() => {
|
||||
// Prioritas 1: Antrian yang sedang diproses di AdminLoket (currentProcessingPatient)
|
||||
if (currentProcessingPatient.value && (currentProcessingPatient.value.status === 'waiting' || currentProcessingPatient.value.status === 'di-loket' || currentProcessingPatient.value.status === 'pending')) {
|
||||
return {
|
||||
...currentProcessingPatient.value,
|
||||
klinik: currentProcessingPatient.value.klinik || 'Klinik'
|
||||
// Prioritas 1: Pasien yang sedang diproses di admin loket
|
||||
if (currentProcessingPatient.value) {
|
||||
const processingPatient = currentProcessingPatient.value
|
||||
// Pastikan pasien memiliki noAntrian dan klinik
|
||||
if (processingPatient.noAntrian) {
|
||||
return {
|
||||
...processingPatient,
|
||||
klinik: processingPatient.klinik || getKlinikNameFromPatient(processingPatient) || 'Klinik'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prioritas 2: Antrian yang paling baru dipanggil dari displayedClinics
|
||||
const allCurrentQueues = displayedClinics.value
|
||||
.filter(klinik => klinik.currentQueue)
|
||||
.map(klinik => ({
|
||||
...klinik.currentQueue,
|
||||
klinikName: klinik.name
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
const dateA = new Date(a.lastCalledAt || a.createdAt || 0)
|
||||
const dateB = new Date(b.lastCalledAt || b.createdAt || 0)
|
||||
return dateB - dateA
|
||||
})
|
||||
// Prioritas 2: Ambil semua tiket yang sudah dipanggil (status 'pending-call' saja, bukan 'waiting')
|
||||
// Status 'waiting' tidak ditampilkan di antrian loket
|
||||
const allCalledQueues = queueStore.allPatients.filter(p =>
|
||||
p.status === 'pending-call' && (p.lastCalledAt || p.pendingCallAt)
|
||||
)
|
||||
|
||||
if (allCurrentQueues.length > 0) {
|
||||
const patient = allCurrentQueues[0]
|
||||
// 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 || a.pendingCallAt || 0)
|
||||
const timeB = new Date(b.lastCalledAt || b.pendingCallAt || 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 {
|
||||
...patient,
|
||||
klinik: patient.klinikName || patient.klinik || 'Klinik'
|
||||
...latest,
|
||||
klinik: latest.klinik || 'Klinik'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,14 +758,14 @@ const currentMultipleCalls = computed(() => {
|
||||
return null
|
||||
})
|
||||
|
||||
// Timer untuk multiple calls
|
||||
// Timer untuk card utama (TTS countdown)
|
||||
const currentMultipleCallsTimer = computed(() => {
|
||||
if (!currentMultipleCalls.value || currentMultipleCalls.value.length === 0) return null
|
||||
if (!currentCalledQueue.value) return null
|
||||
|
||||
const _ = currentTime.value // Force reactivity
|
||||
|
||||
const firstCall = currentMultipleCalls.value[0]
|
||||
const callTime = firstCall.lastCalledAt ? new Date(firstCall.lastCalledAt) : (firstCall.createdAt ? new Date(firstCall.createdAt) : null)
|
||||
const callTime = currentCalledQueue.value.lastCalledAt ? new Date(currentCalledQueue.value.lastCalledAt) :
|
||||
(currentCalledQueue.value.pendingCallAt ? new Date(currentCalledQueue.value.pendingCallAt) : null)
|
||||
if (!callTime) return null
|
||||
|
||||
const ttsDuration = 15000 // 15 detik
|
||||
@@ -545,82 +810,22 @@ const getTimerText = (queue) => {
|
||||
return `${seconds}s`
|
||||
}
|
||||
|
||||
// Next 5 tickets to be called (untuk urutan text-to-speech ketika ada multiple loket memanggil bersamaan)
|
||||
// Next 5 tickets to be called - tiket yang sudah dipanggil tapi menunggu giliran TTS
|
||||
const nextTicketsToCall = computed(() => {
|
||||
// Ambil semua antrian dari SEMUA loket yang memiliki status 'waiting' atau 'pending-call' (sudah dipanggil atau akan dipanggil)
|
||||
// Ini untuk menampilkan urutan text-to-speech ketika ada 2+ loket memanggil bersamaan
|
||||
const allWaitingFromAllLokets = queueStore.allPatients.filter(p =>
|
||||
(p.status === 'waiting' || p.status === 'pending-call') && (p.lastCalledAt || p.pendingCallAt)
|
||||
// Ambil semua tiket yang sudah dipanggil (status 'pending-call' saja, bukan 'waiting')
|
||||
// Status 'waiting' tidak ditampilkan di antrian loket
|
||||
const allCalledQueues = queueStore.allPatients.filter(p =>
|
||||
p.status === 'pending-call' && (p.lastCalledAt || p.pendingCallAt)
|
||||
)
|
||||
|
||||
// Group berdasarkan waktu panggilan (dalam 5 detik = multiple calls)
|
||||
const callGroups = []
|
||||
const processed = new Set()
|
||||
|
||||
allWaitingFromAllLokets.forEach((queue) => {
|
||||
if (processed.has(queue.no)) return
|
||||
|
||||
// Gunakan lastCalledAt atau pendingCallAt untuk waktu panggilan
|
||||
const callTime = new Date(queue.lastCalledAt || queue.pendingCallAt)
|
||||
const group = [queue]
|
||||
processed.add(queue.no)
|
||||
|
||||
// Cari semua tiket yang dipanggil dalam 5 detik
|
||||
allWaitingFromAllLokets.forEach((otherQueue) => {
|
||||
if (!processed.has(otherQueue.no) && otherQueue.no !== queue.no) {
|
||||
const otherCallTime = new Date(otherQueue.lastCalledAt || otherQueue.pendingCallAt)
|
||||
const timeDiff = Math.abs(callTime - otherCallTime)
|
||||
if (timeDiff <= 5000) {
|
||||
group.push(otherQueue)
|
||||
processed.add(otherQueue.no)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (group.length > 1) {
|
||||
// Sort dalam group berdasarkan waktu panggilan (siapa yang dipanggil duluan)
|
||||
group.sort((a, b) => {
|
||||
const timeA = new Date(a.lastCalledAt || a.pendingCallAt)
|
||||
const timeB = new Date(b.lastCalledAt || b.pendingCallAt)
|
||||
return timeA - timeB
|
||||
})
|
||||
callGroups.push(...group)
|
||||
}
|
||||
})
|
||||
|
||||
// Jika ada multiple calls, ambil 5 teratas dari yang dipanggil bersamaan
|
||||
// Urutkan berdasarkan waktu panggilan untuk text-to-speech
|
||||
if (callGroups.length > 0) {
|
||||
// Ambil 5 teratas dari multiple calls, urutkan berdasarkan waktu panggilan
|
||||
const sortedMultipleCalls = callGroups
|
||||
.sort((a, b) => {
|
||||
const timeA = new Date(a.lastCalledAt || a.pendingCallAt)
|
||||
const timeB = new Date(b.lastCalledAt || b.pendingCallAt)
|
||||
return timeA - timeB
|
||||
})
|
||||
.slice(0, 5)
|
||||
|
||||
return sortedMultipleCalls.map(queue => ({
|
||||
...queue,
|
||||
isMultipleCall: true,
|
||||
klinik: queue.klinik || 'Klinik',
|
||||
loket: queue.loket || 'Loket'
|
||||
}))
|
||||
}
|
||||
|
||||
// Jika tidak ada multiple calls, tampilkan 5 tiket tercepat yang akan dipanggil
|
||||
const menungguQueues = loketPatients.value.filter(p => p.status === 'menunggu')
|
||||
const waitingQueues = loketPatients.value.filter(p => p.status === 'waiting')
|
||||
const allWaitingQueues = [...menungguQueues, ...waitingQueues]
|
||||
|
||||
// Filter berdasarkan pelayanan loket jika ada
|
||||
const targetLoketId = loketId.value
|
||||
let filteredQueues = allWaitingQueues
|
||||
let filteredQueues = allCalledQueues
|
||||
|
||||
if (targetLoketId && loketData.value) {
|
||||
const allowedPelayananCodes = loketData.value.pelayanan || []
|
||||
if (allowedPelayananCodes.length > 0) {
|
||||
filteredQueues = allWaitingQueues.filter(patient => {
|
||||
filteredQueues = allCalledQueues.filter(patient => {
|
||||
const klinikName = patient.klinik || 'UMUM'
|
||||
const clinic = clinicStore.getClinicByName ? clinicStore.getClinicByName(klinikName) : null
|
||||
|
||||
@@ -637,36 +842,24 @@ const nextTicketsToCall = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
// Sort berdasarkan prioritas
|
||||
const sortedQueues = filteredQueues.sort((a, b) => {
|
||||
const statusPriority = { 'menunggu': 1, 'waiting': 2 }
|
||||
const statusDiff = (statusPriority[a.status] || 99) - (statusPriority[b.status] || 99)
|
||||
if (statusDiff !== 0) return statusDiff
|
||||
|
||||
const createdAtA = new Date(a.createdAt || 0)
|
||||
const createdAtB = new Date(b.createdAt || 0)
|
||||
if (createdAtA.getTime() !== createdAtB.getTime()) {
|
||||
return createdAtA - createdAtB
|
||||
}
|
||||
|
||||
if (a.no !== b.no) {
|
||||
return a.no - b.no
|
||||
}
|
||||
|
||||
const checkInA = getCheckInTime(a)
|
||||
const checkInB = getCheckInTime(b)
|
||||
return checkInA - checkInB
|
||||
// Urutkan berdasarkan waktu panggilan (yang dipanggil duluan lebih dulu)
|
||||
const sortedByCallTime = filteredQueues.sort((a, b) => {
|
||||
const timeA = new Date(a.lastCalledAt || a.pendingCallAt || 0)
|
||||
const timeB = new Date(b.lastCalledAt || b.pendingCallAt || 0)
|
||||
return timeA - timeB
|
||||
})
|
||||
|
||||
// Exclude current called queue
|
||||
// Exclude current called queue (yang sedang dalam TTS window)
|
||||
const currentCalledNo = currentCalledQueue.value?.no
|
||||
const filteredForNext = sortedQueues.filter(q => q.no !== currentCalledNo)
|
||||
const waitingForTTS = sortedByCallTime.filter(q => q.no !== currentCalledNo)
|
||||
|
||||
// Ambil 5 teratas
|
||||
return filteredForNext.slice(0, 5).map(queue => ({
|
||||
// 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 => ({
|
||||
...queue,
|
||||
isMultipleCall: false,
|
||||
klinik: queue.klinik || 'Klinik'
|
||||
isMultipleCall: true, // Semua di section ini adalah tiket yang sudah dipanggil
|
||||
klinik: queue.klinik || 'Klinik',
|
||||
loket: queue.loket || 'Loket'
|
||||
}))
|
||||
})
|
||||
|
||||
@@ -855,12 +1048,12 @@ onUnmounted(() => {
|
||||
|
||||
/* ========== HERO CALL SECTION (LARGE) ========== */
|
||||
.hero-call-section {
|
||||
background: linear-gradient(135deg, var(--color-danger-600) 0%, var(--color-danger-700) 100%);
|
||||
background: linear-gradient(135deg, var(--color-primary-600) 0%, var(--color-primary-700) 100%);
|
||||
border-radius: 20px;
|
||||
padding: 32px;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
box-shadow: 0 12px 32px rgba(224, 21, 7, 0.35);
|
||||
box-shadow: 0 12px 32px rgba(33, 150, 243, 0.35);
|
||||
animation: pulse-highlight 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -894,6 +1087,21 @@ onUnmounted(() => {
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.call-timer-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--color-neutral-100);
|
||||
margin-top: 16px;
|
||||
padding: 8px 16px;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-radius: 12px;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* ========== NEXT TICKETS SECTION ========== */
|
||||
.next-tickets-section {
|
||||
background: var(--color-neutral-100);
|
||||
@@ -964,6 +1172,14 @@ onUnmounted(() => {
|
||||
animation: highlight-flash 1s ease-in-out infinite;
|
||||
box-shadow: 0 2px 8px rgba(244, 67, 54, 0.4);
|
||||
}
|
||||
|
||||
/* Next in queue - akan naik ke card utama setelah TTS selesai */
|
||||
&.is-next-in-queue {
|
||||
border-color: var(--color-primary-500);
|
||||
background: var(--color-primary-50);
|
||||
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.3);
|
||||
border-width: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.next-ticket-number {
|
||||
@@ -1036,23 +1252,12 @@ onUnmounted(() => {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* ========== HERO CALL SECTION (OLD - KEEP FOR REFERENCE) ========== */
|
||||
.hero-call-section {
|
||||
background: linear-gradient(135deg, var(--color-danger-600) 0%, var(--color-danger-700) 100%);
|
||||
border-radius: 20px;
|
||||
padding: 32px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
box-shadow: 0 12px 32px rgba(224, 21, 7, 0.35);
|
||||
animation: pulse-highlight 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-highlight {
|
||||
0%, 100% {
|
||||
box-shadow: 0 12px 32px rgba(224, 21, 7, 0.35);
|
||||
box-shadow: 0 12px 32px rgba(33, 150, 243, 0.35);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 12px 48px rgba(224, 21, 7, 0.55);
|
||||
box-shadow: 0 12px 48px rgba(33, 150, 243, 0.55);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1192,6 +1397,16 @@ onUnmounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.current-waiting-text {
|
||||
font-size: 48px;
|
||||
font-weight: 700;
|
||||
color: var(--color-neutral-500);
|
||||
letter-spacing: 2px;
|
||||
line-height: 1;
|
||||
margin-top: 10px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Multiple Calls Row (Small chips) */
|
||||
.multiple-calls-row {
|
||||
display: flex;
|
||||
@@ -1274,6 +1489,25 @@ onUnmounted(() => {
|
||||
color: var(--color-danger-700);
|
||||
box-shadow: 0 2px 8px rgba(244, 67, 54, 0.4);
|
||||
}
|
||||
|
||||
/* Terlambat - highlighted in orange */
|
||||
&.is-terlambat {
|
||||
background: var(--color-warning-50);
|
||||
border: 3px solid var(--color-warning-500);
|
||||
color: var(--color-warning-800);
|
||||
font-weight: 800;
|
||||
box-shadow: 0 2px 6px rgba(255, 152, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Pending - highlighted in grey */
|
||||
&.is-pending {
|
||||
background: var(--color-neutral-100);
|
||||
border: 3px solid var(--color-neutral-400);
|
||||
color: var(--color-neutral-600);
|
||||
font-weight: 800;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
</div>
|
||||
<div class="loket-tags">
|
||||
<v-chip
|
||||
v-for="(pelayanan, idx) in (loket.pelayanan || []).slice(0, 3)"
|
||||
v-for="(pelayananKode, idx) in (loket.pelayanan || []).slice(0, 3)"
|
||||
:key="idx"
|
||||
size="small"
|
||||
class="ma-1 chip-preview"
|
||||
>
|
||||
{{ pelayanan }}
|
||||
{{ getKlinikName(pelayananKode) }}
|
||||
</v-chip>
|
||||
<v-chip
|
||||
v-if="(loket.pelayanan || []).length > 3"
|
||||
@@ -91,6 +91,7 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useLoketStore } from '@/stores/loketStore';
|
||||
import { useMasterStore } from '@/stores/masterStore';
|
||||
import { useRoute } from '#app';
|
||||
|
||||
definePageMeta({
|
||||
@@ -98,6 +99,7 @@ definePageMeta({
|
||||
});
|
||||
|
||||
const loketStore = useLoketStore();
|
||||
const masterStore = useMasterStore();
|
||||
const route = useRoute();
|
||||
|
||||
// Helper function: Convert nomor loket ke huruf (1 -> A, 2 -> B, dst)
|
||||
@@ -145,6 +147,11 @@ const navigateToLoket = (loketId) => {
|
||||
const navigateToSettings = () => {
|
||||
navigateTo('/setting/masterloket');
|
||||
};
|
||||
|
||||
// Helper function untuk mendapatkan nama klinik dari kode
|
||||
const getKlinikName = (kode) => {
|
||||
return masterStore.getKlinikNameByKode ? masterStore.getKlinikNameByKode(kode) : kode;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
+28
-10
@@ -119,28 +119,46 @@ export const useLoketStore = defineStore('loket', () => {
|
||||
|
||||
// Computed - Available services (reference dari clinicStore)
|
||||
// Mengambil data dari clinicStore untuk dropdown pelayanan
|
||||
// Menggunakan getAllClinics computed untuk memastikan reactivity
|
||||
const availableServices = computed(() => {
|
||||
try {
|
||||
// Akses getAllClinics computed dari clinicStore
|
||||
// Karena kita di dalam computed, Vue akan handle reactivity
|
||||
// Gunakan getAllClinics computed dari clinicStore
|
||||
// Ini akan otomatis reactive ketika clinics berubah
|
||||
const clinicsComputed = clinicStore.getAllClinics;
|
||||
|
||||
// getAllClinics adalah computed, jadi kita perlu .value untuk mendapatkan array
|
||||
const clinicsArray = clinicsComputed?.value || [];
|
||||
if (!clinicsComputed) {
|
||||
console.warn('clinicStore.getAllClinics is not available');
|
||||
return [];
|
||||
}
|
||||
|
||||
// getAllClinics adalah computed, akses .value untuk mendapatkan array
|
||||
// Vue akan otomatis track dependency ini
|
||||
const clinicsArray = clinicsComputed.value || [];
|
||||
|
||||
// Pastikan clinicsArray adalah array
|
||||
if (!Array.isArray(clinicsArray) || clinicsArray.length === 0) {
|
||||
if (!Array.isArray(clinicsArray)) {
|
||||
console.warn('getAllClinics.value is not an array:', typeof clinicsArray, clinicsArray);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (clinicsArray.length === 0) {
|
||||
console.warn('No clinics available from clinicStore');
|
||||
return [];
|
||||
}
|
||||
|
||||
// Map ke format yang dibutuhkan form: { id, nama, kode }
|
||||
// id menggunakan kode untuk kompatibilitas dengan form yang menggunakan item-value="id"
|
||||
return clinicsArray.map(c => ({
|
||||
id: c.kode, // Menggunakan kode sebagai id (sesuai dengan item-value="id" di form)
|
||||
nama: c.name,
|
||||
kode: c.kode,
|
||||
}));
|
||||
return clinicsArray.map(c => {
|
||||
if (!c || !c.kode || !c.name) {
|
||||
console.warn('Invalid clinic data:', c);
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: c.kode, // Menggunakan kode sebagai id (sesuai dengan item-value="id" di form)
|
||||
nama: c.name,
|
||||
kode: c.kode,
|
||||
};
|
||||
}).filter(Boolean); // Filter out null values
|
||||
} catch (error) {
|
||||
console.error('Error getting available services from clinicStore:', error);
|
||||
return [];
|
||||
|
||||
@@ -127,7 +127,12 @@ export const useMasterStore = defineStore('master', () => {
|
||||
const loketData = computed(() => loketStore.loketData);
|
||||
// availableServices adalah computed dari loketStore
|
||||
// Pinia computed sudah handle reactivity dengan baik, jadi akses langsung
|
||||
const availableServices = computed(() => loketStore.availableServices);
|
||||
// loketStore.availableServices adalah computed, jadi kita bisa langsung reference
|
||||
const availableServices = computed(() => {
|
||||
// loketStore.availableServices adalah computed, akses .value untuk mendapatkan array
|
||||
const services = loketStore.availableServices;
|
||||
return services?.value || services || [];
|
||||
});
|
||||
|
||||
// Actions - Loket (delegate to loketStore)
|
||||
const addLoket = (loketPayload) => loketStore.addLoket(loketPayload);
|
||||
|
||||
+21
-9
@@ -602,29 +602,41 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
// Ambil data terbaru dari array
|
||||
const patient = allPatients.value[patientIndex];
|
||||
|
||||
// Jika pasien memiliki status "pending" atau "terlambat", ubah menjadi "di-loket"
|
||||
// agar pasien masuk ke kategori diLoketPatients dan ditampilkan sebagai "diproses"
|
||||
const currentStatus = patient.status;
|
||||
const shouldUpdateStatus = currentStatus === "pending" || currentStatus === "terlambat";
|
||||
|
||||
// Jika adminType adalah 'loket', pastikan ada loket assignment
|
||||
if (adminType === 'loket') {
|
||||
// Pastikan antrian yang diproses memiliki loket assignment
|
||||
const currentLoket = patient.loket || getDefaultLoket();
|
||||
const currentLoketId = patient.loketId || 1;
|
||||
|
||||
// Update patient dengan loket assignment (jika belum ada)
|
||||
if (!patient.loket || !patient.loketId) {
|
||||
// Update patient dengan loket assignment dan status (jika perlu)
|
||||
const updatedPatient = {
|
||||
...patient,
|
||||
loket: patient.loket || currentLoket,
|
||||
loketId: patient.loketId || currentLoketId,
|
||||
// Ubah status menjadi "di-loket" jika sebelumnya "pending" atau "terlambat"
|
||||
...(shouldUpdateStatus && { status: "di-loket" })
|
||||
};
|
||||
|
||||
allPatients.value[patientIndex] = updatedPatient;
|
||||
// Set currentProcessingPatient dengan data terbaru
|
||||
currentProcessingPatient.value[adminType] = updatedPatient;
|
||||
} else {
|
||||
// Untuk adminType selain loket, update status jika perlu
|
||||
if (shouldUpdateStatus) {
|
||||
const updatedPatient = {
|
||||
...patient,
|
||||
loket: currentLoket,
|
||||
loketId: currentLoketId
|
||||
status: "di-loket"
|
||||
};
|
||||
allPatients.value[patientIndex] = updatedPatient;
|
||||
// Set currentProcessingPatient dengan loket assignment
|
||||
currentProcessingPatient.value[adminType] = updatedPatient;
|
||||
} else {
|
||||
// Jika sudah ada loket assignment, langsung set currentProcessingPatient
|
||||
currentProcessingPatient.value[adminType] = patient;
|
||||
}
|
||||
} else {
|
||||
// Untuk adminType selain loket, langsung set currentProcessingPatient
|
||||
currentProcessingPatient.value[adminType] = patient;
|
||||
}
|
||||
message = `Memproses pasien ${patientCode}`;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user