@7365admin1/layer-common 3.0.25 → 3.0.27
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 +14 -0
- package/components/AccessCardDetailsDialog.vue +129 -3
- package/components/AccessCardPreviewDialog.vue +31 -3
- package/components/AccessManagement.vue +10 -1
- package/components/AddPassKeyToVisitor.vue +346 -225
- package/components/DashboardMain.vue +95 -59
- package/components/DocumentManagement.vue +71 -5
- package/components/EntryPassInformation.vue +55 -17
- package/components/HidIntercomManagement.vue +186 -0
- package/components/HidReaderForm.vue +10 -16
- package/components/HidReaderManagement.vue +21 -1
- package/components/MemberInformation.vue +59 -1
- package/components/RolePermissionMain.vue +14 -8
- package/components/SiteSettings.vue +3 -1
- package/components/VisitorForm.vue +35 -7
- package/components/VisitorManagement.vue +233 -39
- package/components/VisitorSocketPopUp.vue +29 -1
- package/composables/useANPRSettings.ts +57 -8
- package/composables/useAccessManagement.ts +17 -1
- package/composables/useCleaningPermission.ts +2 -2
- package/composables/useCommonPermission.ts +2 -39
- package/composables/useDocument.ts +21 -0
- package/composables/useLocalAuth.ts +3 -1
- package/package.json +1 -1
- package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -0
- package/pages/[org]/[site]/access-mgmt/hid-readers/index.vue +2 -0
- package/pages/[org]/[site]/access-mgmt/hid-users/index.vue +2 -0
- package/pages/[org]/[site]/access-mgmt/identity-mapping/index.vue +2 -0
|
@@ -1,268 +1,389 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
2
|
+
<v-card width="100%" :loading="processing">
|
|
3
|
+
<v-toolbar>
|
|
4
|
+
<v-row
|
|
5
|
+
no-gutters
|
|
6
|
+
class="fill-height px-6 d-flex justify-space-between align-center"
|
|
7
|
+
align="center"
|
|
8
|
+
>
|
|
9
|
+
<span class="font-weight-bold text-subtitle-1"
|
|
10
|
+
>{{ isEditMode ? "Edit" : "Assign" }} Pass & Keys</span
|
|
11
|
+
>
|
|
12
|
+
<ButtonClose @click="emit('close')" />
|
|
13
|
+
</v-row>
|
|
14
|
+
</v-toolbar>
|
|
15
|
+
|
|
16
|
+
<v-card-text>
|
|
17
|
+
<v-row no-gutters class="ga-1">
|
|
18
|
+
<v-col cols="12">
|
|
19
|
+
<span class="text-subtitle-2 text-medium-emphasis">
|
|
20
|
+
Name: {{ prop.visitor.name }}
|
|
21
|
+
</span>
|
|
22
|
+
</v-col>
|
|
23
|
+
|
|
24
|
+
<!-- Pass section -->
|
|
25
|
+
<v-col cols="12" class="mt-3">
|
|
26
|
+
<InputLabel title="Pass" />
|
|
27
|
+
|
|
28
|
+
<!-- Existing pass -->
|
|
29
|
+
<div v-if="existingPass" class="d-flex align-center ga-2 mb-2">
|
|
30
|
+
<v-chip
|
|
31
|
+
prepend-icon="mdi-card-bulleted-outline"
|
|
32
|
+
color="blue"
|
|
33
|
+
variant="tonal"
|
|
34
|
+
size="small"
|
|
35
|
+
closable
|
|
36
|
+
@click:close="
|
|
37
|
+
existingPassToBeReplaced = existingPass;
|
|
38
|
+
existingPass = null;
|
|
39
|
+
"
|
|
40
|
+
>
|
|
41
|
+
{{ existingPass.prefixAndName }}
|
|
42
|
+
</v-chip>
|
|
43
|
+
<span class="text-caption text-medium-emphasis">(current)</span>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<!-- New pass selector -->
|
|
47
|
+
<v-autocomplete
|
|
48
|
+
v-if="!existingPass"
|
|
49
|
+
v-model="selectedPass"
|
|
50
|
+
v-model:search="passInput"
|
|
51
|
+
:hide-no-data="false"
|
|
52
|
+
:items="passItems"
|
|
53
|
+
item-title="prefixAndName"
|
|
54
|
+
item-value="_id"
|
|
55
|
+
variant="outlined"
|
|
56
|
+
hide-details
|
|
57
|
+
density="compact"
|
|
58
|
+
small-chips
|
|
59
|
+
:loading="fetchPassesPending"
|
|
60
|
+
clearable
|
|
61
|
+
>
|
|
62
|
+
<template v-slot:chip="{ props: chipProps, item }">
|
|
63
|
+
<v-chip
|
|
64
|
+
v-if="selectedPass"
|
|
65
|
+
v-bind="chipProps"
|
|
66
|
+
prepend-icon="mdi-card-bulleted-outline"
|
|
67
|
+
:text="item.raw?.prefixAndName"
|
|
68
|
+
/>
|
|
69
|
+
</template>
|
|
70
|
+
<template v-slot:no-data>
|
|
71
|
+
<v-list-item density="compact">
|
|
72
|
+
<v-list-item-title>No available passes</v-list-item-title>
|
|
73
|
+
</v-list-item>
|
|
74
|
+
</template>
|
|
75
|
+
</v-autocomplete>
|
|
76
|
+
</v-col>
|
|
77
|
+
|
|
78
|
+
<!-- Keys section -->
|
|
79
|
+
<v-col v-if="showKeys" cols="12" class="mt-3">
|
|
80
|
+
<InputLabel title="Keys" />
|
|
81
|
+
|
|
82
|
+
<!-- Existing keys -->
|
|
83
|
+
<div
|
|
84
|
+
v-if="existingKeys.length > 0"
|
|
85
|
+
class="d-flex flex-wrap ga-1 mb-2"
|
|
86
|
+
>
|
|
87
|
+
<v-chip
|
|
88
|
+
v-for="key in existingKeys"
|
|
89
|
+
:key="key.keyId"
|
|
90
|
+
prepend-icon="mdi-key"
|
|
91
|
+
color="orange"
|
|
92
|
+
variant="tonal"
|
|
93
|
+
size="small"
|
|
94
|
+
closable
|
|
95
|
+
@click:close="removeExistingKey(key.keyId)"
|
|
96
|
+
>
|
|
97
|
+
{{ key.prefixAndName }}
|
|
98
|
+
</v-chip>
|
|
99
|
+
<span class="text-caption text-medium-emphasis align-self-center"
|
|
100
|
+
>(current)</span
|
|
101
|
+
>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<!-- New keys selector -->
|
|
105
|
+
<v-autocomplete
|
|
106
|
+
v-model="selectedKeys"
|
|
107
|
+
v-model:search="keyInput"
|
|
108
|
+
:hide-no-data="false"
|
|
109
|
+
:items="keyItems"
|
|
110
|
+
item-title="prefixAndName"
|
|
111
|
+
item-value="_id"
|
|
112
|
+
:label="existingKeys.length > 0 ? 'Add more keys' : undefined"
|
|
113
|
+
multiple
|
|
114
|
+
variant="outlined"
|
|
115
|
+
hide-details
|
|
116
|
+
density="compact"
|
|
117
|
+
small-chips
|
|
118
|
+
:loading="fetchKeysPending"
|
|
119
|
+
>
|
|
120
|
+
<template v-slot:chip="{ props: chipProps, item }">
|
|
121
|
+
<v-chip
|
|
122
|
+
v-if="selectedKeys.length > 0"
|
|
123
|
+
v-bind="chipProps"
|
|
124
|
+
prepend-icon="mdi-key"
|
|
125
|
+
:text="item.raw?.prefixAndName"
|
|
126
|
+
/>
|
|
127
|
+
</template>
|
|
128
|
+
<template v-slot:no-data>
|
|
129
|
+
<v-list-item density="compact">
|
|
130
|
+
<v-list-item-title>No available keys</v-list-item-title>
|
|
131
|
+
</v-list-item>
|
|
132
|
+
</template>
|
|
133
|
+
</v-autocomplete>
|
|
134
|
+
</v-col>
|
|
135
|
+
</v-row>
|
|
136
|
+
|
|
137
|
+
<v-row v-if="errorMessage" no-gutters class="mt-2">
|
|
138
|
+
<p class="text-error text-subtitle-2 w-100 text-center">
|
|
139
|
+
{{ errorMessage }}
|
|
140
|
+
</p>
|
|
141
|
+
</v-row>
|
|
142
|
+
</v-card-text>
|
|
143
|
+
|
|
144
|
+
<v-toolbar density="compact">
|
|
145
|
+
<v-row no-gutters>
|
|
146
|
+
<v-col cols="6">
|
|
147
|
+
<v-btn
|
|
148
|
+
tile
|
|
149
|
+
block
|
|
150
|
+
variant="text"
|
|
151
|
+
class="text-none"
|
|
152
|
+
size="48"
|
|
153
|
+
text="Cancel"
|
|
154
|
+
@click="emit('close')"
|
|
155
|
+
/>
|
|
156
|
+
</v-col>
|
|
157
|
+
<v-col cols="6">
|
|
158
|
+
<v-btn
|
|
159
|
+
tile
|
|
160
|
+
block
|
|
161
|
+
variant="flat"
|
|
162
|
+
color="black"
|
|
163
|
+
class="text-none"
|
|
164
|
+
size="48"
|
|
165
|
+
:text="isEditMode ? 'Save' : 'Assign'"
|
|
166
|
+
:disabled="!canSubmit"
|
|
167
|
+
:loading="processing"
|
|
168
|
+
@click="handleSubmit"
|
|
169
|
+
/>
|
|
170
|
+
</v-col>
|
|
171
|
+
</v-row>
|
|
172
|
+
</v-toolbar>
|
|
173
|
+
</v-card>
|
|
98
174
|
</template>
|
|
99
175
|
|
|
100
176
|
<script setup lang="ts">
|
|
101
|
-
import type { PropType } from
|
|
102
|
-
import usePassKey from
|
|
103
|
-
import useVisitor from
|
|
177
|
+
import type { PropType } from "vue";
|
|
178
|
+
import usePassKey from "../composables/usePassKey";
|
|
179
|
+
import useVisitor from "../composables/useVisitor";
|
|
104
180
|
|
|
105
181
|
const prop = defineProps({
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
})
|
|
182
|
+
visitor: {
|
|
183
|
+
type: Object as PropType<TVisitor>,
|
|
184
|
+
required: true,
|
|
185
|
+
},
|
|
186
|
+
site: {
|
|
187
|
+
type: String,
|
|
188
|
+
required: true,
|
|
189
|
+
},
|
|
190
|
+
mode: {
|
|
191
|
+
type: String as PropType<"add" | "edit">,
|
|
192
|
+
default: "add",
|
|
193
|
+
},
|
|
194
|
+
});
|
|
119
195
|
|
|
120
196
|
const emit = defineEmits<{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}>()
|
|
197
|
+
(e: "done"): void;
|
|
198
|
+
(e: "close"): void;
|
|
199
|
+
}>();
|
|
124
200
|
|
|
125
|
-
const { getPassKeysByPageSearch } = usePassKey()
|
|
126
|
-
const {
|
|
201
|
+
const { getPassKeysByPageSearch } = usePassKey();
|
|
202
|
+
const { updateVisitor } = useVisitor();
|
|
127
203
|
|
|
128
|
-
const processing = ref(false)
|
|
129
|
-
const errorMessage = ref(
|
|
204
|
+
const processing = ref(false);
|
|
205
|
+
const errorMessage = ref("");
|
|
130
206
|
|
|
131
207
|
// New selections
|
|
132
|
-
const selectedPass = ref<string>(
|
|
133
|
-
const selectedKeys = ref<string[]>([])
|
|
134
|
-
const passInput = ref(
|
|
135
|
-
const keyInput = ref(
|
|
136
|
-
const passItems = ref<TPassKey[]>([])
|
|
137
|
-
const keyItems = ref<TPassKey[]>([])
|
|
208
|
+
const selectedPass = ref<string>("");
|
|
209
|
+
const selectedKeys = ref<string[]>([]);
|
|
210
|
+
const passInput = ref("");
|
|
211
|
+
const keyInput = ref("");
|
|
212
|
+
const passItems = ref<TPassKey[]>([]);
|
|
213
|
+
const keyItems = ref<TPassKey[]>([]);
|
|
138
214
|
|
|
139
215
|
// Existing pass/keys (editable)
|
|
140
|
-
const existingPass = ref<{ keyId: string; prefixAndName: string } | null>(null)
|
|
141
|
-
const
|
|
216
|
+
const existingPass = ref<{ keyId: string; prefixAndName: string } | null>(null);
|
|
217
|
+
const existingPassToBeReplaced = ref<{
|
|
218
|
+
keyId: string;
|
|
219
|
+
prefixAndName: string;
|
|
220
|
+
} | null>(null);
|
|
221
|
+
const existingKeys = ref<{ keyId: string; prefixAndName: string }[]>([]);
|
|
142
222
|
|
|
143
|
-
const isEditMode = computed(() => prop.mode ===
|
|
144
|
-
const showKeys = computed(() => prop.visitor.type ===
|
|
223
|
+
const isEditMode = computed(() => prop.mode === "edit");
|
|
224
|
+
const showKeys = computed(() => prop.visitor.type === "contractor");
|
|
145
225
|
|
|
146
226
|
const passTypesComputed = computed(() => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
227
|
+
const type = prop.visitor.type;
|
|
228
|
+
const contractorType = (prop.visitor as any).contractorType;
|
|
229
|
+
if (type === "contractor") {
|
|
230
|
+
return contractorType === "property-agent"
|
|
231
|
+
? ["agent-pass"]
|
|
232
|
+
: ["contractor-pass"];
|
|
233
|
+
}
|
|
234
|
+
return ["visitor-pass"];
|
|
235
|
+
});
|
|
154
236
|
|
|
155
237
|
// Initialise existing values in edit mode
|
|
156
238
|
onMounted(() => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
239
|
+
if (isEditMode.value) {
|
|
240
|
+
const vPass = prop.visitor.visitorPass;
|
|
241
|
+
if (Array.isArray(vPass) && vPass.length > 0) {
|
|
242
|
+
const p = vPass[0] as any;
|
|
243
|
+
existingPass.value = { keyId: p.keyId, prefixAndName: p.prefixAndName };
|
|
244
|
+
}
|
|
245
|
+
const vKeys = prop.visitor.passKeys;
|
|
246
|
+
if (Array.isArray(vKeys) && vKeys.length > 0) {
|
|
247
|
+
existingKeys.value = (vKeys as any[]).map((k) => ({
|
|
248
|
+
keyId: k.keyId,
|
|
249
|
+
prefixAndName: k.prefixAndName,
|
|
250
|
+
}));
|
|
167
251
|
}
|
|
168
|
-
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
169
254
|
|
|
170
255
|
function removeExistingKey(keyId: string) {
|
|
171
|
-
|
|
256
|
+
existingKeys.value = existingKeys.value.filter((k) => k.keyId !== keyId);
|
|
172
257
|
}
|
|
173
258
|
|
|
174
259
|
// Exclude already-held pass/keys from selectable lists
|
|
175
|
-
const existingPassId = computed(() => existingPass.value?.keyId)
|
|
176
|
-
const existingKeyIds = computed(() => existingKeys.value.map(k => k.keyId))
|
|
177
|
-
|
|
178
|
-
const {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
260
|
+
const existingPassId = computed(() => existingPass.value?.keyId);
|
|
261
|
+
const existingKeyIds = computed(() => existingKeys.value.map((k) => k.keyId));
|
|
262
|
+
|
|
263
|
+
const {
|
|
264
|
+
data: passesData,
|
|
265
|
+
refresh: refreshPasses,
|
|
266
|
+
pending: fetchPassesPending,
|
|
267
|
+
} = await useLazyAsyncData(
|
|
268
|
+
`add-pass-key-visitor-passes-${prop.visitor._id}`,
|
|
269
|
+
() =>
|
|
270
|
+
getPassKeysByPageSearch({
|
|
271
|
+
search: passInput.value,
|
|
272
|
+
page: 1,
|
|
273
|
+
limit: 500,
|
|
274
|
+
passTypes: passTypesComputed.value,
|
|
275
|
+
sites: [prop.site],
|
|
276
|
+
statuses: ["Available"],
|
|
187
277
|
})
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
const {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const {
|
|
281
|
+
data: keysData,
|
|
282
|
+
refresh: refreshKeys,
|
|
283
|
+
pending: fetchKeysPending,
|
|
284
|
+
} = await useLazyAsyncData(
|
|
285
|
+
`add-pass-key-visitor-keys-${prop.visitor._id}`,
|
|
286
|
+
() =>
|
|
287
|
+
getPassKeysByPageSearch({
|
|
288
|
+
search: keyInput.value,
|
|
289
|
+
page: 1,
|
|
290
|
+
limit: 500,
|
|
291
|
+
passTypes: ["pass-key"],
|
|
292
|
+
sites: [prop.site],
|
|
293
|
+
statuses: ["Available"],
|
|
199
294
|
})
|
|
200
|
-
)
|
|
295
|
+
);
|
|
201
296
|
|
|
202
297
|
watch(passesData, (data: any) => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
})
|
|
298
|
+
const all: TPassKey[] = Array.isArray(data?.items) ? data.items : [];
|
|
299
|
+
passItems.value = all.filter((p) => p._id !== existingPassId.value);
|
|
300
|
+
});
|
|
206
301
|
|
|
207
302
|
watch(keysData, (data: any) => {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
})
|
|
303
|
+
const all: TPassKey[] = Array.isArray(data?.items) ? data.items : [];
|
|
304
|
+
keyItems.value = all.filter((k) => !existingKeyIds.value.includes(k._id!));
|
|
305
|
+
});
|
|
211
306
|
|
|
212
307
|
// Re-filter when existing items change
|
|
213
|
-
watch(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
308
|
+
watch(
|
|
309
|
+
[existingPassId, existingKeyIds],
|
|
310
|
+
() => {
|
|
311
|
+
const rawPasses = (passesData.value as any)?.items ?? [];
|
|
312
|
+
passItems.value = rawPasses.filter(
|
|
313
|
+
(p: TPassKey) => p._id !== existingPassId.value
|
|
314
|
+
);
|
|
315
|
+
const rawKeys = (keysData.value as any)?.items ?? [];
|
|
316
|
+
keyItems.value = rawKeys.filter(
|
|
317
|
+
(k: TPassKey) => !existingKeyIds.value.includes(k._id!)
|
|
318
|
+
);
|
|
319
|
+
},
|
|
320
|
+
{ deep: true }
|
|
321
|
+
);
|
|
219
322
|
|
|
220
323
|
const canSubmit = computed(() => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
324
|
+
if (isEditMode.value) {
|
|
325
|
+
// allow save if anything changed: existing items modified OR new items selected
|
|
326
|
+
return (
|
|
327
|
+
existingPass.value !== null ||
|
|
328
|
+
selectedPass.value ||
|
|
329
|
+
existingKeys.value.length > 0 ||
|
|
330
|
+
selectedKeys.value.length > 0
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
return !!selectedPass.value || selectedKeys.value.length > 0;
|
|
334
|
+
});
|
|
228
335
|
|
|
229
336
|
async function handleSubmit() {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
if (selectedPass.value) {
|
|
243
|
-
finalPasses.push({ keyId: selectedPass.value})
|
|
244
|
-
}
|
|
245
|
-
payload.visitorPass = finalPasses
|
|
246
|
-
|
|
247
|
-
// Build final keys list: kept existing + newly selected
|
|
248
|
-
if (showKeys.value) {
|
|
249
|
-
const finalKeys: { keyId: string}[] = [
|
|
250
|
-
...existingKeys.value.map(k => ({ keyId: k.keyId })),
|
|
251
|
-
...selectedKeys.value.map(keyId => ({ keyId })),
|
|
252
|
-
]
|
|
253
|
-
payload.passKeys = finalKeys
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
await updateVisitorPassKey(prop.visitor._id, payload)
|
|
257
|
-
emit('done')
|
|
258
|
-
emit('close')
|
|
259
|
-
} catch (error: any) {
|
|
260
|
-
errorMessage.value = error?.data?.message || 'Failed to save pass & keys. Please try again.'
|
|
261
|
-
} finally {
|
|
262
|
-
processing.value = false
|
|
337
|
+
if (!prop.visitor._id) return;
|
|
338
|
+
errorMessage.value = "";
|
|
339
|
+
processing.value = true;
|
|
340
|
+
|
|
341
|
+
try {
|
|
342
|
+
let payload: any = {};
|
|
343
|
+
|
|
344
|
+
// Build final pass list: kept existing + newly selected
|
|
345
|
+
const finalPasses: { keyId: string; status?: string; add?: boolean }[] = [];
|
|
346
|
+
if (existingPass.value) {
|
|
347
|
+
finalPasses.push({ keyId: existingPass.value.keyId, status: "Removed" });
|
|
263
348
|
}
|
|
349
|
+
if (existingPassToBeReplaced.value) {
|
|
350
|
+
finalPasses.push({
|
|
351
|
+
keyId: existingPassToBeReplaced.value.keyId,
|
|
352
|
+
status: "Removed",
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
if (selectedPass.value) {
|
|
356
|
+
finalPasses.push({
|
|
357
|
+
keyId: selectedPass.value,
|
|
358
|
+
status: "Not Returned",
|
|
359
|
+
add: true,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
payload.visitorPass = finalPasses;
|
|
363
|
+
|
|
364
|
+
// Build final keys list: kept existing + newly selected
|
|
365
|
+
if (showKeys.value) {
|
|
366
|
+
const finalKeys: { keyId: string; status?: string; add?: boolean }[] = [
|
|
367
|
+
...existingKeys.value.map((k) => ({ keyId: k.keyId })),
|
|
368
|
+
...selectedKeys.value.map((keyId) => ({
|
|
369
|
+
keyId,
|
|
370
|
+
status: "Not Returned",
|
|
371
|
+
add: true,
|
|
372
|
+
})),
|
|
373
|
+
];
|
|
374
|
+
payload.passKeys = finalKeys;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
await updateVisitor(prop.visitor._id, payload);
|
|
378
|
+
emit("done");
|
|
379
|
+
emit("close");
|
|
380
|
+
} catch (error: any) {
|
|
381
|
+
errorMessage.value =
|
|
382
|
+
error?.data?.message || "Failed to save pass & keys. Please try again.";
|
|
383
|
+
} finally {
|
|
384
|
+
processing.value = false;
|
|
385
|
+
}
|
|
264
386
|
}
|
|
265
387
|
</script>
|
|
266
388
|
|
|
267
389
|
<style scoped></style>
|
|
268
|
-
|