@7365admin1/layer-common 3.0.23 → 3.0.25
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 +12 -0
- package/components/AccessCardAddForm.vue +2 -2
- package/components/AccessCardAssignToUnitForm.vue +2 -2
- package/components/AccessManagement.vue +16 -6
- package/components/BuildingUnitFormEdit.vue +1 -1
- package/components/DashboardMain.vue +29 -1
- package/components/DocumentManagement.vue +228 -1
- package/components/Nfc/NFCPatrolReportMain.vue +1 -0
- package/components/Nfc/PatrolReport/PatrolReportTab.vue +2 -1
- package/components/Nfc/PatrolReport/ReportFilters.vue +3 -1
- package/components/RolePermissionMain.vue +25 -2
- package/components/ServiceProviderMain.vue +1 -0
- package/components/VisitorForm.vue +161 -397
- package/composables/useNFCPatrolLog.ts +35 -0
- package/composables/useNFCPatrolReport.ts +37 -4
- package/composables/useNFCPatrolReportFilters.ts +28 -5
- package/composables/useServiceProvider.ts +2 -1
- package/package.json +1 -1
- package/services/nfcPatrolReport.ts +5 -1
- package/types/nfc-patrol-report.ts +7 -1
- package/types/visitor.d.ts +1 -0
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-card width="100%" :loading="processing">
|
|
3
3
|
<v-toolbar>
|
|
4
|
-
<v-row
|
|
5
|
-
no-gutters
|
|
6
|
-
class="fill-height px-6 d-flex justify-space-between align-center"
|
|
7
|
-
align="center"
|
|
8
|
-
>
|
|
4
|
+
<v-row no-gutters class="fill-height px-6 d-flex justify-space-between align-center" align="center">
|
|
9
5
|
<span class="font-weight-bold text-h5 text-capitalize">
|
|
10
6
|
{{ prop.mode }} {{ formatVisitorType(type) }}
|
|
11
7
|
</span>
|
|
@@ -16,54 +12,25 @@
|
|
|
16
12
|
<div class="w-100 d-flex justify-space-between ga-2">
|
|
17
13
|
<span class="text-subtitle-1 w-100 font-weight-bold mb-3">{{
|
|
18
14
|
formTitle
|
|
19
|
-
|
|
20
|
-
<span
|
|
21
|
-
|
|
22
|
-
class="text-subtitle-2 font-weight-bold"
|
|
23
|
-
style="text-wrap: nowrap"
|
|
24
|
-
>Step <span class="text-primary-button">{{ contractorStep }}</span
|
|
25
|
-
>/{{ withStep3 ? 3 : withStep2 ? 2 : 1 }}</span
|
|
26
|
-
>
|
|
15
|
+
}}</span>
|
|
16
|
+
<span v-if="withStep2 || withStep3" class="text-subtitle-2 font-weight-bold" style="text-wrap: nowrap">Step
|
|
17
|
+
<span class="text-primary-button">{{ contractorStep }}</span>/{{ withStep3 ? 3 : withStep2 ? 2 : 1 }}</span>
|
|
27
18
|
</div>
|
|
28
|
-
<v-form
|
|
29
|
-
ref="formRef"
|
|
30
|
-
v-model="validForm"
|
|
31
|
-
:disabled="processing"
|
|
32
|
-
@click="errorMessage = ''"
|
|
33
|
-
>
|
|
19
|
+
<v-form ref="formRef" v-model="validForm" :disabled="processing" @click="errorMessage = ''">
|
|
34
20
|
<v-row no-gutters class="pt-4">
|
|
35
21
|
<v-col v-if="shouldShowField('contractorType')" cols="12">
|
|
36
|
-
<InputLabel
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
v-model="contractorTypeObj"
|
|
43
|
-
v-model:search="contractorTypeInput"
|
|
44
|
-
ref="contractorTypeCombo"
|
|
45
|
-
autocomplete="off"
|
|
46
|
-
:hide-no-data="false"
|
|
47
|
-
@update:focused="handleFocusedContractorType"
|
|
48
|
-
:items="contractorTypes"
|
|
49
|
-
:rules="[requiredRule]"
|
|
50
|
-
item-value="value"
|
|
51
|
-
@update:model-value="handleSelectContractorType"
|
|
52
|
-
variant="outlined"
|
|
53
|
-
density="comfortable"
|
|
54
|
-
persistent-hint
|
|
55
|
-
small-chips
|
|
56
|
-
>
|
|
22
|
+
<InputLabel class="text-capitalize" title="Contractor Type" required />
|
|
23
|
+
<v-combobox v-model="contractorTypeObj" v-model:search="contractorTypeInput" ref="contractorTypeCombo"
|
|
24
|
+
autocomplete="off" :hide-no-data="false" @update:focused="handleFocusedContractorType"
|
|
25
|
+
:items="contractorTypes" :rules="[requiredRule]" item-value="value"
|
|
26
|
+
@update:model-value="handleSelectContractorType" variant="outlined" density="comfortable" persistent-hint
|
|
27
|
+
small-chips>
|
|
57
28
|
<template v-slot:no-data>
|
|
58
29
|
<v-list-item>
|
|
59
|
-
<v-list-item-title
|
|
60
|
-
@click.stop="handleAddNewContractorType"
|
|
61
|
-
class="d-flex align-center ga-1"
|
|
62
|
-
>
|
|
30
|
+
<v-list-item-title @click.stop="handleAddNewContractorType" class="d-flex align-center ga-1">
|
|
63
31
|
<span><v-icon icon="mdi-plus" /></span> Add "<strong>{{
|
|
64
32
|
contractorTypeInput
|
|
65
|
-
|
|
66
|
-
>" as custom contractor type.
|
|
33
|
+
}}</strong>" as custom contractor type.
|
|
67
34
|
</v-list-item-title>
|
|
68
35
|
</v-list-item>
|
|
69
36
|
</template>
|
|
@@ -72,26 +39,14 @@
|
|
|
72
39
|
|
|
73
40
|
<v-col v-if="shouldShowField('attachments')" class="w-100">
|
|
74
41
|
<InputLabel class="text-capitalize" title="Attach Image" />
|
|
75
|
-
<InputFileV2
|
|
76
|
-
v-model="visitor.attachments"
|
|
77
|
-
multiple
|
|
78
|
-
:max-length="3"
|
|
79
|
-
/>
|
|
42
|
+
<InputFileV2 v-model="visitor.attachments" multiple :max-length="3" />
|
|
80
43
|
</v-col>
|
|
81
44
|
|
|
82
45
|
<v-col v-if="shouldShowField('name')" cols="12">
|
|
83
46
|
<v-row>
|
|
84
47
|
<v-col cols="12">
|
|
85
|
-
<InputLabel
|
|
86
|
-
|
|
87
|
-
title="Full Name"
|
|
88
|
-
required
|
|
89
|
-
/>
|
|
90
|
-
<v-text-field
|
|
91
|
-
v-model.trim="visitor.name"
|
|
92
|
-
density="comfortable"
|
|
93
|
-
:rules="[requiredRule]"
|
|
94
|
-
/>
|
|
48
|
+
<InputLabel class="text-capitalize" title="Full Name" required />
|
|
49
|
+
<v-text-field v-model.trim="visitor.name" density="comfortable" :rules="[requiredRule]" />
|
|
95
50
|
</v-col>
|
|
96
51
|
</v-row>
|
|
97
52
|
</v-col>
|
|
@@ -99,44 +54,36 @@
|
|
|
99
54
|
<v-col v-if="shouldShowField('nric')" cols="12">
|
|
100
55
|
<v-row>
|
|
101
56
|
<v-col cols="12">
|
|
102
|
-
<InputLabel
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
57
|
+
<InputLabel class="text-capitalize" title="NRIC" :required="requireNRIC" />
|
|
58
|
+
<v-menu v-model="nricSearchMenu" location="bottom" offset-y :close-on-content-click="false">
|
|
59
|
+
<template #activator="{ props }">
|
|
60
|
+
<InputNRICNumber v-bind="props" v-model="visitor.nric" density="comfortable"
|
|
61
|
+
:rules="[requireNRIC ? requiredRule : () => true]" :key="currentAutofillSource + 'nric-key'"
|
|
62
|
+
@update:model-value="handleUpdateNRIC" :loading="fetchPersonByNRICPending" />
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<v-list v-if="nricSearchResults.length">
|
|
66
|
+
<v-list-item v-for="(item, index) in nricSearchResults" :key="item._id || index"
|
|
67
|
+
@click="selectNricSearchResult(item)" class="cursor-pointer">
|
|
68
|
+
<v-list-item-title>{{ item.name || 'Unknown' }}</v-list-item-title>
|
|
69
|
+
<v-list-item-subtitle>{{ item.contact }}</v-list-item-subtitle>
|
|
70
|
+
</v-list-item>
|
|
71
|
+
</v-list>
|
|
72
|
+
</v-menu>
|
|
115
73
|
</v-col>
|
|
116
74
|
</v-row>
|
|
117
75
|
</v-col>
|
|
118
76
|
|
|
119
77
|
<v-col v-if="shouldShowField('contact')" cols="12">
|
|
120
78
|
<InputLabel class="text-capitalize" title="Phone Number" required />
|
|
121
|
-
<InputPhoneNumberV2
|
|
122
|
-
|
|
123
|
-
:rules="[requiredRule]"
|
|
124
|
-
density="comfortable"
|
|
125
|
-
:key="currentAutofillSource + 'phone-key'"
|
|
126
|
-
:loading="fetchPersonByContactPending"
|
|
127
|
-
@update:model-value="handleUpdateContact"
|
|
128
|
-
/>
|
|
79
|
+
<InputPhoneNumberV2 v-model="visitor.contact" :rules="[requiredRule]" density="comfortable"
|
|
80
|
+
:key="currentAutofillSource + 'phone-key'" />
|
|
129
81
|
</v-col>
|
|
130
82
|
|
|
131
83
|
<v-col v-if="shouldShowField('deliveryType')" cols="12">
|
|
132
84
|
<v-row>
|
|
133
85
|
<v-col cols="12">
|
|
134
|
-
<v-radio-group
|
|
135
|
-
v-model="visitor.deliveryType"
|
|
136
|
-
inline
|
|
137
|
-
color="primary"
|
|
138
|
-
:rules="[requiredRule]"
|
|
139
|
-
>
|
|
86
|
+
<v-radio-group v-model="visitor.deliveryType" inline color="primary" :rules="[requiredRule]">
|
|
140
87
|
<v-radio label="Food" value="Food"></v-radio>
|
|
141
88
|
<v-radio label="Parcel" value="Parcel"></v-radio>
|
|
142
89
|
</v-radio-group>
|
|
@@ -147,44 +94,23 @@
|
|
|
147
94
|
<template v-if="shouldShowField('company')">
|
|
148
95
|
<v-col cols="12">
|
|
149
96
|
<InputLabel class="text-capitalize" title="Company Name" />
|
|
150
|
-
<v-combobox
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
autocomplete="off"
|
|
155
|
-
:hide-no-data="false"
|
|
156
|
-
:items="companyNames"
|
|
157
|
-
item-value="value"
|
|
158
|
-
:loading="fetchCompanyListPending"
|
|
159
|
-
@update:model-value="handleSelectCompanyName"
|
|
160
|
-
variant="outlined"
|
|
161
|
-
density="comfortable"
|
|
162
|
-
persistent-hint
|
|
163
|
-
small-chips
|
|
164
|
-
>
|
|
97
|
+
<v-combobox v-model="visitor.company" v-model:search="companyNameInput" ref="companyCombo"
|
|
98
|
+
autocomplete="off" :hide-no-data="false" :items="companyNames" item-value="value"
|
|
99
|
+
:loading="fetchCompanyListPending" @update:model-value="handleSelectCompanyName" variant="outlined"
|
|
100
|
+
density="comfortable" persistent-hint small-chips>
|
|
165
101
|
<template v-slot:no-data>
|
|
166
102
|
<v-list-item>
|
|
167
103
|
<v-list-item-title v-if="fetchCompanyListPending">
|
|
168
|
-
<v-progress-circular
|
|
169
|
-
indeterminate
|
|
170
|
-
size="20"
|
|
171
|
-
class="mr-3"
|
|
172
|
-
/>
|
|
104
|
+
<v-progress-circular indeterminate size="20" class="mr-3" />
|
|
173
105
|
Searching companies…
|
|
174
106
|
</v-list-item-title>
|
|
175
|
-
<v-list-item-title
|
|
176
|
-
|
|
177
|
-
@click.stop="handleAddNewCompany"
|
|
178
|
-
class="d-flex align-center ga-1"
|
|
179
|
-
>
|
|
107
|
+
<v-list-item-title v-else-if="companyNameInput" @click.stop="handleAddNewCompany"
|
|
108
|
+
class="d-flex align-center ga-1">
|
|
180
109
|
<span><v-icon icon="mdi-plus" /></span>Add "<strong>{{
|
|
181
110
|
companyNameInput
|
|
182
|
-
|
|
183
|
-
>" as new company.
|
|
111
|
+
}}</strong>" as new company.
|
|
184
112
|
</v-list-item-title>
|
|
185
|
-
<v-list-item-title
|
|
186
|
-
v-else-if="!companyNameInput && companyNames.length === 0"
|
|
187
|
-
>
|
|
113
|
+
<v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
|
|
188
114
|
Start typing to search for companies.
|
|
189
115
|
</v-list-item-title>
|
|
190
116
|
<v-list-item-title v-else>
|
|
@@ -199,43 +125,22 @@
|
|
|
199
125
|
<template v-if="shouldShowField('delivery-company')">
|
|
200
126
|
<v-col cols="12">
|
|
201
127
|
<InputLabel class="text-capitalize" title="Delivery Company" />
|
|
202
|
-
<v-combobox
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
ref="companyCombo"
|
|
206
|
-
autocomplete="off"
|
|
207
|
-
:hide-no-data="false"
|
|
208
|
-
:items="deliveryCompanyList"
|
|
209
|
-
item-value="value"
|
|
210
|
-
:loading="siteDataPending"
|
|
211
|
-
variant="outlined"
|
|
212
|
-
density="comfortable"
|
|
213
|
-
persistent-hint
|
|
214
|
-
small-chips
|
|
215
|
-
>
|
|
128
|
+
<v-combobox v-model="deliveryCompany" v-model:search="deliveryCompanyInput" ref="companyCombo"
|
|
129
|
+
autocomplete="off" :hide-no-data="false" :items="deliveryCompanyList" item-value="value"
|
|
130
|
+
:loading="siteDataPending" variant="outlined" density="comfortable" persistent-hint small-chips>
|
|
216
131
|
<template v-slot:no-data>
|
|
217
132
|
<v-list-item>
|
|
218
133
|
<v-list-item-title v-if="fetchCompanyListPending">
|
|
219
|
-
<v-progress-circular
|
|
220
|
-
indeterminate
|
|
221
|
-
size="20"
|
|
222
|
-
class="mr-3"
|
|
223
|
-
/>
|
|
134
|
+
<v-progress-circular indeterminate size="20" class="mr-3" />
|
|
224
135
|
Searching companies…
|
|
225
136
|
</v-list-item-title>
|
|
226
|
-
<v-list-item-title
|
|
227
|
-
|
|
228
|
-
@click.stop="handleAddNewCompany"
|
|
229
|
-
class="d-flex align-center ga-1"
|
|
230
|
-
>
|
|
137
|
+
<v-list-item-title v-else-if="companyNameInput" @click.stop="handleAddNewCompany"
|
|
138
|
+
class="d-flex align-center ga-1">
|
|
231
139
|
<span><v-icon icon="mdi-plus" /></span>Add "<strong>{{
|
|
232
140
|
companyNameInput
|
|
233
|
-
|
|
234
|
-
>" as new company.
|
|
141
|
+
}}</strong>" as new company.
|
|
235
142
|
</v-list-item-title>
|
|
236
|
-
<v-list-item-title
|
|
237
|
-
v-else-if="!companyNameInput && companyNames.length === 0"
|
|
238
|
-
>
|
|
143
|
+
<v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
|
|
239
144
|
Start typing to search for companies.
|
|
240
145
|
</v-list-item-title>
|
|
241
146
|
<v-list-item-title v-else>
|
|
@@ -250,135 +155,61 @@
|
|
|
250
155
|
<v-col v-if="shouldShowField('plateNumber')" cols="12">
|
|
251
156
|
<v-row>
|
|
252
157
|
<v-col cols="12">
|
|
253
|
-
<InputLabel
|
|
254
|
-
class="text-capitalize"
|
|
255
|
-
title="Vehicle Number"
|
|
256
|
-
required
|
|
257
|
-
/>
|
|
158
|
+
<InputLabel class="text-capitalize" title="Vehicle Number" required />
|
|
258
159
|
<!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
|
|
259
|
-
<InputVehicleNumber
|
|
260
|
-
v-model="visitor.plateNumber"
|
|
261
|
-
density="comfortable"
|
|
262
|
-
/>
|
|
160
|
+
<InputVehicleNumber v-model="visitor.plateNumber" density="comfortable" />
|
|
263
161
|
</v-col>
|
|
264
162
|
</v-row>
|
|
265
163
|
</v-col>
|
|
266
164
|
|
|
267
165
|
<v-col v-if="shouldShowField('block')" cols="12">
|
|
268
166
|
<InputLabel class="text-capitalize" title="Block" required />
|
|
269
|
-
<v-autocomplete
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
autocomplete="off"
|
|
274
|
-
item-title="title"
|
|
275
|
-
:key="
|
|
276
|
-
blockListDataPending ? 'block-list-pending' : 'block-list-ready'
|
|
277
|
-
"
|
|
278
|
-
:loading="blockListDataPending"
|
|
279
|
-
@update:model-value="handleChangeBlock"
|
|
280
|
-
density="comfortable"
|
|
281
|
-
:rules="[requiredRule]"
|
|
282
|
-
/>
|
|
167
|
+
<v-autocomplete v-model="visitor.block" :items="blocksArray" item-value="value" autocomplete="off"
|
|
168
|
+
item-title="title" :key="blockListDataPending ? 'block-list-pending' : 'block-list-ready'
|
|
169
|
+
" :loading="blockListDataPending" @update:model-value="handleChangeBlock" density="comfortable"
|
|
170
|
+
:rules="[requiredRule]" />
|
|
283
171
|
</v-col>
|
|
284
172
|
|
|
285
173
|
<v-col v-if="shouldShowField('level')" cols="12">
|
|
286
174
|
<InputLabel class="text-capitalize" title="Level" required />
|
|
287
|
-
<v-autocomplete
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
density="comfortable"
|
|
291
|
-
autocomplete="off"
|
|
292
|
-
:disabled="!visitor.block"
|
|
293
|
-
:key="
|
|
294
|
-
levelsDataPending ? 'level-list-pending' : 'level-list-ready'
|
|
295
|
-
"
|
|
296
|
-
:loading="levelsDataPending"
|
|
297
|
-
@update:model-value="handleChangeLevel"
|
|
298
|
-
:rules="[requiredRule]"
|
|
299
|
-
/>
|
|
175
|
+
<v-autocomplete v-model="visitor.level" :items="levelsArray" density="comfortable" autocomplete="off"
|
|
176
|
+
:disabled="!visitor.block" :key="levelsDataPending ? 'level-list-pending' : 'level-list-ready'
|
|
177
|
+
" :loading="levelsDataPending" @update:model-value="handleChangeLevel" :rules="[requiredRule]" />
|
|
300
178
|
</v-col>
|
|
301
179
|
<v-col v-if="shouldShowField('unit')" cols="12">
|
|
302
180
|
<InputLabel class="text-capitalize" title="Unit" required />
|
|
303
|
-
<v-autocomplete
|
|
304
|
-
|
|
305
|
-
:
|
|
306
|
-
|
|
307
|
-
autocomplete="off"
|
|
308
|
-
item-title="title"
|
|
309
|
-
item-value="value"
|
|
310
|
-
:disabled="!visitor.level"
|
|
311
|
-
:key="unitsDataPending ? 'unit-list-pending' : 'unit-list-ready'"
|
|
312
|
-
:loading="unitsDataPending"
|
|
313
|
-
:rules="[requiredRule]"
|
|
314
|
-
@update:model-value="handleUpdateUnit"
|
|
315
|
-
/>
|
|
181
|
+
<v-autocomplete v-model="visitor.unit" :items="unitsArray" density="comfortable" autocomplete="off"
|
|
182
|
+
item-title="title" item-value="value" :disabled="!visitor.level"
|
|
183
|
+
:key="unitsDataPending ? 'unit-list-pending' : 'unit-list-ready'" :loading="unitsDataPending"
|
|
184
|
+
:rules="[requiredRule]" @update:model-value="handleUpdateUnit" />
|
|
316
185
|
</v-col>
|
|
317
186
|
|
|
318
187
|
<v-col v-if="shouldShowField('unit')" cols="12">
|
|
319
|
-
<InputLabel
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
:key="'unit-key' + visitor.level"
|
|
324
|
-
/>
|
|
325
|
-
<v-text-field
|
|
326
|
-
v-model.trim="registeredUnitCompanyName"
|
|
327
|
-
density="comfortable"
|
|
328
|
-
:loading="buildingUnitDataPending"
|
|
329
|
-
readonly
|
|
330
|
-
class="no-pointer"
|
|
331
|
-
/>
|
|
188
|
+
<InputLabel class="text-capitalize" title="Registered Unit Company Name" required
|
|
189
|
+
:key="'unit-key' + visitor.level" />
|
|
190
|
+
<v-text-field v-model.trim="registeredUnitCompanyName" density="comfortable"
|
|
191
|
+
:loading="buildingUnitDataPending" readonly class="no-pointer" />
|
|
332
192
|
</v-col>
|
|
333
193
|
|
|
334
194
|
<v-col v-if="shouldShowField('remarks')" cols="12">
|
|
335
195
|
<InputLabel class="text-capitalize" title="Remarks" />
|
|
336
|
-
<v-textarea
|
|
337
|
-
v-model="visitor.remarks"
|
|
338
|
-
density="comfortable"
|
|
339
|
-
:rows="3"
|
|
340
|
-
no-resize
|
|
341
|
-
/>
|
|
196
|
+
<v-textarea v-model="visitor.remarks" density="comfortable" :rows="3" no-resize />
|
|
342
197
|
</v-col>
|
|
343
198
|
|
|
344
|
-
<v-col
|
|
345
|
-
v-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
<
|
|
349
|
-
v-model:
|
|
350
|
-
|
|
351
|
-
:
|
|
352
|
-
:
|
|
353
|
-
:contractor-type="visitor.contractorType"
|
|
354
|
-
:hide-keys="!showShowKeysField"
|
|
355
|
-
:passKeys="visitor.passKeys"
|
|
356
|
-
:clearable="true"
|
|
357
|
-
/>
|
|
358
|
-
<EntryPassInformation
|
|
359
|
-
v-if="showEntryPassInformation"
|
|
360
|
-
v-model="passType"
|
|
361
|
-
v-model:quantity="passQuantity"
|
|
362
|
-
v-model:cards="passCards"
|
|
363
|
-
:settings="entryPassSettings"
|
|
364
|
-
:loading="entryPassSettingsPending || siteDataPending"
|
|
365
|
-
:site-id="prop.site"
|
|
366
|
-
:unit-id="visitor.unit || null"
|
|
367
|
-
:visitor-type="prop.type"
|
|
368
|
-
:hid-qr-code-enabled="hidQrCodePassAllowed"
|
|
369
|
-
:hid-qr-printer-configured="hasHidQrPrinterConfig"
|
|
370
|
-
/>
|
|
199
|
+
<v-col v-show="(withStep2 || withStep3) && contractorStep === 2" cols="12">
|
|
200
|
+
<PassInformation v-model:pass="visitor.visitorPass" v-model:keys="visitor.passKeys" :site="prop.site"
|
|
201
|
+
:type="prop.type" :contractor-type="visitor.contractorType" :hide-keys="!showShowKeysField"
|
|
202
|
+
:passKeys="visitor.passKeys" :clearable="true" />
|
|
203
|
+
<EntryPassInformation v-if="showEntryPassInformation" v-model="passType" v-model:quantity="passQuantity"
|
|
204
|
+
v-model:cards="passCards" :settings="entryPassSettings"
|
|
205
|
+
:loading="entryPassSettingsPending || siteDataPending" :site-id="prop.site"
|
|
206
|
+
:unit-id="visitor.unit || null" :visitor-type="prop.type" :hid-qr-code-enabled="hidQrCodePassAllowed"
|
|
207
|
+
:hid-qr-printer-configured="hasHidQrPrinterConfig" />
|
|
371
208
|
</v-col>
|
|
372
209
|
|
|
373
210
|
<v-col v-show="withStep3 && contractorStep === 3" cols="12">
|
|
374
|
-
<MemberInformation
|
|
375
|
-
|
|
376
|
-
:type="prop.type"
|
|
377
|
-
:contractor-type="visitor.contractorType"
|
|
378
|
-
:site="prop.site"
|
|
379
|
-
:selected-visitor-pass="visitor.visitorPass"
|
|
380
|
-
:clearable="true"
|
|
381
|
-
/>
|
|
211
|
+
<MemberInformation v-model="visitor.members" :type="prop.type" :contractor-type="visitor.contractorType"
|
|
212
|
+
:site="prop.site" :selected-visitor-pass="visitor.visitorPass" :clearable="true" />
|
|
382
213
|
</v-col>
|
|
383
214
|
|
|
384
215
|
<v-col v-if="prop.mode === 'add'" cols="12" class="mt-2">
|
|
@@ -402,89 +233,33 @@
|
|
|
402
233
|
<v-toolbar density="compact">
|
|
403
234
|
<v-row no-gutters>
|
|
404
235
|
<v-col cols="6">
|
|
405
|
-
<v-btn
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
variant="text"
|
|
414
|
-
class="text-none"
|
|
415
|
-
size="48"
|
|
416
|
-
@click="handleGoToPreviousPage"
|
|
417
|
-
text="Back"
|
|
418
|
-
/>
|
|
419
|
-
<v-btn
|
|
420
|
-
v-else-if="prop.mode === 'add' || prop.mode === 'register'"
|
|
421
|
-
tile
|
|
422
|
-
block
|
|
423
|
-
variant="text"
|
|
424
|
-
class="text-none"
|
|
425
|
-
size="48"
|
|
426
|
-
@click="backToSelection"
|
|
427
|
-
text="Back to Selection"
|
|
428
|
-
/>
|
|
429
|
-
<v-btn
|
|
430
|
-
v-else
|
|
431
|
-
tile
|
|
432
|
-
block
|
|
433
|
-
variant="text"
|
|
434
|
-
class="text-none"
|
|
435
|
-
size="48"
|
|
436
|
-
@click="emit('close:all')"
|
|
437
|
-
text="Close"
|
|
438
|
-
/>
|
|
236
|
+
<v-btn v-if="
|
|
237
|
+
prop.mode === 'add' &&
|
|
238
|
+
(withStep2 || withStep3) &&
|
|
239
|
+
contractorStep > 1
|
|
240
|
+
" tile block variant="text" class="text-none" size="48" @click="handleGoToPreviousPage" text="Back" />
|
|
241
|
+
<v-btn v-else-if="prop.mode === 'add' || prop.mode === 'register'" tile block variant="text" class="text-none"
|
|
242
|
+
size="48" @click="backToSelection" text="Back to Selection" />
|
|
243
|
+
<v-btn v-else tile block variant="text" class="text-none" size="48" @click="emit('close:all')" text="Close" />
|
|
439
244
|
</v-col>
|
|
440
245
|
<v-col cols="6">
|
|
441
|
-
<v-btn
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
color="primary-button"
|
|
447
|
-
class="text-none"
|
|
448
|
-
size="48"
|
|
449
|
-
:disabled="processing"
|
|
450
|
-
@click="handleNextPage"
|
|
451
|
-
:text="'Next'"
|
|
452
|
-
/>
|
|
453
|
-
<v-btn
|
|
454
|
-
v-else
|
|
455
|
-
tile
|
|
456
|
-
block
|
|
457
|
-
variant="flat"
|
|
458
|
-
color="black"
|
|
459
|
-
class="text-none"
|
|
460
|
-
size="48"
|
|
461
|
-
:disabled="!validForm || processing || membersFieldIncomplete"
|
|
462
|
-
@click="submit"
|
|
463
|
-
:text="prop.mode == 'add' ? 'Submit' : 'Update'"
|
|
464
|
-
/>
|
|
246
|
+
<v-btn v-if="showNextButton" tile block variant="flat" color="primary-button" class="text-none" size="48"
|
|
247
|
+
:disabled="processing" @click="handleNextPage" :text="'Next'" />
|
|
248
|
+
<v-btn v-else tile block variant="flat" color="black" class="text-none" size="48"
|
|
249
|
+
:disabled="!validForm || processing || membersFieldIncomplete" @click="submit"
|
|
250
|
+
:text="prop.mode == 'add' ? 'Submit' : 'Update'" />
|
|
465
251
|
</v-col>
|
|
466
252
|
</v-row>
|
|
467
253
|
</v-toolbar>
|
|
468
254
|
|
|
469
|
-
<v-dialog
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
>
|
|
475
|
-
<SearchVehicleNumberUser
|
|
476
|
-
:vehicle-number="visitor.plateNumber ?? ''"
|
|
477
|
-
:vehicle-number-users-list="vehicleNumberUserItems"
|
|
478
|
-
@close="dialog.vehicleNumberUsersList = false"
|
|
479
|
-
@update:people="handleAutofillDataViaVehicleNumber"
|
|
480
|
-
/>
|
|
255
|
+
<v-dialog v-model="dialog.vehicleNumberUsersList" v-if="vehicleNumberUserItems.length > 0" persistent
|
|
256
|
+
max-width="600">
|
|
257
|
+
<SearchVehicleNumberUser :vehicle-number="visitor.plateNumber ?? ''"
|
|
258
|
+
:vehicle-number-users-list="vehicleNumberUserItems" @close="dialog.vehicleNumberUsersList = false"
|
|
259
|
+
@update:people="handleAutofillDataViaVehicleNumber" />
|
|
481
260
|
</v-dialog>
|
|
482
261
|
|
|
483
|
-
<v-dialog
|
|
484
|
-
v-model="dialog.showNonCheckedOutDialog"
|
|
485
|
-
max-width="700"
|
|
486
|
-
persistent
|
|
487
|
-
>
|
|
262
|
+
<v-dialog v-model="dialog.showNonCheckedOutDialog" max-width="700" persistent>
|
|
488
263
|
<v-card :loading="loading.checkingOut">
|
|
489
264
|
<v-toolbar>
|
|
490
265
|
<v-toolbar-title>
|
|
@@ -498,12 +273,8 @@
|
|
|
498
273
|
|
|
499
274
|
<v-card-text>
|
|
500
275
|
<v-list lines="three">
|
|
501
|
-
<v-list-item
|
|
502
|
-
v-
|
|
503
|
-
v-for="v in matchingPlateNumberNonCheckedOutArr"
|
|
504
|
-
:key="v._id"
|
|
505
|
-
class="cursor-pointer"
|
|
506
|
-
>
|
|
276
|
+
<v-list-item v-if="matchingPlateNumberNonCheckedOutArr.length > 0"
|
|
277
|
+
v-for="v in matchingPlateNumberNonCheckedOutArr" :key="v._id" class="cursor-pointer">
|
|
507
278
|
<v-list-item-title>
|
|
508
279
|
{{ v.plateNumber }} - {{ v.name }}
|
|
509
280
|
</v-list-item-title>
|
|
@@ -513,16 +284,8 @@
|
|
|
513
284
|
</v-list-item-subtitle>
|
|
514
285
|
|
|
515
286
|
<template #append>
|
|
516
|
-
<v-btn
|
|
517
|
-
|
|
518
|
-
class="text-capitalize"
|
|
519
|
-
color="red"
|
|
520
|
-
text="Checkout"
|
|
521
|
-
:loading="
|
|
522
|
-
loading.checkingOut && v?._id === prop.visitorData?._id
|
|
523
|
-
"
|
|
524
|
-
@click.stop="handleCheckout(v._id)"
|
|
525
|
-
/>
|
|
287
|
+
<v-btn size="x-small" class="text-capitalize" color="red" text="Checkout" :loading="loading.checkingOut && v?._id === prop.visitorData?._id
|
|
288
|
+
" @click.stop="handleCheckout(v._id)" />
|
|
526
289
|
</template>
|
|
527
290
|
</v-list-item>
|
|
528
291
|
</v-list>
|
|
@@ -536,6 +299,14 @@
|
|
|
536
299
|
import { propsFactory } from "vuetify/lib/util/propsFactory.mjs";
|
|
537
300
|
import useBuildingUnit from "../composables/useBuildingUnit";
|
|
538
301
|
import useWebUsb from "../composables/useWebUsb";
|
|
302
|
+
import useUtils from "../composables/useUtils";
|
|
303
|
+
import useSiteSettings from "../composables/useSiteSettings";
|
|
304
|
+
import useLocalAuth from "../composables/useLocalAuth";
|
|
305
|
+
import useBuilding from "../composables/useBuilding";
|
|
306
|
+
import useVisitor from "../composables/useVisitor";
|
|
307
|
+
import useSiteEntryPassSettings from "../composables/useSiteEntryPassSettings";
|
|
308
|
+
import useAccessManagement from "../composables/useAccessManagement";
|
|
309
|
+
import usePeople from "../composables/usePeople";
|
|
539
310
|
|
|
540
311
|
const prop = defineProps({
|
|
541
312
|
type: {
|
|
@@ -569,6 +340,7 @@ const currentAutofillSource = ref<AutofillSource>(null);
|
|
|
569
340
|
|
|
570
341
|
const { requiredRule, debounce, UTCToLocalTIme } = useUtils();
|
|
571
342
|
const { getSiteById } = useSiteSettings();
|
|
343
|
+
const { currentUser } = useLocalAuth();
|
|
572
344
|
const { getBlocksSelection, getLevelsSelection, getUnitSelection } =
|
|
573
345
|
useBuilding();
|
|
574
346
|
const {
|
|
@@ -584,7 +356,7 @@ const { createVisitorPass, signQr } = useAccessManagement();
|
|
|
584
356
|
const { testConnection } = useWebUsb();
|
|
585
357
|
const {
|
|
586
358
|
findPersonByNRIC,
|
|
587
|
-
|
|
359
|
+
findPersonByNRICMultipleResult,
|
|
588
360
|
searchCompanyList,
|
|
589
361
|
findUsersByPlateNumber,
|
|
590
362
|
} = usePeople();
|
|
@@ -734,7 +506,7 @@ const hidQrCodePassAllowed = computed(() => {
|
|
|
734
506
|
const showEntryPassInformation = computed(() => {
|
|
735
507
|
return Boolean(
|
|
736
508
|
entryPassSettings.value?.data?.settings?.nfcPass ||
|
|
737
|
-
|
|
509
|
+
hidQrCodePassAllowed.value
|
|
738
510
|
);
|
|
739
511
|
});
|
|
740
512
|
|
|
@@ -748,6 +520,9 @@ const companyAutofillDataArray = ref<
|
|
|
748
520
|
unitName: string;
|
|
749
521
|
}[]
|
|
750
522
|
>([]);
|
|
523
|
+
const nricSearchMenu = ref(false);
|
|
524
|
+
const nricSearchResults = ref<Partial<TPeople>[]>([]);
|
|
525
|
+
const skipNricFetch = ref(false);
|
|
751
526
|
|
|
752
527
|
const formTitle = computed(() => {
|
|
753
528
|
const isContractorForm = prop.type === "contractor";
|
|
@@ -819,57 +594,50 @@ const {
|
|
|
819
594
|
pending: fetchPersonByNRICPending,
|
|
820
595
|
} = useLazyAsyncData(`fetch-person`, () => {
|
|
821
596
|
const NRIC = visitor.nric;
|
|
822
|
-
if (!NRIC) return Promise.resolve(null);
|
|
823
|
-
return
|
|
597
|
+
if (!NRIC || NRIC.length < 4) return Promise.resolve(null);
|
|
598
|
+
return findPersonByNRICMultipleResult(NRIC, prop.site);
|
|
824
599
|
});
|
|
825
600
|
|
|
826
601
|
watch(fetchPersonByNRICReq, (obj) => {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
visitor.contact = obj.contact;
|
|
832
|
-
if (!visitor.company) {
|
|
833
|
-
visitor.company = companyNames.value?.[0];
|
|
834
|
-
}
|
|
835
|
-
visitor.block = obj.block ?? "";
|
|
836
|
-
visitor.level = obj.level ?? "";
|
|
837
|
-
visitor.unit = obj.unit ?? "";
|
|
602
|
+
const items = obj?.items ?? [];
|
|
603
|
+
nricSearchResults.value = Array.isArray(items) ? items : [];
|
|
604
|
+
nricSearchMenu.value = nricSearchResults.value.length > 0;
|
|
605
|
+
});
|
|
838
606
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
607
|
+
watch(
|
|
608
|
+
() => visitor.nric,
|
|
609
|
+
(value) => {
|
|
610
|
+
if (!value || value.length < 4) {
|
|
611
|
+
nricSearchMenu.value = false;
|
|
612
|
+
nricSearchResults.value = [];
|
|
613
|
+
}
|
|
842
614
|
}
|
|
843
|
-
|
|
615
|
+
);
|
|
844
616
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
} = useLazyAsyncData(`fetch-contact`, () => {
|
|
850
|
-
const contact = visitor.contact;
|
|
851
|
-
if (!contact) return Promise.resolve(null);
|
|
852
|
-
return findPersonByContact(contact);
|
|
853
|
-
});
|
|
617
|
+
function selectNricSearchResult(item: Partial<TPeople>) {
|
|
618
|
+
nricSearchMenu.value = false;
|
|
619
|
+
nricSearchResults.value = [];
|
|
620
|
+
skipNricFetch.value = true;
|
|
854
621
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
// visitor.block = visitor.block ?? obj.block ?? ""
|
|
864
|
-
// visitor.level = visitor.level ?? obj.level ?? ""
|
|
865
|
-
// visitor.unit = visitor.unit ?? obj.unit ?? ""
|
|
866
|
-
visitor.nric = visitor.nric ?? obj.nric ?? "";
|
|
867
|
-
|
|
868
|
-
setTimeout(() => {
|
|
869
|
-
currentAutofillSource.value = null;
|
|
870
|
-
}, 1000);
|
|
622
|
+
currentAutofillSource.value = "nric";
|
|
623
|
+
|
|
624
|
+
visitor.nric = item.nric || visitor.nric;
|
|
625
|
+
visitor.name = item.name || visitor.name;
|
|
626
|
+
visitor.contact = item.contact || visitor.contact;
|
|
627
|
+
companyNames.value = item.companyName ?? [];
|
|
628
|
+
if (!visitor.company) {
|
|
629
|
+
visitor.company = companyNames.value?.[0] || visitor.company;
|
|
871
630
|
}
|
|
872
|
-
|
|
631
|
+
visitor.block = (item.block as any) ?? (visitor.block as any) ?? "";
|
|
632
|
+
visitor.level = (item.level as any) ?? (visitor.level as any) ?? "";
|
|
633
|
+
visitor.unit = item.unit ?? visitor.unit ?? "";
|
|
634
|
+
visitor.unitName = item.unitName ?? visitor.unitName;
|
|
635
|
+
|
|
636
|
+
setTimeout(() => {
|
|
637
|
+
currentAutofillSource.value = null;
|
|
638
|
+
skipNricFetch.value = false;
|
|
639
|
+
}, 1000);
|
|
640
|
+
}
|
|
873
641
|
|
|
874
642
|
const {
|
|
875
643
|
data: fetchCompanyListReq,
|
|
@@ -1171,20 +939,14 @@ function handleUpdateUnit(value: any) {
|
|
|
1171
939
|
}
|
|
1172
940
|
|
|
1173
941
|
const debounceFetchNRIC = debounce(fetchPersonByNRICRefresh, 500);
|
|
1174
|
-
const debounceFetchContact = debounce(fetchPersonByContactRefresh, 500);
|
|
1175
942
|
|
|
1176
943
|
function handleUpdateNRIC() {
|
|
944
|
+
if (skipNricFetch.value) return;
|
|
1177
945
|
if (currentAutofillSource.value && currentAutofillSource.value !== "nric")
|
|
1178
946
|
return;
|
|
1179
947
|
debounceFetchNRIC();
|
|
1180
948
|
}
|
|
1181
949
|
|
|
1182
|
-
function handleUpdateContact() {
|
|
1183
|
-
if (currentAutofillSource.value && currentAutofillSource.value !== "contact")
|
|
1184
|
-
return;
|
|
1185
|
-
debounceFetchContact();
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
950
|
function backToSelection() {
|
|
1189
951
|
emit("back");
|
|
1190
952
|
message.value = "";
|
|
@@ -1291,6 +1053,10 @@ async function submit() {
|
|
|
1291
1053
|
// add register status when registering unregistered visitor
|
|
1292
1054
|
if (prop.mode === "register") {
|
|
1293
1055
|
payload.status = "registered";
|
|
1056
|
+
const currentUserId = currentUser.value?._id;
|
|
1057
|
+
if(currentUserId) {
|
|
1058
|
+
payload.updatedBy = currentUserId;
|
|
1059
|
+
}
|
|
1294
1060
|
}
|
|
1295
1061
|
|
|
1296
1062
|
try {
|
|
@@ -1321,8 +1087,7 @@ async function submit() {
|
|
|
1321
1087
|
const visitorId = res as unknown as string;
|
|
1322
1088
|
const rawUrl = entryPassSettings.value?.data?.settings?.url;
|
|
1323
1089
|
const { encrypted: acmUrl } = await $fetch<{ encrypted: string }>(
|
|
1324
|
-
`/api/encrypt-acm-url${
|
|
1325
|
-
rawUrl ? `?url=${encodeURIComponent(rawUrl)}` : ""
|
|
1090
|
+
`/api/encrypt-acm-url${rawUrl ? `?url=${encodeURIComponent(rawUrl)}` : ""
|
|
1326
1091
|
}`
|
|
1327
1092
|
);
|
|
1328
1093
|
if (visitorId && acmUrl) {
|
|
@@ -1431,8 +1196,7 @@ async function submit() {
|
|
|
1431
1196
|
const err = error?.data?.message;
|
|
1432
1197
|
errorMessage.value =
|
|
1433
1198
|
err ||
|
|
1434
|
-
`Failed to ${
|
|
1435
|
-
prop.mode === "add" ? "add" : "update"
|
|
1199
|
+
`Failed to ${prop.mode === "add" ? "add" : "update"
|
|
1436
1200
|
} visitor. Please try again.`;
|
|
1437
1201
|
} finally {
|
|
1438
1202
|
processing.value = false;
|