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