Merge branch 'Antrean-Code' of https://git.rssa.top/arie.bagus.2905/web-antrean into Antrean-Code

This commit is contained in:
bagus-arie05
2026-01-29 09:52:10 +07:00
3 changed files with 74 additions and 9 deletions
+1 -1
View File
@@ -93,7 +93,7 @@
<script setup lang="ts">
import { ref } from "vue";
import TabelData from "../components/TabelData.vue"; // Pastikan path-nya benar
import TabelData from "@/components/features/monitoring/TabelData.vue";
// Ini adalah data yang akan menjadi "single source of truth"
// untuk tabel Anda. Data ini dikirim sebagai props ke komponen anak.
+1 -1
View File
@@ -24,7 +24,7 @@
variant="flat"
@click="openTambahDialog"
elevation="0"
class="action-btn"
class="action-btn text-white"
>
<v-icon left size="20">mdi-plus-circle</v-icon>
Tambah Screen
+72 -7
View File
@@ -26,11 +26,24 @@ export const useQueueStore = defineStore('queue', () => {
* Sync patient status to apiPatientsPerLoket for reactivity
*/
const syncApiPatientStatus = (patient, newStatus) => {
if (!patient || patient.registrationType !== 'api') return;
if (!patient) return;
// Allow syncing if strictly 'api' OR if we can find a matching ID in the API store
// This handles cases where we have an 'onsite' patient locally that corresponds to an API patient
const loketId = patient.loketId;
if (loketId && apiPatientsPerLoket.value[loketId]) {
const index = apiPatientsPerLoket.value[loketId].findIndex(p => p.no === patient.no);
// Try to find patient in the API list
const index = apiPatientsPerLoket.value[loketId].findIndex(p => {
if (patient.registrationType === 'api' && p.no === patient.no) return true;
// Fallback matching for 'onsite' patients
if (patient.idtiket && p.idtiket && String(patient.idtiket) === String(p.idtiket)) return true;
if (patient.barcode && p.barcode && String(patient.barcode) === String(p.barcode)) return true;
return false;
});
if (index !== -1) {
const updated = [...apiPatientsPerLoket.value[loketId]];
updated[index] = { ...updated[index], status: newStatus };
@@ -258,18 +271,66 @@ export const useQueueStore = defineStore('queue', () => {
apiPatientsPerLoket.value[loketId] = finalPatients;
// IMPORTANT: Also merge into allPatients so callMultiplePatients can find them
// Remove any existing API patients for this loket first
allPatients.value = allPatients.value.filter(p =>
p.registrationType !== 'api' || String(p.loketId) !== String(loketId)
);
// Add new API patients with loketId assigned
// Prepare list of new API patients with loketId assigned
const patientsWithLoketId = finalPatients.map(p => ({
...p,
loketId: parseInt(loketId),
registrationType: 'api'
}));
// ROBUST DEDUPLICATION & STATUS MERGE
// 1. Identify matches between existing allPatients and new API patients
const newPatientMap = new Map();
patientsWithLoketId.forEach(p => {
const key = p.idtiket ? `id-${p.idtiket}` : `bc-${p.barcode}`;
newPatientMap.set(key, p);
});
// 2. Iterate existing patients to find matches and preserve status
const preservedStatuses = new Map();
allPatients.value.forEach(p => {
const key = p.idtiket ? `id-${p.idtiket}` : `bc-${p.barcode}`;
if (newPatientMap.has(key)) {
// If existing patient has more advanced status (waiting/di-loket), preserve it!
// This handles cases where we updated status locally ('onsite' or 'api') but API is lagging
const statusPriority = { 'di-loket': 3, 'waiting': 2, 'menunggu': 1 };
const existingPrio = statusPriority[p.status] || 0;
const newPatient = newPatientMap.get(key);
const newPrio = statusPriority[newPatient.status] || 0;
if (existingPrio > newPrio) {
preservedStatuses.set(key, p.status);
// Also preserve lastCalledAt/calledByAdmin if available
if (p.lastCalledAt) newPatient.lastCalledAt = p.lastCalledAt;
if (p.calledByAdmin) newPatient.calledByAdmin = p.calledByAdmin;
}
}
});
// 3. Update new patients with preserved status
patientsWithLoketId.forEach(p => {
const key = p.idtiket ? `id-${p.idtiket}` : `bc-${p.barcode}`;
if (preservedStatuses.has(key)) {
p.status = preservedStatuses.get(key);
}
});
// 4. Remove existing patients that collide with new ones (to be replaced)
// AND remove stale 'api' patients for this loket
allPatients.value = allPatients.value.filter(p => {
const key = p.idtiket ? `id-${p.idtiket}` : `bc-${p.barcode}`;
// Remove if it's being replaced by new batch
if (newPatientMap.has(key)) return false;
// Remove if it's a stale 'api' patient for this loket (that wasn't in the new batch)
if (p.registrationType === 'api' && String(p.loketId) === String(loketId)) return false;
return true;
});
// 5. Add merged patients
allPatients.value.push(...patientsWithLoketId);
console.log(`✅ [queueStore] Successfully fetched ${finalPatients.length} unique patients for loket ${loketId} (Original: ${mappedPatients.length})`);
@@ -757,6 +818,10 @@ export const useQueueStore = defineStore('queue', () => {
if (newState.allPatients) allPatients.value = newState.allPatients;
if (newState.quotaUsed !== undefined) quotaUsed.value = newState.quotaUsed;
if (newState.currentProcessingPatient) currentProcessingPatient.value = newState.currentProcessingPatient;
// FIX: Hydrate apiPatientsPerLoket as well since it is persisted.
// Failure to hydrate this causes "ping-pong" writes between tabs if they have different local values.
if (newState.apiPatientsPerLoket) apiPatientsPerLoket.value = newState.apiPatientsPerLoket;
}
} catch (e) {
console.error('Error hydrating from storage event:', e);