update draft klinik ruang dan cetak anjungan
This commit is contained in:
@@ -564,6 +564,246 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
};
|
||||
};
|
||||
|
||||
// Scan barcode dan generate antrean klinik ruang baru
|
||||
const scanAndCreateAntreanKlinikRuang = (barcodeInput, klinikRuang, ruang, tipeLayanan = 'Pemeriksaan Awal') => {
|
||||
// Clean input - remove whitespace and handle prefix letters
|
||||
const cleanInput = String(barcodeInput).trim().toUpperCase();
|
||||
// Remove leading letters if any (e.g., "J200730100005" -> "200730100005")
|
||||
const numericInput = cleanInput.replace(/^[A-Z]+/, '');
|
||||
|
||||
// Find patient by barcode or noAntrian
|
||||
const sourcePatient = allPatients.value.find(p => {
|
||||
// Exact barcode match
|
||||
if (p.barcode === cleanInput || p.barcode === numericInput) return true;
|
||||
|
||||
// Check if noAntrian includes the input
|
||||
const noAntrianUpper = (p.noAntrian || '').toUpperCase();
|
||||
if (noAntrianUpper.includes(cleanInput) || noAntrianUpper.includes(numericInput)) return true;
|
||||
|
||||
// Try extracting number from noAntrian
|
||||
const noAntrianNumber = noAntrianUpper.match(/([A-Z]+)(\d+)/);
|
||||
if (noAntrianNumber) {
|
||||
const extractedNumber = noAntrianNumber[2];
|
||||
if (extractedNumber.includes(numericInput) || numericInput.includes(extractedNumber)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!sourcePatient) {
|
||||
return { success: false, message: "Pasien tidak ditemukan. Pastikan barcode/nomor antrian benar." };
|
||||
}
|
||||
|
||||
// Check if patient already has antrean klinik ruang for this room
|
||||
const existingAntrean = allPatients.value.find(p =>
|
||||
p.referencePatient === sourcePatient.noAntrian &&
|
||||
p.kodeKlinik === klinikRuang.kodeKlinik &&
|
||||
p.nomorRuang === ruang.nomorRuang &&
|
||||
p.processStage === 'klinik-ruang'
|
||||
);
|
||||
|
||||
if (existingAntrean) {
|
||||
return {
|
||||
success: false,
|
||||
message: `Pasien sudah memiliki antrean di ${klinikRuang.namaKlinik} Ruang ${ruang.nomorRuang}`
|
||||
};
|
||||
}
|
||||
|
||||
// Generate queue number for this specific room and tipeLayanan
|
||||
const roomQueues = allPatients.value.filter(p =>
|
||||
p.kodeKlinik === klinikRuang.kodeKlinik &&
|
||||
p.nomorRuang === ruang.nomorRuang &&
|
||||
p.tipeLayanan === tipeLayanan &&
|
||||
p.processStage === 'klinik-ruang'
|
||||
);
|
||||
|
||||
const queueNumber = roomQueues.length + 1;
|
||||
const prefix = tipeLayanan === 'Pemeriksaan Awal' ? 'PA' : 'TD';
|
||||
const newNo = allPatients.value.length + 1;
|
||||
const timestamp = new Date();
|
||||
|
||||
const newPatient = {
|
||||
no: newNo,
|
||||
jamPanggil: `${String(timestamp.getHours()).padStart(2, "0")}:${String(
|
||||
timestamp.getMinutes()
|
||||
).padStart(2, "0")}`,
|
||||
barcode: sourcePatient.barcode,
|
||||
noAntrian: `${prefix}${String(queueNumber).padStart(3, "0")} | ${klinikRuang.namaKlinik} - ${ruang.namaRuang} - ${tipeLayanan}`,
|
||||
noAntrianRuang: `${klinikRuang.namaKlinik} - ${ruang.namaRuang} | ${prefix}${String(queueNumber).padStart(3, "0")}`,
|
||||
shift: sourcePatient.shift || "Shift 1",
|
||||
klinik: klinikRuang.namaKlinik,
|
||||
ruang: ruang.namaRuang,
|
||||
kodeKlinik: klinikRuang.kodeKlinik,
|
||||
nomorRuang: ruang.nomorRuang,
|
||||
nomorScreen: ruang.nomorScreen,
|
||||
tipeLayanan: tipeLayanan,
|
||||
fastTrack: sourcePatient.fastTrack || "TIDAK",
|
||||
pembayaran: sourcePatient.pembayaran || "UMUM",
|
||||
status: "waiting",
|
||||
processStage: "klinik-ruang",
|
||||
createdAt: timestamp.toISOString(),
|
||||
referencePatient: sourcePatient.noAntrian,
|
||||
sourcePatientNo: sourcePatient.no,
|
||||
};
|
||||
|
||||
allPatients.value.push(newPatient);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Antrean ${tipeLayanan} berhasil dibuat: ${newPatient.noAntrian.split(" |")[0]} untuk ${klinikRuang.namaKlinik} Ruang ${ruang.nomorRuang}`,
|
||||
patient: newPatient,
|
||||
};
|
||||
};
|
||||
|
||||
// Get patients by klinik and ruang
|
||||
const getPatientsByKlinikRuang = (kodeKlinik, nomorRuang, tipeLayanan = null) => {
|
||||
return computed(() => {
|
||||
let patients = allPatients.value.filter(p =>
|
||||
p.kodeKlinik === kodeKlinik &&
|
||||
p.nomorRuang === nomorRuang &&
|
||||
p.processStage === 'klinik-ruang'
|
||||
);
|
||||
|
||||
if (tipeLayanan) {
|
||||
patients = patients.filter(p => p.tipeLayanan === tipeLayanan);
|
||||
}
|
||||
|
||||
return {
|
||||
all: patients,
|
||||
waiting: patients.filter(p => p.status === 'waiting'),
|
||||
diLoket: patients.filter(p => p.status === 'di-loket'),
|
||||
terlambat: patients.filter(p => p.status === 'terlambat'),
|
||||
pending: patients.filter(p => p.status === 'pending'),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// Call next patient for a specific room and tipeLayanan
|
||||
const callNextKlinikRuang = (kodeKlinik, nomorRuang, tipeLayanan, allowMultiple = false) => {
|
||||
const patients = allPatients.value.filter(p =>
|
||||
p.kodeKlinik === kodeKlinik &&
|
||||
p.nomorRuang === nomorRuang &&
|
||||
p.tipeLayanan === tipeLayanan &&
|
||||
p.processStage === 'klinik-ruang' &&
|
||||
(p.status === 'waiting' || (allowMultiple && p.status === 'di-loket'))
|
||||
).sort((a, b) => {
|
||||
// Sort by status priority first
|
||||
const statusPriority = {
|
||||
'waiting': 1,
|
||||
'di-loket': 2
|
||||
};
|
||||
const priorityDiff = (statusPriority[a.status] || 99) - (statusPriority[b.status] || 99);
|
||||
if (priorityDiff !== 0) return priorityDiff;
|
||||
|
||||
// Then sort by queue number (extract from noAntrian)
|
||||
const numA = parseInt(a.noAntrian.match(/\d+/)?.[0] || '999');
|
||||
const numB = parseInt(b.noAntrian.match(/\d+/)?.[0] || '999');
|
||||
return numA - numB;
|
||||
});
|
||||
|
||||
if (patients.length === 0) {
|
||||
return { success: false, message: `Tidak ada antrian ${tipeLayanan} yang menunggu di ruang ini` };
|
||||
}
|
||||
|
||||
const nextPatient = patients[0];
|
||||
const patientIndex = allPatients.value.findIndex(p => p.no === nextPatient.no);
|
||||
|
||||
if (patientIndex !== -1) {
|
||||
// If allowMultiple, we can call even if already di-loket (just update timestamp)
|
||||
// Otherwise, only update if status is waiting
|
||||
if (allowMultiple || nextPatient.status === 'waiting') {
|
||||
allPatients.value[patientIndex] = {
|
||||
...allPatients.value[patientIndex],
|
||||
status: "di-loket",
|
||||
lastCalledAt: new Date().toISOString() // Track last call time
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Memanggil pasien ${nextPatient.noAntrian.split(" |")[0]} untuk ${tipeLayanan}`,
|
||||
patient: allPatients.value[patientIndex],
|
||||
};
|
||||
};
|
||||
|
||||
// Process patient in klinik ruang (set as current processing)
|
||||
const processPatientKlinikRuang = (patient, action, kodeKlinik, nomorRuang) => {
|
||||
const patientIndex = allPatients.value.findIndex(p => p.no === patient.no);
|
||||
|
||||
if (patientIndex === -1) {
|
||||
return { success: false, message: "Pasien tidak ditemukan" };
|
||||
}
|
||||
|
||||
const patientCode = patient.noAntrian.split(" |")[0];
|
||||
const key = `klinik-ruang-${kodeKlinik}-${nomorRuang}`;
|
||||
let message = "";
|
||||
|
||||
switch (action) {
|
||||
case "proses":
|
||||
// Set as current processing for this room
|
||||
if (!currentProcessingPatient.value[key]) {
|
||||
// Use Vue's reactive assignment
|
||||
currentProcessingPatient.value = {
|
||||
...currentProcessingPatient.value,
|
||||
[key]: {}
|
||||
};
|
||||
}
|
||||
// Update nested property reactively
|
||||
currentProcessingPatient.value[key] = {
|
||||
...currentProcessingPatient.value[key],
|
||||
[patient.tipeLayanan]: allPatients.value[patientIndex]
|
||||
};
|
||||
message = `Memproses pasien ${patientCode}`;
|
||||
break;
|
||||
|
||||
case "selesai":
|
||||
allPatients.value[patientIndex] = {
|
||||
...allPatients.value[patientIndex],
|
||||
status: "processed"
|
||||
};
|
||||
// Clear current processing
|
||||
if (currentProcessingPatient.value[key]) {
|
||||
currentProcessingPatient.value[key] = {
|
||||
...currentProcessingPatient.value[key],
|
||||
[patient.tipeLayanan]: null
|
||||
};
|
||||
}
|
||||
message = `Pasien ${patientCode} selesai diproses`;
|
||||
break;
|
||||
|
||||
case "terlambat":
|
||||
allPatients.value[patientIndex] = {
|
||||
...allPatients.value[patientIndex],
|
||||
status: "terlambat"
|
||||
};
|
||||
if (currentProcessingPatient.value[key]) {
|
||||
currentProcessingPatient.value[key] = {
|
||||
...currentProcessingPatient.value[key],
|
||||
[patient.tipeLayanan]: null
|
||||
};
|
||||
}
|
||||
message = `Pasien ${patientCode} ditandai terlambat`;
|
||||
break;
|
||||
|
||||
case "pending":
|
||||
allPatients.value[patientIndex] = {
|
||||
...allPatients.value[patientIndex],
|
||||
status: "pending"
|
||||
};
|
||||
if (currentProcessingPatient.value[key]) {
|
||||
currentProcessingPatient.value[key] = {
|
||||
...currentProcessingPatient.value[key],
|
||||
[patient.tipeLayanan]: null
|
||||
};
|
||||
}
|
||||
message = `Pasien ${patientCode} di-pending`;
|
||||
break;
|
||||
}
|
||||
|
||||
return { success: true, message };
|
||||
};
|
||||
|
||||
const changeKlinik = (patient, newKlinik, adminType = 'loket') => {
|
||||
const patientIndex = allPatients.value.findIndex((p) => p.no === patient.no);
|
||||
|
||||
@@ -765,6 +1005,10 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
createAntreanKlinik,
|
||||
createAntreanPenunjang,
|
||||
createAntreanKlinikRuang,
|
||||
scanAndCreateAntreanKlinikRuang,
|
||||
getPatientsByKlinikRuang,
|
||||
callNextKlinikRuang,
|
||||
processPatientKlinikRuang,
|
||||
changeKlinik,
|
||||
processNextQueue,
|
||||
getPatientsByStage,
|
||||
|
||||
Reference in New Issue
Block a user