perbaikan LOAD usage memperingan penggunaan
This commit is contained in:
+46
-187
@@ -36,7 +36,6 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
if (!loketId) return;
|
||||
const id = String(loketId);
|
||||
activeLoketInterest.value[id] = (activeLoketInterest.value[id] || 0) + 1;
|
||||
console.log(`🔌 [queueStore] Registered interest in Loket ${id}. Active:`, activeLoketInterest.value);
|
||||
};
|
||||
|
||||
const unregisterInterest = (loketId) => {
|
||||
@@ -48,14 +47,12 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
delete activeLoketInterest.value[id];
|
||||
}
|
||||
}
|
||||
console.log(`🔌 [queueStore] Unregistered interest in Loket ${id}. Active lokets:`, activeLoketInterest.value);
|
||||
};
|
||||
|
||||
const registerClinicInterest = (kodeKlinik) => {
|
||||
if (!kodeKlinik) return;
|
||||
const code = String(kodeKlinik);
|
||||
activeClinicInterest.value[code] = (activeClinicInterest.value[code] || 0) + 1;
|
||||
console.log(`🔌 [queueStore] Registered interest in Clinic ${code}. Active clinics:`, activeClinicInterest.value);
|
||||
};
|
||||
|
||||
const unregisterClinicInterest = (kodeKlinik) => {
|
||||
@@ -67,17 +64,14 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
delete activeClinicInterest.value[code];
|
||||
}
|
||||
}
|
||||
console.log(`🔌 [queueStore] Unregistered interest in Clinic ${code}. Active clinics:`, activeClinicInterest.value);
|
||||
};
|
||||
|
||||
const registerGlobalInterest = () => {
|
||||
globalInterestCount.value++;
|
||||
console.log(`🌐 [queueStore] Global interest registered. Total: ${globalInterestCount.value}`);
|
||||
};
|
||||
|
||||
const unregisterGlobalInterest = () => {
|
||||
globalInterestCount.value = Math.max(0, globalInterestCount.value - 1);
|
||||
console.log(`🌐 [queueStore] Global interest unregistered. Total: ${globalInterestCount.value}`);
|
||||
};
|
||||
|
||||
const fetchPatientsForClinic = async (kodeKlinik, force = false) => {
|
||||
@@ -304,10 +298,7 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
const targetLoketId = messageData?.loketId || messageData?.idloket;
|
||||
const targetKlinikId = messageData?.klinikId || messageData?.idklinik;
|
||||
|
||||
console.log('📨 [queueStore] Global WS Message received Type:', typeof messageData);
|
||||
console.log('📨 [queueStore] Global WS Message content:', JSON.stringify(messageData));
|
||||
|
||||
// Handle Call Events (cross-device sync for "Sedang Dipanggil" popup
|
||||
// Handle Call Events and WS messages
|
||||
if (messageData?.triggerRefresh) {
|
||||
if (messageData.klinikId) {
|
||||
console.log(`🔄 [queueStore] Received refresh trigger for clinic ${messageData.klinikId}`);
|
||||
@@ -335,7 +326,6 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
}
|
||||
}
|
||||
if (messageData?.callEvent) {
|
||||
console.log('📞 [queueStore] Call event received:', messageData.callEvent);
|
||||
lastGlobalCall.value = messageData.callEvent;
|
||||
}
|
||||
|
||||
@@ -381,53 +371,39 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TRIGGER STRATEGIC REFRESHES
|
||||
let refreshedSomething = false;
|
||||
|
||||
if (targetLoketId) {
|
||||
// 1. If message specifies a loket, refresh that one specifically (Force bypass throttle)
|
||||
console.log(`🎯 [queueStore] WS targeting Loket ${targetLoketId}: Refreshing (FORCED)...`);
|
||||
fetchPatientsForLoket(targetLoketId, true);
|
||||
refreshedSomething = true;
|
||||
}
|
||||
|
||||
if (targetKlinikId) {
|
||||
// 2. If message specifies a klinik, refresh those clinics (Force bypass throttle)
|
||||
const interestingClinics = Object.keys(activeClinicInterest.value);
|
||||
if (interestingClinics.includes(String(targetKlinikId)) || targetKlinikId === 'broadcast') {
|
||||
const clinicToFetch = targetKlinikId === 'broadcast' ? interestingClinics[0] : targetKlinikId;
|
||||
console.log(`🎯 [queueStore] WS targeting Clinic ${targetKlinikId}: Refreshing ${clinicToFetch} (FORCED)...`);
|
||||
fetchPatientsForClinic(clinicToFetch, true);
|
||||
refreshedSomething = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Global interest refresh (Force bypass throttle)
|
||||
if (globalInterestCount.value > 0) {
|
||||
console.log(`📡 [queueStore] WS trigger: Global Interest active, triggering bulk refresh (FORCED)...`);
|
||||
fetchAllPatients(); // Note: fetchAllPatients might need force internal too, but typically calls fetchPatientsForClinic
|
||||
fetchAllPatients();
|
||||
refreshedSomething = true;
|
||||
}
|
||||
|
||||
// 4. Fallback: If nothing specific was refreshed but we have generic interest, refresh all active things (FORCED)
|
||||
if (!refreshedSomething) {
|
||||
const interestingLokets = Object.keys(activeLoketInterest.value);
|
||||
const interestingClinics = Object.keys(activeClinicInterest.value);
|
||||
|
||||
if (interestingLokets.length > 0) {
|
||||
console.log(`🌐 [queueStore] WS trigger fallback: Refreshing ${interestingLokets.length} active lokets (FORCED):`, interestingLokets);
|
||||
interestingLokets.forEach(loketId => {
|
||||
fetchPatientsForLoket(loketId, true);
|
||||
});
|
||||
interestingLokets.forEach(loketId => { fetchPatientsForLoket(loketId, true); });
|
||||
refreshedSomething = true;
|
||||
}
|
||||
|
||||
if (interestingClinics.length > 0) {
|
||||
console.log(`🌐 [queueStore] WS trigger fallback: Refreshing ${interestingClinics.length} active clinics (FORCED):`, interestingClinics);
|
||||
interestingClinics.forEach(kodeKlinik => {
|
||||
fetchPatientsForClinic(kodeKlinik, true);
|
||||
});
|
||||
interestingClinics.forEach(kodeKlinik => { fetchPatientsForClinic(kodeKlinik, true); });
|
||||
refreshedSomething = true;
|
||||
}
|
||||
}
|
||||
@@ -1009,7 +985,34 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ [queueStore] Staggered bulk fetch completed. Total: ${allPatients.value.length} patients in memory.`);
|
||||
// Trim allPatients if it grows too large (keep processed patients manageable)
|
||||
trimPatients();
|
||||
};
|
||||
|
||||
/**
|
||||
* PHASE 2: Cap allPatients to prevent unbounded memory growth.
|
||||
* Removes 'processed' patients first, then oldest non-critical ones if still over limit.
|
||||
*/
|
||||
const MAX_PATIENTS_IN_MEMORY = 3000;
|
||||
const trimPatients = () => {
|
||||
if (allPatients.value.length <= MAX_PATIENTS_IN_MEMORY) return;
|
||||
|
||||
// 1. Remove 'processed' patients first (they are done)
|
||||
const activePatients = allPatients.value.filter(p => p.status !== 'processed');
|
||||
|
||||
if (activePatients.length <= MAX_PATIENTS_IN_MEMORY) {
|
||||
allPatients.value = activePatients;
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. If still over limit, keep the MAX most recent by createdAt
|
||||
const sorted = [...activePatients].sort((a, b) => {
|
||||
const aTime = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
||||
const bTime = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
||||
return bTime - aTime; // Newest first
|
||||
});
|
||||
allPatients.value = sorted.slice(0, MAX_PATIENTS_IN_MEMORY);
|
||||
console.warn(`[queueStore] allPatients trimmed to ${MAX_PATIENTS_IN_MEMORY} entries to prevent memory leak.`);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1585,30 +1588,24 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
* Handles complex names like "UMUM / JKMM / SPM / DLL"
|
||||
*/
|
||||
const isPaymentCompatible = (patientPayment, loketPayments) => {
|
||||
if (!loketPayments || loketPayments.length === 0) return true; // No restriction
|
||||
if (!loketPayments || loketPayments.length === 0) return true;
|
||||
if (!patientPayment) return false;
|
||||
|
||||
const normalizedPatient = String(patientPayment).toUpperCase().trim();
|
||||
|
||||
// Map patient payment to category
|
||||
const patientCategory =
|
||||
(normalizedPatient.includes('JKN') || normalizedPatient.includes('BPJS')) ? 'JKN' :
|
||||
normalizedPatient.includes('EKSEKUTIF') || normalizedPatient.includes('VIP') ? 'EKSEKUTIF' :
|
||||
'UMUM'; // Default to UMUM for non-JKN, non-EKSEKUTIF
|
||||
'UMUM';
|
||||
|
||||
// Check if loket accepts this category
|
||||
return loketPayments.some(lp => {
|
||||
const normalized = String(lp).toUpperCase().trim();
|
||||
|
||||
const result = (normalized === patientCategory) ||
|
||||
return (normalized === patientCategory) ||
|
||||
(patientCategory === 'UMUM' && (normalized.includes('UMUM') || normalized.includes('MANDIRI'))) ||
|
||||
(patientCategory === 'JKN' && (normalized.includes('JKN') || normalized.includes('BPJS'))) ||
|
||||
(patientCategory === 'EKSEKUTIF' && (normalized.includes('EKSEKUTIF') || normalized.includes('VIP'))) ||
|
||||
(normalized === 'BPJS' && patientCategory === 'JKN') ||
|
||||
(normalized === 'JKN' && patientCategory === 'JKN');
|
||||
|
||||
console.log(` - Checking loket accepts "${lp}" (normalized: "${normalized}") vs patient category "${patientCategory}": ${result}`);
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1943,66 +1940,36 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
idklinikstatus2: "2"
|
||||
};
|
||||
|
||||
console.log('📤 [TERLAMBAT] Sending API request:', payload);
|
||||
|
||||
// POST to external API and WAIT for response
|
||||
try {
|
||||
const response = await fetch('http://10.10.123.140:8089/api/v1/tiket/update', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
console.log('📥 [TERLAMBAT] API response status:', response.status);
|
||||
|
||||
// Read response body
|
||||
const responseData = await response.json().catch(() => ({}));
|
||||
console.log('📥 [TERLAMBAT] API response data:', responseData);
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`✅ [TERLAMBAT] API accepted request`);
|
||||
|
||||
// Add delay to ensure database is updated
|
||||
console.log('⏳ [TERLAMBAT] Waiting 500ms for database update...');
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
// REFRESH data from database to get updated status
|
||||
console.log(`🔄 [TERLAMBAT] Refreshing data from database...`);
|
||||
await fetchPatientsForLoket(loketId);
|
||||
|
||||
// Verify status after refresh
|
||||
const updatedPatient = allPatients.value.find(p => p.barcode === patient.barcode);
|
||||
console.log('🔍 [TERLAMBAT] Patient after refresh:', updatedPatient);
|
||||
|
||||
if (updatedPatient?.status === 'terlambat') {
|
||||
// API successfully saved status
|
||||
console.log('✅ [TERLAMBAT] Status persisted in database!');
|
||||
message = `Pasien ${patientCode} ditandai terlambat`;
|
||||
} else {
|
||||
// API didn't save status - use LocalStorage fallback
|
||||
console.warn('⚠️ [TERLAMBAT] API did not persist status. Using LocalStorage fallback.');
|
||||
|
||||
// Save to LocalStorage
|
||||
const storageKey = `patient-status-${patient.barcode}`;
|
||||
localStorage.setItem(storageKey, JSON.stringify({
|
||||
status: 'terlambat',
|
||||
timestamp: Date.now(),
|
||||
barcode: patient.barcode
|
||||
}));
|
||||
|
||||
// Manually update local state since API didn't save
|
||||
localStorage.setItem(storageKey, JSON.stringify({ status: 'terlambat', timestamp: Date.now(), barcode: patient.barcode }));
|
||||
const patientIndex = allPatients.value.findIndex(p => p.barcode === patient.barcode);
|
||||
if (patientIndex !== -1) {
|
||||
allPatients.value[patientIndex] = {
|
||||
...allPatients.value[patientIndex],
|
||||
status: 'terlambat',
|
||||
calledByAdmin: false
|
||||
};
|
||||
allPatients.value[patientIndex] = { ...allPatients.value[patientIndex], status: 'terlambat', calledByAdmin: false };
|
||||
syncApiPatientStatus(allPatients.value[patientIndex], 'terlambat');
|
||||
}
|
||||
|
||||
message = `Pasien ${patientCode} ditandai terlambat (local)`;
|
||||
}
|
||||
} else {
|
||||
@@ -2035,66 +2002,33 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
idklinikstatus2: "2"
|
||||
};
|
||||
|
||||
console.log('📤 [PENDING] Sending API request:', payload);
|
||||
|
||||
// POST to external API and WAIT for response
|
||||
try {
|
||||
const response = await fetch('http://10.10.123.140:8089/api/v1/tiket/update', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
console.log('📥 [PENDING] API response status:', response.status);
|
||||
|
||||
// Read response body
|
||||
const responseData = await response.json().catch(() => ({}));
|
||||
console.log('📥 [PENDING] API response data:', responseData);
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`✅ [PENDING] API accepted request`);
|
||||
|
||||
// Add delay to ensure database is updated
|
||||
console.log('⏳ [PENDING] Waiting 500ms for database update...');
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
// REFRESH data from database to get updated status
|
||||
console.log(`🔄 [PENDING] Refreshing data from database...`);
|
||||
await fetchPatientsForLoket(loketId);
|
||||
|
||||
// Verify status after refresh
|
||||
const updatedPatient = allPatients.value.find(p => p.barcode === patient.barcode);
|
||||
console.log('🔍 [PENDING] Patient after refresh:', updatedPatient);
|
||||
|
||||
if (updatedPatient?.status === 'pending') {
|
||||
// API successfully saved status
|
||||
console.log('✅ [PENDING] Status persisted in database!');
|
||||
message = `Pasien ${patientCode} di-pending`;
|
||||
} else {
|
||||
// API didn't save status - use LocalStorage fallback
|
||||
console.warn('⚠️ [PENDING] API did not persist status. Using LocalStorage fallback.');
|
||||
|
||||
// Save to LocalStorage
|
||||
const storageKey = `patient-status-${patient.barcode}`;
|
||||
localStorage.setItem(storageKey, JSON.stringify({
|
||||
status: 'pending',
|
||||
timestamp: Date.now(),
|
||||
barcode: patient.barcode
|
||||
}));
|
||||
|
||||
// Manually update local state since API didn't save
|
||||
localStorage.setItem(storageKey, JSON.stringify({ status: 'pending', timestamp: Date.now(), barcode: patient.barcode }));
|
||||
const patientIndex = allPatients.value.findIndex(p => p.barcode === patient.barcode);
|
||||
if (patientIndex !== -1) {
|
||||
allPatients.value[patientIndex] = {
|
||||
...allPatients.value[patientIndex],
|
||||
status: 'pending',
|
||||
calledByAdmin: false
|
||||
};
|
||||
allPatients.value[patientIndex] = { ...allPatients.value[patientIndex], status: 'pending', calledByAdmin: false };
|
||||
syncApiPatientStatus(allPatients.value[patientIndex], 'pending');
|
||||
}
|
||||
|
||||
message = `Pasien ${patientCode} di-pending (local)`;
|
||||
}
|
||||
} else {
|
||||
@@ -2291,13 +2225,9 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
const targetLoket = allLokets.find(l =>
|
||||
l.pelayanan && Array.isArray(l.pelayanan) && l.pelayanan.includes(newPatient.kodeKlinik)
|
||||
);
|
||||
|
||||
if (targetLoket) {
|
||||
newPatient.loketId = targetLoket.id;
|
||||
newPatient.loket = targetLoket.namaLoket;
|
||||
console.log(`✅ Auto-assigned Ticket ${newPatient.noAntrian} to Loket ${targetLoket.id} (${targetLoket.namaLoket})`);
|
||||
} else {
|
||||
console.log(`⚠️ No specific Loket found for Clinic ${newPatient.kodeKlinik}, defaulting to general pool.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2364,8 +2294,7 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
|
||||
// Use API ticket number if available, otherwise generate locally
|
||||
if (apiTicketNumber) {
|
||||
newNoAntrian = apiTicketNumber; // Use ticket from API (e.g., "PK001")
|
||||
console.log('🎫 Using API ticket number:', newNoAntrian);
|
||||
newNoAntrian = apiTicketNumber;
|
||||
} else {
|
||||
// 1. Ambil huruf pertama dari nama klinik/poli
|
||||
const firstLetter = klinikRuang.namaKlinik.charAt(0).toUpperCase();
|
||||
@@ -3001,51 +2930,23 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
*/
|
||||
const registerRegulerPatientViaApi = async (clinic, paymentType, visitType = 'SEKARANG', isFastTrack = false, fastTrackData = null) => {
|
||||
try {
|
||||
console.log('🔄 [queueStore] Generating ticket via API for REGULER patient...');
|
||||
console.log('📋 [queueStore] Payment Type:', paymentType, '| Clinic:', clinic.name, '| Clinic Code:', clinic.kode);
|
||||
|
||||
// 1. Find appropriate idloket based on BOTH clinic code AND payment type
|
||||
// IMPROVED: Check specifically for API-source lokets (id < 1000)
|
||||
const apiLoketsExist = loketStore.lokets?.some(l => l.source === 'api' || l.id < 1000);
|
||||
if (!apiLoketsExist) {
|
||||
console.log('🔄 [queueStore] API loket data empty, fetching from API...');
|
||||
await loketStore.fetchLoketFromAPI();
|
||||
}
|
||||
const allLokets = loketStore.lokets || [];
|
||||
|
||||
|
||||
|
||||
// Determine payment type for matching (normalize BPJS to JKN for API compatibility)
|
||||
const paymentTypeForMatching = paymentType === "BPJS" ? "JKN" : paymentType;
|
||||
|
||||
console.log('🔍 [queueStore] Searching lokets...');
|
||||
console.log(' Total lokets:', allLokets.length);
|
||||
console.log(' API lokets (id < 1000):', allLokets.filter(l => l.source === 'api' && l.id < 1000).length);
|
||||
console.log(' Looking for clinic:', clinic.kode, 'payment:', paymentTypeForMatching);
|
||||
|
||||
// Find loket that handles BOTH the clinic AND the payment type
|
||||
const targetLoket = allLokets.find(l => {
|
||||
// Check source: only use API lokets (id < 1000), not local eksekutif
|
||||
if (l.source !== 'api' || l.id >= 1000) return false;
|
||||
|
||||
// Check if loket handles the clinic
|
||||
const handlesClinic = l.pelayanan && Array.isArray(l.pelayanan) && l.pelayanan.includes(clinic.kode);
|
||||
|
||||
if (handlesClinic) {
|
||||
// Debug: This loket handles the clinic, now check payment
|
||||
console.log(` ✓ Loket ${l.id} (${l.namaLoket}) handles clinic ${clinic.kode}`);
|
||||
console.log(` Pembayaran array:`, l.pembayaran);
|
||||
|
||||
// NEW: Use isPaymentCompatible helper for robust payment matching
|
||||
const acceptsPayment = isPaymentCompatible(paymentTypeForMatching, l.pembayaran);
|
||||
console.log(` Accepts payment ${paymentTypeForMatching}:`, acceptsPayment);
|
||||
|
||||
if (acceptsPayment) {
|
||||
console.log(` ✅ MATCH FOUND: Loket ${l.id}`);
|
||||
return true;
|
||||
}
|
||||
return isPaymentCompatible(paymentTypeForMatching, l.pembayaran);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -3065,8 +2966,7 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
};
|
||||
}
|
||||
|
||||
console.log('🎯 [queueStore] Target Loket:', `${targetLoket.namaLoket} (ID: ${targetLoket.id})`, '| Accepts Payment:', targetLoket.pembayaran);
|
||||
|
||||
|
||||
// 2. Determine idpembayaran based on paymentType
|
||||
const idloket = String(targetLoket.id);
|
||||
// BPJS (JKN) = "2", UMUM and others = "1"
|
||||
@@ -3100,7 +3000,6 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('📥 [queueStore] API Response:', result);
|
||||
|
||||
if (result.metadata && result.metadata.code !== 200) {
|
||||
return { success: false, message: result.message || 'Gagal generate barcode via API' };
|
||||
@@ -3158,7 +3057,6 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
allPatients.value.push(newPatient);
|
||||
// NOTE: Kita tidak perlu incrementBarcodeCounter() di sini karena barcode berasal dari API
|
||||
|
||||
console.log(`✅ [queueStore] Successfully registered REGULER patient via API: ${noAntrian}`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -3182,8 +3080,6 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
*/
|
||||
const checkInPatientViaApi = async (barcode) => {
|
||||
try {
|
||||
console.log(`🔄 [queueStore] Syncing check-in via API for barcode: ${barcode}...`);
|
||||
|
||||
const body = {
|
||||
barcode: barcode,
|
||||
statuspasien: "5",
|
||||
@@ -3192,13 +3088,9 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
idklinikstatus2: "2"
|
||||
};
|
||||
|
||||
console.log('📤 [queueStore] Check-in API Body:', body);
|
||||
|
||||
const response = await fetch('http://10.10.123.140:8089/api/v1/tiket/checkin', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
||||
@@ -3207,7 +3099,6 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('📥 [queueStore] Check-in API Response:', result);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -3229,53 +3120,21 @@ const fetchPatientsForLoket = async (loketId, force = false) => {
|
||||
// Format barcode: YYMMDD + 5 digit (contoh: 26011500001)
|
||||
// Jangan gunakan fallback ke noAntrian atau no karena bisa menyebabkan false positive
|
||||
const checkInPatient = async (patientIdOrBarcode) => {
|
||||
console.log('🔍 checkInPatient called with:', patientIdOrBarcode);
|
||||
console.log('📊 Total patients in store:', allPatients.value.length);
|
||||
|
||||
// Clean input - remove whitespace and normalize
|
||||
const cleanInput = String(patientIdOrBarcode).trim();
|
||||
|
||||
// PRIORITAS: Hanya cari dengan EXACT barcode match (case-insensitive, whitespace-insensitive)
|
||||
// Format barcode: YYMMDD + 5 digit (contoh: 26011500001)
|
||||
// Ini adalah satu-satunya cara yang aman untuk match pasien
|
||||
const patientIndex = allPatients.value.findIndex(p => {
|
||||
// Normalize barcode untuk comparison
|
||||
const patientBarcode = String(p.barcode || '').trim();
|
||||
|
||||
// EXACT barcode match (case-insensitive, whitespace-insensitive)
|
||||
// Ini adalah satu-satunya cara yang aman untuk match pasien
|
||||
if (patientBarcode === cleanInput ||
|
||||
patientBarcode.toLowerCase() === cleanInput.toLowerCase()) {
|
||||
console.log('✅ Found by exact barcode match:', patientBarcode, '===', cleanInput);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return patientBarcode === cleanInput || patientBarcode.toLowerCase() === cleanInput.toLowerCase();
|
||||
});
|
||||
|
||||
if (patientIndex === -1) {
|
||||
console.log('❌ Patient not found. Searched for barcode:', cleanInput);
|
||||
console.log('📋 Available barcodes (first 10):', allPatients.value.slice(0, 10).map(p => ({
|
||||
no: p.no,
|
||||
barcode: p.barcode,
|
||||
noAntrian: p.noAntrian?.split(' |')[0]
|
||||
})));
|
||||
return { success: false, message: `Pasien dengan barcode ${cleanInput} tidak ditemukan. Pastikan barcode benar (format: YYMMDD + 5 digit, contoh: 26011500001).` };
|
||||
}
|
||||
|
||||
// IMPORTANT: Get fresh patient data from array to avoid stale data
|
||||
// Use the patientIndex we found earlier, but get fresh data from array
|
||||
const patient = allPatients.value[patientIndex];
|
||||
console.log('✅ Patient found (fresh):', {
|
||||
no: patient.no,
|
||||
barcode: patient.barcode,
|
||||
noAntrian: patient.noAntrian,
|
||||
status: patient.status,
|
||||
processStage: patient.processStage
|
||||
});
|
||||
|
||||
// Only allow check-in if status is anjungan (sudah dipanggil) or pending
|
||||
// Pasien dengan status "menunggu" belum bisa check-in (belum dipanggil)
|
||||
if (patient.status === 'menunggu') {
|
||||
console.log('⚠️ Patient status is menunggu (belum dipanggil):', patient.status);
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user