@7365admin1/layer-common 3.2.8-staging.205 → 3.2.8-staging.207
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/components/HidAccessLogDashboard.vue +176 -246
- package/components/HidIntercomManagement.vue +51 -18
- package/components/HidQrCodeConfiguration.vue +2 -3
- package/components/HidReaderForm.vue +176 -10
- package/components/HidReaderManagement.vue +211 -96
- package/components/HidServiceSettingsPanel.vue +21 -6
- package/components/HidUserEnrollment.vue +371 -198
- package/components/Layout/NavigationDrawer.vue +19 -2
- package/composables/useHidAmico.ts +113 -28
- package/composables/useHidNavigation.ts +4 -2
- package/composables/useOptionalServices.ts +26 -16
- package/package.json +1 -1
|
@@ -169,13 +169,30 @@ const { menuItem: hidFaceReaderMenu } = useHidFaceReaderMenu({
|
|
|
169
169
|
cacheKey: "layout-navigation-hid-site",
|
|
170
170
|
});
|
|
171
171
|
|
|
172
|
-
const
|
|
172
|
+
const HID_NAVIGATION_PERMISSIONS = [
|
|
173
|
+
"access-card-mgmt:see-all-card",
|
|
174
|
+
"access-card-mgmt:see-all-qr-tagging",
|
|
175
|
+
"access-card-mgmt:view",
|
|
176
|
+
"access-card-mgmt:add-access-card",
|
|
177
|
+
"access-card-mgmt:update-access-card",
|
|
178
|
+
"access-card-mgmt:delete-access-card",
|
|
179
|
+
"access-card-mgmt:assign-access-card",
|
|
180
|
+
"access-card-mgmt:manage-hid",
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
const { userAppRole } = useLocalSetup();
|
|
184
|
+
const canAccessHid = computed(() => {
|
|
185
|
+
const permissions = userAppRole.value?.permissions ?? [];
|
|
186
|
+
return permissions.includes("*") || HID_NAVIGATION_PERMISSIONS.some(
|
|
187
|
+
(permission) => permissions.includes(permission),
|
|
188
|
+
);
|
|
189
|
+
});
|
|
173
190
|
|
|
174
191
|
const navigationItems = computed(() => {
|
|
175
192
|
const items = [...(props.navigationItems as TNavigationItem[])];
|
|
176
193
|
|
|
177
194
|
if (
|
|
178
|
-
|
|
195
|
+
canAccessHid.value &&
|
|
179
196
|
hidFaceReaderMenu.value &&
|
|
180
197
|
!items.some((item) => item.title === hidFaceReaderMenu.value?.title)
|
|
181
198
|
) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type HidReaderPayload = {
|
|
1
|
+
export type HidReaderPayload = {
|
|
2
2
|
site?: string;
|
|
3
3
|
name?: string;
|
|
4
4
|
location?: string;
|
|
@@ -6,14 +6,26 @@ type HidReaderPayload = {
|
|
|
6
6
|
username?: string;
|
|
7
7
|
password?: string;
|
|
8
8
|
deviceId?: string;
|
|
9
|
+
serial?: string;
|
|
10
|
+
firmwareVersion?: string;
|
|
11
|
+
readerModel?: "VL35LF" | "VL70LF" | "unknown";
|
|
12
|
+
capabilities?: Record<string, boolean>;
|
|
9
13
|
portalId?: number;
|
|
10
14
|
portalName?: string;
|
|
11
15
|
monitorPath?: string;
|
|
16
|
+
monitorStatus?: "unconfigured" | "configured" | "disabled" | "failed";
|
|
17
|
+
monitorEnabled?: boolean;
|
|
18
|
+
operatingMode?: "standalone" | "online";
|
|
19
|
+
cardReadingMode?: "unconfigured" | "pacs" | "csn" | "csn_for_mifare";
|
|
20
|
+
csnByteOrder?: "msb" | "lsb";
|
|
21
|
+
pacsFormat?: "raw" | "wiegand";
|
|
12
22
|
enabled?: boolean;
|
|
13
23
|
status?: string;
|
|
14
24
|
lastSyncAt?: string;
|
|
15
25
|
lastSyncStatus?: "idle" | "running" | "completed" | "failed";
|
|
16
26
|
lastSyncMessage?: string;
|
|
27
|
+
lastCallbackAt?: string;
|
|
28
|
+
lastCallbackType?: string;
|
|
17
29
|
};
|
|
18
30
|
|
|
19
31
|
type HidIdentityPayload = {
|
|
@@ -24,10 +36,32 @@ type HidIdentityPayload = {
|
|
|
24
36
|
person?: string;
|
|
25
37
|
user?: string;
|
|
26
38
|
member?: string;
|
|
39
|
+
serviceProvider?: string;
|
|
27
40
|
visitor?: string;
|
|
28
|
-
type?: "resident" | "staff" | "contractor" | "visitor" | "unknown";
|
|
41
|
+
type?: "resident" | "staff" | "contractor" | "visitor" | "admin" | "unknown";
|
|
29
42
|
status?: "active" | "inactive" | "deleted";
|
|
30
|
-
metadata?: Record<string,
|
|
43
|
+
metadata?: Record<string, unknown>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type HidApiRecord = {
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
data?: HidApiRecord;
|
|
49
|
+
items?: HidApiRecord[];
|
|
50
|
+
identities?: HidApiRecord[];
|
|
51
|
+
users?: HidApiRecord[];
|
|
52
|
+
message?: string;
|
|
53
|
+
};
|
|
54
|
+
type HidCollectionResponse = HidApiRecord & {
|
|
55
|
+
items?: HidApiRecord[];
|
|
56
|
+
total?: number;
|
|
57
|
+
pages?: number;
|
|
58
|
+
pageRange?: string;
|
|
59
|
+
data?: HidApiRecord & {
|
|
60
|
+
items?: HidApiRecord[];
|
|
61
|
+
total?: number;
|
|
62
|
+
pages?: number;
|
|
63
|
+
pageRange?: string;
|
|
64
|
+
};
|
|
31
65
|
};
|
|
32
66
|
|
|
33
67
|
type HidVisitorQrData = {
|
|
@@ -74,7 +108,7 @@ export type HidPhysicalCard = {
|
|
|
74
108
|
};
|
|
75
109
|
|
|
76
110
|
type HidPhysicalCardInput =
|
|
77
|
-
| { cardType: "pacs"; facilityCode: number; cardNumber: number }
|
|
111
|
+
| { cardType: "pacs"; facilityCode: string | number; cardNumber: string | number }
|
|
78
112
|
| { cardType: "csn"; cardValue: string };
|
|
79
113
|
|
|
80
114
|
export type HidSipAccountData = {
|
|
@@ -110,48 +144,68 @@ export function isUnknownSiteFieldError(error: unknown): boolean {
|
|
|
110
144
|
export default function useHidAmico() {
|
|
111
145
|
const basePath = "/api/access-management/hid";
|
|
112
146
|
|
|
113
|
-
function getReaders(query:
|
|
114
|
-
return useNuxtApp().$api<
|
|
147
|
+
function getReaders(query: HidApiRecord = {}) {
|
|
148
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers`, {
|
|
115
149
|
method: "GET",
|
|
116
150
|
query,
|
|
117
151
|
});
|
|
118
152
|
}
|
|
119
153
|
|
|
120
154
|
function createReader(payload: HidReaderPayload) {
|
|
121
|
-
return useNuxtApp().$api<
|
|
155
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers`, {
|
|
122
156
|
method: "POST",
|
|
123
157
|
body: payload,
|
|
124
158
|
});
|
|
125
159
|
}
|
|
126
160
|
|
|
127
161
|
function updateReader(readerId: string, payload: HidReaderPayload) {
|
|
128
|
-
return useNuxtApp().$api<
|
|
162
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}`, {
|
|
129
163
|
method: "PATCH",
|
|
130
164
|
body: payload,
|
|
131
165
|
});
|
|
132
166
|
}
|
|
133
167
|
|
|
134
168
|
function deleteReader(readerId: string) {
|
|
135
|
-
return useNuxtApp().$api<
|
|
169
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}`, {
|
|
136
170
|
method: "DELETE",
|
|
137
171
|
});
|
|
138
172
|
}
|
|
139
173
|
|
|
140
174
|
function testReader(readerId: string) {
|
|
141
|
-
return useNuxtApp().$api<
|
|
175
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/test`, {
|
|
142
176
|
method: "POST",
|
|
143
177
|
});
|
|
144
178
|
}
|
|
145
179
|
|
|
146
|
-
function syncReader(readerId: string, payload:
|
|
147
|
-
return useNuxtApp().$api<
|
|
180
|
+
function syncReader(readerId: string, payload: HidApiRecord = {}) {
|
|
181
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/sync`, {
|
|
148
182
|
method: "POST",
|
|
149
183
|
body: payload,
|
|
150
184
|
});
|
|
151
185
|
}
|
|
152
186
|
|
|
153
|
-
function
|
|
154
|
-
return useNuxtApp().$api<
|
|
187
|
+
function configureReaderIntegration(readerId: string) {
|
|
188
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/configure`, {
|
|
189
|
+
method: "POST",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function setReaderMonitor(readerId: string, enabled: boolean) {
|
|
194
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/monitor`, {
|
|
195
|
+
method: "PUT",
|
|
196
|
+
body: { enabled },
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function setReaderOperatingMode(readerId: string, mode: "standalone" | "online") {
|
|
201
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/operating-mode`, {
|
|
202
|
+
method: "PUT",
|
|
203
|
+
body: { mode },
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function runObjectOperation(readerId: string, payload: HidApiRecord) {
|
|
208
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/objects`, {
|
|
155
209
|
method: "POST",
|
|
156
210
|
body: payload,
|
|
157
211
|
});
|
|
@@ -168,35 +222,61 @@ export default function useHidAmico() {
|
|
|
168
222
|
}
|
|
169
223
|
|
|
170
224
|
function getReaderConfiguration(readerId: string, payload: Record<string, string[]> = {}) {
|
|
171
|
-
return useNuxtApp().$api<
|
|
225
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/configuration`, {
|
|
172
226
|
method: "POST",
|
|
173
227
|
body: payload,
|
|
174
228
|
});
|
|
175
229
|
}
|
|
176
230
|
|
|
177
|
-
function setReaderConfiguration(readerId: string, payload:
|
|
178
|
-
return useNuxtApp().$api<
|
|
231
|
+
function setReaderConfiguration(readerId: string, payload: HidApiRecord) {
|
|
232
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/configuration`, {
|
|
179
233
|
method: "PUT",
|
|
180
234
|
body: payload,
|
|
181
235
|
});
|
|
182
236
|
}
|
|
183
237
|
|
|
184
|
-
function getIdentities(readerId: string, query:
|
|
185
|
-
return useNuxtApp().$api<
|
|
238
|
+
function getIdentities(readerId: string, query: HidApiRecord = {}) {
|
|
239
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/identities`, {
|
|
240
|
+
method: "GET",
|
|
241
|
+
query,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function getReaderUsers(readerId: string, query: {
|
|
246
|
+
page?: number;
|
|
247
|
+
limit?: number;
|
|
248
|
+
search?: string;
|
|
249
|
+
status?: "mapped" | "unmapped" | "";
|
|
250
|
+
} = {}) {
|
|
251
|
+
return useNuxtApp().$api<HidCollectionResponse>(`${basePath}/readers/${readerId}/users`, {
|
|
252
|
+
method: "GET",
|
|
253
|
+
query,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function getReaderAccessLogs(readerId: string, query: {
|
|
258
|
+
page?: number;
|
|
259
|
+
limit?: number;
|
|
260
|
+
search?: string;
|
|
261
|
+
status?: "authorized" | "not_authorized" | "unknown" | "";
|
|
262
|
+
method?: "facial" | "qr_code" | "id_password" | "pin" | "card" | "";
|
|
263
|
+
tab?: "resident" | "visitor" | "administrator";
|
|
264
|
+
} = {}) {
|
|
265
|
+
return useNuxtApp().$api<HidCollectionResponse>(`${basePath}/readers/${readerId}/access-logs`, {
|
|
186
266
|
method: "GET",
|
|
187
267
|
query,
|
|
188
268
|
});
|
|
189
269
|
}
|
|
190
270
|
|
|
191
|
-
function getLogs(readerId: string, query:
|
|
192
|
-
return useNuxtApp().$api<
|
|
271
|
+
function getLogs(readerId: string, query: HidApiRecord = {}) {
|
|
272
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/logs`, {
|
|
193
273
|
method: "GET",
|
|
194
274
|
query,
|
|
195
275
|
});
|
|
196
276
|
}
|
|
197
277
|
|
|
198
278
|
function getUserImage(readerId: string, hidUserId: string | number) {
|
|
199
|
-
return useNuxtApp().$api<
|
|
279
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/users/${hidUserId}/image`, {
|
|
200
280
|
method: "GET",
|
|
201
281
|
});
|
|
202
282
|
}
|
|
@@ -323,40 +403,40 @@ export default function useHidAmico() {
|
|
|
323
403
|
}
|
|
324
404
|
|
|
325
405
|
function createIdentity(readerId: string, payload: HidIdentityPayload) {
|
|
326
|
-
return useNuxtApp().$api<
|
|
406
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/identities`, {
|
|
327
407
|
method: "POST",
|
|
328
408
|
body: payload,
|
|
329
409
|
});
|
|
330
410
|
}
|
|
331
411
|
|
|
332
412
|
function updateIdentity(identityId: string, payload: HidIdentityPayload) {
|
|
333
|
-
return useNuxtApp().$api<
|
|
413
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/identities/${identityId}`, {
|
|
334
414
|
method: "PATCH",
|
|
335
415
|
body: payload,
|
|
336
416
|
});
|
|
337
417
|
}
|
|
338
418
|
|
|
339
419
|
function deleteIdentity(identityId: string) {
|
|
340
|
-
return useNuxtApp().$api<
|
|
420
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/identities/${identityId}`, {
|
|
341
421
|
method: "DELETE",
|
|
342
422
|
});
|
|
343
423
|
}
|
|
344
424
|
|
|
345
425
|
function getIntercomStatus(readerId: string) {
|
|
346
|
-
return useNuxtApp().$api<
|
|
426
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/intercom/status`, {
|
|
347
427
|
method: "GET",
|
|
348
428
|
});
|
|
349
429
|
}
|
|
350
430
|
|
|
351
431
|
function makeIntercomCall(readerId: string, target: string) {
|
|
352
|
-
return useNuxtApp().$api<
|
|
432
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/intercom/call`, {
|
|
353
433
|
method: "POST",
|
|
354
434
|
body: { target },
|
|
355
435
|
});
|
|
356
436
|
}
|
|
357
437
|
|
|
358
438
|
function finalizeIntercomCall(readerId: string) {
|
|
359
|
-
return useNuxtApp().$api<
|
|
439
|
+
return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/intercom/hangup`, {
|
|
360
440
|
method: "POST",
|
|
361
441
|
});
|
|
362
442
|
}
|
|
@@ -412,6 +492,9 @@ export default function useHidAmico() {
|
|
|
412
492
|
deleteReader,
|
|
413
493
|
testReader,
|
|
414
494
|
syncReader,
|
|
495
|
+
configureReaderIntegration,
|
|
496
|
+
setReaderMonitor,
|
|
497
|
+
setReaderOperatingMode,
|
|
415
498
|
runObjectOperation,
|
|
416
499
|
issueVisitorQr,
|
|
417
500
|
getReaderConfiguration,
|
|
@@ -429,6 +512,8 @@ export default function useHidAmico() {
|
|
|
429
512
|
setUserPin,
|
|
430
513
|
deleteUserPin,
|
|
431
514
|
getIdentities,
|
|
515
|
+
getReaderUsers,
|
|
516
|
+
getReaderAccessLogs,
|
|
432
517
|
createIdentity,
|
|
433
518
|
updateIdentity,
|
|
434
519
|
deleteIdentity,
|
|
@@ -5,6 +5,8 @@ type HidNavigationParams = {
|
|
|
5
5
|
site: string;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
type HidNavigationSite = Record<string, unknown>;
|
|
9
|
+
|
|
8
10
|
export default function useHidNavigation() {
|
|
9
11
|
const { getSiteById } = useSiteSettings();
|
|
10
12
|
const { getHidServiceEnabled } = useOptionalServices();
|
|
@@ -61,10 +63,10 @@ export default function useHidNavigation() {
|
|
|
61
63
|
}: {
|
|
62
64
|
org: Ref<string> | ComputedRef<string>;
|
|
63
65
|
site: Ref<string> | ComputedRef<string>;
|
|
64
|
-
fallbackSite?: Ref<
|
|
66
|
+
fallbackSite?: Ref<HidNavigationSite | undefined> | ComputedRef<HidNavigationSite | undefined>;
|
|
65
67
|
cacheKey?: string;
|
|
66
68
|
}) {
|
|
67
|
-
const siteDetails = ref<
|
|
69
|
+
const siteDetails = ref<HidNavigationSite | null>(null);
|
|
68
70
|
|
|
69
71
|
watch(
|
|
70
72
|
site,
|
|
@@ -32,7 +32,15 @@ function normalizeServiceKey(value: unknown) {
|
|
|
32
32
|
.replace(/[\s-]+/g, "_");
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
type OptionalServiceRecord = Record<string, unknown>;
|
|
36
|
+
|
|
37
|
+
function toOptionalServiceRecord(value: unknown): OptionalServiceRecord {
|
|
38
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
39
|
+
? value as OptionalServiceRecord
|
|
40
|
+
: {};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function itemHasService(item: unknown) {
|
|
36
44
|
if (!item) return false;
|
|
37
45
|
|
|
38
46
|
if (typeof item === "string") {
|
|
@@ -44,25 +52,26 @@ function itemHasService(item: any) {
|
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
if (typeof item === "object") {
|
|
55
|
+
const record = toOptionalServiceRecord(item);
|
|
47
56
|
const key = normalizeServiceKey(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
record.key ??
|
|
58
|
+
record.code ??
|
|
59
|
+
record.name ??
|
|
60
|
+
record.type ??
|
|
61
|
+
record.service ??
|
|
62
|
+
record.module ??
|
|
63
|
+
record.feature,
|
|
55
64
|
);
|
|
56
65
|
|
|
57
66
|
const isEnabled =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
(
|
|
67
|
+
record.enabled ??
|
|
68
|
+
record.active ??
|
|
69
|
+
record.isEnabled ??
|
|
70
|
+
(record.status ? record.status === "active" : true);
|
|
62
71
|
|
|
63
72
|
if (hidServiceKeys.includes(key)) return isEnabled !== false;
|
|
64
73
|
|
|
65
|
-
return Object.values(
|
|
74
|
+
return Object.values(record).some(itemHasService);
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
return false;
|
|
@@ -74,10 +83,11 @@ export default function useOptionalServices() {
|
|
|
74
83
|
() => ({}),
|
|
75
84
|
);
|
|
76
85
|
|
|
77
|
-
function hasHidService(source:
|
|
86
|
+
function hasHidService(source: OptionalServiceRecord | null | undefined) {
|
|
78
87
|
if (!source) return false;
|
|
79
88
|
|
|
80
|
-
|
|
89
|
+
const metadata = toOptionalServiceRecord(source.metadata);
|
|
90
|
+
if (itemHasService(metadata.services)) return true;
|
|
81
91
|
|
|
82
92
|
const presentGateFields = optionalServiceFields.filter((field) =>
|
|
83
93
|
Object.prototype.hasOwnProperty.call(source, field),
|
|
@@ -90,7 +100,7 @@ export default function useOptionalServices() {
|
|
|
90
100
|
|
|
91
101
|
function getHidServiceEnabled(
|
|
92
102
|
siteId: string,
|
|
93
|
-
source:
|
|
103
|
+
source: OptionalServiceRecord | null | undefined,
|
|
94
104
|
) {
|
|
95
105
|
if (siteId && Object.prototype.hasOwnProperty.call(hidServiceOverrides.value, siteId)) {
|
|
96
106
|
return hidServiceOverrides.value[siteId];
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "3.2.8-staging.
|
|
5
|
+
"version": "3.2.8-staging.207",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",
|