@7365admin1/layer-common 1.10.3 → 1.10.5
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/AccessCardDeleteDialog.vue +109 -0
- package/components/AccessCardHistoryDialog.vue +133 -0
- package/components/AccessCardPreviewDialog.vue +308 -0
- package/components/AccessCardQrTagging.vue +183 -0
- package/components/AccessCardReplaceForm.vue +179 -0
- package/components/AccessManagement.vue +61 -251
- package/components/AreaChecklistHistoryLogs.vue +1 -1
- package/components/BuildingManagement/units.vue +33 -2
- package/components/BuildingUnitFormAdd.vue +45 -99
- package/components/BuildingUnitFormEdit.vue +59 -148
- package/components/BulletinBoardManagement.vue +6 -1
- package/components/BulletinBoardView.vue +2 -2
- package/components/Button/Close.vue +3 -1
- package/components/CleaningScheduleMain.vue +20 -9
- package/components/IncidentReport/IncidentInformation.vue +45 -6
- package/components/IncidentReport/affectedEntities.vue +29 -0
- package/components/PeopleForm.vue +1 -1
- package/components/PlateNumberDisplay.vue +45 -0
- package/components/ScheduleAreaMain.vue +5 -2
- package/components/ScheduleTaskForm.vue +59 -114
- package/components/ScheduleTaskMain.vue +19 -15
- package/components/VehicleAddSelection.vue +58 -0
- package/components/VehicleForm.vue +600 -0
- package/components/VehicleManagement.vue +298 -0
- package/components/VisitorForm.vue +1 -1
- package/composables/useAccessManagement.ts +16 -0
- package/composables/useBulletin.ts +11 -9
- package/composables/useCard.ts +14 -0
- package/composables/useScheduleTask.ts +4 -8
- package/composables/useVehicle.ts +114 -0
- package/package.json +1 -1
- package/types/bulletin-board.d.ts +1 -1
- package/types/checkout-item.d.ts +1 -0
- package/types/cleaner-schedule.d.ts +1 -1
- package/types/people.d.ts +1 -1
- package/types/vehicle.d.ts +43 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters>
|
|
3
|
+
<TableMain :headers="headers" :items="items" :loading="loading || getVehiclesPending" :page="page" :pages="pages"
|
|
4
|
+
:pageRange="pageRange" :extension-height="70" :canCreate="canCreateVehicle" @refresh="getVehiclesRefresh"
|
|
5
|
+
createLabel="Add Vehicle" show-header @row-click="handleRowClick" @create="dialog.showSelection = true"
|
|
6
|
+
@update:page="handleUpdatePage">
|
|
7
|
+
|
|
8
|
+
<template #extension>
|
|
9
|
+
<v-row no-gutters class="px-5 py-1 d-flex align-center justify-end ga-3">
|
|
10
|
+
<v-text-field v-model="searchInput" density="compact" placeholder="Search" clearable max-width="300"
|
|
11
|
+
append-inner-icon="mdi-magnify" hide-details />
|
|
12
|
+
<v-select v-model="vehicleType" density="compact" item-title="label" item-value="value"
|
|
13
|
+
placeholder="Filter by Type" clearable max-width="200" hide-details :items="typeOptions" />
|
|
14
|
+
</v-row>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<template #item.block="{ value }">
|
|
18
|
+
{{ value ? `blk ${value}` : "" }}
|
|
19
|
+
</template>
|
|
20
|
+
<template #item.status="{ value }">
|
|
21
|
+
<v-chip :color="formatVehicleStatus(value).color" size="x-small" dark>
|
|
22
|
+
{{ formatVehicleStatus(value).label }}
|
|
23
|
+
</v-chip>
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<template #item.plateNumbers="{ value, item }">
|
|
29
|
+
<PlateNumberDisplay :plate-numbers="value" :default-value="item.plateNumber" />
|
|
30
|
+
</template>
|
|
31
|
+
</TableMain>
|
|
32
|
+
|
|
33
|
+
<!-- <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" /> -->
|
|
34
|
+
|
|
35
|
+
<v-dialog v-model="dialog.showSelection" width="450" persistent>
|
|
36
|
+
<VehicleAddSelection @cancel="dialog.showSelection = false" @select="handleSelectVehicleStatus" />
|
|
37
|
+
</v-dialog>
|
|
38
|
+
|
|
39
|
+
<v-dialog v-model="dialog.createVehicle" v-if="vehicleType" width="450" persistent>
|
|
40
|
+
<VehicleForm :type="vehicleType" mode="add" @back="handleBackToSelection" @done="handleAddVehicleComplete"
|
|
41
|
+
:org="org" :site="props.site" @close:all="handleCloseAll" />
|
|
42
|
+
</v-dialog>
|
|
43
|
+
|
|
44
|
+
<v-dialog v-model="dialog.updateVehicle" v-if="vehicleType" width="450" persistent>
|
|
45
|
+
<VehicleForm :type="vehicleType" mode="edit" :vehicle-data="selectedVehicleObject"
|
|
46
|
+
@back="dialog.updateVehicle = false" @close="dialog.updateVehicle = false" @done="handleUpdateVehicleComplete"
|
|
47
|
+
:org="org" :site="site" @close:all="handleCloseAll" />
|
|
48
|
+
</v-dialog>
|
|
49
|
+
|
|
50
|
+
<v-dialog v-if="canViewVehicleDetails" v-model="dialog.showMoreActions" width="450" persistent>
|
|
51
|
+
<DialogUpdateMoreAction title="Preview" :can-update="canUpdateVehicle" :can-delete="canDeleteVehicle"
|
|
52
|
+
@close="dialog.showMoreActions = false" edit-button-label="Edit Vehicle" delete-button-label="Delete Vehicle"
|
|
53
|
+
@delete="handleDeleteVehicleAction" @edit="handleEditVehicleAction">
|
|
54
|
+
<template v-slot:content>
|
|
55
|
+
<v-row no-gutters class="ga-1 mb-5">
|
|
56
|
+
|
|
57
|
+
<template v-for="(label, key) in formattedFields" :key="key">
|
|
58
|
+
<v-col v-if="key === 'plateNumbers'" class="d-flex ga-2">
|
|
59
|
+
<span class="d-flex ga-3 align-center"><strong>{{ label }}:</strong></span>
|
|
60
|
+
<PlateNumberDisplay :plate-numbers="selectedVehicleObject[key]" :default-value="selectedVehicleObject.plateNumber" />
|
|
61
|
+
</v-col>
|
|
62
|
+
|
|
63
|
+
<v-col v-else-if="selectedVehicleObject[key]" cols="12">
|
|
64
|
+
<span class="d-flex ga-3 align-center"><strong>{{ label }}:</strong> {{ formatValues(key,
|
|
65
|
+
selectedVehicleObject[key])
|
|
66
|
+
}}</span>
|
|
67
|
+
</v-col>
|
|
68
|
+
</template>
|
|
69
|
+
</v-row>
|
|
70
|
+
</template>
|
|
71
|
+
</DialogUpdateMoreAction>
|
|
72
|
+
</v-dialog>
|
|
73
|
+
<v-dialog v-model="dialog.deleteVehicle" persistent width="540">
|
|
74
|
+
<DialogDeleteConfirmation :message="message" prompt-title="Are you sure want to delete this vehicle?"
|
|
75
|
+
@delete="submitDelete" @close="closeDeleteDialog" />
|
|
76
|
+
</v-dialog>
|
|
77
|
+
</v-row>
|
|
78
|
+
</template>
|
|
79
|
+
|
|
80
|
+
<script lang="ts" setup>
|
|
81
|
+
import useVehicle from '../composables/useVehicle';
|
|
82
|
+
|
|
83
|
+
definePageMeta({
|
|
84
|
+
middleware: ["01-auth", "02-org"],
|
|
85
|
+
memberOnly: true,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
const props = defineProps({
|
|
90
|
+
canCreateVehicle: { type: Boolean, default: false },
|
|
91
|
+
canUpdateVehicle: { type: Boolean, default: true },
|
|
92
|
+
canDeleteVehicle: { type: Boolean, default: true },
|
|
93
|
+
canViewVehicleDetails: { type: Boolean, default: true },
|
|
94
|
+
site: { type: String, required: true },
|
|
95
|
+
org: { type: String, required: true },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
const headers = [
|
|
100
|
+
{ title: "Name", value: "name" },
|
|
101
|
+
// { title: "Building", value: "buildingName" },
|
|
102
|
+
{ title: "Vehicle Numbers", value: "plateNumbers" },
|
|
103
|
+
{ title: "NRIC", value: "nric" },
|
|
104
|
+
{ title: "Block", value: "block" },
|
|
105
|
+
{ title: "Floor", value: "level" },
|
|
106
|
+
{ title: "Category", value: "category" },
|
|
107
|
+
{ title: "Type", value: "type" },
|
|
108
|
+
{ title: "Status", value: "status" },
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
const { formatCamelCaseToWords, formatDate, debounce } = useUtils();
|
|
114
|
+
const { getVehicles, deleteVehicle, formatVehicleStatus } = useVehicle();
|
|
115
|
+
|
|
116
|
+
const items = ref<Array<Record<string, any>>>([]);
|
|
117
|
+
const page = ref(1);
|
|
118
|
+
const pages = ref(0);
|
|
119
|
+
const pageRange = ref("-- - -- of --");
|
|
120
|
+
|
|
121
|
+
const searchInput = ref("")
|
|
122
|
+
|
|
123
|
+
const loading = ref(false);
|
|
124
|
+
const selectedVehicleId = ref<string | null>(null)
|
|
125
|
+
const vehicleType = ref<TVehicleType | null>(null);
|
|
126
|
+
|
|
127
|
+
const message = ref("");
|
|
128
|
+
const messageColor = ref("");
|
|
129
|
+
const messageSnackbar = ref(false);
|
|
130
|
+
const bypass = ref(false);
|
|
131
|
+
|
|
132
|
+
function showMessage(msg: string, color: string) {
|
|
133
|
+
message.value = msg;
|
|
134
|
+
messageColor.value = color;
|
|
135
|
+
messageSnackbar.value = true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const dialog = reactive({
|
|
139
|
+
createVehicle: false,
|
|
140
|
+
updateVehicle: false,
|
|
141
|
+
showSelection: false,
|
|
142
|
+
deleteVehicle: false,
|
|
143
|
+
showMoreActions: false,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const typeOptions = [
|
|
147
|
+
{ label: "Whitelist", value: "whitelist" },
|
|
148
|
+
{ label: "Blocklist", value: "blocklist" },
|
|
149
|
+
{ label: "Season Pass", value: "seasonPass" },
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
const formattedFields: Partial<Record<keyof TVehicle, string>> = {
|
|
153
|
+
name: "Name",
|
|
154
|
+
plateNumbers: "Vehicle Numbers",
|
|
155
|
+
phoneNumber: "Phone Number",
|
|
156
|
+
nric: "NRIC",
|
|
157
|
+
block: "Block",
|
|
158
|
+
level: "Level",
|
|
159
|
+
unit: "Unit",
|
|
160
|
+
start: "Start",
|
|
161
|
+
end: "End",
|
|
162
|
+
category: "Category",
|
|
163
|
+
type: "Type",
|
|
164
|
+
remarks: "Remarks",
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function formatValues(key: string, value: any) {
|
|
168
|
+
if (!value) return ""
|
|
169
|
+
switch (key) {
|
|
170
|
+
case "start":
|
|
171
|
+
return formatDate(value)
|
|
172
|
+
case "end":
|
|
173
|
+
return formatDate(value)
|
|
174
|
+
case "type":
|
|
175
|
+
case "category":
|
|
176
|
+
return String(value).charAt(0).toUpperCase() + String(value).slice(1).toLowerCase();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const closeDeleteDialog = () => {
|
|
183
|
+
dialog.deleteVehicle = false;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const handleCloseAll = () => {
|
|
187
|
+
dialog.createVehicle = false;
|
|
188
|
+
dialog.updateVehicle = false;
|
|
189
|
+
dialog.showSelection = false;
|
|
190
|
+
vehicleType.value = null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const selectedVehicleObject = computed(() => {
|
|
194
|
+
return items.value.find(item => item?._id === selectedVehicleId.value) || {}
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
const { data: getVehiclesReq, refresh: getVehiclesRefresh, pending: getVehiclesPending } =
|
|
198
|
+
await useLazyAsyncData(
|
|
199
|
+
"get-all-vehicles",
|
|
200
|
+
() =>
|
|
201
|
+
getVehicles({
|
|
202
|
+
page: page.value,
|
|
203
|
+
search: searchInput.value,
|
|
204
|
+
type: vehicleType.value ?? "",
|
|
205
|
+
}),
|
|
206
|
+
{
|
|
207
|
+
watch: [page],
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
watch(getVehiclesReq, (newData: any) => {
|
|
213
|
+
items.value = newData?.items || [];
|
|
214
|
+
pages.value = newData?.pages || 0;
|
|
215
|
+
pageRange.value = newData?.pageRange || "-- - -- of --";
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
function handleRowClick(data: any) {
|
|
219
|
+
selectedVehicleId.value = data?.item?._id;
|
|
220
|
+
dialog.showMoreActions = true;
|
|
221
|
+
message.value = "";
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function handleEditVehicleAction() {
|
|
225
|
+
vehicleType.value = selectedVehicleObject.value?.type || null;
|
|
226
|
+
dialog.showSelection = false;
|
|
227
|
+
dialog.updateVehicle = true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function handleDeleteVehicleAction() {
|
|
231
|
+
dialog.showMoreActions = false;
|
|
232
|
+
dialog.deleteVehicle = true;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function handleSelectVehicleStatus(value: TVehicleType) {
|
|
236
|
+
vehicleType.value = value;
|
|
237
|
+
dialog.showSelection = false;
|
|
238
|
+
dialog.createVehicle = true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function handleBackToSelection() {
|
|
242
|
+
dialog.showSelection = true;
|
|
243
|
+
dialog.createVehicle = false;
|
|
244
|
+
vehicleType.value = null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function handleAddVehicleComplete() {
|
|
248
|
+
dialog.showSelection = false;
|
|
249
|
+
dialog.createVehicle = false;
|
|
250
|
+
vehicleType.value = null;
|
|
251
|
+
getVehiclesRefresh();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function handleUpdateVehicleComplete() {
|
|
255
|
+
dialog.showSelection = false;
|
|
256
|
+
dialog.updateVehicle = false;
|
|
257
|
+
dialog.showMoreActions = false;
|
|
258
|
+
vehicleType.value = null;
|
|
259
|
+
getVehiclesRefresh();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function handleUpdatePage(newPageNum: number) {
|
|
263
|
+
page.value = newPageNum;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const formatPlateNumbers = (value: any) => {
|
|
267
|
+
if (!value || value.length === 0) return "";
|
|
268
|
+
|
|
269
|
+
const firstTwo = value.slice(0, 2).map((item: any) => item.plateNumber || "");
|
|
270
|
+
return firstTwo.join(", ");
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
async function submitDelete() {
|
|
274
|
+
bypass.value = false;
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
const res = await deleteVehicle({ site: props.site, id: selectedVehicleId.value as string, recno: selectedVehicleObject.value.recno, type: selectedVehicleObject.value.type }
|
|
278
|
+
);
|
|
279
|
+
dialog.deleteVehicle = false;
|
|
280
|
+
dialog.showMoreActions = false;
|
|
281
|
+
selectedVehicleId.value = null
|
|
282
|
+
showMessage(res.message, "success");
|
|
283
|
+
getVehiclesRefresh();
|
|
284
|
+
} catch (error: any) {
|
|
285
|
+
console.error("Error deleting vehicle:", error);
|
|
286
|
+
message.value = error.response._data.message;
|
|
287
|
+
bypass.value = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const debouncedSearch = debounce(getVehiclesRefresh, 500);
|
|
292
|
+
watch([searchInput, vehicleType], () => {
|
|
293
|
+
page.value = 1;
|
|
294
|
+
debouncedSearch()
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
</script>
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
<v-col v-if="shouldShowField('nric')" cols="12">
|
|
55
55
|
<v-row>
|
|
56
56
|
<v-col cols="12">
|
|
57
|
-
<InputLabel class="text-capitalize" title="NRIC
|
|
57
|
+
<InputLabel class="text-capitalize" title="NRIC" required />
|
|
58
58
|
<InputNRICNumber v-model="visitor.nric" density="comfortable" :rules="[requiredRule]"
|
|
59
59
|
@update:model-value="handleUpdateNRIC" :loading="fetchPersonByNRICPending" />
|
|
60
60
|
</v-col>
|
|
@@ -148,6 +148,20 @@ export default function useAccessManagement() {
|
|
|
148
148
|
);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
function deleteCard(payload: { cardId: string; remarks: string }) {
|
|
152
|
+
return useNuxtApp().$api(`/api/access-management/delete-card`, {
|
|
153
|
+
method: "PATCH",
|
|
154
|
+
body: payload,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function getCardHistory(cardId: string) {
|
|
159
|
+
return useNuxtApp().$api<Record<string, any>[]>(
|
|
160
|
+
`/api/access-management/card-history/${cardId}`,
|
|
161
|
+
{ method: "GET" }
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
151
165
|
return {
|
|
152
166
|
getDoorAccessLevels,
|
|
153
167
|
getLiftAccessLevels,
|
|
@@ -159,5 +173,7 @@ export default function useAccessManagement() {
|
|
|
159
173
|
bulkPhysicalAccessCard,
|
|
160
174
|
assignAccessCard,
|
|
161
175
|
getAvailableAccessCards,
|
|
176
|
+
deleteCard,
|
|
177
|
+
getCardHistory,
|
|
162
178
|
};
|
|
163
179
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export default function(){
|
|
2
2
|
|
|
3
3
|
const recipientList: { title: string, value: TAnnouncementRecipients }[] = [
|
|
4
|
-
|
|
5
|
-
{ title: "
|
|
6
|
-
{ title: "
|
|
7
|
-
{ title: "
|
|
8
|
-
{ title: "
|
|
4
|
+
// resident | security_agency | cleaning_services | mechanical_electrical | property_management_agency
|
|
5
|
+
{ title: "Security Agency", value: "security_agency" },
|
|
6
|
+
{ title: "Cleaning Services", value: "cleaning_services" },
|
|
7
|
+
{ title: "Mechanical & Electrical", value: "mechanical_electrical" },
|
|
8
|
+
{ title: "Property Management Agency", value: "property_management_agency" },
|
|
9
9
|
{ title: "Resident", value: "resident" }
|
|
10
10
|
]
|
|
11
11
|
|
|
@@ -29,7 +29,8 @@ export default function(){
|
|
|
29
29
|
sort?: 'asc' | 'desc';
|
|
30
30
|
site?: string;
|
|
31
31
|
status?: TAnnouncementStatus;
|
|
32
|
-
search?: string
|
|
32
|
+
search?: string;
|
|
33
|
+
recipients?: TAnnouncementRecipients;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
async function getAll({
|
|
@@ -38,7 +39,8 @@ export default function(){
|
|
|
38
39
|
sort = "asc",
|
|
39
40
|
site,
|
|
40
41
|
status,
|
|
41
|
-
search
|
|
42
|
+
search,
|
|
43
|
+
recipients
|
|
42
44
|
} : TGetAllParams) {
|
|
43
45
|
return await useNuxtApp().$api<Record<string, any>>(
|
|
44
46
|
"/api/bulletin-boards",
|
|
@@ -50,8 +52,8 @@ export default function(){
|
|
|
50
52
|
sort,
|
|
51
53
|
site,
|
|
52
54
|
status,
|
|
53
|
-
search
|
|
54
|
-
|
|
55
|
+
search,
|
|
56
|
+
recipients
|
|
55
57
|
},
|
|
56
58
|
}
|
|
57
59
|
);
|
package/composables/useCard.ts
CHANGED
|
@@ -39,10 +39,24 @@ export default function useCard() {
|
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function replaceCard(payload: {
|
|
43
|
+
cardId: string;
|
|
44
|
+
issuedCardId: string;
|
|
45
|
+
unitId: string;
|
|
46
|
+
remarks: string;
|
|
47
|
+
userId: string;
|
|
48
|
+
}) {
|
|
49
|
+
return useNuxtApp().$api("/api/access-management/card-replacement", {
|
|
50
|
+
method: "POST",
|
|
51
|
+
body: payload,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
return {
|
|
43
56
|
getAll,
|
|
44
57
|
add,
|
|
45
58
|
deleteById,
|
|
46
59
|
updateById,
|
|
60
|
+
replaceCard,
|
|
47
61
|
};
|
|
48
62
|
}
|
|
@@ -31,8 +31,7 @@ export default function useScheduleTask() {
|
|
|
31
31
|
function createScheduleTask(payload: {
|
|
32
32
|
title: string;
|
|
33
33
|
time: string;
|
|
34
|
-
|
|
35
|
-
endDate?: string;
|
|
34
|
+
dates: string[];
|
|
36
35
|
description?: string;
|
|
37
36
|
areas: { name: string; value: string }[];
|
|
38
37
|
site: string;
|
|
@@ -44,8 +43,7 @@ export default function useScheduleTask() {
|
|
|
44
43
|
body: {
|
|
45
44
|
title: payload.title,
|
|
46
45
|
time: payload.time,
|
|
47
|
-
|
|
48
|
-
endDate: payload.endDate,
|
|
46
|
+
dates: payload.dates,
|
|
49
47
|
description: payload.description,
|
|
50
48
|
areas: payload.areas,
|
|
51
49
|
},
|
|
@@ -58,8 +56,7 @@ export default function useScheduleTask() {
|
|
|
58
56
|
payload: {
|
|
59
57
|
title: string;
|
|
60
58
|
time: string;
|
|
61
|
-
|
|
62
|
-
endDate?: string;
|
|
59
|
+
dates: string[];
|
|
63
60
|
description?: string;
|
|
64
61
|
areas: { name: string; value: string }[];
|
|
65
62
|
},
|
|
@@ -71,8 +68,7 @@ export default function useScheduleTask() {
|
|
|
71
68
|
body: {
|
|
72
69
|
title: payload.title,
|
|
73
70
|
time: payload.time,
|
|
74
|
-
|
|
75
|
-
endDate: payload.endDate,
|
|
71
|
+
dates: payload.dates,
|
|
76
72
|
description: payload.description,
|
|
77
73
|
areas: payload.areas,
|
|
78
74
|
},
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export default function useVehicle() {
|
|
2
|
+
async function getVehicles({
|
|
3
|
+
search = "",
|
|
4
|
+
page = 1,
|
|
5
|
+
limit = 10,
|
|
6
|
+
sort = "asc",
|
|
7
|
+
order = "",
|
|
8
|
+
type = "",
|
|
9
|
+
category = "",
|
|
10
|
+
} = {}) {
|
|
11
|
+
return await useNuxtApp().$api<Record<string, any>>("/api/vehicles", {
|
|
12
|
+
method: "GET",
|
|
13
|
+
query: { search, page, limit, sort, order, type, category },
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function getVehicleById(id: string) {
|
|
18
|
+
return await useNuxtApp().$api<Record<string, any>>(`/api/vehicles/${id}`, {
|
|
19
|
+
method: "GET",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function addVehicle(payload: Partial<TVehiclePayload>) {
|
|
24
|
+
return await useNuxtApp().$api<Record<string, any>>("/api/vehicles", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
body: payload,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function updateVehicle(id: string, payload: Partial<TVehiclePayload>) {
|
|
31
|
+
return await useNuxtApp().$api<Record<string, any>>(`/api/vehicles/${id}`, {
|
|
32
|
+
method: "PUT",
|
|
33
|
+
body: payload,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function getCustomSeasonPassTypes(site: string) {
|
|
38
|
+
return await useNuxtApp().$api<Record<string, any>>(
|
|
39
|
+
`/api/vehicles/site/${site}`,
|
|
40
|
+
{
|
|
41
|
+
method: "GET",
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface IDeleteVehicleParams {
|
|
47
|
+
site: string;
|
|
48
|
+
id: string;
|
|
49
|
+
recno: string;
|
|
50
|
+
type: "whitelist" | "blocklist";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function deleteVehicle({ site, id, recno, type }: IDeleteVehicleParams) {
|
|
54
|
+
return await useNuxtApp().$api<Record<string, any>>(
|
|
55
|
+
`/api/vehicles/${id}`,
|
|
56
|
+
{
|
|
57
|
+
method: "PUT",
|
|
58
|
+
body: {
|
|
59
|
+
site,
|
|
60
|
+
recno,
|
|
61
|
+
type,
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function getVehicleByNRIC(search: string) {
|
|
68
|
+
return await useNuxtApp().$api<Record<string, any>>(
|
|
69
|
+
`/api/vehicles/nric`,
|
|
70
|
+
{
|
|
71
|
+
method: "GET",
|
|
72
|
+
query: {
|
|
73
|
+
search,
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
function formatVehicleStatus(status: string){
|
|
81
|
+
let label = ""
|
|
82
|
+
let color = ""
|
|
83
|
+
switch (status) {
|
|
84
|
+
case 'pending':
|
|
85
|
+
label = "Pending"
|
|
86
|
+
color = "orange"
|
|
87
|
+
break;
|
|
88
|
+
case 'active':
|
|
89
|
+
label = "Active"
|
|
90
|
+
color = "green"
|
|
91
|
+
break;
|
|
92
|
+
case 'rejected':
|
|
93
|
+
label = "Rejected"
|
|
94
|
+
color = "red"
|
|
95
|
+
break;
|
|
96
|
+
default:
|
|
97
|
+
label = status?.charAt(0).toUpperCase() + status?.slice(1) || ""
|
|
98
|
+
color = "grey"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { label, color }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
getVehicles,
|
|
106
|
+
addVehicle,
|
|
107
|
+
getCustomSeasonPassTypes,
|
|
108
|
+
getVehicleById,
|
|
109
|
+
updateVehicle,
|
|
110
|
+
deleteVehicle,
|
|
111
|
+
getVehicleByNRIC,
|
|
112
|
+
formatVehicleStatus
|
|
113
|
+
};
|
|
114
|
+
}
|
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@ declare interface TAnnouncementFile {
|
|
|
20
20
|
preview: boolean;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
declare type TAnnouncementRecipients = "
|
|
23
|
+
declare type TAnnouncementRecipients = "resident" | "security_agency" | "cleaning_services" | "mechanical_electrical" | "property_management_agency"
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
package/types/checkout-item.d.ts
CHANGED
|
@@ -50,5 +50,5 @@ declare type TFlattenedUnitItem = TUnitChecklistItem & {
|
|
|
50
50
|
set: number;
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
declare type TScheduleAreaStatus = "All" | "
|
|
53
|
+
declare type TScheduleAreaStatus = "All" | "Open" | "Ongoing" | "Completed";
|
|
54
54
|
declare type TAreaType = "all" | "common" | "toilet";
|
package/types/people.d.ts
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
declare type TVehicle = {
|
|
2
|
+
plateNumber: string;
|
|
3
|
+
plateNumbers?: string[]; // For display purposes, the API will return an array of plate numbers if there are multiple associated with the same vehicle record
|
|
4
|
+
type: TVehicleType;
|
|
5
|
+
category: "resident" | "visitor";
|
|
6
|
+
direction: "entry" | "exit" | "both" | "none";
|
|
7
|
+
name: string;
|
|
8
|
+
phoneNumber?: string;
|
|
9
|
+
block: number | "";
|
|
10
|
+
level: string;
|
|
11
|
+
unit: string;
|
|
12
|
+
nric?: string | null;
|
|
13
|
+
remarks?: string;
|
|
14
|
+
seasonPassType?: string;
|
|
15
|
+
start?: string; // ISO date string
|
|
16
|
+
end?: string; // ISO date string
|
|
17
|
+
site?: string;
|
|
18
|
+
org?: string;
|
|
19
|
+
_id?: string;
|
|
20
|
+
recNo?: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
declare type TVehicleType = "whitelist" | "blocklist" | "seasonpass";
|
|
24
|
+
|
|
25
|
+
declare type TVehiclePayload = Pick<
|
|
26
|
+
TVehicle,
|
|
27
|
+
| "plateNumber"
|
|
28
|
+
| "type"
|
|
29
|
+
| "category"
|
|
30
|
+
| "direction"
|
|
31
|
+
| "name"
|
|
32
|
+
| "phoneNumber"
|
|
33
|
+
| "block"
|
|
34
|
+
| "level"
|
|
35
|
+
| "unit"
|
|
36
|
+
| "nric"
|
|
37
|
+
| "remarks"
|
|
38
|
+
| "seasonPassType"
|
|
39
|
+
| "start"
|
|
40
|
+
| "end"
|
|
41
|
+
| "site"
|
|
42
|
+
| "org"
|
|
43
|
+
>;
|