@7365admin1/layer-common 1.11.13 → 1.11.15
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/AreaMain.vue +1 -1
- package/components/AttendanceCheckInOutDialog.vue +5 -0
- package/components/AttendanceDetailsDialog.vue +1 -0
- package/components/AttendanceSettingsDialog.vue +1 -1
- package/components/MyAttendanceMain.vue +4 -0
- package/components/OvernightParkingManagement.vue +48 -2
- package/components/QrTemplate/PrintDialog.vue +56 -56
- package/components/ScheduleTaskForm.vue +1 -1
- package/components/ScheduleTaskMain.vue +76 -2
- package/components/UnitMain.vue +1 -1
- package/components/VisitorManagement.vue +26 -9
- package/composables/useAreas.ts +3 -4
- package/composables/useAttendance.ts +4 -3
- package/composables/useScheduleTask.ts +12 -0
- package/composables/useUnits.ts +3 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/components/AreaMain.vue
CHANGED
|
@@ -570,7 +570,7 @@ async function handleDownloadExcel() {
|
|
|
570
570
|
return;
|
|
571
571
|
}
|
|
572
572
|
|
|
573
|
-
const excelBuffer = await exportAreas(props.site);
|
|
573
|
+
const excelBuffer = await exportAreas(props.site, props.serviceType);
|
|
574
574
|
|
|
575
575
|
if (!excelBuffer) {
|
|
576
576
|
showMessage("Failed to download areas.", "error");
|
|
@@ -162,6 +162,7 @@ const emit = defineEmits(["saved", "close"]);
|
|
|
162
162
|
|
|
163
163
|
const props = defineProps({
|
|
164
164
|
action: { type: String, default: "checkIn" }, // "checkIn" or "checkOut"
|
|
165
|
+
serviceType: { type: String, default: "" },
|
|
165
166
|
});
|
|
166
167
|
|
|
167
168
|
const formRef = ref<any>(null);
|
|
@@ -386,6 +387,10 @@ const submit = async () => {
|
|
|
386
387
|
payload[props.action].img = imageId;
|
|
387
388
|
}
|
|
388
389
|
|
|
390
|
+
if (props.serviceType) {
|
|
391
|
+
payload.serviceType = props.serviceType;
|
|
392
|
+
}
|
|
393
|
+
|
|
389
394
|
emit("saved", payload);
|
|
390
395
|
|
|
391
396
|
close();
|
|
@@ -365,7 +365,7 @@ const onSubmit = async () => {
|
|
|
365
365
|
payload.isGeofencingEnabled = false;
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
-
await updateAttendanceSettings(props.site, payload);
|
|
368
|
+
await updateAttendanceSettings(props.site, payload, props.serviceType);
|
|
369
369
|
await getAttendanceSettingsRefresh();
|
|
370
370
|
|
|
371
371
|
showSnackbar("Settings updated successfully");
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
<AttendanceCheckInOutDialog
|
|
63
63
|
v-model="dialogShowForm"
|
|
64
64
|
:action="currentAction"
|
|
65
|
+
:serviceType="props.serviceType"
|
|
65
66
|
@saved="onAttendanceSaved"
|
|
66
67
|
@close="dialogShowForm = false"
|
|
67
68
|
/>
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
<AttendanceDetailsDialog
|
|
70
71
|
v-model="dialogShowMoreActions"
|
|
71
72
|
:attendance-id="selectedAttendanceId"
|
|
73
|
+
:serviceType="props.serviceType"
|
|
72
74
|
@close="dialogShowMoreActions = false"
|
|
73
75
|
/>
|
|
74
76
|
|
|
@@ -82,6 +84,7 @@ import { useAttendancePermission } from "../composables/useAttendancePermission"
|
|
|
82
84
|
const props = defineProps({
|
|
83
85
|
orgId: { type: String, default: "" },
|
|
84
86
|
site: { type: String, default: "" },
|
|
87
|
+
serviceType: { type: String, default: "" },
|
|
85
88
|
});
|
|
86
89
|
|
|
87
90
|
const { canViewOwnAttendance, canCheckInOut, canViewAttendanceDetails } =
|
|
@@ -151,6 +154,7 @@ const {
|
|
|
151
154
|
page: page.value,
|
|
152
155
|
search: searchInput.value,
|
|
153
156
|
site: props.site,
|
|
157
|
+
serviceType: props.serviceType,
|
|
154
158
|
}),
|
|
155
159
|
{
|
|
156
160
|
watch: [page, searchInput, () => props.site],
|
|
@@ -66,6 +66,22 @@
|
|
|
66
66
|
</template>
|
|
67
67
|
</TableMain>
|
|
68
68
|
|
|
69
|
+
<v-dialog v-model="viewDialog" width="450" persistent>
|
|
70
|
+
<VehicleUpdateMoreAction title="Preview" :can-update="false" :can-delete="false"
|
|
71
|
+
@close="viewDialog = false">
|
|
72
|
+
<template v-slot:content>
|
|
73
|
+
<v-row no-gutters class="mb-4">
|
|
74
|
+
<v-col v-for="(label, key) in formattedFields" :key="key" cols="12">
|
|
75
|
+
<span v-if="selectedItem?.[key] !== undefined && selectedItem?.[key] !== null && selectedItem?.[key] !== ''" class="d-flex ga-3 align-center">
|
|
76
|
+
<strong>{{ label }}:</strong>
|
|
77
|
+
{{ formatItemValue(key, selectedItem[key]) }}
|
|
78
|
+
</span>
|
|
79
|
+
</v-col>
|
|
80
|
+
</v-row>
|
|
81
|
+
</template>
|
|
82
|
+
</VehicleUpdateMoreAction>
|
|
83
|
+
</v-dialog>
|
|
84
|
+
|
|
69
85
|
<v-dialog v-model="actionDialog.open" max-width="520" persistent>
|
|
70
86
|
<v-card>
|
|
71
87
|
<v-card-title class="text-subtitle-1 font-weight-bold pt-4 px-4">
|
|
@@ -109,7 +125,7 @@ const props = defineProps({
|
|
|
109
125
|
|
|
110
126
|
});
|
|
111
127
|
|
|
112
|
-
const emits = defineEmits(["refresh", "create", "
|
|
128
|
+
const emits = defineEmits(["refresh", "create", "update:page"]);
|
|
113
129
|
|
|
114
130
|
const searchInput = defineModel<string>("search", { default: "" });
|
|
115
131
|
|
|
@@ -124,6 +140,35 @@ const extensionHeight = ref(0)
|
|
|
124
140
|
const offset = ref(0)
|
|
125
141
|
const createLabel = "New Overnight Parking Request"
|
|
126
142
|
|
|
143
|
+
const viewDialog = ref(false)
|
|
144
|
+
const selectedItem = ref<TOvernightParkingRequest | null>(null)
|
|
145
|
+
|
|
146
|
+
const formattedFields = {
|
|
147
|
+
name: "Name",
|
|
148
|
+
email: "Email",
|
|
149
|
+
contact: "Contact",
|
|
150
|
+
isOvernightParking: "Overnight Parking",
|
|
151
|
+
numberOfPassengers: "No. of Passengers",
|
|
152
|
+
purposeOfVisit: "Purpose of Visit",
|
|
153
|
+
status: "Status",
|
|
154
|
+
remarks: "Remarks",
|
|
155
|
+
createdAt: "Date Requested",
|
|
156
|
+
} as const
|
|
157
|
+
|
|
158
|
+
function formatItemValue(key: string, value: any) {
|
|
159
|
+
if (value === undefined || value === null || value === '') return ''
|
|
160
|
+
switch (key) {
|
|
161
|
+
case 'createdAt':
|
|
162
|
+
case 'updatedAt':
|
|
163
|
+
return formatDateDDMMYYYYLocal(value)
|
|
164
|
+
case 'isOvernightParking':
|
|
165
|
+
return value ? 'Yes' : 'No'
|
|
166
|
+
case 'status':
|
|
167
|
+
return formatStatus(value as TOvernightParkingRequest['status']).label
|
|
168
|
+
}
|
|
169
|
+
return value
|
|
170
|
+
}
|
|
171
|
+
|
|
127
172
|
const remarks = ref('')
|
|
128
173
|
const actionLoading = ref(false)
|
|
129
174
|
const actionDialog = reactive<{
|
|
@@ -197,7 +242,8 @@ watch(overnightParkingRequests, (data: any) => {
|
|
|
197
242
|
// }
|
|
198
243
|
|
|
199
244
|
function handleRowClick(data: { item?: TOvernightParkingRequest }) {
|
|
200
|
-
|
|
245
|
+
selectedItem.value = data?.item ?? null
|
|
246
|
+
viewDialog.value = true
|
|
201
247
|
}
|
|
202
248
|
|
|
203
249
|
function handleUpdatePage(value: number) {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
<v-autocomplete
|
|
54
54
|
:items="
|
|
55
55
|
localTemplateList.filter(
|
|
56
|
-
(item) => !['All', 'Manually Added'].includes(item.name)
|
|
56
|
+
(item) => !['All', 'Manually Added'].includes(item.name)
|
|
57
57
|
)
|
|
58
58
|
"
|
|
59
59
|
item-title="name"
|
|
@@ -69,9 +69,9 @@
|
|
|
69
69
|
Select template
|
|
70
70
|
<span class="text-red font-weight-bold">*</span>
|
|
71
71
|
</template>
|
|
72
|
-
<template v-slot:append-item>
|
|
72
|
+
<!-- <template v-slot:append-item>
|
|
73
73
|
<div v-intersect="endIntersectTemplateList" />
|
|
74
|
-
</template>
|
|
74
|
+
</template> -->
|
|
75
75
|
</v-autocomplete>
|
|
76
76
|
</v-col>
|
|
77
77
|
</v-row>
|
|
@@ -833,57 +833,57 @@ watch(
|
|
|
833
833
|
() => props.templateList,
|
|
834
834
|
(newVal) => {
|
|
835
835
|
localTemplateList.value = newVal;
|
|
836
|
-
}
|
|
836
|
+
}
|
|
837
837
|
);
|
|
838
838
|
|
|
839
839
|
// interset start
|
|
840
840
|
|
|
841
841
|
// const page = ref(1); // replace with your actual page value
|
|
842
|
-
const totalNumberOfPagesTemplateList = ref(1); // replace with your actual total number of pages value
|
|
843
|
-
|
|
844
|
-
const endIntersectTemplateList = async (isIntersecting) => {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
};
|
|
851
|
-
|
|
852
|
-
const getTemplateNameLists = async (page = 1, query = "") => {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
};
|
|
842
|
+
// const totalNumberOfPagesTemplateList = ref(1); // replace with your actual total number of pages value
|
|
843
|
+
|
|
844
|
+
// const endIntersectTemplateList = async (isIntersecting) => {
|
|
845
|
+
// await getTemplateNameLists(page.value);
|
|
846
|
+
// if (isIntersecting && !isFetchingTemplates.value) {
|
|
847
|
+
// page.value += 1;
|
|
848
|
+
// await getTemplateNameLists(page.value);
|
|
849
|
+
// }
|
|
850
|
+
// };
|
|
851
|
+
|
|
852
|
+
// const getTemplateNameLists = async (page = 1, query = "") => {
|
|
853
|
+
// isFetchingTemplates.value = true;
|
|
854
|
+
|
|
855
|
+
// const result = await getTemplatesByPageSearch({
|
|
856
|
+
// sites: [route.params.site as string],
|
|
857
|
+
// limit: 10,
|
|
858
|
+
// page: page,
|
|
859
|
+
// statuses: ["active"],
|
|
860
|
+
// search: query,
|
|
861
|
+
// });
|
|
862
|
+
|
|
863
|
+
// totalNumberOfPagesTemplateList.value = result?.pages;
|
|
864
|
+
// if (result?.items.length) {
|
|
865
|
+
// const newItems = result?.items.map((item) => ({
|
|
866
|
+
// _id: item._id,
|
|
867
|
+
// name: item.name,
|
|
868
|
+
// prefixPass: item.prefixPass,
|
|
869
|
+
// prefixKey: item.prefixKey,
|
|
870
|
+
// }));
|
|
871
|
+
|
|
872
|
+
// if (page === 1) {
|
|
873
|
+
// newItems.unshift({ _id: null, name: "All" });
|
|
874
|
+
// newItems.push({ _id: "Manually Added", name: "Manually Added" });
|
|
875
|
+
// }
|
|
876
|
+
|
|
877
|
+
// // Only add new items if they don't already exist in the list
|
|
878
|
+
// newItems.forEach((newItem) => {
|
|
879
|
+
// if (!localTemplateList.value.find((item) => item._id === newItem._id)) {
|
|
880
|
+
// localTemplateList.value.push(newItem);
|
|
881
|
+
// }
|
|
882
|
+
// });
|
|
883
|
+
// }
|
|
884
|
+
|
|
885
|
+
// isFetchingTemplates.value = false;
|
|
886
|
+
// };
|
|
887
887
|
|
|
888
888
|
const searchTemplate = async (query) => {
|
|
889
889
|
isFetchingTemplates.value = true;
|
|
@@ -999,7 +999,7 @@ watch(
|
|
|
999
999
|
}
|
|
1000
1000
|
}
|
|
1001
1001
|
},
|
|
1002
|
-
{ immediate: true }
|
|
1002
|
+
{ immediate: true }
|
|
1003
1003
|
);
|
|
1004
1004
|
|
|
1005
1005
|
const router = useRouter();
|
|
@@ -1031,7 +1031,7 @@ const printContent = () => {
|
|
|
1031
1031
|
if (printOrientation == "KeyCard") {
|
|
1032
1032
|
localStorage.setItem(
|
|
1033
1033
|
"selectedKeysToPrint",
|
|
1034
|
-
JSON.stringify(selectedKeysToPrint.value)
|
|
1034
|
+
JSON.stringify(selectedKeysToPrint.value)
|
|
1035
1035
|
);
|
|
1036
1036
|
}
|
|
1037
1037
|
|
|
@@ -1083,14 +1083,14 @@ watch(selectedChoicePaperSizeOrientation, async (newVal: any) => {
|
|
|
1083
1083
|
resultKeys2.value.sort(
|
|
1084
1084
|
(firstItem: { value: string }, secondItem: { value: string }) => {
|
|
1085
1085
|
const numericValueOfFirstItem = Number(
|
|
1086
|
-
firstItem.value.replace(/\D/g, "")
|
|
1086
|
+
firstItem.value.replace(/\D/g, "")
|
|
1087
1087
|
);
|
|
1088
1088
|
const numericValueOfSecondItem = Number(
|
|
1089
|
-
secondItem.value.replace(/\D/g, "")
|
|
1089
|
+
secondItem.value.replace(/\D/g, "")
|
|
1090
1090
|
);
|
|
1091
1091
|
|
|
1092
1092
|
return numericValueOfFirstItem - numericValueOfSecondItem;
|
|
1093
|
-
}
|
|
1093
|
+
}
|
|
1094
1094
|
);
|
|
1095
1095
|
|
|
1096
1096
|
startRange.value = props.start.toString();
|
|
@@ -1107,7 +1107,7 @@ watch(startRange, (newVal: any, oldVal: any) => {
|
|
|
1107
1107
|
|
|
1108
1108
|
const endRangeKeys = computed(() => {
|
|
1109
1109
|
return resultKeys2.value.filter(
|
|
1110
|
-
(item: any) => item.value >= startRange.value
|
|
1110
|
+
(item: any) => item.value >= startRange.value
|
|
1111
1111
|
);
|
|
1112
1112
|
});
|
|
1113
1113
|
const message = ref("");
|
|
@@ -1127,7 +1127,7 @@ const showSnackbarEndRange = () => {
|
|
|
1127
1127
|
? "Please select a start range first."
|
|
1128
1128
|
: `No ${tab.value == "key" ? "Key" : "Pass"} found. Please try to
|
|
1129
1129
|
generate first.`,
|
|
1130
|
-
"error"
|
|
1130
|
+
"error"
|
|
1131
1131
|
);
|
|
1132
1132
|
}
|
|
1133
1133
|
};
|
|
@@ -377,7 +377,7 @@ const submitTask = async () => {
|
|
|
377
377
|
(props.taskData as any)?._id || (props.taskData as any)?.id;
|
|
378
378
|
response = await updateScheduleTask(taskId, payload);
|
|
379
379
|
} else {
|
|
380
|
-
response = await createScheduleTask({ ...payload, site: props.site });
|
|
380
|
+
response = await createScheduleTask({ ...payload, site: props.site, serviceType: props.serviceType });
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
showMessage(
|
|
@@ -88,8 +88,10 @@
|
|
|
88
88
|
:title="selectedTask?.title || 'Schedule Task Actions'"
|
|
89
89
|
:canUpdate="canUpdateScheduleTask"
|
|
90
90
|
@close="dialogShowMoreActions = false"
|
|
91
|
-
:canDelete="
|
|
91
|
+
:canDelete="canDeleteScheduleTask"
|
|
92
|
+
:deleteButtonLabel="'Delete Schedule Task'"
|
|
92
93
|
@edit="onEditFromMoreAction"
|
|
94
|
+
@delete="onDeleteFromMoreAction"
|
|
93
95
|
:editButtonLabel="'Edit Schedule Task'"
|
|
94
96
|
>
|
|
95
97
|
<template #content>
|
|
@@ -198,6 +200,52 @@
|
|
|
198
200
|
</HygieneUpdateMoreAction>
|
|
199
201
|
</v-dialog>
|
|
200
202
|
|
|
203
|
+
<v-dialog v-model="dialogDeleteTask" max-width="450">
|
|
204
|
+
<v-card>
|
|
205
|
+
<v-toolbar>
|
|
206
|
+
<v-row no-gutters class="fill-height px-6" align="center">
|
|
207
|
+
<span class="font-weight-bold text-h6 text-capitalize">
|
|
208
|
+
Delete {{ selectedTask?.title || 'Schedule Task' }}
|
|
209
|
+
</span>
|
|
210
|
+
</v-row>
|
|
211
|
+
</v-toolbar>
|
|
212
|
+
<v-card-text>
|
|
213
|
+
<span class="text-subtitle-2">Are you sure you want to delete this schedule task?</span>
|
|
214
|
+
</v-card-text>
|
|
215
|
+
|
|
216
|
+
<v-toolbar class="pa-0" density="compact">
|
|
217
|
+
<v-row no-gutters>
|
|
218
|
+
<v-col cols="6" class="pa-0">
|
|
219
|
+
<v-btn
|
|
220
|
+
block
|
|
221
|
+
variant="text"
|
|
222
|
+
class="text-none"
|
|
223
|
+
size="large"
|
|
224
|
+
@click="dialogDeleteTask = false"
|
|
225
|
+
height="48"
|
|
226
|
+
>
|
|
227
|
+
Cancel
|
|
228
|
+
</v-btn>
|
|
229
|
+
</v-col>
|
|
230
|
+
|
|
231
|
+
<v-col cols="6" class="pa-0">
|
|
232
|
+
<v-btn
|
|
233
|
+
block
|
|
234
|
+
variant="flat"
|
|
235
|
+
color="black"
|
|
236
|
+
class="text-none font-weight-bold"
|
|
237
|
+
height="48"
|
|
238
|
+
:loading="submitting"
|
|
239
|
+
@click="_deleteScheduleTask"
|
|
240
|
+
>
|
|
241
|
+
Delete
|
|
242
|
+
</v-btn>
|
|
243
|
+
</v-col>
|
|
244
|
+
</v-row>
|
|
245
|
+
</v-toolbar>
|
|
246
|
+
</v-card>
|
|
247
|
+
</v-dialog>
|
|
248
|
+
|
|
201
249
|
<Snackbar
|
|
202
250
|
v-model="messageSnackbar"
|
|
203
251
|
:text="message"
|
|
@@ -219,7 +267,7 @@ const props = defineProps({
|
|
|
219
267
|
});
|
|
220
268
|
|
|
221
269
|
const { formatDate, debounce } = useUtils();
|
|
222
|
-
const { getScheduleTasks, getScheduleTaskById } = useScheduleTask();
|
|
270
|
+
const { getScheduleTasks, getScheduleTaskById, deleteScheduleTask } = useScheduleTask();
|
|
223
271
|
const {
|
|
224
272
|
canViewScheduleTasks,
|
|
225
273
|
canCreateScheduleTask,
|
|
@@ -349,4 +397,30 @@ const onEditFromMoreAction = async () => {
|
|
|
349
397
|
formMode.value = "edit";
|
|
350
398
|
showForm.value = true;
|
|
351
399
|
};
|
|
400
|
+
|
|
401
|
+
const onDeleteFromMoreAction = () => {
|
|
402
|
+
dialogShowMoreActions.value = false;
|
|
403
|
+
dialogDeleteTask.value = true;
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
async function _deleteScheduleTask() {
|
|
407
|
+
if (!selectedTask.value) return;
|
|
408
|
+
|
|
409
|
+
try {
|
|
410
|
+
submitting.value = true;
|
|
411
|
+
const id =
|
|
412
|
+
(selectedTask.value as any)._id || (selectedTask.value as any).id;
|
|
413
|
+
if (!id) throw new Error("Invalid schedule task id");
|
|
414
|
+
|
|
415
|
+
const response = await deleteScheduleTask(id);
|
|
416
|
+
dialogDeleteTask.value = false;
|
|
417
|
+
showMessage(response?.message, "success");
|
|
418
|
+
|
|
419
|
+
await getTaskRefresh();
|
|
420
|
+
} catch (error: any) {
|
|
421
|
+
showMessage(error?.data?.message, "error");
|
|
422
|
+
} finally {
|
|
423
|
+
submitting.value = false;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
352
426
|
</script>
|
package/components/UnitMain.vue
CHANGED
|
@@ -317,7 +317,7 @@ async function handleDownloadExcel() {
|
|
|
317
317
|
return;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
const excelBuffer = await downloadUnits(props.site);
|
|
320
|
+
const excelBuffer = await downloadUnits(props.site, props.serviceType);
|
|
321
321
|
|
|
322
322
|
if (!excelBuffer) {
|
|
323
323
|
showMessage("Failed to download units.", "error");
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
<v-icon icon="mdi-user" size="15" />
|
|
51
51
|
<span v-if="item.type === 'contractor'" class="text-capitalize">{{
|
|
52
52
|
formatCamelCaseToWords(item.contractorType)
|
|
53
|
-
|
|
53
|
+
}}</span>
|
|
54
54
|
<span v-else class="text-capitalize">{{ formatType(item) }}</span>
|
|
55
55
|
</span>
|
|
56
56
|
<span class="d-flex align-center ga-2">
|
|
@@ -88,9 +88,10 @@
|
|
|
88
88
|
<v-icon icon="mdi-clock-time-four-outline" color="green" size="20" />
|
|
89
89
|
<span class="text-capitalize">{{
|
|
90
90
|
UTCToLocalTIme(item.checkIn) || "-"
|
|
91
|
-
|
|
91
|
+
}}</span>
|
|
92
92
|
<span>
|
|
93
|
-
<v-icon v-if="item?.snapshotEntryImage" size="17" icon="mdi-image"
|
|
93
|
+
<v-icon v-if="item?.snapshotEntryImage" size="17" icon="mdi-image"
|
|
94
|
+
@click.stop="handleViewImage(item.snapshotEntryImage)" />
|
|
94
95
|
</span>
|
|
95
96
|
</span>
|
|
96
97
|
<span class="d-flex align-center ga-2">
|
|
@@ -98,9 +99,10 @@
|
|
|
98
99
|
<template v-if="item.checkOut">
|
|
99
100
|
<span class="text-capitalize">{{
|
|
100
101
|
UTCToLocalTIme(item.checkOut) || "-"
|
|
101
|
-
|
|
102
|
+
}}</span>
|
|
102
103
|
<span>
|
|
103
|
-
<v-icon v-if="item?.snapshotExitImage" size="17" icon="mdi-image"
|
|
104
|
+
<v-icon v-if="item?.snapshotExitImage" size="17" icon="mdi-image"
|
|
105
|
+
@click.stop="handleViewImage(item.snapshotExitImage)" />
|
|
104
106
|
</span>
|
|
105
107
|
<span v-if="item?.manualCheckout">
|
|
106
108
|
<TooltipInfo text="Manual Checkout" density="compact" size="x-small" />
|
|
@@ -149,7 +151,7 @@
|
|
|
149
151
|
</span>
|
|
150
152
|
|
|
151
153
|
<span v-else-if="selectedVisitorObject[key]" class="d-flex ga-3 align-center"><strong>{{ label
|
|
152
|
-
|
|
154
|
+
}}:</strong>
|
|
153
155
|
{{ formatValues(key, selectedVisitorObject[key]) }}
|
|
154
156
|
<TooltipInfo v-if="key === 'checkOut'" text="Manual Checkout" density="compact" size="x-small" />
|
|
155
157
|
</span>
|
|
@@ -165,6 +167,18 @@
|
|
|
165
167
|
@delete="handleProceedDeleteVisitor" />
|
|
166
168
|
</v-dialog>
|
|
167
169
|
|
|
170
|
+
<v-dialog v-model="dialog.snapshotImage" max-width="700">
|
|
171
|
+
<v-card>
|
|
172
|
+
<v-card-title class="d-flex justify-space-between align-center">
|
|
173
|
+
<span>Snapshot</span>
|
|
174
|
+
<v-btn icon="mdi-close" variant="text" @click="dialog.snapshotImage = false" />
|
|
175
|
+
</v-card-title>
|
|
176
|
+
<v-card-text class="pa-2 d-flex justify-center">
|
|
177
|
+
<v-img :src="snapshotImageUrl" max-height="600" contain />
|
|
178
|
+
</v-card-text>
|
|
179
|
+
</v-card>
|
|
180
|
+
</v-dialog>
|
|
181
|
+
|
|
168
182
|
<Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
|
|
169
183
|
</v-row>
|
|
170
184
|
</template>
|
|
@@ -207,7 +221,7 @@ const {
|
|
|
207
221
|
const { debounce, formatCamelCaseToWords, formatDate, UTCToLocalTIme } =
|
|
208
222
|
useUtils();
|
|
209
223
|
const { formatLocation } = useSecurityUtils();
|
|
210
|
-
const {
|
|
224
|
+
const { getFileUrlAnpr } = useFile();
|
|
211
225
|
// const { status: visitorStatus, search } = useRoute().query as { status: string, search: string};
|
|
212
226
|
|
|
213
227
|
const route = useRoute()
|
|
@@ -249,8 +263,11 @@ const dialog = reactive({
|
|
|
249
263
|
showForm: false,
|
|
250
264
|
viewVisitor: false,
|
|
251
265
|
deleteConfirmation: false,
|
|
266
|
+
snapshotImage: false,
|
|
252
267
|
});
|
|
253
268
|
|
|
269
|
+
const snapshotImageUrl = ref("");
|
|
270
|
+
|
|
254
271
|
const headers = computed(() => [
|
|
255
272
|
{ title: "Name", value: "name" },
|
|
256
273
|
{ title: "Type/Company", value: "type-company" },
|
|
@@ -447,8 +464,8 @@ function handleRegistrationUnregisteredVisitor(item: Partial<TVisitor>) {
|
|
|
447
464
|
|
|
448
465
|
function handleViewImage(imageId: string) {
|
|
449
466
|
const imageEndpoint = `${siteId}/${imageId}`;
|
|
450
|
-
|
|
451
|
-
|
|
467
|
+
snapshotImageUrl.value = getFileUrlAnpr(imageEndpoint);
|
|
468
|
+
dialog.snapshotImage = true;
|
|
452
469
|
}
|
|
453
470
|
|
|
454
471
|
|
package/composables/useAreas.ts
CHANGED
|
@@ -74,22 +74,21 @@ export default function useAreas() {
|
|
|
74
74
|
function uploadAreas(file: File, site: string, serviceType?: string) {
|
|
75
75
|
const formData = new FormData();
|
|
76
76
|
formData.append("file", file);
|
|
77
|
-
if (serviceType) {
|
|
78
|
-
formData.append("serviceType", serviceType);
|
|
79
|
-
}
|
|
80
77
|
return useNuxtApp().$api<Record<string, any>>(
|
|
81
78
|
`/api/hygiene-areas/site/${site}/upload`,
|
|
82
79
|
{
|
|
83
80
|
method: "POST",
|
|
84
81
|
body: formData,
|
|
82
|
+
query: { serviceType },
|
|
85
83
|
},
|
|
86
84
|
);
|
|
87
85
|
}
|
|
88
86
|
|
|
89
|
-
async function exportAreas(site: string) {
|
|
87
|
+
async function exportAreas(site: string, serviceType: string) {
|
|
90
88
|
return useNuxtApp().$api<Blob>(`/api/hygiene-areas/site/${site}/download`, {
|
|
91
89
|
method: "GET",
|
|
92
90
|
responseType: "blob",
|
|
91
|
+
query: { serviceType },
|
|
93
92
|
});
|
|
94
93
|
}
|
|
95
94
|
|
|
@@ -57,7 +57,7 @@ export default function useAttendance() {
|
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
function getAttendanceSettings(site: string, serviceType: string) {
|
|
60
|
+
function getAttendanceSettings(site: string, serviceType: string = "") {
|
|
61
61
|
return useNuxtApp().$api<TAttendanceSettings>(
|
|
62
62
|
`/api/attendance-settings/site/${site}`,
|
|
63
63
|
{
|
|
@@ -69,13 +69,14 @@ export default function useAttendance() {
|
|
|
69
69
|
|
|
70
70
|
function updateAttendanceSettings(
|
|
71
71
|
site: string,
|
|
72
|
-
payload: TAttendanceSettings
|
|
72
|
+
payload: TAttendanceSettings,
|
|
73
|
+
serviceType: string = ""
|
|
73
74
|
) {
|
|
74
75
|
return useNuxtApp().$api<Record<string, any>>(
|
|
75
76
|
`/api/attendance-settings/site/${site}`,
|
|
76
77
|
{
|
|
77
78
|
method: "PUT",
|
|
78
|
-
body: payload,
|
|
79
|
+
body: { ...payload, serviceType },
|
|
79
80
|
}
|
|
80
81
|
);
|
|
81
82
|
}
|
|
@@ -37,6 +37,7 @@ export default function useScheduleTask() {
|
|
|
37
37
|
description?: string;
|
|
38
38
|
areas: { name: string; value: string }[];
|
|
39
39
|
site: string;
|
|
40
|
+
serviceType: string;
|
|
40
41
|
}) {
|
|
41
42
|
return useNuxtApp().$api<Record<string, any>>(
|
|
42
43
|
`/api/hygiene-schedule-tasks/site/${payload.site}`,
|
|
@@ -48,6 +49,7 @@ export default function useScheduleTask() {
|
|
|
48
49
|
dates: payload.dates,
|
|
49
50
|
description: payload.description,
|
|
50
51
|
areas: payload.areas,
|
|
52
|
+
serviceType: payload.serviceType,
|
|
51
53
|
},
|
|
52
54
|
},
|
|
53
55
|
);
|
|
@@ -78,10 +80,20 @@ export default function useScheduleTask() {
|
|
|
78
80
|
);
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
function deleteScheduleTask(id: string) {
|
|
84
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
85
|
+
`/api/hygiene-schedule-tasks/id/${id}`,
|
|
86
|
+
{
|
|
87
|
+
method: "DELETE",
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
81
92
|
return {
|
|
82
93
|
getScheduleTasks,
|
|
83
94
|
createScheduleTask,
|
|
84
95
|
updateScheduleTask,
|
|
85
96
|
getScheduleTaskById,
|
|
97
|
+
deleteScheduleTask,
|
|
86
98
|
};
|
|
87
99
|
}
|
package/composables/useUnits.ts
CHANGED
|
@@ -57,23 +57,22 @@ export default function useUnits() {
|
|
|
57
57
|
function uploadUnits(file: File, site: string, serviceType?: string) {
|
|
58
58
|
const formData = new FormData();
|
|
59
59
|
formData.append("file", file);
|
|
60
|
-
if (serviceType) {
|
|
61
|
-
formData.append("serviceType", serviceType);
|
|
62
|
-
}
|
|
63
60
|
|
|
64
61
|
return useNuxtApp().$api<Record<string, any>>(
|
|
65
62
|
`/api/hygiene-units/site/${site}/upload`,
|
|
66
63
|
{
|
|
67
64
|
method: "POST",
|
|
68
65
|
body: formData,
|
|
66
|
+
query: { serviceType },
|
|
69
67
|
}
|
|
70
68
|
);
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
function downloadUnits(site: string) {
|
|
71
|
+
function downloadUnits(site: string, serviceType: string) {
|
|
74
72
|
return useNuxtApp().$api<Blob>(`/api/hygiene-units/site/${site}/download`, {
|
|
75
73
|
method: "GET",
|
|
76
74
|
responseType: "blob",
|
|
75
|
+
query: { serviceType },
|
|
77
76
|
});
|
|
78
77
|
}
|
|
79
78
|
|