@7365admin1/layer-common 1.10.5 → 1.10.7
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/AccessCardDetailsDialog.vue +144 -0
- package/components/AccessCardPreviewDialog.vue +7 -2
- package/components/AccessCardQrTagging.vue +314 -34
- package/components/AccessCardQrTaggingPrintQr.vue +75 -0
- package/components/AccessManagement.vue +5 -1
- package/components/AreaChecklistHistoryLogs.vue +9 -0
- package/components/BuildingForm.vue +36 -5
- package/components/BuildingManagement/buildings.vue +18 -9
- package/components/BuildingManagement/units.vue +12 -114
- package/components/BuildingUnitFormAdd.vue +39 -30
- package/components/BuildingUnitFormEdit.vue +265 -116
- package/components/CleaningScheduleMain.vue +60 -13
- package/components/Dialog/DeleteConfirmation.vue +2 -2
- package/components/Dialog/UpdateMoreAction.vue +2 -2
- package/components/EntryPassInformation.vue +215 -0
- package/components/Input/InputPhoneNumberV2.vue +11 -0
- package/components/ManageChecklistMain.vue +29 -3
- package/components/PlateNumberDisplay.vue +9 -1
- package/components/ScheduleAreaMain.vue +56 -0
- package/components/TableHygiene.vue +265 -113
- package/components/UnitPersonCard.vue +63 -0
- package/components/VehicleAddSelection.vue +2 -2
- package/components/VehicleForm.vue +169 -47
- package/components/VehicleManagement.vue +169 -43
- package/components/VisitorForm.vue +19 -0
- package/components/VisitorManagement.vue +1 -1
- package/components/WorkOrder/Main.vue +2 -1
- package/composables/useAccessManagement.ts +63 -0
- package/composables/useFeedback.ts +2 -2
- package/composables/usePeople.ts +14 -3
- package/composables/useVehicle.ts +15 -1
- package/composables/useWorkOrder.ts +2 -2
- package/package.json +3 -2
- package/types/cleaner-schedule.d.ts +1 -0
- package/types/html2pdf.d.ts +19 -0
- package/types/people.d.ts +4 -0
- package/types/site.d.ts +8 -0
- package/types/vehicle.d.ts +3 -4
- package/.playground/app.vue +0 -41
- package/.playground/eslint.config.mjs +0 -6
- package/.playground/nuxt.config.ts +0 -22
- package/.playground/pages/feedback.vue +0 -30
- package/components/AccessCardHistoryDialog.vue +0 -133
|
@@ -2,31 +2,31 @@
|
|
|
2
2
|
<v-row no-gutters>
|
|
3
3
|
<TableMain :headers="headers" :items="items" :loading="loading || getVehiclesPending" :page="page" :pages="pages"
|
|
4
4
|
:pageRange="pageRange" :extension-height="70" :canCreate="canCreateVehicle" @refresh="getVehiclesRefresh"
|
|
5
|
-
createLabel="Add Vehicle" show-header @row-click="handleRowClick" @create="
|
|
5
|
+
createLabel="Add Vehicle" show-header @row-click="handleRowClick" @create="handleAddVehicleClick"
|
|
6
6
|
@update:page="handleUpdatePage">
|
|
7
7
|
|
|
8
8
|
<template #extension>
|
|
9
9
|
<v-row no-gutters class="px-5 py-1 d-flex align-center justify-end ga-3">
|
|
10
10
|
<v-text-field v-model="searchInput" density="compact" placeholder="Search" clearable max-width="300"
|
|
11
11
|
append-inner-icon="mdi-magnify" hide-details />
|
|
12
|
-
<v-select v-model="
|
|
12
|
+
<v-select v-model="vehicleTypeFilter" density="compact" item-title="label" item-value="value"
|
|
13
13
|
placeholder="Filter by Type" clearable max-width="200" hide-details :items="typeOptions" />
|
|
14
14
|
</v-row>
|
|
15
15
|
</template>
|
|
16
16
|
|
|
17
17
|
<template #item.block="{ value }">
|
|
18
|
-
{{ value ? `
|
|
18
|
+
{{ value ? `Blk ${value}` : "" }}
|
|
19
19
|
</template>
|
|
20
|
-
<template #item.status="{ value }">
|
|
20
|
+
<!-- <template #item.status="{ value }">
|
|
21
21
|
<v-chip :color="formatVehicleStatus(value).color" size="x-small" dark>
|
|
22
22
|
{{ formatVehicleStatus(value).label }}
|
|
23
23
|
</v-chip>
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
</template>
|
|
26
|
+
</template> -->
|
|
27
27
|
|
|
28
|
-
<template #item.
|
|
29
|
-
|
|
28
|
+
<template #item.plates="{ value, item }">
|
|
29
|
+
<PlateNumberDisplay :plate-numbers="value" :default-value="item.plateNumber" />
|
|
30
30
|
</template>
|
|
31
31
|
</TableMain>
|
|
32
32
|
|
|
@@ -37,33 +37,51 @@
|
|
|
37
37
|
</v-dialog>
|
|
38
38
|
|
|
39
39
|
<v-dialog v-model="dialog.createVehicle" v-if="vehicleType" width="450" persistent>
|
|
40
|
-
<VehicleForm :type="vehicleType" mode="add" @back="handleBackToSelection" @done="handleAddVehicleComplete"
|
|
40
|
+
<VehicleForm :type="vehicleType" mode="add" :vehicle-data="selectedVehicleObject" @back="handleBackToSelection" @done="handleAddVehicleComplete"
|
|
41
41
|
:org="org" :site="props.site" @close:all="handleCloseAll" />
|
|
42
42
|
</v-dialog>
|
|
43
43
|
|
|
44
|
-
<v-dialog v-model="dialog.updateVehicle" v-if="vehicleType" width="450" persistent>
|
|
44
|
+
<!-- <v-dialog v-model="dialog.updateVehicle" v-if="vehicleType" width="450" persistent>
|
|
45
45
|
<VehicleForm :type="vehicleType" mode="edit" :vehicle-data="selectedVehicleObject"
|
|
46
46
|
@back="dialog.updateVehicle = false" @close="dialog.updateVehicle = false" @done="handleUpdateVehicleComplete"
|
|
47
47
|
:org="org" :site="site" @close:all="handleCloseAll" />
|
|
48
|
-
</v-dialog>
|
|
48
|
+
</v-dialog> -->
|
|
49
49
|
|
|
50
|
-
<v-dialog v-if="canViewVehicleDetails" v-model="dialog.showMoreActions" width="
|
|
51
|
-
<DialogUpdateMoreAction title="Preview" :can-update="
|
|
52
|
-
@close="dialog.showMoreActions = false"
|
|
53
|
-
@delete="handleDeleteVehicleAction" @edit="handleEditVehicleAction">
|
|
50
|
+
<v-dialog v-if="canViewVehicleDetails" v-model="dialog.showMoreActions" width="600" persistent>
|
|
51
|
+
<DialogUpdateMoreAction title="Preview" :can-update="false" :can-delete="false"
|
|
52
|
+
@close="dialog.showMoreActions = false">
|
|
54
53
|
<template v-slot:content>
|
|
55
54
|
<v-row no-gutters class="ga-1 mb-5">
|
|
56
|
-
|
|
55
|
+
|
|
57
56
|
<template v-for="(label, key) in formattedFields" :key="key">
|
|
58
|
-
<v-col v-if="key === '
|
|
57
|
+
<v-col v-if="key === 'plates'" class="d-flex flex-column ga-2">
|
|
59
58
|
<span class="d-flex ga-3 align-center"><strong>{{ label }}:</strong></span>
|
|
60
|
-
<PlateNumberDisplay :plate-numbers="selectedVehicleObject[key]" :default-value="selectedVehicleObject.plateNumber" />
|
|
59
|
+
<!-- <PlateNumberDisplay :plate-numbers="selectedVehicleObject[key]" show-all :default-value="selectedVehicleObject.plateNumber" /> -->
|
|
60
|
+
<v-col cols="12">
|
|
61
|
+
<v-card flat outlined class="pa-2" border="sm black">
|
|
62
|
+
<v-data-table :items="selectedVehicleObject[key]" :headers="plateHeaders" hide-default-footer>
|
|
63
|
+
<template #item.status="{ value }">
|
|
64
|
+
<v-chip :color="formatVehicleStatus(value).color" size="x-small" dark>
|
|
65
|
+
{{ formatVehicleStatus(value).label }}
|
|
66
|
+
</v-chip>
|
|
67
|
+
</template>
|
|
68
|
+
<template #item.action="{ item }">
|
|
69
|
+
<v-btn v-if="canDeleteVehicle && (item as TPlateNumber)?.status == 'active'" text="Delete" color="error" flat size="x-small" @click="handleDeleteVehicleAction(item as TPlateNumber)"/>
|
|
70
|
+
<v-btn v-if="props.app === 'property_management_agency' && (item as TPlateNumber)?.status == 'pending'" text="Approve" color="success" flat size="x-small" @click="handleApproveVehicle(item as TPlateNumber)"/>
|
|
71
|
+
<v-btn v-if=" (item as TPlateNumber)?.status == 'deleted'" text="Restore" color="orange" flat size="x-small" @click="handleRestoreVehicle(item as TPlateNumber)"/>
|
|
72
|
+
</template>
|
|
73
|
+
</v-data-table>
|
|
74
|
+
<v-btn text="Add Vehicle Number" class="mt-6 text-capitalize" prepend-icon="mdi-plus"
|
|
75
|
+
@click="addNewPlateNumbers" color="primary" />
|
|
76
|
+
</v-card>
|
|
77
|
+
</v-col>å
|
|
78
|
+
|
|
61
79
|
</v-col>
|
|
62
80
|
|
|
63
81
|
<v-col v-else-if="selectedVehicleObject[key]" cols="12">
|
|
64
82
|
<span class="d-flex ga-3 align-center"><strong>{{ label }}:</strong> {{ formatValues(key,
|
|
65
83
|
selectedVehicleObject[key])
|
|
66
|
-
|
|
84
|
+
}}</span>
|
|
67
85
|
</v-col>
|
|
68
86
|
</template>
|
|
69
87
|
</v-row>
|
|
@@ -71,13 +89,22 @@
|
|
|
71
89
|
</DialogUpdateMoreAction>
|
|
72
90
|
</v-dialog>
|
|
73
91
|
<v-dialog v-model="dialog.deleteVehicle" persistent width="540">
|
|
74
|
-
<DialogDeleteConfirmation :message="message" prompt-title="Are you sure want to delete this vehicle
|
|
92
|
+
<DialogDeleteConfirmation :message="message" :loading="deletingVehicle" :prompt-title="`Are you sure want to delete this vehicle - ${selectedPlateNumberObject?.plateNumber}?`"
|
|
75
93
|
@delete="submitDelete" @close="closeDeleteDialog" />
|
|
76
94
|
</v-dialog>
|
|
95
|
+
<v-dialog v-model="dialog.approveVehicle" persistent width="540">
|
|
96
|
+
<DialogReusablePrompt :message="message" :loading="approvingVehicle" :prompt-title="`Are you sure want to approve this vehicle - ${selectedPlateNumberObject?.plateNumber}?`"
|
|
97
|
+
@approve="submitApprove" @close="dialog.approveVehicle = false" />
|
|
98
|
+
</v-dialog>
|
|
99
|
+
<v-dialog v-model="dialog.restoreVehicle" persistent width="540">
|
|
100
|
+
<DialogReusablePrompt :message="message" :loading="restoringVehicle" :prompt-title="`Are you sure want to restore this vehicle - ${selectedPlateNumberObject?.plateNumber}?`"
|
|
101
|
+
@approve="submitRestore" @close="dialog.restoreVehicle = false" />
|
|
102
|
+
</v-dialog>
|
|
77
103
|
</v-row>
|
|
78
104
|
</template>
|
|
79
105
|
|
|
80
106
|
<script lang="ts" setup>
|
|
107
|
+
import useUtils from '../composables/useUtils';
|
|
81
108
|
import useVehicle from '../composables/useVehicle';
|
|
82
109
|
|
|
83
110
|
definePageMeta({
|
|
@@ -93,25 +120,33 @@ const props = defineProps({
|
|
|
93
120
|
canViewVehicleDetails: { type: Boolean, default: true },
|
|
94
121
|
site: { type: String, required: true },
|
|
95
122
|
org: { type: String, required: true },
|
|
123
|
+
app: { type: String, required: true },
|
|
96
124
|
});
|
|
97
125
|
|
|
98
126
|
|
|
99
127
|
const headers = [
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
128
|
+
{ title: "Name", value: "name" },
|
|
129
|
+
{ title: "Vehicle Numbers", value: "plates" },
|
|
130
|
+
{ title: "NRIC", value: "nric" },
|
|
131
|
+
{ title: "Block", value: "block" },
|
|
132
|
+
{ title: "Floor", value: "level" },
|
|
133
|
+
{ title: "Unit", value: "unitName" },
|
|
134
|
+
{ title: "Category", value: "category" },
|
|
135
|
+
// { title: "Type", value: "type" },
|
|
136
|
+
// { title: "Status", value: "status" },
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
const plateHeaders = [
|
|
140
|
+
{ title: "Plate Number", value: "plateNumber" },
|
|
141
|
+
{ title: "Type", value: "type" },
|
|
142
|
+
{ title: "Status", value: "status" },
|
|
143
|
+
{ title: "", value: "action" },
|
|
144
|
+
]
|
|
110
145
|
|
|
111
146
|
|
|
112
147
|
|
|
113
148
|
const { formatCamelCaseToWords, formatDate, debounce } = useUtils();
|
|
114
|
-
const { getVehicles, deleteVehicle, formatVehicleStatus } = useVehicle();
|
|
149
|
+
const { getVehicles, deleteVehicle, formatVehicleStatus, approveVehicle } = useVehicle();
|
|
115
150
|
|
|
116
151
|
const items = ref<Array<Record<string, any>>>([]);
|
|
117
152
|
const page = ref(1);
|
|
@@ -121,8 +156,15 @@ const pageRange = ref("-- - -- of --");
|
|
|
121
156
|
const searchInput = ref("")
|
|
122
157
|
|
|
123
158
|
const loading = ref(false);
|
|
159
|
+
const deletingVehicle = ref(false);
|
|
160
|
+
const approvingVehicle = ref(false);
|
|
161
|
+
const restoringVehicle = ref(false);
|
|
162
|
+
|
|
124
163
|
const selectedVehicleId = ref<string | null>(null)
|
|
125
164
|
const vehicleType = ref<TVehicleType | null>(null);
|
|
165
|
+
const vehicleTypeFilter = ref<TVehicleType | null>(null);
|
|
166
|
+
|
|
167
|
+
const selectedPlateNumberObject = ref<TPlateNumber | null>(null);
|
|
126
168
|
|
|
127
169
|
const message = ref("");
|
|
128
170
|
const messageColor = ref("");
|
|
@@ -141,17 +183,18 @@ const dialog = reactive({
|
|
|
141
183
|
showSelection: false,
|
|
142
184
|
deleteVehicle: false,
|
|
143
185
|
showMoreActions: false,
|
|
186
|
+
approveVehicle: false,
|
|
187
|
+
restoreVehicle: false
|
|
144
188
|
});
|
|
145
189
|
|
|
190
|
+
|
|
146
191
|
const typeOptions = [
|
|
147
192
|
{ label: "Whitelist", value: "whitelist" },
|
|
148
193
|
{ label: "Blocklist", value: "blocklist" },
|
|
149
|
-
{ label: "Season Pass", value: "seasonPass" },
|
|
150
194
|
]
|
|
151
195
|
|
|
152
196
|
const formattedFields: Partial<Record<keyof TVehicle, string>> = {
|
|
153
197
|
name: "Name",
|
|
154
|
-
plateNumbers: "Vehicle Numbers",
|
|
155
198
|
phoneNumber: "Phone Number",
|
|
156
199
|
nric: "NRIC",
|
|
157
200
|
block: "Block",
|
|
@@ -162,6 +205,7 @@ const formattedFields: Partial<Record<keyof TVehicle, string>> = {
|
|
|
162
205
|
category: "Category",
|
|
163
206
|
type: "Type",
|
|
164
207
|
remarks: "Remarks",
|
|
208
|
+
plates: "Vehicle Numbers",
|
|
165
209
|
}
|
|
166
210
|
|
|
167
211
|
function formatValues(key: string, value: any) {
|
|
@@ -201,7 +245,7 @@ const { data: getVehiclesReq, refresh: getVehiclesRefresh, pending: getVehiclesP
|
|
|
201
245
|
getVehicles({
|
|
202
246
|
page: page.value,
|
|
203
247
|
search: searchInput.value,
|
|
204
|
-
type:
|
|
248
|
+
type: vehicleTypeFilter.value ?? "",
|
|
205
249
|
}),
|
|
206
250
|
{
|
|
207
251
|
watch: [page],
|
|
@@ -210,9 +254,9 @@ const { data: getVehiclesReq, refresh: getVehiclesRefresh, pending: getVehiclesP
|
|
|
210
254
|
|
|
211
255
|
|
|
212
256
|
watch(getVehiclesReq, (newData: any) => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
257
|
+
items.value = newData?.items || [];
|
|
258
|
+
pages.value = newData?.pages || 0;
|
|
259
|
+
pageRange.value = newData?.pageRange || "-- - -- of --";
|
|
216
260
|
})
|
|
217
261
|
|
|
218
262
|
function handleRowClick(data: any) {
|
|
@@ -221,17 +265,33 @@ function handleRowClick(data: any) {
|
|
|
221
265
|
message.value = "";
|
|
222
266
|
}
|
|
223
267
|
|
|
268
|
+
function addNewPlateNumbers() {
|
|
269
|
+
if (!selectedVehicleId.value) return;
|
|
270
|
+
dialog.showSelection = true;
|
|
271
|
+
}
|
|
272
|
+
|
|
224
273
|
function handleEditVehicleAction() {
|
|
225
274
|
vehicleType.value = selectedVehicleObject.value?.type || null;
|
|
275
|
+
console.log("Selected Vehicle Object: ", selectedVehicleObject.value);
|
|
226
276
|
dialog.showSelection = false;
|
|
277
|
+
dialog.updateVehicle = false;
|
|
227
278
|
dialog.updateVehicle = true;
|
|
228
279
|
}
|
|
229
280
|
|
|
230
|
-
function handleDeleteVehicleAction() {
|
|
231
|
-
|
|
281
|
+
function handleDeleteVehicleAction(item: TPlateNumber) {
|
|
282
|
+
selectedPlateNumberObject.value = item || null;
|
|
232
283
|
dialog.deleteVehicle = true;
|
|
233
284
|
}
|
|
234
285
|
|
|
286
|
+
function handleApproveVehicle(item: TPlateNumber) {
|
|
287
|
+
selectedPlateNumberObject.value = item || null;
|
|
288
|
+
dialog.approveVehicle = true;
|
|
289
|
+
}
|
|
290
|
+
function handleRestoreVehicle(item: TPlateNumber) {
|
|
291
|
+
selectedPlateNumberObject.value = item || null;
|
|
292
|
+
dialog.restoreVehicle = true;
|
|
293
|
+
}
|
|
294
|
+
|
|
235
295
|
function handleSelectVehicleStatus(value: TVehicleType) {
|
|
236
296
|
vehicleType.value = value;
|
|
237
297
|
dialog.showSelection = false;
|
|
@@ -259,10 +319,16 @@ function handleUpdateVehicleComplete() {
|
|
|
259
319
|
getVehiclesRefresh();
|
|
260
320
|
}
|
|
261
321
|
|
|
322
|
+
|
|
262
323
|
function handleUpdatePage(newPageNum: number) {
|
|
263
324
|
page.value = newPageNum;
|
|
264
325
|
}
|
|
265
326
|
|
|
327
|
+
function handleAddVehicleClick() {
|
|
328
|
+
dialog.showSelection = true;
|
|
329
|
+
selectedVehicleId.value = null;
|
|
330
|
+
}
|
|
331
|
+
|
|
266
332
|
const formatPlateNumbers = (value: any) => {
|
|
267
333
|
if (!value || value.length === 0) return "";
|
|
268
334
|
|
|
@@ -271,25 +337,85 @@ const formatPlateNumbers = (value: any) => {
|
|
|
271
337
|
};
|
|
272
338
|
|
|
273
339
|
async function submitDelete() {
|
|
274
|
-
|
|
340
|
+
|
|
341
|
+
const plateNumberId = selectedPlateNumberObject.value?._id;
|
|
342
|
+
const type = selectedPlateNumberObject.value?.type as TVehicleType;
|
|
343
|
+
if (!plateNumberId) {
|
|
344
|
+
showMessage("Invalid plate number selected for deletion.", "error");
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
275
347
|
|
|
276
348
|
try {
|
|
277
|
-
|
|
349
|
+
deletingVehicle.value = true;
|
|
350
|
+
const res = await deleteVehicle({ site: props.site, id: plateNumberId as string, recno: selectedVehicleObject.value.recno, type }
|
|
278
351
|
);
|
|
279
352
|
dialog.deleteVehicle = false;
|
|
280
|
-
dialog.showMoreActions = false;
|
|
281
353
|
selectedVehicleId.value = null
|
|
282
354
|
showMessage(res.message, "success");
|
|
283
355
|
getVehiclesRefresh();
|
|
284
356
|
} catch (error: any) {
|
|
285
357
|
console.error("Error deleting vehicle:", error);
|
|
286
358
|
message.value = error.response._data.message;
|
|
287
|
-
|
|
359
|
+
} finally {
|
|
360
|
+
deletingVehicle.value = false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
async function submitRestore() {
|
|
367
|
+
|
|
368
|
+
const plateNumberId = selectedPlateNumberObject.value?._id;
|
|
369
|
+
if (!plateNumberId) {
|
|
370
|
+
showMessage("Invalid plate number selected for restoration.", "error");
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
restoringVehicle.value = true;
|
|
376
|
+
// reactivate and restore will use the same endpoint, just with different payload
|
|
377
|
+
const res = await approveVehicle({ site: props.site, org: props.org, id: plateNumberId as string }
|
|
378
|
+
);
|
|
379
|
+
dialog.restoreVehicle = false;
|
|
380
|
+
selectedVehicleId.value = null
|
|
381
|
+
showMessage(res.message, "success");
|
|
382
|
+
getVehiclesRefresh();
|
|
383
|
+
} catch (error: any) {
|
|
384
|
+
console.error("Error restoring vehicle:", error);
|
|
385
|
+
message.value = error.response._data.message;
|
|
386
|
+
} finally {
|
|
387
|
+
restoringVehicle.value = false;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
async function submitApprove() {
|
|
393
|
+
|
|
394
|
+
const plateNumberId = selectedPlateNumberObject.value?._id;
|
|
395
|
+
if (!plateNumberId) {
|
|
396
|
+
showMessage("Invalid plate number selected for approval.", "error");
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
approvingVehicle.value = true;
|
|
402
|
+
const res = await approveVehicle({ site: props.site, org: props.org, id: plateNumberId as string }
|
|
403
|
+
|
|
404
|
+
);
|
|
405
|
+
dialog.approveVehicle = false;
|
|
406
|
+
selectedVehicleId.value = null
|
|
407
|
+
showMessage(res.message, "success");
|
|
408
|
+
getVehiclesRefresh();
|
|
409
|
+
} catch (error: any) {
|
|
410
|
+
console.error("Error approving vehicle:", error);
|
|
411
|
+
message.value = error.response._data.message;
|
|
412
|
+
} finally {
|
|
413
|
+
approvingVehicle.value = false;
|
|
288
414
|
}
|
|
289
415
|
}
|
|
290
416
|
|
|
291
417
|
const debouncedSearch = debounce(getVehiclesRefresh, 500);
|
|
292
|
-
watch([searchInput,
|
|
418
|
+
watch([searchInput, vehicleTypeFilter], () => {
|
|
293
419
|
page.value = 1;
|
|
294
420
|
debouncedSearch()
|
|
295
421
|
})
|
|
@@ -146,6 +146,7 @@
|
|
|
146
146
|
|
|
147
147
|
<v-col v-if="prop.type === 'contractor' && contractorStep === 2" cols="12">
|
|
148
148
|
<PassInformation />
|
|
149
|
+
<EntryPassInformation v-if="entryPassSettings?.data?.settings?.nfcPass" v-model="passType" v-model:quantity="passQuantity" v-model:cards="passCards" :settings="entryPassSettings" :loading="entryPassSettingsPending" @scan:barcode="$emit('scan:barcode')" @scan:camera="$emit('scan:camera')" />
|
|
149
150
|
</v-col>
|
|
150
151
|
|
|
151
152
|
<v-col v-if="prop.type === 'contractor' && contractorStep === 3" cols="12">
|
|
@@ -230,6 +231,7 @@ const currentAutofillSource = ref<AutofillSource>(null);
|
|
|
230
231
|
const { requiredRule, debounce } = useUtils();
|
|
231
232
|
const { getSiteById, getSiteLevels, getSiteUnits } = useSiteSettings();
|
|
232
233
|
const { createVisitor, typeFieldMap, contractorTypes } = useVisitor();
|
|
234
|
+
const { getBySiteId: getEntryPassSettingsBySiteId } = useSiteEntryPassSettings();
|
|
233
235
|
const { findPersonByNRIC, findPersonByContact, searchCompanyList, findUsersByPlateNumber } = usePeople()
|
|
234
236
|
|
|
235
237
|
const emit = defineEmits([
|
|
@@ -259,6 +261,10 @@ const visitor = reactive<Partial<TVisitorPayload>>({
|
|
|
259
261
|
members: [],
|
|
260
262
|
});
|
|
261
263
|
|
|
264
|
+
const passType = ref("");
|
|
265
|
+
const passQuantity = ref<number | null>(null);
|
|
266
|
+
const passCards = ref<string[]>([]);
|
|
267
|
+
|
|
262
268
|
const dialog = reactive({
|
|
263
269
|
vehicleNumberUsersList: false,
|
|
264
270
|
});
|
|
@@ -504,6 +510,19 @@ function handleAutofillDataViaVehicleNumber(item: TPeople){
|
|
|
504
510
|
}
|
|
505
511
|
|
|
506
512
|
|
|
513
|
+
const {
|
|
514
|
+
data: entryPassSettings,
|
|
515
|
+
pending: entryPassSettingsPending,
|
|
516
|
+
refresh: refreshEntryPassSettings,
|
|
517
|
+
} = useLazyAsyncData(`fetch-entrypass-settings-${prop.site}`, () => {
|
|
518
|
+
if (contractorStep.value !== 2) return Promise.resolve(null);
|
|
519
|
+
return getEntryPassSettingsBySiteId(prop.site);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
watch(contractorStep, (step) => {
|
|
523
|
+
if (step === 2) refreshEntryPassSettings();
|
|
524
|
+
});
|
|
525
|
+
|
|
507
526
|
const {
|
|
508
527
|
data: siteData,
|
|
509
528
|
refresh: refreshSiteData,
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
</template>
|
|
109
109
|
</TableMain>
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
<v-dialog v-model="dialog.showSelection" width="450" persistent>
|
|
112
112
|
<VisitorFormSelection @cancel="dialog.showSelection = false" @select="handleSelectVisitorType" />
|
|
113
113
|
</v-dialog>
|
|
114
114
|
|
|
@@ -437,7 +437,8 @@ async function handleFileAdded(file: File) {
|
|
|
437
437
|
const res = await addFile(file);
|
|
438
438
|
const uploadedId = res?.id;
|
|
439
439
|
if (uploadedId) {
|
|
440
|
-
const url = `${API_DO_STORAGE_ENDPOINT}/${uploadedId}`;
|
|
440
|
+
// const url = `${API_DO_STORAGE_ENDPOINT}/${uploadedId}`;
|
|
441
|
+
const url = `${uploadedId}`;
|
|
441
442
|
_workOrder.value.attachments = _workOrder.value.attachments ?? [];
|
|
442
443
|
_workOrder.value.attachments.push(url);
|
|
443
444
|
}
|
|
@@ -162,6 +162,65 @@ export default function useAccessManagement() {
|
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
function getCardDetails(params: { siteId: string; cardId: string }) {
|
|
166
|
+
return useNuxtApp().$api<{ message: string; data: Record<string, any> }>(
|
|
167
|
+
`/api/access-management/card-details`,
|
|
168
|
+
{
|
|
169
|
+
method: "GET",
|
|
170
|
+
query: { siteId: params.siteId, cardId: params.cardId },
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function saveVisitorAccessCardQrTag(
|
|
176
|
+
siteId: string,
|
|
177
|
+
payloads: Array<{
|
|
178
|
+
_id: string;
|
|
179
|
+
cardNo: string;
|
|
180
|
+
qrTag: string;
|
|
181
|
+
qrTagCardNo: string;
|
|
182
|
+
}>
|
|
183
|
+
) {
|
|
184
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
185
|
+
`/api/access-management/qr-tag/${siteId}`,
|
|
186
|
+
{
|
|
187
|
+
method: "POST",
|
|
188
|
+
body: payloads,
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function getAllVisitorAccessCardsQrTags(site: string) {
|
|
194
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
195
|
+
`/api/access-management/qr-tag`,
|
|
196
|
+
{
|
|
197
|
+
method: "GET",
|
|
198
|
+
query: { site },
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function getVisitorAccessCards(params: {
|
|
204
|
+
page?: number;
|
|
205
|
+
limit?: number;
|
|
206
|
+
site?: string;
|
|
207
|
+
search?: string;
|
|
208
|
+
} = {}) {
|
|
209
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
210
|
+
`/api/access-management/visitor-access-cards`,
|
|
211
|
+
{
|
|
212
|
+
method: "GET",
|
|
213
|
+
query: {
|
|
214
|
+
type: "Visitor/Resident",
|
|
215
|
+
...(params.page ? { page: params.page } : {}),
|
|
216
|
+
...(params.limit ? { limit: params.limit } : {}),
|
|
217
|
+
...(params.site ? { site: params.site } : {}),
|
|
218
|
+
...(params.search ? { search: params.search } : {}),
|
|
219
|
+
},
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
165
224
|
return {
|
|
166
225
|
getDoorAccessLevels,
|
|
167
226
|
getLiftAccessLevels,
|
|
@@ -175,5 +234,9 @@ export default function useAccessManagement() {
|
|
|
175
234
|
getAvailableAccessCards,
|
|
176
235
|
deleteCard,
|
|
177
236
|
getCardHistory,
|
|
237
|
+
getCardDetails,
|
|
238
|
+
getVisitorAccessCards,
|
|
239
|
+
saveVisitorAccessCardQrTag,
|
|
240
|
+
getAllVisitorAccessCardsQrTags,
|
|
178
241
|
};
|
|
179
242
|
}
|
|
@@ -75,9 +75,9 @@ export default function useFeedback() {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function deleteFeedback(id: string) {
|
|
78
|
-
return useNuxtApp().$api<Record<string, any>>(`/api/feedbacks/deleted/feedback`, {
|
|
78
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/feedbacks/deleted/feedback/${id}`, {
|
|
79
79
|
method: "PUT",
|
|
80
|
-
query: { id },
|
|
80
|
+
// query: { id },
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
|
package/composables/usePeople.ts
CHANGED
|
@@ -10,10 +10,11 @@ export default function () {
|
|
|
10
10
|
dateFrom = "",
|
|
11
11
|
type = "",
|
|
12
12
|
displayNoCheckOut = false,
|
|
13
|
+
status = "",
|
|
13
14
|
} = {}) {
|
|
14
15
|
return await useNuxtApp().$api<Record<string, any>>("/api/people", {
|
|
15
16
|
method: "GET",
|
|
16
|
-
query: { page, limit, sort, search, org, site, dateTo, dateFrom, type },
|
|
17
|
+
query: { page, limit, sort, search, org, site, dateTo, dateFrom, type, status },
|
|
17
18
|
});
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -25,6 +26,15 @@ export default function () {
|
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
async function findPersonByNRICMultipleResult(
|
|
30
|
+
nric: string, site: string
|
|
31
|
+
){
|
|
32
|
+
return await $fetch<Record<any, any>>(`/api/people/all-nric`, {
|
|
33
|
+
method: "GET",
|
|
34
|
+
query: { nric, site }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
async function findPersonByContact(
|
|
29
39
|
contact: string
|
|
30
40
|
): Promise<null | Partial<TPeople>> {
|
|
@@ -78,13 +88,13 @@ export default function () {
|
|
|
78
88
|
|
|
79
89
|
async function getPeopleByUnit(
|
|
80
90
|
_id: string,
|
|
81
|
-
{ status = "active", type = "
|
|
91
|
+
{ status = "active", type = "" } = {}
|
|
82
92
|
) {
|
|
83
93
|
return await useNuxtApp().$api<Record<string, any>>(
|
|
84
94
|
`/api/people/unit/${_id}`,
|
|
85
95
|
{
|
|
86
96
|
method: "GET",
|
|
87
|
-
query: { status
|
|
97
|
+
query: { status },
|
|
88
98
|
}
|
|
89
99
|
);
|
|
90
100
|
}
|
|
@@ -95,6 +105,7 @@ export default function () {
|
|
|
95
105
|
updateById,
|
|
96
106
|
deleteById,
|
|
97
107
|
findPersonByNRIC,
|
|
108
|
+
findPersonByNRICMultipleResult,
|
|
98
109
|
findPersonByContact,
|
|
99
110
|
getPeopleByUnit,
|
|
100
111
|
searchCompanyList,
|
|
@@ -64,6 +64,19 @@ export default function useVehicle() {
|
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
async function approveVehicle({ site, org, id }: { site: string, org: string, id: string}){
|
|
68
|
+
return await useNuxtApp().$api<Record<string, any>>(
|
|
69
|
+
`/api/vehicles/approve/ ${id}`,
|
|
70
|
+
{
|
|
71
|
+
method: "PUT",
|
|
72
|
+
body: {
|
|
73
|
+
site,
|
|
74
|
+
org,
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
67
80
|
async function getVehicleByNRIC(search: string) {
|
|
68
81
|
return await useNuxtApp().$api<Record<string, any>>(
|
|
69
82
|
`/api/vehicles/nric`,
|
|
@@ -109,6 +122,7 @@ export default function useVehicle() {
|
|
|
109
122
|
updateVehicle,
|
|
110
123
|
deleteVehicle,
|
|
111
124
|
getVehicleByNRIC,
|
|
112
|
-
formatVehicleStatus
|
|
125
|
+
formatVehicleStatus,
|
|
126
|
+
approveVehicle
|
|
113
127
|
};
|
|
114
128
|
}
|
|
@@ -72,9 +72,9 @@ export default function useWorkOrder() {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function deleteWorkOrder(id: string) {
|
|
75
|
-
return useNuxtApp().$api<Record<string, any>>(`/api/work-orders/deleted/work-order`, {
|
|
75
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/work-orders/deleted/work-order/${id}`, {
|
|
76
76
|
method: "PUT",
|
|
77
|
-
query: { id },
|
|
77
|
+
// query: { id },
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "1.10.
|
|
5
|
+
"version": "1.10.7",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"publishConfig": {
|
|
@@ -30,11 +30,12 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@ckeditor/ckeditor5-vue": "^7.3.0",
|
|
32
32
|
"@iconify/vue": "^5.0.0",
|
|
33
|
-
"qrcode.vue": "^3.4.1",
|
|
34
33
|
"@mdi/font": "^7.4.47",
|
|
35
34
|
"@types/qrcode": "^1.5.6",
|
|
36
35
|
"ckeditor5": "^47.2.0",
|
|
36
|
+
"html2pdf.js": "^0.10.2",
|
|
37
37
|
"qrcode": "^1.5.4",
|
|
38
|
+
"qrcode.vue": "^3.4.1",
|
|
38
39
|
"sass": "^1.80.6",
|
|
39
40
|
"vue3-signature": "^0.2.4",
|
|
40
41
|
"zod": "^3.24.2"
|