@7365admin1/layer-common 1.10.8 → 1.10.9
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 +6 -0
- package/components/AccessCardAddForm.vue +1 -1
- package/components/AccessCardAssignToUnitForm.vue +1 -1
- package/components/AccessManagement.vue +1 -1
- package/components/Carousel.vue +474 -0
- package/components/DrawImage.vue +172 -0
- package/components/EntryPassInformation.vue +36 -10
- package/components/EquipmentItemMain.vue +9 -4
- package/components/Feedback/Form.vue +4 -4
- package/components/FeedbackMain.vue +748 -145
- package/components/FileInput.vue +289 -0
- package/components/StockCard.vue +11 -7
- package/components/VisitorForm.vue +129 -44
- package/composables/useAccessManagement.ts +41 -18
- package/composables/useEquipmentManagement.ts +63 -0
- package/composables/useFeedback.ts +53 -21
- package/composables/useLocalAuth.ts +29 -1
- package/composables/useUploadFiles.ts +94 -0
- package/composables/useUtils.ts +152 -53
- package/composables/useVisitor.ts +6 -4
- package/package.json +2 -1
- package/types/feedback.d.ts +5 -2
- package/types/user.d.ts +1 -0
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-row no-gutters>
|
|
3
3
|
<v-col cols="12" class="mb-2">
|
|
4
|
-
<v-row no-gutters align="center"
|
|
5
|
-
<v-btn
|
|
6
|
-
class="text-none text-capitalize"
|
|
7
|
-
rounded="pill"
|
|
8
|
-
variant="tonal"
|
|
9
|
-
size="large"
|
|
10
|
-
@click="showCreateDialog = true"
|
|
11
|
-
v-if="canCreateFeedback"
|
|
12
|
-
>
|
|
13
|
-
Create Feedback
|
|
14
|
-
</v-btn>
|
|
15
|
-
|
|
4
|
+
<v-row no-gutters align="center">
|
|
16
5
|
<v-text-field
|
|
17
6
|
v-model="searchText"
|
|
18
7
|
placeholder="Search feedback..."
|
|
@@ -20,8 +9,55 @@
|
|
|
20
9
|
density="comfortable"
|
|
21
10
|
clearable
|
|
22
11
|
hide-details
|
|
12
|
+
/>
|
|
13
|
+
<v-autocomplete
|
|
14
|
+
v-model="filterByStatus"
|
|
15
|
+
:items="['All', 'To-Do', 'In-Progress', 'For Review', 'Completed']"
|
|
16
|
+
label="Filter by status"
|
|
17
|
+
hide-details
|
|
18
|
+
class="ml-2"
|
|
19
|
+
style="max-width: 250px"
|
|
20
|
+
/>
|
|
21
|
+
<v-text-field
|
|
22
|
+
v-model="startDate"
|
|
23
|
+
:value="standardFormatDate(startDate)"
|
|
24
|
+
label="Start Date"
|
|
25
|
+
readonly
|
|
26
|
+
hide-details
|
|
27
|
+
class="ml-2"
|
|
28
|
+
append-inner-icon="mdi-calendar"
|
|
29
|
+
style="max-width: 250px"
|
|
30
|
+
@click="startDateDialog = true"
|
|
31
|
+
/>
|
|
32
|
+
<v-dialog v-model="startDateDialog" max-width="355">
|
|
33
|
+
<v-card>
|
|
34
|
+
<v-date-picker v-model="startDate" width="320" :locale="locale" />
|
|
35
|
+
</v-card>
|
|
36
|
+
</v-dialog>
|
|
37
|
+
<v-text-field
|
|
38
|
+
v-model="endDate"
|
|
39
|
+
:value="standardFormatDate(endDate)"
|
|
40
|
+
label="End Date"
|
|
41
|
+
readonly
|
|
42
|
+
hide-details
|
|
23
43
|
class="ml-2"
|
|
44
|
+
append-inner-icon="mdi-calendar"
|
|
24
45
|
style="max-width: 250px"
|
|
46
|
+
@click="endDateDialog = true"
|
|
47
|
+
/>
|
|
48
|
+
<v-dialog v-model="endDateDialog" max-width="355">
|
|
49
|
+
<v-card>
|
|
50
|
+
<v-date-picker v-model="endDate" width="320" :locale="locale" />
|
|
51
|
+
</v-card>
|
|
52
|
+
</v-dialog>
|
|
53
|
+
<v-btn
|
|
54
|
+
v-if="canCreateFeedback"
|
|
55
|
+
text="create feedback"
|
|
56
|
+
class="text-none text-capitalize ml-2"
|
|
57
|
+
rounded="pill"
|
|
58
|
+
variant="tonal"
|
|
59
|
+
size="large"
|
|
60
|
+
@click="showCreateDialog = true"
|
|
25
61
|
/>
|
|
26
62
|
</v-row>
|
|
27
63
|
</v-col>
|
|
@@ -36,8 +72,13 @@
|
|
|
36
72
|
>
|
|
37
73
|
<v-toolbar density="compact" color="grey-lighten-4">
|
|
38
74
|
<template #prepend>
|
|
39
|
-
<v-btn
|
|
40
|
-
|
|
75
|
+
<v-btn
|
|
76
|
+
fab
|
|
77
|
+
icon
|
|
78
|
+
density="comfortable"
|
|
79
|
+
@click="(page = 1), refreshFeedbacks()"
|
|
80
|
+
>
|
|
81
|
+
<v-icon icon="mdi-refresh" />
|
|
41
82
|
</v-btn>
|
|
42
83
|
</template>
|
|
43
84
|
|
|
@@ -66,12 +107,102 @@
|
|
|
66
107
|
@click:row="tableRowClickHandler"
|
|
67
108
|
style="max-height: calc(100vh - (200px))"
|
|
68
109
|
>
|
|
110
|
+
<template #item.createdBy="{ item, index }">
|
|
111
|
+
<v-avatar
|
|
112
|
+
v-if="
|
|
113
|
+
item?.createdBy &&
|
|
114
|
+
Boolean(item?.createdBy) &&
|
|
115
|
+
typeof item?.createdBy === 'object' &&
|
|
116
|
+
Object.keys(item?.createdBy).length > 0
|
|
117
|
+
"
|
|
118
|
+
size="small"
|
|
119
|
+
:color="materialColors[index % materialColors.length]"
|
|
120
|
+
class="text-subtitle-2 mr-1 mr-md-4"
|
|
121
|
+
>
|
|
122
|
+
{{
|
|
123
|
+
getInitial(
|
|
124
|
+
`${item?.createdBy?.givenName ?? ""} ${
|
|
125
|
+
item?.createdBy?.surname ?? ""
|
|
126
|
+
}`
|
|
127
|
+
) || ""
|
|
128
|
+
}}
|
|
129
|
+
</v-avatar>
|
|
130
|
+
{{
|
|
131
|
+
`${item?.createdBy?.givenName ?? ""} ${
|
|
132
|
+
item?.createdBy?.surname ?? ""
|
|
133
|
+
}`
|
|
134
|
+
}}
|
|
135
|
+
</template>
|
|
136
|
+
<template #item.subject="{ item }">
|
|
137
|
+
{{ item.subject || "N/A" }}
|
|
138
|
+
<v-tooltip text="High Priority" location="end">
|
|
139
|
+
<template v-slot:activator="{ props }">
|
|
140
|
+
<v-icon
|
|
141
|
+
v-if="item.highPriority"
|
|
142
|
+
icon="mdi-alert-circle-outline"
|
|
143
|
+
color="red"
|
|
144
|
+
class="mb-1"
|
|
145
|
+
size="large"
|
|
146
|
+
v-bind="props"
|
|
147
|
+
/>
|
|
148
|
+
</template>
|
|
149
|
+
</v-tooltip>
|
|
150
|
+
</template>
|
|
151
|
+
<template #item.createdAt="{ value }">
|
|
152
|
+
<v-icon icon="mdi-calendar-month-outline" />
|
|
153
|
+
{{ standardFormatDateTime(value || "") }}
|
|
154
|
+
</template>
|
|
155
|
+
<template #item.status="{ value }">
|
|
156
|
+
<span class="d-inline-block text-truncate">
|
|
157
|
+
<v-chip
|
|
158
|
+
:color="getStatusColor(value ?? '')"
|
|
159
|
+
class="pa-5 text-capitalize text-center whitespace-nowrap text-body-1"
|
|
160
|
+
variant="flat"
|
|
161
|
+
>
|
|
162
|
+
{{ value }}
|
|
163
|
+
</v-chip>
|
|
164
|
+
</span>
|
|
165
|
+
</template>
|
|
166
|
+
<template #item.assigneeInfo="{ item, index }">
|
|
167
|
+
<!-- <span v-if="!item.assigneeInfo">
|
|
168
|
+
<v-btn
|
|
169
|
+
:block="$vuetify.display.xs"
|
|
170
|
+
text="accept"
|
|
171
|
+
variant="flat"
|
|
172
|
+
color="primary"
|
|
173
|
+
:class="`text-${$vuetify.display.xs ? 'h5' : 'body-1'}`"
|
|
174
|
+
:disabled="canAccept(item.raw) ? false : true"
|
|
175
|
+
@click.stop="accept(item.raw)"
|
|
176
|
+
/>
|
|
177
|
+
</span> -->
|
|
178
|
+
<span v-if="item.assigneeInfo" class="mt-1 text-wrap">
|
|
179
|
+
<v-avatar
|
|
180
|
+
size="small"
|
|
181
|
+
:color="materialColors[index % materialColors.length]"
|
|
182
|
+
class="mr-2 text-white"
|
|
183
|
+
>
|
|
184
|
+
{{
|
|
185
|
+
getInitial(
|
|
186
|
+
`${item.assigneeInfo?.givenName ?? ""} ${
|
|
187
|
+
item.assigneeInfo?.surname ?? ""
|
|
188
|
+
}`
|
|
189
|
+
) || ""
|
|
190
|
+
}}
|
|
191
|
+
</v-avatar>
|
|
192
|
+
{{
|
|
193
|
+
`${item.assigneeInfo?.givenName ?? ""} ${
|
|
194
|
+
item.assigneeInfo?.surname ?? ""
|
|
195
|
+
}` || "N/A"
|
|
196
|
+
}}
|
|
197
|
+
</span>
|
|
198
|
+
<span v-else class="mt-1 text-wrap"> Not Assigned </span>
|
|
199
|
+
</template>
|
|
69
200
|
</v-data-table>
|
|
70
201
|
</v-card>
|
|
71
202
|
</v-col>
|
|
72
203
|
</v-row>
|
|
73
204
|
|
|
74
|
-
<FeedbackForm
|
|
205
|
+
<!-- <FeedbackForm
|
|
75
206
|
v-model="showCreateDialog"
|
|
76
207
|
:feedback="_feedback"
|
|
77
208
|
:is-edit-mode="isEditMode"
|
|
@@ -84,7 +215,207 @@
|
|
|
84
215
|
@submit="submitFeedback"
|
|
85
216
|
@file-added="handleFileAdded"
|
|
86
217
|
@file-deleted="deleteFile"
|
|
87
|
-
/>
|
|
218
|
+
/> -->
|
|
219
|
+
|
|
220
|
+
<!-- create feeback dialog -->
|
|
221
|
+
<v-dialog
|
|
222
|
+
v-model="showCreateDialog"
|
|
223
|
+
transition="dialog-bottom-transition"
|
|
224
|
+
style="max-width: 650px"
|
|
225
|
+
>
|
|
226
|
+
<v-card class="rounded-lg pa-0">
|
|
227
|
+
<v-toolbar flat class="rounded-tl-lg rounded-tr-lg">
|
|
228
|
+
<span class="ml-6 font-weight-bold text-1-4rem"> Create Feedback </span>
|
|
229
|
+
<v-spacer />
|
|
230
|
+
<v-btn @click="showCreateDialog = false">
|
|
231
|
+
<v-icon icon="mdi-close" size="40" />
|
|
232
|
+
</v-btn>
|
|
233
|
+
</v-toolbar>
|
|
234
|
+
|
|
235
|
+
<v-row no-gutters class="pa-8">
|
|
236
|
+
<v-col cols="12" class="text-center">
|
|
237
|
+
<Carousel
|
|
238
|
+
v-if="attachedFiles && attachedFiles.length > 0"
|
|
239
|
+
:data-files="
|
|
240
|
+
attachedFiles.map((file) => ({
|
|
241
|
+
name: file.data.name,
|
|
242
|
+
data: file.data,
|
|
243
|
+
progress: 100,
|
|
244
|
+
type: file.data.type,
|
|
245
|
+
url: file.url,
|
|
246
|
+
}))
|
|
247
|
+
"
|
|
248
|
+
:clickable="true"
|
|
249
|
+
:img-editable="true"
|
|
250
|
+
@on-file-edit="onImageEdited"
|
|
251
|
+
:img-delete="true"
|
|
252
|
+
@on-file-delete="removeFile"
|
|
253
|
+
/>
|
|
254
|
+
<span v-else class="font-weight-bold text-subtitle-1">
|
|
255
|
+
No attached image(s) found.
|
|
256
|
+
</span>
|
|
257
|
+
</v-col>
|
|
258
|
+
|
|
259
|
+
<v-col cols="12" class="mt-6">
|
|
260
|
+
<div class="text-subtitle-1 text-medium-emphasis">
|
|
261
|
+
Attach image (Optional)
|
|
262
|
+
</div>
|
|
263
|
+
<FileInput
|
|
264
|
+
:init-files="attachedFiles.map((file) => file.data)"
|
|
265
|
+
@update:files="handleFileUpdate"
|
|
266
|
+
@on-clear="attachedFiles = []"
|
|
267
|
+
/>
|
|
268
|
+
</v-col>
|
|
269
|
+
|
|
270
|
+
<v-col cols="12" class="my-2">
|
|
271
|
+
<div class="text-subtitle-1 text-medium-emphasis">
|
|
272
|
+
Subject
|
|
273
|
+
<span class="text-red">* (Required)</span>
|
|
274
|
+
</div>
|
|
275
|
+
<v-combobox
|
|
276
|
+
v-model="_feedback.subject"
|
|
277
|
+
:items="subjectOptions"
|
|
278
|
+
density="comfortable"
|
|
279
|
+
placeholder="Enter subject"
|
|
280
|
+
clearable
|
|
281
|
+
:filter-keys="['title', 'description']"
|
|
282
|
+
:persistent-hint="false"
|
|
283
|
+
hide-details
|
|
284
|
+
>
|
|
285
|
+
<template v-slot:item="{ props, item }">
|
|
286
|
+
<v-row no-gutters v-bind="props" class="px-3">
|
|
287
|
+
<v-col cols="12" class="pa-2">
|
|
288
|
+
<span class="font-weight-bold">
|
|
289
|
+
{{ item.raw.title }}
|
|
290
|
+
</span>
|
|
291
|
+
<span
|
|
292
|
+
class="d-flex align-center flex-wrap mx-auto px-4 text-caption"
|
|
293
|
+
>
|
|
294
|
+
{{ item.raw.description }}
|
|
295
|
+
</span>
|
|
296
|
+
</v-col>
|
|
297
|
+
</v-row>
|
|
298
|
+
</template>
|
|
299
|
+
</v-combobox>
|
|
300
|
+
</v-col>
|
|
301
|
+
|
|
302
|
+
<v-col cols="12" class="mb-2">
|
|
303
|
+
<div class="text-subtitle-1 text-medium-emphasis">
|
|
304
|
+
Location
|
|
305
|
+
<span class="text-red">* (Required)</span>
|
|
306
|
+
</div>
|
|
307
|
+
<v-text-field
|
|
308
|
+
v-model="_feedback.location"
|
|
309
|
+
density="comfortable"
|
|
310
|
+
placeholder="Enter location"
|
|
311
|
+
clearable
|
|
312
|
+
:persistent-hint="false"
|
|
313
|
+
/>
|
|
314
|
+
</v-col>
|
|
315
|
+
|
|
316
|
+
<v-col cols="12">
|
|
317
|
+
<div class="text-subtitle-1 text-medium-emphasis">
|
|
318
|
+
Description
|
|
319
|
+
<span class="text-red">* (Required)</span>
|
|
320
|
+
</div>
|
|
321
|
+
<v-textarea
|
|
322
|
+
v-model="_feedback.description"
|
|
323
|
+
density="comfortable"
|
|
324
|
+
placeholder="Enter description"
|
|
325
|
+
clearable
|
|
326
|
+
:persistent-hint="false"
|
|
327
|
+
no-resize
|
|
328
|
+
></v-textarea>
|
|
329
|
+
</v-col>
|
|
330
|
+
|
|
331
|
+
<!-- <v-col cols="12" class="mb-4">
|
|
332
|
+
<v-btn
|
|
333
|
+
color="primary"
|
|
334
|
+
height="auto"
|
|
335
|
+
class="mb-4"
|
|
336
|
+
variant="flat"
|
|
337
|
+
@click="attachWorkOrderDialog = true"
|
|
338
|
+
>
|
|
339
|
+
<div class="d-flex justify-space-between align-center w-100 py-2">
|
|
340
|
+
<v-icon
|
|
341
|
+
icon="mdi-check-circle-outline"
|
|
342
|
+
size="50"
|
|
343
|
+
:color="attachWorkOrderForm.attachWorkOrder && 'green'"
|
|
344
|
+
/>
|
|
345
|
+
<span class="text-wrap ml-4"> Create and Attach Work Order </span>
|
|
346
|
+
</div>
|
|
347
|
+
</v-btn>
|
|
348
|
+
</v-col> -->
|
|
349
|
+
|
|
350
|
+
<v-col cols="12">
|
|
351
|
+
<v-btn
|
|
352
|
+
text="submit"
|
|
353
|
+
block
|
|
354
|
+
size="large"
|
|
355
|
+
class="font-weight-bold"
|
|
356
|
+
color="primary"
|
|
357
|
+
:disabled="isFileUploading || isSubmitting"
|
|
358
|
+
@click="submit()"
|
|
359
|
+
:loading="isFileUploading || isSubmitting"
|
|
360
|
+
/>
|
|
361
|
+
</v-col>
|
|
362
|
+
</v-row>
|
|
363
|
+
</v-card>
|
|
364
|
+
</v-dialog>
|
|
365
|
+
|
|
366
|
+
<!-- attach work order dialog -->
|
|
367
|
+
<!-- <v-dialog
|
|
368
|
+
v-model="attachWorkOrderDialog"
|
|
369
|
+
transition="dialog-bottom-transition"
|
|
370
|
+
style="max-width: 650px"
|
|
371
|
+
>
|
|
372
|
+
<v-card class="rounded-lg">
|
|
373
|
+
<v-toolbar>
|
|
374
|
+
<span class="ml-6 font-weight-bold">
|
|
375
|
+
Create and Attach Work Order
|
|
376
|
+
</span>
|
|
377
|
+
<v-spacer />
|
|
378
|
+
<v-btn @click="attachWorkOrderDialog = false">
|
|
379
|
+
<v-icon icon="mdi-close" size="40" />
|
|
380
|
+
</v-btn>
|
|
381
|
+
</v-toolbar>
|
|
382
|
+
|
|
383
|
+
<v-col cols="12" class="px-4">
|
|
384
|
+
<v-textarea
|
|
385
|
+
v-model="attachWorkOrderForm.description"
|
|
386
|
+
label="Email"
|
|
387
|
+
autocomplete="email"
|
|
388
|
+
density="default"
|
|
389
|
+
class="pt-0 mt-0"
|
|
390
|
+
hide-details
|
|
391
|
+
clearable
|
|
392
|
+
>
|
|
393
|
+
<template v-slot:label>
|
|
394
|
+
Description
|
|
395
|
+
<span class="text-error"> (Required)*</span>
|
|
396
|
+
</template>
|
|
397
|
+
</v-textarea>
|
|
398
|
+
<v-checkbox
|
|
399
|
+
v-model="attachWorkOrderForm.isHighPriority"
|
|
400
|
+
label="Set Work Order as High Priority (Optional)"
|
|
401
|
+
class="mb-0 pb-1 mb-n1 ml-n2"
|
|
402
|
+
hide-details
|
|
403
|
+
/>
|
|
404
|
+
</v-col>
|
|
405
|
+
|
|
406
|
+
<v-col cols="12" class="mb-2 px-4">
|
|
407
|
+
<v-btn
|
|
408
|
+
block
|
|
409
|
+
:text="attachWorkOrderForm.attachWorkOrder ? 'detach' : 'attach'"
|
|
410
|
+
class="rounded-lg"
|
|
411
|
+
color="primary"
|
|
412
|
+
height="40px"
|
|
413
|
+
elevation="0"
|
|
414
|
+
@click="attachWorkOrder()"
|
|
415
|
+
/>
|
|
416
|
+
</v-col>
|
|
417
|
+
</v-card>
|
|
418
|
+
</v-dialog> -->
|
|
88
419
|
|
|
89
420
|
<ConfirmDialog
|
|
90
421
|
v-model="showDeleteDialog"
|
|
@@ -206,9 +537,44 @@
|
|
|
206
537
|
</v-toolbar>
|
|
207
538
|
</v-card></v-dialog
|
|
208
539
|
>
|
|
540
|
+
|
|
541
|
+
<!-- accept dialog -->
|
|
542
|
+
<v-dialog
|
|
543
|
+
v-model="acceptDialog"
|
|
544
|
+
transition="dialog-bottom-transition"
|
|
545
|
+
style="max-width: 650px"
|
|
546
|
+
>
|
|
547
|
+
<v-card class="rounded-lg pa-0">
|
|
548
|
+
<v-toolbar flat class="rounded-tl-lg rounded-tr-lg">
|
|
549
|
+
<span class="ml-6 font-weight-bold"> Accept Feedback </span>
|
|
550
|
+
<v-spacer />
|
|
551
|
+
<v-btn @click="acceptDialog = false">
|
|
552
|
+
<v-icon icon="mdi-close" size="40" />
|
|
553
|
+
</v-btn>
|
|
554
|
+
</v-toolbar>
|
|
555
|
+
|
|
556
|
+
<v-card-text class="text-center text-h6">
|
|
557
|
+
Are you sure you want to accept this feedback?
|
|
558
|
+
</v-card-text>
|
|
559
|
+
|
|
560
|
+
<v-col cols="12" class="mb-2 px-4">
|
|
561
|
+
<v-btn
|
|
562
|
+
text="confirm"
|
|
563
|
+
class="rounded-lg"
|
|
564
|
+
color="primary"
|
|
565
|
+
block
|
|
566
|
+
size="x-large"
|
|
567
|
+
elevation="0"
|
|
568
|
+
@click="handleAccept()"
|
|
569
|
+
/>
|
|
570
|
+
</v-col>
|
|
571
|
+
</v-card>
|
|
572
|
+
</v-dialog>
|
|
209
573
|
</template>
|
|
210
574
|
|
|
211
575
|
<script setup lang="ts">
|
|
576
|
+
import moment from "moment-timezone";
|
|
577
|
+
|
|
212
578
|
const props = defineProps({
|
|
213
579
|
detailRoute: {
|
|
214
580
|
type: String,
|
|
@@ -265,7 +631,7 @@ const message = ref("");
|
|
|
265
631
|
const messageColor = ref("");
|
|
266
632
|
const messageSnackbar = ref(false);
|
|
267
633
|
|
|
268
|
-
const {
|
|
634
|
+
const { currentUser } = useLocalAuth();
|
|
269
635
|
|
|
270
636
|
const serviceProviders = ref<
|
|
271
637
|
Array<{ title: string; value: string; subtitle: string }>
|
|
@@ -301,29 +667,34 @@ const _feedback = ref({
|
|
|
301
667
|
location: "",
|
|
302
668
|
description: "",
|
|
303
669
|
highPriority: false,
|
|
304
|
-
attachments: [] as string
|
|
670
|
+
attachments: [] as Array<{ _id: string; name: string; type: string }>,
|
|
305
671
|
serviceProvider: "",
|
|
306
672
|
assignee: "",
|
|
307
673
|
organization: "",
|
|
308
674
|
site: "",
|
|
309
675
|
});
|
|
310
676
|
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
677
|
+
const {
|
|
678
|
+
getStatusColor,
|
|
679
|
+
debounce,
|
|
680
|
+
standardFormatDateTime,
|
|
681
|
+
standardFormatDate,
|
|
682
|
+
materialColors,
|
|
683
|
+
getInitial,
|
|
684
|
+
getImage,
|
|
685
|
+
} = useUtils();
|
|
314
686
|
|
|
315
687
|
const headers: Array<Record<string, any>> = [
|
|
316
688
|
{ title: "Name", value: "createdByName", align: "start" },
|
|
317
689
|
{ title: "Subject", value: "subject", align: "start" },
|
|
318
|
-
{ title: "
|
|
690
|
+
{ title: "Date", value: "createdAt", align: "start" },
|
|
691
|
+
{ title: "App", value: "app", align: "start" },
|
|
319
692
|
{ title: "Status", value: "status", align: "start" },
|
|
693
|
+
{ title: "Assignee", value: "assigneeInfo", align: "start" },
|
|
320
694
|
{ title: "", value: "action-table", align: "end" },
|
|
321
695
|
];
|
|
322
696
|
|
|
323
|
-
// const loading = ref(false);
|
|
324
|
-
const erroredImages = ref<string[]>([]);
|
|
325
697
|
const route = useRoute();
|
|
326
|
-
const { customers } = useCustomer();
|
|
327
698
|
|
|
328
699
|
const dialogPreview = ref(false);
|
|
329
700
|
const selectedFeedback = ref<TFeedback | null>(null);
|
|
@@ -342,49 +713,69 @@ const pages = ref(0);
|
|
|
342
713
|
const pageRange = ref("-- - -- of --");
|
|
343
714
|
const items = ref<Array<Record<string, any>>>([]);
|
|
344
715
|
|
|
716
|
+
const filterByStatus = ref("All");
|
|
717
|
+
const getPast30DaysDate = (): Date => {
|
|
718
|
+
const today = new Date();
|
|
719
|
+
const past30Days = new Date(today);
|
|
720
|
+
past30Days.setDate(today.getDate() - 30);
|
|
721
|
+
return past30Days;
|
|
722
|
+
};
|
|
723
|
+
const startDate = ref<any>(getPast30DaysDate());
|
|
724
|
+
const startDateDialog = ref(false);
|
|
725
|
+
const endDate = ref<any>(new Date());
|
|
726
|
+
const endDateDialog = ref(false);
|
|
727
|
+
const locale = "en";
|
|
728
|
+
|
|
345
729
|
const {
|
|
346
|
-
data:
|
|
347
|
-
status:
|
|
348
|
-
refresh:
|
|
349
|
-
} = useLazyAsyncData(
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
730
|
+
data: feedbacks,
|
|
731
|
+
status: getFeedbacksStatus,
|
|
732
|
+
refresh: refreshFeedbacks,
|
|
733
|
+
} = useLazyAsyncData(
|
|
734
|
+
"get-all-feedbacks",
|
|
735
|
+
() =>
|
|
736
|
+
_getFeedbacks({
|
|
737
|
+
page: page.value,
|
|
738
|
+
site: route.params.site as string,
|
|
739
|
+
provider: currentUser.value.serviceProvider,
|
|
740
|
+
...(currentUser.value.type != "site" && {
|
|
741
|
+
userId: currentUser.value._id,
|
|
742
|
+
}),
|
|
743
|
+
service: "Security",
|
|
744
|
+
dateFrom: moment(startDate.value, "DD/MM/YYYY").startOf("day"),
|
|
745
|
+
dateTo: moment(endDate.value, "DD/MM/YYYY").endOf("day"),
|
|
746
|
+
search: searchText.value,
|
|
747
|
+
status: filterByStatus.value == "All" ? "" : filterByStatus.value,
|
|
748
|
+
}),
|
|
749
|
+
{
|
|
750
|
+
watch: [filterByStatus, searchText, page, startDate, endDate],
|
|
751
|
+
}
|
|
356
752
|
);
|
|
357
753
|
|
|
358
|
-
const loading = computed(() => getAllReqStatus.value === "pending");
|
|
359
|
-
const onNextPrevPageLoading = ref(false);
|
|
360
|
-
|
|
361
754
|
watchEffect(() => {
|
|
362
|
-
if (
|
|
363
|
-
items.value =
|
|
364
|
-
pages.value =
|
|
365
|
-
pageRange.value =
|
|
755
|
+
if (feedbacks.value) {
|
|
756
|
+
items.value = feedbacks.value?.items;
|
|
757
|
+
pages.value = feedbacks.value?.pages;
|
|
758
|
+
pageRange.value = feedbacks.value?.pageRange;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (startDate.value) {
|
|
762
|
+
startDateDialog.value = false;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (endDate.value) {
|
|
766
|
+
endDateDialog.value = false;
|
|
366
767
|
}
|
|
367
768
|
});
|
|
368
769
|
|
|
770
|
+
const loading = computed(() => getFeedbacksStatus.value === "pending");
|
|
771
|
+
|
|
369
772
|
async function updatePage(pageVal: any) {
|
|
370
|
-
onNextPrevPageLoading.value = true;
|
|
371
773
|
page.value = pageVal;
|
|
372
|
-
const response = await _getFeedbacks({
|
|
373
|
-
page: page.value,
|
|
374
|
-
site: route.params.site as string,
|
|
375
|
-
category: props.category,
|
|
376
|
-
});
|
|
377
|
-
if (response) {
|
|
378
|
-
items.value = response.items;
|
|
379
|
-
pages.value = response.pages;
|
|
380
|
-
pageRange.value = response.pageRange;
|
|
381
|
-
onNextPrevPageLoading.value = false;
|
|
382
|
-
}
|
|
383
774
|
}
|
|
384
775
|
|
|
385
|
-
function onSelectedUpdate(newSelected: string[]) {
|
|
386
|
-
|
|
387
|
-
}
|
|
776
|
+
// function onSelectedUpdate(newSelected: string[]) {
|
|
777
|
+
// selected.value = newSelected;
|
|
778
|
+
// }
|
|
388
779
|
|
|
389
780
|
async function editFeedback(item: any) {
|
|
390
781
|
try {
|
|
@@ -436,7 +827,7 @@ async function submitDelete() {
|
|
|
436
827
|
try {
|
|
437
828
|
const response = await deleteFeedback(feedbackToDelete.value._id);
|
|
438
829
|
showMessage(response.message, "success");
|
|
439
|
-
await
|
|
830
|
+
await refreshFeedbacks();
|
|
440
831
|
} catch (error) {
|
|
441
832
|
console.error("Failed to delete feedback:", error);
|
|
442
833
|
showMessage("Failed to delete feedback!", "error");
|
|
@@ -450,7 +841,7 @@ async function submitDelete() {
|
|
|
450
841
|
|
|
451
842
|
const resetFeedbackForm = () => {
|
|
452
843
|
_feedback.value = {
|
|
453
|
-
attachments: [] as string
|
|
844
|
+
attachments: [] as Array<{ _id: string; name: string; type: string }>,
|
|
454
845
|
category: "",
|
|
455
846
|
subject: "",
|
|
456
847
|
location: "",
|
|
@@ -468,67 +859,68 @@ function handleCloseDialog() {
|
|
|
468
859
|
isEditMode.value = false;
|
|
469
860
|
showCreateDialog.value = false;
|
|
470
861
|
}
|
|
471
|
-
const _feedbackId = ref<string | null>(null);
|
|
472
|
-
|
|
473
|
-
async function _createFeedback(organization: string, site: string) {
|
|
474
|
-
const userId = getUserFromCookie();
|
|
475
|
-
|
|
476
|
-
const createPayload: TFeedbackCreate = {
|
|
477
|
-
subject: _feedback.value.subject,
|
|
478
|
-
category: _feedback.value.category,
|
|
479
|
-
location: _feedback.value.location,
|
|
480
|
-
description: _feedback.value.description,
|
|
481
|
-
highPriority: _feedback.value.highPriority ?? false,
|
|
482
|
-
attachments: _feedback.value.attachments || [],
|
|
483
|
-
serviceProvider: _feedback.value.serviceProvider || "",
|
|
484
|
-
assignee: _feedback.value.assignee || "",
|
|
485
|
-
organization,
|
|
486
|
-
site,
|
|
487
|
-
...(userId !== null ? { createdBy: userId } : {}),
|
|
488
|
-
};
|
|
489
862
|
|
|
490
|
-
|
|
491
|
-
showMessage(response?.message || "Feedback created successfully", "success");
|
|
492
|
-
}
|
|
863
|
+
// const _feedbackId = ref<string | null>(null);
|
|
493
864
|
|
|
494
|
-
async function
|
|
495
|
-
|
|
865
|
+
// async function _createFeedback(organization: string, site: string) {
|
|
866
|
+
// const userId = getUserFromCookie();
|
|
496
867
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
868
|
+
// const createPayload: TFeedbackCreate = {
|
|
869
|
+
// subject: _feedback.value.subject,
|
|
870
|
+
// category: _feedback.value.category,
|
|
871
|
+
// location: _feedback.value.location,
|
|
872
|
+
// description: _feedback.value.description,
|
|
873
|
+
// highPriority: _feedback.value.highPriority ?? false,
|
|
874
|
+
// attachments: _feedback.value.attachments || [],
|
|
875
|
+
// serviceProvider: _feedback.value.serviceProvider || "",
|
|
876
|
+
// assignee: _feedback.value.assignee || "",
|
|
877
|
+
// organization,
|
|
878
|
+
// site,
|
|
879
|
+
// ...(userId !== null ? { createdBy: userId } : {}),
|
|
880
|
+
// };
|
|
504
881
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
882
|
+
// const response = await createFeedback(createPayload);
|
|
883
|
+
// showMessage(response?.message || "Feedback created successfully", "success");
|
|
884
|
+
// }
|
|
508
885
|
|
|
509
|
-
|
|
510
|
-
|
|
886
|
+
// async function _updateFeedback() {
|
|
887
|
+
// if (!_feedbackId.value) return;
|
|
511
888
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
889
|
+
// const updatePayload: TFeedbackUpdate = {
|
|
890
|
+
// subject: _feedback.value.subject,
|
|
891
|
+
// category: _feedback.value.category,
|
|
892
|
+
// location: _feedback.value.location,
|
|
893
|
+
// description: _feedback.value.description,
|
|
894
|
+
// attachments: _feedback.value.attachments || [],
|
|
895
|
+
// };
|
|
515
896
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
await _createFeedback(organization, site);
|
|
520
|
-
}
|
|
897
|
+
// const response = await updateFeedback(_feedbackId.value, updatePayload);
|
|
898
|
+
// showMessage(response?.message || "Feedback updated successfully", "success");
|
|
899
|
+
// }
|
|
521
900
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}
|
|
901
|
+
// const submitFeedback = async () => {
|
|
902
|
+
// submitting.value = true;
|
|
903
|
+
|
|
904
|
+
// try {
|
|
905
|
+
// const organization = route.params.org as string;
|
|
906
|
+
// const site = route.params.site as string;
|
|
907
|
+
|
|
908
|
+
// if (isEditMode.value) {
|
|
909
|
+
// await _updateFeedback();
|
|
910
|
+
// } else {
|
|
911
|
+
// await _createFeedback(organization, site);
|
|
912
|
+
// }
|
|
913
|
+
|
|
914
|
+
// showCreateDialog.value = false;
|
|
915
|
+
// await refreshFeedbacks();
|
|
916
|
+
// resetFeedbackForm();
|
|
917
|
+
// } catch (error) {
|
|
918
|
+
// console.error(error);
|
|
919
|
+
// showMessage("Something went wrong", "error");
|
|
920
|
+
// } finally {
|
|
921
|
+
// submitting.value = false;
|
|
922
|
+
// }
|
|
923
|
+
// };
|
|
532
924
|
|
|
533
925
|
function showMessage(msg: string, color: string) {
|
|
534
926
|
message.value = msg;
|
|
@@ -538,36 +930,36 @@ function showMessage(msg: string, color: string) {
|
|
|
538
930
|
|
|
539
931
|
const { addFile, deleteFile: _deleteFile } = useFile();
|
|
540
932
|
|
|
541
|
-
const API_DO_STORAGE_ENDPOINT =
|
|
542
|
-
|
|
933
|
+
// const API_DO_STORAGE_ENDPOINT =
|
|
934
|
+
// useRuntimeConfig().public.API_DO_STORAGE_ENDPOINT;
|
|
543
935
|
|
|
544
|
-
async function handleFileAdded(file: File) {
|
|
545
|
-
|
|
546
|
-
|
|
936
|
+
// async function handleFileAdded(file: File) {
|
|
937
|
+
// try {
|
|
938
|
+
// const res = await addFile(file);
|
|
547
939
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
940
|
+
// const uploadedId = res?.id;
|
|
941
|
+
// if (uploadedId) {
|
|
942
|
+
// const url = `${uploadedId}`;
|
|
943
|
+
// _feedback.value.attachments = _feedback.value.attachments ?? [];
|
|
944
|
+
// _feedback.value.attachments.push(url);
|
|
945
|
+
// }
|
|
946
|
+
// } catch (error) {
|
|
947
|
+
// console.error("Error uploading file:", error);
|
|
948
|
+
// showMessage("Failed to upload file", "error");
|
|
949
|
+
// }
|
|
950
|
+
// }
|
|
559
951
|
|
|
560
|
-
async function deleteFile(value: string) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
}
|
|
952
|
+
// async function deleteFile(value: string) {
|
|
953
|
+
// try {
|
|
954
|
+
// await _deleteFile(value);
|
|
955
|
+
// _feedback.value.attachments = (_feedback.value.attachments ?? []).filter(
|
|
956
|
+
// (file) => file !== value
|
|
957
|
+
// );
|
|
958
|
+
// } catch (error) {
|
|
959
|
+
// console.log(error);
|
|
960
|
+
// showMessage("Failed to delete file", "error");
|
|
961
|
+
// }
|
|
962
|
+
// }
|
|
571
963
|
|
|
572
964
|
const { serviceProviderCategories, getServiceProviderCategories } =
|
|
573
965
|
useServiceProvider();
|
|
@@ -587,12 +979,223 @@ function tableRowClickHandler(_: any, data: any) {
|
|
|
587
979
|
|
|
588
980
|
getServiceProviderCategories();
|
|
589
981
|
|
|
590
|
-
|
|
982
|
+
onMounted(() => {
|
|
983
|
+
_feedback.value.description = "";
|
|
984
|
+
_feedback.value.location = "";
|
|
985
|
+
_feedback.value.subject = "";
|
|
986
|
+
_feedback.value.attachments = [];
|
|
987
|
+
});
|
|
591
988
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
989
|
+
const acceptDialog = ref(false);
|
|
990
|
+
const feedbackData = ref();
|
|
991
|
+
|
|
992
|
+
function canAccept(feedBack: any) {
|
|
993
|
+
return (
|
|
994
|
+
feedBack.provider === currentUser.value?.serviceProvider ||
|
|
995
|
+
(feedBack.subject &&
|
|
996
|
+
feedBack.subject.toLowerCase().includes("security") &&
|
|
997
|
+
!feedBack.provider)
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
async function accept(feedBack: any) {
|
|
1001
|
+
acceptDialog.value = true;
|
|
1002
|
+
feedbackData.value = feedBack;
|
|
1003
|
+
}
|
|
1004
|
+
async function handleAccept() {
|
|
1005
|
+
if (
|
|
1006
|
+
feedbackData.value.provider === currentUser.value?.serviceProvider ||
|
|
1007
|
+
(feedbackData.value.subject &&
|
|
1008
|
+
feedbackData.value.subject.toLowerCase().includes("security") &&
|
|
1009
|
+
!feedbackData.value.provider)
|
|
1010
|
+
) {
|
|
1011
|
+
try {
|
|
1012
|
+
const data: any = {
|
|
1013
|
+
_id: feedbackData.value._id,
|
|
1014
|
+
statusUpdate: {
|
|
1015
|
+
status: "In-Progress",
|
|
1016
|
+
updatedById: currentUser.value._id,
|
|
1017
|
+
updatedByName: `${currentUser.value.givenName} ${currentUser.value.surname}`,
|
|
1018
|
+
assignee: currentUser.value._id,
|
|
1019
|
+
provider: currentUser.value?.serviceProvider,
|
|
1020
|
+
},
|
|
1021
|
+
};
|
|
1022
|
+
|
|
1023
|
+
// await updateStatusFeedback(data);
|
|
1024
|
+
|
|
1025
|
+
acceptDialog.value = false;
|
|
1026
|
+
// changePath(feedbackData.value);
|
|
1027
|
+
} catch (error) {
|
|
1028
|
+
showMessage(error as string, "error");
|
|
1029
|
+
}
|
|
1030
|
+
} else {
|
|
1031
|
+
return showMessage(
|
|
1032
|
+
"Only assigned Provider can accept this feedback.",
|
|
1033
|
+
"error"
|
|
1034
|
+
);
|
|
596
1035
|
}
|
|
597
|
-
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
const subjectOptions = computed(() => {
|
|
1039
|
+
return [
|
|
1040
|
+
{
|
|
1041
|
+
title: "Facilities",
|
|
1042
|
+
description:
|
|
1043
|
+
"Shared amenities like gym, pool, BBQ pits, and function rooms.",
|
|
1044
|
+
},
|
|
1045
|
+
{
|
|
1046
|
+
title: "Building Facade",
|
|
1047
|
+
description:
|
|
1048
|
+
"Exterior walls, paint, cladding, signage, and overall appearance.",
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
title: "Security",
|
|
1052
|
+
description:
|
|
1053
|
+
"Guard services, access control, patrols, and visitor management.",
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
title: "Cleaning",
|
|
1057
|
+
description:
|
|
1058
|
+
"Cleanliness of lobbies, corridors, lifts, bins, and common areas.",
|
|
1059
|
+
},
|
|
1060
|
+
{
|
|
1061
|
+
title: "Landscape",
|
|
1062
|
+
description: "Condition of plants, lawns, trees, and garden maintenance.",
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
title: "Pest Control",
|
|
1066
|
+
description:
|
|
1067
|
+
"Effectiveness of measures against insects, rodents, and pests.",
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
title: "Water Features",
|
|
1071
|
+
description:
|
|
1072
|
+
"Operation and cleanliness of fountains, ponds, and pools (non-swimming).",
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
title: "Car Park",
|
|
1076
|
+
description:
|
|
1077
|
+
"Parking availability, markings, lighting, and barrier systems.",
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
title: "Lift",
|
|
1081
|
+
description:
|
|
1082
|
+
"Lift reliability, speed, cleanliness, ventilation, and downtime.",
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
title: "Security Systems",
|
|
1086
|
+
description: "CCTV, intercoms, access cards, and gate/door sensors.",
|
|
1087
|
+
},
|
|
1088
|
+
{
|
|
1089
|
+
title: "Others",
|
|
1090
|
+
description:
|
|
1091
|
+
"Any issues or feedback not covered by the categories above.",
|
|
1092
|
+
},
|
|
1093
|
+
]
|
|
1094
|
+
.filter((item) => item.title !== "Others")
|
|
1095
|
+
.sort((a, b) => a.title.localeCompare(b.title))
|
|
1096
|
+
.concat({
|
|
1097
|
+
title: "Others",
|
|
1098
|
+
description:
|
|
1099
|
+
"Any issues or feedback not covered by the categories above.",
|
|
1100
|
+
});
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
const isFileUploading = ref<boolean>(false);
|
|
1104
|
+
type TFile = {
|
|
1105
|
+
name: string;
|
|
1106
|
+
data: File;
|
|
1107
|
+
progress: number;
|
|
1108
|
+
url?: string;
|
|
1109
|
+
type?: string;
|
|
1110
|
+
id?: string;
|
|
1111
|
+
};
|
|
1112
|
+
const attachedFiles = ref<TFile[]>([]);
|
|
1113
|
+
|
|
1114
|
+
const handleFileUpdate = async (
|
|
1115
|
+
files: Array<{ data: File; name: string; url: string }>
|
|
1116
|
+
) => {
|
|
1117
|
+
for (const file of files) {
|
|
1118
|
+
attachedFiles.value.push(file);
|
|
1119
|
+
}
|
|
1120
|
+
};
|
|
1121
|
+
|
|
1122
|
+
const onImageEdited = async (url: string, idx: number) => {
|
|
1123
|
+
const response = await getImage(url);
|
|
1124
|
+
if (!response) return;
|
|
1125
|
+
attachedFiles.value[idx].data = new File(
|
|
1126
|
+
[response],
|
|
1127
|
+
attachedFiles.value[idx].data?.name,
|
|
1128
|
+
{ type: attachedFiles.value[idx].data?.type }
|
|
1129
|
+
);
|
|
1130
|
+
attachedFiles.value[idx].url = url;
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
function removeFile(url: string) {
|
|
1134
|
+
const newFiles = attachedFiles.value.filter((item: any) => item.url !== url);
|
|
1135
|
+
|
|
1136
|
+
attachedFiles.value = [];
|
|
1137
|
+
nextTick(() => {
|
|
1138
|
+
attachedFiles.value = newFiles;
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
const attachWorkOrderDialog = ref(false);
|
|
1143
|
+
const attachWorkOrderForm = ref<any>({
|
|
1144
|
+
description: "",
|
|
1145
|
+
isHighPriority: false,
|
|
1146
|
+
attachWorkOrder: false,
|
|
1147
|
+
});
|
|
1148
|
+
|
|
1149
|
+
const attachWorkOrder = () => {
|
|
1150
|
+
attachWorkOrderForm.value.attachWorkOrder =
|
|
1151
|
+
!attachWorkOrderForm.value.attachWorkOrder;
|
|
1152
|
+
attachWorkOrderDialog.value = false;
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
const isSubmitting = ref<boolean>(false);
|
|
1156
|
+
|
|
1157
|
+
async function submit() {
|
|
1158
|
+
if (attachedFiles.value && attachedFiles.value?.length) {
|
|
1159
|
+
isFileUploading.value = true;
|
|
1160
|
+
for (const file of attachedFiles.value) {
|
|
1161
|
+
const res = await addFile(file.data);
|
|
1162
|
+
|
|
1163
|
+
const uploadedId = res?.id;
|
|
1164
|
+
if (uploadedId) {
|
|
1165
|
+
_feedback.value.attachments = _feedback.value.attachments ?? [];
|
|
1166
|
+
_feedback.value.attachments.push(uploadedId);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
isFileUploading.value = false;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
try {
|
|
1173
|
+
isSubmitting.value = true;
|
|
1174
|
+
|
|
1175
|
+
const result = await createFeedback({
|
|
1176
|
+
createdBy: currentUser.value._id,
|
|
1177
|
+
description: _feedback.value.description,
|
|
1178
|
+
attachments: _feedback.value.attachments,
|
|
1179
|
+
site: route.params.site as string,
|
|
1180
|
+
organization: route.params.org as string,
|
|
1181
|
+
subject: _feedback.value.subject?.title || _feedback.value.subject,
|
|
1182
|
+
location: _feedback.value.location,
|
|
1183
|
+
app: "MA",
|
|
1184
|
+
...(attachWorkOrderForm.value.attachWorkOrder && {
|
|
1185
|
+
provider: _feedback.value.serviceProvider,
|
|
1186
|
+
workOrder: {
|
|
1187
|
+
isHighPriority: attachWorkOrderForm.value.isHighPriority,
|
|
1188
|
+
description: attachWorkOrderForm.value.description,
|
|
1189
|
+
},
|
|
1190
|
+
}),
|
|
1191
|
+
});
|
|
1192
|
+
handleCloseDialog();
|
|
1193
|
+
await refreshFeedbacks();
|
|
1194
|
+
showMessage(result.message as string, "success");
|
|
1195
|
+
} catch (error) {
|
|
1196
|
+
showMessage(error as string, "error");
|
|
1197
|
+
} finally {
|
|
1198
|
+
isSubmitting.value = false;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
598
1201
|
</script>
|