@7365admin1/layer-common 4.96.0 → 4.97.1-staging.500
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 +10 -4
- package/assets/css/primitives.css +57 -0
- package/assets/css/screens.css +8 -4
- package/components/AccessCardDetailsDialog.vue +59 -6
- package/components/AccessCardPreviewDialog.vue +371 -53
- package/components/AppSelect.vue +143 -4
- package/components/BuildingUnitFormEdit.vue +6 -0
- package/components/BuildingUnitManagement.vue +298 -0
- package/components/Dialog/UpdateMoreAction.vue +11 -1
- package/components/DocumentForm.vue +407 -112
- package/components/DocumentManagement.vue +213 -12
- package/components/Facility/BookingSetup.vue +63 -0
- package/components/HidAccessLogDashboard.vue +74 -17
- package/components/HidAccessPermissions.vue +424 -0
- package/components/HidIntercomManagement.vue +183 -14
- package/components/HidProfileQrCode.vue +332 -0
- package/components/HidQrCodeConfiguration.vue +17 -195
- package/components/HidReaderManagement.vue +398 -0
- package/components/HidReaderUserRoster.vue +44 -3
- package/components/HidUserEnrollment.vue +2239 -276
- package/components/InvitationClientForm.vue +19 -1
- package/components/Nfc/NFCPatrolRouteForm.vue +109 -58
- package/components/Nfc/NFCPatrolRouteMain.vue +3 -18
- package/components/Nfc/PatrolReport/PatrolActivityTable.vue +0 -8
- package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +1 -1
- package/components/ServiceProviderMain.vue +48 -0
- package/components/SiteProviderChange.vue +371 -0
- package/components/TableMain.vue +22 -7
- package/components/VehicleQrStickerDialog.vue +64 -4
- package/components/VisitorForm.vue +12 -0
- package/components/VisitorManagement.vue +267 -5
- package/composables/useAccessManagement.ts +17 -1
- package/composables/useCustomerSite.ts +29 -0
- package/composables/useDocument.ts +7 -0
- package/composables/useFacility.ts +11 -0
- package/composables/useHidAmico.ts +165 -0
- package/composables/useHidNavigation.ts +25 -1
- package/composables/useHidReaderSelection.ts +50 -0
- package/composables/useMember.ts +12 -0
- package/composables/useNFCPatrolReport.ts +36 -32
- package/composables/useNFCPatrolReportFilters.ts +21 -3
- package/composables/useNFCPatrolRoute.ts +10 -3
- package/composables/usePeople.ts +19 -0
- package/composables/useServiceProvider.ts +45 -2
- package/composables/useSiteCategory.ts +45 -0
- package/package.json +1 -1
- package/pages/[org]/[site]/access-mgmt/administrator/index.vue +1 -1
- package/pages/[org]/[site]/access-mgmt/hid-cards/index.vue +1 -1
- package/pages/[org]/[site]/access-mgmt/hid-qr-code/index.vue +23 -0
- package/pages/[org]/[site]/access-mgmt/hid-readers/index.vue +1 -1
- package/types/document.d.ts +14 -0
- package/types/facility.d.ts +4 -0
- package/types/member.d.ts +4 -0
- package/types/nfc-patrol-report.ts +0 -2
- package/types/people.d.ts +28 -1
- package/types/service-provider.d.ts +5 -0
- package/types/site.d.ts +7 -1
- package/utils/hid-enrolment-subject.ts +344 -0
- package/utils/hid-permission-assignments.ts +198 -0
- package/utils/hid-reader-selection.ts +52 -0
- package/utils/nfc-patrol-time.ts +99 -0
- package/utils/occupancy-role.ts +109 -0
- package/utils/service-type.ts +30 -0
- package/utils/vehicle-qr-design.ts +304 -20
- package/utils/vehicle-qr-sticker.ts +126 -20
|
@@ -21,33 +21,6 @@
|
|
|
21
21
|
<div class="config-body">
|
|
22
22
|
<div class="section-label config-body__title">HID Configuration</div>
|
|
23
23
|
|
|
24
|
-
<div class="form-section identification-section">
|
|
25
|
-
<div class="section-label">Enable/disable reader identification method</div>
|
|
26
|
-
<p class="section-description">
|
|
27
|
-
Toggles multi-factor access methods, allowing users to authenticate via biometric, physical card, or credential inputs.
|
|
28
|
-
</p>
|
|
29
|
-
<div class="methods-grid">
|
|
30
|
-
<div
|
|
31
|
-
v-for="method in identificationMethodOptions"
|
|
32
|
-
:key="method.key"
|
|
33
|
-
class="method-control"
|
|
34
|
-
>
|
|
35
|
-
<span>{{ method.label }}</span>
|
|
36
|
-
<v-switch
|
|
37
|
-
v-model="form.identificationMethods[method.key]"
|
|
38
|
-
class="app-switch"
|
|
39
|
-
hide-details
|
|
40
|
-
density="compact"
|
|
41
|
-
:loading="savingSection === `method-${method.key}`"
|
|
42
|
-
:disabled="Boolean(savingSection) || !form.readerId"
|
|
43
|
-
@update:model-value="saveIdentificationMethod(method.key)"
|
|
44
|
-
/>
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
<v-divider />
|
|
50
|
-
|
|
51
24
|
<div class="form-section">
|
|
52
25
|
<div class="section-label">Printer Setup</div>
|
|
53
26
|
<div class="printer-grid">
|
|
@@ -224,14 +197,11 @@
|
|
|
224
197
|
|
|
225
198
|
|
|
226
199
|
<script setup lang="ts">
|
|
227
|
-
type HidIdentificationMethod = keyof NonNullable<THidQrCodePassConfig["identificationMethods"]>;
|
|
228
|
-
|
|
229
200
|
type HidQrConfig = Omit<
|
|
230
201
|
THidQrCodePassConfig,
|
|
231
202
|
"identificationMethods" | "onlineMode" | "updatedAt" | "qrGatePermissions"
|
|
232
203
|
> & {
|
|
233
204
|
onlineMode: boolean;
|
|
234
|
-
identificationMethods: Record<HidIdentificationMethod, boolean>;
|
|
235
205
|
qrGatePermissions: {
|
|
236
206
|
resident: string[];
|
|
237
207
|
propertyManagement: string[];
|
|
@@ -265,11 +235,7 @@ const runtimeConfig = useRuntimeConfig();
|
|
|
265
235
|
const isPermissionManager = computed(() => runtimeConfig.public.APP === "security_agency");
|
|
266
236
|
|
|
267
237
|
const { getSiteById, updateSitebyId } = useSiteSettings();
|
|
268
|
-
const {
|
|
269
|
-
getReaders,
|
|
270
|
-
getReaderConfiguration,
|
|
271
|
-
setReaderConfiguration,
|
|
272
|
-
} = useHidAmico();
|
|
238
|
+
const { getReaders } = useHidAmico();
|
|
273
239
|
const {
|
|
274
240
|
requestDevice: requestPrinterDevice,
|
|
275
241
|
testConnection: testPrinterConnection,
|
|
@@ -284,14 +250,6 @@ const defaultConfig: HidQrConfig = {
|
|
|
284
250
|
propertyManagement: [],
|
|
285
251
|
},
|
|
286
252
|
qrFormat: "0",
|
|
287
|
-
identificationMethods: {
|
|
288
|
-
facial: true,
|
|
289
|
-
card: true,
|
|
290
|
-
qrCode: false,
|
|
291
|
-
idPassword: true,
|
|
292
|
-
pin: false,
|
|
293
|
-
bluetooth: false,
|
|
294
|
-
},
|
|
295
253
|
printer: {
|
|
296
254
|
vendorId: "",
|
|
297
255
|
productId: "",
|
|
@@ -321,16 +279,6 @@ const visitorQrGateOptions = computed(() => readers.value
|
|
|
321
279
|
title: String(reader.name || reader.deviceId || reader._id) + " - " + String(reader.portalName || "Portal"),
|
|
322
280
|
value: reader._id,
|
|
323
281
|
})));
|
|
324
|
-
const identificationMethodOptions: Array<{
|
|
325
|
-
key: HidIdentificationMethod;
|
|
326
|
-
label: string;
|
|
327
|
-
}> = [
|
|
328
|
-
{ key: "facial", label: "Facial" },
|
|
329
|
-
{ key: "card", label: "Card" },
|
|
330
|
-
{ key: "qrCode", label: "QR Code" },
|
|
331
|
-
{ key: "idPassword", label: "ID Password" },
|
|
332
|
-
{ key: "pin", label: "PIN" },
|
|
333
|
-
];
|
|
334
282
|
const siteName = computed(() => siteData.value?.name || "Site");
|
|
335
283
|
const siteLabel = computed(() => siteData.value?.code || siteData.value?.block || props.site);
|
|
336
284
|
const primaryQrGateReaderId = computed(() => (
|
|
@@ -371,7 +319,6 @@ async function loadConfig() {
|
|
|
371
319
|
const readerList = readerResponse as HidReaderListResponse;
|
|
372
320
|
readers.value = readerList.items ?? readerList.data?.items ?? readerList.data?.readers ?? [];
|
|
373
321
|
const config = siteData.value?.metadata?.hidQrCodePass || {};
|
|
374
|
-
const configuredMethods = config.identificationMethods;
|
|
375
322
|
Object.assign(form, {
|
|
376
323
|
enabled: Boolean(config.enabled),
|
|
377
324
|
// Visitor QR is reader-local. Do not restore a legacy Online Mode value
|
|
@@ -392,14 +339,6 @@ async function loadConfig() {
|
|
|
392
339
|
|| "",
|
|
393
340
|
),
|
|
394
341
|
qrFormat: "0",
|
|
395
|
-
identificationMethods: {
|
|
396
|
-
facial: configuredMethods?.facial ?? true,
|
|
397
|
-
card: configuredMethods?.card ?? true,
|
|
398
|
-
qrCode: configuredMethods?.qrCode ?? Boolean(config.enabled),
|
|
399
|
-
idPassword: configuredMethods?.idPassword ?? true,
|
|
400
|
-
pin: configuredMethods?.pin ?? false,
|
|
401
|
-
bluetooth: false,
|
|
402
|
-
},
|
|
403
342
|
printer: {
|
|
404
343
|
vendorId: String(config.printer?.vendorId || ""),
|
|
405
344
|
productId: String(config.printer?.productId || ""),
|
|
@@ -410,57 +349,25 @@ async function loadConfig() {
|
|
|
410
349
|
},
|
|
411
350
|
validityMinutes: config.validityMinutes ? Number(config.validityMinutes) : null,
|
|
412
351
|
});
|
|
413
|
-
|
|
414
|
-
await loadReaderConfiguration();
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function isUnknownRecord(value: unknown): value is Record<string, unknown> {
|
|
418
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function getConfigurationData(response: unknown) {
|
|
422
|
-
if (!isUnknownRecord(response)) return {};
|
|
423
|
-
return isUnknownRecord(response.data) ? response.data : response;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function isEnabledConfiguration(value: unknown) {
|
|
427
|
-
return value === true || value === 1 || value === "1";
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
async function loadReaderConfiguration() {
|
|
431
|
-
if (!form.readerId) return;
|
|
432
|
-
|
|
433
|
-
try {
|
|
434
|
-
const response = await getReaderConfiguration(form.readerId, {
|
|
435
|
-
identifier: [
|
|
436
|
-
"card_identification_enabled",
|
|
437
|
-
"pin_identification_enabled",
|
|
438
|
-
"multi_factor_authentication",
|
|
439
|
-
],
|
|
440
|
-
});
|
|
441
|
-
const configuration = getConfigurationData(response);
|
|
442
|
-
const identifier = isUnknownRecord(configuration.identifier) ? configuration.identifier : {};
|
|
443
|
-
|
|
444
|
-
if (identifier.pin_identification_enabled !== undefined) {
|
|
445
|
-
const pinEnabled = isEnabledConfiguration(identifier.pin_identification_enabled);
|
|
446
|
-
form.identificationMethods.pin = pinEnabled;
|
|
447
|
-
form.identificationMethods.idPassword = !pinEnabled;
|
|
448
|
-
}
|
|
449
|
-
if (identifier.card_identification_enabled !== undefined) {
|
|
450
|
-
form.identificationMethods.card = isEnabledConfiguration(
|
|
451
|
-
identifier.card_identification_enabled,
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
} catch (error: unknown) {
|
|
455
|
-
console.warn("Unable to load HID reader configuration:", errorConverter(error));
|
|
456
|
-
}
|
|
457
352
|
}
|
|
458
353
|
|
|
459
354
|
function buildPayload() {
|
|
355
|
+
/*
|
|
356
|
+
* `enabled` and `identificationMethods` are passed through from what was
|
|
357
|
+
* loaded, never recomputed.
|
|
358
|
+
*
|
|
359
|
+
* Which credentials a reader accepts now lives on the READER record and is
|
|
360
|
+
* set from HID Readers > Identification Methods, because the device is what
|
|
361
|
+
* holds them. The toggles that used to derive these two values are gone from
|
|
362
|
+
* this screen, so deriving them again from a form that no longer has them
|
|
363
|
+
* would erase the stored copy and flip `enabled` every time somebody saved
|
|
364
|
+
* the printer settings.
|
|
365
|
+
*/
|
|
366
|
+
const storedQrPass = siteData.value?.metadata?.hidQrCodePass || {};
|
|
460
367
|
const metadata = {
|
|
461
368
|
...(siteData.value?.metadata || {}),
|
|
462
369
|
hidQrCodePass: {
|
|
463
|
-
enabled:
|
|
370
|
+
enabled: Boolean(storedQrPass.enabled),
|
|
464
371
|
onlineMode: false,
|
|
465
372
|
// Kept only for old background/mobile flows. Gate permissions, not this
|
|
466
373
|
// compatibility value, decide where a new Visitor QR may be scanned.
|
|
@@ -471,7 +378,9 @@ function buildPayload() {
|
|
|
471
378
|
},
|
|
472
379
|
// Visitor QR passes always use Amico alphanumeric qrcodes.
|
|
473
380
|
qrFormat: "0",
|
|
474
|
-
|
|
381
|
+
...(storedQrPass.identificationMethods
|
|
382
|
+
? { identificationMethods: storedQrPass.identificationMethods }
|
|
383
|
+
: {}),
|
|
475
384
|
printer: {
|
|
476
385
|
vendorId: form.printer.vendorId.trim(),
|
|
477
386
|
productId: form.printer.productId.trim(),
|
|
@@ -507,43 +416,6 @@ async function saveSection(section: string) {
|
|
|
507
416
|
}
|
|
508
417
|
}
|
|
509
418
|
|
|
510
|
-
async function saveIdentificationMethod(method: HidIdentificationMethod) {
|
|
511
|
-
if (!props.site) return;
|
|
512
|
-
|
|
513
|
-
form.enabled = form.identificationMethods.qrCode;
|
|
514
|
-
|
|
515
|
-
savingSection.value = `method-${method}`;
|
|
516
|
-
try {
|
|
517
|
-
if (method === "card") {
|
|
518
|
-
await setReaderConfiguration(form.readerId, {
|
|
519
|
-
identifier: {
|
|
520
|
-
card_identification_enabled: form.identificationMethods.card ? "1" : "0",
|
|
521
|
-
},
|
|
522
|
-
});
|
|
523
|
-
} else if (method === "pin" || method === "idPassword") {
|
|
524
|
-
if (method === "pin" && form.identificationMethods.pin) {
|
|
525
|
-
form.identificationMethods.idPassword = false;
|
|
526
|
-
} else if (method === "idPassword" && form.identificationMethods.idPassword) {
|
|
527
|
-
form.identificationMethods.pin = false;
|
|
528
|
-
}
|
|
529
|
-
await setReaderConfiguration(form.readerId, {
|
|
530
|
-
identifier: {
|
|
531
|
-
pin_identification_enabled: form.identificationMethods.pin ? "1" : "0",
|
|
532
|
-
// Mode 1: PIN is an alternative credential, never a second factor.
|
|
533
|
-
multi_factor_authentication: "0",
|
|
534
|
-
},
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
await updateSitebyId(props.site, buildPayload());
|
|
538
|
-
showMessage(`${identificationMethodOptions.find((item) => item.key === method)?.label || "Identification method"} updated.`, "success");
|
|
539
|
-
} catch (error: unknown) {
|
|
540
|
-
await loadConfig();
|
|
541
|
-
showMessage(errorConverter(error), "error");
|
|
542
|
-
} finally {
|
|
543
|
-
savingSection.value = "";
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
419
|
async function scanPrinter() {
|
|
548
420
|
if (!("usb" in navigator)) {
|
|
549
421
|
showMessage("USB printer scan is not available in this browser.", "error");
|
|
@@ -651,51 +523,6 @@ function showMessage(text: string, color: string) {
|
|
|
651
523
|
padding: 16px 0;
|
|
652
524
|
}
|
|
653
525
|
|
|
654
|
-
.identification-section {
|
|
655
|
-
padding-bottom: 20px;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
.methods-grid {
|
|
659
|
-
display: grid;
|
|
660
|
-
grid-template-columns: repeat(6, minmax(120px, 1fr));
|
|
661
|
-
gap: 18px;
|
|
662
|
-
margin-top: 16px;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
.method-control {
|
|
666
|
-
display: flex;
|
|
667
|
-
align-items: center;
|
|
668
|
-
justify-content: space-between;
|
|
669
|
-
min-width: 0;
|
|
670
|
-
min-height: 42px;
|
|
671
|
-
padding: 0 10px 0 14px;
|
|
672
|
-
border: 1px solid var(--border);
|
|
673
|
-
border-radius: var(--r-inner);
|
|
674
|
-
color: var(--text2);
|
|
675
|
-
font-family: var(--font-sans);
|
|
676
|
-
font-size: 12px;
|
|
677
|
-
font-weight: 700;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
.method-control span {
|
|
681
|
-
overflow: hidden;
|
|
682
|
-
text-overflow: ellipsis;
|
|
683
|
-
white-space: nowrap;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
.method-control--disabled {
|
|
687
|
-
background-color: var(--hover);
|
|
688
|
-
color: var(--muted);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
.method-control :deep(.v-switch) {
|
|
692
|
-
flex: 0 0 auto;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
.method-control :deep(.v-selection-control) {
|
|
696
|
-
min-height: 32px;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
526
|
/* The three `.hid-config-switch` rules are gone: `.app-switch` in
|
|
700
527
|
primitives.css is the handoff's toggle, and it is shared with the other two
|
|
701
528
|
HID panels that have one. */
|
|
@@ -867,10 +694,6 @@ function showMessage(text: string, color: string) {
|
|
|
867
694
|
}
|
|
868
695
|
|
|
869
696
|
@media (max-width: 1100px) {
|
|
870
|
-
.methods-grid {
|
|
871
|
-
grid-template-columns: repeat(3, minmax(140px, 1fr));
|
|
872
|
-
}
|
|
873
|
-
|
|
874
697
|
.printer-grid,
|
|
875
698
|
.reader-grid,
|
|
876
699
|
.template-grid,
|
|
@@ -891,7 +714,6 @@ function showMessage(text: string, color: string) {
|
|
|
891
714
|
.reader-grid,
|
|
892
715
|
.template-grid,
|
|
893
716
|
.validity-grid,
|
|
894
|
-
.methods-grid,
|
|
895
717
|
.permission-location,
|
|
896
718
|
.permission-row,
|
|
897
719
|
.permission-actions {
|