@7365admin1/layer-common 1.11.23 → 1.11.24
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/AreaChecklistHistoryMain.vue +1 -1
- package/components/CleaningScheduleMain.vue +10 -1
- package/components/EquipmentItemMain.vue +4 -2
- package/components/EquipmentManagementMain.vue +14 -10
- package/components/ManageChecklistMain.vue +13 -1
- package/components/ScanVisitorQRCode.vue +9 -2
- package/components/ScheduleAreaMain.vue +0 -1
- package/components/VisitorDataFromScannedQRCodeForm.vue +50 -20
- package/components/VisitorForm.vue +6 -8
- package/components/VisitorManagement.vue +123 -27
- package/composables/useVisitor.ts +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -97,7 +97,7 @@ const props = defineProps({
|
|
|
97
97
|
site: { type: String, required: true, default: "" },
|
|
98
98
|
scheduleAreaId: { type: String, required: true, default: "" },
|
|
99
99
|
type: { type: String, required: true, default: "cleaner" },
|
|
100
|
-
scheduleRoute: { type: String, default: "
|
|
100
|
+
scheduleRoute: { type: String, default: "pest-schedule" },
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
const { formatDate, back, debounce } = useUtils();
|
|
@@ -76,6 +76,15 @@
|
|
|
76
76
|
{{ value || "No Status" }}
|
|
77
77
|
</v-chip>
|
|
78
78
|
</template>
|
|
79
|
+
<template #item.completedAt="{ value }">
|
|
80
|
+
{{
|
|
81
|
+
formatDate
|
|
82
|
+
? formatDate(value)
|
|
83
|
+
: value
|
|
84
|
+
? new Date(value).toLocaleString()
|
|
85
|
+
: ""
|
|
86
|
+
}}
|
|
87
|
+
</template>
|
|
79
88
|
<template #item.download="{ item }">
|
|
80
89
|
<v-btn
|
|
81
90
|
v-if="canDownloadSchedule"
|
|
@@ -136,7 +145,7 @@ const headers = [
|
|
|
136
145
|
{ title: "Created Date", value: "createdAt" },
|
|
137
146
|
{ title: "Close in", value: "closeIn" },
|
|
138
147
|
{ title: "Status", value: "status" },
|
|
139
|
-
{ title: "Completion Date", value: "
|
|
148
|
+
{ title: "Completion Date", value: "completedAt" },
|
|
140
149
|
{ title: "", value: "download" },
|
|
141
150
|
];
|
|
142
151
|
const remainingTime = ref({} as Record<string, string>);
|
|
@@ -441,7 +441,6 @@
|
|
|
441
441
|
|
|
442
442
|
<script setup lang="ts">
|
|
443
443
|
import useEquipmentItem from "../composables/useEquipmentItem";
|
|
444
|
-
import { useEquipmentItemPermission } from "../composables/useEquipmentItemPermission";
|
|
445
444
|
import useEquipmentManagement from "../composables/useEquipmentManagement";
|
|
446
445
|
import useFile from "../composables/useFile";
|
|
447
446
|
import useUtils from "../composables/useUtils";
|
|
@@ -450,9 +449,12 @@ const props = defineProps({
|
|
|
450
449
|
orgId: { type: String, default: "" },
|
|
451
450
|
site: { type: String, default: "" },
|
|
452
451
|
serviceType: { type: String, default: "" },
|
|
452
|
+
canViewAllEquipmentItems: { type: Boolean, default: true },
|
|
453
|
+
canCreateEquipmentItem: { type: Boolean, default: false },
|
|
453
454
|
});
|
|
454
455
|
|
|
455
|
-
const
|
|
456
|
+
const canViewAllEquipmentItems = computed(() => props.canViewAllEquipmentItems);
|
|
457
|
+
const canCreateEquipmentItem = computed(() => props.canCreateEquipmentItem);
|
|
456
458
|
|
|
457
459
|
const items = ref<Array<Record<string, any>>>([]);
|
|
458
460
|
const siteName = ref<string>("");
|
|
@@ -247,7 +247,6 @@
|
|
|
247
247
|
<script setup lang="ts">
|
|
248
248
|
import useEquipment from "../composables/useEquipment";
|
|
249
249
|
import useStock from "../composables/useStock";
|
|
250
|
-
import { useEquipmentPermission } from "../composables/useEquipmentPermission";
|
|
251
250
|
import useUtils from "../composables/useUtils";
|
|
252
251
|
import useEquipmentManagement from "../composables/useEquipmentManagement";
|
|
253
252
|
|
|
@@ -255,17 +254,22 @@ const props = defineProps({
|
|
|
255
254
|
orgId: { type: String, default: "" },
|
|
256
255
|
site: { type: String, default: "" },
|
|
257
256
|
serviceType: { type: String, default: "" },
|
|
257
|
+
canViewEquipments: { type: Boolean, default: true },
|
|
258
|
+
canAddEquipment: { type: Boolean, default: false },
|
|
259
|
+
canUpdateEquipment: { type: Boolean, default: false },
|
|
260
|
+
canDeleteEquipment: { type: Boolean, default: false },
|
|
261
|
+
canAddStock: { type: Boolean, default: false },
|
|
262
|
+
canViewStock: { type: Boolean, default: true },
|
|
263
|
+
canRequestItem: { type: Boolean, default: false },
|
|
258
264
|
});
|
|
259
265
|
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
canRequestItem,
|
|
268
|
-
} = useEquipmentPermission();
|
|
266
|
+
const canViewEquipments = computed(() => props.canViewEquipments);
|
|
267
|
+
const canAddEquipment = computed(() => props.canAddEquipment);
|
|
268
|
+
const canUpdateEquipment = computed(() => props.canUpdateEquipment);
|
|
269
|
+
const canDeleteEquipment = computed(() => props.canDeleteEquipment);
|
|
270
|
+
const canAddStock = computed(() => props.canAddStock);
|
|
271
|
+
const canViewStock = computed(() => props.canViewStock);
|
|
272
|
+
const canRequestItem = computed(() => props.canRequestItem);
|
|
269
273
|
|
|
270
274
|
const items = ref<Array<Record<string, any>>>([]);
|
|
271
275
|
const siteName = ref<string>("");
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</v-col>
|
|
18
18
|
</v-row>
|
|
19
19
|
<TableHygiene
|
|
20
|
-
:title="
|
|
20
|
+
:title="scheduleTitle"
|
|
21
21
|
:headers="headers"
|
|
22
22
|
:items="items"
|
|
23
23
|
:item-value="'unit'"
|
|
@@ -319,6 +319,18 @@ const props = defineProps({
|
|
|
319
319
|
const { getUnitCleanerChecklist, updateUnitChecklist } = useCleaningSchedules();
|
|
320
320
|
const { getBySiteAsServiceProvider } = useCustomerSite();
|
|
321
321
|
const { back } = useUtils();
|
|
322
|
+
|
|
323
|
+
const route = useRoute();
|
|
324
|
+
const scheduleTitle = computed(() => {
|
|
325
|
+
const path = route.path;
|
|
326
|
+
if (path.includes('cleaning-schedule')) return 'Cleaning Checklist';
|
|
327
|
+
if (path.includes('technician-schedule')) return 'Technician Checklist';
|
|
328
|
+
if (path.includes('landscape-schedule')) return 'Landscape Checklist';
|
|
329
|
+
if (path.includes('pool-schedule')) return 'Pool Checklist';
|
|
330
|
+
if (path.includes('pest-schedule')) return 'Pest Checklist';
|
|
331
|
+
return 'Cleaner Checklist';
|
|
332
|
+
});
|
|
333
|
+
|
|
322
334
|
const canAddRemarks = computed(() => props.canAddRemarks);
|
|
323
335
|
const canManageScheduleTasks = computed(() => props.canManageScheduleTasks);
|
|
324
336
|
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<!-- This is where the QR code scanner will be displayed -->
|
|
33
33
|
</div>
|
|
34
34
|
<!-- Show Error Messages -->
|
|
35
|
-
<div v-if="showNotFoundMessage" class="text-error mt-4">
|
|
35
|
+
<div v-if="showNotFoundMessage" class="text-error mt-4 text-h5">
|
|
36
36
|
<p>{{ errorMessage }}</p>
|
|
37
37
|
</div>
|
|
38
38
|
<!-- Switch camera button inside the reader box -->
|
|
@@ -58,6 +58,8 @@ const props = defineProps({
|
|
|
58
58
|
},
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
const { standardFormatDate } = useUtils();
|
|
62
|
+
|
|
61
63
|
const { validateVisitorQrCode } = useVisitor();
|
|
62
64
|
|
|
63
65
|
const emits = defineEmits([
|
|
@@ -109,9 +111,14 @@ const handleScanVisitorQRCode = async () => {
|
|
|
109
111
|
console.log("validateVisitorQrCode", response);
|
|
110
112
|
if (response.errorMessage) {
|
|
111
113
|
showNotFoundMessage.value = true;
|
|
112
|
-
errorMessage.value =
|
|
114
|
+
errorMessage.value =
|
|
115
|
+
response.errorMessage +
|
|
116
|
+
(response.scheduledDate
|
|
117
|
+
? standardFormatDate(response.scheduledDate)
|
|
118
|
+
: "");
|
|
113
119
|
showMessage(errorMessage.value, "error");
|
|
114
120
|
} else {
|
|
121
|
+
closeDialog();
|
|
115
122
|
emits("openVisitorDataFromScannedQrCodeDialog", response);
|
|
116
123
|
}
|
|
117
124
|
} else {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
/>
|
|
29
29
|
</v-col>
|
|
30
30
|
|
|
31
|
-
<v-col cols="12">
|
|
31
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
32
32
|
<InputLabel class="text-capitalize" title="NRIC/Passport/ID No." />
|
|
33
33
|
<v-text-field
|
|
34
34
|
v-if="!visitorInfo.checkIn"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
/>
|
|
47
47
|
</v-col>
|
|
48
48
|
|
|
49
|
-
<v-col cols="12" class="mt-4">
|
|
49
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12" class="mt-4">
|
|
50
50
|
<InputLabel
|
|
51
51
|
class="text-capitalize"
|
|
52
52
|
title="Vehicle Number (Optional)"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
/>
|
|
68
68
|
</v-col>
|
|
69
69
|
|
|
70
|
-
<v-col cols="12" class="mt-4">
|
|
70
|
+
<!-- <v-col cols="12" class="mt-4">
|
|
71
71
|
<InputLabel class="text-capitalize" title="Type" />
|
|
72
72
|
<v-text-field
|
|
73
73
|
v-model="visitorInfo.type"
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
hide-details
|
|
76
76
|
readonly
|
|
77
77
|
/>
|
|
78
|
-
</v-col>
|
|
78
|
+
</v-col> -->
|
|
79
79
|
|
|
80
|
-
<v-col cols="12" class="mt-4">
|
|
80
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12" class="mt-4">
|
|
81
81
|
<InputLabel class="text-capitalize" title="Phone Number" />
|
|
82
82
|
<InputPhoneNumberV2
|
|
83
83
|
v-model="visitorInfo.contact"
|
|
@@ -87,32 +87,62 @@
|
|
|
87
87
|
</v-col>
|
|
88
88
|
|
|
89
89
|
<v-col cols="12">
|
|
90
|
+
<InputLabel class="text-capitalize" title="Location" />
|
|
91
|
+
<v-text-field v-model="location" density="comfortable" readonly />
|
|
92
|
+
</v-col>
|
|
93
|
+
|
|
94
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
90
95
|
<InputLabel class="text-capitalize" title="Purpose" />
|
|
91
96
|
<v-textarea
|
|
92
97
|
v-model="visitorInfo.purpose"
|
|
93
98
|
density="comfortable"
|
|
94
|
-
:rows="
|
|
99
|
+
:rows="2"
|
|
95
100
|
no-resize
|
|
96
101
|
readonly
|
|
97
102
|
/>
|
|
98
103
|
</v-col>
|
|
99
104
|
|
|
100
|
-
<v-col cols="12">
|
|
101
|
-
<InputLabel class="text-capitalize" title="
|
|
102
|
-
<v-
|
|
105
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
106
|
+
<InputLabel class="text-capitalize" title="Remarks" />
|
|
107
|
+
<v-textarea
|
|
108
|
+
v-model="visitorInfo.remarks"
|
|
109
|
+
density="comfortable"
|
|
110
|
+
:rows="2"
|
|
111
|
+
no-resize
|
|
112
|
+
/>
|
|
103
113
|
</v-col>
|
|
104
114
|
|
|
105
|
-
<v-col cols="12">
|
|
115
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
106
116
|
<InputLabel class="text-capitalize" title="Visitor Pass" />
|
|
107
117
|
<PassInformation
|
|
108
118
|
v-model:pass="visitorInfo.visitorPass"
|
|
109
119
|
:site="prop.site"
|
|
110
120
|
:type="visitorInfo.type"
|
|
121
|
+
:hideKeys="true"
|
|
111
122
|
:clearable="true"
|
|
112
123
|
/>
|
|
113
124
|
</v-col>
|
|
114
125
|
|
|
115
|
-
<v-col cols="12"
|
|
126
|
+
<v-col v-else cols="12">
|
|
127
|
+
<v-card elevation="4" height="100%" width="100%">
|
|
128
|
+
<v-col cols="12" class="d-flex justify-center pb-0">
|
|
129
|
+
<span
|
|
130
|
+
class="text-h6 font-weight-bold d-flex text-center text-success"
|
|
131
|
+
>
|
|
132
|
+
{{
|
|
133
|
+
visitorInfo.checkIn
|
|
134
|
+
? standardFormatDateTime(visitorInfo.checkIn)
|
|
135
|
+
: "N/A"
|
|
136
|
+
}}
|
|
137
|
+
</span>
|
|
138
|
+
</v-col>
|
|
139
|
+
<v-col cols="12" class="d-flex justify-center">
|
|
140
|
+
Actual Check In
|
|
141
|
+
</v-col>
|
|
142
|
+
</v-card>
|
|
143
|
+
</v-col>
|
|
144
|
+
|
|
145
|
+
<!-- <v-col cols="12" class="mt-4">
|
|
116
146
|
<v-row no-gutters class="pt-2">
|
|
117
147
|
<v-col cols="6" class="pr-1">
|
|
118
148
|
<v-card elevation="3" height="100%" width="100%">
|
|
@@ -151,7 +181,7 @@
|
|
|
151
181
|
</v-card>
|
|
152
182
|
</v-col>
|
|
153
183
|
</v-row>
|
|
154
|
-
</v-col>
|
|
184
|
+
</v-col> -->
|
|
155
185
|
</v-row>
|
|
156
186
|
<!-- </v-form> -->
|
|
157
187
|
</v-card-text>
|
|
@@ -177,7 +207,7 @@
|
|
|
177
207
|
<v-btn
|
|
178
208
|
v-if="visitorInfo.checkIn && !visitorInfo.checkOut"
|
|
179
209
|
block
|
|
180
|
-
text="Check Out"
|
|
210
|
+
text="Confirm Check Out"
|
|
181
211
|
variant="flat"
|
|
182
212
|
color="error"
|
|
183
213
|
size="48"
|
|
@@ -229,13 +259,13 @@ const visitorPlateNumber = computed({
|
|
|
229
259
|
set: () => {}, // readonly, do nothing on set
|
|
230
260
|
});
|
|
231
261
|
|
|
232
|
-
watchEffect(() => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
});
|
|
262
|
+
// watchEffect(() => {
|
|
263
|
+
// if (visitorInfo.value.plateNumber) {
|
|
264
|
+
// visitorInfo.value.type = "guest";
|
|
265
|
+
// } else {
|
|
266
|
+
// visitorInfo.value.type = "walk-in";
|
|
267
|
+
// }
|
|
268
|
+
// });
|
|
239
269
|
|
|
240
270
|
const location = computed({
|
|
241
271
|
get: () => {
|
|
@@ -475,15 +475,13 @@ async function handleAddNewContractorType() {
|
|
|
475
475
|
|
|
476
476
|
async function handleSelectCompanyName(company: string) {
|
|
477
477
|
visitor.company = company
|
|
478
|
+
// const selected = companyAutofillDataArray.value.find(x => x.companyName?.includes(company))
|
|
479
|
+
// if (!selected) return
|
|
478
480
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
visitor.
|
|
483
|
-
visitor.level = selected.level || ""
|
|
484
|
-
visitor.unit = selected.unit || ""
|
|
485
|
-
visitor.unitName = selected.unitName || ""
|
|
486
|
-
|
|
481
|
+
// visitor.block = selected.block || ""
|
|
482
|
+
// visitor.level = selected.level || ""
|
|
483
|
+
// visitor.unit = selected.unit || ""
|
|
484
|
+
// visitor.unitName = selected.unitName || ""
|
|
487
485
|
}
|
|
488
486
|
|
|
489
487
|
const companyCombo = ref(null)
|
|
@@ -297,6 +297,36 @@
|
|
|
297
297
|
</v-row>
|
|
298
298
|
</template>
|
|
299
299
|
|
|
300
|
+
<template v-slot:item.arrival-date-time="{ item }">
|
|
301
|
+
<v-row no-gutters class="d-flex flex-column py-2">
|
|
302
|
+
<span class="d-flex align-center ga-2">
|
|
303
|
+
<v-icon icon="mdi-calendar" size="20" />
|
|
304
|
+
{{ standardFormatDate(item.expectedCheckIn) || "-" }}
|
|
305
|
+
</span>
|
|
306
|
+
<span class="d-flex align-center ga-2">
|
|
307
|
+
<v-icon icon="mdi-clock-time-four-outline" size="20" />
|
|
308
|
+
{{ formatTime(item.expectedCheckIn) || "-" }}
|
|
309
|
+
</span>
|
|
310
|
+
|
|
311
|
+
<span v-if="!item.checkIn && canUpdateVisitor">
|
|
312
|
+
<span class="d-flex align-center ga-2 cursor-pointer">
|
|
313
|
+
<v-icon
|
|
314
|
+
icon="mdi-clock-time-eight-outline"
|
|
315
|
+
color="success"
|
|
316
|
+
size="20"
|
|
317
|
+
/>
|
|
318
|
+
<v-btn
|
|
319
|
+
size="x-small"
|
|
320
|
+
class="text-capitalize"
|
|
321
|
+
color="success"
|
|
322
|
+
text="Checkin"
|
|
323
|
+
@click.stop="handleCheckIn(item)"
|
|
324
|
+
/>
|
|
325
|
+
</span>
|
|
326
|
+
</span>
|
|
327
|
+
</v-row>
|
|
328
|
+
</template>
|
|
329
|
+
|
|
300
330
|
<template v-slot:item.action="{ item }">
|
|
301
331
|
<v-btn
|
|
302
332
|
v-if="activeTab === 'unregistered' && canAddVisitor"
|
|
@@ -496,6 +526,25 @@
|
|
|
496
526
|
<p class="text-body-2 mb-3">
|
|
497
527
|
Please ensure all passes and keys are returned before checking out.
|
|
498
528
|
</p>
|
|
529
|
+
|
|
530
|
+
<div>
|
|
531
|
+
<InputLabel class="text-capitalize" title="Full Name" />
|
|
532
|
+
<v-text-field
|
|
533
|
+
v-model="selectedVisitorObject.name"
|
|
534
|
+
density="comfortable"
|
|
535
|
+
readonly
|
|
536
|
+
/>
|
|
537
|
+
</div>
|
|
538
|
+
|
|
539
|
+
<div>
|
|
540
|
+
<InputLabel class="text-capitalize" title="Location" />
|
|
541
|
+
<v-text-field
|
|
542
|
+
v-model="selectedVisitorObject.location"
|
|
543
|
+
density="comfortable"
|
|
544
|
+
readonly
|
|
545
|
+
/>
|
|
546
|
+
</div>
|
|
547
|
+
|
|
499
548
|
<div v-if="passReturnStatuses.length > 0" class="mb-2">
|
|
500
549
|
<p class="text-caption text-medium-emphasis mb-1">Passes</p>
|
|
501
550
|
<v-row
|
|
@@ -709,10 +758,16 @@ const {
|
|
|
709
758
|
visitorSelection,
|
|
710
759
|
typeFieldMap,
|
|
711
760
|
updateVisitor,
|
|
712
|
-
|
|
761
|
+
visitorDataFromScannedQRCodeCheckIn,
|
|
713
762
|
} = useVisitor();
|
|
714
|
-
const {
|
|
715
|
-
|
|
763
|
+
const {
|
|
764
|
+
debounce,
|
|
765
|
+
formatCamelCaseToWords,
|
|
766
|
+
formatDate,
|
|
767
|
+
formatTime,
|
|
768
|
+
UTCToLocalTIme,
|
|
769
|
+
standardFormatDate,
|
|
770
|
+
} = useUtils();
|
|
716
771
|
const { formatLocation } = useSecurityUtils();
|
|
717
772
|
const { getFileUrlAnpr } = useFile();
|
|
718
773
|
// const { status: visitorStatus, search } = useRoute().query as { status: string, search: string};
|
|
@@ -775,7 +830,9 @@ const headers = computed(() => [
|
|
|
775
830
|
{ title: "Type/Company", value: "type-company" },
|
|
776
831
|
{ title: "Location", value: "location" },
|
|
777
832
|
{ title: "Contact/Vehicle No.", value: "contact-vehicleNumber" },
|
|
778
|
-
|
|
833
|
+
...(activeTab.value != "guests"
|
|
834
|
+
? [{ title: "Check In/Out", value: "checkin-out" }]
|
|
835
|
+
: [{ title: "Arrival Date / Time", value: "arrival-date-time" }]),
|
|
779
836
|
...(activeTab.value === "resident-transactions"
|
|
780
837
|
? [
|
|
781
838
|
{ title: "Check-in Remarks", value: "checkInRemarks" },
|
|
@@ -880,7 +937,7 @@ const {
|
|
|
880
937
|
|
|
881
938
|
if (activeTab.value === "guests") {
|
|
882
939
|
params.type = "guest";
|
|
883
|
-
params.status = "
|
|
940
|
+
params.status = "approved";
|
|
884
941
|
} else if (activeTab.value === "resident-transactions") {
|
|
885
942
|
params.status = "registered";
|
|
886
943
|
params.type = "resident,tenant";
|
|
@@ -916,7 +973,9 @@ watch(getVisitorReq, (newData: any) => {
|
|
|
916
973
|
const selectedVisitorObject = computed(() => {
|
|
917
974
|
const obj = items.value.find((x: any) => x?._id === selectedVisitorId.value);
|
|
918
975
|
if (!obj) return {};
|
|
976
|
+
|
|
919
977
|
const type = obj?.type as TVisitorType | undefined;
|
|
978
|
+
|
|
920
979
|
let includedKeys: string[] = [
|
|
921
980
|
"checkIn",
|
|
922
981
|
"checkOut",
|
|
@@ -925,9 +984,23 @@ const selectedVisitorObject = computed(() => {
|
|
|
925
984
|
"snapshotExitImage",
|
|
926
985
|
];
|
|
927
986
|
includedKeys.unshift(...(typeFieldMap[type] ?? []));
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
987
|
+
|
|
988
|
+
let locationString = "N/A";
|
|
989
|
+
|
|
990
|
+
if (obj?.block || obj?.level || obj?.unitName) {
|
|
991
|
+
locationString = `${obj.block} / ${obj.level} / ${obj.unitName}`;
|
|
992
|
+
} else if (obj?.block) {
|
|
993
|
+
locationString = obj.block;
|
|
994
|
+
} else {
|
|
995
|
+
locationString = "N/A";
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
return {
|
|
999
|
+
...Object.fromEntries(
|
|
1000
|
+
Object.entries(obj).filter(([key]) => includedKeys.includes(key))
|
|
1001
|
+
),
|
|
1002
|
+
location: locationString,
|
|
1003
|
+
};
|
|
931
1004
|
});
|
|
932
1005
|
|
|
933
1006
|
function formatValues(key: string, value: any) {
|
|
@@ -947,9 +1020,20 @@ function formatValues(key: string, value: any) {
|
|
|
947
1020
|
const visitorDataFromScannedQRCode = ref<Record<string, any>>({});
|
|
948
1021
|
|
|
949
1022
|
function handleShowVisitorDataFromScannedQRCodeDialog(
|
|
950
|
-
|
|
1023
|
+
scannedData: Record<string, any>
|
|
951
1024
|
) {
|
|
952
|
-
visitorDataFromScannedQRCode.value =
|
|
1025
|
+
visitorDataFromScannedQRCode.value = scannedData;
|
|
1026
|
+
|
|
1027
|
+
const { checkIn, checkOut, _id, visitorPass } = scannedData;
|
|
1028
|
+
const hasPasses = (visitorPass?.length ?? 0) > 0;
|
|
1029
|
+
|
|
1030
|
+
// 1. If they are checked in and HAVE passes/keys, go to the Return screen
|
|
1031
|
+
if (checkIn && !checkOut && hasPasses) {
|
|
1032
|
+
handleCheckout(_id);
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// 2. Default Case: Show visitor data (Entry, already checked out, or checked in with no passes)
|
|
953
1037
|
dialog.showVisitorDataFromScannedQRCode = true;
|
|
954
1038
|
}
|
|
955
1039
|
|
|
@@ -961,24 +1045,31 @@ async function handleVisitorDataFromScannedQRCodeCheckInOut(
|
|
|
961
1045
|
) {
|
|
962
1046
|
try {
|
|
963
1047
|
isVisitorDataFromScannedQRCodeCheckingInOut.value = true;
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1048
|
+
if (type != "checkOut") {
|
|
1049
|
+
await visitorDataFromScannedQRCodeCheckIn({
|
|
1050
|
+
type,
|
|
1051
|
+
filter: {
|
|
1052
|
+
_id: visitorData._id,
|
|
1053
|
+
},
|
|
1054
|
+
update: {
|
|
1055
|
+
updatedBy: currentUser.value._id,
|
|
1056
|
+
visitorPass: visitorData.visitorPass.find(
|
|
1057
|
+
(i: Record<string, any>) => i.keyId === null
|
|
1058
|
+
)
|
|
1059
|
+
? undefined
|
|
1060
|
+
: visitorData.visitorPass,
|
|
1061
|
+
nric: visitorData.nric ?? "",
|
|
1062
|
+
plateNumber: visitorData.plateNumber ?? "",
|
|
1063
|
+
},
|
|
1064
|
+
userType: "site",
|
|
1065
|
+
});
|
|
1066
|
+
showMessage("Visitor successfully checked-in!", "info");
|
|
1067
|
+
} else {
|
|
1068
|
+
selectedVisitorId.value = visitorData._id;
|
|
1069
|
+
await proceedCheckout();
|
|
1070
|
+
}
|
|
981
1071
|
handleCloseVisitorDataFromScannedQRCodeDialog();
|
|
1072
|
+
getVisitorRefresh();
|
|
982
1073
|
} catch (error) {
|
|
983
1074
|
showMessage(errorConverter(error), "error");
|
|
984
1075
|
} finally {
|
|
@@ -1171,6 +1262,11 @@ const canConfirmCheckout = computed(() => {
|
|
|
1171
1262
|
});
|
|
1172
1263
|
});
|
|
1173
1264
|
|
|
1265
|
+
async function handleCheckIn(user: Record<string, any>) {
|
|
1266
|
+
visitorDataFromScannedQRCode.value = user;
|
|
1267
|
+
dialog.showVisitorDataFromScannedQRCode = true;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1174
1270
|
function handleCheckout(userId: string) {
|
|
1175
1271
|
if (!userId) {
|
|
1176
1272
|
showMessage("Invalid userId", "error");
|
|
@@ -174,7 +174,7 @@ export default function () {
|
|
|
174
174
|
);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
function
|
|
177
|
+
function visitorDataFromScannedQRCodeCheckIn(payload: any) {
|
|
178
178
|
return useNuxtApp().$api<Record<string, any>>("/api/visitors/update-one", {
|
|
179
179
|
method: "PUT",
|
|
180
180
|
body: payload,
|
|
@@ -191,6 +191,6 @@ export default function () {
|
|
|
191
191
|
deleteVisitor,
|
|
192
192
|
validateVisitorQrCode,
|
|
193
193
|
updateVisitorPassKey,
|
|
194
|
-
|
|
194
|
+
visitorDataFromScannedQRCodeCheckIn,
|
|
195
195
|
};
|
|
196
196
|
}
|