@7365admin1/layer-common 3.0.0 → 3.0.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 +14 -0
- package/components/AttendanceCheckInOutDialog.vue +0 -1
- package/components/BuildingForm.vue +26 -7
- package/components/BuildingManagement/buildings.vue +1 -1
- package/components/BuildingUnitFormAdd.vue +17 -5
- package/components/DashboardEmptyState.vue +18 -0
- package/components/DashboardMain.vue +998 -1268
- package/components/DashboardPanel.vue +44 -0
- package/components/DocumentForm.vue +22 -4
- package/components/DocumentManagement.vue +43 -6
- package/components/Editor.vue +47 -22
- package/components/MyAttendanceMain.vue +1 -2
- package/components/VisitorManagement.vue +2 -2
- package/components/VisitorsReportPreview.vue +4 -4
- package/composables/useAttendance.ts +2 -2
- package/composables/useDashboard.ts +77 -18
- package/composables/useDocument.ts +1 -0
- package/package.json +1 -1
- package/types/dashboard.d.ts +66 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card
|
|
3
|
+
flat
|
|
4
|
+
border
|
|
5
|
+
rounded="lg"
|
|
6
|
+
class="d-flex flex-column w-100"
|
|
7
|
+
style="min-height: 200px"
|
|
8
|
+
>
|
|
9
|
+
<div class="d-flex align-center justify-space-between pa-5 pb-3">
|
|
10
|
+
<h2 class="text-body-1 font-weight-black text-blue-grey-darken-4 mb-0">
|
|
11
|
+
{{ title }}
|
|
12
|
+
</h2>
|
|
13
|
+
<v-btn
|
|
14
|
+
v-if="actionLabel"
|
|
15
|
+
variant="text"
|
|
16
|
+
color="primary"
|
|
17
|
+
size="small"
|
|
18
|
+
class="text-none font-weight-bold"
|
|
19
|
+
@click="$emit('action')"
|
|
20
|
+
>
|
|
21
|
+
{{ actionLabel }}
|
|
22
|
+
</v-btn>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="flex-1-1-100 overflow-y-auto pa-5 pt-0" style="max-height: 400px">
|
|
26
|
+
<slot />
|
|
27
|
+
</div>
|
|
28
|
+
</v-card>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
defineProps({
|
|
33
|
+
title: {
|
|
34
|
+
type: String,
|
|
35
|
+
required: true,
|
|
36
|
+
},
|
|
37
|
+
actionLabel: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: '',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
defineEmits(['action']);
|
|
44
|
+
</script>
|
|
@@ -125,17 +125,35 @@ const routeParentId = computed(() =>
|
|
|
125
125
|
);
|
|
126
126
|
const effectiveParentId = computed(() => prop.parentId || routeParentId.value);
|
|
127
127
|
|
|
128
|
+
function getAttachmentId(attachment: any): string {
|
|
129
|
+
if (!attachment) return "";
|
|
130
|
+
if (Array.isArray(attachment)) {
|
|
131
|
+
const first = attachment[0];
|
|
132
|
+
if (!first) return "";
|
|
133
|
+
if (typeof first === "string") return first;
|
|
134
|
+
return String(first?._id || first?.id || "");
|
|
135
|
+
}
|
|
136
|
+
if (typeof attachment === "string") return attachment;
|
|
137
|
+
return String(attachment?._id || attachment?.id || "");
|
|
138
|
+
}
|
|
139
|
+
|
|
128
140
|
if (prop.mode === "edit") {
|
|
129
141
|
document.value.name = prop.document.name;
|
|
130
|
-
|
|
142
|
+
|
|
143
|
+
const extractedId = getAttachmentId(prop.document.attachment);
|
|
144
|
+
document.value.attachment = extractedId ? [extractedId] : [];
|
|
145
|
+
|
|
131
146
|
document.value.type = prop.document.type;
|
|
132
147
|
}
|
|
133
148
|
|
|
134
149
|
watch(
|
|
135
150
|
() => document.value.attachment,
|
|
136
|
-
async (newVal) => {
|
|
137
|
-
|
|
138
|
-
|
|
151
|
+
async (newVal, oldVal) => {
|
|
152
|
+
const newId = Array.isArray(newVal) ? newVal[0] : newVal;
|
|
153
|
+
const oldId = Array.isArray(oldVal) ? oldVal[0] : oldVal;
|
|
154
|
+
|
|
155
|
+
if (newId && newId !== oldId) {
|
|
156
|
+
const fileId = newId;
|
|
139
157
|
const fileData = await getFileById(fileId);
|
|
140
158
|
if (fileData) {
|
|
141
159
|
document.value.name = fileData.data.name;
|
|
@@ -177,6 +177,7 @@
|
|
|
177
177
|
<!-- Create Dialog -->
|
|
178
178
|
<v-dialog v-model="createDialog" width="450" persistent>
|
|
179
179
|
<DocumentForm
|
|
180
|
+
v-if="createDialog"
|
|
180
181
|
:parent-id="activeParentId"
|
|
181
182
|
@cancel="createDialog = false"
|
|
182
183
|
@success="successCreate()"
|
|
@@ -253,6 +254,7 @@
|
|
|
253
254
|
<!-- Edit Dialog -->
|
|
254
255
|
<v-dialog v-model="editDialog" width="450" persistent>
|
|
255
256
|
<DocumentForm
|
|
257
|
+
v-if="editDialog"
|
|
256
258
|
mode="edit"
|
|
257
259
|
@cancel="editDialog = false"
|
|
258
260
|
@success="successUpdate()"
|
|
@@ -277,13 +279,19 @@
|
|
|
277
279
|
<v-col cols="6" class="text-right text-body-1">
|
|
278
280
|
<NuxtLink
|
|
279
281
|
v-if="selectedDocument?.attachment && isViewable"
|
|
280
|
-
:to="
|
|
282
|
+
:to="
|
|
283
|
+
getFileUrl(getAttachmentId(selectedDocument.attachment))
|
|
284
|
+
"
|
|
281
285
|
external
|
|
282
286
|
target="_blank"
|
|
283
287
|
>
|
|
284
288
|
View Document
|
|
285
289
|
</NuxtLink>
|
|
286
|
-
<span
|
|
290
|
+
<span
|
|
291
|
+
v-else-if="selectedDocument?.attachment"
|
|
292
|
+
class="text-grey"
|
|
293
|
+
style="opacity: 0.6; cursor: not-allowed"
|
|
294
|
+
>
|
|
287
295
|
View Document
|
|
288
296
|
</span>
|
|
289
297
|
<span v-else>N/A</span>
|
|
@@ -528,6 +536,20 @@ const {
|
|
|
528
536
|
} = documentService;
|
|
529
537
|
const { getFileUrl } = useFile();
|
|
530
538
|
|
|
539
|
+
function getAttachmentId(attachment: any): string {
|
|
540
|
+
if (!attachment) return "";
|
|
541
|
+
|
|
542
|
+
if (Array.isArray(attachment)) {
|
|
543
|
+
const first = attachment[0];
|
|
544
|
+
if (!first) return "";
|
|
545
|
+
if (typeof first === "string") return first;
|
|
546
|
+
return String(first?._id || first?.id || "");
|
|
547
|
+
}
|
|
548
|
+
if (typeof attachment === "string") return attachment;
|
|
549
|
+
|
|
550
|
+
return String(attachment?._id || attachment?.id || "");
|
|
551
|
+
}
|
|
552
|
+
|
|
531
553
|
const router = useRouter();
|
|
532
554
|
const route = useRoute();
|
|
533
555
|
|
|
@@ -627,11 +649,26 @@ function formatBytes(bytes = 0) {
|
|
|
627
649
|
return `${parseFloat((b / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
628
650
|
}
|
|
629
651
|
|
|
652
|
+
const KNOWN_FILE_TYPES = new Set(["pdf", "csv", "doc", "docx", "folder", "mixed"]);
|
|
653
|
+
|
|
654
|
+
function inferDisplayType(doc: any): string {
|
|
655
|
+
if (doc.type === "folder") return "Folder";
|
|
656
|
+
// If stored type is a known file format, use it directly
|
|
657
|
+
const t = String(doc.type || "").toLowerCase().trim();
|
|
658
|
+
if (t && KNOWN_FILE_TYPES.has(t)) return t;
|
|
659
|
+
// Otherwise infer from the document name (handles legacy "public" ACL type)
|
|
660
|
+
const name = String(doc.name || "").toLowerCase();
|
|
661
|
+
if (name.endsWith(".pdf")) return "pdf";
|
|
662
|
+
if (name.endsWith(".csv")) return "csv";
|
|
663
|
+
if (name.endsWith(".docx") || name.endsWith(".doc")) return "doc";
|
|
664
|
+
return t || "N/A";
|
|
665
|
+
}
|
|
666
|
+
|
|
630
667
|
const tableItems = computed(() => {
|
|
631
668
|
return items.value.map((doc: any) => ({
|
|
632
669
|
...doc,
|
|
633
670
|
_raw: doc,
|
|
634
|
-
file_type: doc
|
|
671
|
+
file_type: inferDisplayType(doc),
|
|
635
672
|
file_size:
|
|
636
673
|
doc.type === "folder"
|
|
637
674
|
? "—"
|
|
@@ -664,8 +701,8 @@ const selectedDocument = ref<TDocument>({
|
|
|
664
701
|
});
|
|
665
702
|
|
|
666
703
|
const isViewable = computed(() => {
|
|
667
|
-
const
|
|
668
|
-
return ["pdf", "doc", "csv"].includes(
|
|
704
|
+
const effectiveType = inferDisplayType(selectedDocument.value as any).toLowerCase();
|
|
705
|
+
return ["pdf", "doc", "csv"].includes(effectiveType);
|
|
669
706
|
});
|
|
670
707
|
|
|
671
708
|
const previewDetails = computed(() => {
|
|
@@ -769,7 +806,7 @@ function downloadDocument(document?: TDocument) {
|
|
|
769
806
|
return;
|
|
770
807
|
}
|
|
771
808
|
|
|
772
|
-
const fileUrl = getFileUrl(document.attachment);
|
|
809
|
+
const fileUrl = getFileUrl(getAttachmentId(document.attachment));
|
|
773
810
|
if (fileUrl) {
|
|
774
811
|
window.open(fileUrl, "_blank", "noopener,noreferrer");
|
|
775
812
|
}
|
package/components/Editor.vue
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<ClientOnly>
|
|
3
3
|
<v-row no-gutters class="ckeditor-container w-100">
|
|
4
|
-
<ckeditor
|
|
4
|
+
<ckeditor
|
|
5
|
+
v-model="data"
|
|
6
|
+
:editor="ClassicEditor"
|
|
7
|
+
:config="config"
|
|
8
|
+
@ready="onReady"
|
|
9
|
+
:key="prop.readOnly"
|
|
10
|
+
/>
|
|
5
11
|
</v-row>
|
|
6
12
|
</ClientOnly>
|
|
7
13
|
</template>
|
|
8
14
|
|
|
9
15
|
<script setup>
|
|
10
|
-
|
|
11
16
|
const prop = defineProps({
|
|
12
17
|
readOnly: {
|
|
13
18
|
type: Boolean,
|
|
14
|
-
required: false
|
|
15
|
-
|
|
16
|
-
}
|
|
19
|
+
required: false,
|
|
20
|
+
default: false,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
17
23
|
import {
|
|
18
24
|
ClassicEditor,
|
|
19
25
|
Essentials,
|
|
@@ -25,28 +31,50 @@ import {
|
|
|
25
31
|
Link,
|
|
26
32
|
Alignment,
|
|
27
33
|
Font,
|
|
28
|
-
} from
|
|
29
|
-
import { Ckeditor } from
|
|
30
|
-
import
|
|
34
|
+
} from "ckeditor5";
|
|
35
|
+
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
|
36
|
+
import "ckeditor5/ckeditor5.css";
|
|
31
37
|
|
|
32
|
-
import
|
|
38
|
+
import "ckeditor5/ckeditor5.css";
|
|
33
39
|
|
|
34
|
-
const data = defineModel({ required: true, default: "" })
|
|
40
|
+
const data = defineModel({ required: true, default: "" });
|
|
35
41
|
|
|
36
42
|
const editorInstance = ref(null);
|
|
37
43
|
|
|
38
44
|
const config = computed(() => ({
|
|
39
|
-
licenseKey:
|
|
40
|
-
plugins: [
|
|
45
|
+
licenseKey: "GPL",
|
|
46
|
+
plugins: [
|
|
47
|
+
Essentials,
|
|
48
|
+
Paragraph,
|
|
49
|
+
Bold,
|
|
50
|
+
Italic,
|
|
51
|
+
Heading,
|
|
52
|
+
List,
|
|
53
|
+
Alignment,
|
|
54
|
+
Font,
|
|
55
|
+
],
|
|
41
56
|
toolbar: [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
"undo",
|
|
58
|
+
"redo",
|
|
59
|
+
"|",
|
|
60
|
+
"bold",
|
|
61
|
+
"italic",
|
|
62
|
+
"|",
|
|
63
|
+
"fontSize",
|
|
64
|
+
"fontColor",
|
|
65
|
+
"fontBackgroundColor",
|
|
66
|
+
"|",
|
|
67
|
+
"bulletedList",
|
|
68
|
+
"numberedList",
|
|
69
|
+
"|",
|
|
70
|
+
"heading",
|
|
71
|
+
"|",
|
|
72
|
+
"alignment:left",
|
|
73
|
+
"alignment:center",
|
|
74
|
+
"alignment:right",
|
|
75
|
+
"alignment:justify",
|
|
47
76
|
],
|
|
48
|
-
}))
|
|
49
|
-
|
|
77
|
+
}));
|
|
50
78
|
|
|
51
79
|
function onReady(editor) {
|
|
52
80
|
editorInstance.value = editor;
|
|
@@ -56,7 +84,6 @@ function onReady(editor) {
|
|
|
56
84
|
function toggleReadOnly(isReadOnly) {
|
|
57
85
|
if (!editorInstance.value) return;
|
|
58
86
|
|
|
59
|
-
|
|
60
87
|
if (isReadOnly) {
|
|
61
88
|
editorInstance.value.enableReadOnlyMode("view-mode-lock");
|
|
62
89
|
} else {
|
|
@@ -70,8 +97,6 @@ watch(
|
|
|
70
97
|
toggleReadOnly(newVal);
|
|
71
98
|
}
|
|
72
99
|
);
|
|
73
|
-
|
|
74
|
-
|
|
75
100
|
</script>
|
|
76
101
|
|
|
77
102
|
<style scoped>
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
<AttendanceCheckInOutDialog
|
|
63
63
|
v-model="dialogShowForm"
|
|
64
64
|
:action="currentAction"
|
|
65
|
-
:serviceType="props.serviceType"
|
|
66
65
|
@saved="onAttendanceSaved"
|
|
67
66
|
@close="dialogShowForm = false"
|
|
68
67
|
/>
|
|
@@ -203,7 +202,7 @@ const onAttendanceSaved = async (
|
|
|
203
202
|
try {
|
|
204
203
|
let response;
|
|
205
204
|
if (currentAction.value === "checkIn") {
|
|
206
|
-
response = await checkIn(props.site, payload as TAttendanceCheckIn);
|
|
205
|
+
response = await checkIn(props.site, payload as TAttendanceCheckIn, props.serviceType);
|
|
207
206
|
} else {
|
|
208
207
|
if (!todayAttendance.value?._id) {
|
|
209
208
|
throw new Error("Attendance ID not found");
|
|
@@ -1446,8 +1446,8 @@ function generateCSVData(visitors: any[]): string {
|
|
|
1446
1446
|
visitor.name || "",
|
|
1447
1447
|
formatExportTypes(formatType(visitor)) || "",
|
|
1448
1448
|
visitor.company || "",
|
|
1449
|
-
visitor.block || "",
|
|
1450
|
-
visitor.level || "",
|
|
1449
|
+
visitor.block?.name || "",
|
|
1450
|
+
visitor.level?.name || "",
|
|
1451
1451
|
visitor.unitName || "",
|
|
1452
1452
|
visitor.contact || "",
|
|
1453
1453
|
visitor.plateNumber || "",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
<v-icon icon="mdi-storefront-outline" size="15" />
|
|
41
41
|
<span class="text-capitalize" style="word-break: break-word;">{{
|
|
42
42
|
formatLocation({
|
|
43
|
-
block: item.block,
|
|
44
|
-
level: item.level,
|
|
43
|
+
block: item.block?.name || "",
|
|
44
|
+
level: item.level?.name,
|
|
45
45
|
unit: item.unitName,
|
|
46
46
|
})
|
|
47
47
|
}}</span>
|
|
@@ -182,10 +182,10 @@ watch(getSitesReq, (newData: any) => {
|
|
|
182
182
|
}
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
const formatLocation = ({ block, level, unit }: { block:
|
|
185
|
+
const formatLocation = ({ block, level, unit }: { block: string, level: string, unit: string | TBuildingUnit }) => {
|
|
186
186
|
const parts = [];
|
|
187
187
|
|
|
188
|
-
if (block) parts.push(
|
|
188
|
+
if (block) parts.push(`${block}`);
|
|
189
189
|
if (level) parts.push(level);
|
|
190
190
|
if (unit) parts.push(unit);
|
|
191
191
|
|
|
@@ -37,12 +37,12 @@ export default function useAttendance() {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
function checkIn(site: string, payload: TAttendanceCheckIn) {
|
|
40
|
+
function checkIn(site: string, payload: TAttendanceCheckIn, serviceType: string = "") {
|
|
41
41
|
return useNuxtApp().$api<Record<string, any>>(
|
|
42
42
|
`/api/attendances/site/${site}/check-in`,
|
|
43
43
|
{
|
|
44
44
|
method: "POST",
|
|
45
|
-
body: payload,
|
|
45
|
+
body: { ...payload, serviceType },
|
|
46
46
|
}
|
|
47
47
|
);
|
|
48
48
|
}
|
|
@@ -1,31 +1,90 @@
|
|
|
1
|
-
export default function(){
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
export default function () {
|
|
2
|
+
function getDashboardHygiene(
|
|
3
|
+
site = "",
|
|
4
|
+
period: TDashboardValues = "today",
|
|
5
|
+
serviceType: TServiceType
|
|
6
|
+
) {
|
|
7
|
+
return useNuxtApp().$api<THygieneDashboardData>(
|
|
8
|
+
`/api/dashboard/serviceType/${serviceType}/site/${site}`,
|
|
9
|
+
{
|
|
10
|
+
method: "GET",
|
|
11
|
+
query: {
|
|
12
|
+
period,
|
|
13
|
+
},
|
|
6
14
|
}
|
|
15
|
+
);
|
|
16
|
+
}
|
|
7
17
|
|
|
18
|
+
function getDashboardHygieneWeeklyActivity(
|
|
19
|
+
site = "",
|
|
20
|
+
serviceType: TServiceType = "cleaning_services"
|
|
21
|
+
) {
|
|
22
|
+
return useNuxtApp().$api<THygieneWeeklyActivityItem[]>(
|
|
23
|
+
`/api/dashboard/serviceType/${serviceType}/site/${site}/weekly-activity`,
|
|
24
|
+
{
|
|
25
|
+
method: "GET",
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
}
|
|
8
29
|
|
|
30
|
+
function getDashboardHygieneTaskSchedule(
|
|
31
|
+
site = "",
|
|
32
|
+
serviceType: TServiceType,
|
|
33
|
+
page = 1,
|
|
34
|
+
limit = 4
|
|
35
|
+
) {
|
|
36
|
+
return useNuxtApp().$api<
|
|
37
|
+
THygienePaginatedResponse<THygieneTaskScheduleItem>
|
|
38
|
+
>(`/api/dashboard/serviceType/${serviceType}/site/${site}/task-schedule`, {
|
|
39
|
+
method: "GET",
|
|
40
|
+
query: {
|
|
41
|
+
page,
|
|
42
|
+
limit,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
9
46
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
47
|
+
function getDashboardHygieneAttendance(
|
|
48
|
+
site = "",
|
|
49
|
+
serviceType: TServiceType,
|
|
50
|
+
page = 1,
|
|
51
|
+
limit = 4
|
|
52
|
+
) {
|
|
53
|
+
return useNuxtApp().$api<THygienePaginatedResponse<THygieneAttendanceItem>>(
|
|
54
|
+
`/api/dashboard/serviceType/${serviceType}/site/${site}/attendance`,
|
|
15
55
|
{
|
|
16
56
|
method: "GET",
|
|
17
57
|
query: {
|
|
18
|
-
|
|
58
|
+
page,
|
|
59
|
+
limit,
|
|
19
60
|
},
|
|
20
61
|
}
|
|
21
62
|
);
|
|
22
63
|
}
|
|
23
64
|
|
|
65
|
+
function getDashboardHygieneFeedbacks(
|
|
66
|
+
site = "",
|
|
67
|
+
serviceType: TServiceType,
|
|
68
|
+
page = 1,
|
|
69
|
+
limit = 4
|
|
70
|
+
) {
|
|
71
|
+
return useNuxtApp().$api<THygienePaginatedResponse<THygieneFeedbackItem>>(
|
|
72
|
+
`/api/dashboard/serviceType/${serviceType}/site/${site}/feedbacks`,
|
|
73
|
+
{
|
|
74
|
+
method: "GET",
|
|
75
|
+
query: {
|
|
76
|
+
page,
|
|
77
|
+
limit,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
24
82
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
83
|
+
return {
|
|
84
|
+
getDashboardHygiene,
|
|
85
|
+
getDashboardHygieneWeeklyActivity,
|
|
86
|
+
getDashboardHygieneTaskSchedule,
|
|
87
|
+
getDashboardHygieneAttendance,
|
|
88
|
+
getDashboardHygieneFeedbacks,
|
|
89
|
+
};
|
|
90
|
+
}
|
package/package.json
CHANGED
package/types/dashboard.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
declare type TDashboardValues = "today" | "thisWeek" | "thisMonth";
|
|
2
2
|
|
|
3
|
+
declare type TServiceType =
|
|
4
|
+
| "real_estate_developer"
|
|
5
|
+
| "property_management_agency"
|
|
6
|
+
| "security_agency"
|
|
7
|
+
| "cleaning_services"
|
|
8
|
+
| "mechanical_electrical_services"
|
|
9
|
+
| "landscaping_services"
|
|
10
|
+
| "pest_control_services"
|
|
11
|
+
| "pool_maintenance_services";
|
|
12
|
+
|
|
3
13
|
declare type TDashboardCardValue = {
|
|
4
14
|
key: string;
|
|
5
15
|
periodKey: string;
|
|
@@ -8,4 +18,60 @@ declare type TDashboardCardValue = {
|
|
|
8
18
|
color: string;
|
|
9
19
|
};
|
|
10
20
|
|
|
21
|
+
declare type TDashboardMetric = {
|
|
22
|
+
count?: number;
|
|
23
|
+
percentage?: number;
|
|
24
|
+
overdue?: number;
|
|
25
|
+
inProgress?: number;
|
|
26
|
+
pending?: number;
|
|
27
|
+
highSeverity?: number;
|
|
28
|
+
currentlyOnSite?: number;
|
|
29
|
+
lowStock?: number;
|
|
30
|
+
outOfStock?: number;
|
|
31
|
+
completed?: number;
|
|
32
|
+
total?: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
declare type THygieneDashboardData = {
|
|
36
|
+
openWorkOrder?: TDashboardMetric;
|
|
37
|
+
supplyAlert?: TDashboardMetric;
|
|
38
|
+
taskCompleted?: TDashboardMetric;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
declare type THygieneWeeklyActivityItem = {
|
|
42
|
+
day: string;
|
|
43
|
+
workOrder: number;
|
|
44
|
+
taskCompleted: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
declare type THygieneTaskScheduleItem = {
|
|
48
|
+
_id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
type: string;
|
|
51
|
+
status: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare type THygieneAttendanceItem = {
|
|
55
|
+
_id: string;
|
|
56
|
+
name?: string;
|
|
57
|
+
role?: string;
|
|
58
|
+
status?: string;
|
|
59
|
+
[key: string]: any;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
declare type THygieneFeedbackItem = {
|
|
63
|
+
_id: string;
|
|
64
|
+
subject: string;
|
|
65
|
+
app: string;
|
|
66
|
+
description: string;
|
|
67
|
+
status: string;
|
|
68
|
+
createdAt: string;
|
|
69
|
+
createdByName: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
declare type THygienePaginatedResponse<T> = {
|
|
73
|
+
items: T[];
|
|
74
|
+
pages: number;
|
|
75
|
+
pageRange: string;
|
|
76
|
+
};
|
|
11
77
|
|