@7365admin1/layer-common 1.11.23 → 1.11.26
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 +18 -0
- package/components/AreaChecklistHistoryMain.vue +1 -1
- package/components/AttachmentsViewer.vue +266 -0
- package/components/BuildingForm.vue +63 -95
- package/components/BuildingManagement/buildings.vue +11 -12
- package/components/CleaningScheduleMain.vue +10 -1
- package/components/DocumentViewer.vue +75 -0
- package/components/EquipmentItemMain.vue +4 -2
- package/components/EquipmentManagementMain.vue +14 -10
- package/components/ManageChecklistMain.vue +13 -1
- package/components/ScanVisitorQRCode.vue +9 -2
- package/components/ScheduleAreaMain.vue +0 -1
- package/components/VisitorDataFromScannedQRCodeForm.vue +50 -20
- package/components/VisitorForm.vue +6 -8
- package/components/VisitorManagement.vue +438 -55
- package/composables/useVisitor.ts +5 -2
- package/package.json +1 -1
- package/types/building.d.ts +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog :model-value="modelValue" :max-width="fileType === 'image' ? '1200' : '900'" scrollable
|
|
3
|
+
@update:model-value="emit('update:modelValue', $event)">
|
|
4
|
+
<v-card>
|
|
5
|
+
<v-toolbar density="compact">
|
|
6
|
+
<v-toolbar-title class="text-subtitle-2 text-truncate">{{ fileName }}</v-toolbar-title>
|
|
7
|
+
<v-spacer />
|
|
8
|
+
<v-btn icon="mdi-open-in-new" variant="text" size="small" @click="openInNewTab()" />
|
|
9
|
+
<v-btn icon="mdi-close" variant="text" size="small" @click="emit('update:modelValue', false)" />
|
|
10
|
+
</v-toolbar>
|
|
11
|
+
<v-card-text class="pa-0"
|
|
12
|
+
:style="{ height: fileType === 'image' ? 'auto' : '75vh', 'overflow-y': fileType === 'image' ? 'auto' : 'auto' }">
|
|
13
|
+
<!-- Image Viewer -->
|
|
14
|
+
<v-img v-if="fileType === 'image'" :src="getFileUrl(fileId)" :alt="fileName" class="w-100" />
|
|
15
|
+
|
|
16
|
+
<!-- Video Viewer -->
|
|
17
|
+
<video v-else-if="fileType === 'video'" width="100%" height="100%" controls
|
|
18
|
+
style="background-color: #000;">
|
|
19
|
+
<source :src="getFileUrl(fileId)" :type="mimeType" />
|
|
20
|
+
Your browser does not support the video tag.
|
|
21
|
+
</video>
|
|
22
|
+
|
|
23
|
+
<!-- Document Viewer (PDF, Word, etc.) -->
|
|
24
|
+
<iframe v-else :src="getFileUrl(fileId)" width="100%" height="100%" style="border: none;"
|
|
25
|
+
:title="fileName" />
|
|
26
|
+
</v-card-text>
|
|
27
|
+
<v-card-actions>
|
|
28
|
+
<v-spacer />
|
|
29
|
+
<v-btn variant="text" class="text-none" @click="openInNewTab()">
|
|
30
|
+
<v-icon start>mdi-download</v-icon>
|
|
31
|
+
Open / Download
|
|
32
|
+
</v-btn>
|
|
33
|
+
</v-card-actions>
|
|
34
|
+
</v-card>
|
|
35
|
+
</v-dialog>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup lang="ts">
|
|
39
|
+
const props = defineProps({
|
|
40
|
+
modelValue: {
|
|
41
|
+
type: Boolean,
|
|
42
|
+
default: false,
|
|
43
|
+
},
|
|
44
|
+
fileId: {
|
|
45
|
+
type: String,
|
|
46
|
+
required: true,
|
|
47
|
+
},
|
|
48
|
+
fileName: {
|
|
49
|
+
type: String,
|
|
50
|
+
default: "Document",
|
|
51
|
+
},
|
|
52
|
+
mimeType: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: "application/octet-stream",
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const emit = defineEmits(['update:modelValue']);
|
|
59
|
+
|
|
60
|
+
const { getFileUrl } = useFile();
|
|
61
|
+
|
|
62
|
+
const fileType = computed(() => {
|
|
63
|
+
if (props.mimeType.startsWith('image/')) {
|
|
64
|
+
return 'image';
|
|
65
|
+
} else if (props.mimeType.startsWith('video/')) {
|
|
66
|
+
return 'video';
|
|
67
|
+
} else {
|
|
68
|
+
return 'document';
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
function openInNewTab() {
|
|
73
|
+
window.open(getFileUrl(props.fileId), '_blank', 'noopener,noreferrer');
|
|
74
|
+
}
|
|
75
|
+
</script>
|
|
@@ -441,7 +441,6 @@
|
|
|
441
441
|
|
|
442
442
|
<script setup lang="ts">
|
|
443
443
|
import useEquipmentItem from "../composables/useEquipmentItem";
|
|
444
|
-
import { useEquipmentItemPermission } from "../composables/useEquipmentItemPermission";
|
|
445
444
|
import useEquipmentManagement from "../composables/useEquipmentManagement";
|
|
446
445
|
import useFile from "../composables/useFile";
|
|
447
446
|
import useUtils from "../composables/useUtils";
|
|
@@ -450,9 +449,12 @@ const props = defineProps({
|
|
|
450
449
|
orgId: { type: String, default: "" },
|
|
451
450
|
site: { type: String, default: "" },
|
|
452
451
|
serviceType: { type: String, default: "" },
|
|
452
|
+
canViewAllEquipmentItems: { type: Boolean, default: true },
|
|
453
|
+
canCreateEquipmentItem: { type: Boolean, default: false },
|
|
453
454
|
});
|
|
454
455
|
|
|
455
|
-
const
|
|
456
|
+
const canViewAllEquipmentItems = computed(() => props.canViewAllEquipmentItems);
|
|
457
|
+
const canCreateEquipmentItem = computed(() => props.canCreateEquipmentItem);
|
|
456
458
|
|
|
457
459
|
const items = ref<Array<Record<string, any>>>([]);
|
|
458
460
|
const siteName = ref<string>("");
|
|
@@ -247,7 +247,6 @@
|
|
|
247
247
|
<script setup lang="ts">
|
|
248
248
|
import useEquipment from "../composables/useEquipment";
|
|
249
249
|
import useStock from "../composables/useStock";
|
|
250
|
-
import { useEquipmentPermission } from "../composables/useEquipmentPermission";
|
|
251
250
|
import useUtils from "../composables/useUtils";
|
|
252
251
|
import useEquipmentManagement from "../composables/useEquipmentManagement";
|
|
253
252
|
|
|
@@ -255,17 +254,22 @@ const props = defineProps({
|
|
|
255
254
|
orgId: { type: String, default: "" },
|
|
256
255
|
site: { type: String, default: "" },
|
|
257
256
|
serviceType: { type: String, default: "" },
|
|
257
|
+
canViewEquipments: { type: Boolean, default: true },
|
|
258
|
+
canAddEquipment: { type: Boolean, default: false },
|
|
259
|
+
canUpdateEquipment: { type: Boolean, default: false },
|
|
260
|
+
canDeleteEquipment: { type: Boolean, default: false },
|
|
261
|
+
canAddStock: { type: Boolean, default: false },
|
|
262
|
+
canViewStock: { type: Boolean, default: true },
|
|
263
|
+
canRequestItem: { type: Boolean, default: false },
|
|
258
264
|
});
|
|
259
265
|
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
canRequestItem,
|
|
268
|
-
} = useEquipmentPermission();
|
|
266
|
+
const canViewEquipments = computed(() => props.canViewEquipments);
|
|
267
|
+
const canAddEquipment = computed(() => props.canAddEquipment);
|
|
268
|
+
const canUpdateEquipment = computed(() => props.canUpdateEquipment);
|
|
269
|
+
const canDeleteEquipment = computed(() => props.canDeleteEquipment);
|
|
270
|
+
const canAddStock = computed(() => props.canAddStock);
|
|
271
|
+
const canViewStock = computed(() => props.canViewStock);
|
|
272
|
+
const canRequestItem = computed(() => props.canRequestItem);
|
|
269
273
|
|
|
270
274
|
const items = ref<Array<Record<string, any>>>([]);
|
|
271
275
|
const siteName = ref<string>("");
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</v-col>
|
|
18
18
|
</v-row>
|
|
19
19
|
<TableHygiene
|
|
20
|
-
:title="
|
|
20
|
+
:title="scheduleTitle"
|
|
21
21
|
:headers="headers"
|
|
22
22
|
:items="items"
|
|
23
23
|
:item-value="'unit'"
|
|
@@ -319,6 +319,18 @@ const props = defineProps({
|
|
|
319
319
|
const { getUnitCleanerChecklist, updateUnitChecklist } = useCleaningSchedules();
|
|
320
320
|
const { getBySiteAsServiceProvider } = useCustomerSite();
|
|
321
321
|
const { back } = useUtils();
|
|
322
|
+
|
|
323
|
+
const route = useRoute();
|
|
324
|
+
const scheduleTitle = computed(() => {
|
|
325
|
+
const path = route.path;
|
|
326
|
+
if (path.includes('cleaning-schedule')) return 'Cleaning Checklist';
|
|
327
|
+
if (path.includes('technician-schedule')) return 'Technician Checklist';
|
|
328
|
+
if (path.includes('landscape-schedule')) return 'Landscape Checklist';
|
|
329
|
+
if (path.includes('pool-schedule')) return 'Pool Checklist';
|
|
330
|
+
if (path.includes('pest-schedule')) return 'Pest Checklist';
|
|
331
|
+
return 'Cleaner Checklist';
|
|
332
|
+
});
|
|
333
|
+
|
|
322
334
|
const canAddRemarks = computed(() => props.canAddRemarks);
|
|
323
335
|
const canManageScheduleTasks = computed(() => props.canManageScheduleTasks);
|
|
324
336
|
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<!-- This is where the QR code scanner will be displayed -->
|
|
33
33
|
</div>
|
|
34
34
|
<!-- Show Error Messages -->
|
|
35
|
-
<div v-if="showNotFoundMessage" class="text-error mt-4">
|
|
35
|
+
<div v-if="showNotFoundMessage" class="text-error mt-4 text-h5">
|
|
36
36
|
<p>{{ errorMessage }}</p>
|
|
37
37
|
</div>
|
|
38
38
|
<!-- Switch camera button inside the reader box -->
|
|
@@ -58,6 +58,8 @@ const props = defineProps({
|
|
|
58
58
|
},
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
+
const { standardFormatDate } = useUtils();
|
|
62
|
+
|
|
61
63
|
const { validateVisitorQrCode } = useVisitor();
|
|
62
64
|
|
|
63
65
|
const emits = defineEmits([
|
|
@@ -109,9 +111,14 @@ const handleScanVisitorQRCode = async () => {
|
|
|
109
111
|
console.log("validateVisitorQrCode", response);
|
|
110
112
|
if (response.errorMessage) {
|
|
111
113
|
showNotFoundMessage.value = true;
|
|
112
|
-
errorMessage.value =
|
|
114
|
+
errorMessage.value =
|
|
115
|
+
response.errorMessage +
|
|
116
|
+
(response.scheduledDate
|
|
117
|
+
? standardFormatDate(response.scheduledDate)
|
|
118
|
+
: "");
|
|
113
119
|
showMessage(errorMessage.value, "error");
|
|
114
120
|
} else {
|
|
121
|
+
closeDialog();
|
|
115
122
|
emits("openVisitorDataFromScannedQrCodeDialog", response);
|
|
116
123
|
}
|
|
117
124
|
} else {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
/>
|
|
29
29
|
</v-col>
|
|
30
30
|
|
|
31
|
-
<v-col cols="12">
|
|
31
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
32
32
|
<InputLabel class="text-capitalize" title="NRIC/Passport/ID No." />
|
|
33
33
|
<v-text-field
|
|
34
34
|
v-if="!visitorInfo.checkIn"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
/>
|
|
47
47
|
</v-col>
|
|
48
48
|
|
|
49
|
-
<v-col cols="12" class="mt-4">
|
|
49
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12" class="mt-4">
|
|
50
50
|
<InputLabel
|
|
51
51
|
class="text-capitalize"
|
|
52
52
|
title="Vehicle Number (Optional)"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
/>
|
|
68
68
|
</v-col>
|
|
69
69
|
|
|
70
|
-
<v-col cols="12" class="mt-4">
|
|
70
|
+
<!-- <v-col cols="12" class="mt-4">
|
|
71
71
|
<InputLabel class="text-capitalize" title="Type" />
|
|
72
72
|
<v-text-field
|
|
73
73
|
v-model="visitorInfo.type"
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
hide-details
|
|
76
76
|
readonly
|
|
77
77
|
/>
|
|
78
|
-
</v-col>
|
|
78
|
+
</v-col> -->
|
|
79
79
|
|
|
80
|
-
<v-col cols="12" class="mt-4">
|
|
80
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12" class="mt-4">
|
|
81
81
|
<InputLabel class="text-capitalize" title="Phone Number" />
|
|
82
82
|
<InputPhoneNumberV2
|
|
83
83
|
v-model="visitorInfo.contact"
|
|
@@ -87,32 +87,62 @@
|
|
|
87
87
|
</v-col>
|
|
88
88
|
|
|
89
89
|
<v-col cols="12">
|
|
90
|
+
<InputLabel class="text-capitalize" title="Location" />
|
|
91
|
+
<v-text-field v-model="location" density="comfortable" readonly />
|
|
92
|
+
</v-col>
|
|
93
|
+
|
|
94
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
90
95
|
<InputLabel class="text-capitalize" title="Purpose" />
|
|
91
96
|
<v-textarea
|
|
92
97
|
v-model="visitorInfo.purpose"
|
|
93
98
|
density="comfortable"
|
|
94
|
-
:rows="
|
|
99
|
+
:rows="2"
|
|
95
100
|
no-resize
|
|
96
101
|
readonly
|
|
97
102
|
/>
|
|
98
103
|
</v-col>
|
|
99
104
|
|
|
100
|
-
<v-col cols="12">
|
|
101
|
-
<InputLabel class="text-capitalize" title="
|
|
102
|
-
<v-
|
|
105
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
106
|
+
<InputLabel class="text-capitalize" title="Remarks" />
|
|
107
|
+
<v-textarea
|
|
108
|
+
v-model="visitorInfo.remarks"
|
|
109
|
+
density="comfortable"
|
|
110
|
+
:rows="2"
|
|
111
|
+
no-resize
|
|
112
|
+
/>
|
|
103
113
|
</v-col>
|
|
104
114
|
|
|
105
|
-
<v-col cols="12">
|
|
115
|
+
<v-col v-if="!visitorInfo.checkIn" cols="12">
|
|
106
116
|
<InputLabel class="text-capitalize" title="Visitor Pass" />
|
|
107
117
|
<PassInformation
|
|
108
118
|
v-model:pass="visitorInfo.visitorPass"
|
|
109
119
|
:site="prop.site"
|
|
110
120
|
:type="visitorInfo.type"
|
|
121
|
+
:hideKeys="true"
|
|
111
122
|
:clearable="true"
|
|
112
123
|
/>
|
|
113
124
|
</v-col>
|
|
114
125
|
|
|
115
|
-
<v-col cols="12"
|
|
126
|
+
<v-col v-else cols="12">
|
|
127
|
+
<v-card elevation="4" height="100%" width="100%">
|
|
128
|
+
<v-col cols="12" class="d-flex justify-center pb-0">
|
|
129
|
+
<span
|
|
130
|
+
class="text-h6 font-weight-bold d-flex text-center text-success"
|
|
131
|
+
>
|
|
132
|
+
{{
|
|
133
|
+
visitorInfo.checkIn
|
|
134
|
+
? standardFormatDateTime(visitorInfo.checkIn)
|
|
135
|
+
: "N/A"
|
|
136
|
+
}}
|
|
137
|
+
</span>
|
|
138
|
+
</v-col>
|
|
139
|
+
<v-col cols="12" class="d-flex justify-center">
|
|
140
|
+
Actual Check In
|
|
141
|
+
</v-col>
|
|
142
|
+
</v-card>
|
|
143
|
+
</v-col>
|
|
144
|
+
|
|
145
|
+
<!-- <v-col cols="12" class="mt-4">
|
|
116
146
|
<v-row no-gutters class="pt-2">
|
|
117
147
|
<v-col cols="6" class="pr-1">
|
|
118
148
|
<v-card elevation="3" height="100%" width="100%">
|
|
@@ -151,7 +181,7 @@
|
|
|
151
181
|
</v-card>
|
|
152
182
|
</v-col>
|
|
153
183
|
</v-row>
|
|
154
|
-
</v-col>
|
|
184
|
+
</v-col> -->
|
|
155
185
|
</v-row>
|
|
156
186
|
<!-- </v-form> -->
|
|
157
187
|
</v-card-text>
|
|
@@ -177,7 +207,7 @@
|
|
|
177
207
|
<v-btn
|
|
178
208
|
v-if="visitorInfo.checkIn && !visitorInfo.checkOut"
|
|
179
209
|
block
|
|
180
|
-
text="Check Out"
|
|
210
|
+
text="Confirm Check Out"
|
|
181
211
|
variant="flat"
|
|
182
212
|
color="error"
|
|
183
213
|
size="48"
|
|
@@ -229,13 +259,13 @@ const visitorPlateNumber = computed({
|
|
|
229
259
|
set: () => {}, // readonly, do nothing on set
|
|
230
260
|
});
|
|
231
261
|
|
|
232
|
-
watchEffect(() => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
});
|
|
262
|
+
// watchEffect(() => {
|
|
263
|
+
// if (visitorInfo.value.plateNumber) {
|
|
264
|
+
// visitorInfo.value.type = "guest";
|
|
265
|
+
// } else {
|
|
266
|
+
// visitorInfo.value.type = "walk-in";
|
|
267
|
+
// }
|
|
268
|
+
// });
|
|
239
269
|
|
|
240
270
|
const location = computed({
|
|
241
271
|
get: () => {
|
|
@@ -475,15 +475,13 @@ async function handleAddNewContractorType() {
|
|
|
475
475
|
|
|
476
476
|
async function handleSelectCompanyName(company: string) {
|
|
477
477
|
visitor.company = company
|
|
478
|
+
// const selected = companyAutofillDataArray.value.find(x => x.companyName?.includes(company))
|
|
479
|
+
// if (!selected) return
|
|
478
480
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
visitor.
|
|
483
|
-
visitor.level = selected.level || ""
|
|
484
|
-
visitor.unit = selected.unit || ""
|
|
485
|
-
visitor.unitName = selected.unitName || ""
|
|
486
|
-
|
|
481
|
+
// visitor.block = selected.block || ""
|
|
482
|
+
// visitor.level = selected.level || ""
|
|
483
|
+
// visitor.unit = selected.unit || ""
|
|
484
|
+
// visitor.unitName = selected.unitName || ""
|
|
487
485
|
}
|
|
488
486
|
|
|
489
487
|
const companyCombo = ref(null)
|