@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,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>
|
|
@@ -27,8 +27,12 @@
|
|
|
27
27
|
import { ref, defineProps, defineEmits } from "vue";
|
|
28
28
|
import Vue3Signature from "vue3-signature";
|
|
29
29
|
|
|
30
|
-
defineProps({
|
|
30
|
+
const props = defineProps({
|
|
31
31
|
modelValue: String,
|
|
32
|
+
hideToast: {
|
|
33
|
+
type: Boolean,
|
|
34
|
+
default: false,
|
|
35
|
+
}
|
|
32
36
|
});
|
|
33
37
|
|
|
34
38
|
const emit = defineEmits(["update:modelValue"]);
|
|
@@ -53,21 +57,29 @@ function showMessage(msg: string, color: string) {
|
|
|
53
57
|
|
|
54
58
|
function onSave(data: string) {
|
|
55
59
|
emit("update:modelValue", data);
|
|
56
|
-
|
|
60
|
+
if(!props.hideToast) {
|
|
61
|
+
showMessage("Signature saved successfully.", "success");
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
function save() {
|
|
60
66
|
const signatureData = signatureRef.value?.save("image/jpeg");
|
|
61
67
|
if (signatureData) {
|
|
62
68
|
emit("update:modelValue", signatureData);
|
|
63
|
-
|
|
69
|
+
if(!props.hideToast) {
|
|
70
|
+
showMessage("Signature saved successfully.", "success");
|
|
71
|
+
}
|
|
64
72
|
} else {
|
|
65
|
-
|
|
73
|
+
if(!props.hideToast) {
|
|
74
|
+
showMessage("No signature to save.", "error");
|
|
75
|
+
}
|
|
66
76
|
}
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
function clear() {
|
|
70
80
|
signatureRef.value?.clear();
|
|
71
|
-
|
|
81
|
+
if(!props.hideToast) {
|
|
82
|
+
showMessage("Signature cleared.", "success");
|
|
83
|
+
}
|
|
72
84
|
}
|
|
73
85
|
</script>
|