@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
|
@@ -0,0 +1,338 @@
|
|
|
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"> Add Unit </span>
|
|
6
|
+
</v-row>
|
|
7
|
+
</v-toolbar>
|
|
8
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto">
|
|
9
|
+
<v-form v-model="validForm" :disabled="disable">
|
|
10
|
+
<v-row no-gutters>
|
|
11
|
+
<v-col cols="12" class="mt-2">
|
|
12
|
+
<v-row no-gutters>
|
|
13
|
+
<InputLabel class="text-capitalize" title="Name" required />
|
|
14
|
+
<v-col cols="12">
|
|
15
|
+
<v-text-field
|
|
16
|
+
v-model="buildingUnit.name"
|
|
17
|
+
density="comfortable"
|
|
18
|
+
:rules="[requiredRule]"
|
|
19
|
+
></v-text-field>
|
|
20
|
+
</v-col>
|
|
21
|
+
</v-row>
|
|
22
|
+
</v-col>
|
|
23
|
+
|
|
24
|
+
<v-col cols="12">
|
|
25
|
+
<v-row>
|
|
26
|
+
<v-col cols="12" class="mt-2">
|
|
27
|
+
<v-row no-gutters>
|
|
28
|
+
<InputLabel
|
|
29
|
+
class="text-capitalize"
|
|
30
|
+
title="Building"
|
|
31
|
+
required
|
|
32
|
+
/>
|
|
33
|
+
<v-col cols="12">
|
|
34
|
+
<v-autocomplete
|
|
35
|
+
v-model="buildingUnit.building"
|
|
36
|
+
:items="buildings"
|
|
37
|
+
item-title="name"
|
|
38
|
+
item-value="_id"
|
|
39
|
+
v-model:search="searchBuilding"
|
|
40
|
+
:hide-no-data="false"
|
|
41
|
+
density="comfortable"
|
|
42
|
+
:rules="[requiredRule]"
|
|
43
|
+
variant="outlined"
|
|
44
|
+
></v-autocomplete>
|
|
45
|
+
</v-col>
|
|
46
|
+
</v-row>
|
|
47
|
+
</v-col>
|
|
48
|
+
</v-row>
|
|
49
|
+
</v-col>
|
|
50
|
+
|
|
51
|
+
<v-col cols="12" class="mt-2">
|
|
52
|
+
<v-row no-gutters>
|
|
53
|
+
<InputLabel class="text-capitalize" title="Category" required />
|
|
54
|
+
<v-col cols="12">
|
|
55
|
+
<v-autocomplete
|
|
56
|
+
v-model="buildingUnit.category"
|
|
57
|
+
:items="unitCategories"
|
|
58
|
+
density="comfortable"
|
|
59
|
+
:rules="[requiredRule]"
|
|
60
|
+
></v-autocomplete>
|
|
61
|
+
</v-col>
|
|
62
|
+
</v-row>
|
|
63
|
+
</v-col>
|
|
64
|
+
|
|
65
|
+
<v-col cols="12">
|
|
66
|
+
<v-row>
|
|
67
|
+
<v-col cols="6" class="mt-2">
|
|
68
|
+
<v-row no-gutters>
|
|
69
|
+
<InputLabel class="text-capitalize" title="Level" required />
|
|
70
|
+
<v-col cols="12">
|
|
71
|
+
<v-select
|
|
72
|
+
v-model="buildingUnit.level"
|
|
73
|
+
:items="buildingLevels"
|
|
74
|
+
density="comfortable"
|
|
75
|
+
:rules="[requiredRule]"
|
|
76
|
+
></v-select>
|
|
77
|
+
</v-col>
|
|
78
|
+
</v-row>
|
|
79
|
+
</v-col>
|
|
80
|
+
|
|
81
|
+
<v-col cols="6" class="mt-2">
|
|
82
|
+
<v-row no-gutters>
|
|
83
|
+
<InputLabel
|
|
84
|
+
class="text-capitalize"
|
|
85
|
+
title="No. of Units"
|
|
86
|
+
required
|
|
87
|
+
/>
|
|
88
|
+
<v-col cols="12">
|
|
89
|
+
<v-text-field
|
|
90
|
+
v-model.number="buildingUnitQty"
|
|
91
|
+
density="comfortable"
|
|
92
|
+
:rules="[requiredRule]"
|
|
93
|
+
type="number"
|
|
94
|
+
@update:model-value="setBuildingLevels()"
|
|
95
|
+
></v-text-field>
|
|
96
|
+
</v-col>
|
|
97
|
+
</v-row>
|
|
98
|
+
</v-col>
|
|
99
|
+
</v-row>
|
|
100
|
+
</v-col>
|
|
101
|
+
|
|
102
|
+
<v-col v-if="buildingLevels" cols="12">
|
|
103
|
+
<v-row justify="center">
|
|
104
|
+
<v-col cols="6">
|
|
105
|
+
<v-btn
|
|
106
|
+
block
|
|
107
|
+
color="primary"
|
|
108
|
+
variant="text"
|
|
109
|
+
class="text-none font-weight-bold"
|
|
110
|
+
text="Set unit labels"
|
|
111
|
+
@click="show = !show"
|
|
112
|
+
></v-btn>
|
|
113
|
+
</v-col>
|
|
114
|
+
</v-row>
|
|
115
|
+
</v-col>
|
|
116
|
+
|
|
117
|
+
<v-expand-transition>
|
|
118
|
+
<v-row v-show="show" no-gutters>
|
|
119
|
+
<template
|
|
120
|
+
v-for="(unitLabel, unitLabelIndex) in unitLabels"
|
|
121
|
+
:key="levelIndex"
|
|
122
|
+
>
|
|
123
|
+
<v-col cols="12">
|
|
124
|
+
<v-row no-gutters>
|
|
125
|
+
<InputLabel
|
|
126
|
+
class="text-capitalize font-weight-bold"
|
|
127
|
+
:title="`Unit ${unitLabelIndex + 1}`"
|
|
128
|
+
/>
|
|
129
|
+
<v-col cols="12">
|
|
130
|
+
<v-text-field
|
|
131
|
+
v-model.trim="unitLabels[unitLabelIndex]"
|
|
132
|
+
density="comfortable"
|
|
133
|
+
></v-text-field>
|
|
134
|
+
</v-col>
|
|
135
|
+
</v-row>
|
|
136
|
+
</v-col>
|
|
137
|
+
</template>
|
|
138
|
+
</v-row>
|
|
139
|
+
</v-expand-transition>
|
|
140
|
+
|
|
141
|
+
<v-col cols="12" class="mt-5">
|
|
142
|
+
<InputLabel class="text-capitalize" title="Upload Files (Lease of Contract, Cert. of Occupancy)" />
|
|
143
|
+
<InputFileV2 v-model="buildingUnit.buildingUnitFiles" :multiple="false" :max-length="10" title="Upload PDF Files" accept="application/pdf" />
|
|
144
|
+
</v-col>
|
|
145
|
+
|
|
146
|
+
<v-col cols="12" class="mt-2">
|
|
147
|
+
<v-checkbox v-model="createMore" density="comfortable" hide-details>
|
|
148
|
+
<template #label>
|
|
149
|
+
<span class="text-subtitle-2 font-weight-bold">
|
|
150
|
+
Create more
|
|
151
|
+
</span>
|
|
152
|
+
</template>
|
|
153
|
+
</v-checkbox>
|
|
154
|
+
</v-col>
|
|
155
|
+
|
|
156
|
+
<v-col cols="12" class="my-2">
|
|
157
|
+
<v-row no-gutters>
|
|
158
|
+
<v-col cols="12" class="text-center">
|
|
159
|
+
<span
|
|
160
|
+
class="text-none text-subtitle-2 font-weight-medium text-error"
|
|
161
|
+
>
|
|
162
|
+
{{ message }}
|
|
163
|
+
</span>
|
|
164
|
+
</v-col>
|
|
165
|
+
</v-row>
|
|
166
|
+
</v-col>
|
|
167
|
+
</v-row>
|
|
168
|
+
</v-form>
|
|
169
|
+
</v-card-text>
|
|
170
|
+
|
|
171
|
+
<v-toolbar density="compact">
|
|
172
|
+
<v-row no-gutters>
|
|
173
|
+
<v-col cols="6">
|
|
174
|
+
<v-btn
|
|
175
|
+
tile
|
|
176
|
+
block
|
|
177
|
+
variant="text"
|
|
178
|
+
class="text-none"
|
|
179
|
+
size="48"
|
|
180
|
+
@click="cancel"
|
|
181
|
+
:disabled="disable"
|
|
182
|
+
>
|
|
183
|
+
Cancel
|
|
184
|
+
</v-btn>
|
|
185
|
+
</v-col>
|
|
186
|
+
|
|
187
|
+
<v-col cols="6">
|
|
188
|
+
<v-btn
|
|
189
|
+
tile
|
|
190
|
+
block
|
|
191
|
+
variant="flat"
|
|
192
|
+
color="black"
|
|
193
|
+
class="text-none"
|
|
194
|
+
size="48"
|
|
195
|
+
:disabled="!validForm || disable"
|
|
196
|
+
@click="submit"
|
|
197
|
+
:loading="disable"
|
|
198
|
+
>
|
|
199
|
+
Submit
|
|
200
|
+
</v-btn>
|
|
201
|
+
</v-col>
|
|
202
|
+
</v-row>
|
|
203
|
+
</v-toolbar>
|
|
204
|
+
</v-card>
|
|
205
|
+
</template>
|
|
206
|
+
|
|
207
|
+
<script setup lang="ts">
|
|
208
|
+
const prop = defineProps({
|
|
209
|
+
site: {
|
|
210
|
+
type: String,
|
|
211
|
+
default: "",
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const searchBuilding = ref("");
|
|
216
|
+
|
|
217
|
+
const emit = defineEmits(["cancel", "success", "success:create-more"]);
|
|
218
|
+
|
|
219
|
+
const validForm = ref(false);
|
|
220
|
+
|
|
221
|
+
const { getAll } = useBuilding();
|
|
222
|
+
|
|
223
|
+
const buildings = ref<TBuilding[]>([]);
|
|
224
|
+
|
|
225
|
+
const { data: getBuildingReq } = useLazyAsyncData(
|
|
226
|
+
"get-all-buildings",
|
|
227
|
+
async () => getAll({ site: prop.site, status: "active" })
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
watchEffect(() => {
|
|
231
|
+
if (getBuildingReq.value) {
|
|
232
|
+
buildings.value = getBuildingReq.value.items;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const buildingUnitQty = ref(1);
|
|
237
|
+
|
|
238
|
+
const buildingUnit = ref<TBuildingUnit>({
|
|
239
|
+
site: "",
|
|
240
|
+
name: "Unit",
|
|
241
|
+
building: "",
|
|
242
|
+
buildingName: "",
|
|
243
|
+
block: 0,
|
|
244
|
+
level: "",
|
|
245
|
+
category: "",
|
|
246
|
+
status: "active",
|
|
247
|
+
buildingUnitFiles: []
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
buildingUnit.value.site = prop.site;
|
|
251
|
+
|
|
252
|
+
const selectedBuilding = computed(() => {
|
|
253
|
+
return buildings.value.find((b) => b._id === buildingUnit.value.building);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
watchEffect(() => {
|
|
257
|
+
if (buildingUnit.value.building) {
|
|
258
|
+
buildingUnit.value.buildingName = selectedBuilding.value?.name;
|
|
259
|
+
buildingUnit.value.block = selectedBuilding.value?.block || 0;
|
|
260
|
+
} else {
|
|
261
|
+
buildingUnit.value.buildingName = "";
|
|
262
|
+
buildingUnit.value.block = 0;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const buildingLevels = computed(() => {
|
|
267
|
+
return selectedBuilding.value?.levels || [];
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const unitLabels = ref<string[]>([]);
|
|
271
|
+
unitLabels.value.push("Unit 1");
|
|
272
|
+
|
|
273
|
+
const show = ref(false);
|
|
274
|
+
|
|
275
|
+
function setBuildingLevels() {
|
|
276
|
+
unitLabels.value.length = 0;
|
|
277
|
+
for (let index = 0; index < buildingUnitQty.value; index++) {
|
|
278
|
+
unitLabels.value.push(`Unit ${index + 1}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const name = ref("");
|
|
283
|
+
const directorName = ref("");
|
|
284
|
+
const createMore = ref(false);
|
|
285
|
+
const disable = ref(false);
|
|
286
|
+
|
|
287
|
+
const { requiredRule } = useUtils();
|
|
288
|
+
|
|
289
|
+
const message = ref("");
|
|
290
|
+
|
|
291
|
+
const { add, categories: unitCategories } = useBuildingUnit();
|
|
292
|
+
|
|
293
|
+
function setBuildingUnit() {
|
|
294
|
+
buildingUnit.value.site = prop.site ?? "";
|
|
295
|
+
buildingUnit.value.name = "Unit";
|
|
296
|
+
buildingUnit.value.building = "";
|
|
297
|
+
buildingUnit.value.buildingName = "";
|
|
298
|
+
buildingUnit.value.level = "";
|
|
299
|
+
buildingUnit.value.category = "";
|
|
300
|
+
buildingUnit.value.status = "active";
|
|
301
|
+
buildingUnit.value.buildingUnitFiles = []
|
|
302
|
+
buildingUnitQty.value = 1;
|
|
303
|
+
message.value = "";
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async function submit() {
|
|
307
|
+
disable.value = true;
|
|
308
|
+
try {
|
|
309
|
+
await add({
|
|
310
|
+
labels: unitLabels.value,
|
|
311
|
+
unit: buildingUnit.value,
|
|
312
|
+
qty: buildingUnitQty.value,
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
if (createMore.value) {
|
|
316
|
+
setBuildingUnit();
|
|
317
|
+
message.value = "";
|
|
318
|
+
emit("success:create-more");
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
emit("success");
|
|
323
|
+
} catch (error: any) {
|
|
324
|
+
message.value =
|
|
325
|
+
error.response?._data?.message || "Failed to create building";
|
|
326
|
+
} finally {
|
|
327
|
+
disable.value = false;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function cancel() {
|
|
332
|
+
name.value = "";
|
|
333
|
+
directorName.value = "";
|
|
334
|
+
createMore.value = false;
|
|
335
|
+
message.value = "";
|
|
336
|
+
emit("cancel");
|
|
337
|
+
}
|
|
338
|
+
</script>
|
|
@@ -0,0 +1,278 @@
|
|
|
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"> Edit Unit </span>
|
|
6
|
+
</v-row>
|
|
7
|
+
</v-toolbar>
|
|
8
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto">
|
|
9
|
+
<v-form v-model="validForm" :disabled="disable">
|
|
10
|
+
<v-row no-gutters>
|
|
11
|
+
<v-col cols="12">
|
|
12
|
+
<v-row>
|
|
13
|
+
<v-col cols="12" class="mt-2">
|
|
14
|
+
<v-row no-gutters>
|
|
15
|
+
<InputLabel
|
|
16
|
+
class="text-capitalize font-weight-bold"
|
|
17
|
+
title="Building"
|
|
18
|
+
/>
|
|
19
|
+
<v-col cols="12">
|
|
20
|
+
{{ buildingUnit.buildingName }}
|
|
21
|
+
</v-col>
|
|
22
|
+
</v-row>
|
|
23
|
+
</v-col>
|
|
24
|
+
</v-row>
|
|
25
|
+
</v-col>
|
|
26
|
+
|
|
27
|
+
<v-col cols="12">
|
|
28
|
+
<v-row>
|
|
29
|
+
<v-col cols="12" class="mt-2">
|
|
30
|
+
<v-row no-gutters>
|
|
31
|
+
<InputLabel
|
|
32
|
+
class="text-capitalize font-weight-bold"
|
|
33
|
+
title="Block"
|
|
34
|
+
/>
|
|
35
|
+
<v-col cols="12">
|
|
36
|
+
{{ buildingUnit.block }}
|
|
37
|
+
</v-col>
|
|
38
|
+
</v-row>
|
|
39
|
+
</v-col>
|
|
40
|
+
</v-row>
|
|
41
|
+
</v-col>
|
|
42
|
+
|
|
43
|
+
<v-col cols="12">
|
|
44
|
+
<v-row>
|
|
45
|
+
<v-col cols="12" class="mt-2">
|
|
46
|
+
<v-row no-gutters>
|
|
47
|
+
<InputLabel
|
|
48
|
+
class="text-capitalize font-weight-bold"
|
|
49
|
+
title="Unit Name"
|
|
50
|
+
/>
|
|
51
|
+
<v-col cols="12">
|
|
52
|
+
<v-text-field
|
|
53
|
+
v-model="buildingUnit.name"
|
|
54
|
+
density="comfortable"
|
|
55
|
+
:rules="[requiredRule]"
|
|
56
|
+
></v-text-field>
|
|
57
|
+
</v-col>
|
|
58
|
+
</v-row>
|
|
59
|
+
</v-col>
|
|
60
|
+
</v-row>
|
|
61
|
+
</v-col>
|
|
62
|
+
|
|
63
|
+
<v-col cols="12" class="mt-2">
|
|
64
|
+
<v-row no-gutters>
|
|
65
|
+
<InputLabel
|
|
66
|
+
class="text-capitalize font-weight-bold"
|
|
67
|
+
title="Category"
|
|
68
|
+
required
|
|
69
|
+
/>
|
|
70
|
+
<v-col cols="12">
|
|
71
|
+
<v-autocomplete
|
|
72
|
+
v-model="buildingUnit.category"
|
|
73
|
+
:items="unitCategories"
|
|
74
|
+
density="comfortable"
|
|
75
|
+
:rules="[requiredRule]"
|
|
76
|
+
></v-autocomplete>
|
|
77
|
+
</v-col>
|
|
78
|
+
</v-row>
|
|
79
|
+
</v-col>
|
|
80
|
+
|
|
81
|
+
<v-col cols="12">
|
|
82
|
+
<v-row>
|
|
83
|
+
<v-col cols="6" class="mt-2">
|
|
84
|
+
<v-row no-gutters>
|
|
85
|
+
<InputLabel
|
|
86
|
+
class="text-capitalize font-weight-bold"
|
|
87
|
+
title="Level"
|
|
88
|
+
required
|
|
89
|
+
/>
|
|
90
|
+
<v-col cols="12">
|
|
91
|
+
<v-select
|
|
92
|
+
v-model="buildingUnit.level"
|
|
93
|
+
:items="buildingLevels"
|
|
94
|
+
density="comfortable"
|
|
95
|
+
:rules="[requiredRule]"
|
|
96
|
+
></v-select>
|
|
97
|
+
</v-col>
|
|
98
|
+
</v-row>
|
|
99
|
+
</v-col>
|
|
100
|
+
</v-row>
|
|
101
|
+
</v-col>
|
|
102
|
+
|
|
103
|
+
<v-col cols="12" class="mt-5">
|
|
104
|
+
<InputLabel class="text-capitalize" title="Upload Files (Lease of Contract, Cert. of Occupancy)" />
|
|
105
|
+
<InputFileV2 v-model="buildingUnit.buildingUnitFiles" :multiple="false" :max-length="10" title="Upload PDF Files" accept="application/pdf" />
|
|
106
|
+
</v-col>
|
|
107
|
+
|
|
108
|
+
<v-col cols="12" class="my-2">
|
|
109
|
+
<v-row no-gutters>
|
|
110
|
+
<v-col cols="12" class="text-center">
|
|
111
|
+
<span
|
|
112
|
+
class="text-none text-subtitle-2 font-weight-medium text-error"
|
|
113
|
+
>
|
|
114
|
+
{{ message }}
|
|
115
|
+
</span>
|
|
116
|
+
</v-col>
|
|
117
|
+
</v-row>
|
|
118
|
+
</v-col>
|
|
119
|
+
</v-row>
|
|
120
|
+
</v-form>
|
|
121
|
+
</v-card-text>
|
|
122
|
+
|
|
123
|
+
<v-toolbar density="compact">
|
|
124
|
+
<v-row no-gutters>
|
|
125
|
+
<v-col cols="6">
|
|
126
|
+
<v-btn
|
|
127
|
+
tile
|
|
128
|
+
block
|
|
129
|
+
variant="text"
|
|
130
|
+
class="text-none"
|
|
131
|
+
size="48"
|
|
132
|
+
@click="cancel"
|
|
133
|
+
>
|
|
134
|
+
Cancel
|
|
135
|
+
</v-btn>
|
|
136
|
+
</v-col>
|
|
137
|
+
|
|
138
|
+
<v-col cols="6">
|
|
139
|
+
<v-btn
|
|
140
|
+
tile
|
|
141
|
+
block
|
|
142
|
+
variant="flat"
|
|
143
|
+
color="black"
|
|
144
|
+
class="text-none"
|
|
145
|
+
size="48"
|
|
146
|
+
:disabled="!validForm || !hasChanges || disable"
|
|
147
|
+
@click="submit"
|
|
148
|
+
:loading="disable"
|
|
149
|
+
>
|
|
150
|
+
Submit
|
|
151
|
+
</v-btn>
|
|
152
|
+
</v-col>
|
|
153
|
+
</v-row>
|
|
154
|
+
</v-toolbar>
|
|
155
|
+
</v-card>
|
|
156
|
+
</template>
|
|
157
|
+
|
|
158
|
+
<script setup lang="ts">
|
|
159
|
+
const prop = defineProps({
|
|
160
|
+
site: {
|
|
161
|
+
type: String,
|
|
162
|
+
default: "",
|
|
163
|
+
},
|
|
164
|
+
roomFacility: {
|
|
165
|
+
type: Object as PropType<TBuildingUnit>,
|
|
166
|
+
default: () => ({
|
|
167
|
+
_id: "",
|
|
168
|
+
site: "",
|
|
169
|
+
name: "",
|
|
170
|
+
building: "",
|
|
171
|
+
buildingName: "",
|
|
172
|
+
category: "",
|
|
173
|
+
block: null,
|
|
174
|
+
level: 0,
|
|
175
|
+
status: "active",
|
|
176
|
+
buildingUnitFiles: []
|
|
177
|
+
}),
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const buildingUnit = ref({
|
|
182
|
+
_id: "",
|
|
183
|
+
site: "",
|
|
184
|
+
name: "",
|
|
185
|
+
building: "",
|
|
186
|
+
buildingName: "",
|
|
187
|
+
level: 0,
|
|
188
|
+
category: "",
|
|
189
|
+
block: null,
|
|
190
|
+
status: "active",
|
|
191
|
+
buildingUnitFiles: []
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
buildingUnit.value = JSON.parse(JSON.stringify(prop.roomFacility));
|
|
195
|
+
|
|
196
|
+
const emit = defineEmits(["cancel", "success", "success:create-more"]);
|
|
197
|
+
|
|
198
|
+
const validForm = ref(false);
|
|
199
|
+
|
|
200
|
+
const { getAll } = useBuilding();
|
|
201
|
+
|
|
202
|
+
const buildings = ref<Record<string, any>[]>([]);
|
|
203
|
+
|
|
204
|
+
const { data: getBuildingReq } = useLazyAsyncData(
|
|
205
|
+
"get-all-buildings",
|
|
206
|
+
async () => getAll({ site: prop.site, status: "active" })
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
watchEffect(() => {
|
|
210
|
+
if (getBuildingReq.value) {
|
|
211
|
+
buildings.value = getBuildingReq.value.items.map((building: TBuilding) => ({
|
|
212
|
+
title: building.name,
|
|
213
|
+
value: building._id,
|
|
214
|
+
levels: building.levels,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
buildingUnit.value.site = prop.site;
|
|
220
|
+
|
|
221
|
+
const selectedBuilding = computed(() => {
|
|
222
|
+
return buildings.value.find((b) => b.value === buildingUnit.value.building);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const buildingLevels = computed(() => {
|
|
226
|
+
return Array.from(
|
|
227
|
+
{ length: selectedBuilding.value?.levels || 0 },
|
|
228
|
+
(_, i) => i + 1
|
|
229
|
+
);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const disable = ref(false);
|
|
233
|
+
|
|
234
|
+
const { requiredRule } = useUtils();
|
|
235
|
+
|
|
236
|
+
const message = ref("");
|
|
237
|
+
|
|
238
|
+
const { updateById, categories: unitCategories } = useBuildingUnit();
|
|
239
|
+
|
|
240
|
+
function arraysAreEqual(a: any[], b: any[]): boolean {
|
|
241
|
+
return a.length === b.length && a.every((val, index) => val === b[index]);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
const hasChanges = computed(() => {
|
|
247
|
+
return (
|
|
248
|
+
prop.roomFacility.name !== buildingUnit.value.name ||
|
|
249
|
+
prop.roomFacility.category !== buildingUnit.value.category ||
|
|
250
|
+
prop.roomFacility.level !== buildingUnit.value.level ||
|
|
251
|
+
!arraysAreEqual(prop.roomFacility.buildingUnitFiles, buildingUnit.value.buildingUnitFiles)
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
async function submit() {
|
|
256
|
+
disable.value = true;
|
|
257
|
+
try {
|
|
258
|
+
await updateById(buildingUnit.value._id ?? "", {
|
|
259
|
+
name: buildingUnit.value.name,
|
|
260
|
+
level: buildingUnit.value.level,
|
|
261
|
+
category: buildingUnit.value.category,
|
|
262
|
+
buildingUnitFiles: buildingUnit.value.buildingUnitFiles || []
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
emit("success");
|
|
266
|
+
} catch (error: any) {
|
|
267
|
+
message.value =
|
|
268
|
+
error.response?._data?.message || "Failed to create building";
|
|
269
|
+
} finally {
|
|
270
|
+
disable.value = false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function cancel() {
|
|
275
|
+
message.value = "";
|
|
276
|
+
emit("cancel");
|
|
277
|
+
}
|
|
278
|
+
</script>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
:placeholder="placeholder"
|
|
7
7
|
:counter="maxlength"
|
|
8
8
|
@input="onInput"
|
|
9
|
+
:loading="loading"
|
|
9
10
|
outlined
|
|
10
11
|
clearable
|
|
11
12
|
/>
|
|
@@ -25,9 +26,15 @@ const props = defineProps({
|
|
|
25
26
|
maxlength: {
|
|
26
27
|
type: [Number, String],
|
|
27
28
|
default: false
|
|
29
|
+
},
|
|
30
|
+
loading: {
|
|
31
|
+
type: Boolean,
|
|
32
|
+
default: false
|
|
28
33
|
}
|
|
29
34
|
})
|
|
30
35
|
|
|
36
|
+
const emit = defineEmits(['update:modelValue'])
|
|
37
|
+
|
|
31
38
|
const model = defineModel({required: true, default: ""})
|
|
32
39
|
|
|
33
40
|
function onInput(event) {
|
|
@@ -38,4 +45,9 @@ function onInput(event) {
|
|
|
38
45
|
|
|
39
46
|
model.value = formatted
|
|
40
47
|
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
watch(model, (newVal) => {
|
|
51
|
+
emit('update:modelValue:', newVal)
|
|
52
|
+
})
|
|
41
53
|
</script>
|
package/components/TableMain.vue
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<!-- Data Table -->
|
|
44
44
|
<v-data-table :headers="headers" :items="items" :item-value="itemValue" :items-per-page="itemsPerPage"
|
|
45
45
|
fixed-header hide-default-footer :hide-default-header="!showHeader"
|
|
46
|
-
@click:row="(_: any, data: any) => emits('row-click', data)" style="max-height: calc(100vh - (
|
|
46
|
+
@click:row="(_: any, data: any) => emits('row-click', data)" :style="`max-height: calc(100vh - (${offset}px))`">
|
|
47
47
|
<template v-for="(_, slotName) in $slots" #[slotName]="slotProps">
|
|
48
48
|
<slot :name="slotName" v-bind="slotProps" />
|
|
49
49
|
</template>
|
|
@@ -103,6 +103,10 @@ const props = defineProps({
|
|
|
103
103
|
extensionHeight: {
|
|
104
104
|
type: Number,
|
|
105
105
|
default: 50
|
|
106
|
+
},
|
|
107
|
+
offset: {
|
|
108
|
+
type: Number,
|
|
109
|
+
default: 200
|
|
106
110
|
}
|
|
107
111
|
});
|
|
108
112
|
|