@7365admin1/layer-common 1.9.0 → 1.10.1
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/AccessCardAddForm.vue +101 -13
- package/components/AccessManagement.vue +130 -47
- 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 +841 -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/ChecklistItemRow.vue +54 -0
- package/components/CheckoutItemMain.vue +705 -0
- package/components/CleaningScheduleMain.vue +271 -0
- package/components/DocumentManagement.vue +8 -9
- package/components/EntryPass/QrTemplatePreview.vue +104 -0
- package/components/EntryPassMain.vue +252 -200
- package/components/HygieneUpdateMoreAction.vue +238 -0
- package/components/IncidentReport/Authorities.vue +226 -0
- package/components/IncidentReport/IncidentInformation.vue +258 -0
- package/components/IncidentReport/affectedEntities.vue +167 -0
- package/components/InvitationMain.vue +19 -17
- 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/PasswordConfirmation.vue +95 -0
- package/components/PhotoUpload.vue +410 -0
- package/components/RolePermissionMain.vue +17 -15
- 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/ServiceProviderMain.vue +27 -7
- 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 +90 -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/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/useDOBEntries.ts +13 -0
- package/composables/useDashboardData.ts +2 -2
- package/composables/useDocument.ts +3 -2
- package/composables/useFeedback.ts +1 -1
- package/composables/useFile.ts +4 -6
- 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/useRole.ts +3 -2
- 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/types/verification.d.ts +1 -1
- package/utils/acm-crypto.ts +30 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters align="center" justify="center">
|
|
3
|
+
<v-col cols="12">
|
|
4
|
+
<TableMain
|
|
5
|
+
:title="'Schedule Tasks'"
|
|
6
|
+
:items="items"
|
|
7
|
+
:headers="headers"
|
|
8
|
+
:loading="loading"
|
|
9
|
+
:show-header="true"
|
|
10
|
+
v-model:page="page"
|
|
11
|
+
:pages="pages"
|
|
12
|
+
:pageRange="pageRange"
|
|
13
|
+
:no-data-text="'No schedule tasks found'"
|
|
14
|
+
@refresh="getTaskRefresh"
|
|
15
|
+
:canCreate="canCreateScheduleTask"
|
|
16
|
+
createLabel="Create Schedule Task"
|
|
17
|
+
@create="openFormDialog"
|
|
18
|
+
@row-click="onRowClick"
|
|
19
|
+
>
|
|
20
|
+
<template #actions>
|
|
21
|
+
<v-row no-gutters align="center" class="w-100">
|
|
22
|
+
<v-col cols="auto" v-if="canCreateScheduleTask">
|
|
23
|
+
<v-btn
|
|
24
|
+
class="text-none"
|
|
25
|
+
rounded="pill"
|
|
26
|
+
variant="tonal"
|
|
27
|
+
size="large"
|
|
28
|
+
@click="openFormDialog"
|
|
29
|
+
>
|
|
30
|
+
Create Schedule Task
|
|
31
|
+
</v-btn>
|
|
32
|
+
</v-col>
|
|
33
|
+
|
|
34
|
+
<v-spacer />
|
|
35
|
+
|
|
36
|
+
<v-col cols="auto">
|
|
37
|
+
<v-text-field
|
|
38
|
+
v-model="searchInput"
|
|
39
|
+
density="compact"
|
|
40
|
+
placeholder="Search"
|
|
41
|
+
clearable
|
|
42
|
+
width="300"
|
|
43
|
+
append-inner-icon="mdi-magnify"
|
|
44
|
+
hide-details
|
|
45
|
+
/>
|
|
46
|
+
</v-col>
|
|
47
|
+
</v-row>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<!-- frequency removed: using explicit date range in details -->
|
|
51
|
+
|
|
52
|
+
<template #item.areas="{ value }">
|
|
53
|
+
<div v-if="value && value.length > 0">
|
|
54
|
+
<v-chip
|
|
55
|
+
v-for="(area, idx) in value.slice(0, 2)"
|
|
56
|
+
:key="idx"
|
|
57
|
+
size="small"
|
|
58
|
+
class="mr-1 mb-1"
|
|
59
|
+
>
|
|
60
|
+
{{ area.name }}
|
|
61
|
+
</v-chip>
|
|
62
|
+
<v-chip v-if="value.length > 2" size="small" class="mb-1">
|
|
63
|
+
+{{ value.length - 2 }} more
|
|
64
|
+
</v-chip>
|
|
65
|
+
</div>
|
|
66
|
+
<span v-else>N/A</span>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<template #item.status="{ value }">
|
|
70
|
+
<v-chip
|
|
71
|
+
:color="value === 'active' ? 'success' : 'default'"
|
|
72
|
+
class="text-capitalize"
|
|
73
|
+
>
|
|
74
|
+
{{ value || "N/A" }}
|
|
75
|
+
</v-chip>
|
|
76
|
+
</template>
|
|
77
|
+
</TableMain>
|
|
78
|
+
|
|
79
|
+
<ScheduleTaskForm
|
|
80
|
+
v-model:show="showForm"
|
|
81
|
+
:mode="formMode"
|
|
82
|
+
:taskData="selectedTask"
|
|
83
|
+
:site="props.site"
|
|
84
|
+
@refresh="getTaskRefresh"
|
|
85
|
+
/>
|
|
86
|
+
|
|
87
|
+
<v-dialog v-model="dialogShowMoreActions" width="400" persistent>
|
|
88
|
+
<HygieneUpdateMoreAction
|
|
89
|
+
:title="selectedTask?.title || 'Schedule Task Actions'"
|
|
90
|
+
:canUpdate="canUpdateScheduleTask"
|
|
91
|
+
@close="dialogShowMoreActions = false"
|
|
92
|
+
:canDelete="false"
|
|
93
|
+
@edit="onEditFromMoreAction"
|
|
94
|
+
:editButtonLabel="'Edit Schedule Task'"
|
|
95
|
+
>
|
|
96
|
+
<template #content>
|
|
97
|
+
<v-row no-gutters>
|
|
98
|
+
<v-col v-if="selectedTask" cols="12" class="mb-2">
|
|
99
|
+
<v-row no-gutters class="mb-2">
|
|
100
|
+
<v-col cols="5" class="text-subtitle-2 font-weight-bold">
|
|
101
|
+
Title:
|
|
102
|
+
</v-col>
|
|
103
|
+
<v-col cols="7" class="text-subtitle-2">
|
|
104
|
+
{{ selectedTask.title || "N/A" }}
|
|
105
|
+
</v-col>
|
|
106
|
+
</v-row>
|
|
107
|
+
|
|
108
|
+
<v-row no-gutters class="mb-2">
|
|
109
|
+
<v-col cols="5" class="text-subtitle-2 font-weight-bold">
|
|
110
|
+
Date Range:
|
|
111
|
+
</v-col>
|
|
112
|
+
<v-col cols="7" class="text-subtitle-2">
|
|
113
|
+
<div v-if="selectedTask.startDate || selectedTask.endDate">
|
|
114
|
+
{{
|
|
115
|
+
selectedTask.startDate
|
|
116
|
+
? formatDate(selectedTask.startDate)
|
|
117
|
+
: "N/A"
|
|
118
|
+
}}
|
|
119
|
+
-
|
|
120
|
+
{{
|
|
121
|
+
selectedTask.endDate
|
|
122
|
+
? formatDate(selectedTask.endDate)
|
|
123
|
+
: "N/A"
|
|
124
|
+
}}
|
|
125
|
+
</div>
|
|
126
|
+
<div v-else>N/A</div>
|
|
127
|
+
</v-col>
|
|
128
|
+
</v-row>
|
|
129
|
+
|
|
130
|
+
<v-row v-if="selectedTask.time" no-gutters class="mb-2">
|
|
131
|
+
<v-col cols="5" class="text-subtitle-2 font-weight-bold">
|
|
132
|
+
Time:
|
|
133
|
+
</v-col>
|
|
134
|
+
<v-col cols="7" class="text-subtitle-2">
|
|
135
|
+
{{ selectedTask.time || "N/A" }}
|
|
136
|
+
</v-col>
|
|
137
|
+
</v-row>
|
|
138
|
+
|
|
139
|
+
<v-row
|
|
140
|
+
v-if="selectedTask.areas && selectedTask.areas.length > 0"
|
|
141
|
+
no-gutters
|
|
142
|
+
class="mb-2"
|
|
143
|
+
>
|
|
144
|
+
<v-col cols="5" class="text-subtitle-2 font-weight-bold">
|
|
145
|
+
Areas:
|
|
146
|
+
</v-col>
|
|
147
|
+
<v-col cols="7" class="text-subtitle-2">
|
|
148
|
+
<div
|
|
149
|
+
v-for="(area, idx) in selectedTask.areas"
|
|
150
|
+
:key="idx"
|
|
151
|
+
class="mb-1"
|
|
152
|
+
>
|
|
153
|
+
{{ area.name || area }}
|
|
154
|
+
</div>
|
|
155
|
+
</v-col>
|
|
156
|
+
</v-row>
|
|
157
|
+
|
|
158
|
+
<v-row v-if="selectedTask.description" no-gutters class="mb-2">
|
|
159
|
+
<v-col cols="5" class="text-subtitle-2 font-weight-bold">
|
|
160
|
+
Description:
|
|
161
|
+
</v-col>
|
|
162
|
+
<v-col cols="7" class="text-subtitle-2">
|
|
163
|
+
{{ selectedTask.description || "N/A" }}
|
|
164
|
+
</v-col>
|
|
165
|
+
</v-row>
|
|
166
|
+
|
|
167
|
+
<v-row v-if="selectedTask.status" no-gutters class="mb-2">
|
|
168
|
+
<v-col cols="5" class="text-subtitle-2 font-weight-bold">
|
|
169
|
+
Status:
|
|
170
|
+
</v-col>
|
|
171
|
+
<v-col cols="7" class="text-subtitle-2">
|
|
172
|
+
<v-chip
|
|
173
|
+
:color="
|
|
174
|
+
selectedTask.status === 'active' ? 'success' : 'default'
|
|
175
|
+
"
|
|
176
|
+
size="small"
|
|
177
|
+
class="text-capitalize"
|
|
178
|
+
>
|
|
179
|
+
{{ selectedTask.status || "N/A" }}
|
|
180
|
+
</v-chip>
|
|
181
|
+
</v-col>
|
|
182
|
+
</v-row>
|
|
183
|
+
|
|
184
|
+
<v-row v-if="selectedTask.createdAt" no-gutters class="mb-2">
|
|
185
|
+
<v-col cols="5" class="text-subtitle-2 font-weight-bold">
|
|
186
|
+
Created At:
|
|
187
|
+
</v-col>
|
|
188
|
+
<v-col cols="7" class="text-subtitle-2">
|
|
189
|
+
{{ formatDate(selectedTask.createdAt) || "N/A" }}
|
|
190
|
+
</v-col>
|
|
191
|
+
</v-row>
|
|
192
|
+
</v-col>
|
|
193
|
+
|
|
194
|
+
<v-col v-if="message" cols="12" class="my-2">
|
|
195
|
+
<span class="text-subtitle-2 text-error">{{ message }}</span>
|
|
196
|
+
</v-col>
|
|
197
|
+
</v-row>
|
|
198
|
+
</template>
|
|
199
|
+
</HygieneUpdateMoreAction>
|
|
200
|
+
</v-dialog>
|
|
201
|
+
|
|
202
|
+
<Snackbar
|
|
203
|
+
v-model="messageSnackbar"
|
|
204
|
+
:text="message"
|
|
205
|
+
:color="messageColor"
|
|
206
|
+
/>
|
|
207
|
+
</v-col>
|
|
208
|
+
</v-row>
|
|
209
|
+
</template>
|
|
210
|
+
|
|
211
|
+
<script lang="ts" setup>
|
|
212
|
+
import useScheduleTask from "../composables/useScheduleTask";
|
|
213
|
+
import useScheduleTaskPermission from "../composables/useScheduleTaskPermission";
|
|
214
|
+
|
|
215
|
+
const props = defineProps({
|
|
216
|
+
orgId: { type: String, required: true },
|
|
217
|
+
site: { type: String, required: true },
|
|
218
|
+
type: { type: String, default: "toilet" },
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const { formatDate, debounce } = useUtils();
|
|
222
|
+
const { getScheduleTasks, getScheduleTaskById } = useScheduleTask();
|
|
223
|
+
const {
|
|
224
|
+
canViewScheduleTasks,
|
|
225
|
+
canCreateScheduleTask,
|
|
226
|
+
canUpdateScheduleTask,
|
|
227
|
+
canDeleteScheduleTask,
|
|
228
|
+
canViewScheduleTaskDetails,
|
|
229
|
+
} = useScheduleTaskPermission();
|
|
230
|
+
|
|
231
|
+
const page = ref(1);
|
|
232
|
+
const pages = ref(0);
|
|
233
|
+
const pageRange = ref("-- - -- of --");
|
|
234
|
+
|
|
235
|
+
const searchInput = ref("");
|
|
236
|
+
const showForm = ref(false);
|
|
237
|
+
const selectedTask = ref<Record<string, any>>({});
|
|
238
|
+
const formMode = ref<"add" | "edit">("add");
|
|
239
|
+
const submitting = ref(false);
|
|
240
|
+
const dialogShowMoreActions = ref(false);
|
|
241
|
+
const dialogDeleteTask = ref(false);
|
|
242
|
+
|
|
243
|
+
const message = ref("");
|
|
244
|
+
const messageSnackbar = ref(false);
|
|
245
|
+
const messageColor = ref("success");
|
|
246
|
+
|
|
247
|
+
const items = ref<any[]>([]);
|
|
248
|
+
|
|
249
|
+
const headers = [
|
|
250
|
+
{ title: "Title", value: "title" },
|
|
251
|
+
{ title: "Areas", value: "areas" },
|
|
252
|
+
{ title: "Status", value: "status" },
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
const showMessage = (text: string, color: string = "success") => {
|
|
256
|
+
message.value = text;
|
|
257
|
+
messageColor.value = color;
|
|
258
|
+
messageSnackbar.value = true;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const mapShortToDay = (short: string) => {
|
|
262
|
+
const mapping: Record<string, string> = {
|
|
263
|
+
Mon: "Monday",
|
|
264
|
+
Tue: "Tuesday",
|
|
265
|
+
Wed: "Wednesday",
|
|
266
|
+
Thu: "Thursday",
|
|
267
|
+
Fri: "Friday",
|
|
268
|
+
Sat: "Saturday",
|
|
269
|
+
Sun: "Sunday",
|
|
270
|
+
};
|
|
271
|
+
return mapping[short] || short;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const formatTaskDays = (dayField: any) => {
|
|
275
|
+
if (!dayField) return "N/A";
|
|
276
|
+
if (Array.isArray(dayField))
|
|
277
|
+
return dayField.map((d) => mapShortToDay(d)).join(", ");
|
|
278
|
+
return String(dayField);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const {
|
|
282
|
+
data: getTaskReq,
|
|
283
|
+
refresh: getTaskRefresh,
|
|
284
|
+
pending: loading,
|
|
285
|
+
} = await useLazyAsyncData(
|
|
286
|
+
`get-schedule-tasks-${props.site}`,
|
|
287
|
+
() =>
|
|
288
|
+
getScheduleTasks({
|
|
289
|
+
page: page.value,
|
|
290
|
+
site: props.site,
|
|
291
|
+
search: searchInput.value,
|
|
292
|
+
}),
|
|
293
|
+
{
|
|
294
|
+
watch: [page, () => props.site],
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
watchEffect(() => {
|
|
299
|
+
if (getTaskReq.value) {
|
|
300
|
+
items.value = getTaskReq.value.items || getTaskReq.value || [];
|
|
301
|
+
pages.value = getTaskReq.value.pages || 0;
|
|
302
|
+
pageRange.value = getTaskReq.value.pageRange || "-- - -- of --";
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const debounceSearch = debounce(getTaskRefresh, 500);
|
|
307
|
+
|
|
308
|
+
watch(
|
|
309
|
+
[searchInput],
|
|
310
|
+
() => {
|
|
311
|
+
debounceSearch();
|
|
312
|
+
},
|
|
313
|
+
{ immediate: false, deep: true }
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
function openFormDialog() {
|
|
317
|
+
formMode.value = "add";
|
|
318
|
+
selectedTask.value = {};
|
|
319
|
+
showForm.value = true;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function onRowClick(data: any) {
|
|
323
|
+
const taskId = data?.item?._id || data?._id || data?.item?.id || data?.id;
|
|
324
|
+
|
|
325
|
+
if (taskId) {
|
|
326
|
+
try {
|
|
327
|
+
const fullTaskData = await getScheduleTaskById(taskId);
|
|
328
|
+
selectedTask.value = fullTaskData || data?.item || data;
|
|
329
|
+
} catch (error) {
|
|
330
|
+
selectedTask.value = data?.item || data;
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
selectedTask.value = data?.item || data;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
dialogShowMoreActions.value = true;
|
|
337
|
+
message.value = "";
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const onEditFromMoreAction = async () => {
|
|
341
|
+
dialogShowMoreActions.value = false;
|
|
342
|
+
formMode.value = "edit";
|
|
343
|
+
showForm.value = true;
|
|
344
|
+
};
|
|
345
|
+
</script>
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters align="center" justify="center">
|
|
3
|
+
<v-col cols="12" lg="10">
|
|
4
|
+
<TableMain
|
|
5
|
+
:title="'Schedule Tasks'"
|
|
6
|
+
:items="items"
|
|
7
|
+
:headers="headers"
|
|
8
|
+
:loading="loading"
|
|
9
|
+
:show-header="true"
|
|
10
|
+
v-model:page="page"
|
|
11
|
+
:pages="pages"
|
|
12
|
+
:pageRange="pageRange"
|
|
13
|
+
:no-data-text="'No Schedule Tasks found'"
|
|
14
|
+
@row-click="onRowClick"
|
|
15
|
+
>
|
|
16
|
+
<template #item.task="{ item }">
|
|
17
|
+
{{ item.task || "N/A" }}
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<template #item.createdAt="{ value }">
|
|
21
|
+
{{
|
|
22
|
+
formatDate
|
|
23
|
+
? formatDate(value)
|
|
24
|
+
: value
|
|
25
|
+
? new Date(value).toLocaleDateString()
|
|
26
|
+
: ""
|
|
27
|
+
}}
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<template #item.area="{ value }">
|
|
31
|
+
{{ value || "N/A" }}
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<template #item.createdBy="{ item }">
|
|
35
|
+
<v-avatar
|
|
36
|
+
size="32"
|
|
37
|
+
class="mr-2"
|
|
38
|
+
:color="getAvatarColor(item.createdBy)"
|
|
39
|
+
>
|
|
40
|
+
<span class="white--text">{{ getInitials(item.createdBy) }}</span>
|
|
41
|
+
</v-avatar>
|
|
42
|
+
{{ item.createdBy || "N/A" }}
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<template #item.cleaners="{ value }">
|
|
46
|
+
{{ value || "N/A" }}
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<template #item.status="{ value }">
|
|
50
|
+
<v-chip
|
|
51
|
+
:color="getStatusColor(value)"
|
|
52
|
+
class="font-weight-bold"
|
|
53
|
+
style="background: #ffe6c2; color: #ff9800"
|
|
54
|
+
>
|
|
55
|
+
{{ value || "To-Do" }}
|
|
56
|
+
</v-chip>
|
|
57
|
+
</template>
|
|
58
|
+
<!-- Completion Date/Time -->
|
|
59
|
+
<template #item.completionDate="{ value }">
|
|
60
|
+
{{ value ? formatDate(value) : "N/A" }}
|
|
61
|
+
</template>
|
|
62
|
+
<!-- Action (Accept button) -->
|
|
63
|
+
<template #item.action="{ item }">
|
|
64
|
+
<v-btn outlined class="accept-btn" @click.stop="acceptTask(item)">
|
|
65
|
+
Accept
|
|
66
|
+
</v-btn>
|
|
67
|
+
</template>
|
|
68
|
+
</TableMain>
|
|
69
|
+
|
|
70
|
+
<!-- Accept Confirmation Dialog -->
|
|
71
|
+
<AcceptDialog
|
|
72
|
+
:model-value="showAcceptDialog"
|
|
73
|
+
title="Accept Scheduled Task"
|
|
74
|
+
message="Are you sure you want to Accept this Scheduled Task?"
|
|
75
|
+
@confirm="confirmAccept"
|
|
76
|
+
@cancel="showAcceptDialog = false"
|
|
77
|
+
/>
|
|
78
|
+
|
|
79
|
+
<!-- ScheduleTaskForm Dialog -->
|
|
80
|
+
<ScheduleTaskForm v-model:show="showForm" />
|
|
81
|
+
</v-col>
|
|
82
|
+
</v-row>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<script lang="ts" setup>
|
|
86
|
+
const props = defineProps({
|
|
87
|
+
orgId: { type: String, required: true },
|
|
88
|
+
site: { type: String, required: true },
|
|
89
|
+
type: { type: String, required: true },
|
|
90
|
+
});
|
|
91
|
+
const loading = ref(false);
|
|
92
|
+
const page = ref(1);
|
|
93
|
+
const pages = ref(1);
|
|
94
|
+
const pageRange = ref("1-3 of 3");
|
|
95
|
+
const showForm = ref(false);
|
|
96
|
+
|
|
97
|
+
const showAcceptDialog = ref(false);
|
|
98
|
+
const selectedTask = ref(null);
|
|
99
|
+
|
|
100
|
+
const items = ref([
|
|
101
|
+
{
|
|
102
|
+
_id: "1",
|
|
103
|
+
task: "Clean Windows",
|
|
104
|
+
createdAt: "2025-10-28T10:00:00Z",
|
|
105
|
+
area: "",
|
|
106
|
+
createdBy: "Demo Smith",
|
|
107
|
+
cleaners: "N/A",
|
|
108
|
+
status: "To-Do",
|
|
109
|
+
completionDate: "2025-10-28T10:00:00Z",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
_id: "2",
|
|
113
|
+
task: "Clean The 3",
|
|
114
|
+
createdAt: "2025-10-28T10:00:00Z",
|
|
115
|
+
area: "",
|
|
116
|
+
createdBy: "Hygiene SP",
|
|
117
|
+
cleaners: "N/A",
|
|
118
|
+
status: "To-Do",
|
|
119
|
+
completionDate: "2025-10-28T10:00:00Z",
|
|
120
|
+
},
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
const headers = [
|
|
124
|
+
{ title: "Task", value: "task" },
|
|
125
|
+
{ title: "Date Created", value: "createdAt" },
|
|
126
|
+
{ title: "Area", value: "area" },
|
|
127
|
+
{ title: "Created By", value: "createdBy" },
|
|
128
|
+
{ title: "Cleaners", value: "cleaners" },
|
|
129
|
+
{ title: "Status", value: "status" },
|
|
130
|
+
{ title: "Completion Date/Time", value: "completionDate" },
|
|
131
|
+
{ title: "Action", value: "action" },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const { formatDate } = useUtils();
|
|
135
|
+
|
|
136
|
+
function getInitials(name: string) {
|
|
137
|
+
if (!name) return "";
|
|
138
|
+
return name
|
|
139
|
+
.split(" ")
|
|
140
|
+
.map((n) => n[0])
|
|
141
|
+
.join("")
|
|
142
|
+
.toUpperCase();
|
|
143
|
+
}
|
|
144
|
+
function getAvatarColor(name: string) {
|
|
145
|
+
if (name === "Demo Smith") return "purple";
|
|
146
|
+
if (name === "Hygiene SP") return "blue";
|
|
147
|
+
return "grey";
|
|
148
|
+
}
|
|
149
|
+
function getStatusColor(status: string) {
|
|
150
|
+
if (status === "To-Do") return "orange";
|
|
151
|
+
if (status === "Completed") return "green";
|
|
152
|
+
return "grey";
|
|
153
|
+
}
|
|
154
|
+
function acceptTask(item: any) {
|
|
155
|
+
selectedTask.value = item;
|
|
156
|
+
showAcceptDialog.value = true;
|
|
157
|
+
}
|
|
158
|
+
function confirmAccept() {
|
|
159
|
+
// Handle accept logic here (e.g., update status, API call)
|
|
160
|
+
showAcceptDialog.value = false;
|
|
161
|
+
}
|
|
162
|
+
function onRowClick(data: any) {
|
|
163
|
+
const item = data?.item ?? data;
|
|
164
|
+
const id = item?._id || item?.id;
|
|
165
|
+
if (id) {
|
|
166
|
+
const path = `/${props.orgId}/${props.site}/schedule-tasks-ticket/${id}`;
|
|
167
|
+
navigateTo(path);
|
|
168
|
+
} else {
|
|
169
|
+
console.warn("Row clicked but no id found to navigate:", item);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<style scoped>
|
|
175
|
+
.accept-btn {
|
|
176
|
+
border: 1px solid #333;
|
|
177
|
+
background: #fff;
|
|
178
|
+
border-radius: 4px;
|
|
179
|
+
cursor: pointer;
|
|
180
|
+
min-width: 80px;
|
|
181
|
+
}
|
|
182
|
+
</style>
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
</div>
|
|
41
41
|
|
|
42
42
|
<v-text-field
|
|
43
|
+
v-model="searchText"
|
|
43
44
|
placeholder="Search..."
|
|
44
45
|
variant="outlined"
|
|
45
46
|
density="comfortable"
|
|
@@ -420,19 +421,27 @@ const {
|
|
|
420
421
|
invite: inviteServiceProvider,
|
|
421
422
|
} = useServiceProvider();
|
|
422
423
|
|
|
423
|
-
const loading = ref(true);
|
|
424
|
-
|
|
425
424
|
const { getSiteById } = useSite();
|
|
426
425
|
|
|
426
|
+
const { getColorStatus, debounce } = useUtils();
|
|
427
|
+
|
|
427
428
|
const { data: site } = await useLazyAsyncData(
|
|
428
429
|
"get-site-by-id-" + props.siteId,
|
|
429
430
|
() => getSiteById(props.siteId)
|
|
430
431
|
);
|
|
431
432
|
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
433
|
+
const loading = computed(() => getAllReqStatus.value === "pending");
|
|
434
|
+
|
|
435
|
+
const {
|
|
436
|
+
data: serviceProviderReq,
|
|
437
|
+
refresh: _getAllServiceProvider,
|
|
438
|
+
status: getAllReqStatus,
|
|
439
|
+
} = await useLazyAsyncData("get-all-service-providers", () =>
|
|
440
|
+
getAllServiceProvider({
|
|
441
|
+
siteId: props.siteId,
|
|
442
|
+
search: searchText.value || "",
|
|
443
|
+
})
|
|
444
|
+
);
|
|
436
445
|
|
|
437
446
|
watchEffect(() => {
|
|
438
447
|
// console.log("serviceProviderReq", serviceProviderReq.value);
|
|
@@ -441,12 +450,14 @@ watchEffect(() => {
|
|
|
441
450
|
pages.value = serviceProviderReq.value.pages;
|
|
442
451
|
pageRange.value = serviceProviderReq.value.pageRange;
|
|
443
452
|
}
|
|
444
|
-
loading.value = false;
|
|
453
|
+
// loading.value = false;
|
|
445
454
|
});
|
|
446
455
|
|
|
447
456
|
const createDialog = ref(false);
|
|
448
457
|
const createInviteDialog = ref(false);
|
|
449
458
|
|
|
459
|
+
const searchText = ref("");
|
|
460
|
+
|
|
450
461
|
const success = () => {
|
|
451
462
|
createDialog.value = false;
|
|
452
463
|
// getServiceProvider();
|
|
@@ -544,4 +555,13 @@ async function submitServiceProviderInvite() {
|
|
|
544
555
|
disableServiceProvider.value = false;
|
|
545
556
|
}
|
|
546
557
|
}
|
|
558
|
+
|
|
559
|
+
const debounceSearch = debounce(_getAllServiceProvider, 500);
|
|
560
|
+
|
|
561
|
+
watch(
|
|
562
|
+
() => searchText.value,
|
|
563
|
+
() => {
|
|
564
|
+
debounceSearch();
|
|
565
|
+
}
|
|
566
|
+
);
|
|
547
567
|
</script>
|