@iservice365/layer-common 1.0.10 → 1.1.0
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/Avatar/Main.vue +68 -0
- package/components/Chat/Information.vue +252 -68
- package/components/Chat/Message.vue +10 -1
- package/components/FeedbackDetail.vue +30 -11
- package/components/FeedbackMain.vue +20 -3
- package/components/Input/DateTimePicker.vue +69 -14
- package/components/Input/File.vue +29 -4
- package/components/Input/FileV2.vue +121 -0
- package/components/InvitationForm.vue +5 -5
- package/components/Layout/Header.vue +22 -66
- package/components/Layout/NavigationDrawer.vue +1 -0
- package/components/NavigationItem.vue +15 -6
- package/components/TableMain.vue +15 -3
- package/components/WorkOrder/Create.vue +22 -1
- package/components/WorkOrder/Detail.vue +71 -0
- package/components/WorkOrder/Main.vue +62 -3
- package/composables/useCustomerSite.ts +21 -1
- package/composables/useFeedback.ts +2 -0
- package/composables/useFile.ts +12 -1
- package/composables/useUtils.ts +20 -0
- package/composables/useWorkOrder.ts +10 -1
- package/middleware/02.org.ts +3 -0
- package/package.json +1 -1
- package/plugins/secure-member.client.ts +20 -6
- package/plugins/vuetify.ts +5 -0
- package/types/feedback.d.ts +3 -0
- package/types/work-order.d.ts +2 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="feedback-detail-wrapper">
|
|
3
|
+
<v-row no-gutters class="fill-height">
|
|
4
|
+
<v-col cols="12" xl="7" lg="7" md="7" class="fill-height">
|
|
5
|
+
<div class="panel-container border-e">
|
|
6
|
+
<ChatMessage :type="'workOrder'" />
|
|
7
|
+
</div>
|
|
8
|
+
</v-col>
|
|
9
|
+
<v-col cols="12" xl="5" lg="5" md="5" class="fill-height">
|
|
10
|
+
<div class="panel-container">
|
|
11
|
+
<ChatInformation
|
|
12
|
+
:item="workOrder"
|
|
13
|
+
:service-providers="_serviceProviders"
|
|
14
|
+
:type="'workOrder'"
|
|
15
|
+
@edit="openEditDialog"
|
|
16
|
+
@mark-complete-request="showCompleteDialog = true"
|
|
17
|
+
@delete="showDeleteDialog = true"
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
</v-col>
|
|
21
|
+
</v-row>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
<script lang="ts" setup>
|
|
25
|
+
const route = useRoute();
|
|
26
|
+
const id = route.params.id;
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
workOrder,
|
|
30
|
+
workOrders,
|
|
31
|
+
getWorkOrderById,
|
|
32
|
+
getWorkOrders: _getWorkOrders,
|
|
33
|
+
} = useWorkOrder();
|
|
34
|
+
|
|
35
|
+
const { getServiceProviderNames } = useServiceProvider();
|
|
36
|
+
|
|
37
|
+
const _getWorkOrderById = async () => {
|
|
38
|
+
try {
|
|
39
|
+
const data = await getWorkOrderById(id as string);
|
|
40
|
+
workOrder.value = data;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error("Error fetching feedback:", error);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
_getWorkOrderById();
|
|
47
|
+
|
|
48
|
+
const _serviceProviders = ref<TServiceProviderName[]>([]);
|
|
49
|
+
|
|
50
|
+
const _getServiceProviderNames = async () => {
|
|
51
|
+
try {
|
|
52
|
+
const response = await getServiceProviderNames();
|
|
53
|
+
if (!response) return;
|
|
54
|
+
|
|
55
|
+
_serviceProviders.value = response.items.map((provider) => ({
|
|
56
|
+
_id: provider._id as string,
|
|
57
|
+
name: provider.name,
|
|
58
|
+
}));
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("Error fetching service providers:", error);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
_getServiceProviderNames();
|
|
65
|
+
|
|
66
|
+
const showCreateDialog = ref(false);
|
|
67
|
+
const showCompleteDialog = ref(false);
|
|
68
|
+
const showDeleteDialog = ref(false);
|
|
69
|
+
|
|
70
|
+
function openEditDialog() {}
|
|
71
|
+
</script>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-row align="start" justify="center" class="fill-height">
|
|
3
|
-
<v-col cols="12" lg="
|
|
3
|
+
<v-col cols="12" lg="12" md="12">
|
|
4
4
|
<ListView
|
|
5
5
|
:headers="headers"
|
|
6
6
|
:items="items"
|
|
7
7
|
:pages="pages"
|
|
8
8
|
:page-range="pageRange"
|
|
9
|
-
:loading="loading"
|
|
9
|
+
:loading="loading || onNextPrevPageLoading"
|
|
10
10
|
:height="'calc(100vh - 175px)'"
|
|
11
11
|
v-model:page="page"
|
|
12
12
|
:selected="selected"
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
@update:selected="onSelectedUpdate"
|
|
15
15
|
@click:create="showCreateDialog = true"
|
|
16
16
|
:length="pages"
|
|
17
|
+
:clickable-rows="true"
|
|
18
|
+
@update:pagination="updatePage"
|
|
17
19
|
>
|
|
18
20
|
<template #title>
|
|
19
21
|
<span class="text-h6 font-weight-regular">Work Orders</span>
|
|
@@ -47,12 +49,34 @@
|
|
|
47
49
|
{{ item.status || "No Status" }}
|
|
48
50
|
</v-chip>
|
|
49
51
|
</template>
|
|
52
|
+
<template #action-table="{ item }">
|
|
53
|
+
<v-menu
|
|
54
|
+
v-model="item.menuOpen"
|
|
55
|
+
:close-on-content-click="false"
|
|
56
|
+
offset-y
|
|
57
|
+
width="150"
|
|
58
|
+
>
|
|
59
|
+
<template v-slot:activator="{ props }">
|
|
60
|
+
<v-icon v-bind="props">mdi-dots-horizontal-circle-outline</v-icon>
|
|
61
|
+
</template>
|
|
62
|
+
<v-list>
|
|
63
|
+
<v-list-item @click="onViewWorkOrder(item)">View</v-list-item>
|
|
64
|
+
<v-list-item @click="editWorkOrder(item)">Edit</v-list-item>
|
|
65
|
+
<v-list-item
|
|
66
|
+
@click="confirmDeleteWorkOrder(item)"
|
|
67
|
+
v-if="canDeleteWorkOrder"
|
|
68
|
+
>Delete</v-list-item
|
|
69
|
+
>
|
|
70
|
+
</v-list>
|
|
71
|
+
</v-menu>
|
|
72
|
+
</template>
|
|
50
73
|
</ListView>
|
|
51
74
|
</v-col>
|
|
52
75
|
</v-row>
|
|
53
76
|
|
|
54
77
|
<WorkOrderCreate
|
|
55
78
|
v-model="showCreateDialog"
|
|
79
|
+
:created-from="'workOrder'"
|
|
56
80
|
:work-order="_workOrder"
|
|
57
81
|
@update:work-order="(val: TWorkOrderCreate) => (_workOrder = val)"
|
|
58
82
|
:is-edit-mode="isEditMode"
|
|
@@ -75,7 +99,7 @@
|
|
|
75
99
|
import { useTheme } from "vuetify";
|
|
76
100
|
const emit = defineEmits(["click:create", "update:pagination"]);
|
|
77
101
|
|
|
78
|
-
defineProps({
|
|
102
|
+
const props = defineProps({
|
|
79
103
|
detailRoute: {
|
|
80
104
|
type: String,
|
|
81
105
|
default: "index",
|
|
@@ -149,6 +173,7 @@ const headers = [
|
|
|
149
173
|
{ title: "Category", value: "category", align: "start" },
|
|
150
174
|
{ title: "Date", value: "createdAt", align: "start" },
|
|
151
175
|
{ title: "Status", value: "status", align: "start" },
|
|
176
|
+
{ title: "", value: "action-table", align: "end" },
|
|
152
177
|
];
|
|
153
178
|
|
|
154
179
|
const submitting = ref(false);
|
|
@@ -176,6 +201,7 @@ const {
|
|
|
176
201
|
);
|
|
177
202
|
|
|
178
203
|
const loading = computed(() => getAllReqStatus.value === "pending");
|
|
204
|
+
const onNextPrevPageLoading = ref(false);
|
|
179
205
|
|
|
180
206
|
watchEffect(() => {
|
|
181
207
|
if (getAllWorkOrderReq.value) {
|
|
@@ -184,6 +210,23 @@ watchEffect(() => {
|
|
|
184
210
|
pageRange.value = getAllWorkOrderReq.value.pageRange;
|
|
185
211
|
}
|
|
186
212
|
});
|
|
213
|
+
|
|
214
|
+
async function updatePage(pageVal: any) {
|
|
215
|
+
onNextPrevPageLoading.value = true;
|
|
216
|
+
page.value = pageVal;
|
|
217
|
+
const response = await _getWorkOrders({
|
|
218
|
+
page: page.value,
|
|
219
|
+
organization: route.params.org as string,
|
|
220
|
+
site: route.params.site as string,
|
|
221
|
+
});
|
|
222
|
+
if (response) {
|
|
223
|
+
items.value = response.items;
|
|
224
|
+
pages.value = response.pages;
|
|
225
|
+
pageRange.value = response.pageRange;
|
|
226
|
+
onNextPrevPageLoading.value = false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
187
230
|
function onSelectedUpdate(newSelected: string[]) {
|
|
188
231
|
selected.value = newSelected;
|
|
189
232
|
}
|
|
@@ -305,4 +348,20 @@ async function submitWorkOrder() {
|
|
|
305
348
|
isSubmitting.value = false;
|
|
306
349
|
}
|
|
307
350
|
}
|
|
351
|
+
|
|
352
|
+
function onViewWorkOrder(item: any) {
|
|
353
|
+
const route = useRoute();
|
|
354
|
+
const org = route.params.org;
|
|
355
|
+
const customer = route.params.customer;
|
|
356
|
+
const site = route.params.site;
|
|
357
|
+
const id = item._id;
|
|
358
|
+
useRouter().push({
|
|
359
|
+
name: props.detailRoute,
|
|
360
|
+
params: { org, site, id },
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function editWorkOrder(item: any) {}
|
|
365
|
+
|
|
366
|
+
function confirmDeleteWorkOrder(item: any) {}
|
|
308
367
|
</script>
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
export default function useCustomerSite() {
|
|
2
2
|
function add(payload: TCustomerSite) {
|
|
3
|
-
return useNuxtApp().$api<Record<string, any>>(
|
|
3
|
+
return useNuxtApp().$api<Record<string, any>>("/api/customer-sites", {
|
|
4
4
|
method: "POST",
|
|
5
5
|
body: payload,
|
|
6
6
|
});
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
function addViaInvite(invite: string) {
|
|
10
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
11
|
+
`/api/customer-sites/invite/${invite}`,
|
|
12
|
+
{
|
|
13
|
+
method: "POST",
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
async function getAll({
|
|
10
19
|
page = 1,
|
|
11
20
|
search = "",
|
|
@@ -29,8 +38,19 @@ export default function useCustomerSite() {
|
|
|
29
38
|
});
|
|
30
39
|
}
|
|
31
40
|
|
|
41
|
+
function getBySiteAsServiceProvider(site: string) {
|
|
42
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
43
|
+
`/api/customer-sites/service-provider/${site}`,
|
|
44
|
+
{
|
|
45
|
+
method: "GET",
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
32
50
|
return {
|
|
33
51
|
add,
|
|
34
52
|
getAll,
|
|
53
|
+
addViaInvite,
|
|
54
|
+
getBySiteAsServiceProvider,
|
|
35
55
|
};
|
|
36
56
|
}
|
|
@@ -10,6 +10,7 @@ export default function useFeedback() {
|
|
|
10
10
|
_id: "",
|
|
11
11
|
attachments: [],
|
|
12
12
|
category: "",
|
|
13
|
+
categoryInfo: "",
|
|
13
14
|
subject: "",
|
|
14
15
|
location: "",
|
|
15
16
|
description: "",
|
|
@@ -27,6 +28,7 @@ export default function useFeedback() {
|
|
|
27
28
|
attachments: "",
|
|
28
29
|
completedAt: "",
|
|
29
30
|
},
|
|
31
|
+
workOrderNo: "",
|
|
30
32
|
})
|
|
31
33
|
);
|
|
32
34
|
|
package/composables/useFile.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export default function useFile() {
|
|
2
2
|
const baseUrl =
|
|
3
|
-
"https://
|
|
3
|
+
"https://iservice365-dev.sgp1.cdn.digitaloceanspaces.com/default";
|
|
4
4
|
|
|
5
5
|
function addFile(file: File | null) {
|
|
6
6
|
if (!file) {
|
|
@@ -23,6 +23,16 @@ export default function useFile() {
|
|
|
23
23
|
return `${baseUrl}/${id}`;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
async function urlToFile(url: string, filename: string): Promise<File> {
|
|
27
|
+
const response = await fetch(url)
|
|
28
|
+
const blob = await response.blob()
|
|
29
|
+
|
|
30
|
+
// Try to extract MIME type if possible (e.g. image/png)
|
|
31
|
+
const mimeType = blob.type || 'image/jpeg'
|
|
32
|
+
|
|
33
|
+
return new File([blob], filename, { type: mimeType })
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
function deleteFile(attachmentId: string) {
|
|
27
37
|
return useNuxtApp().$api<Record<string, any>>(
|
|
28
38
|
`/api/files/${attachmentId}`,
|
|
@@ -35,6 +45,7 @@ export default function useFile() {
|
|
|
35
45
|
return {
|
|
36
46
|
addFile,
|
|
37
47
|
deleteFile,
|
|
48
|
+
urlToFile,
|
|
38
49
|
getFileUrl,
|
|
39
50
|
};
|
|
40
51
|
}
|
package/composables/useUtils.ts
CHANGED
|
@@ -256,6 +256,7 @@ export default function useUtils() {
|
|
|
256
256
|
|
|
257
257
|
const search = useState("search", () => "");
|
|
258
258
|
|
|
259
|
+
//returns Oct 16, 2025, 03:45 PM // N/A format
|
|
259
260
|
function formatDate(dateString: string) {
|
|
260
261
|
if (!dateString) return "N/A";
|
|
261
262
|
|
|
@@ -269,6 +270,23 @@ export default function useUtils() {
|
|
|
269
270
|
});
|
|
270
271
|
}
|
|
271
272
|
|
|
273
|
+
// returns 16/10/2025, 15:45 format
|
|
274
|
+
function UTCToLocalTIme(UTCDateTime: string) {
|
|
275
|
+
if (!UTCDateTime) return "";
|
|
276
|
+
const local = new Date(UTCDateTime);
|
|
277
|
+
|
|
278
|
+
const formatted = local.toLocaleString("en-GB", {
|
|
279
|
+
day: "2-digit",
|
|
280
|
+
month: "2-digit",
|
|
281
|
+
year: "numeric",
|
|
282
|
+
hour: "2-digit",
|
|
283
|
+
minute: "2-digit",
|
|
284
|
+
hour12: false, // 24-hour format
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
return formatted;
|
|
288
|
+
}
|
|
289
|
+
|
|
272
290
|
function formatNature(value: string): string {
|
|
273
291
|
if (!value) return "";
|
|
274
292
|
return value
|
|
@@ -341,6 +359,7 @@ export default function useUtils() {
|
|
|
341
359
|
}
|
|
342
360
|
|
|
343
361
|
function formatCamelCaseToWords(key: string){
|
|
362
|
+
if(!key) return "";
|
|
344
363
|
return key
|
|
345
364
|
.replace(/([A-Z])/g, ' $1')
|
|
346
365
|
.replace(/^./, str => str.toUpperCase());
|
|
@@ -372,6 +391,7 @@ export default function useUtils() {
|
|
|
372
391
|
getOrigin,
|
|
373
392
|
search,
|
|
374
393
|
formatDate,
|
|
394
|
+
UTCToLocalTIme,
|
|
375
395
|
formatNature,
|
|
376
396
|
replaceMatch,
|
|
377
397
|
setRouteParams,
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
export default function
|
|
1
|
+
export default function useWorkOrder() {
|
|
2
2
|
const workOrders = useState<Array<TWorkOrder>>("workOrders", () => []);
|
|
3
3
|
const page = useState("page", () => 1);
|
|
4
4
|
const pages = useState("pages", () => 0);
|
|
5
5
|
const pageRange = useState("pageRange", () => "-- - -- of --");
|
|
6
6
|
const workOrder = useState<TWorkOrder>("workOrder", () => ({
|
|
7
7
|
_id: "",
|
|
8
|
+
category: "",
|
|
9
|
+
categoryInfo: "",
|
|
8
10
|
subject: "",
|
|
9
11
|
description: "",
|
|
10
12
|
createdBy: "",
|
|
@@ -49,6 +51,12 @@ export default function useFeedback() {
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
function getWorkOrderById(id: string) {
|
|
55
|
+
return useNuxtApp().$api<TWorkOrder>(`/api/work-orders/${id}`, {
|
|
56
|
+
method: "GET",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
function createWorkOrder(payload: TWorkOrderCreate) {
|
|
53
61
|
return useNuxtApp().$api<Record<string, any>>("/api/work-orders", {
|
|
54
62
|
method: "POST",
|
|
@@ -64,5 +72,6 @@ export default function useFeedback() {
|
|
|
64
72
|
pageRange,
|
|
65
73
|
createWorkOrder,
|
|
66
74
|
getWorkOrders,
|
|
75
|
+
getWorkOrderById,
|
|
67
76
|
};
|
|
68
77
|
}
|
package/middleware/02.org.ts
CHANGED
|
@@ -9,7 +9,10 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
|
|
|
9
9
|
|
|
10
10
|
const { organization, org } = to.params;
|
|
11
11
|
|
|
12
|
+
// console.log('org-aut-middleware running', hexSchema.safeParse(organization).success)
|
|
13
|
+
|
|
12
14
|
if (!hexSchema.safeParse(organization || org).success) {
|
|
15
|
+
console.log('[02.org] middleware run')
|
|
13
16
|
return navigateTo(
|
|
14
17
|
{ name: "require-organization-membership" },
|
|
15
18
|
{ replace: true }
|
package/package.json
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
const hexSchema = z
|
|
4
|
+
.string()
|
|
5
|
+
.regex(/^[0-9a-fA-F]{24}$/, "Invalid organization ID");
|
|
6
|
+
|
|
1
7
|
export default defineNuxtPlugin(() => {
|
|
2
8
|
const router = useRouter();
|
|
3
9
|
const { getByUserType } = useMember();
|
|
@@ -17,17 +23,24 @@ export default defineNuxtPlugin(() => {
|
|
|
17
23
|
(to.params.org as string) || (to.params.organization as string) || ""
|
|
18
24
|
);
|
|
19
25
|
|
|
26
|
+
console.log('[secure-member-plugin', 'org', org.value)
|
|
27
|
+
|
|
28
|
+
if (!hexSchema.safeParse(org.value).success) {
|
|
29
|
+
return router.replace({ name: "require-organization-membership" });
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
const userId = computed(() => useCookie("user").value ?? "");
|
|
21
33
|
|
|
22
34
|
const { data: userMemberData, error: userMemberError } =
|
|
23
35
|
await useLazyAsyncData(
|
|
24
|
-
"get-member-by-id",
|
|
36
|
+
"plugin-get-member-by-id-" + userId.value + "-" + APP + "-" + org.value,
|
|
25
37
|
() => getByUserType(userId.value, APP, org.value),
|
|
26
38
|
{ watch: [userId] }
|
|
27
39
|
);
|
|
28
40
|
|
|
29
41
|
watchEffect(() => {
|
|
30
42
|
if (userMemberError.value) {
|
|
43
|
+
console.log('running-secure-member-redirect-plugin')
|
|
31
44
|
navigateTo(
|
|
32
45
|
{
|
|
33
46
|
name: "index",
|
|
@@ -37,14 +50,17 @@ export default defineNuxtPlugin(() => {
|
|
|
37
50
|
}
|
|
38
51
|
});
|
|
39
52
|
|
|
53
|
+
const roleId = ref("roleId");
|
|
54
|
+
|
|
40
55
|
watchEffect(() => {
|
|
41
56
|
if (userMemberData.value) {
|
|
42
57
|
id.value = userMemberData.value.org ?? "";
|
|
58
|
+
roleId.value = userMemberData.value.role ?? "roleId";
|
|
43
59
|
}
|
|
44
60
|
});
|
|
45
61
|
|
|
46
62
|
const { data: getOrgByIdReq } = await useLazyAsyncData(
|
|
47
|
-
"get-org-by-id",
|
|
63
|
+
"plugin-get-org-by-id-" + org.value,
|
|
48
64
|
() => getById(org.value),
|
|
49
65
|
{ watch: [org] }
|
|
50
66
|
);
|
|
@@ -55,12 +71,10 @@ export default defineNuxtPlugin(() => {
|
|
|
55
71
|
}
|
|
56
72
|
});
|
|
57
73
|
|
|
58
|
-
const roleId = computed(() => userMemberData.value?.role ?? "");
|
|
59
|
-
|
|
60
74
|
const { data: getRoleByIdReq } = await useLazyAsyncData(
|
|
61
|
-
"get-role-by-id",
|
|
75
|
+
"plugin-get-role-by-id-" + roleId.value,
|
|
62
76
|
() => getRoleById(roleId.value),
|
|
63
|
-
{ watch: [roleId]
|
|
77
|
+
{ watch: [roleId] }
|
|
64
78
|
);
|
|
65
79
|
|
|
66
80
|
watchEffect(() => {
|
package/plugins/vuetify.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// import this after install `@mdi/font` package
|
|
2
2
|
import "@mdi/font/css/materialdesignicons.css";
|
|
3
|
+
import { VFileUpload, VFileUploadItem } from 'vuetify/labs/VFileUpload'
|
|
3
4
|
|
|
4
5
|
import "vuetify/styles";
|
|
5
6
|
import { createVuetify } from "vuetify";
|
|
@@ -46,6 +47,10 @@ export default defineNuxtPlugin((app) => {
|
|
|
46
47
|
},
|
|
47
48
|
},
|
|
48
49
|
},
|
|
50
|
+
components: {
|
|
51
|
+
VFileUpload,
|
|
52
|
+
VFileUploadItem
|
|
53
|
+
}
|
|
49
54
|
});
|
|
50
55
|
|
|
51
56
|
app.vueApp.use(vuetify);
|
package/types/feedback.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ declare type TFeedback = {
|
|
|
2
2
|
_id: string;
|
|
3
3
|
attachments?: string[];
|
|
4
4
|
category: string;
|
|
5
|
+
categoryInfo?: string;
|
|
5
6
|
subject: string;
|
|
6
7
|
location: string;
|
|
7
8
|
description: string;
|
|
@@ -19,6 +20,8 @@ declare type TFeedback = {
|
|
|
19
20
|
serviceProvider?: string;
|
|
20
21
|
assignee?: string;
|
|
21
22
|
createdBy?: string;
|
|
23
|
+
workOrderNo?: string;
|
|
24
|
+
workOrderId?: string;
|
|
22
25
|
};
|
|
23
26
|
|
|
24
27
|
declare type TFeedbackMetadata = {
|