@iservice365/layer-common 1.3.0 → 1.3.1
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/BuildingForm.vue +303 -0
- package/components/BuildingManagement/buildings.vue +395 -0
- package/components/BuildingManagement/units.vue +391 -0
- package/components/BuildingUnitFormAdd.vue +338 -0
- package/components/BuildingUnitFormEdit.vue +278 -0
- package/components/Chat/Information.vue +1 -1
- package/components/Input/NRICNumber.vue +12 -0
- package/components/TableMain.vue +5 -1
- package/components/VisitorForm.vue +114 -279
- package/components/VisitorManagement.vue +89 -169
- package/components/WorkOrder/Create.vue +5 -1
- package/composables/useBuilding.ts +1 -1
- package/composables/usePeople.ts +13 -5
- package/composables/useVisitor.ts +74 -51
- package/package.json +1 -1
- package/types/building.d.ts +2 -0
- package/types/people.d.ts +2 -1
- package/types/visitor.d.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-card width="100%">
|
|
3
|
+
<v-toolbar>
|
|
4
|
+
<v-row no-gutters class="fill-height px-6" align="center">
|
|
5
|
+
<span class="font-weight-bold text-h5 text-capitalize">
|
|
6
|
+
{{ prop.mode }} Building
|
|
7
|
+
</span>
|
|
8
|
+
</v-row>
|
|
9
|
+
</v-toolbar>
|
|
10
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-0">
|
|
11
|
+
<v-form v-model="validForm" :disabled="disable">
|
|
12
|
+
<v-row no-gutters class="px-6 pt-4">
|
|
13
|
+
<v-col cols="12" class="mt-2">
|
|
14
|
+
<v-row no-gutters>
|
|
15
|
+
<InputLabel
|
|
16
|
+
class="text-capitalize font-weight-bold"
|
|
17
|
+
title="Name"
|
|
18
|
+
required
|
|
19
|
+
/>
|
|
20
|
+
<v-col cols="12">
|
|
21
|
+
<v-text-field
|
|
22
|
+
v-model="building.name"
|
|
23
|
+
density="comfortable"
|
|
24
|
+
:rules="[requiredRule]"
|
|
25
|
+
></v-text-field>
|
|
26
|
+
</v-col>
|
|
27
|
+
</v-row>
|
|
28
|
+
</v-col>
|
|
29
|
+
|
|
30
|
+
<v-col cols="12">
|
|
31
|
+
<v-row>
|
|
32
|
+
<v-col cols="6" class="mt-2">
|
|
33
|
+
<v-row no-gutters>
|
|
34
|
+
<InputLabel
|
|
35
|
+
class="text-capitalize font-weight-bold"
|
|
36
|
+
title="Block"
|
|
37
|
+
required
|
|
38
|
+
/>
|
|
39
|
+
<v-col cols="12">
|
|
40
|
+
<v-select
|
|
41
|
+
v-model.number="building.block"
|
|
42
|
+
:items="blocks"
|
|
43
|
+
density="comfortable"
|
|
44
|
+
:rules="[
|
|
45
|
+
requiredRule,
|
|
46
|
+
() =>
|
|
47
|
+
(building.block && building.block > 0) ||
|
|
48
|
+
'Block is required',
|
|
49
|
+
]"
|
|
50
|
+
type="number"
|
|
51
|
+
></v-select>
|
|
52
|
+
</v-col>
|
|
53
|
+
</v-row>
|
|
54
|
+
</v-col>
|
|
55
|
+
|
|
56
|
+
<v-col cols="6" class="mt-2">
|
|
57
|
+
<v-row no-gutters>
|
|
58
|
+
<InputLabel
|
|
59
|
+
class="text-capitalize font-weight-bold"
|
|
60
|
+
title="Levels"
|
|
61
|
+
required
|
|
62
|
+
/>
|
|
63
|
+
<v-col cols="12">
|
|
64
|
+
<v-text-field
|
|
65
|
+
v-model.number="buildingLevels"
|
|
66
|
+
density="comfortable"
|
|
67
|
+
:rules="[requiredRule]"
|
|
68
|
+
type="number"
|
|
69
|
+
@update:model-value="setBuildingLevels()"
|
|
70
|
+
></v-text-field>
|
|
71
|
+
</v-col>
|
|
72
|
+
</v-row>
|
|
73
|
+
</v-col>
|
|
74
|
+
</v-row>
|
|
75
|
+
</v-col>
|
|
76
|
+
|
|
77
|
+
<v-col v-if="buildingLevels" cols="12">
|
|
78
|
+
<v-row justify="center">
|
|
79
|
+
<v-col cols="6">
|
|
80
|
+
<v-btn
|
|
81
|
+
block
|
|
82
|
+
color="primary"
|
|
83
|
+
variant="text"
|
|
84
|
+
class="text-none font-weight-bold"
|
|
85
|
+
text="Set level labels"
|
|
86
|
+
@click="show = !show"
|
|
87
|
+
></v-btn>
|
|
88
|
+
</v-col>
|
|
89
|
+
</v-row>
|
|
90
|
+
</v-col>
|
|
91
|
+
</v-row>
|
|
92
|
+
|
|
93
|
+
<v-expand-transition>
|
|
94
|
+
<v-row v-show="show" no-gutters class="px-6">
|
|
95
|
+
<template
|
|
96
|
+
v-for="(level, levelIndex) in building.levels"
|
|
97
|
+
:key="levelIndex"
|
|
98
|
+
>
|
|
99
|
+
<v-col cols="12">
|
|
100
|
+
<v-row no-gutters>
|
|
101
|
+
<InputLabel
|
|
102
|
+
class="text-capitalize font-weight-bold"
|
|
103
|
+
:title="`Level ${levelIndex + 1}`"
|
|
104
|
+
/>
|
|
105
|
+
<v-col cols="12">
|
|
106
|
+
<v-text-field
|
|
107
|
+
v-model.trim="building.levels[levelIndex]"
|
|
108
|
+
density="comfortable"
|
|
109
|
+
></v-text-field>
|
|
110
|
+
</v-col>
|
|
111
|
+
</v-row>
|
|
112
|
+
</v-col>
|
|
113
|
+
</template>
|
|
114
|
+
</v-row>
|
|
115
|
+
</v-expand-transition>
|
|
116
|
+
|
|
117
|
+
<v-col cols="12" class="px-6">
|
|
118
|
+
<InputLabel class="text-capitalize" title="Building Floor plan" />
|
|
119
|
+
<InputFileV2 v-model="building.buildingFloorPlan" :multiple="true" :max-length="10" title="Upload Images" />
|
|
120
|
+
</v-col>
|
|
121
|
+
|
|
122
|
+
<v-col cols="12" class="mt-2">
|
|
123
|
+
<v-checkbox v-model="createMore" density="comfortable" hide-details>
|
|
124
|
+
<template #label>
|
|
125
|
+
<span class="text-subtitle-2 font-weight-bold">
|
|
126
|
+
Create more
|
|
127
|
+
</span>
|
|
128
|
+
</template>
|
|
129
|
+
</v-checkbox>
|
|
130
|
+
</v-col>
|
|
131
|
+
|
|
132
|
+
<v-col cols="12">
|
|
133
|
+
<v-row no-gutters>
|
|
134
|
+
<v-col cols="12" class="text-center">
|
|
135
|
+
<span
|
|
136
|
+
class="text-none text-subtitle-2 font-weight-medium text-error"
|
|
137
|
+
>
|
|
138
|
+
{{ message }}
|
|
139
|
+
</span>
|
|
140
|
+
</v-col>
|
|
141
|
+
</v-row>
|
|
142
|
+
</v-col>
|
|
143
|
+
</v-form>
|
|
144
|
+
</v-card-text>
|
|
145
|
+
|
|
146
|
+
<v-toolbar density="compact">
|
|
147
|
+
<v-row no-gutters>
|
|
148
|
+
<v-col cols="6">
|
|
149
|
+
<v-btn
|
|
150
|
+
tile
|
|
151
|
+
block
|
|
152
|
+
variant="text"
|
|
153
|
+
class="text-none"
|
|
154
|
+
size="48"
|
|
155
|
+
@click="cancel"
|
|
156
|
+
:disabled="disable"
|
|
157
|
+
>
|
|
158
|
+
Cancel
|
|
159
|
+
</v-btn>
|
|
160
|
+
</v-col>
|
|
161
|
+
|
|
162
|
+
<v-col cols="6">
|
|
163
|
+
<v-btn
|
|
164
|
+
tile
|
|
165
|
+
block
|
|
166
|
+
variant="flat"
|
|
167
|
+
color="black"
|
|
168
|
+
class="text-none"
|
|
169
|
+
size="48"
|
|
170
|
+
:disabled="!validForm || disable"
|
|
171
|
+
@click="submit"
|
|
172
|
+
:loading="disable"
|
|
173
|
+
>
|
|
174
|
+
Submit
|
|
175
|
+
</v-btn>
|
|
176
|
+
</v-col>
|
|
177
|
+
</v-row>
|
|
178
|
+
</v-toolbar>
|
|
179
|
+
</v-card>
|
|
180
|
+
</template>
|
|
181
|
+
|
|
182
|
+
<script setup lang="ts">
|
|
183
|
+
const prop = defineProps({
|
|
184
|
+
site: {
|
|
185
|
+
type: String,
|
|
186
|
+
default: "",
|
|
187
|
+
},
|
|
188
|
+
mode: {
|
|
189
|
+
type: String,
|
|
190
|
+
default: "add",
|
|
191
|
+
},
|
|
192
|
+
building: {
|
|
193
|
+
type: Object as PropType<TBuilding>,
|
|
194
|
+
default: () => ({
|
|
195
|
+
site: "",
|
|
196
|
+
name: "",
|
|
197
|
+
block: null,
|
|
198
|
+
levels: [],
|
|
199
|
+
buildingFloorPlan: []
|
|
200
|
+
}),
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const { getSiteById } = useSite();
|
|
205
|
+
|
|
206
|
+
const site = ref<TSite | null>(null);
|
|
207
|
+
|
|
208
|
+
const { data: getSiteReq } = useLazyAsyncData(
|
|
209
|
+
"get-site-by-id-" + prop.site,
|
|
210
|
+
async () => getSiteById(prop.site)
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
watchEffect(() => {
|
|
214
|
+
if (getSiteReq.value) {
|
|
215
|
+
site.value = getSiteReq.value;
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const blocks = computed(() => {
|
|
220
|
+
if (!site.value) return [];
|
|
221
|
+
return Array.from({ length: site.value?.metadata?.block || 0 }, (_, i) => i + 1);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const emit = defineEmits(["cancel", "success", "success:create-more"]);
|
|
225
|
+
|
|
226
|
+
const validForm = ref(false);
|
|
227
|
+
|
|
228
|
+
const buildingLevels = ref(0);
|
|
229
|
+
|
|
230
|
+
const show = ref(false);
|
|
231
|
+
|
|
232
|
+
function setBuildingLevels() {
|
|
233
|
+
building.value.levels.length = 0;
|
|
234
|
+
for (let index = 0; index < buildingLevels.value; index++) {
|
|
235
|
+
building.value.levels.push(`Lvl${index + 1}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const building = ref<TBuilding>({
|
|
240
|
+
site: "",
|
|
241
|
+
name: "",
|
|
242
|
+
block: null,
|
|
243
|
+
levels: [],
|
|
244
|
+
buildingFloorPlan: []
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
building.value.site = prop.site;
|
|
248
|
+
if (prop.mode === "edit") {
|
|
249
|
+
building.value = JSON.parse(JSON.stringify(prop.building));
|
|
250
|
+
buildingLevels.value = building.value.levels.length;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const createMore = ref(false);
|
|
254
|
+
const disable = ref(false);
|
|
255
|
+
|
|
256
|
+
const { requiredRule } = useUtils();
|
|
257
|
+
|
|
258
|
+
const message = ref("");
|
|
259
|
+
|
|
260
|
+
const { createBuilding, updateById } = useBuilding();
|
|
261
|
+
|
|
262
|
+
async function submit() {
|
|
263
|
+
disable.value = true;
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
if (prop.mode === "add") {
|
|
267
|
+
await createBuilding(building.value);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (prop.mode === "edit") {
|
|
271
|
+
await updateById(building.value._id ?? "", {
|
|
272
|
+
name: building.value.name,
|
|
273
|
+
block: building.value.block,
|
|
274
|
+
levels: building.value.levels,
|
|
275
|
+
buildingFloorPlan: building.value.buildingFloorPlan
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (createMore.value) {
|
|
280
|
+
building.value.levels = [];
|
|
281
|
+
building.value.name = "";
|
|
282
|
+
building.value.block = null;
|
|
283
|
+
|
|
284
|
+
message.value = "";
|
|
285
|
+
emit("success:create-more");
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
emit("success");
|
|
290
|
+
} catch (error: any) {
|
|
291
|
+
message.value =
|
|
292
|
+
error.response?._data?.message || "Failed to create building";
|
|
293
|
+
} finally {
|
|
294
|
+
disable.value = false;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function cancel() {
|
|
299
|
+
createMore.value = false;
|
|
300
|
+
message.value = "";
|
|
301
|
+
emit("cancel");
|
|
302
|
+
}
|
|
303
|
+
</script>
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters>
|
|
3
|
+
<v-col cols="12" class="mb-2">
|
|
4
|
+
<v-row no-gutters>
|
|
5
|
+
<v-btn
|
|
6
|
+
class="text-none"
|
|
7
|
+
rounded="pill"
|
|
8
|
+
variant="tonal"
|
|
9
|
+
@click="setBuilding()"
|
|
10
|
+
size="large"
|
|
11
|
+
v-if="canCreate && canCreateBuilding"
|
|
12
|
+
>
|
|
13
|
+
Add Building
|
|
14
|
+
</v-btn>
|
|
15
|
+
</v-row>
|
|
16
|
+
</v-col>
|
|
17
|
+
<v-col cols="12">
|
|
18
|
+
<v-card
|
|
19
|
+
width="100%"
|
|
20
|
+
variant="outlined"
|
|
21
|
+
border="thin"
|
|
22
|
+
rounded="lg"
|
|
23
|
+
:loading="loading"
|
|
24
|
+
>
|
|
25
|
+
<v-toolbar density="compact" color="grey-lighten-4">
|
|
26
|
+
<template #prepend>
|
|
27
|
+
<v-btn fab icon density="comfortable" @click="getBuildings()">
|
|
28
|
+
<v-icon>mdi-refresh</v-icon>
|
|
29
|
+
</v-btn>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<template #append>
|
|
33
|
+
<v-row no-gutters justify="end" align="center">
|
|
34
|
+
<span class="mr-2 text-caption text-fontgray">
|
|
35
|
+
{{ pageRange }}
|
|
36
|
+
</span>
|
|
37
|
+
<local-pagination
|
|
38
|
+
v-model="page"
|
|
39
|
+
:length="pages"
|
|
40
|
+
@update:value="getBuildings()"
|
|
41
|
+
/>
|
|
42
|
+
</v-row>
|
|
43
|
+
</template>
|
|
44
|
+
</v-toolbar>
|
|
45
|
+
|
|
46
|
+
<v-data-table
|
|
47
|
+
:headers="headers"
|
|
48
|
+
:items="items"
|
|
49
|
+
item-value="_id"
|
|
50
|
+
items-per-page="20"
|
|
51
|
+
fixed-header
|
|
52
|
+
hide-default-footer
|
|
53
|
+
hide-default-header
|
|
54
|
+
@click:row="tableRowClickHandler"
|
|
55
|
+
style="max-height: calc(100vh - (200px))"
|
|
56
|
+
>
|
|
57
|
+
<template #item.createdAt="{ value }">
|
|
58
|
+
{{ new Date(value).toLocaleDateString() }}
|
|
59
|
+
</template>
|
|
60
|
+
</v-data-table>
|
|
61
|
+
</v-card>
|
|
62
|
+
</v-col>
|
|
63
|
+
|
|
64
|
+
<!-- Create Dialog -->
|
|
65
|
+
<v-dialog v-model="createDialog" width="450" persistent>
|
|
66
|
+
<BuildingForm
|
|
67
|
+
:site="site"
|
|
68
|
+
@cancel="createDialog = false"
|
|
69
|
+
@success="successCreate()"
|
|
70
|
+
@success:create-more="getBuildings()"
|
|
71
|
+
/>
|
|
72
|
+
</v-dialog>
|
|
73
|
+
|
|
74
|
+
<!-- Edit Dialog -->
|
|
75
|
+
<v-dialog v-model="editDialog" width="450" persistent>
|
|
76
|
+
<BuildingForm
|
|
77
|
+
:site="site"
|
|
78
|
+
mode="edit"
|
|
79
|
+
@cancel="editDialog = false"
|
|
80
|
+
@success="successUpdate()"
|
|
81
|
+
:building="selectedBuilding"
|
|
82
|
+
/>
|
|
83
|
+
</v-dialog>
|
|
84
|
+
|
|
85
|
+
<!-- Preview Dialog -->
|
|
86
|
+
<v-dialog v-if="canViewBuildingDetails" v-model="previewDialog" width="450" persistent>
|
|
87
|
+
<v-card width="100%">
|
|
88
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
|
|
89
|
+
<v-row no-gutters class="mb-4">
|
|
90
|
+
<v-col cols="12">
|
|
91
|
+
<strong>Name:</strong> {{ selectedBuilding?.name ?? "N/A" }}
|
|
92
|
+
</v-col>
|
|
93
|
+
|
|
94
|
+
<v-col cols="12">
|
|
95
|
+
<strong>Block:</strong>
|
|
96
|
+
{{ selectedBuilding?.block ?? "N/A" }}
|
|
97
|
+
</v-col>
|
|
98
|
+
|
|
99
|
+
<v-col cols="12">
|
|
100
|
+
<strong>Levels:</strong>
|
|
101
|
+
{{ selectedBuilding?.levels.length ?? "N/A" }}
|
|
102
|
+
</v-col>
|
|
103
|
+
</v-row>
|
|
104
|
+
</v-card-text>
|
|
105
|
+
|
|
106
|
+
<v-toolbar class="pa-0" density="compact">
|
|
107
|
+
<v-row no-gutters>
|
|
108
|
+
<v-col cols="6" class="pa-0">
|
|
109
|
+
<v-btn
|
|
110
|
+
block
|
|
111
|
+
variant="text"
|
|
112
|
+
class="text-none"
|
|
113
|
+
size="large"
|
|
114
|
+
@click="previewDialog = false"
|
|
115
|
+
height="48"
|
|
116
|
+
>
|
|
117
|
+
Close
|
|
118
|
+
</v-btn>
|
|
119
|
+
</v-col>
|
|
120
|
+
|
|
121
|
+
<v-col cols="6" class="pa-0" v-if="canUpdate">
|
|
122
|
+
<v-menu>
|
|
123
|
+
<template #activator="{ props }">
|
|
124
|
+
<v-btn
|
|
125
|
+
block
|
|
126
|
+
variant="flat"
|
|
127
|
+
color="black"
|
|
128
|
+
class="text-none"
|
|
129
|
+
height="48"
|
|
130
|
+
v-bind="props"
|
|
131
|
+
tile
|
|
132
|
+
:disabled="!canUpdateBuilding && !canDeleteBuilding"
|
|
133
|
+
>
|
|
134
|
+
More actions
|
|
135
|
+
</v-btn>
|
|
136
|
+
</template>
|
|
137
|
+
|
|
138
|
+
<v-list class="pa-0">
|
|
139
|
+
<v-list-item v-if="canUpdateBuilding" @click="openEditDialog()">
|
|
140
|
+
<v-list-item-title class="text-subtitle-2">
|
|
141
|
+
Edit Building
|
|
142
|
+
</v-list-item-title>
|
|
143
|
+
</v-list-item>
|
|
144
|
+
|
|
145
|
+
<v-list-item v-if="canDeleteBuilding" @click="openDeleteDialog()" class="text-red">
|
|
146
|
+
<v-list-item-title class="text-subtitle-2">
|
|
147
|
+
Delete Building
|
|
148
|
+
</v-list-item-title>
|
|
149
|
+
</v-list-item>
|
|
150
|
+
</v-list>
|
|
151
|
+
</v-menu>
|
|
152
|
+
</v-col>
|
|
153
|
+
</v-row>
|
|
154
|
+
</v-toolbar>
|
|
155
|
+
</v-card>
|
|
156
|
+
</v-dialog>
|
|
157
|
+
|
|
158
|
+
<v-dialog
|
|
159
|
+
v-model="confirmDialog"
|
|
160
|
+
:loading="deleteLoading"
|
|
161
|
+
width="450"
|
|
162
|
+
persistent
|
|
163
|
+
>
|
|
164
|
+
<v-card width="100%">
|
|
165
|
+
<v-toolbar density="compact" class="pl-4">
|
|
166
|
+
<span class="font-weight-medium text-h5">Delete Building</span>
|
|
167
|
+
</v-toolbar>
|
|
168
|
+
|
|
169
|
+
<v-card-text>
|
|
170
|
+
<p class="text-subtitle-2 text-center">
|
|
171
|
+
Are you sure you want to delete this building? This action cannot be
|
|
172
|
+
undone.
|
|
173
|
+
</p>
|
|
174
|
+
|
|
175
|
+
<v-row v-if="message" no-gutters justify="center" class="mt-4">
|
|
176
|
+
<span class="text-caption text-error text-center">
|
|
177
|
+
{{ message }}
|
|
178
|
+
</span>
|
|
179
|
+
</v-row>
|
|
180
|
+
</v-card-text>
|
|
181
|
+
|
|
182
|
+
<v-toolbar density="compact">
|
|
183
|
+
<v-row no-gutters>
|
|
184
|
+
<v-col cols="6">
|
|
185
|
+
<v-btn
|
|
186
|
+
tile
|
|
187
|
+
block
|
|
188
|
+
size="48"
|
|
189
|
+
variant="text"
|
|
190
|
+
class="text-none"
|
|
191
|
+
@click="confirmDialog = false"
|
|
192
|
+
:disabled="deleteLoading"
|
|
193
|
+
>
|
|
194
|
+
Close
|
|
195
|
+
</v-btn>
|
|
196
|
+
</v-col>
|
|
197
|
+
<v-col cols="6">
|
|
198
|
+
<v-btn
|
|
199
|
+
tile
|
|
200
|
+
block
|
|
201
|
+
size="48"
|
|
202
|
+
color="black"
|
|
203
|
+
variant="flat"
|
|
204
|
+
class="text-none"
|
|
205
|
+
@click="handleDeleteBuilding"
|
|
206
|
+
:loading="deleteLoading"
|
|
207
|
+
>
|
|
208
|
+
Delete Building
|
|
209
|
+
</v-btn>
|
|
210
|
+
</v-col>
|
|
211
|
+
</v-row>
|
|
212
|
+
</v-toolbar>
|
|
213
|
+
</v-card>
|
|
214
|
+
</v-dialog>
|
|
215
|
+
|
|
216
|
+
<Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
|
|
217
|
+
</v-row>
|
|
218
|
+
</template>
|
|
219
|
+
|
|
220
|
+
<script setup lang="ts">
|
|
221
|
+
definePageMeta({
|
|
222
|
+
middleware: ["01-auth", "02-org"],
|
|
223
|
+
memberOnly: true,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const props = defineProps({
|
|
227
|
+
headers: {
|
|
228
|
+
type: Array as PropType<Array<Record<string, any>>>,
|
|
229
|
+
default: () => [
|
|
230
|
+
{
|
|
231
|
+
title: "Name",
|
|
232
|
+
value: "name",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
title: "Director",
|
|
236
|
+
value: "directorName",
|
|
237
|
+
},
|
|
238
|
+
{ title: "Action", value: "action-table" },
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
canCreate: {
|
|
242
|
+
type: Boolean,
|
|
243
|
+
default: true,
|
|
244
|
+
},
|
|
245
|
+
canUpdate: {
|
|
246
|
+
type: Boolean,
|
|
247
|
+
default: true,
|
|
248
|
+
},
|
|
249
|
+
canDelete: {
|
|
250
|
+
type: Boolean,
|
|
251
|
+
default: true,
|
|
252
|
+
},
|
|
253
|
+
canCreateBuilding: {
|
|
254
|
+
type: Boolean,
|
|
255
|
+
default: true,
|
|
256
|
+
},
|
|
257
|
+
canUpdateBuilding: {
|
|
258
|
+
type: Boolean,
|
|
259
|
+
default: true,
|
|
260
|
+
},
|
|
261
|
+
canDeleteBuilding: {
|
|
262
|
+
type: Boolean,
|
|
263
|
+
default: true,
|
|
264
|
+
},
|
|
265
|
+
canViewBuildingDetails: {
|
|
266
|
+
type: Boolean,
|
|
267
|
+
default: true,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const site = (useRoute().params.site as string) ?? "";
|
|
272
|
+
const status = (useRoute().params.status as string) ?? "active";
|
|
273
|
+
|
|
274
|
+
const { headerSearch } = useLocal();
|
|
275
|
+
const { getAll: _getBuildings, deleteById } = useBuilding();
|
|
276
|
+
|
|
277
|
+
const page = ref(1);
|
|
278
|
+
const pages = ref(0);
|
|
279
|
+
const pageRange = ref("-- - -- of --");
|
|
280
|
+
|
|
281
|
+
const message = ref("");
|
|
282
|
+
const messageSnackbar = ref(false);
|
|
283
|
+
const messageColor = ref("");
|
|
284
|
+
|
|
285
|
+
const items = ref<Array<Record<string, any>>>([]);
|
|
286
|
+
|
|
287
|
+
const {
|
|
288
|
+
data: getBuildingReq,
|
|
289
|
+
refresh: getBuildings,
|
|
290
|
+
status: getBuildingReqStatus,
|
|
291
|
+
} = useLazyAsyncData(
|
|
292
|
+
"buildings-get-all",
|
|
293
|
+
() =>
|
|
294
|
+
_getBuildings({
|
|
295
|
+
page: page.value,
|
|
296
|
+
search: headerSearch.value,
|
|
297
|
+
status,
|
|
298
|
+
site,
|
|
299
|
+
}),
|
|
300
|
+
{
|
|
301
|
+
watch: [page, headerSearch],
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
const loading = computed(() => getBuildingReqStatus.value === "pending");
|
|
306
|
+
|
|
307
|
+
watchEffect(() => {
|
|
308
|
+
if (getBuildingReq.value) {
|
|
309
|
+
items.value = getBuildingReq.value.items;
|
|
310
|
+
pages.value = getBuildingReq.value.pages;
|
|
311
|
+
pageRange.value = getBuildingReq.value.pageRange;
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const createDialog = ref(false);
|
|
316
|
+
const editDialog = ref(false);
|
|
317
|
+
const previewDialog = ref(false);
|
|
318
|
+
const selectedBuilding = ref<TBuilding>({
|
|
319
|
+
_id: "",
|
|
320
|
+
site: "",
|
|
321
|
+
name: "",
|
|
322
|
+
block: null,
|
|
323
|
+
levels: [],
|
|
324
|
+
buildingFloorPlan: [],
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
function tableRowClickHandler(_: any, data: any) {
|
|
328
|
+
selectedBuilding.value = data.item as TBuilding;
|
|
329
|
+
previewDialog.value = true;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function successCreate() {
|
|
333
|
+
createDialog.value = false;
|
|
334
|
+
getBuildings();
|
|
335
|
+
showMessage("Building created successfully!", "success");
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function successUpdate() {
|
|
339
|
+
editDialog.value = false;
|
|
340
|
+
previewDialog.value = false;
|
|
341
|
+
getBuildings();
|
|
342
|
+
showMessage("Building updated successfully!", "success");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function openEditDialog() {
|
|
346
|
+
editDialog.value = true;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const confirmDialog = ref(false);
|
|
350
|
+
const selectedBuildingId = ref<string | null>(null);
|
|
351
|
+
const deleteLoading = ref(false);
|
|
352
|
+
|
|
353
|
+
function openDeleteDialog() {
|
|
354
|
+
confirmDialog.value = true;
|
|
355
|
+
message.value = "";
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function showMessage(msg: string, color: string) {
|
|
359
|
+
message.value = msg;
|
|
360
|
+
messageColor.value = color;
|
|
361
|
+
messageSnackbar.value = true;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async function handleDeleteBuilding() {
|
|
365
|
+
deleteLoading.value = true;
|
|
366
|
+
try {
|
|
367
|
+
await deleteById(selectedBuilding.value._id ?? "");
|
|
368
|
+
await getBuildings();
|
|
369
|
+
selectedBuildingId.value = null;
|
|
370
|
+
confirmDialog.value = false;
|
|
371
|
+
previewDialog.value = false
|
|
372
|
+
} catch (error: any) {
|
|
373
|
+
message.value =
|
|
374
|
+
error?.response?._data?.message || "Failed to delete region";
|
|
375
|
+
} finally {
|
|
376
|
+
deleteLoading.value = false;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function setBuilding({
|
|
381
|
+
mode = "create",
|
|
382
|
+
dialog = true,
|
|
383
|
+
data = {} as TBuilding,
|
|
384
|
+
} = {}) {
|
|
385
|
+
if (mode === "create") {
|
|
386
|
+
createDialog.value = dialog;
|
|
387
|
+
} else if (mode === "edit") {
|
|
388
|
+
editDialog.value = dialog;
|
|
389
|
+
selectedBuilding.value = data;
|
|
390
|
+
} else if (mode === "preview") {
|
|
391
|
+
previewDialog.value = dialog;
|
|
392
|
+
selectedBuilding.value = data;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
</script>
|