@7365admin1/layer-common 1.11.37 → 1.11.38
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/ClientMain.vue +28 -53
- package/components/InvitationClientForm.vue +37 -19
- package/components/ScheduleTaskForm.vue +168 -18
- package/components/ScheduleTaskMain.vue +10 -4
- package/components/VehicleForm.vue +1 -0
- package/components/VisitorManagement.vue +4 -4
- package/composables/useMember.ts +16 -0
- package/composables/useWorkOrder.ts +13 -7
- package/package.json +1 -1
- package/types/org.d.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-row no-gutters>
|
|
3
3
|
<v-col cols="12">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
:loading="loading"
|
|
8
|
-
:page="page"
|
|
9
|
-
:pages="pages"
|
|
10
|
-
:pageRange="pageRange"
|
|
11
|
-
:items-per-page="-1"
|
|
12
|
-
:extension-height="120"
|
|
13
|
-
:offset="300"
|
|
14
|
-
show-header
|
|
15
|
-
@refresh="handleRefresh"
|
|
16
|
-
@update:page="handleUpdatePage"
|
|
17
|
-
>
|
|
4
|
+
<TableMain :headers="currentHeaders" :items="items" :loading="loading" :page="page" :pages="pages"
|
|
5
|
+
:pageRange="pageRange" :items-per-page="-1" :extension-height="120" :offset="300" show-header
|
|
6
|
+
@refresh="handleRefresh" @update:page="handleUpdatePage">
|
|
18
7
|
<!-- EXTENSION -->
|
|
19
8
|
<template #extension>
|
|
20
9
|
<v-row no-gutters class="w-100 d-flex flex-column ga-2 pt-2">
|
|
@@ -25,30 +14,16 @@
|
|
|
25
14
|
</v-tabs>
|
|
26
15
|
|
|
27
16
|
<div class="px-3 py-2 w-100">
|
|
28
|
-
<v-text-field
|
|
29
|
-
|
|
30
|
-
density="compact"
|
|
31
|
-
placeholder="Search"
|
|
32
|
-
clearable
|
|
33
|
-
max-width="300"
|
|
34
|
-
append-inner-icon="mdi-magnify"
|
|
35
|
-
hide-details
|
|
36
|
-
@update:model-value="handleSearch"
|
|
37
|
-
/>
|
|
17
|
+
<v-text-field v-model="search" density="compact" placeholder="Search" clearable max-width="300"
|
|
18
|
+
append-inner-icon="mdi-magnify" hide-details @update:model-value="handleSearch" />
|
|
38
19
|
</div>
|
|
39
20
|
</v-row>
|
|
40
21
|
</template>
|
|
41
22
|
|
|
42
23
|
<!-- ACTIONS -->
|
|
43
24
|
<template #actions>
|
|
44
|
-
<v-btn
|
|
45
|
-
|
|
46
|
-
class="text-none"
|
|
47
|
-
rounded="pill"
|
|
48
|
-
variant="tonal"
|
|
49
|
-
size="large"
|
|
50
|
-
@click="openInviteDialog"
|
|
51
|
-
>
|
|
25
|
+
<v-btn v-if="tab !== 'suspended'" class="text-none" rounded="pill" variant="tonal" size="large"
|
|
26
|
+
@click="openInviteDialog">
|
|
52
27
|
Invite Client
|
|
53
28
|
</v-btn>
|
|
54
29
|
</template>
|
|
@@ -60,26 +35,16 @@
|
|
|
60
35
|
|
|
61
36
|
<!-- STATUS CELL -->
|
|
62
37
|
<template #item.status="{ value }">
|
|
63
|
-
<v-chip
|
|
64
|
-
size="small"
|
|
65
|
-
:color="value === 'suspended' ? 'error' : 'success'"
|
|
66
|
-
variant="flat"
|
|
67
|
-
>
|
|
38
|
+
<v-chip size="small" :color="value === 'suspended' ? 'error' : 'success'" variant="flat">
|
|
68
39
|
{{ value }}
|
|
69
40
|
</v-chip>
|
|
70
41
|
</template>
|
|
71
42
|
|
|
72
43
|
<!-- ACTION CELL (pending only) -->
|
|
73
44
|
<template #item.action="{ item }">
|
|
74
|
-
<v-btn
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
color="error"
|
|
78
|
-
variant="tonal"
|
|
79
|
-
:loading="cancelLoadingId === item._id"
|
|
80
|
-
:disabled="cancelLoadingId === item._id"
|
|
81
|
-
@click="cancelInvite(item)"
|
|
82
|
-
>
|
|
45
|
+
<v-btn v-if="tab === 'pending'" size="small" color="error" variant="tonal"
|
|
46
|
+
:loading="cancelLoadingId === item._id" :disabled="cancelLoadingId === item._id"
|
|
47
|
+
@click="cancelInvite(item)">
|
|
83
48
|
Cancel Invite
|
|
84
49
|
</v-btn>
|
|
85
50
|
</template>
|
|
@@ -88,11 +53,7 @@
|
|
|
88
53
|
|
|
89
54
|
<!-- DIALOG -->
|
|
90
55
|
<v-dialog v-model="dialog" max-width="500">
|
|
91
|
-
<InvitationClientForm
|
|
92
|
-
title="Invite Client"
|
|
93
|
-
@success="handleSuccess"
|
|
94
|
-
@cancel="dialog = false"
|
|
95
|
-
/>
|
|
56
|
+
<InvitationClientForm title="Invite Client" @success="handleSuccess" @cancel="dialog = false" />
|
|
96
57
|
</v-dialog>
|
|
97
58
|
</v-row>
|
|
98
59
|
</template>
|
|
@@ -125,6 +86,17 @@ const search = ref('')
|
|
|
125
86
|
const totalItems = ref(0)
|
|
126
87
|
const cancelLoadingId = ref<string | null>(null)
|
|
127
88
|
|
|
89
|
+
|
|
90
|
+
const APP_LIST = [
|
|
91
|
+
{ title: "Organization", value: "organization" },
|
|
92
|
+
{ title: "Security Agency", value: "security_agency" },
|
|
93
|
+
{ title: "Cleaning Services", value: "cleaning_services" },
|
|
94
|
+
{ title: "Property Management Agency", value: "property_management_agency" },
|
|
95
|
+
{ title: "Mechanical & Electrical Services", value: "mechanical_electrical_services" },
|
|
96
|
+
{ title: "Pest Control Services", value: "pest_control_services" },
|
|
97
|
+
{ title: "Landscaping Services", value: "landscaping_services" },
|
|
98
|
+
{ title: "Pool Maintenance Services", value: "pool_maintenance_services" },
|
|
99
|
+
]
|
|
128
100
|
/* ================= HEADERS ================= */
|
|
129
101
|
const orgHeaders = [
|
|
130
102
|
{ title: 'Organization Name', key: 'name' },
|
|
@@ -286,13 +258,16 @@ async function fetchPending() {
|
|
|
286
258
|
type: 'user-invite',
|
|
287
259
|
page: page.value,
|
|
288
260
|
search: search.value,
|
|
289
|
-
app: 'organization',
|
|
261
|
+
// app: 'organization',
|
|
290
262
|
})
|
|
291
263
|
|
|
292
264
|
items.value = await Promise.all(
|
|
293
265
|
(res?.items || []).map(async (i: any) => ({
|
|
294
266
|
...i,
|
|
295
|
-
app:
|
|
267
|
+
app:
|
|
268
|
+
APP_LIST.find(a => a.value === i.metadata?.app)?.title ||
|
|
269
|
+
i.metadata?.app ||
|
|
270
|
+
'-',
|
|
296
271
|
role: await resolveRoleName(i.metadata?.role),
|
|
297
272
|
}))
|
|
298
273
|
)
|
|
@@ -119,17 +119,18 @@
|
|
|
119
119
|
import { computed, ref, reactive, watchEffect } from 'vue'
|
|
120
120
|
import useCustomerSite from '../composables/useCustomerSite'
|
|
121
121
|
import useLocal from '../composables/useLocal'
|
|
122
|
-
import { useLocalSetup } from '../composables/useLocalSetup'
|
|
123
122
|
import useRole from '../composables/useRole'
|
|
124
123
|
import useUser from '../composables/useUser'
|
|
125
124
|
import useUtils from '../composables/useUtils'
|
|
125
|
+
import useOrg from '../composables/useOrg'
|
|
126
|
+
import { watch } from 'vue'
|
|
126
127
|
|
|
127
128
|
const APP = useRuntimeConfig().public.APP
|
|
128
129
|
|
|
129
130
|
/* ================= PROPS ================= */
|
|
130
131
|
const props = defineProps({
|
|
131
132
|
title: { type: String, default: "Invite Form" },
|
|
132
|
-
app: { type: String, default: "
|
|
133
|
+
app: { type: String, default: "" },
|
|
133
134
|
org: { type: String, default: "" },
|
|
134
135
|
mode: { type: String, default: "create" },
|
|
135
136
|
})
|
|
@@ -162,17 +163,23 @@ if (props.mode === "create") {
|
|
|
162
163
|
|
|
163
164
|
/* ================= APP LIST ================= */
|
|
164
165
|
const APP_LIST = [
|
|
165
|
-
{ title: "
|
|
166
|
+
{ title: "Property Management Agency", value: "property_management_agency" },
|
|
166
167
|
{ title: "Security Agency", value: "security_agency" },
|
|
167
168
|
{ title: "Cleaning Services", value: "cleaning_services" },
|
|
168
|
-
{ title: "Property Management Agency", value: "property_management_agency" },
|
|
169
169
|
{ title: "Mechanical & Electrical Services", value: "mechanical_electrical_services" },
|
|
170
170
|
{ title: "Pest Control Services", value: "pest_control_services" },
|
|
171
|
-
{ title: "Landscaping Services", value: "landscaping_services" },
|
|
172
171
|
{ title: "Pool Maintenance Services", value: "pool_maintenance_services" },
|
|
173
172
|
]
|
|
174
|
-
|
|
175
|
-
const
|
|
173
|
+
const { getByName } = useOrg()
|
|
174
|
+
const org = ref<any>(null)
|
|
175
|
+
watch(
|
|
176
|
+
() => props.org,
|
|
177
|
+
async (name) => {
|
|
178
|
+
if (!name) return
|
|
179
|
+
org.value = await getByName(name)
|
|
180
|
+
},
|
|
181
|
+
{ immediate: true }
|
|
182
|
+
)
|
|
176
183
|
|
|
177
184
|
const apps = computed(() => APP_LIST)
|
|
178
185
|
|
|
@@ -188,7 +195,7 @@ const { getAll: getAllCustomerSite } = useCustomerSite()
|
|
|
188
195
|
|
|
189
196
|
const { data: siteData, refresh: refreshSiteData } = await useLazyAsyncData(
|
|
190
197
|
"sites",
|
|
191
|
-
() => getAllCustomerSite({ org:
|
|
198
|
+
() => getAllCustomerSite({ org: org.value?._id, limit: 50 })
|
|
192
199
|
)
|
|
193
200
|
|
|
194
201
|
watchEffect(() => {
|
|
@@ -200,9 +207,13 @@ watchEffect(() => {
|
|
|
200
207
|
}
|
|
201
208
|
})
|
|
202
209
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
210
|
+
watch(
|
|
211
|
+
() => org.value?._id,
|
|
212
|
+
async (id) => {
|
|
213
|
+
if (!id) return
|
|
214
|
+
await refreshSiteData()
|
|
215
|
+
}
|
|
216
|
+
)
|
|
206
217
|
|
|
207
218
|
/* ================= ROLE ================= */
|
|
208
219
|
const roles = ref<any[]>([])
|
|
@@ -211,18 +222,24 @@ const { getRoles } = useRole()
|
|
|
211
222
|
const { data: roleData, refresh: refreshRoles } = await useLazyAsyncData(
|
|
212
223
|
"roles",
|
|
213
224
|
() =>
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
225
|
+
getRoles({
|
|
226
|
+
org: org.value?._id,
|
|
227
|
+
type: props.app,
|
|
228
|
+
limit: 50,
|
|
229
|
+
}),
|
|
219
230
|
{ watch: [() => props.app] }
|
|
220
231
|
)
|
|
221
232
|
|
|
222
233
|
watchEffect(() => {
|
|
223
234
|
if (roleData.value) roles.value = roleData.value.items
|
|
224
235
|
})
|
|
225
|
-
|
|
236
|
+
watch(
|
|
237
|
+
() => org.value?._id,
|
|
238
|
+
async (id) => {
|
|
239
|
+
if (!id) return
|
|
240
|
+
await refreshRoles()
|
|
241
|
+
}
|
|
242
|
+
)
|
|
226
243
|
/* ================= EVENTS ================= */
|
|
227
244
|
async function handleUpdateApp(value: string[]) {
|
|
228
245
|
invite.value.role = ""
|
|
@@ -255,7 +272,8 @@ async function submit() {
|
|
|
255
272
|
email: invite.value.email,
|
|
256
273
|
app,
|
|
257
274
|
role: invite.value.role,
|
|
258
|
-
org: invite.value.org,
|
|
275
|
+
// org: invite.value.org,
|
|
276
|
+
org: org.value?._id,
|
|
259
277
|
site: invite.value.site,
|
|
260
278
|
siteName: invite.value.siteName,
|
|
261
279
|
// isMemberInvite: invite.value.isMemberInvite,
|
|
@@ -269,7 +287,7 @@ async function submit() {
|
|
|
269
287
|
email: "",
|
|
270
288
|
app: [],
|
|
271
289
|
role: "",
|
|
272
|
-
org:
|
|
290
|
+
org: org.value?._id || "",
|
|
273
291
|
site: "",
|
|
274
292
|
siteName: "",
|
|
275
293
|
isMemberInvite: false,
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
</v-row>
|
|
21
21
|
</v-toolbar>
|
|
22
22
|
|
|
23
|
-
<v-card-text class="pa-
|
|
23
|
+
<v-card-text class="pa-4 flex-grow-1" style="overflow-y: auto">
|
|
24
24
|
<v-form ref="formRef" v-model="valid">
|
|
25
25
|
<v-row dense>
|
|
26
26
|
<v-col cols="12">
|
|
@@ -52,7 +52,10 @@
|
|
|
52
52
|
<div class="text-caption text-medium-emphasis mb-2">
|
|
53
53
|
{{ selectedDates.length }} date(s) selected
|
|
54
54
|
</div>
|
|
55
|
-
<div
|
|
55
|
+
<div
|
|
56
|
+
v-if="selectedDates.length > 0"
|
|
57
|
+
class="d-flex flex-wrap ga-2"
|
|
58
|
+
>
|
|
56
59
|
<v-chip
|
|
57
60
|
v-for="date in selectedDates"
|
|
58
61
|
:key="date"
|
|
@@ -121,6 +124,108 @@
|
|
|
121
124
|
</v-select>
|
|
122
125
|
</v-col>
|
|
123
126
|
|
|
127
|
+
<v-col v-if="selectedAreas.length > 0" cols="12">
|
|
128
|
+
<InputLabel title="Units Under Selected Areas" />
|
|
129
|
+
<v-card variant="outlined" rounded class="mb-4">
|
|
130
|
+
<v-list density="compact" nav>
|
|
131
|
+
<template
|
|
132
|
+
v-for="(area, idx) in selectedAreas"
|
|
133
|
+
:key="area.value || area._id"
|
|
134
|
+
>
|
|
135
|
+
<v-divider v-if="idx > 0" />
|
|
136
|
+
|
|
137
|
+
<v-list-item
|
|
138
|
+
rounded="0"
|
|
139
|
+
class="px-3"
|
|
140
|
+
@click="toggleArea(area.value || area._id)"
|
|
141
|
+
>
|
|
142
|
+
<template #prepend>
|
|
143
|
+
<v-icon size="18" color="medium-emphasis">
|
|
144
|
+
{{
|
|
145
|
+
openAreas.includes(area.value || area._id)
|
|
146
|
+
? "mdi-chevron-down"
|
|
147
|
+
: "mdi-chevron-right"
|
|
148
|
+
}}
|
|
149
|
+
</v-icon>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<v-list-item-title class="text-body-2 font-weight-medium">
|
|
153
|
+
{{ area.name }}
|
|
154
|
+
</v-list-item-title>
|
|
155
|
+
|
|
156
|
+
<template #append>
|
|
157
|
+
<v-progress-circular
|
|
158
|
+
v-if="
|
|
159
|
+
loadingUnits &&
|
|
160
|
+
!(area.value || area._id in fetchedAreaUnits)
|
|
161
|
+
"
|
|
162
|
+
size="14"
|
|
163
|
+
width="2"
|
|
164
|
+
indeterminate
|
|
165
|
+
color="primary"
|
|
166
|
+
/>
|
|
167
|
+
<v-chip
|
|
168
|
+
v-else
|
|
169
|
+
size="x-small"
|
|
170
|
+
variant="tonal"
|
|
171
|
+
color="primary"
|
|
172
|
+
>
|
|
173
|
+
{{
|
|
174
|
+
(fetchedAreaUnits[area.value || area._id] || [])
|
|
175
|
+
.length
|
|
176
|
+
}}
|
|
177
|
+
</v-chip>
|
|
178
|
+
</template>
|
|
179
|
+
</v-list-item>
|
|
180
|
+
|
|
181
|
+
<v-expand-transition>
|
|
182
|
+
<div v-show="openAreas.includes(area.value || area._id)">
|
|
183
|
+
<v-card-text class="pt-1 pb-3 px-3">
|
|
184
|
+
<div
|
|
185
|
+
v-if="
|
|
186
|
+
loadingUnits &&
|
|
187
|
+
!(area.value || area._id in fetchedAreaUnits)
|
|
188
|
+
"
|
|
189
|
+
class="d-flex flex-wrap ga-2"
|
|
190
|
+
>
|
|
191
|
+
<v-skeleton-loader
|
|
192
|
+
v-for="n in 4"
|
|
193
|
+
:key="n"
|
|
194
|
+
type="chip"
|
|
195
|
+
width="80"
|
|
196
|
+
/>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<div
|
|
200
|
+
v-else-if="
|
|
201
|
+
(fetchedAreaUnits[area.value || area._id] || [])
|
|
202
|
+
.length > 0
|
|
203
|
+
"
|
|
204
|
+
class="d-flex flex-wrap ga-1"
|
|
205
|
+
>
|
|
206
|
+
<v-chip
|
|
207
|
+
v-for="unit in fetchedAreaUnits[
|
|
208
|
+
area.value || area._id
|
|
209
|
+
]"
|
|
210
|
+
:key="unit.unit"
|
|
211
|
+
size="small"
|
|
212
|
+
variant="tonal"
|
|
213
|
+
>
|
|
214
|
+
{{ unit.name }}
|
|
215
|
+
</v-chip>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<span v-else class="text-caption text-disabled">
|
|
219
|
+
No units configured
|
|
220
|
+
</span>
|
|
221
|
+
</v-card-text>
|
|
222
|
+
</div>
|
|
223
|
+
</v-expand-transition>
|
|
224
|
+
</template>
|
|
225
|
+
</v-list>
|
|
226
|
+
</v-card>
|
|
227
|
+
</v-col>
|
|
228
|
+
|
|
124
229
|
<v-col cols="12">
|
|
125
230
|
<InputLabel for="description" title="Task Description" />
|
|
126
231
|
<v-textarea
|
|
@@ -138,18 +243,16 @@
|
|
|
138
243
|
</v-form>
|
|
139
244
|
</v-card-text>
|
|
140
245
|
|
|
141
|
-
<v-
|
|
142
|
-
|
|
143
|
-
<v-card-actions class="pa-0">
|
|
144
|
-
<v-row no-gutters class="fill-width">
|
|
246
|
+
<v-toolbar class="pa-0" density="compact">
|
|
247
|
+
<v-row no-gutters>
|
|
145
248
|
<v-col cols="6" class="pa-0">
|
|
146
249
|
<v-btn
|
|
147
250
|
block
|
|
148
251
|
variant="text"
|
|
149
|
-
class="text-none
|
|
150
|
-
size="
|
|
252
|
+
class="text-none"
|
|
253
|
+
size="large"
|
|
151
254
|
@click="close"
|
|
152
|
-
height="
|
|
255
|
+
height="48"
|
|
153
256
|
:disabled="submitting"
|
|
154
257
|
>
|
|
155
258
|
Cancel
|
|
@@ -161,7 +264,7 @@
|
|
|
161
264
|
variant="flat"
|
|
162
265
|
color="primary"
|
|
163
266
|
class="text-none font-weight-bold rounded-0"
|
|
164
|
-
height="
|
|
267
|
+
height="48"
|
|
165
268
|
@click="submitTask"
|
|
166
269
|
:loading="submitting"
|
|
167
270
|
>
|
|
@@ -169,7 +272,7 @@
|
|
|
169
272
|
</v-btn>
|
|
170
273
|
</v-col>
|
|
171
274
|
</v-row>
|
|
172
|
-
</v-
|
|
275
|
+
</v-toolbar>
|
|
173
276
|
</v-card>
|
|
174
277
|
</v-dialog>
|
|
175
278
|
|
|
@@ -202,7 +305,7 @@ const props = defineProps({
|
|
|
202
305
|
const show = defineModel("show", { type: Boolean, default: false });
|
|
203
306
|
const emit = defineEmits(["saved", "close", "refresh"]);
|
|
204
307
|
|
|
205
|
-
const { getAreas } = useAreas();
|
|
308
|
+
const { getAreas, getAreaById } = useAreas();
|
|
206
309
|
const { createScheduleTask, updateScheduleTask, getScheduleTaskById } =
|
|
207
310
|
useScheduleTask();
|
|
208
311
|
|
|
@@ -215,19 +318,52 @@ const subject = ref("");
|
|
|
215
318
|
const description = ref("");
|
|
216
319
|
const scheduleTime = ref("08:00");
|
|
217
320
|
const pickerDates = ref<Date[]>([]);
|
|
218
|
-
// Derived from pickerDates — single source of truth, always in sync
|
|
219
321
|
const selectedDates = computed(() =>
|
|
220
322
|
pickerDates.value.map((d) => toLocalISO(d)).sort()
|
|
221
323
|
);
|
|
222
324
|
|
|
223
325
|
const selectedAreas = ref<any[]>([]);
|
|
326
|
+
const loadingUnits = ref(false);
|
|
327
|
+
const fetchedAreaUnits = ref<Record<string, { name: string; unit: string }[]>>(
|
|
328
|
+
{}
|
|
329
|
+
);
|
|
330
|
+
const openAreas = ref<string[]>([]);
|
|
331
|
+
|
|
332
|
+
const selectedAreaIds = computed(() =>
|
|
333
|
+
selectedAreas.value.map((a: any) => a.value || a._id)
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
watch(selectedAreaIds, async (ids, prevIds) => {
|
|
337
|
+
openAreas.value = ids.slice();
|
|
338
|
+
|
|
339
|
+
const toFetch = ids.filter(
|
|
340
|
+
(id) => !prevIds?.includes(id) && !(id in fetchedAreaUnits.value)
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
if (!toFetch.length) return;
|
|
344
|
+
|
|
345
|
+
loadingUnits.value = true;
|
|
346
|
+
try {
|
|
347
|
+
await Promise.all(
|
|
348
|
+
toFetch.map(async (id) => {
|
|
349
|
+
try {
|
|
350
|
+
const result = await getAreaById(id);
|
|
351
|
+
fetchedAreaUnits.value[id] = result?.units || [];
|
|
352
|
+
} catch {
|
|
353
|
+
fetchedAreaUnits.value[id] = [];
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
} finally {
|
|
358
|
+
loadingUnits.value = false;
|
|
359
|
+
}
|
|
360
|
+
});
|
|
224
361
|
|
|
225
362
|
const message = ref("");
|
|
226
363
|
const messageSnackbar = ref(false);
|
|
227
364
|
const messageColor = ref("success");
|
|
228
365
|
const areasList = ref<any[]>([]);
|
|
229
366
|
|
|
230
|
-
// Helper function to generate all dates between start and end
|
|
231
367
|
const generateDateRange = (start: Date, end: Date): Date[] => {
|
|
232
368
|
const dates: Date[] = [];
|
|
233
369
|
const current = new Date(start);
|
|
@@ -240,7 +376,6 @@ const generateDateRange = (start: Date, end: Date): Date[] => {
|
|
|
240
376
|
return dates;
|
|
241
377
|
};
|
|
242
378
|
|
|
243
|
-
// Helper: convert a Date to a local YYYY-MM-DD string (avoids UTC-shift issues)
|
|
244
379
|
const toLocalISO = (d: Date): string => {
|
|
245
380
|
const y = d.getFullYear();
|
|
246
381
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
@@ -248,7 +383,6 @@ const toLocalISO = (d: Date): string => {
|
|
|
248
383
|
return `${y}-${m}-${day}`;
|
|
249
384
|
};
|
|
250
385
|
|
|
251
|
-
// Remove a single date from the selection via chip close
|
|
252
386
|
const removeDate = (dateISO: string) => {
|
|
253
387
|
pickerDates.value = pickerDates.value.filter(
|
|
254
388
|
(d) => toLocalISO(d) !== dateISO
|
|
@@ -261,12 +395,23 @@ const showMessage = (text: string, color: string = "success") => {
|
|
|
261
395
|
messageSnackbar.value = true;
|
|
262
396
|
};
|
|
263
397
|
|
|
398
|
+
const toggleArea = (id: string) => {
|
|
399
|
+
const idx = openAreas.value.indexOf(id);
|
|
400
|
+
if (idx === -1) {
|
|
401
|
+
openAreas.value.push(id);
|
|
402
|
+
} else {
|
|
403
|
+
openAreas.value.splice(idx, 1);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
264
407
|
const resetForm = () => {
|
|
265
408
|
subject.value = "";
|
|
266
409
|
description.value = "";
|
|
267
410
|
scheduleTime.value = "08:00";
|
|
268
411
|
pickerDates.value = [];
|
|
269
412
|
selectedAreas.value = [];
|
|
413
|
+
fetchedAreaUnits.value = {};
|
|
414
|
+
openAreas.value = [];
|
|
270
415
|
};
|
|
271
416
|
|
|
272
417
|
const setFormFromTask = (task: any) => {
|
|
@@ -310,7 +455,8 @@ const setFormFromTask = (task: any) => {
|
|
|
310
455
|
|
|
311
456
|
const { data: getAreasReq, pending: loadingAreas } = await useLazyAsyncData(
|
|
312
457
|
`get-areas-${props.site}`,
|
|
313
|
-
() =>
|
|
458
|
+
() =>
|
|
459
|
+
getAreas({ site: props.site, limit: 1000, serviceType: props.serviceType }),
|
|
314
460
|
{
|
|
315
461
|
watch: [show, () => props.site],
|
|
316
462
|
immediate: false,
|
|
@@ -377,7 +523,11 @@ const submitTask = async () => {
|
|
|
377
523
|
(props.taskData as any)?._id || (props.taskData as any)?.id;
|
|
378
524
|
response = await updateScheduleTask(taskId, payload);
|
|
379
525
|
} else {
|
|
380
|
-
response = await createScheduleTask({
|
|
526
|
+
response = await createScheduleTask({
|
|
527
|
+
...payload,
|
|
528
|
+
site: props.site,
|
|
529
|
+
serviceType: props.serviceType,
|
|
530
|
+
});
|
|
381
531
|
}
|
|
382
532
|
|
|
383
533
|
showMessage(
|
|
@@ -205,12 +205,14 @@
|
|
|
205
205
|
<v-toolbar>
|
|
206
206
|
<v-row no-gutters class="fill-height px-6" align="center">
|
|
207
207
|
<span class="font-weight-bold text-h6 text-capitalize">
|
|
208
|
-
Delete {{ selectedTask?.title ||
|
|
208
|
+
Delete {{ selectedTask?.title || "Schedule Task" }}
|
|
209
209
|
</span>
|
|
210
210
|
</v-row>
|
|
211
211
|
</v-toolbar>
|
|
212
212
|
<v-card-text>
|
|
213
|
-
<span class="text-subtitle-2"
|
|
213
|
+
<span class="text-subtitle-2"
|
|
214
|
+
>Are you sure you want to delete this schedule task?</span
|
|
215
|
+
>
|
|
214
216
|
</v-card-text>
|
|
215
217
|
|
|
216
218
|
<v-toolbar class="pa-0" density="compact">
|
|
@@ -257,6 +259,7 @@
|
|
|
257
259
|
|
|
258
260
|
<script lang="ts" setup>
|
|
259
261
|
import useScheduleTask from "../composables/useScheduleTask";
|
|
262
|
+
import useUtils from "../composables/useUtils";
|
|
260
263
|
|
|
261
264
|
const props = defineProps({
|
|
262
265
|
orgId: { type: String, required: true },
|
|
@@ -271,13 +274,16 @@ const props = defineProps({
|
|
|
271
274
|
});
|
|
272
275
|
|
|
273
276
|
const { formatDate, debounce } = useUtils();
|
|
274
|
-
const { getScheduleTasks, getScheduleTaskById, deleteScheduleTask } =
|
|
277
|
+
const { getScheduleTasks, getScheduleTaskById, deleteScheduleTask } =
|
|
278
|
+
useScheduleTask();
|
|
275
279
|
|
|
276
280
|
const canViewScheduleTasks = computed(() => props.canViewScheduleTasks);
|
|
277
281
|
const canCreateScheduleTask = computed(() => props.canCreateScheduleTask);
|
|
278
282
|
const canUpdateScheduleTask = computed(() => props.canUpdateScheduleTask);
|
|
279
283
|
const canDeleteScheduleTask = computed(() => props.canDeleteScheduleTask);
|
|
280
|
-
const canViewScheduleTaskDetails = computed(
|
|
284
|
+
const canViewScheduleTaskDetails = computed(
|
|
285
|
+
() => props.canViewScheduleTaskDetails
|
|
286
|
+
);
|
|
281
287
|
|
|
282
288
|
const page = ref(1);
|
|
283
289
|
const pages = ref(0);
|
|
@@ -776,6 +776,7 @@ onMounted(() => {
|
|
|
776
776
|
vehicle.end = prop.vehicleData.end || '';
|
|
777
777
|
vehicle.start = prop.vehicleData.start || '';
|
|
778
778
|
vehicle.plateNumber = prop.vehicleData.plates?.find((p) => p._id === prop.plateNumberId)?.plateNumber || '';
|
|
779
|
+
vehicle.peopleId = prop.vehicleData.peopleId || '';
|
|
779
780
|
}
|
|
780
781
|
}, 300);
|
|
781
782
|
})
|
|
@@ -1331,10 +1331,10 @@ const {
|
|
|
1331
1331
|
params.status = activeTab.value;
|
|
1332
1332
|
}
|
|
1333
1333
|
|
|
1334
|
-
if (activeTab.value !== "registered") {
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
}
|
|
1334
|
+
// if (activeTab.value !== "registered") {
|
|
1335
|
+
// delete params.type;
|
|
1336
|
+
// delete params.checkedOut;
|
|
1337
|
+
// }
|
|
1338
1338
|
|
|
1339
1339
|
return await getVisitors(params);
|
|
1340
1340
|
},
|
package/composables/useMember.ts
CHANGED
|
@@ -93,6 +93,21 @@ export default function useMember() {
|
|
|
93
93
|
}
|
|
94
94
|
);
|
|
95
95
|
}
|
|
96
|
+
|
|
97
|
+
function createMemberDirect(payload: {
|
|
98
|
+
userId: string;
|
|
99
|
+
orgId: string;
|
|
100
|
+
roleId: string;
|
|
101
|
+
app: string;
|
|
102
|
+
siteId?: string;
|
|
103
|
+
siteName?:string;
|
|
104
|
+
}) {
|
|
105
|
+
return useNuxtApp().$api<TMember>('/api/members/direct', {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
body: payload,
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
96
111
|
return {
|
|
97
112
|
members,
|
|
98
113
|
member,
|
|
@@ -107,5 +122,6 @@ export default function useMember() {
|
|
|
107
122
|
getByUserIdType,
|
|
108
123
|
updateMemberStatus,
|
|
109
124
|
updateMemberRole,
|
|
125
|
+
createMemberDirect
|
|
110
126
|
};
|
|
111
127
|
}
|
|
@@ -137,15 +137,21 @@ export default function useWorkOrder() {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
function deleteWorkOrder(id: string) {
|
|
140
|
-
return useNuxtApp().$api<Record<string, any>>(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
method: "PUT",
|
|
144
|
-
// query: { id },
|
|
145
|
-
}
|
|
146
|
-
);
|
|
140
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/work-orders/${id}`, {
|
|
141
|
+
method: "DELETE",
|
|
142
|
+
});
|
|
147
143
|
}
|
|
148
144
|
|
|
145
|
+
// function deleteWorkOrder(id: string) {
|
|
146
|
+
// return useNuxtApp().$api<Record<string, any>>(
|
|
147
|
+
// `/api/work-orders/deleted/work-order/${id}`,
|
|
148
|
+
// {
|
|
149
|
+
// method: "PUT",
|
|
150
|
+
// // query: { id },
|
|
151
|
+
// }
|
|
152
|
+
// );
|
|
153
|
+
// }
|
|
154
|
+
|
|
149
155
|
function getWorkOrderSettings(_workOrderSettings: Record<string, any>) {
|
|
150
156
|
return useNuxtApp().$api<Record<string, any>>(
|
|
151
157
|
"/api/work-order-settings/get-by-site",
|
package/package.json
CHANGED