@7365admin1/layer-common 1.11.22 → 1.11.24
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/AreaChecklistHistoryMain.vue +1 -1
- package/components/AttendanceMain.vue +6 -6
- package/components/CleaningScheduleMain.vue +18 -8
- package/components/EquipmentItemMain.vue +4 -2
- package/components/EquipmentManagementMain.vue +14 -10
- package/components/ManageChecklistMain.vue +17 -4
- package/components/MemberInformation.vue +49 -13
- package/components/MyAttendanceMain.vue +6 -3
- package/components/PassInformation.vue +197 -144
- package/components/ScanVisitorQRCode.vue +54 -12
- package/components/ScheduleAreaMain.vue +6 -4
- package/components/ScheduleTaskMain.vue +11 -8
- package/components/VisitorDataFromScannedQRCodeForm.vue +292 -0
- package/components/VisitorForm.vue +6 -8
- package/components/VisitorManagement.vue +229 -20
- package/components/VisitorPassKeyQRScanner.vue +138 -0
- package/composables/useVisitor.ts +89 -28
- package/package.json +2 -1
- package/types/visitor.d.ts +45 -15
package/CHANGELOG.md
CHANGED
|
@@ -97,7 +97,7 @@ const props = defineProps({
|
|
|
97
97
|
site: { type: String, required: true, default: "" },
|
|
98
98
|
scheduleAreaId: { type: String, required: true, default: "" },
|
|
99
99
|
type: { type: String, required: true, default: "cleaner" },
|
|
100
|
-
scheduleRoute: { type: String, default: "
|
|
100
|
+
scheduleRoute: { type: String, default: "pest-schedule" },
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
const { formatDate, back, debounce } = useUtils();
|
|
@@ -61,20 +61,20 @@
|
|
|
61
61
|
|
|
62
62
|
<script setup lang="ts">
|
|
63
63
|
import useAttendance from "../composables/useAttendance";
|
|
64
|
-
import { useAttendancePermission } from "../composables/useAttendancePermission";
|
|
65
64
|
import useUtils from "../composables/useUtils";
|
|
66
65
|
|
|
67
66
|
const props = defineProps({
|
|
68
67
|
orgId: { type: String, default: "" },
|
|
69
68
|
site: { type: String, default: "" },
|
|
70
69
|
serviceType: { type: String, default: "" },
|
|
70
|
+
canViewAllAttendance: { type: Boolean, default: true },
|
|
71
|
+
canViewAttendanceDetails: { type: Boolean, default: true },
|
|
72
|
+
canManageAttendanceSettings: { type: Boolean, default: false },
|
|
71
73
|
});
|
|
72
74
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
canManageAttendanceSettings,
|
|
77
|
-
} = useAttendancePermission();
|
|
75
|
+
const canViewAllAttendance = computed(() => props.canViewAllAttendance);
|
|
76
|
+
const canViewAttendanceDetails = computed(() => props.canViewAttendanceDetails);
|
|
77
|
+
const canManageAttendanceSettings = computed(() => props.canManageAttendanceSettings);
|
|
78
78
|
|
|
79
79
|
const submitting = ref(false);
|
|
80
80
|
const page = ref(1);
|
|
@@ -76,6 +76,15 @@
|
|
|
76
76
|
{{ value || "No Status" }}
|
|
77
77
|
</v-chip>
|
|
78
78
|
</template>
|
|
79
|
+
<template #item.completedAt="{ value }">
|
|
80
|
+
{{
|
|
81
|
+
formatDate
|
|
82
|
+
? formatDate(value)
|
|
83
|
+
: value
|
|
84
|
+
? new Date(value).toLocaleString()
|
|
85
|
+
: ""
|
|
86
|
+
}}
|
|
87
|
+
</template>
|
|
79
88
|
<template #item.download="{ item }">
|
|
80
89
|
<v-btn
|
|
81
90
|
v-if="canDownloadSchedule"
|
|
@@ -102,7 +111,6 @@
|
|
|
102
111
|
</template>
|
|
103
112
|
|
|
104
113
|
<script lang="ts" setup>
|
|
105
|
-
import { useCleaningSchedulePermission } from "../composables/useCleaningSchedulePermission";
|
|
106
114
|
import useCleaningSchedules from "../composables/useCleaningSchedules";
|
|
107
115
|
import useUtils from "../composables/useUtils";
|
|
108
116
|
|
|
@@ -112,6 +120,10 @@ const props = defineProps({
|
|
|
112
120
|
type: { type: String, required: true },
|
|
113
121
|
serviceType: { type: String, default: "" },
|
|
114
122
|
scheduleRoute: { type: String, default: "cleaning-schedule" },
|
|
123
|
+
canViewSchedules: { type: Boolean, default: true },
|
|
124
|
+
canViewScheduleDetails: { type: Boolean, default: true },
|
|
125
|
+
canDownloadSchedule: { type: Boolean, default: false },
|
|
126
|
+
canManageScheduleTasks: { type: Boolean, default: false },
|
|
115
127
|
});
|
|
116
128
|
|
|
117
129
|
const startDate = ref("");
|
|
@@ -133,7 +145,7 @@ const headers = [
|
|
|
133
145
|
{ title: "Created Date", value: "createdAt" },
|
|
134
146
|
{ title: "Close in", value: "closeIn" },
|
|
135
147
|
{ title: "Status", value: "status" },
|
|
136
|
-
{ title: "Completion Date", value: "
|
|
148
|
+
{ title: "Completion Date", value: "completedAt" },
|
|
137
149
|
{ title: "", value: "download" },
|
|
138
150
|
];
|
|
139
151
|
const remainingTime = ref({} as Record<string, string>);
|
|
@@ -172,12 +184,10 @@ const getCloseInColor = (id: string): string => {
|
|
|
172
184
|
return "primary";
|
|
173
185
|
};
|
|
174
186
|
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
canManageScheduleTasks,
|
|
180
|
-
} = useCleaningSchedulePermission();
|
|
187
|
+
const canDownloadSchedule = computed(() => props.canDownloadSchedule);
|
|
188
|
+
const canViewSchedules = computed(() => props.canViewSchedules);
|
|
189
|
+
const canViewScheduleDetails = computed(() => props.canViewScheduleDetails);
|
|
190
|
+
const canManageScheduleTasks = computed(() => props.canManageScheduleTasks);
|
|
181
191
|
|
|
182
192
|
const {
|
|
183
193
|
data: getCleanerChecklistReq,
|
|
@@ -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'"
|
|
@@ -300,7 +300,6 @@
|
|
|
300
300
|
</template>
|
|
301
301
|
|
|
302
302
|
<script setup lang="ts">
|
|
303
|
-
import { useCleaningSchedulePermission } from "../composables/useCleaningSchedulePermission";
|
|
304
303
|
import useCleaningSchedules from "../composables/useCleaningSchedules";
|
|
305
304
|
import useCustomerSite from "../composables/useCustomerSite";
|
|
306
305
|
import useFile from "../composables/useFile";
|
|
@@ -313,13 +312,27 @@ const props = defineProps({
|
|
|
313
312
|
scheduleAreaId: { type: String, default: "" },
|
|
314
313
|
type: { type: String, default: "cleaner" },
|
|
315
314
|
serviceType: { type: String, default: "" },
|
|
315
|
+
canAddRemarks: { type: Boolean, default: false },
|
|
316
|
+
canManageScheduleTasks: { type: Boolean, default: false },
|
|
316
317
|
});
|
|
317
318
|
|
|
318
319
|
const { getUnitCleanerChecklist, updateUnitChecklist } = useCleaningSchedules();
|
|
319
320
|
const { getBySiteAsServiceProvider } = useCustomerSite();
|
|
320
321
|
const { back } = useUtils();
|
|
321
|
-
|
|
322
|
-
|
|
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
|
+
|
|
334
|
+
const canAddRemarks = computed(() => props.canAddRemarks);
|
|
335
|
+
const canManageScheduleTasks = computed(() => props.canManageScheduleTasks);
|
|
323
336
|
|
|
324
337
|
const selectedScheduleStatus = useState<string>(
|
|
325
338
|
"selectedScheduleStatus",
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<v-row no-gutters class="w-100">
|
|
3
3
|
<v-card class="w-100">
|
|
4
4
|
<v-card-text>
|
|
5
|
-
<v-btn block color="primary-button" :height="40" text="Scan QR Code" class="text-capitalize"
|
|
6
|
-
prepend-icon="mdi-qrcode" />
|
|
7
|
-
<v-form ref="formRef" v-model="validForm" :disabled="processing" @click="
|
|
5
|
+
<v-btn block color="primary-button" :height="40" text="Scan QR Code" class="text-capitalize"
|
|
6
|
+
prepend-icon="mdi-qrcode" @click="handleScanQRPass" />
|
|
7
|
+
<v-form ref="formRef" v-model="validForm" :disabled="processing" @click="errorScanPassMessage = ''">
|
|
8
8
|
<v-row no-gutters class="pt-5 ga-2">
|
|
9
9
|
<v-col cols="12">
|
|
10
10
|
<InputLabel class="text-capitalize" title="Full Name" required />
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
</v-col>
|
|
20
20
|
|
|
21
21
|
<v-col cols="12">
|
|
22
|
-
<v-autocomplete v-model="selectedPass" v-model:search="passInput"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
<v-autocomplete v-model="selectedPass" v-model:search="passInput" :hide-no-data="false"
|
|
23
|
+
class="mt-3" :items="passItemsFilteredFinal" item-title="prefixAndName" item-value="_id"
|
|
24
|
+
label="Pass (optional)" variant="outlined" density="compact" :error-messages="errorScanPassMessage"
|
|
25
|
+
persistent-hint small-chips>
|
|
26
26
|
<template v-slot:no-data>
|
|
27
27
|
<v-list-item density="compact">
|
|
28
28
|
<v-list-item-title v-if="passInput">
|
|
@@ -35,8 +35,7 @@
|
|
|
35
35
|
</template>
|
|
36
36
|
|
|
37
37
|
<template v-slot:chip="{ props, item }">
|
|
38
|
-
<v-chip v-if="selectedPass" v-bind="props"
|
|
39
|
-
prepend-icon="mdi-card-bulleted-outline"
|
|
38
|
+
<v-chip v-if="selectedPass" v-bind="props" prepend-icon="mdi-card-bulleted-outline"
|
|
40
39
|
:text="item.raw?.prefixAndName"></v-chip>
|
|
41
40
|
</template>
|
|
42
41
|
</v-autocomplete>
|
|
@@ -62,12 +61,15 @@
|
|
|
62
61
|
</v-form>
|
|
63
62
|
</v-card-text>
|
|
64
63
|
</v-card>
|
|
64
|
+
<visitor-pass-key-q-r-scanner :dialog="dialog.scanQRCode" v-model:scannedValue="scannedPassValue"
|
|
65
|
+
@close-dialog="dialog.scanQRCode = false" />
|
|
65
66
|
<v-divider class="my-3" />
|
|
66
67
|
<v-row v-if="committedMembers.length > 0" no-gutters class="w-100 mt-5 ga-3">
|
|
67
68
|
<template v-for="member, index in committedMembers" :key="member.nric">
|
|
68
69
|
<CardMemberInfoSummary :member="membersDisplayed[index]" @remove="handleRemoveMember(index)" />
|
|
69
70
|
</template>
|
|
70
71
|
</v-row>
|
|
72
|
+
<!-- <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" /> -->
|
|
71
73
|
</v-row>
|
|
72
74
|
</template>
|
|
73
75
|
|
|
@@ -103,18 +105,33 @@ const { getPassKeysByPageSearch } = usePassKey()
|
|
|
103
105
|
const memberForm = reactive<TMemberInfo>({
|
|
104
106
|
name: "",
|
|
105
107
|
nric: "",
|
|
106
|
-
visitorPass:
|
|
108
|
+
visitorPass: [] as { keyId: string }[],
|
|
107
109
|
contact: ""
|
|
108
110
|
})
|
|
109
111
|
|
|
110
112
|
const validForm = ref(false)
|
|
111
113
|
const formRef = ref<HTMLFormElement>()
|
|
112
114
|
const processing = ref(false);
|
|
113
|
-
const
|
|
115
|
+
const errorScanPassMessage = ref('')
|
|
116
|
+
|
|
117
|
+
const message = ref("");
|
|
118
|
+
const messageColor = ref("");
|
|
119
|
+
const messageSnackbar = ref(false);
|
|
120
|
+
|
|
121
|
+
function showMessage(msg: string, color: string) {
|
|
122
|
+
message.value = msg;
|
|
123
|
+
messageColor.value = color;
|
|
124
|
+
messageSnackbar.value = true;
|
|
125
|
+
}
|
|
114
126
|
|
|
115
127
|
// pass
|
|
116
128
|
const passInput = ref('')
|
|
117
129
|
const passItems = ref<TPassKey[]>([])
|
|
130
|
+
const scannedPassValue = ref<string>("")
|
|
131
|
+
|
|
132
|
+
const dialog = reactive({
|
|
133
|
+
scanQRCode: false,
|
|
134
|
+
})
|
|
118
135
|
|
|
119
136
|
const selectedPass = ref<string>('')
|
|
120
137
|
|
|
@@ -160,7 +177,7 @@ watch(passesData, (data: any) => {
|
|
|
160
177
|
|
|
161
178
|
const passItemsFilteredFinal = computed(() => {
|
|
162
179
|
return passItems.value.filter((item: TPassKey) => {
|
|
163
|
-
return !props.selectedVisitorPass.some((pass: TPassKeyPayload) => pass.keyId === item._id) && !committedMembers.value.some((member: TMemberInfo) => member.visitorPass === item._id)
|
|
180
|
+
return !props.selectedVisitorPass.some((pass: TPassKeyPayload) => pass.keyId === item._id) && !committedMembers.value.some((member: TMemberInfo) => member.visitorPass?.some((pass) => pass.keyId === item._id))
|
|
164
181
|
})
|
|
165
182
|
})
|
|
166
183
|
|
|
@@ -168,15 +185,34 @@ const membersDisplayed = computed(() => {
|
|
|
168
185
|
return committedMembers.value.map((member: TMemberInfo) => {
|
|
169
186
|
return {
|
|
170
187
|
...member,
|
|
171
|
-
visitorPass: passItems.value.find((item: TPassKey) => item._id === member.visitorPass)?.prefixAndName || ""
|
|
188
|
+
visitorPass: passItems.value.find((item: TPassKey) => item._id === member.visitorPass?.[0]?.keyId)?.prefixAndName || ""
|
|
172
189
|
}
|
|
173
190
|
})
|
|
174
191
|
})
|
|
175
192
|
|
|
193
|
+
function handleScanQRPass() {
|
|
194
|
+
errorScanPassMessage.value = ""
|
|
195
|
+
dialog.scanQRCode = true
|
|
196
|
+
}
|
|
197
|
+
|
|
176
198
|
watch(selectedPass, (newVal) => {
|
|
177
199
|
memberForm.visitorPass = [{ keyId: newVal }]
|
|
178
200
|
})
|
|
179
201
|
|
|
202
|
+
watch(scannedPassValue, (newVal) => {
|
|
203
|
+
if (!newVal) return
|
|
204
|
+
|
|
205
|
+
const matchedPass = passItemsFilteredFinal.value.find((p) => p.prefixAndName === newVal)
|
|
206
|
+
|
|
207
|
+
if (matchedPass) {
|
|
208
|
+
selectedPass.value = matchedPass._id ?? ""
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
errorScanPassMessage.value = "Scanned pass not available"
|
|
213
|
+
showMessage("Scanned pass not available", "error")
|
|
214
|
+
})
|
|
215
|
+
|
|
180
216
|
|
|
181
217
|
|
|
182
218
|
function handleClearForm() {
|
|
@@ -79,16 +79,19 @@
|
|
|
79
79
|
|
|
80
80
|
<script setup lang="ts">
|
|
81
81
|
import useAttendance from "../composables/useAttendance";
|
|
82
|
-
import { useAttendancePermission } from "../composables/useAttendancePermission";
|
|
83
82
|
|
|
84
83
|
const props = defineProps({
|
|
85
84
|
orgId: { type: String, default: "" },
|
|
86
85
|
site: { type: String, default: "" },
|
|
87
86
|
serviceType: { type: String, default: "" },
|
|
87
|
+
canViewOwnAttendance: { type: Boolean, default: true },
|
|
88
|
+
canCheckInOut: { type: Boolean, default: false },
|
|
89
|
+
canViewAttendanceDetails: { type: Boolean, default: true },
|
|
88
90
|
});
|
|
89
91
|
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
+
const canViewOwnAttendance = computed(() => props.canViewOwnAttendance);
|
|
93
|
+
const canCheckInOut = computed(() => props.canCheckInOut);
|
|
94
|
+
const canViewAttendanceDetails = computed(() => props.canViewAttendanceDetails);
|
|
92
95
|
|
|
93
96
|
const searchInput = ref("");
|
|
94
97
|
const dialogShowForm = ref(false);
|