@7365admin1/layer-common 1.8.5 → 1.9.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/AccessCardAddForm.vue +235 -27
- package/components/BuildingManagement/buildings.vue +6 -1
- package/components/BuildingManagement/units.vue +7 -1
- package/components/BuildingUnitFormAdd.vue +13 -11
- package/components/Button/Close.vue +16 -0
- package/components/CameraMain.vue +9 -4
- package/components/Dialog/UpdateMoreAction.vue +6 -1
- package/components/FeedbackDetail.vue +21 -10
- package/components/FeedbackMain.vue +16 -6
- package/components/Input/DatePicker.vue +102 -0
- package/components/NumberSettingField.vue +3 -2
- package/components/VisitorForm.vue +3 -1
- package/components/VisitorManagement.vue +6 -1
- package/components/WorkOrder/Detail.vue +179 -2
- package/components/WorkOrder/Main.vue +89 -7
- package/composables/useBuildingUnit.ts +1 -1
- package/composables/useFeedback.ts +3 -2
- package/composables/useNFCPatrolSettings.ts +1 -1
- package/composables/useWorkOrder.ts +8 -0
- package/package.json +1 -1
- package/types/card.d.ts +5 -0
- /package/components/{NFC/PatrolSettings.vue → Nfc/NFCPatrolSettings.vue} +0 -0
|
@@ -310,7 +310,7 @@ const _feedback = ref({
|
|
|
310
310
|
|
|
311
311
|
const selected = ref<string[]>([]);
|
|
312
312
|
|
|
313
|
-
const { getColorStatus } = useUtils();
|
|
313
|
+
const { getColorStatus, debounce } = useUtils();
|
|
314
314
|
|
|
315
315
|
const headers: Array<Record<string, any>> = [
|
|
316
316
|
{ title: "Name", value: "createdByName", align: "start" },
|
|
@@ -325,6 +325,10 @@ const erroredImages = ref<string[]>([]);
|
|
|
325
325
|
const route = useRoute();
|
|
326
326
|
const { customers } = useCustomer();
|
|
327
327
|
|
|
328
|
+
const dialogPreview = ref(false);
|
|
329
|
+
const selectedFeedback = ref<TFeedback | null>(null);
|
|
330
|
+
const searchText = ref("");
|
|
331
|
+
|
|
328
332
|
const {
|
|
329
333
|
getFeedbacks: _getFeedbacks,
|
|
330
334
|
deleteFeedback,
|
|
@@ -347,6 +351,7 @@ const {
|
|
|
347
351
|
page: page.value,
|
|
348
352
|
site: route.params.site as string,
|
|
349
353
|
category: props.category,
|
|
354
|
+
search: searchText.value || "",
|
|
350
355
|
})
|
|
351
356
|
);
|
|
352
357
|
|
|
@@ -575,14 +580,19 @@ const categories = computed(() =>
|
|
|
575
580
|
);
|
|
576
581
|
|
|
577
582
|
function tableRowClickHandler(_: any, data: any) {
|
|
578
|
-
console.log(data.item);
|
|
583
|
+
// console.log(data.item);
|
|
579
584
|
selectedFeedback.value = data.item;
|
|
580
585
|
dialogPreview.value = true;
|
|
581
586
|
}
|
|
582
587
|
|
|
583
|
-
const dialogPreview = ref(false);
|
|
584
|
-
const selectedFeedback = ref<TFeedback | null>(null);
|
|
585
|
-
const searchText = ref("");
|
|
586
|
-
|
|
587
588
|
getServiceProviderCategories();
|
|
589
|
+
|
|
590
|
+
const debounceSearch = debounce(getAllReqRefresh, 500);
|
|
591
|
+
|
|
592
|
+
watch(
|
|
593
|
+
() => searchText.value,
|
|
594
|
+
() => {
|
|
595
|
+
debounceSearch();
|
|
596
|
+
}
|
|
597
|
+
);
|
|
588
598
|
</script>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="d-flex flex-column">
|
|
3
|
+
<v-text-field v-bind="$attrs" ref="datePickerRef" :model-value="dateFormattedReadOnly" autocomplete="off"
|
|
4
|
+
:placeholder="placeholder" :rules="rules" style="z-index: 10" @click="openDatePicker">
|
|
5
|
+
<template #append-inner>
|
|
6
|
+
<v-icon icon="mdi-calendar" @click.stop="openDatePicker" />
|
|
7
|
+
</template>
|
|
8
|
+
</v-text-field>
|
|
9
|
+
<div class="w-100 d-flex align-end ga-3 hidden-input">
|
|
10
|
+
<input ref="dateInput" type="date" v-model="date" />
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
|
|
17
|
+
const prop = defineProps({
|
|
18
|
+
rules: {
|
|
19
|
+
type: Array as PropType<Array<any>>,
|
|
20
|
+
default: () => []
|
|
21
|
+
},
|
|
22
|
+
placeholder: {
|
|
23
|
+
type: String,
|
|
24
|
+
default: 'MM/DD/YYYY'
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const date = defineModel<string | null>({ default: null }) // YYYY-MM-DD format
|
|
29
|
+
|
|
30
|
+
const dateFormattedReadOnly = ref<string | null>(null)
|
|
31
|
+
|
|
32
|
+
const dateInput = ref<HTMLInputElement | null>(null)
|
|
33
|
+
const datePickerRef = ref<HTMLInputElement | null>(null)
|
|
34
|
+
|
|
35
|
+
const isInitialLoad = ref(true)
|
|
36
|
+
|
|
37
|
+
function openDatePicker() {
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
dateInput.value?.showPicker?.()
|
|
40
|
+
}, 0)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function validate() {
|
|
44
|
+
(datePickerRef.value as any)?.validate()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function convertToReadableFormat(dateStr: string): string {
|
|
48
|
+
if (!dateStr) return ""
|
|
49
|
+
const dateObj = new Date(dateStr + "T00:00:00")
|
|
50
|
+
const options: Intl.DateTimeFormatOptions = {
|
|
51
|
+
year: 'numeric',
|
|
52
|
+
month: '2-digit',
|
|
53
|
+
day: '2-digit'
|
|
54
|
+
}
|
|
55
|
+
return dateObj.toLocaleDateString('en-US', options)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function handleInitialDate() {
|
|
59
|
+
if (date.value) {
|
|
60
|
+
dateFormattedReadOnly.value = convertToReadableFormat(date.value)
|
|
61
|
+
} else {
|
|
62
|
+
dateFormattedReadOnly.value = null
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
watch(date, (dateVal) => {
|
|
67
|
+
if (isInitialLoad.value) return
|
|
68
|
+
if (!dateVal) {
|
|
69
|
+
dateFormattedReadOnly.value = null
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
dateFormattedReadOnly.value = convertToReadableFormat(dateVal)
|
|
73
|
+
}, { immediate: false })
|
|
74
|
+
|
|
75
|
+
watch(date, () => {
|
|
76
|
+
handleInitialDate()
|
|
77
|
+
}, { immediate: true })
|
|
78
|
+
|
|
79
|
+
onMounted(async () => {
|
|
80
|
+
await nextTick()
|
|
81
|
+
isInitialLoad.value = false
|
|
82
|
+
const nativeInput = (datePickerRef.value as any)?.$el?.querySelector('input')
|
|
83
|
+
if (nativeInput) {
|
|
84
|
+
nativeInput.addEventListener('click', (e: MouseEvent) => {
|
|
85
|
+
e.stopPropagation()
|
|
86
|
+
openDatePicker()
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
defineExpose({
|
|
92
|
+
validate
|
|
93
|
+
})
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<style scoped>
|
|
97
|
+
.hidden-input {
|
|
98
|
+
opacity: 0;
|
|
99
|
+
height: 0;
|
|
100
|
+
width: 1px;
|
|
101
|
+
}
|
|
102
|
+
</style>
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
<v-row>
|
|
5
5
|
<v-col cols="6">
|
|
6
6
|
<InputLabel class="text-capitalize font-weight-bold" :title="title" :required="required" />
|
|
7
|
-
<v-text-field v-model.number="count" type="number" density="comfortable" :rules="rules" />
|
|
7
|
+
<v-text-field v-model.number="count" type="number" density="comfortable" :rules="rules" :readonly="readOnly" />
|
|
8
8
|
</v-col>
|
|
9
9
|
|
|
10
10
|
<v-col cols="6">
|
|
11
|
-
<v-btn color="primary" class="text-none mt-6" size="large" variant="flat"
|
|
11
|
+
<v-btn v-if="!readOnly" color="primary" class="text-none mt-6" size="large" variant="flat"
|
|
12
12
|
:disabled="!valid || disabled" :loading="loading || updating" text="Save" @click="handleSave" />
|
|
13
13
|
</v-col>
|
|
14
14
|
</v-row>
|
|
@@ -34,6 +34,7 @@ const props = defineProps({
|
|
|
34
34
|
siteId: { type: String, required: true },
|
|
35
35
|
existingBlockNumber: { type: Number, default: 0 },
|
|
36
36
|
existingGuardPostsNumber: { type: Number, default: 0 },
|
|
37
|
+
readOnly: { type: Boolean, default: false },
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
const { updateSite, setSiteGuardPosts } = useSiteSettings()
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-card width="100%" :loading="processing">
|
|
3
3
|
<v-toolbar>
|
|
4
|
-
<v-row no-gutters class="fill-height px-6" align="center">
|
|
4
|
+
<v-row no-gutters class="fill-height px-6 d-flex justify-space-between align-center" align="center">
|
|
5
5
|
<span class="font-weight-bold text-h5 text-capitalize">
|
|
6
6
|
{{ prop.mode }} {{ formatVisitorType(type) }}
|
|
7
7
|
</span>
|
|
8
|
+
<ButtonClose @click="emit('close:all')" />
|
|
8
9
|
</v-row>
|
|
9
10
|
</v-toolbar>
|
|
10
11
|
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-5 my-3">
|
|
@@ -238,6 +239,7 @@ const emit = defineEmits([
|
|
|
238
239
|
"done:more",
|
|
239
240
|
"error",
|
|
240
241
|
"close",
|
|
242
|
+
"close:all"
|
|
241
243
|
]);
|
|
242
244
|
|
|
243
245
|
const visitor = reactive<Partial<TVisitorPayload>>({
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
|
|
115
115
|
<v-dialog v-model="dialog.addVisitor" v-if="activeVisitorFormType" width="450" persistent>
|
|
116
116
|
<VisitorForm mode="add" :org="orgId" :site="siteId" :type="activeVisitorFormType" @back="handleClickBack"
|
|
117
|
-
@done="handleVisitorFormDone" @done:more="handleVisitorFormCreateMore" />
|
|
117
|
+
@done="handleVisitorFormDone" @done:more="handleVisitorFormCreateMore" @close:all="handleCloseAll" />
|
|
118
118
|
</v-dialog>
|
|
119
119
|
|
|
120
120
|
<v-dialog v-model="dialog.viewVisitor" width="450" persistent>
|
|
@@ -385,6 +385,11 @@ function showMessage(msg: string, color: string) {
|
|
|
385
385
|
messageSnackbar.value = true;
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
function handleCloseAll() {
|
|
389
|
+
dialog.showSelection = false;
|
|
390
|
+
dialog.addVisitor = false;
|
|
391
|
+
}
|
|
392
|
+
|
|
388
393
|
function handleUpdateAutofillDetails(people: TPeople){
|
|
389
394
|
dialog.vehicleNumberUsersList = false
|
|
390
395
|
console.log('people', people)
|
|
@@ -20,19 +20,51 @@
|
|
|
20
20
|
</v-col>
|
|
21
21
|
</v-row>
|
|
22
22
|
</div>
|
|
23
|
+
<WorkOrderCreate
|
|
24
|
+
v-model="showCreateDialog"
|
|
25
|
+
created-from="workOrder"
|
|
26
|
+
:work-order="_workOrder"
|
|
27
|
+
@update:work-order="(val: TWorkOrderCreate) => (_workOrder = val)"
|
|
28
|
+
:is-edit-mode="isEditMode"
|
|
29
|
+
:loading="isSubmitting"
|
|
30
|
+
:categories="serviceProviders"
|
|
31
|
+
:theme="theme"
|
|
32
|
+
:errored-images="erroredImages"
|
|
33
|
+
:max-files="5"
|
|
34
|
+
:message-fn="showMessage"
|
|
35
|
+
@close="handleCloseDialog"
|
|
36
|
+
@file-added="handleFileAdded"
|
|
37
|
+
@file-deleted="deleteFile"
|
|
38
|
+
@submit="submitWorkOrder"
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
<Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
|
|
23
42
|
</template>
|
|
24
43
|
<script lang="ts" setup>
|
|
44
|
+
import { useTheme } from "vuetify";
|
|
25
45
|
const route = useRoute();
|
|
26
46
|
const id = route.params.id;
|
|
27
47
|
|
|
28
48
|
const {
|
|
29
49
|
workOrder,
|
|
30
|
-
workOrders,
|
|
31
50
|
getWorkOrderById,
|
|
32
51
|
getWorkOrders: _getWorkOrders,
|
|
52
|
+
updateWorkOrder,
|
|
53
|
+
createWorkOrder,
|
|
33
54
|
} = useWorkOrder();
|
|
34
55
|
|
|
35
56
|
const { getServiceProviderNames } = useServiceProvider();
|
|
57
|
+
const erroredImages = ref<string[]>([]);
|
|
58
|
+
|
|
59
|
+
const message = ref("");
|
|
60
|
+
const messageColor = ref("");
|
|
61
|
+
const messageSnackbar = ref(false);
|
|
62
|
+
|
|
63
|
+
function showMessage(msg: string, color: string) {
|
|
64
|
+
message.value = msg;
|
|
65
|
+
messageColor.value = color;
|
|
66
|
+
messageSnackbar.value = true;
|
|
67
|
+
}
|
|
36
68
|
|
|
37
69
|
const _getWorkOrderById = async () => {
|
|
38
70
|
try {
|
|
@@ -67,5 +99,150 @@ const showCreateDialog = ref(false);
|
|
|
67
99
|
const showCompleteDialog = ref(false);
|
|
68
100
|
const showDeleteDialog = ref(false);
|
|
69
101
|
|
|
70
|
-
|
|
102
|
+
const _workOrder = ref<TWorkOrderCreate>({
|
|
103
|
+
attachments: [],
|
|
104
|
+
category: "",
|
|
105
|
+
subject: "",
|
|
106
|
+
location: "",
|
|
107
|
+
description: "",
|
|
108
|
+
highPriority: false,
|
|
109
|
+
block: "",
|
|
110
|
+
level: "",
|
|
111
|
+
unit: "",
|
|
112
|
+
serviceProvider: "",
|
|
113
|
+
assignee: "",
|
|
114
|
+
organization: "",
|
|
115
|
+
site: "",
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const isEditMode = ref(false);
|
|
119
|
+
const isSubmitting = ref(false);
|
|
120
|
+
const theme = useTheme().name;
|
|
121
|
+
|
|
122
|
+
const _workOrderId = ref<string | null>(null);
|
|
123
|
+
|
|
124
|
+
const serviceProviders = ref<
|
|
125
|
+
Array<{ title: string; value: string; subtitle: string }>
|
|
126
|
+
>([]);
|
|
127
|
+
|
|
128
|
+
const { getBySiteAsServiceProvider } = useCustomerSite();
|
|
129
|
+
|
|
130
|
+
const { data: getAllReq } = useLazyAsyncData(
|
|
131
|
+
"get-by-site-as-service-provider",
|
|
132
|
+
() => getBySiteAsServiceProvider(useRoute().params.site as string)
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
watchEffect(() => {
|
|
136
|
+
if (getAllReq.value) {
|
|
137
|
+
serviceProviders.value = getAllReq.value.map((i: any) => ({
|
|
138
|
+
title: i.nature.replace(/_/g, " "),
|
|
139
|
+
subtitle: i.title,
|
|
140
|
+
value: i.nature,
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
function openEditDialog() {
|
|
146
|
+
isEditMode.value = true;
|
|
147
|
+
_workOrder.value = { ...workOrder.value };
|
|
148
|
+
showCreateDialog.value = true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function handleCloseDialog() {
|
|
152
|
+
resetWorkOrderForm();
|
|
153
|
+
isEditMode.value = false;
|
|
154
|
+
showCreateDialog.value = false;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function resetWorkOrderForm() {
|
|
158
|
+
_workOrder.value = {
|
|
159
|
+
attachments: [],
|
|
160
|
+
category: "",
|
|
161
|
+
subject: "",
|
|
162
|
+
location: "",
|
|
163
|
+
description: "",
|
|
164
|
+
highPriority: false,
|
|
165
|
+
block: "",
|
|
166
|
+
level: "",
|
|
167
|
+
unit: "",
|
|
168
|
+
serviceProvider: "",
|
|
169
|
+
assignee: "",
|
|
170
|
+
organization: "",
|
|
171
|
+
site: "",
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const { addFile, deleteFile: _deleteFile } = useFile();
|
|
176
|
+
|
|
177
|
+
const API_DO_STORAGE_ENDPOINT =
|
|
178
|
+
useRuntimeConfig().public.API_DO_STORAGE_ENDPOINT;
|
|
179
|
+
|
|
180
|
+
async function handleFileAdded(file: File) {
|
|
181
|
+
try {
|
|
182
|
+
const res = await addFile(file);
|
|
183
|
+
const uploadedId = res?.id;
|
|
184
|
+
if (uploadedId) {
|
|
185
|
+
const url = `${API_DO_STORAGE_ENDPOINT}/${uploadedId}`;
|
|
186
|
+
_workOrder.value.attachments = _workOrder.value.attachments ?? [];
|
|
187
|
+
_workOrder.value.attachments.push(url);
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error("Error uploading file:", error);
|
|
191
|
+
showMessage("Failed to upload file", "error");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function deleteFile(value: string) {
|
|
196
|
+
try {
|
|
197
|
+
await _deleteFile(value);
|
|
198
|
+
_workOrder.value.attachments = (_workOrder.value.attachments ?? []).filter(
|
|
199
|
+
(file) => file !== value
|
|
200
|
+
);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.log(error);
|
|
203
|
+
showMessage("Failed to delete file", "error");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function submitWorkOrder() {
|
|
208
|
+
if (!isEditMode.value || !workOrder.value?._id) {
|
|
209
|
+
console.warn("Update called without valid edit mode or work order ID.");
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
isSubmitting.value = true;
|
|
214
|
+
|
|
215
|
+
const payload = {
|
|
216
|
+
// ..._workOrder.value,
|
|
217
|
+
attachments: _workOrder.value.attachments,
|
|
218
|
+
category: _workOrder.value.category,
|
|
219
|
+
description: _workOrder.value.description,
|
|
220
|
+
highPriority: _workOrder.value.highPriority,
|
|
221
|
+
organization: route.params.org as string,
|
|
222
|
+
site: route.params.site as string,
|
|
223
|
+
subject: _workOrder.value.subject,
|
|
224
|
+
unit: _workOrder.value.unit,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
let res: Record<string, any> = {};
|
|
228
|
+
|
|
229
|
+
if (isEditMode.value) {
|
|
230
|
+
console.log("updating...");
|
|
231
|
+
res = await updateWorkOrder(workOrder.value._id as string, payload);
|
|
232
|
+
} else {
|
|
233
|
+
res = await createWorkOrder(payload);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
showMessage(res.message, "success");
|
|
237
|
+
showCreateDialog.value = false;
|
|
238
|
+
|
|
239
|
+
await _getWorkOrderById();
|
|
240
|
+
|
|
241
|
+
resetWorkOrderForm();
|
|
242
|
+
} catch (err) {
|
|
243
|
+
showMessage((err as Error).message, "error");
|
|
244
|
+
} finally {
|
|
245
|
+
isSubmitting.value = false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
71
248
|
</script>
|
|
@@ -65,6 +65,9 @@
|
|
|
65
65
|
@click:row="tableRowClickHandler"
|
|
66
66
|
style="max-height: calc(100vh - (200px))"
|
|
67
67
|
>
|
|
68
|
+
<template v-slot:item.createdAt="{ item }">
|
|
69
|
+
{{ formatDateDDMMYYYYLocal(item.createdAt) }}
|
|
70
|
+
</template>
|
|
68
71
|
</v-data-table>
|
|
69
72
|
</v-card>
|
|
70
73
|
</v-col>
|
|
@@ -88,10 +91,48 @@
|
|
|
88
91
|
@submit="submitWorkOrder"
|
|
89
92
|
/>
|
|
90
93
|
|
|
94
|
+
<ConfirmDialog
|
|
95
|
+
v-model="showDeleteDialog"
|
|
96
|
+
:loading="submitting"
|
|
97
|
+
@submit="submitDelete"
|
|
98
|
+
:image-src="'/images/icons/delete-icon.png'"
|
|
99
|
+
>
|
|
100
|
+
<template #image>
|
|
101
|
+
<v-img
|
|
102
|
+
height="120"
|
|
103
|
+
src="/images/icons/delete-icon.png"
|
|
104
|
+
alt="Delete Icon"
|
|
105
|
+
contain
|
|
106
|
+
/>
|
|
107
|
+
</template>
|
|
108
|
+
|
|
109
|
+
<template #title>
|
|
110
|
+
Are you sure you want to delete this work order?
|
|
111
|
+
</template>
|
|
112
|
+
|
|
113
|
+
<template #footer>
|
|
114
|
+
<v-btn
|
|
115
|
+
color="primary-button"
|
|
116
|
+
variant="flat"
|
|
117
|
+
class="font-weight-bold py-5 d-flex align-center justify-center"
|
|
118
|
+
@click="submitDelete"
|
|
119
|
+
:loading="submitting"
|
|
120
|
+
block
|
|
121
|
+
>
|
|
122
|
+
Confirm
|
|
123
|
+
</v-btn>
|
|
124
|
+
</template>
|
|
125
|
+
</ConfirmDialog>
|
|
126
|
+
|
|
91
127
|
<Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
|
|
92
128
|
|
|
93
129
|
<!-- Preview Dialog -->
|
|
94
|
-
<v-dialog
|
|
130
|
+
<v-dialog
|
|
131
|
+
v-model="dialogPreview"
|
|
132
|
+
width="450"
|
|
133
|
+
persistent
|
|
134
|
+
v-if="canViewWorkOrders"
|
|
135
|
+
>
|
|
95
136
|
<v-card width="100%">
|
|
96
137
|
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
|
|
97
138
|
<v-row no-gutters v-if="selectedWorkOrder" class="mb-4">
|
|
@@ -139,12 +180,18 @@
|
|
|
139
180
|
</template>
|
|
140
181
|
|
|
141
182
|
<v-list class="pa-0">
|
|
142
|
-
<v-list-item
|
|
183
|
+
<v-list-item
|
|
184
|
+
@click="onViewWorkOrder(selectedWorkOrder)"
|
|
185
|
+
v-if="canViewWorkOrderDetails"
|
|
186
|
+
>
|
|
143
187
|
<v-list-item-title class="text-subtitle-2">
|
|
144
188
|
View
|
|
145
189
|
</v-list-item-title>
|
|
146
190
|
</v-list-item>
|
|
147
|
-
<v-list-item
|
|
191
|
+
<v-list-item
|
|
192
|
+
@click="editWorkOrder(selectedWorkOrder)"
|
|
193
|
+
v-if="canUpdateWorkOrder"
|
|
194
|
+
>
|
|
148
195
|
<v-list-item-title class="text-subtitle-2">
|
|
149
196
|
Edit
|
|
150
197
|
</v-list-item-title>
|
|
@@ -224,7 +271,8 @@ const message = ref("");
|
|
|
224
271
|
const messageColor = ref("");
|
|
225
272
|
const messageSnackbar = ref(false);
|
|
226
273
|
|
|
227
|
-
const { getColorStatus, formatDate } =
|
|
274
|
+
const { getColorStatus, formatDate, debounce, formatDateDDMMYYYYLocal } =
|
|
275
|
+
useUtils();
|
|
228
276
|
|
|
229
277
|
const _workOrder = ref<TWorkOrderCreate>({
|
|
230
278
|
attachments: [],
|
|
@@ -261,12 +309,14 @@ const submitting = ref(false);
|
|
|
261
309
|
const selected = ref<string[]>([]);
|
|
262
310
|
const route = useRoute();
|
|
263
311
|
const { customers } = useCustomer();
|
|
312
|
+
const showDeleteDialog = ref(false);
|
|
264
313
|
|
|
265
314
|
const {
|
|
266
315
|
getWorkOrders: _getWorkOrders,
|
|
267
316
|
createWorkOrder,
|
|
268
317
|
getWorkOrderById,
|
|
269
318
|
updateWorkOrder,
|
|
319
|
+
deleteWorkOrder,
|
|
270
320
|
} = useWorkOrder();
|
|
271
321
|
|
|
272
322
|
const page = ref(1);
|
|
@@ -283,6 +333,7 @@ const {
|
|
|
283
333
|
page: page.value,
|
|
284
334
|
site: route.params.site as string,
|
|
285
335
|
category: props.category,
|
|
336
|
+
search: searchText.value || "",
|
|
286
337
|
})
|
|
287
338
|
);
|
|
288
339
|
|
|
@@ -432,8 +483,8 @@ async function submitWorkOrder() {
|
|
|
432
483
|
|
|
433
484
|
showMessage(res.message, "success");
|
|
434
485
|
showCreateDialog.value = false;
|
|
486
|
+
await getAllReqRefresh();
|
|
435
487
|
resetWorkOrderForm();
|
|
436
|
-
getAllReqRefresh();
|
|
437
488
|
} catch (err) {
|
|
438
489
|
showMessage((err as Error).message, "error");
|
|
439
490
|
} finally {
|
|
@@ -456,7 +507,6 @@ function onViewWorkOrder(item: any) {
|
|
|
456
507
|
async function editWorkOrder(item: any) {
|
|
457
508
|
try {
|
|
458
509
|
const _workOrders = await getWorkOrderById(item._id);
|
|
459
|
-
console.log(_workOrders);
|
|
460
510
|
_workOrder.value = {
|
|
461
511
|
attachments: (_workOrders.attachments || []) as string[],
|
|
462
512
|
category: _workOrders.category || "",
|
|
@@ -476,7 +526,30 @@ async function editWorkOrder(item: any) {
|
|
|
476
526
|
|
|
477
527
|
async function _updateWorkOrder() {}
|
|
478
528
|
|
|
479
|
-
function confirmDeleteWorkOrder(item: any) {
|
|
529
|
+
function confirmDeleteWorkOrder(item: any) {
|
|
530
|
+
workOrderToDelete.value = item;
|
|
531
|
+
showDeleteDialog.value = true;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const workOrderToDelete = ref<any>(null);
|
|
535
|
+
|
|
536
|
+
async function submitDelete() {
|
|
537
|
+
if (!workOrderToDelete.value) return;
|
|
538
|
+
submitting.value = true;
|
|
539
|
+
try {
|
|
540
|
+
const response = await deleteWorkOrder(workOrderToDelete.value._id);
|
|
541
|
+
showMessage(response.message, "success");
|
|
542
|
+
await getAllReqRefresh();
|
|
543
|
+
} catch (error) {
|
|
544
|
+
console.error("Failed to delete work order:", error);
|
|
545
|
+
showMessage("Failed to delete work order!", "error");
|
|
546
|
+
} finally {
|
|
547
|
+
submitting.value = false;
|
|
548
|
+
showDeleteDialog.value = false;
|
|
549
|
+
workOrderToDelete.value = null;
|
|
550
|
+
dialogPreview.value = false;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
480
553
|
|
|
481
554
|
function tableRowClickHandler(_: any, data: any) {
|
|
482
555
|
selectedWorkOrder.value = data.item;
|
|
@@ -486,4 +559,13 @@ function tableRowClickHandler(_: any, data: any) {
|
|
|
486
559
|
const dialogPreview = ref(false);
|
|
487
560
|
const selectedWorkOrder = ref<TWorkOrder | null>(null);
|
|
488
561
|
const searchText = ref("");
|
|
562
|
+
|
|
563
|
+
const debounceSearch = debounce(getAllReqRefresh, 500);
|
|
564
|
+
|
|
565
|
+
watch(
|
|
566
|
+
() => searchText.value,
|
|
567
|
+
() => {
|
|
568
|
+
debounceSearch();
|
|
569
|
+
}
|
|
570
|
+
);
|
|
489
571
|
</script>
|
|
@@ -73,7 +73,7 @@ export default function useBuildingUnit() {
|
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
function add(data: { labels: string[]; unit: TBuildingUnit
|
|
76
|
+
function add(data: { labels: string[]; unit: Partial<TBuildingUnit>; qty?: number }) {
|
|
77
77
|
return useNuxtApp().$api("/api/building-units", {
|
|
78
78
|
method: "POST",
|
|
79
79
|
body: data,
|
|
@@ -75,8 +75,9 @@ export default function useFeedback() {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function deleteFeedback(id: string) {
|
|
78
|
-
return useNuxtApp().$api<Record<string, any>>(`/api/feedbacks
|
|
78
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/feedbacks/deleted/feedback`, {
|
|
79
79
|
method: "DELETE",
|
|
80
|
+
query: { id },
|
|
80
81
|
});
|
|
81
82
|
}
|
|
82
83
|
|
|
@@ -94,7 +95,7 @@ export default function useFeedback() {
|
|
|
94
95
|
|
|
95
96
|
function updateStatusComplete(id: string, payload: TFeedbackStatusComplete) {
|
|
96
97
|
return useNuxtApp().$api<Record<string, any>>(
|
|
97
|
-
`/api/feedbacks/${id}/status
|
|
98
|
+
`/api/feedbacks/${id}/status/complete`,
|
|
98
99
|
{
|
|
99
100
|
method: "PUT",
|
|
100
101
|
body: payload,
|
|
@@ -71,6 +71,13 @@ export default function useWorkOrder() {
|
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
function deleteWorkOrder(id: string) {
|
|
75
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/work-orders/deleted/work-order`, {
|
|
76
|
+
method: "DELETE",
|
|
77
|
+
query: { id },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
74
81
|
return {
|
|
75
82
|
workOrders,
|
|
76
83
|
workOrder,
|
|
@@ -81,5 +88,6 @@ export default function useWorkOrder() {
|
|
|
81
88
|
getWorkOrders,
|
|
82
89
|
getWorkOrderById,
|
|
83
90
|
updateWorkOrder,
|
|
91
|
+
deleteWorkOrder,
|
|
84
92
|
};
|
|
85
93
|
}
|
package/package.json
CHANGED
package/types/card.d.ts
CHANGED
|
File without changes
|