@7365admin1/layer-common 1.11.28 → 1.11.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.
|
@@ -1,95 +1,51 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-row no-gutters>
|
|
3
|
-
<TableMain
|
|
4
|
-
:
|
|
5
|
-
:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
<TableMain :headers="headers" :items="items" :loading="getVisitorPending" :page="page" :pages="pages"
|
|
4
|
+
:extension-height="110" :offset="300" :pageRange="pageRange" @refresh="getVisitorRefresh"
|
|
5
|
+
@update:page="handleUpdatePage" show-header @row-click="handleRowClick">
|
|
6
|
+
<template #actions>
|
|
7
|
+
<v-row no-gutters>
|
|
8
|
+
<v-btn v-if="canAddVisitor" class="text-none" rounded="pill" variant="tonal" size="large"
|
|
9
|
+
@click="handleAddNew" text="Add Visitor" />
|
|
10
|
+
<v-btn v-if="canScanVisitorQRCode" text="Scan QR Code" class="text-none ml-2" rounded="pill" variant="tonal"
|
|
11
|
+
size="large" @click="dialog.scanVisitorQRCode = true" />
|
|
12
|
+
<v-menu>
|
|
13
|
+
<template #activator="{ props }">
|
|
14
|
+
<v-btn v-bind="props" text="Download Report" class="text-none ml-2" prepend-icon="mdi-download"
|
|
15
|
+
rounded="pill" variant="tonal" size="large" />
|
|
16
|
+
</template>
|
|
17
|
+
<v-list>
|
|
18
|
+
<v-list-item prepend-icon="mdi-file-pdf" title="Download PDF Report" @click="handleDownloadPDFReport" />
|
|
19
|
+
<v-list-item prepend-icon="mdi-file-csv" title="Download CSV Report" @click="handleDownloadCSVReport" />
|
|
20
|
+
</v-list>
|
|
21
|
+
</v-menu>
|
|
22
|
+
</v-row>
|
|
23
|
+
</template>
|
|
22
24
|
<template #extension>
|
|
23
25
|
<v-row no-gutters class="w-100 d-flex flex-column">
|
|
24
|
-
<v-tabs
|
|
25
|
-
v-
|
|
26
|
-
color="primary"
|
|
27
|
-
:height="40"
|
|
28
|
-
@update:model-value="toRoute"
|
|
29
|
-
class="w-100"
|
|
30
|
-
>
|
|
31
|
-
<v-tab
|
|
32
|
-
v-for="tab in tabOptions"
|
|
33
|
-
:value="tab.value"
|
|
34
|
-
:key="tab.value"
|
|
35
|
-
class="text-capitalize"
|
|
36
|
-
>
|
|
26
|
+
<v-tabs v-model="activeTab" color="primary" :height="40" @update:model-value="toRoute" class="w-100">
|
|
27
|
+
<v-tab v-for="tab in tabOptions" :value="tab.value" :key="tab.value" class="text-capitalize">
|
|
37
28
|
{{ tab.name }}
|
|
38
29
|
</v-tab>
|
|
39
30
|
</v-tabs>
|
|
40
31
|
|
|
41
|
-
<v-card
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
>
|
|
46
|
-
<v-text-field
|
|
47
|
-
v-model="searchInput"
|
|
48
|
-
density="compact"
|
|
49
|
-
placeholder="Search"
|
|
50
|
-
clearable
|
|
51
|
-
max-width="300"
|
|
52
|
-
append-inner-icon="mdi-magnify"
|
|
53
|
-
hide-details
|
|
54
|
-
/>
|
|
55
|
-
<v-checkbox
|
|
56
|
-
v-model="displayNotCheckedOut"
|
|
57
|
-
class="text-subtitle-2"
|
|
58
|
-
hide-details
|
|
59
|
-
>
|
|
32
|
+
<v-card class="w-100 px-3 d-flex align-center ga-5 py-2" flat :height="60">
|
|
33
|
+
<v-text-field v-model="searchInput" density="compact" placeholder="Search" clearable max-width="300"
|
|
34
|
+
append-inner-icon="mdi-magnify" hide-details />
|
|
35
|
+
<v-checkbox v-model="displayNotCheckedOut" class="text-subtitle-2" hide-details>
|
|
60
36
|
<template #label>
|
|
61
37
|
<span class="text-caption">Not Checked Out</span>
|
|
62
38
|
</template>
|
|
63
39
|
</v-checkbox>
|
|
64
|
-
<InputDatePicker
|
|
65
|
-
v-model="dateFrom"
|
|
66
|
-
density="compact"
|
|
67
|
-
hide-details
|
|
68
|
-
/>
|
|
40
|
+
<InputDatePicker v-model="dateFrom" density="compact" hide-details />
|
|
69
41
|
<InputDatePicker v-model="dateTo" density="compact" hide-details />
|
|
70
|
-
<v-select
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
label="Filter by types"
|
|
74
|
-
item-title="label"
|
|
75
|
-
item-value="value"
|
|
76
|
-
:items="visitorSelection"
|
|
77
|
-
density="compact"
|
|
78
|
-
clearable
|
|
79
|
-
multiple
|
|
80
|
-
max-width="200"
|
|
81
|
-
hide-details
|
|
82
|
-
>
|
|
42
|
+
<v-select v-if="activeTab == 'registered'" v-model="filterTypes" label="Filter by types" item-title="label"
|
|
43
|
+
item-value="value" :items="visitorSelection" density="compact" clearable multiple max-width="200"
|
|
44
|
+
hide-details>
|
|
83
45
|
<template v-slot:selection="{ item, index }">
|
|
84
46
|
<div class="d-flex align-center text-caption text-nowrap">
|
|
85
|
-
<v-chip
|
|
86
|
-
|
|
87
|
-
color="error"
|
|
88
|
-
:text="filterTypeSelectionLabel()"
|
|
89
|
-
size="x-small"
|
|
90
|
-
variant="tonal"
|
|
91
|
-
class="ml-2"
|
|
92
|
-
/>
|
|
47
|
+
<v-chip v-if="index === 0" color="error" :text="filterTypeSelectionLabel()" size="x-small"
|
|
48
|
+
variant="tonal" class="ml-2" />
|
|
93
49
|
</div>
|
|
94
50
|
</template>
|
|
95
51
|
</v-select>
|
|
@@ -104,9 +60,8 @@
|
|
|
104
60
|
</span>
|
|
105
61
|
<span class="text-capitalize">{{ item?.name }}</span>
|
|
106
62
|
</span>
|
|
107
|
-
<span class="text-grey text-caption" v-if="item?.members?.length > 0"
|
|
108
|
-
|
|
109
|
-
>
|
|
63
|
+
<span class="text-grey text-caption" v-if="item?.members?.length > 0">( +{{ item?.members?.length }}
|
|
64
|
+
members)</span>
|
|
110
65
|
</template>
|
|
111
66
|
|
|
112
67
|
<template v-slot:item.email="{ value }">
|
|
@@ -115,12 +70,7 @@
|
|
|
115
70
|
|
|
116
71
|
<template v-slot:item.invited-by="{ item }">
|
|
117
72
|
<span class="d-flex align-center ga-2">
|
|
118
|
-
<AvatarMain
|
|
119
|
-
v-if="item?.inviterName"
|
|
120
|
-
:name="item?.inviterName"
|
|
121
|
-
:size="20"
|
|
122
|
-
:id="item?._id"
|
|
123
|
-
/>
|
|
73
|
+
<AvatarMain v-if="item?.inviterName" :name="item?.inviterName" :size="20" :id="item?._id" />
|
|
124
74
|
<span class="text-capitalize">{{ item?.inviterName ?? "N/A" }}</span>
|
|
125
75
|
</span>
|
|
126
76
|
</template>
|
|
@@ -130,7 +80,7 @@
|
|
|
130
80
|
<v-icon icon="mdi-user" size="15" />
|
|
131
81
|
<span v-if="item.type === 'contractor'" class="text-capitalize">{{
|
|
132
82
|
formatCamelCaseToWords(item.contractorType)
|
|
133
|
-
|
|
83
|
+
}}</span>
|
|
134
84
|
<span v-else class="text-capitalize">{{ formatType(item) }}</span>
|
|
135
85
|
</span>
|
|
136
86
|
<span class="d-flex align-center ga-2">
|
|
@@ -166,52 +116,26 @@
|
|
|
166
116
|
<template v-slot:item.checkin-out="{ item }">
|
|
167
117
|
<v-row no-gutters class="d-flex flex-column py-2">
|
|
168
118
|
<span class="d-flex align-center ga-2">
|
|
169
|
-
<v-icon
|
|
170
|
-
icon="mdi-clock-time-four-outline"
|
|
171
|
-
color="green"
|
|
172
|
-
size="20"
|
|
173
|
-
/>
|
|
119
|
+
<v-icon icon="mdi-clock-time-four-outline" color="green" size="20" />
|
|
174
120
|
<span class="text-capitalize">{{
|
|
175
121
|
UTCToLocalTIme(item.checkIn) || "-"
|
|
176
|
-
|
|
122
|
+
}}</span>
|
|
177
123
|
<span>
|
|
178
|
-
<v-icon
|
|
179
|
-
|
|
180
|
-
size="17"
|
|
181
|
-
icon="mdi-image"
|
|
182
|
-
@click.stop="handleViewImage(item.snapshotEntryImage)"
|
|
183
|
-
/>
|
|
124
|
+
<v-icon v-if="item?.snapshotEntryImage" size="17" icon="mdi-image"
|
|
125
|
+
@click.stop="handleViewImage(item.snapshotEntryImage)" />
|
|
184
126
|
</span>
|
|
185
127
|
</span>
|
|
186
128
|
|
|
187
|
-
<span
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
"
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
v-bind="menuProps"
|
|
198
|
-
style="cursor: pointer"
|
|
199
|
-
>
|
|
200
|
-
<v-icon
|
|
201
|
-
icon="mdi-clock-time-eight-outline"
|
|
202
|
-
color="red"
|
|
203
|
-
size="20"
|
|
204
|
-
/>
|
|
205
|
-
<v-btn
|
|
206
|
-
size="x-small"
|
|
207
|
-
class="text-capitalize"
|
|
208
|
-
color="red"
|
|
209
|
-
text="Checkout"
|
|
210
|
-
:loading="
|
|
211
|
-
loading.checkingOut && item?._id === selectedVisitorId
|
|
212
|
-
"
|
|
213
|
-
@click.stop="handleCheckout(item._id)"
|
|
214
|
-
/>
|
|
129
|
+
<span v-if="
|
|
130
|
+
!item.checkOut &&
|
|
131
|
+
(item?.status === 'registered' ||
|
|
132
|
+
item?.status === 'unregistered') &&
|
|
133
|
+
canCheckoutVisitor
|
|
134
|
+
">
|
|
135
|
+
<span class="d-flex align-center ga-2" v-bind="menuProps" style="cursor: pointer">
|
|
136
|
+
<v-icon icon="mdi-clock-time-eight-outline" color="red" size="20" />
|
|
137
|
+
<v-btn size="x-small" class="text-capitalize" color="red" text="Checkout" :loading="loading.checkingOut && item?._id === selectedVisitorId
|
|
138
|
+
" @click.stop="handleCheckout(item._id)" />
|
|
215
139
|
</span>
|
|
216
140
|
</span>
|
|
217
141
|
<span v-else class="d-flex align-center ga-2">
|
|
@@ -219,95 +143,49 @@
|
|
|
219
143
|
<template v-if="item.checkOut">
|
|
220
144
|
<span class="text-capitalize">{{
|
|
221
145
|
UTCToLocalTIme(item.checkOut) || "-"
|
|
222
|
-
|
|
146
|
+
}}</span>
|
|
223
147
|
<span>
|
|
224
|
-
<v-icon
|
|
225
|
-
|
|
226
|
-
size="17"
|
|
227
|
-
icon="mdi-image"
|
|
228
|
-
@click.stop="handleViewImage(item.snapshotExitImage)"
|
|
229
|
-
/>
|
|
148
|
+
<v-icon v-if="item?.snapshotExitImage" size="17" icon="mdi-image"
|
|
149
|
+
@click.stop="handleViewImage(item.snapshotExitImage)" />
|
|
230
150
|
</span>
|
|
231
151
|
<span v-if="item?.manualCheckout">
|
|
232
|
-
<TooltipInfo
|
|
233
|
-
text="Manual Checkout"
|
|
234
|
-
density="compact"
|
|
235
|
-
size="x-small"
|
|
236
|
-
/>
|
|
152
|
+
<TooltipInfo text="Manual Checkout" density="compact" size="x-small" />
|
|
237
153
|
</span>
|
|
238
154
|
</template>
|
|
239
155
|
</span>
|
|
240
156
|
|
|
241
|
-
<div
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
style="cursor: pointer"
|
|
246
|
-
>
|
|
247
|
-
<v-chip
|
|
248
|
-
size="x-small"
|
|
249
|
-
variant="tonal"
|
|
250
|
-
prepend-icon="mdi-key"
|
|
251
|
-
@click.stop="handleOpenAddPassKey(item)"
|
|
252
|
-
>Add Pass/Key</v-chip
|
|
253
|
-
>
|
|
157
|
+
<div v-if="showAddPassKeyButton(item)" class="d-flex flex-wrap ga-1 mt-1" v-bind="menuProps"
|
|
158
|
+
style="cursor: pointer">
|
|
159
|
+
<v-chip size="x-small" variant="tonal" prepend-icon="mdi-key" @click.stop="handleOpenAddPassKey(item)">Add
|
|
160
|
+
Pass/Key</v-chip>
|
|
254
161
|
</div>
|
|
255
162
|
|
|
256
163
|
<v-menu :close-on-content-click="true">
|
|
257
164
|
<template v-slot:activator="{ props: menuProps }">
|
|
258
|
-
<div
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
"
|
|
263
|
-
|
|
264
|
-
v-bind="menuProps"
|
|
265
|
-
style="cursor: pointer"
|
|
266
|
-
>
|
|
267
|
-
<v-chip
|
|
268
|
-
v-for="pass in item.visitorPass"
|
|
269
|
-
:key="(pass as any)._id ?? (pass as any).keyId"
|
|
270
|
-
prepend-icon="mdi-card-bulleted-outline"
|
|
271
|
-
size="x-small"
|
|
272
|
-
variant="tonal"
|
|
273
|
-
color="blue"
|
|
274
|
-
>
|
|
165
|
+
<div v-if="
|
|
166
|
+
(item.visitorPass?.length ?? 0) > 0 ||
|
|
167
|
+
(item.passKeys?.length ?? 0) > 0
|
|
168
|
+
" class="d-flex flex-wrap ga-1 mt-1" v-bind="menuProps" style="cursor: pointer">
|
|
169
|
+
<v-chip v-for="pass in item.visitorPass" :key="(pass as any)._id ?? (pass as any).keyId"
|
|
170
|
+
prepend-icon="mdi-card-bulleted-outline" size="x-small" variant="tonal" color="blue">
|
|
275
171
|
{{ (pass as any)?.prefixAndName }}
|
|
276
172
|
</v-chip>
|
|
277
|
-
<v-chip
|
|
278
|
-
|
|
279
|
-
:key="(key as any)._id ?? (key as any).keyId"
|
|
280
|
-
prepend-icon="mdi-key"
|
|
281
|
-
size="x-small"
|
|
282
|
-
variant="tonal"
|
|
283
|
-
color="orange"
|
|
284
|
-
>
|
|
173
|
+
<v-chip v-for="key in item.passKeys" :key="(key as any)._id ?? (key as any).keyId"
|
|
174
|
+
prepend-icon="mdi-key" size="x-small" variant="tonal" color="orange">
|
|
285
175
|
{{ (key as any)?.prefixAndName }}
|
|
286
176
|
</v-chip>
|
|
287
177
|
</div>
|
|
288
178
|
</template>
|
|
289
179
|
<v-list density="compact">
|
|
290
|
-
<v-list-item
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
(item.passKeys?.length ?? 0) > 0
|
|
300
|
-
"
|
|
301
|
-
prepend-icon="mdi-card-bulleted-outline"
|
|
302
|
-
:title="item.checkOut ? 'View Pass/Key' : 'Edit Pass/Key'"
|
|
303
|
-
@click.stop="handleOpenEditPassKey(item)"
|
|
304
|
-
/>
|
|
305
|
-
<v-list-item
|
|
306
|
-
v-if="showAddPassKeyButton(item)"
|
|
307
|
-
prepend-icon="mdi-plus"
|
|
308
|
-
title="Add Pass/Key"
|
|
309
|
-
@click.stop="handleOpenAddPassKey(item)"
|
|
310
|
-
/>
|
|
180
|
+
<v-list-item v-if="!item?.checkOut" prepend-icon="mdi-logout" title="Checkout"
|
|
181
|
+
@click.stop="handleCheckout(item._id)" />
|
|
182
|
+
<v-list-item v-if="
|
|
183
|
+
(item.visitorPass?.length ?? 0) > 0 ||
|
|
184
|
+
(item.passKeys?.length ?? 0) > 0
|
|
185
|
+
" prepend-icon="mdi-card-bulleted-outline" :title="item.checkOut ? 'View Pass/Key' : 'Edit Pass/Key'"
|
|
186
|
+
@click.stop="handleOpenEditPassKey(item)" />
|
|
187
|
+
<v-list-item v-if="showAddPassKeyButton(item)" prepend-icon="mdi-plus" title="Add Pass/Key"
|
|
188
|
+
@click.stop="handleOpenAddPassKey(item)" />
|
|
311
189
|
</v-list>
|
|
312
190
|
</v-menu>
|
|
313
191
|
</v-row>
|
|
@@ -326,44 +204,27 @@
|
|
|
326
204
|
|
|
327
205
|
<span v-if="!item.checkIn && canUpdateVisitor">
|
|
328
206
|
<span class="d-flex align-center ga-2 cursor-pointer">
|
|
329
|
-
<v-icon
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
size="20"
|
|
333
|
-
/>
|
|
334
|
-
<v-btn
|
|
335
|
-
size="x-small"
|
|
336
|
-
class="text-capitalize"
|
|
337
|
-
color="success"
|
|
338
|
-
text="Checkin"
|
|
339
|
-
@click.stop="handleCheckin(item)"
|
|
340
|
-
/>
|
|
207
|
+
<v-icon icon="mdi-clock-time-eight-outline" color="success" size="20" />
|
|
208
|
+
<v-btn size="x-small" class="text-capitalize" color="success" text="Checkin"
|
|
209
|
+
@click.stop="handleCheckin(item)" />
|
|
341
210
|
</span>
|
|
342
211
|
</span>
|
|
343
212
|
</v-row>
|
|
344
213
|
</template>
|
|
345
214
|
|
|
346
215
|
<template v-slot:item.status="{ item }">
|
|
347
|
-
<v-card
|
|
348
|
-
v-if="item?.overnightParking?.status"
|
|
349
|
-
size="small"
|
|
216
|
+
<v-card v-if="item?.overnightParking?.status" size="small"
|
|
350
217
|
class="rounded-xl text-capitalize text-center elevation-0 py-1 px-2"
|
|
351
218
|
:color="getOvernightParkingRequestStatusColor(item?.overnightParking?.status as string)"
|
|
352
|
-
style="max-width: 150px; margin: auto"
|
|
353
|
-
>
|
|
219
|
+
style="max-width: 150px; margin: auto">
|
|
354
220
|
{{ item?.overnightParking?.status }}
|
|
355
221
|
</v-card>
|
|
356
222
|
<span v-else> N/A </span>
|
|
357
223
|
</template>
|
|
358
224
|
|
|
359
225
|
<template v-slot:item.action="{ item }">
|
|
360
|
-
<v-btn
|
|
361
|
-
|
|
362
|
-
size="small"
|
|
363
|
-
color="primary"
|
|
364
|
-
text="Register"
|
|
365
|
-
@click.stop="handleRegistrationUnregisteredVisitor(item)"
|
|
366
|
-
/>
|
|
226
|
+
<v-btn v-if="activeTab === 'unregistered' && canAddVisitor" size="small" color="primary" text="Register"
|
|
227
|
+
@click.stop="handleRegistrationUnregisteredVisitor(item)" />
|
|
367
228
|
<v-menu v-else-if="activeTab === 'overnight-parking'">
|
|
368
229
|
<template #activator="{ props }">
|
|
369
230
|
<v-avatar v-bind="props" class="rounded-xl border-md">
|
|
@@ -372,20 +233,17 @@
|
|
|
372
233
|
</template>
|
|
373
234
|
|
|
374
235
|
<v-card>
|
|
375
|
-
<v-list-item
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
)
|
|
387
|
-
"
|
|
388
|
-
>
|
|
236
|
+
<v-list-item v-if="
|
|
237
|
+
!overNightParkingListActions[0].disabled ||
|
|
238
|
+
!['approved', 'rejected'].includes(
|
|
239
|
+
item?.overnightParking?.status
|
|
240
|
+
)
|
|
241
|
+
" @click.stop="
|
|
242
|
+
openApproveRejectOverNightParkingRequestDialog(
|
|
243
|
+
item,
|
|
244
|
+
overNightParkingListActions[0].status
|
|
245
|
+
)
|
|
246
|
+
">
|
|
389
247
|
<template #title>
|
|
390
248
|
<span class="text-caption">
|
|
391
249
|
{{ overNightParkingListActions[0].text }}
|
|
@@ -393,36 +251,30 @@
|
|
|
393
251
|
</template>
|
|
394
252
|
</v-list-item>
|
|
395
253
|
<v-divider />
|
|
396
|
-
<v-list-item
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
)
|
|
408
|
-
"
|
|
409
|
-
>
|
|
254
|
+
<v-list-item v-if="
|
|
255
|
+
!overNightParkingListActions[1].disabled ||
|
|
256
|
+
!['approved', 'rejected'].includes(
|
|
257
|
+
item?.overnightParking?.status
|
|
258
|
+
)
|
|
259
|
+
" @click="
|
|
260
|
+
openApproveRejectOverNightParkingRequestDialog(
|
|
261
|
+
item,
|
|
262
|
+
overNightParkingListActions[1].status
|
|
263
|
+
)
|
|
264
|
+
">
|
|
410
265
|
<template #title>
|
|
411
266
|
<span class="text-caption">
|
|
412
267
|
{{ overNightParkingListActions[1].text }}
|
|
413
268
|
</span>
|
|
414
269
|
</template>
|
|
415
270
|
</v-list-item>
|
|
416
|
-
<v-list-item
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
)
|
|
424
|
-
"
|
|
425
|
-
>
|
|
271
|
+
<v-list-item v-if="item?.overnightParking?.remarks" @click="
|
|
272
|
+
openApproveRejectOverNightParkingRequestDialog(
|
|
273
|
+
item,
|
|
274
|
+
overNightParkingListActions[2].status,
|
|
275
|
+
item?.overnightParking?.remarks
|
|
276
|
+
)
|
|
277
|
+
">
|
|
426
278
|
<template #title>
|
|
427
279
|
<span class="text-caption">
|
|
428
280
|
{{ overNightParkingListActions[2].text }}
|
|
@@ -436,118 +288,61 @@
|
|
|
436
288
|
|
|
437
289
|
<template v-slot:item.checkInRemarks="{ item }">
|
|
438
290
|
<span>
|
|
439
|
-
<v-btn
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
density="compact"
|
|
443
|
-
size="small"
|
|
444
|
-
@click.stop="handleOpenRemarks(item, 'checkIn')"
|
|
445
|
-
>{{ item.checkInRemarks ? "View Remarks" : "Add Remarks" }}</v-btn
|
|
446
|
-
>
|
|
291
|
+
<v-btn variant="text" color="blue-darken-2" density="compact" size="small"
|
|
292
|
+
@click.stop="handleOpenRemarks(item, 'checkIn')">{{ item.checkInRemarks ? "View Remarks" : "Add Remarks"
|
|
293
|
+
}}</v-btn>
|
|
447
294
|
</span>
|
|
448
295
|
</template>
|
|
449
296
|
<template v-slot:item.checkOutRemarks="{ item }">
|
|
450
297
|
<span>
|
|
451
|
-
<v-btn
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
density="compact"
|
|
455
|
-
size="small"
|
|
456
|
-
@click.stop="handleOpenRemarks(item, 'checkOut')"
|
|
457
|
-
>{{ item.checkOutRemarks ? "View Remarks" : "Add Remarks" }}</v-btn
|
|
458
|
-
>
|
|
298
|
+
<v-btn variant="text" color="blue-darken-2" density="compact" size="small"
|
|
299
|
+
@click.stop="handleOpenRemarks(item, 'checkOut')">{{ item.checkOutRemarks ? "View Remarks" : "Add Remarks"
|
|
300
|
+
}}</v-btn>
|
|
459
301
|
</span>
|
|
460
302
|
</template>
|
|
461
303
|
</TableMain>
|
|
462
304
|
|
|
463
305
|
<v-dialog v-model="dialog.showSelection" width="450" persistent>
|
|
464
|
-
<VisitorFormSelection
|
|
465
|
-
:mode="mode"
|
|
466
|
-
@cancel="dialog.showSelection = false"
|
|
467
|
-
@select="handleSelectVisitorType"
|
|
468
|
-
/>
|
|
306
|
+
<VisitorFormSelection :mode="mode" @cancel="dialog.showSelection = false" @select="handleSelectVisitorType" />
|
|
469
307
|
</v-dialog>
|
|
470
308
|
|
|
471
|
-
<v-dialog
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
persistent
|
|
476
|
-
>
|
|
477
|
-
<VisitorForm
|
|
478
|
-
:mode="mode"
|
|
479
|
-
:org="orgId"
|
|
480
|
-
:site="siteId"
|
|
481
|
-
:visitor-data="selectedVisitorDataObject"
|
|
482
|
-
:type="activeVisitorFormType"
|
|
483
|
-
@back="handleClickBack"
|
|
484
|
-
@done="handleVisitorFormDone"
|
|
485
|
-
@done:more="handleVisitorFormCreateMore"
|
|
486
|
-
@close:all="handleCloseAll"
|
|
487
|
-
/>
|
|
309
|
+
<v-dialog v-model="dialog.showForm" v-if="activeVisitorFormType" width="450" persistent>
|
|
310
|
+
<VisitorForm :mode="mode" :org="orgId" :site="siteId" :visitor-data="selectedVisitorDataObject"
|
|
311
|
+
:type="activeVisitorFormType" @back="handleClickBack" @done="handleVisitorFormDone"
|
|
312
|
+
@done:more="handleVisitorFormCreateMore" @close:all="handleCloseAll" />
|
|
488
313
|
</v-dialog>
|
|
489
314
|
|
|
490
315
|
<v-dialog v-model="dialog.viewVisitor" width="450" persistent>
|
|
491
|
-
<VehicleUpdateMoreAction
|
|
492
|
-
|
|
493
|
-
:can-update="false"
|
|
494
|
-
:can-delete="false"
|
|
495
|
-
@close="dialog.viewVisitor = false"
|
|
496
|
-
edit-button-label="Edit Visitor"
|
|
497
|
-
>
|
|
316
|
+
<VehicleUpdateMoreAction title="Preview" :can-update="false" :can-delete="false"
|
|
317
|
+
@close="dialog.viewVisitor = false" edit-button-label="Edit Visitor">
|
|
498
318
|
<template v-slot:content>
|
|
499
319
|
<v-row no-gutters class="mb-4">
|
|
500
320
|
<v-col v-for="(label, key) in formattedFields" :key="key" cols="12">
|
|
501
|
-
<span
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
"
|
|
507
|
-
class="d-flex align-center"
|
|
508
|
-
>
|
|
321
|
+
<span v-if="
|
|
322
|
+
key === 'checkIn' &&
|
|
323
|
+
!selectedVisitorObject[key] &&
|
|
324
|
+
canUpdateVisitor
|
|
325
|
+
" class="d-flex align-center">
|
|
509
326
|
<strong>{{ label }}:</strong>
|
|
510
|
-
<v-btn
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
color="success"
|
|
514
|
-
text="Checkin"
|
|
515
|
-
:disabled="isVisitorDataFromScannedQRCodeCheckingInOut"
|
|
516
|
-
@click="handleCheckin(selectedVisitorObject)"
|
|
517
|
-
:loading="isVisitorDataFromScannedQRCodeCheckingInOut"
|
|
518
|
-
/>
|
|
327
|
+
<v-btn size="x-small" class="ml-3 text-capitalize" color="success" text="Checkin"
|
|
328
|
+
:disabled="isVisitorDataFromScannedQRCodeCheckingInOut" @click="handleCheckin(selectedVisitorObject)"
|
|
329
|
+
:loading="isVisitorDataFromScannedQRCodeCheckingInOut" />
|
|
519
330
|
</span>
|
|
520
|
-
<span
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
"
|
|
527
|
-
class="d-flex align-center"
|
|
528
|
-
>
|
|
331
|
+
<span v-if="
|
|
332
|
+
key === 'checkOut' &&
|
|
333
|
+
selectedVisitorObject['checkIn'] &&
|
|
334
|
+
!selectedVisitorObject[key] &&
|
|
335
|
+
canCheckoutVisitor
|
|
336
|
+
" class="d-flex align-center">
|
|
529
337
|
<strong>{{ label }}:</strong>
|
|
530
|
-
<v-btn
|
|
531
|
-
|
|
532
|
-
class="ml-3 text-capitalize"
|
|
533
|
-
color="red"
|
|
534
|
-
text="Checkout"
|
|
535
|
-
:disabled="loading.checkingOut"
|
|
536
|
-
@click="handleCheckout(selectedVisitorId as string)"
|
|
537
|
-
/>
|
|
338
|
+
<v-btn size="x-small" class="ml-3 text-capitalize" color="red" text="Checkout"
|
|
339
|
+
:disabled="loading.checkingOut" @click="handleCheckout(selectedVisitorId as string)" />
|
|
538
340
|
</span>
|
|
539
341
|
|
|
540
|
-
<span
|
|
541
|
-
|
|
542
|
-
class="d-flex ga-3 align-center"
|
|
543
|
-
><strong>{{ label }}:</strong>
|
|
342
|
+
<span v-else-if="selectedVisitorObject[key]" class="d-flex ga-3 align-center"><strong>{{ label
|
|
343
|
+
}}:</strong>
|
|
544
344
|
{{ formatValues(key, selectedVisitorObject[key]) }}
|
|
545
|
-
<TooltipInfo
|
|
546
|
-
v-if="key === 'checkOut'"
|
|
547
|
-
text="Manual Checkout"
|
|
548
|
-
density="compact"
|
|
549
|
-
size="x-small"
|
|
550
|
-
/>
|
|
345
|
+
<TooltipInfo v-if="key === 'checkOut'" text="Manual Checkout" density="compact" size="x-small" />
|
|
551
346
|
</span>
|
|
552
347
|
</v-col>
|
|
553
348
|
</v-row>
|
|
@@ -559,11 +354,7 @@
|
|
|
559
354
|
<v-card>
|
|
560
355
|
<v-card-title class="d-flex justify-space-between align-center">
|
|
561
356
|
<span>Snapshot</span>
|
|
562
|
-
<v-btn
|
|
563
|
-
icon="mdi-close"
|
|
564
|
-
variant="text"
|
|
565
|
-
@click="dialog.snapshotImage = false"
|
|
566
|
-
/>
|
|
357
|
+
<v-btn icon="mdi-close" variant="text" @click="dialog.snapshotImage = false" />
|
|
567
358
|
</v-card-title>
|
|
568
359
|
<v-card-text class="pa-2 d-flex justify-center">
|
|
569
360
|
<v-img :src="snapshotImageUrl" max-height="600" contain />
|
|
@@ -573,51 +364,25 @@
|
|
|
573
364
|
|
|
574
365
|
<v-dialog v-model="dialog.remarks" max-width="450" persistent>
|
|
575
366
|
<v-card>
|
|
576
|
-
<v-card-title
|
|
577
|
-
class="d-flex justify-space-between align-center pt-4 px-4"
|
|
578
|
-
>
|
|
367
|
+
<v-card-title class="d-flex justify-space-between align-center pt-4 px-4">
|
|
579
368
|
<span>{{
|
|
580
369
|
remarksType === "checkIn" ? "Check-In Remarks" : "Check-Out Remarks"
|
|
581
|
-
|
|
582
|
-
<v-btn
|
|
583
|
-
icon="mdi-close"
|
|
584
|
-
variant="text"
|
|
585
|
-
@click="dialog.remarks = false"
|
|
586
|
-
/>
|
|
370
|
+
}}</span>
|
|
371
|
+
<v-btn icon="mdi-close" variant="text" @click="dialog.remarks = false" />
|
|
587
372
|
</v-card-title>
|
|
588
373
|
<v-card-text class="px-4 pb-2">
|
|
589
|
-
<v-textarea
|
|
590
|
-
|
|
591
|
-
label="Remarks"
|
|
592
|
-
rows="4"
|
|
593
|
-
auto-grow
|
|
594
|
-
variant="outlined"
|
|
595
|
-
:readonly="remarksViewOnly"
|
|
596
|
-
/>
|
|
374
|
+
<v-textarea v-model="remarksInput" label="Remarks" rows="4" auto-grow variant="outlined"
|
|
375
|
+
:readonly="remarksViewOnly" />
|
|
597
376
|
</v-card-text>
|
|
598
377
|
<v-toolbar class="pa-0" density="compact">
|
|
599
378
|
<v-row no-gutters>
|
|
600
379
|
<v-col cols="6">
|
|
601
|
-
<v-btn
|
|
602
|
-
|
|
603
|
-
block
|
|
604
|
-
:disabled="loading.savingRemarks"
|
|
605
|
-
@click="dialog.remarks = false"
|
|
606
|
-
>Cancel</v-btn
|
|
607
|
-
>
|
|
380
|
+
<v-btn variant="text" block :disabled="loading.savingRemarks"
|
|
381
|
+
@click="dialog.remarks = false">Cancel</v-btn>
|
|
608
382
|
</v-col>
|
|
609
383
|
<v-col cols="6">
|
|
610
|
-
<v-btn
|
|
611
|
-
|
|
612
|
-
variant="flat"
|
|
613
|
-
height="48"
|
|
614
|
-
rounded="0"
|
|
615
|
-
block
|
|
616
|
-
:loading="loading.savingRemarks"
|
|
617
|
-
:disabled="!remarksInput.trim()"
|
|
618
|
-
@click="handleSaveRemarks"
|
|
619
|
-
>Save</v-btn
|
|
620
|
-
>
|
|
384
|
+
<v-btn color="primary" variant="flat" height="48" rounded="0" block :loading="loading.savingRemarks"
|
|
385
|
+
:disabled="!remarksInput.trim()" @click="handleSaveRemarks">Save</v-btn>
|
|
621
386
|
</v-col>
|
|
622
387
|
</v-row>
|
|
623
388
|
</v-toolbar>
|
|
@@ -627,16 +392,9 @@
|
|
|
627
392
|
<v-dialog v-model="dialog.returnPassesKeys" max-width="450" persistent>
|
|
628
393
|
<v-card>
|
|
629
394
|
<v-toolbar density="compact" color="">
|
|
630
|
-
<v-row
|
|
631
|
-
no-gutters
|
|
632
|
-
class="d-flex fill-height justify-space-between align-center px-4"
|
|
633
|
-
>
|
|
395
|
+
<v-row no-gutters class="d-flex fill-height justify-space-between align-center px-4">
|
|
634
396
|
<span class="font-weight-bold">Return Passes & Keys</span>
|
|
635
|
-
<v-btn
|
|
636
|
-
icon="mdi-close"
|
|
637
|
-
variant="text"
|
|
638
|
-
@click="dialog.returnPassesKeys = false"
|
|
639
|
-
/>
|
|
397
|
+
<v-btn icon="mdi-close" variant="text" @click="dialog.returnPassesKeys = false" />
|
|
640
398
|
</v-row>
|
|
641
399
|
</v-toolbar>
|
|
642
400
|
<v-card-text class="px-4 pb-2">
|
|
@@ -646,134 +404,55 @@
|
|
|
646
404
|
|
|
647
405
|
<div>
|
|
648
406
|
<InputLabel class="text-capitalize" title="Full Name" />
|
|
649
|
-
<v-text-field
|
|
650
|
-
v-model="selectedVisitorObject.name"
|
|
651
|
-
density="comfortable"
|
|
652
|
-
readonly
|
|
653
|
-
/>
|
|
407
|
+
<v-text-field v-model="selectedVisitorObject.name" density="comfortable" readonly />
|
|
654
408
|
</div>
|
|
655
409
|
|
|
656
410
|
<div>
|
|
657
411
|
<InputLabel class="text-capitalize" title="Location" />
|
|
658
|
-
<v-text-field
|
|
659
|
-
v-model="selectedVisitorObject.location"
|
|
660
|
-
density="comfortable"
|
|
661
|
-
readonly
|
|
662
|
-
/>
|
|
412
|
+
<v-text-field v-model="selectedVisitorObject.location" density="comfortable" readonly />
|
|
663
413
|
</div>
|
|
664
414
|
|
|
665
415
|
<div v-if="passReturnStatuses.length > 0" class="mb-2">
|
|
666
416
|
<p class="text-caption text-medium-emphasis mb-1">Passes</p>
|
|
667
|
-
<v-row
|
|
668
|
-
|
|
669
|
-
v-
|
|
670
|
-
:key="(pass as any)._id ?? (pass as any).keyId"
|
|
671
|
-
class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2"
|
|
672
|
-
>
|
|
673
|
-
<v-chip
|
|
674
|
-
prepend-icon="mdi-card-bulleted-outline"
|
|
675
|
-
size="small"
|
|
676
|
-
variant="tonal"
|
|
677
|
-
color="blue"
|
|
678
|
-
>
|
|
417
|
+
<v-row no-gutters v-for="pass in passReturnStatuses" :key="(pass as any)._id ?? (pass as any).keyId"
|
|
418
|
+
class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2">
|
|
419
|
+
<v-chip prepend-icon="mdi-card-bulleted-outline" size="small" variant="tonal" color="blue">
|
|
679
420
|
{{ (pass as any)?.prefixAndName }}
|
|
680
421
|
</v-chip>
|
|
681
|
-
<v-select
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
density="compact"
|
|
685
|
-
:items="passStatusOptions"
|
|
686
|
-
item-title="label"
|
|
687
|
-
item-value="value"
|
|
688
|
-
v-model="pass.status"
|
|
689
|
-
:disabled="selectedVisitorObject.checkOut"
|
|
690
|
-
></v-select>
|
|
691
|
-
<v-textarea
|
|
692
|
-
v-if="pass.status === 'Lost' || pass.status === 'Damaged'"
|
|
693
|
-
no-resize
|
|
694
|
-
rows="3"
|
|
695
|
-
class="w-100"
|
|
696
|
-
density="compact"
|
|
697
|
-
v-model="pass.remarks"
|
|
698
|
-
:disabled="selectedVisitorObject.checkOut"
|
|
699
|
-
></v-textarea>
|
|
422
|
+
<v-select hide-details max-width="200px" density="compact" :items="passStatusOptions" item-title="label"
|
|
423
|
+
item-value="value" v-model="pass.status" :disabled="selectedVisitorObject.checkOut"></v-select>
|
|
424
|
+
<v-textarea v-if="pass.status === 'Lost' || pass.status === 'Damaged'" no-resize rows="3" class="w-100"
|
|
425
|
+
density="compact" v-model="pass.remarks" :disabled="selectedVisitorObject.checkOut"></v-textarea>
|
|
700
426
|
</v-row>
|
|
701
427
|
</div>
|
|
702
428
|
<div v-if="keyReturnStatuses.length > 0" class="mb-2">
|
|
703
429
|
<p class="text-caption text-medium-emphasis mb-1">Keys</p>
|
|
704
|
-
<v-row
|
|
705
|
-
|
|
706
|
-
v-
|
|
707
|
-
:key="(key as any)._id ?? (key as any).keyId"
|
|
708
|
-
class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2"
|
|
709
|
-
>
|
|
710
|
-
<v-chip
|
|
711
|
-
prepend-icon="mdi-key"
|
|
712
|
-
size="small"
|
|
713
|
-
variant="tonal"
|
|
714
|
-
color="orange"
|
|
715
|
-
>
|
|
430
|
+
<v-row no-gutters v-for="key in keyReturnStatuses" :key="(key as any)._id ?? (key as any).keyId"
|
|
431
|
+
class="d-flex flex-wrap justify-space-between align-center ga-5 mb-2">
|
|
432
|
+
<v-chip prepend-icon="mdi-key" size="small" variant="tonal" color="orange">
|
|
716
433
|
{{ (key as any)?.prefixAndName }}
|
|
717
434
|
</v-chip>
|
|
718
|
-
<v-select
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
density="compact"
|
|
722
|
-
:items="passStatusOptions"
|
|
723
|
-
item-title="label"
|
|
724
|
-
item-value="value"
|
|
725
|
-
v-model="key.status"
|
|
726
|
-
:disabled="selectedVisitorObject.checkOut"
|
|
727
|
-
></v-select>
|
|
728
|
-
<v-textarea
|
|
729
|
-
v-if="key.status === 'Lost' || key.status === 'Damaged'"
|
|
730
|
-
no-resize
|
|
731
|
-
rows="3"
|
|
732
|
-
class="w-100"
|
|
733
|
-
density="compact"
|
|
734
|
-
v-model="key.remarks"
|
|
735
|
-
:disabled="selectedVisitorObject.checkOut"
|
|
736
|
-
></v-textarea>
|
|
435
|
+
<v-select hide-details max-width="200px" density="compact" :items="passStatusOptions" item-title="label"
|
|
436
|
+
item-value="value" v-model="key.status" :disabled="selectedVisitorObject.checkOut"></v-select>
|
|
437
|
+
<v-textarea v-if="key.status === 'Lost' || key.status === 'Damaged'" no-resize rows="3" class="w-100"
|
|
438
|
+
density="compact" v-model="key.remarks" :disabled="selectedVisitorObject.checkOut"></v-textarea>
|
|
737
439
|
</v-row>
|
|
738
440
|
</div>
|
|
739
441
|
|
|
740
442
|
<v-row no-gutters class="my-5">
|
|
741
|
-
<v-btn
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
density="comfortable"
|
|
745
|
-
class="text-capitalize"
|
|
746
|
-
:disabled="selectedVisitorObject.checkOut"
|
|
747
|
-
:loading="loading.updatingPassKeys"
|
|
748
|
-
@click.stop="handleUpdatePassKeys"
|
|
749
|
-
>Update Pass/Keys</v-btn
|
|
750
|
-
>
|
|
443
|
+
<v-btn variant="flat" color="blue" density="comfortable" class="text-capitalize"
|
|
444
|
+
:disabled="selectedVisitorObject.checkOut" :loading="loading.updatingPassKeys"
|
|
445
|
+
@click.stop="handleUpdatePassKeys">Update Pass/Keys</v-btn>
|
|
751
446
|
</v-row>
|
|
752
447
|
</v-card-text>
|
|
753
448
|
<v-toolbar class="pa-0" density="compact">
|
|
754
449
|
<v-row no-gutters>
|
|
755
450
|
<v-col cols="6">
|
|
756
|
-
<v-btn
|
|
757
|
-
variant="text"
|
|
758
|
-
block
|
|
759
|
-
@click="dialog.returnPassesKeys = false"
|
|
760
|
-
>Close</v-btn
|
|
761
|
-
>
|
|
451
|
+
<v-btn variant="text" block @click="dialog.returnPassesKeys = false">Close</v-btn>
|
|
762
452
|
</v-col>
|
|
763
453
|
<v-col cols="6">
|
|
764
|
-
<v-btn
|
|
765
|
-
|
|
766
|
-
variant="flat"
|
|
767
|
-
height="48"
|
|
768
|
-
rounded="0"
|
|
769
|
-
block
|
|
770
|
-
:loading="loading.checkingOut"
|
|
771
|
-
:disabled="
|
|
772
|
-
!canConfirmCheckout || selectedVisitorObject.checkOut
|
|
773
|
-
"
|
|
774
|
-
@click="proceedCheckout"
|
|
775
|
-
>Confirm Checkout</v-btn
|
|
776
|
-
>
|
|
454
|
+
<v-btn color="red" variant="flat" height="48" rounded="0" block :loading="loading.checkingOut" :disabled="!canConfirmCheckout || selectedVisitorObject.checkOut
|
|
455
|
+
" @click="proceedCheckout">Confirm Checkout</v-btn>
|
|
777
456
|
</v-col>
|
|
778
457
|
</v-row>
|
|
779
458
|
</v-toolbar>
|
|
@@ -781,145 +460,80 @@
|
|
|
781
460
|
</v-dialog>
|
|
782
461
|
|
|
783
462
|
<v-dialog v-model="dialog.addPassKey" width="450" persistent>
|
|
784
|
-
<AddPassKeyToVisitor
|
|
785
|
-
|
|
786
|
-
:visitor="selectedVisitorDataObject"
|
|
787
|
-
:site="siteId"
|
|
788
|
-
@close="dialog.addPassKey = false"
|
|
789
|
-
@done="
|
|
463
|
+
<AddPassKeyToVisitor mode="add" :visitor="selectedVisitorDataObject" :site="siteId"
|
|
464
|
+
@close="dialog.addPassKey = false" @done="
|
|
790
465
|
() => {
|
|
791
466
|
dialog.addPassKey = false;
|
|
792
467
|
getVisitorRefresh();
|
|
793
468
|
}
|
|
794
|
-
"
|
|
795
|
-
/>
|
|
469
|
+
" />
|
|
796
470
|
</v-dialog>
|
|
797
471
|
|
|
798
472
|
<v-dialog v-model="dialog.editPassKey" width="450" persistent>
|
|
799
|
-
<AddPassKeyToVisitor
|
|
800
|
-
|
|
801
|
-
:visitor="selectedVisitorDataObject"
|
|
802
|
-
:site="siteId"
|
|
803
|
-
@close="dialog.editPassKey = false"
|
|
804
|
-
@done="
|
|
473
|
+
<AddPassKeyToVisitor mode="edit" :visitor="selectedVisitorDataObject" :site="siteId"
|
|
474
|
+
@close="dialog.editPassKey = false" @done="
|
|
805
475
|
() => {
|
|
806
476
|
dialog.editPassKey = false;
|
|
807
477
|
getVisitorRefresh();
|
|
808
478
|
}
|
|
809
|
-
"
|
|
810
|
-
/>
|
|
479
|
+
" />
|
|
811
480
|
</v-dialog>
|
|
812
481
|
|
|
813
|
-
<ScanVisitorQRCode
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
"
|
|
819
|
-
@close-dialog="dialog.scanVisitorQRCode = false"
|
|
820
|
-
/>
|
|
821
|
-
|
|
822
|
-
<v-dialog
|
|
823
|
-
v-model="dialog.showVisitorDataFromScannedQRCode"
|
|
824
|
-
width="450"
|
|
825
|
-
persistent
|
|
826
|
-
>
|
|
827
|
-
<VisitorDataFromScannedQRCodeForm
|
|
828
|
-
:site="siteId"
|
|
829
|
-
:visitor-data="visitorDataFromScannedQRCode"
|
|
482
|
+
<ScanVisitorQRCode :dialog="dialog.scanVisitorQRCode" :site="siteId" @open-visitor-data-from-scanned-qr-code-dialog="
|
|
483
|
+
handleShowVisitorDataFromScannedQRCodeDialog
|
|
484
|
+
" @close-dialog="dialog.scanVisitorQRCode = false" />
|
|
485
|
+
|
|
486
|
+
<v-dialog v-model="dialog.showVisitorDataFromScannedQRCode" width="450" persistent>
|
|
487
|
+
<VisitorDataFromScannedQRCodeForm :site="siteId" :visitor-data="visitorDataFromScannedQRCode"
|
|
830
488
|
@check-in-out="handleVisitorDataFromScannedQRCodeCheckInOut"
|
|
831
489
|
:processing="isVisitorDataFromScannedQRCodeCheckingInOut"
|
|
832
|
-
@close="handleCloseVisitorDataFromScannedQRCodeDialog"
|
|
833
|
-
/>
|
|
490
|
+
@close="handleCloseVisitorDataFromScannedQRCodeDialog" />
|
|
834
491
|
</v-dialog>
|
|
835
492
|
|
|
836
|
-
<v-dialog
|
|
837
|
-
|
|
838
|
-
transition="dialog-bottom-transition"
|
|
839
|
-
persistent
|
|
840
|
-
width="60vh"
|
|
841
|
-
>
|
|
493
|
+
<v-dialog v-model="dialog.approveRejectOvernightParkingRequestDialog" transition="dialog-bottom-transition"
|
|
494
|
+
persistent width="60vh">
|
|
842
495
|
<v-card>
|
|
843
496
|
<v-toolbar density="compact">
|
|
844
|
-
<v-row
|
|
845
|
-
no-gutters
|
|
846
|
-
class="d-flex fill-height justify-space-between align-center px-4"
|
|
847
|
-
>
|
|
497
|
+
<v-row no-gutters class="d-flex fill-height justify-space-between align-center px-4">
|
|
848
498
|
<span class="font-weight-bold"> Overnight Parking Request </span>
|
|
849
|
-
<v-btn
|
|
850
|
-
icon="mdi-close"
|
|
851
|
-
variant="text"
|
|
852
|
-
@click="dialog.approveRejectOvernightParkingRequestDialog = false"
|
|
853
|
-
/>
|
|
499
|
+
<v-btn icon="mdi-close" variant="text" @click="dialog.approveRejectOvernightParkingRequestDialog = false" />
|
|
854
500
|
</v-row>
|
|
855
501
|
</v-toolbar>
|
|
856
502
|
<v-card-text class="px-4 pb-6">
|
|
857
503
|
<v-row no-gutters justify="center" align-content="center">
|
|
858
|
-
<v-col
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
"
|
|
862
|
-
cols="12"
|
|
863
|
-
class="text-h6 text-center"
|
|
864
|
-
>
|
|
504
|
+
<v-col v-if="
|
|
505
|
+
approveRejectOvernightParkingRequestDialog.status !== 'remarks'
|
|
506
|
+
" cols="12" class="text-h6 text-center">
|
|
865
507
|
{{
|
|
866
|
-
`Are you sure you want to ${approveRejectOvernightParkingRequestDialog.text} the visitor's overnight
|
|
508
|
+
`Are you sure you want to ${approveRejectOvernightParkingRequestDialog.text} the visitor's overnight
|
|
509
|
+
parking
|
|
510
|
+
request?`
|
|
867
511
|
}}
|
|
868
512
|
</v-col>
|
|
869
513
|
|
|
870
514
|
<v-col cols="12" md="8" class="mt-4">
|
|
871
|
-
<v-textarea
|
|
872
|
-
|
|
873
|
-
label="Remarks"
|
|
874
|
-
placeholder="Enter remarks"
|
|
875
|
-
outlined
|
|
876
|
-
rows="3"
|
|
877
|
-
clearable
|
|
878
|
-
:hide-details="
|
|
879
|
-
approveRejectOvernightParkingRequestDialog.status ===
|
|
515
|
+
<v-textarea v-model="overNightParkingRequestApproveRejectRemarks" label="Remarks"
|
|
516
|
+
placeholder="Enter remarks" outlined rows="3" clearable :hide-details="approveRejectOvernightParkingRequestDialog.status ===
|
|
880
517
|
'remarks'
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
'remarks'
|
|
885
|
-
"
|
|
886
|
-
/>
|
|
518
|
+
" :readonly="approveRejectOvernightParkingRequestDialog.status ===
|
|
519
|
+
'remarks'
|
|
520
|
+
" />
|
|
887
521
|
</v-col>
|
|
888
522
|
</v-row>
|
|
889
523
|
</v-card-text>
|
|
890
|
-
<v-toolbar
|
|
891
|
-
|
|
892
|
-
class="pa-0"
|
|
893
|
-
density="compact"
|
|
894
|
-
>
|
|
524
|
+
<v-toolbar v-if="approveRejectOvernightParkingRequestDialog.status !== 'remarks'" class="pa-0"
|
|
525
|
+
density="compact">
|
|
895
526
|
<v-row no-gutters>
|
|
896
527
|
<v-col cols="6">
|
|
897
|
-
<v-btn
|
|
898
|
-
text="No"
|
|
899
|
-
color="grey-lighten-3"
|
|
900
|
-
variant="flat"
|
|
901
|
-
height="48"
|
|
902
|
-
tile
|
|
903
|
-
block
|
|
528
|
+
<v-btn text="No" color="grey-lighten-3" variant="flat" height="48" tile block
|
|
904
529
|
:disabled="isApprovingRejectingOvernightParkingRequest"
|
|
905
|
-
@click="closeApproveRejectOvernightParkingDialog"
|
|
906
|
-
/>
|
|
530
|
+
@click="closeApproveRejectOvernightParkingDialog" />
|
|
907
531
|
</v-col>
|
|
908
532
|
<v-col cols="6">
|
|
909
|
-
<v-btn
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
height="48"
|
|
914
|
-
tile
|
|
915
|
-
block
|
|
916
|
-
:disabled="
|
|
917
|
-
!overNightParkingRequestApproveRejectRemarks ||
|
|
918
|
-
isApprovingRejectingOvernightParkingRequest
|
|
919
|
-
"
|
|
920
|
-
@click="updateOvernightParkingRequestStatus"
|
|
921
|
-
:loading="isApprovingRejectingOvernightParkingRequest"
|
|
922
|
-
/>
|
|
533
|
+
<v-btn text="Yes" color="success" variant="flat" height="48" tile block :disabled="!overNightParkingRequestApproveRejectRemarks ||
|
|
534
|
+
isApprovingRejectingOvernightParkingRequest
|
|
535
|
+
" @click="updateOvernightParkingRequestStatus"
|
|
536
|
+
:loading="isApprovingRejectingOvernightParkingRequest" />
|
|
923
537
|
</v-col>
|
|
924
538
|
</v-row>
|
|
925
539
|
</v-toolbar>
|
|
@@ -937,6 +551,8 @@ definePageMeta({
|
|
|
937
551
|
middleware: ["01-auth", "02-org"],
|
|
938
552
|
});
|
|
939
553
|
|
|
554
|
+
const { downloadPDF } = usePDFDownload();
|
|
555
|
+
|
|
940
556
|
const props = defineProps({
|
|
941
557
|
canAddVisitor: {
|
|
942
558
|
type: Boolean,
|
|
@@ -1253,8 +869,8 @@ const {
|
|
|
1253
869
|
page: page.value,
|
|
1254
870
|
site: siteId,
|
|
1255
871
|
search: searchInput.value,
|
|
1256
|
-
dateTo: moment(dateTo.value).endOf("day").toISOString(),
|
|
1257
|
-
dateFrom: moment(dateFrom.value).startOf("day").toISOString(),
|
|
872
|
+
dateTo: dateTo.value ? moment(dateTo.value).endOf("day").toISOString() : undefined,
|
|
873
|
+
dateFrom: dateFrom.value ? moment(dateFrom.value).startOf("day").toISOString() : undefined,
|
|
1258
874
|
type:
|
|
1259
875
|
filterTypes.value.length === 0 && activeTab.value === "registered"
|
|
1260
876
|
? "contractor,delivery,walk-in,pick-up,drop-off,guest"
|
|
@@ -1678,6 +1294,146 @@ async function proceedCheckout() {
|
|
|
1678
1294
|
}
|
|
1679
1295
|
}
|
|
1680
1296
|
|
|
1297
|
+
function buildReportParams(): any {
|
|
1298
|
+
const params: any = {
|
|
1299
|
+
site: siteId,
|
|
1300
|
+
search: searchInput.value,
|
|
1301
|
+
dateTo: dateTo.value ? moment(dateTo.value).endOf("day").toISOString() : undefined,
|
|
1302
|
+
dateFrom: dateFrom.value ? moment(dateFrom.value).startOf("day").toISOString() : undefined,
|
|
1303
|
+
type:
|
|
1304
|
+
filterTypes.value.length === 0 && activeTab.value === "registered"
|
|
1305
|
+
? "contractor,delivery,walk-in,pick-up,drop-off,guest"
|
|
1306
|
+
: filterTypes.value.filter(Boolean).join(","),
|
|
1307
|
+
checkedOut: displayNotCheckedOut.value ? false : undefined,
|
|
1308
|
+
limit: 100,
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
if (activeTab.value === "guests") {
|
|
1312
|
+
params.type = "guest";
|
|
1313
|
+
params.status = "approved";
|
|
1314
|
+
} else if (activeTab.value === "resident-transactions") {
|
|
1315
|
+
params.status = "registered";
|
|
1316
|
+
params.type = "resident,tenant";
|
|
1317
|
+
} else if (activeTab.value === "overnight-parking") {
|
|
1318
|
+
params.tab = "Overnight Parking";
|
|
1319
|
+
} else {
|
|
1320
|
+
params.status = activeTab.value;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
return params;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
|
|
1327
|
+
async function handleDownloadPDFReport() {
|
|
1328
|
+
try {
|
|
1329
|
+
showMessage("Generating PDF report...", "info");
|
|
1330
|
+
|
|
1331
|
+
// Build URL with query parameters
|
|
1332
|
+
const queryParams = new URLSearchParams();
|
|
1333
|
+
if (searchInput.value) queryParams.append("search", searchInput.value);
|
|
1334
|
+
if (dateFrom.value) queryParams.append("dateFrom", dateFrom.value);
|
|
1335
|
+
if (dateTo.value) queryParams.append("dateTo", dateTo.value);
|
|
1336
|
+
if (filterTypes.value.length > 0) queryParams.append("type", filterTypes.value.join(","));
|
|
1337
|
+
if (activeTab.value) queryParams.append("tab", activeTab.value);
|
|
1338
|
+
if (displayNotCheckedOut.value) queryParams.append("checkedOut", "true");
|
|
1339
|
+
|
|
1340
|
+
const queryString = queryParams.toString();
|
|
1341
|
+
const url = `/${route.params.org}/${siteId}/visitor-management/preview${queryString ? "?" + queryString : ""}`;
|
|
1342
|
+
const title = `Visitor-Report-${siteId}-${new Date().toISOString().split("T")[0]}`;
|
|
1343
|
+
|
|
1344
|
+
await downloadPDF({ url, title, orientation: "P", appKey: "SECURITY" });
|
|
1345
|
+
showMessage("PDF report downloaded successfully!", "success");
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
showMessage("Error downloading PDF report", "error");
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
async function handleDownloadCSVReport() {
|
|
1352
|
+
try {
|
|
1353
|
+
showMessage("Generating CSV report...", "info");
|
|
1354
|
+
|
|
1355
|
+
const params = buildReportParams();
|
|
1356
|
+
const reportData = await getVisitors(params);
|
|
1357
|
+
const csvData = generateCSVData(reportData.items ?? []);
|
|
1358
|
+
downloadCSVFile(csvData);
|
|
1359
|
+
showMessage("CSV report downloaded successfully!", "success");
|
|
1360
|
+
} catch (error) {
|
|
1361
|
+
showMessage("Error downloading CSV report", "error");
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
function generateCSVData(visitors: any[]): string {
|
|
1366
|
+
const headers = [
|
|
1367
|
+
"NAME",
|
|
1368
|
+
"TYPE",
|
|
1369
|
+
"COMPANY",
|
|
1370
|
+
"BLOCK",
|
|
1371
|
+
"LEVEL",
|
|
1372
|
+
"UNIT",
|
|
1373
|
+
"CONTACT",
|
|
1374
|
+
"VEHICLE NO.",
|
|
1375
|
+
"CHECK-IN",
|
|
1376
|
+
"CHECK-OUT",
|
|
1377
|
+
"CHECK-IN IMAGE",
|
|
1378
|
+
"CHECK-OUT IMAGE",
|
|
1379
|
+
];
|
|
1380
|
+
|
|
1381
|
+
const formatExportTypes = (type: string) => {
|
|
1382
|
+
if (!type || type === "null") return "";
|
|
1383
|
+
if (type === "guest") return "Drive In";
|
|
1384
|
+
const typeParts = type.split("-");
|
|
1385
|
+
return typeParts.map((part) => formatCamelCaseToWords(part)).join("-");
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
const rows = visitors.map((visitor) => [
|
|
1389
|
+
visitor.name || "",
|
|
1390
|
+
formatExportTypes(formatType(visitor)) || "",
|
|
1391
|
+
visitor.company || "",
|
|
1392
|
+
visitor.block || "",
|
|
1393
|
+
visitor.level || "",
|
|
1394
|
+
visitor.unitName || "",
|
|
1395
|
+
visitor.contact || "",
|
|
1396
|
+
visitor.plateNumber || "",
|
|
1397
|
+
formatDate(visitor.checkIn) || "",
|
|
1398
|
+
formatDate(visitor.checkOut) || "",
|
|
1399
|
+
visitor.snapshotEntryImage ? getFileUrlAnpr(`${siteId}/${visitor.snapshotEntryImage}`) : "",
|
|
1400
|
+
visitor.snapshotExitImage ? getFileUrlAnpr(`${siteId}/${visitor.snapshotExitImage}`) : "",
|
|
1401
|
+
]);
|
|
1402
|
+
|
|
1403
|
+
const csvContent = [
|
|
1404
|
+
headers.map((h) => `"${h}"`).join(","),
|
|
1405
|
+
...rows.map((row) =>
|
|
1406
|
+
row
|
|
1407
|
+
.map((cell) => {
|
|
1408
|
+
const cellStr = String(cell || "");
|
|
1409
|
+
return `"${cellStr.replace(/"/g, '""')}"`;
|
|
1410
|
+
})
|
|
1411
|
+
.join(",")
|
|
1412
|
+
),
|
|
1413
|
+
].join("\n");
|
|
1414
|
+
|
|
1415
|
+
return csvContent;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
function downloadCSVFile(csvContent: string) {
|
|
1419
|
+
const now = new Date();
|
|
1420
|
+
const dateStr = now.toISOString().split("T")[0];
|
|
1421
|
+
const timeStr = now.toTimeString().split(" ")[0].replace(/:/g, "_");
|
|
1422
|
+
const filename = `VISITOR_MANAGEMENT_CSV_REPORT_${activeTab.value}_${dateStr}_${timeStr}.csv`;
|
|
1423
|
+
|
|
1424
|
+
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
|
1425
|
+
const link = document.createElement("a");
|
|
1426
|
+
const url = URL.createObjectURL(blob);
|
|
1427
|
+
|
|
1428
|
+
link.setAttribute("href", url);
|
|
1429
|
+
link.setAttribute("download", filename);
|
|
1430
|
+
link.style.visibility = "hidden";
|
|
1431
|
+
|
|
1432
|
+
document.body.appendChild(link);
|
|
1433
|
+
link.click();
|
|
1434
|
+
document.body.removeChild(link);
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1681
1437
|
const updateRouteQuery = debounce(
|
|
1682
1438
|
// (search: string, from: string, to: string, types: string[], status, checkedOut) => {
|
|
1683
1439
|
({
|
|
@@ -1748,6 +1504,9 @@ onMounted(() => {
|
|
|
1748
1504
|
displayNotCheckedOut.value =
|
|
1749
1505
|
(route.query.checkedOut as string) == "true" || false;
|
|
1750
1506
|
});
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
|
|
1751
1510
|
</script>
|
|
1752
1511
|
|
|
1753
1512
|
<style scoped></style>
|