@7365admin1/layer-common 3.0.8 → 3.0.10
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 +12 -0
- package/components/DashboardMain.vue +1864 -803
- package/components/EntryPassInformation.vue +60 -0
- package/components/HidAccessLogDashboard.vue +1691 -0
- package/components/HidEnabledGate.vue +51 -0
- package/components/HidIdentityMapping.vue +975 -0
- package/components/HidQrCodeConfiguration.vue +618 -0
- package/components/HidReaderForm.vue +246 -0
- package/components/HidReaderManagement.vue +1233 -0
- package/components/HidServiceSettingsPanel.vue +150 -0
- package/components/HidUserEnrollment.vue +1274 -0
- package/components/Layout/NavigationDrawer.vue +31 -1
- package/components/MemberInformation.vue +1 -1
- package/components/NavigationItem.vue +11 -4
- package/components/SiteSettings.vue +24 -1
- package/components/VisitorForm.vue +195 -4
- package/components/VisitorFormSelection.vue +12 -2
- package/composables/useDashboard.ts +31 -4
- package/composables/useHidAmico.ts +152 -0
- package/composables/useHidNavigation.ts +106 -0
- package/composables/useMember.ts +8 -3
- package/composables/useOptionalServices.ts +118 -0
- package/composables/useSiteSettings.ts +1 -1
- package/composables/useUser.ts +1 -2
- package/nuxt.config.ts +1 -1
- package/package.json +2 -1
- package/pages/[org]/[site]/access-mgmt/access-logs/index.vue +21 -0
- package/pages/[org]/[site]/access-mgmt/administrator/index.vue +21 -0
- package/pages/[org]/[site]/access-mgmt/hid-readers/index.vue +21 -0
- package/pages/[org]/[site]/access-mgmt/hid-users/index.vue +21 -0
- package/pages/[org]/[site]/access-mgmt/identity-mapping/index.vue +21 -0
- package/types/local.d.ts +2 -1
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
<!-- NAVIGATION ITEMS -->
|
|
14
14
|
<v-tooltip
|
|
15
|
-
v-for="(item, index) in
|
|
15
|
+
v-for="(item, index) in navigationItems"
|
|
16
16
|
:key="`${item.title}-${index}`"
|
|
17
17
|
location="right"
|
|
18
18
|
:disabled="!item.disabled"
|
|
@@ -52,6 +52,36 @@ const emit = defineEmits(["navigate"]);
|
|
|
52
52
|
|
|
53
53
|
const { drawer } = useLocal();
|
|
54
54
|
const { APP_NAME } = useRuntimeConfig().public;
|
|
55
|
+
const route = useRoute();
|
|
56
|
+
const orgId = computed(() => String(route.params.org ?? ""));
|
|
57
|
+
const siteId = computed(() => String(route.params.site ?? ""));
|
|
58
|
+
const { useHidFaceReaderMenu } = useHidNavigation();
|
|
59
|
+
const { menuItem: hidFaceReaderMenu } = useHidFaceReaderMenu({
|
|
60
|
+
org: orgId,
|
|
61
|
+
site: siteId,
|
|
62
|
+
cacheKey: "layout-navigation-hid-site",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const navigationItems = computed(() => {
|
|
66
|
+
const items = [...(props.navigationItems as TNavigationItem[])];
|
|
67
|
+
|
|
68
|
+
if (
|
|
69
|
+
hidFaceReaderMenu.value &&
|
|
70
|
+
!items.some((item) => item.title === hidFaceReaderMenu.value?.title)
|
|
71
|
+
) {
|
|
72
|
+
const insertAfterIndex = items.findIndex(
|
|
73
|
+
(item) => item.title === "Pass & Key Mgmt",
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (insertAfterIndex >= 0) {
|
|
77
|
+
items.splice(insertAfterIndex + 1, 0, hidFaceReaderMenu.value);
|
|
78
|
+
} else {
|
|
79
|
+
items.push(hidFaceReaderMenu.value);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return items;
|
|
84
|
+
});
|
|
55
85
|
|
|
56
86
|
const handleClick = (item: any) => {
|
|
57
87
|
if (item.disabled) return;
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
</v-list-group>
|
|
23
23
|
|
|
24
24
|
<v-list-item
|
|
25
|
-
v-else-if="
|
|
25
|
+
v-else-if="routeTo"
|
|
26
26
|
:prepend-icon="icon"
|
|
27
|
-
:to="
|
|
27
|
+
:to="routeTo"
|
|
28
28
|
class="text-subtitle-2"
|
|
29
29
|
>
|
|
30
30
|
{{ title }}
|
|
@@ -76,8 +76,15 @@ const props = defineProps({
|
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
function onParentClick() {
|
|
79
|
-
if (
|
|
80
|
-
navigateTo(
|
|
79
|
+
if (routeTo.value) {
|
|
80
|
+
navigateTo(routeTo.value);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
+
|
|
84
|
+
const routeTo = computed(() => {
|
|
85
|
+
if (!props.route) return null;
|
|
86
|
+
if (props.route.name) return props.route;
|
|
87
|
+
if (props.route.path) return props.route;
|
|
88
|
+
return null;
|
|
89
|
+
});
|
|
83
90
|
</script>
|
|
@@ -150,7 +150,28 @@
|
|
|
150
150
|
</v-expansion-panel-text>
|
|
151
151
|
</v-expansion-panel>
|
|
152
152
|
|
|
153
|
-
<
|
|
153
|
+
<v-expansion-panel color="primary">
|
|
154
|
+
<v-expansion-panel-title>
|
|
155
|
+
<v-icon class="mr-2">mdi-face-recognition</v-icon>
|
|
156
|
+
HID Face Reader
|
|
157
|
+
</v-expansion-panel-title>
|
|
158
|
+
<v-expansion-panel-text>
|
|
159
|
+
<HidServiceSettingsPanel
|
|
160
|
+
:site="siteId"
|
|
161
|
+
:org="orgId"
|
|
162
|
+
:site-data="siteData"
|
|
163
|
+
@refresh="refreshSiteData"
|
|
164
|
+
/>
|
|
165
|
+
<v-divider class="my-4" />
|
|
166
|
+
<HidQrCodeConfiguration :site="siteId" />
|
|
167
|
+
</v-expansion-panel-text>
|
|
168
|
+
</v-expansion-panel>
|
|
169
|
+
|
|
170
|
+
<slot
|
|
171
|
+
name="panels"
|
|
172
|
+
:can-manage="canManageSiteSettings"
|
|
173
|
+
:site-id="siteId"
|
|
174
|
+
/>
|
|
154
175
|
</v-expansion-panels>
|
|
155
176
|
|
|
156
177
|
<Snackbar v-model="toast.show" :text="toast.message" :color="toast.color" />
|
|
@@ -165,6 +186,7 @@ import useANPRSettings from "../composables/useANPRSettings";
|
|
|
165
186
|
|
|
166
187
|
const props = defineProps({
|
|
167
188
|
siteId: { type: String, required: true },
|
|
189
|
+
orgId: { type: String, default: "" },
|
|
168
190
|
createdBy: { type: String },
|
|
169
191
|
canManageSiteSettings: { type: Boolean, default: false },
|
|
170
192
|
showAnprCamera: { type: Boolean, default: false },
|
|
@@ -227,6 +249,7 @@ const { data: siteData, refresh: refreshSiteData } = await useLazyAsyncData(
|
|
|
227
249
|
`site-${props.siteId}`,
|
|
228
250
|
() => getSiteById(props.siteId)
|
|
229
251
|
);
|
|
252
|
+
const orgId = computed(() => props.orgId || String((siteData.value as any)?.orgId ?? ""));
|
|
230
253
|
|
|
231
254
|
watch(
|
|
232
255
|
siteData,
|
|
@@ -357,14 +357,17 @@
|
|
|
357
357
|
:passKeys="visitor.passKeys"
|
|
358
358
|
/>
|
|
359
359
|
<EntryPassInformation
|
|
360
|
-
v-if="
|
|
360
|
+
v-if="showEntryPassInformation"
|
|
361
361
|
v-model="passType"
|
|
362
362
|
v-model:quantity="passQuantity"
|
|
363
363
|
v-model:cards="passCards"
|
|
364
364
|
:settings="entryPassSettings"
|
|
365
|
-
:loading="entryPassSettingsPending"
|
|
365
|
+
:loading="entryPassSettingsPending || siteDataPending"
|
|
366
366
|
:site-id="prop.site"
|
|
367
367
|
:unit-id="visitor.unit || null"
|
|
368
|
+
:visitor-type="prop.type"
|
|
369
|
+
:hid-qr-code-enabled="hidQrCodePassAllowed"
|
|
370
|
+
:hid-qr-printer-configured="hasHidQrPrinterConfig"
|
|
368
371
|
/>
|
|
369
372
|
</v-col>
|
|
370
373
|
|
|
@@ -619,6 +622,8 @@ const visitor = reactive<Partial<TVisitorPayload>>({
|
|
|
619
622
|
const passType = ref<string | null>(null);
|
|
620
623
|
const passQuantity = ref<number | null>(1);
|
|
621
624
|
const passCards = ref<{ _id: string; cardNo: string }[]>([]);
|
|
625
|
+
const hidQrPrintPayload = ref<string | null>(null);
|
|
626
|
+
const hidQrPrinted = ref(false);
|
|
622
627
|
|
|
623
628
|
const registeredUnitCompanyName = ref("N/A");
|
|
624
629
|
|
|
@@ -685,13 +690,46 @@ const showNextButton = computed(() => {
|
|
|
685
690
|
});
|
|
686
691
|
|
|
687
692
|
const showShowKeysField = computed(() => {
|
|
688
|
-
return
|
|
693
|
+
return ["guest", "contractor", "walk-in"].includes(prop.type);
|
|
689
694
|
});
|
|
690
695
|
|
|
691
696
|
const requireNRIC = computed(() => {
|
|
692
697
|
return prop.type !== "walk-in" && prop.type !== "guest";
|
|
693
698
|
});
|
|
694
699
|
|
|
700
|
+
const hidQrCodePassConfig = computed(() => {
|
|
701
|
+
return (siteData.value as any)?.metadata?.hidQrCodePass || {};
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
const hidQrCodePassEnabled = computed(() => {
|
|
705
|
+
return Boolean(hidQrCodePassConfig.value?.enabled);
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
const hidQrPrinterConfig = computed(() => {
|
|
709
|
+
return hidQrCodePassConfig.value?.printer || {};
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
const hasHidQrPrinterConfig = computed(() => {
|
|
713
|
+
return Boolean(hidQrPrinterConfig.value?.vendorId && hidQrPrinterConfig.value?.productId);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
const hidQrTemplate = computed(() => {
|
|
717
|
+
return hidQrCodePassConfig.value?.template || {};
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
const hidQrValidityMinutes = computed(() => {
|
|
721
|
+
const value = Number(hidQrCodePassConfig.value?.validityMinutes);
|
|
722
|
+
return Number.isFinite(value) && value > 0 ? value : 60;
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
const hidQrCodePassAllowed = computed(() => {
|
|
726
|
+
return hidQrCodePassEnabled.value && ["guest", "contractor", "walk-in"].includes(prop.type);
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
const showEntryPassInformation = computed(() => {
|
|
730
|
+
return Boolean(entryPassSettings.value?.data?.settings?.nfcPass || hidQrCodePassAllowed.value);
|
|
731
|
+
});
|
|
732
|
+
|
|
695
733
|
const companyNames = ref<string[]>([]);
|
|
696
734
|
const companyAutofillDataArray = ref<
|
|
697
735
|
{
|
|
@@ -1189,6 +1227,13 @@ async function handleNextPage() {
|
|
|
1189
1227
|
async function submit() {
|
|
1190
1228
|
formRef.value!.validate();
|
|
1191
1229
|
errorMessage.value = "";
|
|
1230
|
+
if (!validForm.value) {
|
|
1231
|
+
errorMessage.value = "Please complete all required fields *";
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
if (passType.value === "HID_QR" && !validateHidQrPrinterConfig()) return;
|
|
1236
|
+
|
|
1192
1237
|
processing.value = true;
|
|
1193
1238
|
|
|
1194
1239
|
let payload: Partial<TVisitorPayload> = {
|
|
@@ -1251,7 +1296,12 @@ async function submit() {
|
|
|
1251
1296
|
}
|
|
1252
1297
|
|
|
1253
1298
|
if (res) {
|
|
1254
|
-
if (
|
|
1299
|
+
if (passType.value === "HID_QR") {
|
|
1300
|
+
const printed = await printHidQrCodePass(getVisitorIdFromResponse(res), false);
|
|
1301
|
+
if (!printed) return;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
if (prop.type === "contractor" && (passType.value === "QR" || passType.value === "NFC")) {
|
|
1255
1305
|
const visitorId = res as unknown as string;
|
|
1256
1306
|
const rawUrl = entryPassSettings.value?.data?.settings?.url;
|
|
1257
1307
|
const { encrypted: acmUrl } = await $fetch<{ encrypted: string }>(
|
|
@@ -1373,6 +1423,131 @@ async function submit() {
|
|
|
1373
1423
|
}
|
|
1374
1424
|
}
|
|
1375
1425
|
|
|
1426
|
+
function parseUsbId(value: unknown) {
|
|
1427
|
+
if (typeof value === "number") return value;
|
|
1428
|
+
const text = String(value || "").trim();
|
|
1429
|
+
if (!text) return NaN;
|
|
1430
|
+
return text.toLowerCase().startsWith("0x")
|
|
1431
|
+
? parseInt(text, 16)
|
|
1432
|
+
: parseInt(text, 10);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
function getVisitorIdFromResponse(response: any) {
|
|
1436
|
+
if (typeof response === "string") return response;
|
|
1437
|
+
return (
|
|
1438
|
+
response?._id ||
|
|
1439
|
+
response?.id ||
|
|
1440
|
+
response?.data?._id ||
|
|
1441
|
+
response?.data?.id ||
|
|
1442
|
+
response?.insertedId ||
|
|
1443
|
+
response?.data?.insertedId ||
|
|
1444
|
+
""
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
function getHidQrPrinterUsbIds() {
|
|
1449
|
+
const vendorId = parseUsbId(hidQrPrinterConfig.value.vendorId);
|
|
1450
|
+
const productId = parseUsbId(hidQrPrinterConfig.value.productId);
|
|
1451
|
+
return { vendorId, productId };
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
function validateHidQrPrinterConfig() {
|
|
1455
|
+
if (!hasHidQrPrinterConfig.value) {
|
|
1456
|
+
errorMessage.value = "No printer is configured on HID settings. Please configure the HID QR Code printer before continuing.";
|
|
1457
|
+
return false;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
const { vendorId, productId } = getHidQrPrinterUsbIds();
|
|
1461
|
+
|
|
1462
|
+
if (!Number.isFinite(vendorId) || !Number.isFinite(productId)) {
|
|
1463
|
+
errorMessage.value = "Invalid HID QR Code printer configuration. Please check Vendor and Product ID in Settings.";
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
return true;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
function buildHidQrCodePayload(visitorId = "") {
|
|
1471
|
+
if (hidQrPrintPayload.value) return hidQrPrintPayload.value;
|
|
1472
|
+
|
|
1473
|
+
const issuedAt = new Date();
|
|
1474
|
+
const expiresAt = new Date(issuedAt.getTime() + hidQrValidityMinutes.value * 60 * 1000);
|
|
1475
|
+
const nonce =
|
|
1476
|
+
typeof crypto !== "undefined" && "randomUUID" in crypto
|
|
1477
|
+
? crypto.randomUUID()
|
|
1478
|
+
: `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
1479
|
+
|
|
1480
|
+
hidQrPrintPayload.value = JSON.stringify({
|
|
1481
|
+
purpose: "hid-amico-visitor-access",
|
|
1482
|
+
visitorId,
|
|
1483
|
+
site: prop.site,
|
|
1484
|
+
org: prop.org,
|
|
1485
|
+
visitorType: prop.type,
|
|
1486
|
+
name: visitor.name || "",
|
|
1487
|
+
company: visitor.company || "",
|
|
1488
|
+
contact: visitor.contact || "",
|
|
1489
|
+
nric: visitor.nric || "",
|
|
1490
|
+
plateNumber: visitor.plateNumber || "",
|
|
1491
|
+
block: visitor.block || "",
|
|
1492
|
+
level: visitor.level || "",
|
|
1493
|
+
unit: visitor.unit || "",
|
|
1494
|
+
unitName: visitor.unitName || "",
|
|
1495
|
+
address: buildVisitorAddress(),
|
|
1496
|
+
issuedAt: issuedAt.toISOString(),
|
|
1497
|
+
expiresAt: expiresAt.toISOString(),
|
|
1498
|
+
nonce,
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
return hidQrPrintPayload.value;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
function buildVisitorAddress() {
|
|
1505
|
+
const blockLabel = blocksArray.value.find((b: any) => b.value === visitor.block)?.title || "";
|
|
1506
|
+
const levelLabel = levelsArray.value.find((l: any) => l.value === visitor.level)?.title || "";
|
|
1507
|
+
const unitLabel = unitsArray.value.find((u: any) => u.value === visitor.unit)?.title || visitor.unitName || "";
|
|
1508
|
+
return [blockLabel, levelLabel, unitLabel].filter(Boolean).join("/");
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
async function printHidQrCodePass(visitorId = "", manageProcessing = true) {
|
|
1512
|
+
if (hidQrPrinted.value) return true;
|
|
1513
|
+
|
|
1514
|
+
if (!validateHidQrPrinterConfig()) return false;
|
|
1515
|
+
|
|
1516
|
+
const { vendorId, productId } = getHidQrPrinterUsbIds();
|
|
1517
|
+
|
|
1518
|
+
if (manageProcessing) processing.value = true;
|
|
1519
|
+
try {
|
|
1520
|
+
const printResult = await testConnection(
|
|
1521
|
+
vendorId,
|
|
1522
|
+
productId,
|
|
1523
|
+
true,
|
|
1524
|
+
buildHidQrCodePayload(visitorId),
|
|
1525
|
+
null,
|
|
1526
|
+
null,
|
|
1527
|
+
visitor.company || visitor.name || "",
|
|
1528
|
+
buildVisitorAddress(),
|
|
1529
|
+
hidQrTemplate.value?.header || "HID QR Code",
|
|
1530
|
+
hidQrTemplate.value?.subtext || "Scan QR code for access",
|
|
1531
|
+
);
|
|
1532
|
+
|
|
1533
|
+
if (!printResult?.success || printResult?.printTest?.success === false) {
|
|
1534
|
+
errorMessage.value =
|
|
1535
|
+
printResult?.printTest?.error ||
|
|
1536
|
+
printResult?.error ||
|
|
1537
|
+
"Unable to print HID QR Code. Please check the printer connection.";
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
hidQrPrinted.value = true;
|
|
1542
|
+
return true;
|
|
1543
|
+
} catch (error: any) {
|
|
1544
|
+
errorMessage.value = error?.message || "Unable to print HID QR Code.";
|
|
1545
|
+
return false;
|
|
1546
|
+
} finally {
|
|
1547
|
+
if (manageProcessing) processing.value = false;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1376
1551
|
watch(
|
|
1377
1552
|
() => visitor.plateNumber,
|
|
1378
1553
|
(newVal) => {
|
|
@@ -1380,6 +1555,22 @@ watch(
|
|
|
1380
1555
|
}
|
|
1381
1556
|
);
|
|
1382
1557
|
|
|
1558
|
+
watch(
|
|
1559
|
+
[
|
|
1560
|
+
() => passType.value,
|
|
1561
|
+
() => visitor.name,
|
|
1562
|
+
() => visitor.company,
|
|
1563
|
+
() => visitor.block,
|
|
1564
|
+
() => visitor.level,
|
|
1565
|
+
() => visitor.unit,
|
|
1566
|
+
() => visitor.unitName,
|
|
1567
|
+
],
|
|
1568
|
+
() => {
|
|
1569
|
+
hidQrPrintPayload.value = null;
|
|
1570
|
+
hidQrPrinted.value = false;
|
|
1571
|
+
}
|
|
1572
|
+
);
|
|
1573
|
+
|
|
1383
1574
|
const membersFieldIncomplete = computed(() => {
|
|
1384
1575
|
if (!visitor.members || visitor.members.length === 0) return false;
|
|
1385
1576
|
|
|
@@ -11,7 +11,17 @@
|
|
|
11
11
|
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-5 my-5">
|
|
12
12
|
<span class="text-subtitle-2 w-100 font-weight-medium d-flex justify-center mb-3">Please Select Visitor Type</span>
|
|
13
13
|
<template v-for="item in selection" :key="item.value">
|
|
14
|
-
<v-btn
|
|
14
|
+
<v-btn
|
|
15
|
+
v-if="showSelection(item)"
|
|
16
|
+
color="primary-button"
|
|
17
|
+
block
|
|
18
|
+
variant="flat"
|
|
19
|
+
rounded="md"
|
|
20
|
+
size="48"
|
|
21
|
+
:text="item.label"
|
|
22
|
+
@click="select(item.value)"
|
|
23
|
+
class="my-2 text-capitalize text-subtitle-2"
|
|
24
|
+
/>
|
|
15
25
|
</template>
|
|
16
26
|
</v-card-text>
|
|
17
27
|
|
|
@@ -39,7 +49,7 @@ const prop = defineProps({
|
|
|
39
49
|
mode: {
|
|
40
50
|
type: String as PropType<"add" | "edit" | "register">,
|
|
41
51
|
default: "add",
|
|
42
|
-
}
|
|
52
|
+
},
|
|
43
53
|
});
|
|
44
54
|
|
|
45
55
|
const emit = defineEmits(['cancel', 'select']);
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
export default function () {
|
|
2
|
+
function getDashboard(
|
|
3
|
+
site = "",
|
|
4
|
+
serviceType: TServiceType,
|
|
5
|
+
period: TDashboardValues = "today",
|
|
6
|
+
query: Record<string, any> = {}
|
|
7
|
+
) {
|
|
8
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
9
|
+
`/api/dashboard/serviceType/${serviceType}/site/${site}`,
|
|
10
|
+
{
|
|
11
|
+
method: "GET",
|
|
12
|
+
query: {
|
|
13
|
+
period,
|
|
14
|
+
...query,
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
2
20
|
function getDashboardHygiene(
|
|
3
21
|
site = "",
|
|
4
22
|
period: TDashboardValues = "today",
|
|
@@ -15,7 +33,7 @@ export default function () {
|
|
|
15
33
|
);
|
|
16
34
|
}
|
|
17
35
|
|
|
18
|
-
function
|
|
36
|
+
function getDashboardWeeklyActivity(
|
|
19
37
|
site = "",
|
|
20
38
|
serviceType: TServiceType = "cleaning_services",
|
|
21
39
|
period?: TDashboardValues
|
|
@@ -34,6 +52,7 @@ export default function () {
|
|
|
34
52
|
function getDashboardHygieneTaskSchedule(
|
|
35
53
|
site = "",
|
|
36
54
|
serviceType: TServiceType,
|
|
55
|
+
period: TDashboardValues = "today",
|
|
37
56
|
page = 1,
|
|
38
57
|
limit = 4
|
|
39
58
|
) {
|
|
@@ -42,6 +61,7 @@ export default function () {
|
|
|
42
61
|
>(`/api/dashboard/serviceType/${serviceType}/site/${site}/task-schedule`, {
|
|
43
62
|
method: "GET",
|
|
44
63
|
query: {
|
|
64
|
+
period,
|
|
45
65
|
page,
|
|
46
66
|
limit,
|
|
47
67
|
},
|
|
@@ -51,6 +71,7 @@ export default function () {
|
|
|
51
71
|
function getDashboardHygieneAttendance(
|
|
52
72
|
site = "",
|
|
53
73
|
serviceType: TServiceType,
|
|
74
|
+
period: TDashboardValues = "today",
|
|
54
75
|
page = 1,
|
|
55
76
|
limit = 4
|
|
56
77
|
) {
|
|
@@ -59,6 +80,7 @@ export default function () {
|
|
|
59
80
|
{
|
|
60
81
|
method: "GET",
|
|
61
82
|
query: {
|
|
83
|
+
period,
|
|
62
84
|
page,
|
|
63
85
|
limit,
|
|
64
86
|
},
|
|
@@ -69,6 +91,7 @@ export default function () {
|
|
|
69
91
|
function getDashboardHygieneFeedbacks(
|
|
70
92
|
site = "",
|
|
71
93
|
serviceType: TServiceType,
|
|
94
|
+
period: TDashboardValues = "today",
|
|
72
95
|
page = 1,
|
|
73
96
|
limit = 4
|
|
74
97
|
) {
|
|
@@ -77,6 +100,7 @@ export default function () {
|
|
|
77
100
|
{
|
|
78
101
|
method: "GET",
|
|
79
102
|
query: {
|
|
103
|
+
period,
|
|
80
104
|
page,
|
|
81
105
|
limit,
|
|
82
106
|
},
|
|
@@ -86,12 +110,13 @@ export default function () {
|
|
|
86
110
|
|
|
87
111
|
function getDashboardPropertyManagement(
|
|
88
112
|
site = "",
|
|
113
|
+
serviceType: TServiceType = "property_management_agency",
|
|
89
114
|
period: TDashboardValues = "today",
|
|
90
115
|
type = "",
|
|
91
116
|
facility = ""
|
|
92
117
|
) {
|
|
93
118
|
return useNuxtApp().$api<Record<string, any>>(
|
|
94
|
-
`/api/dashboard/serviceType/
|
|
119
|
+
`/api/dashboard/serviceType/${serviceType}/site/${site}`,
|
|
95
120
|
{
|
|
96
121
|
method: "GET",
|
|
97
122
|
query: {
|
|
@@ -105,11 +130,12 @@ export default function () {
|
|
|
105
130
|
|
|
106
131
|
function getDashboardSecurity(
|
|
107
132
|
site = "",
|
|
133
|
+
serviceType: TServiceType = "security_agency",
|
|
108
134
|
period: TDashboardValues = "today",
|
|
109
135
|
type = ""
|
|
110
136
|
) {
|
|
111
137
|
return useNuxtApp().$api<Record<string, any>>(
|
|
112
|
-
`/api/dashboard/serviceType/
|
|
138
|
+
`/api/dashboard/serviceType/${serviceType}/site/${site}`,
|
|
113
139
|
{
|
|
114
140
|
method: "GET",
|
|
115
141
|
query: {
|
|
@@ -121,8 +147,9 @@ export default function () {
|
|
|
121
147
|
}
|
|
122
148
|
|
|
123
149
|
return {
|
|
150
|
+
getDashboard,
|
|
124
151
|
getDashboardHygiene,
|
|
125
|
-
|
|
152
|
+
getDashboardWeeklyActivity,
|
|
126
153
|
getDashboardHygieneTaskSchedule,
|
|
127
154
|
getDashboardHygieneAttendance,
|
|
128
155
|
getDashboardHygieneFeedbacks,
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
type HidReaderPayload = {
|
|
2
|
+
site?: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
location?: string;
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
username?: string;
|
|
7
|
+
password?: string;
|
|
8
|
+
deviceId?: string;
|
|
9
|
+
monitorPath?: string;
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
status?: string;
|
|
12
|
+
lastSyncAt?: string;
|
|
13
|
+
lastSyncStatus?: "idle" | "running" | "completed" | "failed";
|
|
14
|
+
lastSyncMessage?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type HidIdentityPayload = {
|
|
18
|
+
site?: string;
|
|
19
|
+
hidUserId?: string | number;
|
|
20
|
+
registration?: string;
|
|
21
|
+
cardNo?: string;
|
|
22
|
+
person?: string;
|
|
23
|
+
user?: string;
|
|
24
|
+
member?: string;
|
|
25
|
+
visitor?: string;
|
|
26
|
+
type?: "resident" | "staff" | "contractor" | "visitor" | "unknown";
|
|
27
|
+
status?: "active" | "inactive" | "deleted";
|
|
28
|
+
metadata?: Record<string, any>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default function useHidAmico() {
|
|
32
|
+
const basePath = "/api/access-management/hid";
|
|
33
|
+
|
|
34
|
+
function getReaders(query: Record<string, any> = {}) {
|
|
35
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers`, {
|
|
36
|
+
method: "GET",
|
|
37
|
+
query,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createReader(payload: HidReaderPayload) {
|
|
42
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
body: payload,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function updateReader(readerId: string, payload: HidReaderPayload) {
|
|
49
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}`, {
|
|
50
|
+
method: "PATCH",
|
|
51
|
+
body: payload,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function deleteReader(readerId: string) {
|
|
56
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}`, {
|
|
57
|
+
method: "DELETE",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function testReader(readerId: string) {
|
|
62
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/test`, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function syncReader(readerId: string, payload: Record<string, any> = {}) {
|
|
68
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/sync`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
body: payload,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function runObjectOperation(readerId: string, payload: Record<string, any>) {
|
|
75
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/objects`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: payload,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getReaderConfiguration(readerId: string, payload: Record<string, string[]> = {}) {
|
|
82
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/configuration`, {
|
|
83
|
+
method: "POST",
|
|
84
|
+
body: payload,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function setReaderConfiguration(readerId: string, payload: Record<string, any>) {
|
|
89
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/configuration`, {
|
|
90
|
+
method: "PUT",
|
|
91
|
+
body: payload,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getIdentities(readerId: string, query: Record<string, any> = {}) {
|
|
96
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/identities`, {
|
|
97
|
+
method: "GET",
|
|
98
|
+
query,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getLogs(readerId: string, query: Record<string, any> = {}) {
|
|
103
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/logs`, {
|
|
104
|
+
method: "GET",
|
|
105
|
+
query,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function getUserImage(readerId: string, hidUserId: string | number) {
|
|
110
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/users/${hidUserId}/image`, {
|
|
111
|
+
method: "GET",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function createIdentity(readerId: string, payload: HidIdentityPayload) {
|
|
116
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/identities`, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
body: payload,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function updateIdentity(identityId: string, payload: HidIdentityPayload) {
|
|
123
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/identities/${identityId}`, {
|
|
124
|
+
method: "PATCH",
|
|
125
|
+
body: payload,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function deleteIdentity(identityId: string) {
|
|
130
|
+
return useNuxtApp().$api<Record<string, any>>(`${basePath}/identities/${identityId}`, {
|
|
131
|
+
method: "DELETE",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
getReaders,
|
|
137
|
+
createReader,
|
|
138
|
+
updateReader,
|
|
139
|
+
deleteReader,
|
|
140
|
+
testReader,
|
|
141
|
+
syncReader,
|
|
142
|
+
runObjectOperation,
|
|
143
|
+
getReaderConfiguration,
|
|
144
|
+
setReaderConfiguration,
|
|
145
|
+
getLogs,
|
|
146
|
+
getUserImage,
|
|
147
|
+
getIdentities,
|
|
148
|
+
createIdentity,
|
|
149
|
+
updateIdentity,
|
|
150
|
+
deleteIdentity,
|
|
151
|
+
};
|
|
152
|
+
}
|