@7365admin1/layer-common 4.97.1-staging.577 → 4.97.1-staging.579
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/components/AreaChecklistHistoryLogs.vue +5 -4
- package/components/CleaningScheduleMain.vue +109 -14
- package/components/ManageChecklistMain.vue +16 -12
- package/components/ScheduleAreaMain.vue +56 -71
- package/components/ScheduleGuide.vue +132 -0
- package/components/ScheduleTaskForm.vue +520 -353
- package/components/ScheduleTaskMain.vue +211 -70
- package/components/TableHygiene.vue +2 -2
- package/composables/useCleaningSchedules.ts +9 -0
- package/composables/useScheduleTask.ts +32 -2
- package/nuxt.config.ts +4 -0
- package/package.json +1 -1
- package/plugins/API.ts +31 -1
- package/plugins/client-logs.client.ts +47 -0
- package/types/cleaner-schedule.d.ts +1 -1
- package/utils/client-log.ts +71 -0
- package/utils/schedule-task.ts +281 -0
- package/utils/status.ts +6 -0
- package/composables/useScheduleTaskArea.ts +0 -85
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
THE ONE-LINE EXPLANATION + "BEFORE YOU START" BANNER, shared by every schedule
|
|
3
|
+
screen (Cleaning / Landscape / Pest / Pool / Technician). The intro says what
|
|
4
|
+
the screen is for; the banner appears only when the site is not set up yet
|
|
5
|
+
(no Areas, an Area without "visits per day", or an Area without Units), and
|
|
6
|
+
links straight to where that is fixed. It never blocks the screen and stays
|
|
7
|
+
silent if the check itself fails.
|
|
8
|
+
-->
|
|
9
|
+
<template>
|
|
10
|
+
<div class="schedule-guide">
|
|
11
|
+
<p v-if="text" class="schedule-guide__text">{{ text }}</p>
|
|
12
|
+
<v-alert
|
|
13
|
+
v-if="problems.length"
|
|
14
|
+
type="warning"
|
|
15
|
+
variant="tonal"
|
|
16
|
+
density="comfortable"
|
|
17
|
+
class="schedule-guide__banner"
|
|
18
|
+
title="Before you start"
|
|
19
|
+
>
|
|
20
|
+
<ul class="schedule-guide__list">
|
|
21
|
+
<li v-for="p in problems" :key="p">{{ p }}</li>
|
|
22
|
+
</ul>
|
|
23
|
+
<template #append>
|
|
24
|
+
<v-btn
|
|
25
|
+
:to="areaLink"
|
|
26
|
+
variant="outlined"
|
|
27
|
+
size="small"
|
|
28
|
+
class="text-none"
|
|
29
|
+
>
|
|
30
|
+
Set up Areas and Units
|
|
31
|
+
</v-btn>
|
|
32
|
+
</template>
|
|
33
|
+
</v-alert>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script setup lang="ts">
|
|
38
|
+
import useAreas from "../composables/useAreas";
|
|
39
|
+
import { scheduleNameFor } from "../utils/schedule-task";
|
|
40
|
+
|
|
41
|
+
const props = defineProps({
|
|
42
|
+
orgId: { type: String, required: true },
|
|
43
|
+
site: { type: String, required: true },
|
|
44
|
+
serviceType: { type: String, default: "" },
|
|
45
|
+
scheduleRoute: { type: String, default: "" },
|
|
46
|
+
text: { type: String, default: "" },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const { getAreas, getAreaById } = useAreas();
|
|
50
|
+
const problems = ref<string[]>([]);
|
|
51
|
+
|
|
52
|
+
const areaLink = computed(
|
|
53
|
+
() =>
|
|
54
|
+
`/${props.orgId}/${props.site}/${
|
|
55
|
+
props.scheduleRoute || scheduleNameFor(props.serviceType).route
|
|
56
|
+
}/area`,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// How many areas get a units check: one request each, so capped.
|
|
60
|
+
const MAX_UNIT_CHECKS = 30;
|
|
61
|
+
const plural = (n: number, one: string, many: string) => (n === 1 ? one : many);
|
|
62
|
+
|
|
63
|
+
async function check() {
|
|
64
|
+
try {
|
|
65
|
+
const res = await getAreas({
|
|
66
|
+
site: props.site,
|
|
67
|
+
limit: 200,
|
|
68
|
+
serviceType: props.serviceType,
|
|
69
|
+
});
|
|
70
|
+
const areas: any[] = res?.items || [];
|
|
71
|
+
const found: string[] = [];
|
|
72
|
+
|
|
73
|
+
if (!areas.length) {
|
|
74
|
+
problems.value = [
|
|
75
|
+
"There are no Areas yet. Add your Areas, then the Units in each one.",
|
|
76
|
+
];
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const noVisits = areas.filter((a) => !(Number(a.set) >= 1));
|
|
81
|
+
if (noVisits.length) {
|
|
82
|
+
found.push(
|
|
83
|
+
`${noVisits.length} ${plural(noVisits.length, "area has", "areas have")} no visits per day set: ${noVisits
|
|
84
|
+
.slice(0, 3)
|
|
85
|
+
.map((a) => a.name)
|
|
86
|
+
.join(", ")}${noVisits.length > 3 ? "..." : ""}.`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const noUnits: string[] = [];
|
|
91
|
+
await Promise.all(
|
|
92
|
+
areas.slice(0, MAX_UNIT_CHECKS).map(async (a) => {
|
|
93
|
+
try {
|
|
94
|
+
const full = await getAreaById(a._id);
|
|
95
|
+
if (!(full?.units || []).length) noUnits.push(a.name);
|
|
96
|
+
} catch {
|
|
97
|
+
// a failed lookup is not evidence of a missing unit
|
|
98
|
+
}
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
if (noUnits.length) {
|
|
102
|
+
found.push(
|
|
103
|
+
`${noUnits.length} ${plural(noUnits.length, "area has", "areas have")} no Units, so ${plural(noUnits.length, "it is", "they are")} skipped: ${noUnits
|
|
104
|
+
.slice(0, 3)
|
|
105
|
+
.join(", ")}${noUnits.length > 3 ? "..." : ""}.`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
problems.value = found;
|
|
109
|
+
} catch {
|
|
110
|
+
problems.value = [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
onMounted(check);
|
|
115
|
+
watch(() => [props.site, props.serviceType], check);
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<style scoped>
|
|
119
|
+
.schedule-guide {
|
|
120
|
+
margin-bottom: 12px;
|
|
121
|
+
}
|
|
122
|
+
.schedule-guide__text {
|
|
123
|
+
margin: 0 0 12px;
|
|
124
|
+
font-family: var(--font-sans);
|
|
125
|
+
font-size: var(--fs-cell);
|
|
126
|
+
color: var(--text2);
|
|
127
|
+
}
|
|
128
|
+
.schedule-guide__list {
|
|
129
|
+
margin: 0;
|
|
130
|
+
padding-left: 18px;
|
|
131
|
+
}
|
|
132
|
+
</style>
|