@7365admin1/layer-common 3.0.28 → 3.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/components/AccessCardDetailsDialog.vue +24 -11
- package/components/AccessCardPreviewDialog.vue +1 -0
- package/components/VehicleForm.vue +570 -285
- package/components/VisitorForm.vue +201 -79
- package/components/VisitorManagement.vue +43 -11
- package/composables/useAccessManagement.ts +1 -1
- package/composables/useVisitor.ts +34 -0
- package/package.json +1 -1
|
@@ -264,36 +264,90 @@
|
|
|
264
264
|
@update:people="handleAutofillDataViaVehicleNumber" />
|
|
265
265
|
</v-dialog>
|
|
266
266
|
|
|
267
|
-
<v-dialog v-model="dialog.showNonCheckedOutDialog" max-width="
|
|
268
|
-
<v-card :loading="loading.checkingOut">
|
|
269
|
-
<v-
|
|
270
|
-
<v-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
</
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
267
|
+
<v-dialog v-model="dialog.showNonCheckedOutDialog" max-width="1200">
|
|
268
|
+
<v-card :loading="loading.checkingOut || loading.searchingNonCheckedOut">
|
|
269
|
+
<v-card-actions class="justify-end bg-grey-lighten-3 pa-4">
|
|
270
|
+
<v-btn icon="mdi-close" variant="text" size="large" @click="dialog.showNonCheckedOutDialog = false" />
|
|
271
|
+
</v-card-actions>
|
|
272
|
+
|
|
273
|
+
<v-card-text class="pa-6">
|
|
274
|
+
<p class="text-subtitle-1 font-weight-medium mb-8">
|
|
275
|
+
The following list needs to check-out before proceeding to add related to the NRIC/Phone Number below:
|
|
276
|
+
</p>
|
|
277
|
+
|
|
278
|
+
<div class="text-subtitle-1 mb-8">
|
|
279
|
+
<div>NRIC: {{ visitor.nric || "N/A" }}</div>
|
|
280
|
+
<div>Phone Number: {{ visitor.contact || "N/A" }}</div>
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
<v-data-table
|
|
284
|
+
class="border rounded"
|
|
285
|
+
:headers="nonCheckedOutVisitorHeaders"
|
|
286
|
+
:items="matchingNonCheckedOutVisitors"
|
|
287
|
+
item-value="_id"
|
|
288
|
+
:items-per-page="5"
|
|
289
|
+
hide-default-footer
|
|
290
|
+
>
|
|
291
|
+
<template #item.name="{ item }">
|
|
292
|
+
<div class="d-flex align-center ga-3">
|
|
293
|
+
<v-avatar color="red" size="32">
|
|
294
|
+
<span class="text-white text-subtitle-2">{{ getVisitorInitial(item.name) }}</span>
|
|
295
|
+
</v-avatar>
|
|
296
|
+
<div>
|
|
297
|
+
<div class="font-weight-medium">{{ item.name || "N/A" }}</div>
|
|
298
|
+
<div class="text-caption">
|
|
299
|
+
<v-icon icon="mdi-card-account-details-outline" size="16" class="mr-1" />
|
|
300
|
+
{{ maskNRIC(item.nric) || "N/A" }}
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
</div>
|
|
304
|
+
</template>
|
|
305
|
+
|
|
306
|
+
<template #item.typeCompany="{ item }">
|
|
307
|
+
<div>
|
|
308
|
+
<v-icon icon="mdi-account" size="18" class="mr-2" />
|
|
309
|
+
{{ formatVisitorType(item.type) }}
|
|
310
|
+
</div>
|
|
311
|
+
<div>
|
|
312
|
+
<v-icon icon="mdi-office-building" size="18" class="mr-2" />
|
|
313
|
+
{{ item.company || "N/A" }}
|
|
314
|
+
</div>
|
|
315
|
+
</template>
|
|
316
|
+
|
|
317
|
+
<template #item.location="{ item }">
|
|
318
|
+
<v-icon icon="mdi-calendar-range" size="18" class="mr-2" />
|
|
319
|
+
{{ formatVisitorLocation(item) }}
|
|
320
|
+
</template>
|
|
321
|
+
|
|
322
|
+
<template #item.contactVehicle="{ item }">
|
|
323
|
+
<div>
|
|
324
|
+
<v-icon icon="mdi-phone" size="18" class="mr-2" />
|
|
325
|
+
{{ item.contact || "N/A" }}
|
|
326
|
+
</div>
|
|
327
|
+
<div>
|
|
328
|
+
<v-icon icon="mdi-car" size="18" class="mr-2" />
|
|
329
|
+
{{ item.plateNumber || "N/A" }}
|
|
330
|
+
</div>
|
|
331
|
+
</template>
|
|
332
|
+
|
|
333
|
+
<template #item.checkInOut="{ item }">
|
|
334
|
+
<div class="py-2">
|
|
335
|
+
<div class="mb-2">
|
|
336
|
+
<v-icon icon="mdi-clock-check-outline" color="green" size="20" class="mr-1" />
|
|
337
|
+
{{ formatNonCheckedOutDate(item.checkIn) }}
|
|
338
|
+
</div>
|
|
339
|
+
<v-btn size="small" class="text-none" color="red" variant="flat" :loading="loading.checkingOut && selectedCheckoutVisitorId === item._id" :disabled="!item._id" @click.stop="item._id && handleCheckout(item._id)">
|
|
340
|
+
Check Out
|
|
341
|
+
</v-btn>
|
|
342
|
+
</div>
|
|
343
|
+
</template>
|
|
344
|
+
</v-data-table>
|
|
345
|
+
|
|
346
|
+
<div class="d-flex justify-end mt-8">
|
|
347
|
+
<v-btn color="red" variant="flat" size="large" class="text-none px-10" :loading="loading.searchingNonCheckedOut" @click="handleSkipNricNonCheckedOut">
|
|
348
|
+
Skip NRIC: {{ visitor.nric || "N/A" }}
|
|
349
|
+
</v-btn>
|
|
350
|
+
</div>
|
|
297
351
|
</v-card-text>
|
|
298
352
|
</v-card>
|
|
299
353
|
</v-dialog>
|
|
@@ -414,12 +468,16 @@ const prop = defineProps({
|
|
|
414
468
|
type: String,
|
|
415
469
|
default: "",
|
|
416
470
|
},
|
|
471
|
+
enableUnregistered: {
|
|
472
|
+
type: Boolean,
|
|
473
|
+
default: false,
|
|
474
|
+
}
|
|
417
475
|
});
|
|
418
476
|
|
|
419
477
|
type AutofillSource = "nric" | "contact" | "vehicleNumber" | null;
|
|
420
478
|
const currentAutofillSource = ref<AutofillSource>(null);
|
|
421
479
|
|
|
422
|
-
const { requiredRule, debounce, UTCToLocalTIme } = useUtils();
|
|
480
|
+
const { requiredRule, debounce, UTCToLocalTIme, maskNRIC } = useUtils();
|
|
423
481
|
const { getSiteById } = useSiteSettings();
|
|
424
482
|
const { currentUser } = useLocalAuth();
|
|
425
483
|
const { getBlocksSelection, getLevelsSelection, getUnitSelection } =
|
|
@@ -428,8 +486,8 @@ const {
|
|
|
428
486
|
createVisitor,
|
|
429
487
|
typeFieldMap,
|
|
430
488
|
contractorTypes,
|
|
431
|
-
getVisitors,
|
|
432
489
|
checkSearchUncheckedOutUnregisteredVisitor,
|
|
490
|
+
searchVisitorObject,
|
|
433
491
|
updateVisitor,
|
|
434
492
|
} = useVisitor();
|
|
435
493
|
const { getBySiteId: getEntryPassSettingsBySiteId } =
|
|
@@ -491,6 +549,7 @@ const dialog = reactive({
|
|
|
491
549
|
const loading = reactive({
|
|
492
550
|
checkingOut: false,
|
|
493
551
|
checkingUnregisteredPlate: false,
|
|
552
|
+
searchingNonCheckedOut: false,
|
|
494
553
|
});
|
|
495
554
|
|
|
496
555
|
const validForm = ref(false);
|
|
@@ -515,7 +574,16 @@ const deliveryCompany = ref("");
|
|
|
515
574
|
const deliveryCompanyInput = ref("");
|
|
516
575
|
const deliveryCompanyList = ref<string[]>([]);
|
|
517
576
|
|
|
518
|
-
const
|
|
577
|
+
const matchingNonCheckedOutVisitors = ref<TVisitor[]>([]);
|
|
578
|
+
const selectedCheckoutVisitorId = ref<string | null>(null);
|
|
579
|
+
const skipNonCheckedOutNric = ref(false);
|
|
580
|
+
const nonCheckedOutVisitorHeaders = [
|
|
581
|
+
{ title: "Name/NRIC", key: "name", align: "start", sortable: false },
|
|
582
|
+
{ title: "Type / Company", key: "typeCompany", align: "start", sortable: false },
|
|
583
|
+
{ title: "Location", key: "location", align: "start", sortable: false },
|
|
584
|
+
{ title: "Contact / Vehicle No.", key: "contactVehicle", align: "start", sortable: false },
|
|
585
|
+
{ title: "Check In / Out", key: "checkInOut", align: "start", sortable: false, width: "200px" },
|
|
586
|
+
] as const;
|
|
519
587
|
const unregisteredPlateMatches = ref<TVisitor[]>([]);
|
|
520
588
|
const unregisteredPlateSearchText = ref("");
|
|
521
589
|
const selectedUnregisteredVisitor = ref<TVisitor | null>(null);
|
|
@@ -556,7 +624,7 @@ const showNextButton = computed(() => {
|
|
|
556
624
|
});
|
|
557
625
|
|
|
558
626
|
const enableUnregistered = computed(() => {
|
|
559
|
-
return prop.mode === "add" &&
|
|
627
|
+
return prop.mode === "add" && prop.enableUnregistered
|
|
560
628
|
});
|
|
561
629
|
|
|
562
630
|
const showShowKeysField = computed(() => {
|
|
@@ -705,6 +773,7 @@ watch(fetchPersonByNRICReq, (obj) => {
|
|
|
705
773
|
watch(
|
|
706
774
|
() => visitor.nric,
|
|
707
775
|
(value) => {
|
|
776
|
+
skipNonCheckedOutNric.value = false;
|
|
708
777
|
if (!value || value.length < 4) {
|
|
709
778
|
nricSearchMenu.value = false;
|
|
710
779
|
nricSearchResults.value = [];
|
|
@@ -712,6 +781,13 @@ watch(
|
|
|
712
781
|
}
|
|
713
782
|
);
|
|
714
783
|
|
|
784
|
+
watch(
|
|
785
|
+
() => visitor.contact,
|
|
786
|
+
() => {
|
|
787
|
+
skipNonCheckedOutNric.value = false;
|
|
788
|
+
}
|
|
789
|
+
);
|
|
790
|
+
|
|
715
791
|
function selectNricSearchResult(item: Partial<TPeople>) {
|
|
716
792
|
nricSearchMenu.value = false;
|
|
717
793
|
nricSearchResults.value = [];
|
|
@@ -752,52 +828,89 @@ watch(fetchCompanyListReq, (arr) => {
|
|
|
752
828
|
companyNames.value = arr?.flatMap((x) => x?.companyName);
|
|
753
829
|
}
|
|
754
830
|
});
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
site: prop.site,
|
|
765
|
-
plateNumber: visitor.plateNumber,
|
|
766
|
-
checkedOut: false,
|
|
767
|
-
status: "registered",
|
|
768
|
-
});
|
|
769
|
-
});
|
|
831
|
+
function getVisitorSearchItems(res: any): TVisitor[] {
|
|
832
|
+
const items =
|
|
833
|
+
res?.items ||
|
|
834
|
+
res?.data?.items ||
|
|
835
|
+
res?.data?.result?.items ||
|
|
836
|
+
res?.result?.items ||
|
|
837
|
+
[];
|
|
838
|
+
return Array.isArray(items) ? items : [];
|
|
839
|
+
}
|
|
770
840
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
841
|
+
function getVisitorInitial(name?: string | null) {
|
|
842
|
+
return name?.trim()?.charAt(0)?.toUpperCase() || "?";
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
function formatLocationPart(value: unknown) {
|
|
846
|
+
if (!value) return "";
|
|
847
|
+
if (typeof value === "string") return value;
|
|
848
|
+
if (typeof value === "object" && "name" in value) {
|
|
849
|
+
return String((value as { name?: string }).name || "");
|
|
779
850
|
}
|
|
780
|
-
|
|
851
|
+
return "";
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
function formatVisitorLocation(v: TVisitor) {
|
|
855
|
+
return [
|
|
856
|
+
formatLocationPart(v.block),
|
|
857
|
+
formatLocationPart(v.level),
|
|
858
|
+
v.unitName || formatLocationPart(v.unit),
|
|
859
|
+
].filter(Boolean).join(" / ") || "N/A";
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
function formatNonCheckedOutDate(date?: string) {
|
|
863
|
+
return date ? UTCToLocalTIme(date) : "N/A";
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
async function checkNonCheckedOutVisitorsBeforeSubmit(
|
|
867
|
+
options: { skipNric?: boolean; showDialog?: boolean } = {}
|
|
868
|
+
) {
|
|
869
|
+
const { skipNric = skipNonCheckedOutNric.value, showDialog = true } = options;
|
|
870
|
+
const nric = skipNric ? null : visitor.nric || null;
|
|
871
|
+
const contact = visitor.contact || null;
|
|
781
872
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
matchingPlateNumberNonCheckedOutArr.value = [];
|
|
873
|
+
if (!nric && !contact) {
|
|
874
|
+
matchingNonCheckedOutVisitors.value = [];
|
|
785
875
|
dialog.showNonCheckedOutDialog = false;
|
|
786
|
-
return;
|
|
876
|
+
return true;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
try {
|
|
880
|
+
loading.searchingNonCheckedOut = true;
|
|
881
|
+
const res = await searchVisitorObject({
|
|
882
|
+
page: 1,
|
|
883
|
+
limit: 1000,
|
|
884
|
+
site: prop.site,
|
|
885
|
+
searchObject: {
|
|
886
|
+
nric,
|
|
887
|
+
contact,
|
|
888
|
+
},
|
|
889
|
+
notCheckedOut: true,
|
|
890
|
+
});
|
|
891
|
+
const items = getVisitorSearchItems(res);
|
|
892
|
+
matchingNonCheckedOutVisitors.value = items;
|
|
893
|
+
dialog.showNonCheckedOutDialog = showDialog && items.length > 0;
|
|
894
|
+
return items.length === 0;
|
|
895
|
+
} catch (error: any) {
|
|
896
|
+
errorMessage.value =
|
|
897
|
+
error?.data?.message ||
|
|
898
|
+
error?.response?._data?.message ||
|
|
899
|
+
"Unable to check unchecked-out visitors. Please try again.";
|
|
900
|
+
return false;
|
|
901
|
+
} finally {
|
|
902
|
+
loading.searchingNonCheckedOut = false;
|
|
787
903
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
// debounceSearchVisitorsByPlateNumbers();
|
|
799
|
-
// }
|
|
800
|
-
// );
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
async function handleSkipNricNonCheckedOut() {
|
|
907
|
+
const canSubmit = await checkNonCheckedOutVisitorsBeforeSubmit({
|
|
908
|
+
skipNric: true,
|
|
909
|
+
});
|
|
910
|
+
if (!canSubmit) return;
|
|
911
|
+
skipNonCheckedOutNric.value = true;
|
|
912
|
+
dialog.showNonCheckedOutDialog = false;
|
|
913
|
+
}
|
|
801
914
|
|
|
802
915
|
async function handleCheckout(visitorId: string) {
|
|
803
916
|
if (!visitorId) {
|
|
@@ -807,19 +920,21 @@ async function handleCheckout(visitorId: string) {
|
|
|
807
920
|
|
|
808
921
|
try {
|
|
809
922
|
loading.checkingOut = true;
|
|
923
|
+
selectedCheckoutVisitorId.value = visitorId;
|
|
810
924
|
const res = await updateVisitor(visitorId as string, {
|
|
811
925
|
checkOut: new Date().toISOString(),
|
|
812
926
|
});
|
|
813
927
|
if (res) {
|
|
814
|
-
await
|
|
928
|
+
await checkNonCheckedOutVisitorsBeforeSubmit();
|
|
815
929
|
}
|
|
816
930
|
} catch (error: any) {
|
|
817
|
-
const
|
|
931
|
+
const checkoutErrorMessage = error?.response?._data?.message;
|
|
818
932
|
console.log("[ERROR]", error);
|
|
819
933
|
errorMessage.value =
|
|
820
|
-
|
|
934
|
+
checkoutErrorMessage || "An error occurred while checking out the vehicle.";
|
|
821
935
|
} finally {
|
|
822
936
|
loading.checkingOut = false;
|
|
937
|
+
selectedCheckoutVisitorId.value = null;
|
|
823
938
|
}
|
|
824
939
|
}
|
|
825
940
|
|
|
@@ -1200,7 +1315,7 @@ async function handleNextPage() {
|
|
|
1200
1315
|
else await submit();
|
|
1201
1316
|
}
|
|
1202
1317
|
|
|
1203
|
-
async function submit() {
|
|
1318
|
+
async function submit(options: { skipNonCheckedOutCheck?: boolean } = {}) {
|
|
1204
1319
|
formRef.value!.validate();
|
|
1205
1320
|
errorMessage.value = "";
|
|
1206
1321
|
if (!validForm.value) {
|
|
@@ -1209,6 +1324,13 @@ async function submit() {
|
|
|
1209
1324
|
}
|
|
1210
1325
|
|
|
1211
1326
|
if (passType.value === "HID_QR" && !validateHidQrPrinterConfig()) return;
|
|
1327
|
+
if (
|
|
1328
|
+
prop.mode === "add" &&
|
|
1329
|
+
!options.skipNonCheckedOutCheck &&
|
|
1330
|
+
!(await checkNonCheckedOutVisitorsBeforeSubmit())
|
|
1331
|
+
) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1212
1334
|
if (!(await checkUnregisteredPlateBeforeContinue("submit"))) return;
|
|
1213
1335
|
|
|
1214
1336
|
processing.value = true;
|
|
@@ -579,6 +579,7 @@
|
|
|
579
579
|
:visitor-data="selectedVisitorDataObject"
|
|
580
580
|
:current-user="currentUser._id"
|
|
581
581
|
:type="activeVisitorFormType"
|
|
582
|
+
:enable-unregistered="enableUnregistered"
|
|
582
583
|
@back="handleClickBack"
|
|
583
584
|
@done="handleVisitorFormDone"
|
|
584
585
|
@done:more="handleVisitorFormCreateMore"
|
|
@@ -1824,7 +1825,7 @@ const nfcCardReturnStatuses = ref<
|
|
|
1824
1825
|
const canConfirmCheckout = computed(() => {
|
|
1825
1826
|
const allEntries = [...passReturnStatuses.value, ...keyReturnStatuses.value];
|
|
1826
1827
|
return allEntries.every((entry) => {
|
|
1827
|
-
if (!entry.status ||
|
|
1828
|
+
if (!entry.status || ["In Use","Not Returned"].includes(entry.status)) return false;
|
|
1828
1829
|
if (
|
|
1829
1830
|
(entry.status === "Lost" || entry.status === "Damaged") &&
|
|
1830
1831
|
!entry.remarks.trim()
|
|
@@ -2190,29 +2191,60 @@ watch([searchInput, dateFrom, dateTo, filterTypes, activeTab], () => {
|
|
|
2190
2191
|
page.value = 1;
|
|
2191
2192
|
});
|
|
2192
2193
|
|
|
2193
|
-
|
|
2194
|
+
const syncVisitorFiltersFromRoute = () => {
|
|
2194
2195
|
const requestedTab = (route.query.tab as string) || "registered";
|
|
2195
|
-
|
|
2196
|
+
const nextTab = enableUnregisteredTab.value
|
|
2196
2197
|
? requestedTab
|
|
2197
2198
|
: requestedTab === "unregistered"
|
|
2198
2199
|
? "registered"
|
|
2199
2200
|
: requestedTab;
|
|
2200
|
-
|
|
2201
|
+
|
|
2202
|
+
if (activeTab.value !== nextTab) {
|
|
2203
|
+
activeTab.value = nextTab;
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
const nextSearch = (route.query.search as string) || "";
|
|
2207
|
+
if (searchInput.value !== nextSearch) {
|
|
2208
|
+
searchInput.value = nextSearch;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2201
2211
|
if (route.query.dateFrom) {
|
|
2202
|
-
|
|
2212
|
+
const nextDateFrom = normalizeDateOnly(route.query.dateFrom as string);
|
|
2213
|
+
if (dateFrom.value !== nextDateFrom) {
|
|
2214
|
+
dateFrom.value = nextDateFrom;
|
|
2215
|
+
}
|
|
2203
2216
|
}
|
|
2217
|
+
|
|
2204
2218
|
if (route.query.dateTo) {
|
|
2205
|
-
|
|
2219
|
+
const nextDateTo = normalizeDateOnly(route.query.dateTo as string);
|
|
2220
|
+
if (dateTo.value !== nextDateTo) {
|
|
2221
|
+
dateTo.value = nextDateTo;
|
|
2222
|
+
}
|
|
2206
2223
|
}
|
|
2224
|
+
|
|
2207
2225
|
if (activeTab.value === "registered") {
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
) as TVisitorType[];
|
|
2226
|
+
const nextFilterTypes = (
|
|
2227
|
+
(route.query.type as string)?.split(",") || []
|
|
2228
|
+
).filter(Boolean) as TVisitorType[];
|
|
2229
|
+
if (filterTypes.value.join(",") !== nextFilterTypes.join(",")) {
|
|
2230
|
+
filterTypes.value = nextFilterTypes;
|
|
2231
|
+
}
|
|
2211
2232
|
|
|
2212
|
-
|
|
2233
|
+
const nextDisplayNotCheckedOut =
|
|
2213
2234
|
(route.query.checkedOut as string) == "true" || false;
|
|
2235
|
+
if (displayNotCheckedOut.value !== nextDisplayNotCheckedOut) {
|
|
2236
|
+
displayNotCheckedOut.value = nextDisplayNotCheckedOut;
|
|
2237
|
+
}
|
|
2214
2238
|
}
|
|
2215
|
-
}
|
|
2239
|
+
};
|
|
2240
|
+
|
|
2241
|
+
onMounted(syncVisitorFiltersFromRoute);
|
|
2242
|
+
|
|
2243
|
+
watch(
|
|
2244
|
+
() => route.query,
|
|
2245
|
+
syncVisitorFiltersFromRoute,
|
|
2246
|
+
{ deep: true }
|
|
2247
|
+
);
|
|
2216
2248
|
|
|
2217
2249
|
const { socketUnregisteredVisitorTrigger, visitorSocketData } =
|
|
2218
2250
|
useVisitorSocket();
|
|
@@ -314,7 +314,7 @@ export default function useAccessManagement() {
|
|
|
314
314
|
);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
function assignUser(payload: { assignees: string[]; unit: string; type: string; acm_url: string }) {
|
|
317
|
+
function assignUser(payload: { assignees: string[]; unit: string; type: string; acm_url: string; id?: string }) {
|
|
318
318
|
return useNuxtApp().$api<Record<string, any>>(
|
|
319
319
|
`/api/access-management/assign-user`,
|
|
320
320
|
{ method: "POST", body: payload }
|
|
@@ -102,6 +102,17 @@ export default function () {
|
|
|
102
102
|
limit?: number;
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
+
type SearchVisitorObjectParams = {
|
|
106
|
+
page?: number;
|
|
107
|
+
limit?: number;
|
|
108
|
+
site: string;
|
|
109
|
+
searchObject: {
|
|
110
|
+
nric?: string | null;
|
|
111
|
+
contact?: string | null;
|
|
112
|
+
};
|
|
113
|
+
notCheckedOut?: boolean;
|
|
114
|
+
};
|
|
115
|
+
|
|
105
116
|
const tab = useState("visitorsTab", () => "visitor");
|
|
106
117
|
|
|
107
118
|
async function getVisitors({
|
|
@@ -187,6 +198,28 @@ export default function () {
|
|
|
187
198
|
});
|
|
188
199
|
}
|
|
189
200
|
|
|
201
|
+
async function searchVisitorObject({
|
|
202
|
+
page = 1,
|
|
203
|
+
limit = 1000,
|
|
204
|
+
site,
|
|
205
|
+
searchObject,
|
|
206
|
+
notCheckedOut = true,
|
|
207
|
+
}: SearchVisitorObjectParams) {
|
|
208
|
+
return await useNuxtApp().$api<Record<string, any>>(
|
|
209
|
+
"/api/visitors/search-object",
|
|
210
|
+
{
|
|
211
|
+
method: "POST",
|
|
212
|
+
body: {
|
|
213
|
+
page,
|
|
214
|
+
limit,
|
|
215
|
+
site,
|
|
216
|
+
searchObject,
|
|
217
|
+
notCheckedOut,
|
|
218
|
+
},
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
190
223
|
async function deleteVisitor(_id: string) {
|
|
191
224
|
return await useNuxtApp().$api<Record<string, any>>(
|
|
192
225
|
`/api/visitor-transactions/id/${_id}`,
|
|
@@ -227,6 +260,7 @@ export default function () {
|
|
|
227
260
|
createVisitor,
|
|
228
261
|
getVisitors,
|
|
229
262
|
checkSearchUncheckedOutUnregisteredVisitor,
|
|
263
|
+
searchVisitorObject,
|
|
230
264
|
updateVisitor,
|
|
231
265
|
deleteVisitor,
|
|
232
266
|
validateVisitorQrCode,
|