@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
|
@@ -17,18 +17,16 @@
|
|
|
17
17
|
class="mb-3"
|
|
18
18
|
/>
|
|
19
19
|
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
/>
|
|
31
|
-
</template>
|
|
20
|
+
<div class="field-label">Base URL / IP address <span>*</span></div>
|
|
21
|
+
<v-text-field
|
|
22
|
+
v-model="draft.baseUrl"
|
|
23
|
+
aria-label="Base URL / IP address"
|
|
24
|
+
placeholder="https://your domain URL"
|
|
25
|
+
variant="outlined"
|
|
26
|
+
density="compact"
|
|
27
|
+
hide-details="auto"
|
|
28
|
+
class="mb-3"
|
|
29
|
+
/>
|
|
32
30
|
|
|
33
31
|
<div class="field-label">Device ID <span>*</span></div>
|
|
34
32
|
<v-text-field
|
|
@@ -175,10 +173,6 @@ function submit() {
|
|
|
175
173
|
status: monitorEnabled.value ? "active" : "inactive",
|
|
176
174
|
};
|
|
177
175
|
|
|
178
|
-
if (props.mode === "edit") {
|
|
179
|
-
delete payload.baseUrl;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
176
|
emit("submit", payload);
|
|
183
177
|
}
|
|
184
178
|
</script>
|
|
@@ -859,12 +859,32 @@ function getFriendlyHidError(error: any) {
|
|
|
859
859
|
return "Unable to verify the HID reader session. Please check the reader username and password, then try again.";
|
|
860
860
|
}
|
|
861
861
|
|
|
862
|
+
if (
|
|
863
|
+
message.includes("status 401") ||
|
|
864
|
+
message.includes("401 Authorization Required") ||
|
|
865
|
+
lowerMessage.includes("authorization required")
|
|
866
|
+
) {
|
|
867
|
+
return "Unable to authorize the HID gateway connection. Please check the relay credentials on the server, then try again.";
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if (message.includes("status 403") || lowerMessage.includes("forbidden")) {
|
|
871
|
+
return "The HID gateway rejected this request. Please check the relay access permissions and try again.";
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (message.includes("status 404") || lowerMessage.includes("not found")) {
|
|
875
|
+
return "The HID gateway endpoint could not be found. Please check the reader Base URL and try again.";
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if (lowerMessage.includes("<html") || lowerMessage.includes("<!doctype")) {
|
|
879
|
+
return "The HID gateway returned an unexpected response. Please check the relay configuration and try again.";
|
|
880
|
+
}
|
|
881
|
+
|
|
862
882
|
if (message.includes("reader is not active")) {
|
|
863
883
|
return "This HID reader is not active. Please enable the reader before syncing.";
|
|
864
884
|
}
|
|
865
885
|
|
|
866
886
|
if (message.includes("HID Amico request failed:")) {
|
|
867
|
-
return
|
|
887
|
+
return "The HID device rejected the request. Please check the reader connection and try again.";
|
|
868
888
|
}
|
|
869
889
|
|
|
870
890
|
return message || "The HID device rejected the request. Please check the reader connection and try again.";
|
|
@@ -77,6 +77,22 @@
|
|
|
77
77
|
</v-autocomplete>
|
|
78
78
|
</v-col>
|
|
79
79
|
|
|
80
|
+
<v-col v-if="props.unitId" cols="12">
|
|
81
|
+
<EntryPassInformation
|
|
82
|
+
v-model="memberPassType"
|
|
83
|
+
v-model:quantity="memberPassQuantity"
|
|
84
|
+
v-model:cards="memberPassCards"
|
|
85
|
+
:settings="props.settings"
|
|
86
|
+
:loading="props.settingsLoading"
|
|
87
|
+
:site-id="props.site"
|
|
88
|
+
:unit-id="props.unitId"
|
|
89
|
+
:visitor-type="props.type"
|
|
90
|
+
:hid-qr-code-enabled="props.hidQrCodeEnabled"
|
|
91
|
+
:hid-qr-printer-configured="props.hidQrPrinterConfigured"
|
|
92
|
+
:excluded-card-ids="props.selectedNfcCards.map((c) => c._id)"
|
|
93
|
+
/>
|
|
94
|
+
</v-col>
|
|
95
|
+
|
|
80
96
|
<v-col cols="12">
|
|
81
97
|
<InputLabel
|
|
82
98
|
class="text-capitalize"
|
|
@@ -164,6 +180,30 @@ const props = defineProps({
|
|
|
164
180
|
type: Boolean,
|
|
165
181
|
default: false,
|
|
166
182
|
},
|
|
183
|
+
settings: {
|
|
184
|
+
type: Object as PropType<Record<string, any> | null>,
|
|
185
|
+
default: null,
|
|
186
|
+
},
|
|
187
|
+
settingsLoading: {
|
|
188
|
+
type: Boolean,
|
|
189
|
+
default: false,
|
|
190
|
+
},
|
|
191
|
+
unitId: {
|
|
192
|
+
type: String as PropType<string | null>,
|
|
193
|
+
default: null,
|
|
194
|
+
},
|
|
195
|
+
hidQrCodeEnabled: {
|
|
196
|
+
type: Boolean,
|
|
197
|
+
default: false,
|
|
198
|
+
},
|
|
199
|
+
hidQrPrinterConfigured: {
|
|
200
|
+
type: Boolean,
|
|
201
|
+
default: false,
|
|
202
|
+
},
|
|
203
|
+
selectedNfcCards: {
|
|
204
|
+
type: Array as PropType<{ _id: string; cardNo: string }[]>,
|
|
205
|
+
default: () => [],
|
|
206
|
+
},
|
|
167
207
|
});
|
|
168
208
|
|
|
169
209
|
const { requiredRule } = useUtils();
|
|
@@ -201,6 +241,9 @@ const dialog = reactive({
|
|
|
201
241
|
});
|
|
202
242
|
|
|
203
243
|
const selectedPass = ref<string>("");
|
|
244
|
+
const memberPassType = ref<string | null>(null);
|
|
245
|
+
const memberPassQuantity = ref<number | null>(1);
|
|
246
|
+
const memberPassCards = ref<{ _id: string; cardNo: string }[]>([]);
|
|
204
247
|
|
|
205
248
|
const members = defineModel<TMemberInfo[]>({ required: true, default: [] });
|
|
206
249
|
const committedMembers = ref<TMemberInfo[]>([]);
|
|
@@ -303,12 +346,27 @@ watch(scannedPassValue, (newVal) => {
|
|
|
303
346
|
showMessage("Scanned pass not available", "error");
|
|
304
347
|
});
|
|
305
348
|
|
|
349
|
+
function resetAccessCard() {
|
|
350
|
+
memberPassType.value = null;
|
|
351
|
+
memberPassQuantity.value = 1;
|
|
352
|
+
memberPassCards.value = [];
|
|
353
|
+
}
|
|
354
|
+
|
|
306
355
|
function handleClearForm() {
|
|
307
356
|
formRef.value?.reset();
|
|
357
|
+
resetAccessCard();
|
|
308
358
|
}
|
|
309
359
|
|
|
310
360
|
async function handleAddMember() {
|
|
311
|
-
committedMembers.value.push({
|
|
361
|
+
committedMembers.value.push({
|
|
362
|
+
...memberForm,
|
|
363
|
+
...(memberPassType.value ? {
|
|
364
|
+
passType: memberPassType.value,
|
|
365
|
+
passQuantity: memberPassQuantity.value,
|
|
366
|
+
passCards: memberPassCards.value,
|
|
367
|
+
} : {}),
|
|
368
|
+
} as any);
|
|
369
|
+
resetAccessCard();
|
|
312
370
|
handleClearForm();
|
|
313
371
|
}
|
|
314
372
|
|
|
@@ -145,11 +145,6 @@
|
|
|
145
145
|
</template>
|
|
146
146
|
|
|
147
147
|
<script setup lang="ts">
|
|
148
|
-
import {
|
|
149
|
-
getPermissionCount,
|
|
150
|
-
updateRolePermissionsInList,
|
|
151
|
-
} from "../utils/rolePermissionCounts";
|
|
152
|
-
|
|
153
148
|
const props = defineProps({
|
|
154
149
|
orgId: {
|
|
155
150
|
type: String,
|
|
@@ -270,10 +265,22 @@ const selectedPermissions = ref<Array<string>>([]);
|
|
|
270
265
|
const originalPermissions = ref<Array<string>>([]);
|
|
271
266
|
const edit = ref(false);
|
|
272
267
|
|
|
273
|
-
const { convertPermissionsToArray } = useUtils();
|
|
274
|
-
|
|
275
268
|
const roleId = ref("");
|
|
276
269
|
|
|
270
|
+
function getPermissionCount(permissions: unknown): number {
|
|
271
|
+
return Array.isArray(permissions) ? permissions.length : 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function updateRolePermissionsInList(
|
|
275
|
+
roles: Array<Record<string, any>>,
|
|
276
|
+
roleId: string,
|
|
277
|
+
permissions: string[]
|
|
278
|
+
) {
|
|
279
|
+
return roles.map((role) =>
|
|
280
|
+
role._id === roleId ? { ...role, permissions } : role
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
277
284
|
const { getRoleById: _getRoleById, deleteRole } = useRole();
|
|
278
285
|
|
|
279
286
|
const { data: role, refresh: getRoleById } = useLazyAsyncData(
|
|
@@ -340,7 +347,6 @@ function successfulUpdate() {
|
|
|
340
347
|
savedPermissions
|
|
341
348
|
);
|
|
342
349
|
void refreshRolesAfterUpdate(savedPermissions);
|
|
343
|
-
useLocalSetup(props.type);
|
|
344
350
|
}
|
|
345
351
|
|
|
346
352
|
async function refreshRolesAfterUpdate(savedPermissions: string[]) {
|
|
@@ -371,7 +371,9 @@ function show(message: string, color: string) {
|
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
// ANPR Settings
|
|
374
|
-
const { getANPRSettingBySite, createUpdateANPRSettings } = useANPRSettings(
|
|
374
|
+
const { getANPRSettingBySite, createUpdateANPRSettings } = useANPRSettings(
|
|
375
|
+
props.siteId
|
|
376
|
+
);
|
|
375
377
|
const isSaving = ref(false);
|
|
376
378
|
|
|
377
379
|
// Reactive object to hold the state of the 3 switches
|
|
@@ -204,12 +204,17 @@
|
|
|
204
204
|
v-model:cards="passCards" :settings="entryPassSettings"
|
|
205
205
|
:loading="entryPassSettingsPending || siteDataPending" :site-id="prop.site"
|
|
206
206
|
:unit-id="visitor.unit || null" :visitor-type="prop.type" :hid-qr-code-enabled="hidQrCodePassAllowed"
|
|
207
|
-
:hid-qr-printer-configured="hasHidQrPrinterConfig"
|
|
207
|
+
:hid-qr-printer-configured="hasHidQrPrinterConfig"
|
|
208
|
+
@update:available-qr-count="(val) => availableQrCount = val" />
|
|
208
209
|
</v-col>
|
|
209
210
|
|
|
210
211
|
<v-col v-show="withStep3 && contractorStep === 3" cols="12">
|
|
211
212
|
<MemberInformation v-model="visitor.members" :type="prop.type" :contractor-type="visitor.contractorType"
|
|
212
|
-
:site="prop.site" :selected-visitor-pass="visitor.visitorPass" :clearable="true"
|
|
213
|
+
:site="prop.site" :selected-visitor-pass="visitor.visitorPass" :clearable="true"
|
|
214
|
+
:settings="entryPassSettings" :settings-loading="entryPassSettingsPending || siteDataPending"
|
|
215
|
+
:unit-id="visitor.unit || null"
|
|
216
|
+
:hid-qr-code-enabled="hidQrCodePassAllowed" :hid-qr-printer-configured="hasHidQrPrinterConfig"
|
|
217
|
+
:selected-nfc-cards="passType === 'NFC' ? passCards : []" />
|
|
213
218
|
</v-col>
|
|
214
219
|
|
|
215
220
|
<v-col v-if="prop.mode === 'add'" cols="12" class="mt-2">
|
|
@@ -394,6 +399,7 @@ const visitor = reactive<Partial<TVisitorPayload>>({
|
|
|
394
399
|
const passType = ref<string | null>(null);
|
|
395
400
|
const passQuantity = ref<number | null>(1);
|
|
396
401
|
const passCards = ref<{ _id: string; cardNo: string }[]>([]);
|
|
402
|
+
const availableQrCount = ref<number | null>(null);
|
|
397
403
|
const hidQrPrintPayload = ref<string | null>(null);
|
|
398
404
|
const hidQrPrinted = ref(false);
|
|
399
405
|
|
|
@@ -628,10 +634,10 @@ function selectNricSearchResult(item: Partial<TPeople>) {
|
|
|
628
634
|
if (!visitor.company) {
|
|
629
635
|
visitor.company = companyNames.value?.[0] || visitor.company;
|
|
630
636
|
}
|
|
631
|
-
visitor.block = (item.block as any) ?? (visitor.block as any) ?? "";
|
|
632
|
-
visitor.level = (item.level as any) ?? (visitor.level as any) ?? "";
|
|
633
|
-
visitor.unit = item.unit ?? visitor.unit ?? "";
|
|
634
|
-
visitor.unitName = item.unitName ?? visitor.unitName;
|
|
637
|
+
// visitor.block = (item.block as any) ?? (visitor.block as any) ?? "";
|
|
638
|
+
// visitor.level = (item.level as any) ?? (visitor.level as any) ?? "";
|
|
639
|
+
// visitor.unit = item.unit ?? visitor.unit ?? "";
|
|
640
|
+
// visitor.unitName = item.unitName ?? visitor.unitName;
|
|
635
641
|
|
|
636
642
|
setTimeout(() => {
|
|
637
643
|
currentAutofillSource.value = null;
|
|
@@ -990,6 +996,20 @@ async function handleNextPage() {
|
|
|
990
996
|
return;
|
|
991
997
|
}
|
|
992
998
|
const step = contractorStep.value;
|
|
999
|
+
if (step === 2 && passType.value === "QR") {
|
|
1000
|
+
if (availableQrCount.value === null) {
|
|
1001
|
+
errorMessage.value = "Please wait while QR passes are being generated...";
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
if (availableQrCount.value === 0) {
|
|
1005
|
+
errorMessage.value = "No QR passes available. Add a non-physical card to this unit in Access Management first.";
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (step === 2 && passType.value === "NFC" && passCards.value.length === 0) {
|
|
1010
|
+
errorMessage.value = "Please select at least one NFC card before proceeding.";
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
993
1013
|
if (step < 3) contractorStep.value++;
|
|
994
1014
|
else await submit();
|
|
995
1015
|
}
|
|
@@ -1098,7 +1118,15 @@ async function submit() {
|
|
|
1098
1118
|
type: passType.value === "QR" ? "QRCODE" : passType.value,
|
|
1099
1119
|
nfcCards: passCards.value,
|
|
1100
1120
|
acm_url: acmUrl,
|
|
1101
|
-
|
|
1121
|
+
user: {
|
|
1122
|
+
visitorId,
|
|
1123
|
+
name: visitor.name,
|
|
1124
|
+
nric: visitor.nric,
|
|
1125
|
+
contact: visitor.contact,
|
|
1126
|
+
company: visitor.company,
|
|
1127
|
+
type: visitor.type,
|
|
1128
|
+
plateNumber: visitor.plateNumber,
|
|
1129
|
+
},
|
|
1102
1130
|
});
|
|
1103
1131
|
|
|
1104
1132
|
if (passType.value === "QR") {
|