@iservice365/layer-common 1.6.0 → 1.7.0
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/AccessCardAddForm.vue +363 -0
- package/components/AccessManagement.vue +286 -8
- package/components/BuildingUnitFormEdit.vue +47 -0
- package/components/EntryPassMain.vue +231 -0
- package/components/ImageCarousel.vue +74 -34
- package/components/Input/FileV2.vue +1 -1
- package/components/Input/NRICNumber.vue +2 -2
- package/components/Input/VehicleNumber.vue +1 -1
- package/components/Nfc/NFCTagForm.vue +210 -0
- package/components/Nfc/NFCTagMain.vue +342 -0
- package/components/VideoPlayer.vue +125 -0
- package/components/VisitorForm.vue +143 -62
- package/components/VisitorManagement.vue +1 -14
- package/composables/useCard.ts +46 -0
- package/composables/useNFCPatrolTag.ts +51 -0
- package/composables/usePeople.ts +19 -1
- package/composables/useVisitor.ts +1 -1
- package/package.json +1 -1
- package/types/building.d.ts +2 -0
- package/types/card.d.ts +22 -0
|
@@ -19,16 +19,17 @@
|
|
|
19
19
|
<v-row no-gutters class="pt-4">
|
|
20
20
|
<v-col v-if="shouldShowField('contractorType')" cols="12">
|
|
21
21
|
<InputLabel class="text-capitalize" title="Contractor Type" required />
|
|
22
|
-
<v-combobox v-model="contractorTypeObj" v-model:search="contractorTypeInput"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
density="comfortable" persistent-hint
|
|
22
|
+
<v-combobox v-model="contractorTypeObj" v-model:search="contractorTypeInput" ref="contractorTypeCombo"
|
|
23
|
+
autocomplete="off" :hide-no-data="false" @update:focused="handleFocusedContractorType"
|
|
24
|
+
:items="contractorTypes" :rules="[requiredRule]" item-value="value"
|
|
25
|
+
@update:model-value="handleSelectContractorType" variant="outlined" density="comfortable" persistent-hint
|
|
26
|
+
small-chips>
|
|
26
27
|
<template v-slot:no-data>
|
|
27
28
|
<v-list-item>
|
|
28
|
-
<v-list-item-title>
|
|
29
|
-
|
|
29
|
+
<v-list-item-title @click.stop="handleAddNewContractorType" class="d-flex align-center ga-1">
|
|
30
|
+
<span><v-icon icon="mdi-plus" /></span> Add "<strong>{{
|
|
30
31
|
contractorTypeInput
|
|
31
|
-
}}</strong>"
|
|
32
|
+
}}</strong>" as custom contractor type.
|
|
32
33
|
</v-list-item-title>
|
|
33
34
|
</v-list-item>
|
|
34
35
|
</template>
|
|
@@ -53,14 +54,16 @@
|
|
|
53
54
|
<v-row>
|
|
54
55
|
<v-col cols="12">
|
|
55
56
|
<InputLabel class="text-capitalize" title="NRIC/Passport/ID No." required />
|
|
56
|
-
<InputNRICNumber v-model
|
|
57
|
+
<InputNRICNumber v-model="visitor.nric" density="comfortable" :rules="[requiredRule]"
|
|
58
|
+
@update:model-value="handleUpdateNRIC" :loading="fetchPersonByNRICPending" />
|
|
57
59
|
</v-col>
|
|
58
60
|
</v-row>
|
|
59
61
|
</v-col>
|
|
60
62
|
|
|
61
63
|
<v-col v-if="shouldShowField('contact')" cols="12">
|
|
62
64
|
<InputLabel class="text-capitalize" title="Phone Number" required />
|
|
63
|
-
<InputPhoneNumberV2 v-model="visitor.contact" :rules="[requiredRule]" density="comfortable"
|
|
65
|
+
<InputPhoneNumberV2 v-model="visitor.contact" :rules="[requiredRule]" density="comfortable"
|
|
66
|
+
:loading="fetchPersonByContactPending" @update:model-value="handleUpdateContact" />
|
|
64
67
|
</v-col>
|
|
65
68
|
|
|
66
69
|
<v-col v-if="shouldShowField('deliveryType')" cols="12">
|
|
@@ -75,16 +78,25 @@
|
|
|
75
78
|
</v-col>
|
|
76
79
|
|
|
77
80
|
<template v-if="shouldShowField('company')">
|
|
78
|
-
<v-col
|
|
79
|
-
<InputLabel class="text-capitalize" title="Company Name"
|
|
80
|
-
<v-combobox v-model="visitor.company" v-model:search="companyNameInput"
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
<v-col cols="12">
|
|
82
|
+
<InputLabel class="text-capitalize" title="Company Name" />
|
|
83
|
+
<v-combobox v-model="visitor.company" v-model:search="companyNameInput" ref="companyCombo"
|
|
84
|
+
autocomplete="off" :hide-no-data="false" :items="companyNames" item-value="value"
|
|
85
|
+
:loading="fetchCompanyListPending" @update:model-value="handleSelectCompanyName" variant="outlined"
|
|
83
86
|
density="comfortable" persistent-hint small-chips>
|
|
84
87
|
<template v-slot:no-data>
|
|
85
88
|
<v-list-item>
|
|
86
|
-
<v-list-item-title v-if="
|
|
87
|
-
|
|
89
|
+
<v-list-item-title v-if="fetchCompanyListPending">
|
|
90
|
+
<v-progress-circular indeterminate size="20" class="mr-3" />
|
|
91
|
+
Searching companies…
|
|
92
|
+
</v-list-item-title>
|
|
93
|
+
<v-list-item-title v-else-if="companyNameInput" @click.stop="handleAddNewCompany"
|
|
94
|
+
class="d-flex align-center ga-1">
|
|
95
|
+
<span><v-icon icon="mdi-plus" /></span>Add "<strong>{{ companyNameInput }}</strong>" as new
|
|
96
|
+
company.
|
|
97
|
+
</v-list-item-title>
|
|
98
|
+
<v-list-item-title v-else-if="!companyNameInput && companyNames.length === 0">
|
|
99
|
+
Start typing to search for companies.
|
|
88
100
|
</v-list-item-title>
|
|
89
101
|
<v-list-item-title v-else>
|
|
90
102
|
No companies available. Start typing to add a new one.
|
|
@@ -101,7 +113,7 @@
|
|
|
101
113
|
<v-col cols="12">
|
|
102
114
|
<InputLabel class="text-capitalize" title="Vehicle Number" required />
|
|
103
115
|
<!-- <v-text-field v-model.trim.uppercase="visitor.plateNumber" density="comfortable" /> -->
|
|
104
|
-
<InputVehicleNumber v-model
|
|
116
|
+
<InputVehicleNumber v-model="visitor.plateNumber" density="comfortable" :rules="[requiredRule]" />
|
|
105
117
|
</v-col>
|
|
106
118
|
</v-row>
|
|
107
119
|
</v-col>
|
|
@@ -121,7 +133,8 @@
|
|
|
121
133
|
|
|
122
134
|
<v-col v-if="shouldShowField('unit')" cols="12">
|
|
123
135
|
<InputLabel class="text-capitalize" title="Unit" required />
|
|
124
|
-
<v-select v-model="visitor.unit" :items="unitsArray" density="comfortable"
|
|
136
|
+
<v-select v-model="visitor.unit" :items="unitsArray" density="comfortable" item-title="title"
|
|
137
|
+
item-value="value" :disabled="!visitor.level"
|
|
125
138
|
:loading="unitsStatus === 'pending'" :rules="[requiredRule]" @update:model-value="handleUpdateUnit" />
|
|
126
139
|
</v-col>
|
|
127
140
|
|
|
@@ -207,7 +220,7 @@ const prop = defineProps({
|
|
|
207
220
|
const { requiredRule, debounce } = useUtils();
|
|
208
221
|
const { getSiteById, getSiteLevels, getSiteUnits } = useSiteSettings();
|
|
209
222
|
const { createVisitor, typeFieldMap, contractorTypes } = useVisitor();
|
|
210
|
-
const { findPersonByNRIC, findPersonByContact } = usePeople()
|
|
223
|
+
const { findPersonByNRIC, findPersonByContact, searchCompanyList } = usePeople()
|
|
211
224
|
|
|
212
225
|
const emit = defineEmits([
|
|
213
226
|
"back",
|
|
@@ -262,6 +275,7 @@ const shouldShowField = (fieldKey: keyof TVisitorPayload) => {
|
|
|
262
275
|
};
|
|
263
276
|
|
|
264
277
|
const companyNames = ref<string[]>([])
|
|
278
|
+
const companyAutofillDataArray = ref<{ companyName: string[], unit: string, block: number, level: string, unitName: string }[]>([])
|
|
265
279
|
|
|
266
280
|
const formTitle = computed(() => {
|
|
267
281
|
const isContractorForm = prop.type === "contractor";
|
|
@@ -278,48 +292,73 @@ function handleSelectContractorType(obj: { title: string; value: string }) {
|
|
|
278
292
|
}
|
|
279
293
|
|
|
280
294
|
function handleFocusedContractorType() {
|
|
281
|
-
const obj = contractorTypeObj.value;
|
|
282
|
-
const matched = contractorTypes.some(
|
|
283
|
-
|
|
284
|
-
);
|
|
285
|
-
if (!matched) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
295
|
+
// const obj = contractorTypeObj.value;
|
|
296
|
+
// const matched = contractorTypes.some(
|
|
297
|
+
// (x) => x.value === obj?.value && x.title === obj?.title
|
|
298
|
+
// );
|
|
299
|
+
// if (!matched) {
|
|
300
|
+
// contractorTypeObj.value = null;
|
|
301
|
+
// contractorTypeInput.value = ""
|
|
302
|
+
// visitor.contractorType = "";
|
|
303
|
+
// }
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const contractorTypeCombo = ref(null)
|
|
307
|
+
|
|
308
|
+
async function handleAddNewContractorType() {
|
|
309
|
+
visitor.contractorType = contractorTypeInput.value
|
|
310
|
+
|
|
311
|
+
const combo = contractorTypeCombo.value as any
|
|
312
|
+
await nextTick();
|
|
313
|
+
|
|
314
|
+
combo.isMenuActive = false;
|
|
315
|
+
combo.$el.querySelector("input")?.blur(); ``
|
|
316
|
+
|
|
290
317
|
}
|
|
291
318
|
|
|
292
|
-
function handleSelectCompanyName(company: string) {
|
|
319
|
+
async function handleSelectCompanyName(company: string) {
|
|
293
320
|
visitor.company = company
|
|
321
|
+
|
|
322
|
+
const selected = companyAutofillDataArray.value.find(x => x.companyName?.includes(company))
|
|
323
|
+
if (!selected) return
|
|
324
|
+
|
|
325
|
+
visitor.block = selected.block || ""
|
|
326
|
+
visitor.level = selected.level || ""
|
|
327
|
+
visitor.unit = selected.unit || ""
|
|
328
|
+
visitor.unitName = selected.unitName || ""
|
|
329
|
+
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const companyCombo = ref(null)
|
|
333
|
+
|
|
334
|
+
async function handleAddNewCompany() {
|
|
335
|
+
visitor.company = companyNameInput.value
|
|
336
|
+
|
|
337
|
+
const combo = companyCombo.value as any
|
|
338
|
+
await nextTick();
|
|
339
|
+
|
|
340
|
+
combo.isMenuActive = false;
|
|
341
|
+
combo.$el.querySelector("input")?.blur();
|
|
294
342
|
}
|
|
295
343
|
|
|
296
|
-
// function handleFocusedCompanyName() {
|
|
297
|
-
// const companyNameSelected = companyNameObj.value;
|
|
298
|
-
// const matched = companyNames.value.some((x) => x === companyNameSelected);
|
|
299
|
-
// if (!matched) {
|
|
300
|
-
// companyNameObj.value = null;
|
|
301
|
-
// companyNameInput.value = "";
|
|
302
|
-
// visitor.company = "";
|
|
303
|
-
// }
|
|
304
|
-
// }
|
|
305
344
|
|
|
306
345
|
const {
|
|
307
346
|
data: fetchPersonByNRICReq,
|
|
308
347
|
refresh: fetchPersonByNRICRefresh,
|
|
309
348
|
pending: fetchPersonByNRICPending,
|
|
310
|
-
} = useLazyAsyncData(`fetch-person`, () =>{
|
|
349
|
+
} = useLazyAsyncData(`fetch-person`, () => {
|
|
311
350
|
const NRIC = visitor.nric;
|
|
312
|
-
if(!NRIC) return Promise.resolve(null)
|
|
351
|
+
if (!NRIC) return Promise.resolve(null)
|
|
313
352
|
return findPersonByNRIC(NRIC)
|
|
314
353
|
}
|
|
315
354
|
);
|
|
316
355
|
|
|
317
356
|
watch(fetchPersonByNRICReq, (obj) => {
|
|
318
|
-
if(obj){
|
|
357
|
+
if (obj) {
|
|
319
358
|
companyNames.value = obj.companyName ?? []
|
|
320
359
|
visitor.name = obj.name
|
|
321
360
|
visitor.contact = obj.contact
|
|
322
|
-
if(!visitor.company){
|
|
361
|
+
if (!visitor.company) {
|
|
323
362
|
visitor.company = companyNames.value?.[0]
|
|
324
363
|
}
|
|
325
364
|
visitor.plateNumber = obj.plateNumber ?? ""
|
|
@@ -333,28 +372,57 @@ const {
|
|
|
333
372
|
data: fetchPersonByContactReq,
|
|
334
373
|
refresh: fetchPersonByContactRefresh,
|
|
335
374
|
pending: fetchPersonByContactPending,
|
|
336
|
-
} = useLazyAsyncData(`fetch-contact`, () =>{
|
|
375
|
+
} = useLazyAsyncData(`fetch-contact`, () => {
|
|
337
376
|
const contact = visitor.contact;
|
|
338
|
-
if(!contact) return Promise.resolve(null)
|
|
377
|
+
if (!contact) return Promise.resolve(null)
|
|
339
378
|
return findPersonByContact(contact)
|
|
340
379
|
}
|
|
341
380
|
);
|
|
342
381
|
|
|
343
382
|
watch(fetchPersonByContactReq, (obj) => {
|
|
344
|
-
if(obj){
|
|
383
|
+
if (obj) {
|
|
345
384
|
companyNames.value = obj.companyName ?? []
|
|
346
385
|
visitor.name = obj.name
|
|
347
|
-
if(!visitor.company){
|
|
386
|
+
if (!visitor.company) {
|
|
348
387
|
visitor.company = companyNames.value?.[0]
|
|
349
388
|
}
|
|
350
389
|
visitor.plateNumber = obj.plateNumber ?? ""
|
|
351
390
|
visitor.block = obj.block ?? ""
|
|
352
391
|
visitor.level = obj.level ?? ""
|
|
353
392
|
visitor.unit = obj.unit ?? ""
|
|
354
|
-
visitor.nric = obj.nric
|
|
393
|
+
visitor.nric = obj.nric ?? ""
|
|
394
|
+
}
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
const {
|
|
398
|
+
data: fetchCompanyListReq,
|
|
399
|
+
refresh: fetchCompanyListRefresh,
|
|
400
|
+
pending: fetchCompanyListPending,
|
|
401
|
+
|
|
402
|
+
} = useLazyAsyncData(`fetch-company-list`, () => {
|
|
403
|
+
if (!companyNameInput.value) return Promise.resolve(null)
|
|
404
|
+
return searchCompanyList(companyNameInput.value)
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
watch(fetchCompanyListReq, (arr) => {
|
|
408
|
+
if (Array.isArray(arr)) {
|
|
409
|
+
companyAutofillDataArray.value = arr;
|
|
410
|
+
companyNames.value = arr?.flatMap(x => x?.companyName)
|
|
355
411
|
}
|
|
356
412
|
})
|
|
357
413
|
|
|
414
|
+
const debounceFetchCompany = debounce(async () => fetchCompanyListRefresh(), 200)
|
|
415
|
+
|
|
416
|
+
watch(companyNameInput, async (val) => {
|
|
417
|
+
if (!val) {
|
|
418
|
+
companyNames.value = []
|
|
419
|
+
return
|
|
420
|
+
}
|
|
421
|
+
await debounceFetchCompany()
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
|
|
358
426
|
const {
|
|
359
427
|
data: siteData,
|
|
360
428
|
refresh: refreshSiteData,
|
|
@@ -372,7 +440,7 @@ const {
|
|
|
372
440
|
async () => {
|
|
373
441
|
if (!visitor.block) return Promise.resolve(null);
|
|
374
442
|
return await getSiteLevels(prop.site, { block: Number(visitor.block) });
|
|
375
|
-
}, {watch: [() => visitor.block]}
|
|
443
|
+
}, { watch: [() => visitor.block] }
|
|
376
444
|
);
|
|
377
445
|
|
|
378
446
|
const {
|
|
@@ -384,7 +452,7 @@ const {
|
|
|
384
452
|
async () => {
|
|
385
453
|
if (!visitor.level) return Promise.resolve(null);
|
|
386
454
|
return await getSiteUnits(prop.site, Number(visitor.block), visitor.level);
|
|
387
|
-
}, {watch: [() => visitor.level]}
|
|
455
|
+
}, { watch: [() => visitor.level] }
|
|
388
456
|
);
|
|
389
457
|
|
|
390
458
|
watch(
|
|
@@ -425,18 +493,31 @@ watch(
|
|
|
425
493
|
watch(
|
|
426
494
|
unitsData,
|
|
427
495
|
(newVal: any) => {
|
|
428
|
-
if (newVal
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
title: unit?.name,
|
|
432
|
-
value: unit?._id,
|
|
433
|
-
}));
|
|
434
|
-
} else {
|
|
435
|
-
unitsArray.value = [];
|
|
496
|
+
if (!newVal) {
|
|
497
|
+
unitsArray.value = []
|
|
498
|
+
return
|
|
436
499
|
}
|
|
500
|
+
|
|
501
|
+
const mapped = newVal.map((unit: any) => ({
|
|
502
|
+
title: unit.name,
|
|
503
|
+
value: unit._id,
|
|
504
|
+
}))
|
|
505
|
+
|
|
506
|
+
// keep custom unit pushed from autofill
|
|
507
|
+
const selected = visitor.unit
|
|
508
|
+
const exists = mapped.some((u: TDefaultOptionObj) => u.value === selected)
|
|
509
|
+
|
|
510
|
+
if (!exists && visitor.unitName) {
|
|
511
|
+
mapped.push({
|
|
512
|
+
title: visitor.unitName,
|
|
513
|
+
value: selected,
|
|
514
|
+
})
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
unitsArray.value = mapped
|
|
437
518
|
},
|
|
438
519
|
{ immediate: true }
|
|
439
|
-
)
|
|
520
|
+
)
|
|
440
521
|
|
|
441
522
|
|
|
442
523
|
function handleChangeBlock(value: any) {
|
|
@@ -456,12 +537,12 @@ function handleUpdateUnit(value: any) {
|
|
|
456
537
|
const debounceFetchNRIC = debounce(fetchPersonByNRICRefresh, 500)
|
|
457
538
|
const debounceFetchContact = debounce(fetchPersonByContactRefresh, 500)
|
|
458
539
|
|
|
459
|
-
function handleUpdateNRIC(){
|
|
460
|
-
|
|
540
|
+
function handleUpdateNRIC() {
|
|
541
|
+
debounceFetchNRIC()
|
|
461
542
|
}
|
|
462
543
|
|
|
463
|
-
function handleUpdateContact(){
|
|
464
|
-
|
|
544
|
+
function handleUpdateContact() {
|
|
545
|
+
debounceFetchContact()
|
|
465
546
|
}
|
|
466
547
|
|
|
467
548
|
function backToSelection() {
|
|
@@ -256,6 +256,7 @@ const formattedFields = {
|
|
|
256
256
|
nric: "NRIC",
|
|
257
257
|
contact: "Phone Number",
|
|
258
258
|
plateNumber: "Vehicle Number",
|
|
259
|
+
company: "Company",
|
|
259
260
|
block: "Block",
|
|
260
261
|
level: "Level",
|
|
261
262
|
unitName: "Unit",
|
|
@@ -434,20 +435,6 @@ async function handleCheckout(userId: string) {
|
|
|
434
435
|
}
|
|
435
436
|
}
|
|
436
437
|
|
|
437
|
-
// get dates in ISO String (UTC Time)
|
|
438
|
-
function getUTCDates() {
|
|
439
|
-
const today = new Date();
|
|
440
|
-
const yesterday = new Date();
|
|
441
|
-
yesterday.setUTCDate(today.getUTCDate() - 1);
|
|
442
|
-
|
|
443
|
-
const dateFrom = ref(yesterday.toISOString()); // yesterday in UTC
|
|
444
|
-
const dateTo = ref(today.toISOString()); // today in UTC
|
|
445
|
-
|
|
446
|
-
const dateYesterday = yesterday.toISOString();
|
|
447
|
-
const dateToday = today.toISOString();
|
|
448
|
-
|
|
449
|
-
return { dateYesterday, dateToday };
|
|
450
|
-
}
|
|
451
438
|
|
|
452
439
|
|
|
453
440
|
const updateRouteQuery = debounce(
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export default function useCard() {
|
|
2
|
+
function getAll({
|
|
3
|
+
page = 1,
|
|
4
|
+
search = "",
|
|
5
|
+
limit = 10,
|
|
6
|
+
status = "active",
|
|
7
|
+
site = "",
|
|
8
|
+
} = {}) {
|
|
9
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/cards`, {
|
|
10
|
+
method: "GET",
|
|
11
|
+
query: {
|
|
12
|
+
page,
|
|
13
|
+
search,
|
|
14
|
+
limit,
|
|
15
|
+
status,
|
|
16
|
+
site,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function add(value: any) {
|
|
21
|
+
return useNuxtApp().$api<Record<string, any>>("/api/cards", {
|
|
22
|
+
method: "POST",
|
|
23
|
+
body: value,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function deleteById(id: string) {
|
|
28
|
+
return useNuxtApp().$api(`/api/cards/${id}`, {
|
|
29
|
+
method: "DELETE",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function updateById(id: string, value: any) {
|
|
34
|
+
return useNuxtApp().$api(`/api/cards/${id}`, {
|
|
35
|
+
method: "PUT",
|
|
36
|
+
body: value,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
getAll,
|
|
42
|
+
add,
|
|
43
|
+
deleteById,
|
|
44
|
+
updateById,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export default function useNFCPatrolTag() {
|
|
2
|
+
function getAll({
|
|
3
|
+
page = 1,
|
|
4
|
+
limit = 10,
|
|
5
|
+
site = "",
|
|
6
|
+
} = {}) {
|
|
7
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/nfc-patrol-tag`, {
|
|
8
|
+
method: "GET",
|
|
9
|
+
query: {
|
|
10
|
+
page,
|
|
11
|
+
limit,
|
|
12
|
+
site,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function add(value: { site: string; tagID: string; name: string }) {
|
|
18
|
+
return useNuxtApp().$api<Record<string, any>>("/api/nfc-patrol-tag", {
|
|
19
|
+
method: "POST",
|
|
20
|
+
body: {
|
|
21
|
+
site: value.site,
|
|
22
|
+
tagID: value.tagID,
|
|
23
|
+
name: value.name,
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function deleteById(id: string) {
|
|
29
|
+
return useNuxtApp().$api(`/api/nfc-patrol-tag/${id}`, {
|
|
30
|
+
method: "DELETE",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function updateById(id: string, value: { site: string; tagID: string; name: string }) {
|
|
35
|
+
return useNuxtApp().$api(`/api/nfc-patrol-tag/${id}`, {
|
|
36
|
+
method: "PUT",
|
|
37
|
+
body: {
|
|
38
|
+
site: value.site,
|
|
39
|
+
tagID: value.tagID,
|
|
40
|
+
name: value.name,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
getAll,
|
|
47
|
+
add,
|
|
48
|
+
deleteById,
|
|
49
|
+
updateById,
|
|
50
|
+
};
|
|
51
|
+
}
|
package/composables/usePeople.ts
CHANGED
|
@@ -31,6 +31,13 @@ export default function(){
|
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
async function searchCompanyList(company: string): Promise<null | Partial<TPeople>> {
|
|
35
|
+
return await $fetch<Record<string, any>>('/api/people/company', {
|
|
36
|
+
method: "GET",
|
|
37
|
+
query: { search: company}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
34
41
|
async function create(payload: Partial<TPeoplePayload>){
|
|
35
42
|
return await useNuxtApp().$api<Record<string, any>>("/api/people", {
|
|
36
43
|
method: "POST",
|
|
@@ -51,6 +58,15 @@ export default function(){
|
|
|
51
58
|
});
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
async function getPeopleByUnit( _id: string,{
|
|
62
|
+
status = "active",
|
|
63
|
+
type = "resident",
|
|
64
|
+
} = {}){
|
|
65
|
+
return await useNuxtApp().$api<Record<string, any>>(`/api/people/unit/${_id}`, {
|
|
66
|
+
method: "GET",
|
|
67
|
+
query: { status, type }
|
|
68
|
+
});
|
|
69
|
+
}
|
|
54
70
|
|
|
55
71
|
return {
|
|
56
72
|
create,
|
|
@@ -58,6 +74,8 @@ export default function(){
|
|
|
58
74
|
updateById,
|
|
59
75
|
deleteById,
|
|
60
76
|
findPersonByNRIC,
|
|
61
|
-
findPersonByContact
|
|
77
|
+
findPersonByContact,
|
|
78
|
+
getPeopleByUnit,
|
|
79
|
+
searchCompanyList
|
|
62
80
|
}
|
|
63
81
|
}
|
|
@@ -14,7 +14,7 @@ export default function () {
|
|
|
14
14
|
];
|
|
15
15
|
|
|
16
16
|
const typeFieldMap: Record<TVisitorType, (keyof TVisitorPayload)[]> = {
|
|
17
|
-
guest: ['name', 'nric', 'contact', 'block', 'level', 'unit' , 'unitName', 'remarks'],
|
|
17
|
+
guest: ['name', 'nric', 'contact', 'company', 'block', 'level', 'unit' , 'unitName', 'remarks'],
|
|
18
18
|
contractor: ['contractorType', 'name', 'nric', 'company', 'contact', 'plateNumber', 'block', 'level', 'unit', 'unitName', 'remarks'],
|
|
19
19
|
delivery: ['attachments', 'name', 'deliveryType', 'company', 'nric', 'contact', 'plateNumber', 'block', 'level', 'unit' , 'unitName', 'remarks'],
|
|
20
20
|
'walk-in': ['name', 'company', 'nric', 'contact', 'block', 'level', 'unit' , 'unitName', 'remarks'],
|
package/package.json
CHANGED
package/types/building.d.ts
CHANGED
package/types/card.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare type TCard = {
|
|
2
|
+
_id?: string;
|
|
3
|
+
name: string;
|
|
4
|
+
accessCardType?: string;
|
|
5
|
+
type?: string;
|
|
6
|
+
cardNumber?: string;
|
|
7
|
+
startDate?: string | Date;
|
|
8
|
+
endDate?: string | Date;
|
|
9
|
+
door?: string;
|
|
10
|
+
accessGroup?: string[];
|
|
11
|
+
cardType?: string;
|
|
12
|
+
pinNo?: string;
|
|
13
|
+
useAsLiftCard?: boolean;
|
|
14
|
+
liftAccessLevel?: string;
|
|
15
|
+
isActivate?: boolean;
|
|
16
|
+
isAntiPassBack?: boolean;
|
|
17
|
+
status?: string;
|
|
18
|
+
org?: string | ObjectId;
|
|
19
|
+
site?: string | ObjectId;
|
|
20
|
+
unit: string;
|
|
21
|
+
assign: string;
|
|
22
|
+
};
|