@7365admin1/layer-common 1.10.0 → 1.10.2
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/AcceptDialog.vue +44 -0
- package/components/AccessCard/AvailableStats.vue +55 -0
- package/components/AccessCardAddForm.vue +284 -19
- package/components/AccessCardAssignToUnitForm.vue +440 -0
- package/components/AccessManagement.vue +218 -85
- package/components/AddSupplyForm.vue +165 -0
- package/components/AreaChecklistHistoryLogs.vue +235 -0
- package/components/AreaChecklistHistoryMain.vue +176 -0
- package/components/AreaFormDialog.vue +266 -0
- package/components/AreaMain.vue +863 -0
- package/components/AttendanceCheckInOutDialog.vue +416 -0
- package/components/AttendanceDetailsDialog.vue +184 -0
- package/components/AttendanceMain.vue +155 -0
- package/components/AttendanceMapSearchDialog.vue +393 -0
- package/components/AttendanceSettingsDialog.vue +398 -0
- package/components/BuildingManagement/buildings.vue +5 -5
- package/components/BuildingManagement/units.vue +5 -5
- package/components/BulletinBoardManagement.vue +322 -0
- package/components/ChecklistItemRow.vue +54 -0
- package/components/CheckoutItemMain.vue +705 -0
- package/components/CleaningScheduleMain.vue +271 -0
- package/components/DocumentManagement.vue +4 -0
- package/components/EntryPass/QrTemplatePreview.vue +104 -0
- package/components/EntryPassMain.vue +252 -200
- package/components/HygieneUpdateMoreAction.vue +238 -0
- package/components/ManageChecklistMain.vue +384 -0
- package/components/MemberMain.vue +48 -20
- package/components/MyAttendanceMain.vue +224 -0
- package/components/OnlineFormsConfiguration.vue +9 -2
- package/components/PhotoUpload.vue +410 -0
- package/components/ScheduleAreaMain.vue +313 -0
- package/components/ScheduleTaskAreaFormDialog.vue +144 -0
- package/components/ScheduleTaskAreaUpdateMoreAction.vue +109 -0
- package/components/ScheduleTaskForm.vue +471 -0
- package/components/ScheduleTaskMain.vue +345 -0
- package/components/ScheduleTastTicketMain.vue +182 -0
- package/components/SignaturePad.vue +17 -5
- package/components/StockCard.vue +191 -0
- package/components/SupplyManagementMain.vue +557 -0
- package/components/TableHygiene.vue +617 -0
- package/components/UnitMain.vue +451 -0
- package/components/VisitorManagement.vue +28 -15
- package/composables/useAccessManagement.ts +163 -0
- package/composables/useAreaPermission.ts +51 -0
- package/composables/useAreas.ts +99 -0
- package/composables/useAttendance.ts +89 -0
- package/composables/useAttendancePermission.ts +68 -0
- package/composables/useBuilding.ts +2 -2
- package/composables/useBuildingUnit.ts +2 -2
- package/composables/useBulletin.ts +82 -0
- package/composables/useCard.ts +2 -0
- package/composables/useCheckout.ts +61 -0
- package/composables/useCheckoutPermission.ts +80 -0
- package/composables/useCleaningPermission.ts +229 -0
- package/composables/useCleaningSchedulePermission.ts +58 -0
- package/composables/useCleaningSchedules.ts +233 -0
- package/composables/useCountry.ts +8 -0
- package/composables/useDashboardData.ts +2 -2
- package/composables/useFeedback.ts +1 -1
- package/composables/useLocation.ts +78 -0
- package/composables/useOnlineForm.ts +16 -9
- package/composables/usePeople.ts +87 -72
- package/composables/useQR.ts +29 -0
- package/composables/useScheduleTask.ts +89 -0
- package/composables/useScheduleTaskArea.ts +85 -0
- package/composables/useScheduleTaskPermission.ts +68 -0
- package/composables/useSiteEntryPassSettings.ts +4 -15
- package/composables/useStock.ts +45 -0
- package/composables/useSupply.ts +63 -0
- package/composables/useSupplyPermission.ts +92 -0
- package/composables/useUnitPermission.ts +51 -0
- package/composables/useUnits.ts +82 -0
- package/composables/useWebUsb.ts +389 -0
- package/composables/useWorkOrder.ts +1 -1
- package/nuxt.config.ts +3 -0
- package/package.json +4 -1
- package/types/area.d.ts +22 -0
- package/types/attendance.d.ts +38 -0
- package/types/checkout-item.d.ts +27 -0
- package/types/cleaner-schedule.d.ts +54 -0
- package/types/location.d.ts +42 -0
- package/types/schedule-task.d.ts +18 -0
- package/types/stock.d.ts +16 -0
- package/types/supply.d.ts +11 -0
- package/utils/acm-crypto.ts +30 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters>
|
|
3
|
+
<TableMain :headers="headers" :items="paginatePlaceholderItem" v-model:search="searchInput"
|
|
4
|
+
:loading="getAnnouncementPending" :page="page" :pages="pages" :pageRange="pageRange"
|
|
5
|
+
@refresh="getAnnouncementsRefresh" show-header @update:page="handleUpdatePage" @row-click="handleRowClick"
|
|
6
|
+
@create="handleCreateEvent" :can-create="canCreateBulletinBoard" create-label="Add Announcement">
|
|
7
|
+
<template #extension>
|
|
8
|
+
<v-row no-gutters class="w-100 d-flex flex-column">
|
|
9
|
+
<v-tabs v-model="status" color="primary" :height="40" @update:model-value="toRoute" class="w-100">
|
|
10
|
+
<v-tab v-for="tab in tabOptions" :value="tab.status" :key="tab.status" class="text-capitalize">
|
|
11
|
+
{{ tab.name }}
|
|
12
|
+
</v-tab>
|
|
13
|
+
</v-tabs>
|
|
14
|
+
</v-row>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<template v-slot:item.createdAt="{ item }">
|
|
18
|
+
<span class="d-flex align-center ga-2">
|
|
19
|
+
<v-icon icon="mdi-calendar-start" color="green" size="20" />
|
|
20
|
+
<span class="text-capitalize">{{ toLocalDate(item.createdAt) || "-" }}</span>
|
|
21
|
+
</span>
|
|
22
|
+
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<template v-slot:item.noExpiration="{ item }">
|
|
26
|
+
<BulletinExpirationChip :value="item?.noExpiration" />
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<template v-slot:item.duration="{ item }">
|
|
30
|
+
<span class="d-flex align-center ga-2">
|
|
31
|
+
<v-icon icon="mdi-calendar-start" color="green" size="20" />
|
|
32
|
+
<span class="text-capitalize">{{ toLocalDate(item.startDate) || "-" }}</span>
|
|
33
|
+
</span>
|
|
34
|
+
<span class="d-flex align-center ga-2">
|
|
35
|
+
<v-icon icon="mdi-calendar-end" color="red" size="20" />
|
|
36
|
+
<span class="text-capitalize">{{ toLocalDate(item.endDate) || "_" }}</span>
|
|
37
|
+
</span>
|
|
38
|
+
</template>
|
|
39
|
+
</TableMain>
|
|
40
|
+
|
|
41
|
+
<Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" style="z-index: 3000;" />
|
|
42
|
+
|
|
43
|
+
<v-dialog v-model="dialog.showForm" width="600" persistent>
|
|
44
|
+
<BulletinBoardForm :mode="mode" :site-id="siteId" :active-id="selectedAnnouncementId"
|
|
45
|
+
@close="dialog.showForm = false" @done="handleDone" />
|
|
46
|
+
</v-dialog>
|
|
47
|
+
|
|
48
|
+
<v-dialog v-model="dialog.moreActions" v-if="activeAnnouncementObj && canViewBulletinBoardDetails" width="600"
|
|
49
|
+
persistent>
|
|
50
|
+
<BulletinBoardView :active-announcement="activeAnnouncementObj" :can-delete="canDeleteBulletinBoard"
|
|
51
|
+
:can-update="canUpdateBulletinBoard" @edit="handleEditAnnouncement" @close="dialog.moreActions = false"
|
|
52
|
+
@delete="dialog.deletePrompt = true" />
|
|
53
|
+
</v-dialog>
|
|
54
|
+
|
|
55
|
+
<v-dialog v-model="dialog.deletePrompt" width="450" persistent>
|
|
56
|
+
<CardDeleteConfirmation prompt-title="Are you sure want to delete this announcement?"
|
|
57
|
+
:loading="loading.deletingAnnouncement" @close="dialog.deletePrompt = false"
|
|
58
|
+
@delete="handleProceedDeleteAnnouncement" />
|
|
59
|
+
</v-dialog>
|
|
60
|
+
</v-row>
|
|
61
|
+
</template>
|
|
62
|
+
<script setup lang="ts">
|
|
63
|
+
definePageMeta({
|
|
64
|
+
memberOnly: true,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const props = defineProps({
|
|
68
|
+
siteId: {
|
|
69
|
+
type: String,
|
|
70
|
+
required: true
|
|
71
|
+
},
|
|
72
|
+
canCreateBulletinBoard: {
|
|
73
|
+
type: Boolean,
|
|
74
|
+
default: true
|
|
75
|
+
},
|
|
76
|
+
canUpdateBulletinBoard: {
|
|
77
|
+
type: Boolean,
|
|
78
|
+
default: true
|
|
79
|
+
},
|
|
80
|
+
canViewBulletinBoardDetails: {
|
|
81
|
+
type: Boolean,
|
|
82
|
+
default: true
|
|
83
|
+
}, canDeleteBulletinBoard: {
|
|
84
|
+
type: Boolean,
|
|
85
|
+
default: true
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
const { authenticate } = useLocalAuth();
|
|
91
|
+
authenticate();
|
|
92
|
+
|
|
93
|
+
const route = useRoute();
|
|
94
|
+
const orgId = route.params.org as string;
|
|
95
|
+
const siteId = props.siteId;
|
|
96
|
+
const routeName = (useRoute().name as string) ?? "";
|
|
97
|
+
const { getAll, deleteBulletinById } = useBulletin()
|
|
98
|
+
const { debounce } = useUtils()
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
const headers = [
|
|
103
|
+
{ title: "Title", value: "title" },
|
|
104
|
+
{ title: "Date Created", value: "createdAt", align: "start" },
|
|
105
|
+
{ title: "Start Date/End Date", value: "duration", align: "start" },
|
|
106
|
+
{ title: "No Expiration", value: "noExpiration", align: "start" },
|
|
107
|
+
{ title: "", value: "actions" },
|
|
108
|
+
];
|
|
109
|
+
const items = ref<TAnnouncement[]>([]);
|
|
110
|
+
const page = ref(1);
|
|
111
|
+
const pages = ref(0);
|
|
112
|
+
const pageRange = ref("-- - -- of --");
|
|
113
|
+
const selectedAnnouncementId = ref<string>("")
|
|
114
|
+
const mode = ref<'add' | 'edit'>('add')
|
|
115
|
+
const status = ref<TAnnouncementStatus>()
|
|
116
|
+
const searchInput = ref('')
|
|
117
|
+
|
|
118
|
+
const dialog = reactive({
|
|
119
|
+
showForm: false,
|
|
120
|
+
moreActions: false,
|
|
121
|
+
viewDetails: false,
|
|
122
|
+
deletePrompt: false,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
const loading = reactive({
|
|
126
|
+
deletingAnnouncement: false
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
const messageSnackbar = ref(false)
|
|
130
|
+
const message = ref('')
|
|
131
|
+
const messageColor = ref<'success' | 'error' | 'info'>()
|
|
132
|
+
|
|
133
|
+
const activeAnnouncementObj = computed(() => {
|
|
134
|
+
return items.value.find(x => x._id === selectedAnnouncementId.value)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
const paginatePlaceholderItem = computed(() => {
|
|
138
|
+
const pageSize = 10
|
|
139
|
+
const total = items.value.length
|
|
140
|
+
const currentPage = page.value
|
|
141
|
+
|
|
142
|
+
const start = (currentPage - 1) * pageSize
|
|
143
|
+
const end = start + pageSize
|
|
144
|
+
|
|
145
|
+
const from = total === 0 ? 0 : start + 1
|
|
146
|
+
const to = Math.min(end, total)
|
|
147
|
+
pageRange.value = `${from}-${to} of ${total}`
|
|
148
|
+
|
|
149
|
+
pages.value = Math.ceil(total / pageSize)
|
|
150
|
+
|
|
151
|
+
return items.value.slice(start, end)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
const {
|
|
156
|
+
data: getAnnouncementReq,
|
|
157
|
+
refresh: getAnnouncementsRefresh,
|
|
158
|
+
pending: getAnnouncementPending,
|
|
159
|
+
} = await useLazyAsyncData(
|
|
160
|
+
`get-all-announcements-${page.value}`,
|
|
161
|
+
() => getAll({ page: page.value, site: siteId, status: status.value }),
|
|
162
|
+
{
|
|
163
|
+
watch: [page, () => route.query],
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
watch(getAnnouncementReq, (newVal) => {
|
|
168
|
+
items.value = newVal?.items || [];
|
|
169
|
+
pages.value = newVal?.pages || 0;
|
|
170
|
+
pageRange.value = newVal?.pageRange || "-- - -- of --";
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
function eventStatusFormat(status: any) {
|
|
175
|
+
switch (status) {
|
|
176
|
+
case 'In Progress':
|
|
177
|
+
return {
|
|
178
|
+
color: 'orange',
|
|
179
|
+
text: 'In Progress'
|
|
180
|
+
};
|
|
181
|
+
case 'Active':
|
|
182
|
+
return {
|
|
183
|
+
color: 'green',
|
|
184
|
+
text: status
|
|
185
|
+
}
|
|
186
|
+
case 'Scheduled':
|
|
187
|
+
return {
|
|
188
|
+
color: 'blue',
|
|
189
|
+
text: status
|
|
190
|
+
}
|
|
191
|
+
default:
|
|
192
|
+
return {
|
|
193
|
+
color: 'grey',
|
|
194
|
+
text: status
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const tabOptions = [
|
|
200
|
+
{ name: "Active", status: "active" },
|
|
201
|
+
{ name: "Expired", status: "expired" },
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
function toRoute(status: any) {
|
|
205
|
+
const obj = tabOptions.find((x) => x.status === status);
|
|
206
|
+
if (!obj) return;
|
|
207
|
+
page.value = 1
|
|
208
|
+
navigateTo({
|
|
209
|
+
name: routeName,
|
|
210
|
+
params: {
|
|
211
|
+
org: orgId,
|
|
212
|
+
},
|
|
213
|
+
query: {
|
|
214
|
+
status: obj.status,
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function toLocalDate(utcString: string) {
|
|
220
|
+
if (!utcString) return ""
|
|
221
|
+
return new Date(utcString).toLocaleString("en-US", {
|
|
222
|
+
year: "numeric",
|
|
223
|
+
month: "2-digit",
|
|
224
|
+
day: "2-digit",
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function handleRowClick(data: any) {
|
|
229
|
+
selectedAnnouncementId.value = data?.item?._id;
|
|
230
|
+
dialog.moreActions = true;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function handleUpdatePage(newPageNum: number) {
|
|
234
|
+
page.value = newPageNum;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function handleClose() {
|
|
238
|
+
dialog.showForm = false;
|
|
239
|
+
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function handleFormDone() {
|
|
243
|
+
getAnnouncementsRefresh();
|
|
244
|
+
dialog.showForm = false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function handleFormCreateMore() {
|
|
248
|
+
getAnnouncementsRefresh();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function handleCreateEvent() {
|
|
252
|
+
selectedAnnouncementId.value = ""
|
|
253
|
+
mode.value = 'add'
|
|
254
|
+
dialog.showForm = true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function handleDeleteAnnouncement() {
|
|
258
|
+
dialog.moreActions = false;
|
|
259
|
+
dialog.showForm = false;
|
|
260
|
+
dialog.deletePrompt = true;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function handleEditAnnouncement() {
|
|
264
|
+
dialog.moreActions = false
|
|
265
|
+
mode.value = "edit"
|
|
266
|
+
dialog.showForm = true;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function showMessage(text: string, type: "error" | 'success' | 'info') {
|
|
270
|
+
messageSnackbar.value = true;
|
|
271
|
+
message.value = text;
|
|
272
|
+
messageColor.value = type
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
async function handleProceedDeleteAnnouncement() {
|
|
280
|
+
try {
|
|
281
|
+
loading.deletingAnnouncement = true;
|
|
282
|
+
const bulletinId = selectedAnnouncementId.value;
|
|
283
|
+
const res = await deleteBulletinById(bulletinId as string);
|
|
284
|
+
if (res) {
|
|
285
|
+
showMessage("Announcement successfully deleted!", "info");
|
|
286
|
+
await getAnnouncementsRefresh();
|
|
287
|
+
dialog.deletePrompt = false;
|
|
288
|
+
}
|
|
289
|
+
} catch (error: any) {
|
|
290
|
+
const errorMessage = error?.response?._data?.message;
|
|
291
|
+
console.log("[ERROR]", error);
|
|
292
|
+
showMessage(
|
|
293
|
+
errorMessage || "Something went wrong. Please try again later.",
|
|
294
|
+
"error"
|
|
295
|
+
);
|
|
296
|
+
} finally {
|
|
297
|
+
loading.deletingAnnouncement = false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
async function handleDone() {
|
|
305
|
+
await getAnnouncementsRefresh()
|
|
306
|
+
dialog.showForm = false
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
const debounceSearch = debounce(getAnnouncementsRefresh, 500)
|
|
311
|
+
|
|
312
|
+
watch([searchInput], ([search]) => {
|
|
313
|
+
debounceSearch()
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
onMounted(() => {
|
|
318
|
+
const statusQuery = (useRoute()?.query?.status)
|
|
319
|
+
status.value = (statusQuery === "active" || statusQuery === "expired") ? statusQuery : "active"
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
</script>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters class="py-3 px-2" align="center">
|
|
3
|
+
<v-col cols="auto">
|
|
4
|
+
<v-btn
|
|
5
|
+
:variant="
|
|
6
|
+
item?._action === 'rejected' || item?.reject ? 'tonal' : 'outlined'
|
|
7
|
+
"
|
|
8
|
+
:color="
|
|
9
|
+
item?._action === 'rejected' || item?.reject ? 'error' : undefined
|
|
10
|
+
"
|
|
11
|
+
:disabled="readOnly"
|
|
12
|
+
size="small"
|
|
13
|
+
class="me-2"
|
|
14
|
+
icon
|
|
15
|
+
@click.stop="handleReject"
|
|
16
|
+
>
|
|
17
|
+
<v-icon>mdi-close</v-icon>
|
|
18
|
+
</v-btn>
|
|
19
|
+
</v-col>
|
|
20
|
+
<v-col cols="auto">
|
|
21
|
+
<v-btn
|
|
22
|
+
:variant="
|
|
23
|
+
item?._action === 'accepted' || item?.approve ? 'tonal' : 'outlined'
|
|
24
|
+
"
|
|
25
|
+
:color="
|
|
26
|
+
item?._action === 'accepted' || item?.approve ? 'success' : undefined
|
|
27
|
+
"
|
|
28
|
+
:disabled="readOnly"
|
|
29
|
+
size="small"
|
|
30
|
+
icon
|
|
31
|
+
@click.stop="handleApprove"
|
|
32
|
+
>
|
|
33
|
+
<v-icon>mdi-check</v-icon>
|
|
34
|
+
</v-btn>
|
|
35
|
+
</v-col>
|
|
36
|
+
</v-row>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup lang="ts">
|
|
40
|
+
const props = defineProps({
|
|
41
|
+
item: { type: Object, required: true },
|
|
42
|
+
readOnly: { type: Boolean, default: false },
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const emit = defineEmits(["reject", "approve"]);
|
|
46
|
+
|
|
47
|
+
function handleReject() {
|
|
48
|
+
emit("reject", props.item);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function handleApprove() {
|
|
52
|
+
emit("approve", props.item);
|
|
53
|
+
}
|
|
54
|
+
</script>
|