update WS admin loket dan checkin
This commit is contained in:
+97
-17
@@ -20,8 +20,42 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
const isLoadingPatients = ref(false);
|
||||
const apiPatientsError = ref(null);
|
||||
|
||||
// Scoped Refresh Logic: track which lokets are currently being viewed
|
||||
const activeLoketInterest = ref({}); // { [loketId]: count }
|
||||
const globalInterestCount = ref(0); // Tracks pages that need ALL loket data (e.g. CheckInPasien)
|
||||
|
||||
const registerInterest = (loketId) => {
|
||||
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) => {
|
||||
if (!loketId) return;
|
||||
const id = String(loketId);
|
||||
if (activeLoketInterest.value[id]) {
|
||||
activeLoketInterest.value[id] = Math.max(0, activeLoketInterest.value[id] - 1);
|
||||
if (activeLoketInterest.value[id] === 0) {
|
||||
delete activeLoketInterest.value[id];
|
||||
}
|
||||
}
|
||||
console.log(`🔌 [queueStore] Unregistered interest in Loket ${id}. Active:`, activeLoketInterest.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}`);
|
||||
};
|
||||
|
||||
// Throttle mechanism: track last fetch time per loket
|
||||
const lastFetchTime = ref({});
|
||||
const lastGlobalFetchTime = ref(0); // Cooldown for bulk refreshes
|
||||
|
||||
// Synchronization Guard: track last update time to break loops across tabs
|
||||
const lastUpdated = ref(Date.now());
|
||||
@@ -68,18 +102,36 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
isWsConnected.value = false;
|
||||
},
|
||||
onMessage: (data) => {
|
||||
console.log('📨 [queueStore] Global WS Message:', data);
|
||||
console.log('📨 [queueStore] Global WS Message received:', data);
|
||||
|
||||
// TRIGGER STRATEGIC REFRESHES
|
||||
// 1. Refetch patients for all active lokets in the store
|
||||
Object.keys(apiPatientsPerLoket.value).forEach(loketId => {
|
||||
fetchPatientsForLoket(loketId);
|
||||
});
|
||||
const messageData = data?.data || data;
|
||||
const targetLoketId = messageData?.loketId || messageData?.idloket;
|
||||
|
||||
// 2. Refetch clinics to update quotas/availability
|
||||
if (targetLoketId) {
|
||||
// 1. If message specifies a loket, refresh that one specifically
|
||||
console.log(`🎯 [queueStore] WS targeting Loket ${targetLoketId}: Refreshing...`);
|
||||
fetchPatientsForLoket(targetLoketId);
|
||||
} else if (globalInterestCount.value > 0) {
|
||||
// 2. If it's a generic message and we have global interest (Check-in page open)
|
||||
// Trigger bulk staggered refresh
|
||||
console.log(`📡 [queueStore] WS generic message: Global Interest active, triggering staggered bulk refresh...`);
|
||||
fetchAllPatients();
|
||||
} else {
|
||||
// 3. Otherwise, only refresh lokets that currently have active interest (Admin tabs open)
|
||||
const interestingLokets = Object.keys(activeLoketInterest.value);
|
||||
if (interestingLokets.length > 0) {
|
||||
console.log(`🌐 [queueStore] WS generic message: Refreshing ${interestingLokets.length} active lokets:`, interestingLokets);
|
||||
interestingLokets.forEach(loketId => {
|
||||
fetchPatientsForLoket(loketId);
|
||||
});
|
||||
} else {
|
||||
console.log(`🔕 [queueStore] WS generic message: No active interest, skipping bulk refresh.`);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Base data sync
|
||||
clinicStore.fetchRegulerClinics();
|
||||
|
||||
// 3. Ensure base data is synced
|
||||
ensureInitialData();
|
||||
}
|
||||
});
|
||||
@@ -450,17 +502,40 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
/**
|
||||
* Global fetcher for all patients across all available lokets
|
||||
*/
|
||||
const fetchAllPatients = async () => {
|
||||
console.log('🔄 [queueStore] Fetching all patients for all lokets...');
|
||||
/**
|
||||
* Global fetcher for all patients across all available lokets
|
||||
* Uses staggered fetching to prevent 429 Too Many Requests errors.
|
||||
*/
|
||||
const fetchAllPatients = async (force = false) => {
|
||||
// 1. Cooldown Check: Prevent global refresh spam (max once every 5 seconds)
|
||||
const now = Date.now();
|
||||
if (!force && now - lastGlobalFetchTime.value < 5000) {
|
||||
console.log(`⏭️ [queueStore] fetchAllPatients: Global refresh on cooldown (${Math.round((now - lastGlobalFetchTime.value)/1000)}s ago)`);
|
||||
return;
|
||||
}
|
||||
lastGlobalFetchTime.value = now;
|
||||
|
||||
console.log('🔄 [queueStore] Fetching all patients for all lokets (Staggered)...');
|
||||
const allLokets = loketStore.lokets || [];
|
||||
if (allLokets.length === 0) {
|
||||
console.warn('⚠️ [queueStore] No lokets available for fetchAllPatients');
|
||||
return;
|
||||
}
|
||||
|
||||
// Use Promise.all for faster fetching
|
||||
await Promise.all(allLokets.map(l => fetchPatientsForLoket(l.id)));
|
||||
console.log(`✅ [queueStore] All patients fetched. Total: ${allPatients.value.length}`);
|
||||
// 2. Staggered Fetch: Instead of Promise.all, we fetch one by one with a small delay
|
||||
// This spreads the load and stays under the 429 threshold
|
||||
for (const loket of allLokets) {
|
||||
const id = loket.id || loket.no;
|
||||
if (id) {
|
||||
// We use await to wait for the fetch to finish, then wait a bit more
|
||||
await fetchPatientsForLoket(id);
|
||||
|
||||
// Wait 150ms between requests (not too long, but enough to breathe)
|
||||
await new Promise(resolve => setTimeout(resolve, 150));
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ [queueStore] Staggered bulk fetch completed. Total: ${allPatients.value.length} patients in memory.`);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -810,11 +885,11 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
// For example: { 'loket-1': patient, 'loket-2': patient, 'klinik-3': patient }
|
||||
const currentProcessingPatient = ref({});
|
||||
|
||||
// Daftar klinik untuk dropdown diambil 1 pintu dari clinicStore
|
||||
const kliniks = ref(clinicStore.clinics || []);
|
||||
// Daftar klinik untuk dropdown diambil 1 pintu dari clinicStore (Computed for stability)
|
||||
const kliniks = computed(() => clinicStore.clinics || []);
|
||||
|
||||
// Penunjang data - reference dari penunjangStore
|
||||
const penunjangs = ref(penunjangStore.penunjangs || []);
|
||||
// Penunjang data - reference dari penunjangStore (Computed for stability)
|
||||
const penunjangs = computed(() => penunjangStore.penunjangList || []);
|
||||
|
||||
const RESET_HOUR = 2; // 2 AM reset threshold
|
||||
|
||||
@@ -2582,6 +2657,11 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
initWebSocket,
|
||||
disconnectWebSocket,
|
||||
isWsConnected,
|
||||
registerInterest,
|
||||
unregisterInterest,
|
||||
activeLoketInterest,
|
||||
registerGlobalInterest,
|
||||
unregisterGlobalInterest,
|
||||
};
|
||||
|
||||
}, {
|
||||
|
||||
Reference in New Issue
Block a user