@7365admin1/layer-common 1.8.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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.editorconfig +12 -0
- package/.github/workflows/main.yml +17 -0
- package/.github/workflows/publish.yml +39 -0
- package/.nuxtrc +1 -0
- package/.playground/app.vue +41 -0
- package/.playground/eslint.config.mjs +6 -0
- package/.playground/nuxt.config.ts +22 -0
- package/.playground/pages/feedback.vue +30 -0
- package/CHANGELOG.md +263 -0
- package/README.md +73 -0
- package/app.vue +3 -0
- package/components/AccessCardAddForm.vue +363 -0
- package/components/AccessManagement.vue +420 -0
- package/components/Avatar/Main.vue +68 -0
- package/components/BillingMain.vue +66 -0
- package/components/BtnUploadFile.vue +139 -0
- package/components/BuildingForm.vue +303 -0
- package/components/BuildingManagement/buildings.vue +335 -0
- package/components/BuildingManagement/units.vue +350 -0
- package/components/BuildingUnitFormAdd.vue +441 -0
- package/components/BuildingUnitFormEdit.vue +429 -0
- package/components/CameraForm.vue +264 -0
- package/components/CameraMain.vue +352 -0
- package/components/Card/DeleteConfirmation.vue +51 -0
- package/components/Card/MemberInfoSummary.vue +44 -0
- package/components/Card/Toggle.vue +25 -0
- package/components/Chat/Bubbles.vue +53 -0
- package/components/Chat/Information.vue +416 -0
- package/components/Chat/ListCard.vue +62 -0
- package/components/Chat/Message.vue +158 -0
- package/components/Chat/Navigation.vue +150 -0
- package/components/ConfirmDialog.vue +66 -0
- package/components/Container/Standard.vue +33 -0
- package/components/DashboardPlaceholder.vue +1524 -0
- package/components/Dialog/DeleteConfirmation.vue +51 -0
- package/components/Dialog/ReplaceAutofillPrompt.vue +49 -0
- package/components/Dialog/UpdateMoreAction.vue +103 -0
- package/components/DocumentForm.vue +187 -0
- package/components/DocumentManagement.vue +376 -0
- package/components/Editor.vue +95 -0
- package/components/EntryPassMain.vue +518 -0
- package/components/Feedback/Form.vue +173 -0
- package/components/FeedbackDetail.vue +599 -0
- package/components/FeedbackMain.vue +588 -0
- package/components/FormDialog.vue +65 -0
- package/components/ImageCarousel.vue +138 -0
- package/components/Input/Date.vue +177 -0
- package/components/Input/DateTimePicker.vue +131 -0
- package/components/Input/File.vue +236 -0
- package/components/Input/FileV2.vue +234 -0
- package/components/Input/InputPhoneNumberV2.vue +164 -0
- package/components/Input/ListGroupSelection.vue +96 -0
- package/components/Input/NRICNumber.vue +53 -0
- package/components/Input/NewDate.vue +123 -0
- package/components/Input/Number.vue +124 -0
- package/components/Input/Password.vue +22 -0
- package/components/Input/PhoneNumber.vue +188 -0
- package/components/Input/VehicleNumber.vue +49 -0
- package/components/InputLabel.vue +22 -0
- package/components/InvitationForm.vue +359 -0
- package/components/InvitationMain.vue +310 -0
- package/components/Layout/Header.vue +129 -0
- package/components/Layout/NavigationDrawer.vue +44 -0
- package/components/ListItem.vue +35 -0
- package/components/ListView.vue +87 -0
- package/components/LocalPagination.vue +31 -0
- package/components/MemberMain.vue +459 -0
- package/components/NFC/NFCPatrolReportMain.vue +591 -0
- package/components/NFC/NFCPatrolRouteForm.vue +596 -0
- package/components/NFC/NFCPatrolRouteMain.vue +539 -0
- package/components/NFC/NFCTagForm.vue +236 -0
- package/components/NFC/NFCTagMain.vue +337 -0
- package/components/NFC/PatrolSettings.vue +130 -0
- package/components/NavigationItem.vue +83 -0
- package/components/NumberSettingField.vue +107 -0
- package/components/OnlineFormConfigurationForm.vue +290 -0
- package/components/OnlineFormsConfiguration.vue +429 -0
- package/components/PeopleForm.vue +452 -0
- package/components/PlaceholderComponent.vue +34 -0
- package/components/RolePermissionFormCreate.vue +161 -0
- package/components/RolePermissionFormPreviewUpdate.vue +183 -0
- package/components/RolePermissionMain.vue +361 -0
- package/components/SearchVehicleNumberUser.vue +91 -0
- package/components/ServiceProviderFormCreate.vue +154 -0
- package/components/ServiceProviderMain.vue +547 -0
- package/components/SignaturePad.vue +73 -0
- package/components/Snackbar.vue +23 -0
- package/components/SpecificAttr.vue +53 -0
- package/components/SupplyManagement.vue +292 -0
- package/components/SwitchContext.vue +108 -0
- package/components/TableList.vue +150 -0
- package/components/TableListSecondary.vue +164 -0
- package/components/TableMain.vue +142 -0
- package/components/TableWithButton.vue +94 -0
- package/components/VehicleUpdateMoreAction.vue +84 -0
- package/components/VideoPlayer.vue +125 -0
- package/components/VisitorForm.vue +659 -0
- package/components/VisitorFormSelection.vue +53 -0
- package/components/VisitorManagement.vue +490 -0
- package/components/WorkOrder/Create.vue +284 -0
- package/components/WorkOrder/Detail.vue +71 -0
- package/components/WorkOrder/ListView.vue +96 -0
- package/components/WorkOrder/Main.vue +489 -0
- package/components/Workorder.vue +1 -0
- package/composables/useAddress.ts +107 -0
- package/composables/useBuilding.ts +250 -0
- package/composables/useBuildingUnit.ts +116 -0
- package/composables/useCard.ts +46 -0
- package/composables/useCommonPermission.ts +207 -0
- package/composables/useCustomer.ts +113 -0
- package/composables/useCustomerSite.ts +56 -0
- package/composables/useDashboard.ts +31 -0
- package/composables/useDashboardData.ts +425 -0
- package/composables/useDocument.ts +57 -0
- package/composables/useFacility.ts +246 -0
- package/composables/useFeedback.ts +119 -0
- package/composables/useFile.ts +55 -0
- package/composables/useInvoice.ts +18 -0
- package/composables/useLocal.ts +131 -0
- package/composables/useLocalAuth.ts +137 -0
- package/composables/useLocalSetup.ts +13 -0
- package/composables/useMember.ts +111 -0
- package/composables/useNFCPatrolRoute.ts +77 -0
- package/composables/useNFCPatrolSettings.ts +19 -0
- package/composables/useNFCPatrolTag.ts +53 -0
- package/composables/useOnlineForm.ts +67 -0
- package/composables/useOrg.ts +129 -0
- package/composables/usePDFDownload.ts +25 -0
- package/composables/usePaymentMethod.ts +101 -0
- package/composables/usePeople.ts +81 -0
- package/composables/usePermission.ts +54 -0
- package/composables/usePhoneCountries.ts +561 -0
- package/composables/usePrice.ts +15 -0
- package/composables/usePromoCode.ts +36 -0
- package/composables/useRecapPermission.ts +26 -0
- package/composables/useRole.ts +104 -0
- package/composables/useSecurityUtils.ts +18 -0
- package/composables/useServiceProvider.ts +224 -0
- package/composables/useSite.ts +109 -0
- package/composables/useSiteEntryPassSettings.ts +46 -0
- package/composables/useSiteSettings.ts +123 -0
- package/composables/useSubscription.ts +150 -0
- package/composables/useUser.ts +132 -0
- package/composables/useUtils.ts +445 -0
- package/composables/useVerification.ts +34 -0
- package/composables/useVisitor.ts +120 -0
- package/composables/useWorkOrder.ts +85 -0
- package/error.vue +41 -0
- package/layouts/plain.vue +7 -0
- package/middleware/01.auth.ts +20 -0
- package/middleware/02.org.ts +21 -0
- package/middleware/03.customer.ts +13 -0
- package/middleware/member.ts +4 -0
- package/nuxt.config.ts +54 -0
- package/package.json +39 -0
- package/pages/index.vue +3 -0
- package/pages/payment-method-linked.vue +31 -0
- package/pages/require-customer.vue +56 -0
- package/pages/require-organization-membership.vue +47 -0
- package/pages/unauthorized.vue +29 -0
- package/plugins/API.ts +21 -0
- package/plugins/iconify.client.ts +5 -0
- package/plugins/secure-member.client.ts +86 -0
- package/plugins/vuetify.ts +62 -0
- package/public/bg-camera.jpg +0 -0
- package/public/bg-city.jpg +0 -0
- package/public/bg-condo.jpg +0 -0
- package/public/images/icons/delete-icon.png +0 -0
- package/public/sprite.svg +1 -0
- package/tsconfig.json +3 -0
- package/types/address.d.ts +13 -0
- package/types/building.d.ts +27 -0
- package/types/camera.d.ts +31 -0
- package/types/card.d.ts +22 -0
- package/types/customer.d.ts +27 -0
- package/types/document.d.ts +6 -0
- package/types/feedback.d.ts +68 -0
- package/types/local.d.ts +74 -0
- package/types/member.d.ts +21 -0
- package/types/online-form.d.ts +15 -0
- package/types/org.d.ts +13 -0
- package/types/people.d.ts +24 -0
- package/types/permission.d.ts +25 -0
- package/types/phone-number.d.ts +10 -0
- package/types/price.d.ts +17 -0
- package/types/promo-code.d.ts +19 -0
- package/types/role.d.ts +11 -0
- package/types/select.d.ts +4 -0
- package/types/service-provider.d.ts +15 -0
- package/types/site.d.ts +20 -0
- package/types/subscription.d.ts +23 -0
- package/types/user.d.ts +19 -0
- package/types/verification.d.ts +20 -0
- package/types/visitor.d.ts +42 -0
- package/types/work-order.d.ts +42 -0
- package/utils/phoneMasks.ts +1703 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-row no-gutters>
|
|
3
|
+
<v-col cols="12">
|
|
4
|
+
<v-row no-gutters class="mb-4" align="center">
|
|
5
|
+
<v-col cols="12" md="6">
|
|
6
|
+
<v-btn
|
|
7
|
+
rounded="pill"
|
|
8
|
+
variant="outlined"
|
|
9
|
+
|
|
10
|
+
size="large"
|
|
11
|
+
class="text-none px-8"
|
|
12
|
+
@click="dialogAdd = true"
|
|
13
|
+
>
|
|
14
|
+
Add Route
|
|
15
|
+
</v-btn>
|
|
16
|
+
</v-col>
|
|
17
|
+
<v-col cols="12" md="6" class="d-flex justify-end">
|
|
18
|
+
<v-text-field
|
|
19
|
+
v-model="searchInput"
|
|
20
|
+
density="comfortable"
|
|
21
|
+
placeholder="Search"
|
|
22
|
+
clearable
|
|
23
|
+
append-inner-icon="mdi-magnify"
|
|
24
|
+
hide-details
|
|
25
|
+
variant="outlined"
|
|
26
|
+
rounded="lg"
|
|
27
|
+
style="max-width: 400px"
|
|
28
|
+
bg-color="white"
|
|
29
|
+
/>
|
|
30
|
+
</v-col>
|
|
31
|
+
</v-row>
|
|
32
|
+
|
|
33
|
+
<v-card width="100%" variant="outlined" border="thin" rounded="lg">
|
|
34
|
+
|
|
35
|
+
<v-card-text class="pa-0">
|
|
36
|
+
<v-data-table
|
|
37
|
+
:headers="headers"
|
|
38
|
+
:items="items"
|
|
39
|
+
:items-per-page="20"
|
|
40
|
+
fixed-header
|
|
41
|
+
hide-default-footer
|
|
42
|
+
@click:row="handleRowClick"
|
|
43
|
+
style="max-height: calc(100vh - 300px)"
|
|
44
|
+
class="nfc-route-table"
|
|
45
|
+
hover
|
|
46
|
+
>
|
|
47
|
+
<template #item.numberOfCheckpoints="{ value }">
|
|
48
|
+
<div class="text-center">{{ value || "--" }}</div>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<template #item.tolerance="{ item }">
|
|
52
|
+
<div class="text-center">
|
|
53
|
+
<div>{{ item.tolerance ? `${item.tolerance} mins` : "--" }}</div>
|
|
54
|
+
<div class="text-grey">{{ item.totalTravelTime ? `${item.totalTravelTime} mins` : "--" }}</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<template #item.schedules="{ value }">
|
|
59
|
+
<span v-if="Array.isArray(value) && value.length > 0">
|
|
60
|
+
{{ value.map(s => `${s.start}-${s.end}`).join(", ") }}
|
|
61
|
+
</span>
|
|
62
|
+
<span v-else>--</span>
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<template #item.repeatDays="{ value }">
|
|
66
|
+
<span>{{ value || "--" }} </span>
|
|
67
|
+
</template>
|
|
68
|
+
</v-data-table>
|
|
69
|
+
</v-card-text>
|
|
70
|
+
|
|
71
|
+
<v-toolbar density="compact" color="grey-lighten-4">
|
|
72
|
+
<template #append>
|
|
73
|
+
<v-row no-gutters justify="end" align="center">
|
|
74
|
+
<span class="mr-2 text-caption text-fontgray">
|
|
75
|
+
{{ pageRange }}
|
|
76
|
+
</span>
|
|
77
|
+
<local-pagination v-model="page" :length="pages" />
|
|
78
|
+
</v-row>
|
|
79
|
+
</template>
|
|
80
|
+
</v-toolbar>
|
|
81
|
+
</v-card>
|
|
82
|
+
</v-col>
|
|
83
|
+
|
|
84
|
+
<!-- Add Dialog -->
|
|
85
|
+
<v-dialog v-model="dialogAdd" persistent max-width="900">
|
|
86
|
+
<NFCPatrolRouteForm
|
|
87
|
+
title="Add Route"
|
|
88
|
+
:site="props.site"
|
|
89
|
+
:org-id="props.orgId"
|
|
90
|
+
@cancel="dialogAdd = false"
|
|
91
|
+
@success="handleSuccess"
|
|
92
|
+
@error="handleError"
|
|
93
|
+
/>
|
|
94
|
+
</v-dialog>
|
|
95
|
+
|
|
96
|
+
<!-- Edit Dialog -->
|
|
97
|
+
<v-dialog v-model="dialogEdit" persistent max-width="900">
|
|
98
|
+
<NFCPatrolRouteForm
|
|
99
|
+
title="Edit Route"
|
|
100
|
+
:site="props.site"
|
|
101
|
+
:org-id="props.orgId"
|
|
102
|
+
@cancel="dialogEdit = false"
|
|
103
|
+
@success="handleSuccess"
|
|
104
|
+
@error="handleError"
|
|
105
|
+
mode="edit"
|
|
106
|
+
:route="selectedRoute"
|
|
107
|
+
/>
|
|
108
|
+
</v-dialog>
|
|
109
|
+
|
|
110
|
+
<!-- Preview Dialog -->
|
|
111
|
+
<v-dialog v-model="dialogPreview" persistent width="540">
|
|
112
|
+
<v-card width="100%">
|
|
113
|
+
<v-toolbar>
|
|
114
|
+
<v-row no-gutters class="fill-height px-6" align="center">
|
|
115
|
+
<span class="font-weight-bold text-h5 text-capitalize">
|
|
116
|
+
Route Details
|
|
117
|
+
</span>
|
|
118
|
+
</v-row>
|
|
119
|
+
</v-toolbar>
|
|
120
|
+
|
|
121
|
+
<v-card-text
|
|
122
|
+
style="max-height: 100vh; overflow-y: auto"
|
|
123
|
+
class="pa-5 my-5 px-7"
|
|
124
|
+
>
|
|
125
|
+
<v-row no-gutters>
|
|
126
|
+
<v-col cols="12" class="mb-2">
|
|
127
|
+
Route Name:
|
|
128
|
+
<span class="font-weight-bold">
|
|
129
|
+
{{ selectedRoute.routeName }}
|
|
130
|
+
</span>
|
|
131
|
+
</v-col>
|
|
132
|
+
|
|
133
|
+
<v-col cols="12" class="mb-2" v-if="selectedRoute.numberOfCheckpoints">
|
|
134
|
+
Number of Checkpoints:
|
|
135
|
+
<span class="font-weight-bold">
|
|
136
|
+
{{ selectedRoute.numberOfCheckpoints }}
|
|
137
|
+
</span>
|
|
138
|
+
</v-col>
|
|
139
|
+
|
|
140
|
+
<v-col cols="12" class="mb-2" v-if="selectedRoute.tolerance">
|
|
141
|
+
Tolerance:
|
|
142
|
+
<span class="font-weight-bold">
|
|
143
|
+
{{ selectedRoute.tolerance }} mins
|
|
144
|
+
</span>
|
|
145
|
+
</v-col>
|
|
146
|
+
|
|
147
|
+
<v-col
|
|
148
|
+
cols="12"
|
|
149
|
+
class="mb-2"
|
|
150
|
+
v-if="selectedRoute.totalTravelTime"
|
|
151
|
+
>
|
|
152
|
+
Total Travel Time:
|
|
153
|
+
<span class="font-weight-bold">
|
|
154
|
+
{{ selectedRoute.totalTravelTime }} mins
|
|
155
|
+
</span>
|
|
156
|
+
</v-col>
|
|
157
|
+
|
|
158
|
+
<v-col cols="12" class="mb-2" v-if="selectedRoute.repeatDays">
|
|
159
|
+
Repeat Every:
|
|
160
|
+
<span class="font-weight-bold">
|
|
161
|
+
{{ selectedRoute.repeatDays }}
|
|
162
|
+
</span>
|
|
163
|
+
</v-col>
|
|
164
|
+
|
|
165
|
+
<v-col
|
|
166
|
+
cols="12"
|
|
167
|
+
class="mb-2"
|
|
168
|
+
v-if="selectedRoute.schedules && selectedRoute.schedules.length"
|
|
169
|
+
>
|
|
170
|
+
Security Check Schedule:
|
|
171
|
+
<span class="font-weight-bold">
|
|
172
|
+
{{ selectedRoute.schedules.map(s => `${s.start}-${s.end}`).join(", ") }}
|
|
173
|
+
</span>
|
|
174
|
+
</v-col>
|
|
175
|
+
|
|
176
|
+
<v-col
|
|
177
|
+
cols="12"
|
|
178
|
+
class="mb-2"
|
|
179
|
+
v-if="selectedRoute.checkpoints && selectedRoute.checkpoints.length"
|
|
180
|
+
>
|
|
181
|
+
Checkpoints:
|
|
182
|
+
<div class="font-weight-bold">
|
|
183
|
+
<div v-for="(cp, idx) in selectedRoute.checkpoints" :key="idx" class="my-1">
|
|
184
|
+
{{ idx + 1 }}. NFC Tag ID: {{ cp.nfcTagId }} - Travel Time: {{ cp.travelTime }} min
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
</v-col>
|
|
188
|
+
</v-row>
|
|
189
|
+
</v-card-text>
|
|
190
|
+
|
|
191
|
+
<v-toolbar class="pa-0" density="compact">
|
|
192
|
+
<v-row no-gutters>
|
|
193
|
+
<v-col cols="6" class="pa-0">
|
|
194
|
+
<v-btn
|
|
195
|
+
block
|
|
196
|
+
variant="text"
|
|
197
|
+
class="text-none"
|
|
198
|
+
size="large"
|
|
199
|
+
@click="dialogPreview = false"
|
|
200
|
+
height="48"
|
|
201
|
+
>
|
|
202
|
+
Close
|
|
203
|
+
</v-btn>
|
|
204
|
+
</v-col>
|
|
205
|
+
|
|
206
|
+
<v-col cols="6" class="pa-0">
|
|
207
|
+
<v-menu>
|
|
208
|
+
<template #activator="{ props }">
|
|
209
|
+
<v-btn
|
|
210
|
+
block
|
|
211
|
+
variant="flat"
|
|
212
|
+
color="black"
|
|
213
|
+
class="text-none"
|
|
214
|
+
height="48"
|
|
215
|
+
v-bind="props"
|
|
216
|
+
tile
|
|
217
|
+
>
|
|
218
|
+
More actions
|
|
219
|
+
</v-btn>
|
|
220
|
+
</template>
|
|
221
|
+
|
|
222
|
+
<v-list class="pa-0">
|
|
223
|
+
<v-list-item @click="openDialogEdit()">
|
|
224
|
+
<v-list-item-title class="text-subtitle-2">
|
|
225
|
+
Edit Route
|
|
226
|
+
</v-list-item-title>
|
|
227
|
+
</v-list-item>
|
|
228
|
+
|
|
229
|
+
<v-list-item @click="openDialogDelete()" class="text-red">
|
|
230
|
+
<v-list-item-title class="text-subtitle-2">
|
|
231
|
+
Delete Route
|
|
232
|
+
</v-list-item-title>
|
|
233
|
+
</v-list-item>
|
|
234
|
+
</v-list>
|
|
235
|
+
</v-menu>
|
|
236
|
+
</v-col>
|
|
237
|
+
</v-row>
|
|
238
|
+
</v-toolbar>
|
|
239
|
+
</v-card>
|
|
240
|
+
</v-dialog>
|
|
241
|
+
|
|
242
|
+
<!-- Delete Dialog -->
|
|
243
|
+
<v-dialog v-model="dialogDelete" persistent width="540">
|
|
244
|
+
<v-card width="100%">
|
|
245
|
+
<v-card-text
|
|
246
|
+
style="max-height: 100vh; overflow-y: auto"
|
|
247
|
+
class="pa-5 my-5 px-7 text-center"
|
|
248
|
+
>
|
|
249
|
+
Are you sure you want to delete this route?
|
|
250
|
+
</v-card-text>
|
|
251
|
+
|
|
252
|
+
<v-toolbar class="pa-0" density="compact">
|
|
253
|
+
<v-row no-gutters>
|
|
254
|
+
<v-col cols="6" class="pa-0">
|
|
255
|
+
<v-btn
|
|
256
|
+
block
|
|
257
|
+
variant="text"
|
|
258
|
+
class="text-none"
|
|
259
|
+
size="large"
|
|
260
|
+
tile
|
|
261
|
+
@click="dialogDelete = false"
|
|
262
|
+
height="48"
|
|
263
|
+
>
|
|
264
|
+
Cancel
|
|
265
|
+
</v-btn>
|
|
266
|
+
</v-col>
|
|
267
|
+
|
|
268
|
+
<v-col cols="6" class="pa-0">
|
|
269
|
+
<v-btn
|
|
270
|
+
block
|
|
271
|
+
tile
|
|
272
|
+
variant="flat"
|
|
273
|
+
class="text-none"
|
|
274
|
+
size="large"
|
|
275
|
+
height="48"
|
|
276
|
+
color="black"
|
|
277
|
+
@click="submitDelete()"
|
|
278
|
+
>
|
|
279
|
+
Delete
|
|
280
|
+
</v-btn>
|
|
281
|
+
</v-col>
|
|
282
|
+
</v-row>
|
|
283
|
+
</v-toolbar>
|
|
284
|
+
</v-card>
|
|
285
|
+
</v-dialog>
|
|
286
|
+
|
|
287
|
+
<Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
|
|
288
|
+
</v-row>
|
|
289
|
+
</template>
|
|
290
|
+
|
|
291
|
+
<script setup lang="ts">
|
|
292
|
+
import useNFCPatrolRoute from "../../composables/useNFCPatrolRoute";
|
|
293
|
+
|
|
294
|
+
const props = defineProps({
|
|
295
|
+
site: {
|
|
296
|
+
type: String,
|
|
297
|
+
required: true,
|
|
298
|
+
},
|
|
299
|
+
siteName: {
|
|
300
|
+
type: String,
|
|
301
|
+
default: "",
|
|
302
|
+
},
|
|
303
|
+
orgId: {
|
|
304
|
+
type: String,
|
|
305
|
+
required: true,
|
|
306
|
+
},
|
|
307
|
+
headers: {
|
|
308
|
+
type: Array as PropType<Array<any>>,
|
|
309
|
+
default: () => [
|
|
310
|
+
{ title: "Route Name", value: "routeName", align: "start" },
|
|
311
|
+
{ title: "Checkpoints", value: "numberOfCheckpoints", align: "center" },
|
|
312
|
+
{
|
|
313
|
+
title: "Tolerance (mins)\nTotal Travel Time (mins)",
|
|
314
|
+
value: "tolerance",
|
|
315
|
+
align: "center",
|
|
316
|
+
sortable: false
|
|
317
|
+
},
|
|
318
|
+
{ title: "Security Check Schedule", value: "schedules", align: "start" },
|
|
319
|
+
{ title: "Route Schedule", value: "repeatDays", align: "start" },
|
|
320
|
+
],
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const items = ref<Array<any>>([]);
|
|
325
|
+
const page = ref(1);
|
|
326
|
+
const pages = ref(0);
|
|
327
|
+
const pageRange = ref("1-20 of 1");
|
|
328
|
+
const searchInput = ref("");
|
|
329
|
+
|
|
330
|
+
const { getAll: getAllRoutes, getById: getRouteById, deleteById: deleteRouteById } =
|
|
331
|
+
useNFCPatrolRoute();
|
|
332
|
+
|
|
333
|
+
function calculateEndTime(startTime: string, toleranceMinutes: number): string {
|
|
334
|
+
if (!startTime) return '';
|
|
335
|
+
|
|
336
|
+
const [hours, minutes] = startTime.split(':').map(Number);
|
|
337
|
+
if (isNaN(hours) || isNaN(minutes)) return startTime;
|
|
338
|
+
|
|
339
|
+
const totalMinutes = hours * 60 + minutes + toleranceMinutes;
|
|
340
|
+
const wrappedMinutes = ((totalMinutes % 1440) + 1440) % 1440;
|
|
341
|
+
|
|
342
|
+
const endHours = String(Math.floor(wrappedMinutes / 60)).padStart(2, '0');
|
|
343
|
+
const endMins = String(wrappedMinutes % 60).padStart(2, '0');
|
|
344
|
+
|
|
345
|
+
return `${endHours}:${endMins}`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Use a reactive trigger for manual refresh
|
|
349
|
+
const refreshTrigger = ref(0);
|
|
350
|
+
|
|
351
|
+
const { data: getRoutesReq, refresh: getRoutesRefresh } =
|
|
352
|
+
await useLazyAsyncData(
|
|
353
|
+
`get-nfc-routes-${props.site}`,
|
|
354
|
+
() =>
|
|
355
|
+
getAllRoutes({
|
|
356
|
+
site: props.site,
|
|
357
|
+
page: page.value,
|
|
358
|
+
search: searchInput.value,
|
|
359
|
+
}),
|
|
360
|
+
{
|
|
361
|
+
watch: [page, searchInput, refreshTrigger],
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
watchEffect(() => {
|
|
366
|
+
if (getRoutesReq.value) {
|
|
367
|
+
items.value = getRoutesReq.value.items?.map((item: any) => ({
|
|
368
|
+
// Original API fields for editing
|
|
369
|
+
_id: item._id,
|
|
370
|
+
name: item.name,
|
|
371
|
+
checkPointNumber: item.checkPointNumber,
|
|
372
|
+
tolerance: item.tolerance,
|
|
373
|
+
totalTravelTime: item.totalTravelTime,
|
|
374
|
+
days: item.days,
|
|
375
|
+
startTimes: item.startTimes || [],
|
|
376
|
+
checkPoints: item.checkPoints || [],
|
|
377
|
+
// Display fields for the table
|
|
378
|
+
routeName: item.name,
|
|
379
|
+
numberOfCheckpoints: item.checkPointNumber,
|
|
380
|
+
schedules: item.startTimes?.map((time: string) => ({
|
|
381
|
+
start: time,
|
|
382
|
+
end: calculateEndTime(time, item.tolerance || 0)
|
|
383
|
+
})) || [],
|
|
384
|
+
repeatDays: item.days?.map((d: number) => {
|
|
385
|
+
const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
386
|
+
return dayNames[d];
|
|
387
|
+
}).join(', ') || '--',
|
|
388
|
+
checkpoints: item.checkPoints?.map((cp: any) => ({
|
|
389
|
+
nfcTagId: cp.nfcTag_id,
|
|
390
|
+
travelTime: cp.travelTime
|
|
391
|
+
})) || []
|
|
392
|
+
})) || [];
|
|
393
|
+
|
|
394
|
+
pageRange.value = getRoutesReq.value.pageRange;
|
|
395
|
+
pages.value = getRoutesReq.value.pages;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
const dialogAdd = ref(false);
|
|
400
|
+
const dialogEdit = ref(false);
|
|
401
|
+
const dialogPreview = ref(false);
|
|
402
|
+
const dialogDelete = ref(false);
|
|
403
|
+
|
|
404
|
+
const message = ref("");
|
|
405
|
+
const messageSnackbar = ref(false);
|
|
406
|
+
const messageColor = ref("");
|
|
407
|
+
|
|
408
|
+
async function openDialogEdit() {
|
|
409
|
+
try {
|
|
410
|
+
// Fetch the full route details from the API
|
|
411
|
+
const response = await getRouteById(selectedRoute.value._id);
|
|
412
|
+
|
|
413
|
+
// Extract the nfcPatrolRoute from the nested response
|
|
414
|
+
const fullRouteData = response.data?.nfcPatrolRoute || response.nfcPatrolRoute || response;
|
|
415
|
+
|
|
416
|
+
// Update selectedRoute with the full data from API
|
|
417
|
+
selectedRoute.value = {
|
|
418
|
+
...selectedRoute.value,
|
|
419
|
+
...fullRouteData,
|
|
420
|
+
// Ensure the display fields are preserved
|
|
421
|
+
routeName: fullRouteData.name,
|
|
422
|
+
numberOfCheckpoints: fullRouteData.checkPointNumber,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
dialogEdit.value = true;
|
|
426
|
+
if (dialogPreview.value) dialogPreview.value = false;
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.error('Error fetching route details:', error);
|
|
429
|
+
handleError(error);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function openDialogDelete() {
|
|
434
|
+
dialogDelete.value = true;
|
|
435
|
+
|
|
436
|
+
if (dialogPreview.value) dialogPreview.value = false;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async function handleSuccess() {
|
|
440
|
+
try {
|
|
441
|
+
// Small delay to ensure backend has processed the update
|
|
442
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
443
|
+
|
|
444
|
+
// Trigger refresh by incrementing the refresh trigger
|
|
445
|
+
refreshTrigger.value++;
|
|
446
|
+
|
|
447
|
+
// Also call refresh to ensure data is fetched
|
|
448
|
+
await getRoutesRefresh();
|
|
449
|
+
|
|
450
|
+
// Wait for next tick to ensure reactivity completes
|
|
451
|
+
await nextTick();
|
|
452
|
+
|
|
453
|
+
if (dialogAdd.value) {
|
|
454
|
+
dialogAdd.value = false;
|
|
455
|
+
showMessage("Route created successfully!", "success");
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (dialogEdit.value) {
|
|
459
|
+
dialogEdit.value = false;
|
|
460
|
+
showMessage("Route updated successfully!", "success");
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (dialogPreview.value) dialogPreview.value = false;
|
|
464
|
+
|
|
465
|
+
if (dialogDelete.value) dialogDelete.value = false;
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.error('Error refreshing routes:', error);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function handleError(error: any) {
|
|
472
|
+
const errorMessage =
|
|
473
|
+
error?.data?.message || error?.message || "An error occurred";
|
|
474
|
+
showMessage(errorMessage, "error");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function showMessage(msg: string, color: string) {
|
|
478
|
+
message.value = msg;
|
|
479
|
+
messageColor.value = color;
|
|
480
|
+
messageSnackbar.value = true;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const selectedRoute = ref<any>({
|
|
484
|
+
_id: "",
|
|
485
|
+
name: "",
|
|
486
|
+
routeName: "",
|
|
487
|
+
checkPointNumber: 5,
|
|
488
|
+
numberOfCheckpoints: 5,
|
|
489
|
+
tolerance: undefined,
|
|
490
|
+
totalTravelTime: undefined,
|
|
491
|
+
days: [],
|
|
492
|
+
repeatDays: "",
|
|
493
|
+
startTimes: [],
|
|
494
|
+
schedules: [],
|
|
495
|
+
checkPoints: [],
|
|
496
|
+
checkpoints: [],
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
function handleRowClick(_: any, data: any) {
|
|
500
|
+
dialogPreview.value = true;
|
|
501
|
+
selectedRoute.value = JSON.parse(JSON.stringify(data.item));
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async function submitDelete() {
|
|
505
|
+
try {
|
|
506
|
+
await deleteRouteById(selectedRoute.value._id ?? "");
|
|
507
|
+
await getRoutesRefresh();
|
|
508
|
+
dialogDelete.value = false;
|
|
509
|
+
showMessage("Route deleted successfully!", "success");
|
|
510
|
+
} catch (error) {
|
|
511
|
+
console.error("Error deleting route:", error);
|
|
512
|
+
handleError(error);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
</script>
|
|
516
|
+
|
|
517
|
+
<style scoped>
|
|
518
|
+
.nfc-route-table :deep(.v-data-table__th) {
|
|
519
|
+
background-color: rgb(250, 250, 250);
|
|
520
|
+
font-weight: 500;
|
|
521
|
+
white-space: pre-line;
|
|
522
|
+
padding: 16px 12px !important;
|
|
523
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.nfc-route-table :deep(.v-data-table__td) {
|
|
527
|
+
padding: 16px 12px !important;
|
|
528
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.nfc-route-table :deep(tbody tr:hover) {
|
|
532
|
+
background-color: rgba(0, 0, 0, 0.02) !important;
|
|
533
|
+
cursor: pointer;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.nfc-route-table :deep(.v-data-table__tr) {
|
|
537
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
|
538
|
+
}
|
|
539
|
+
</style>
|