@7365admin1/layer-common 3.2.8-staging.205 → 3.2.8-staging.206
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
|
@@ -238,7 +238,7 @@
|
|
|
238
238
|
<AppField
|
|
239
239
|
v-model="sipForm.password"
|
|
240
240
|
:disabled="areSipCredentialFieldsDisabled"
|
|
241
|
-
placeholder="
|
|
241
|
+
placeholder="Leave blank to keep current password"
|
|
242
242
|
:type="showSipPassword ? 'text' : 'password'"
|
|
243
243
|
autocomplete="new-password"
|
|
244
244
|
class="sip-input"
|
|
@@ -653,6 +653,17 @@ type ContactRow = {
|
|
|
653
653
|
dialCode: string;
|
|
654
654
|
};
|
|
655
655
|
|
|
656
|
+
type HidReader = Record<string, unknown> & {
|
|
657
|
+
_id: string;
|
|
658
|
+
name?: string;
|
|
659
|
+
deviceId?: string;
|
|
660
|
+
location?: string;
|
|
661
|
+
monitorPath?: string;
|
|
662
|
+
portalName?: string;
|
|
663
|
+
readerModel?: string;
|
|
664
|
+
capabilities?: unknown;
|
|
665
|
+
};
|
|
666
|
+
|
|
656
667
|
type SipAccount = {
|
|
657
668
|
orgId: string;
|
|
658
669
|
site: string;
|
|
@@ -718,7 +729,7 @@ const {
|
|
|
718
729
|
} = useHidAmico();
|
|
719
730
|
|
|
720
731
|
const activeTab = ref<IntercomTab>("intercom");
|
|
721
|
-
const readers = ref<
|
|
732
|
+
const readers = ref<HidReader[]>([]);
|
|
722
733
|
const selectedReaderId = ref("");
|
|
723
734
|
const testingSipReaderId = ref("");
|
|
724
735
|
const testingContactReaderId = ref("");
|
|
@@ -770,7 +781,6 @@ const pjsipKeys = [
|
|
|
770
781
|
"numeric_branch_enabled",
|
|
771
782
|
"branch",
|
|
772
783
|
"login",
|
|
773
|
-
"password",
|
|
774
784
|
"peer_to_peer_enabled",
|
|
775
785
|
"reg_status_query_period",
|
|
776
786
|
"server_retry_interval",
|
|
@@ -1064,14 +1074,21 @@ async function reload() {
|
|
|
1064
1074
|
loading.value = true;
|
|
1065
1075
|
try {
|
|
1066
1076
|
const response = await getReaders({ site: props.site, page: 1, limit: 100 });
|
|
1067
|
-
|
|
1077
|
+
const responseRecord = toRecord(response);
|
|
1078
|
+
const responseData = toRecord(responseRecord.data);
|
|
1079
|
+
const availableReaders = responseRecord.items ?? responseData.items ?? responseData.readers ?? [];
|
|
1080
|
+
readers.value = (Array.isArray(availableReaders) ? availableReaders : [])
|
|
1081
|
+
.map(toHidReader)
|
|
1082
|
+
.filter((reader): reader is HidReader => (
|
|
1083
|
+
reader !== null && reader.readerModel === "VL70LF" && toRecord(reader.capabilities).intercom === true
|
|
1084
|
+
));
|
|
1068
1085
|
if (!readers.value.some((reader) => reader._id === selectedReaderId.value)) {
|
|
1069
1086
|
selectedReaderId.value = readers.value[0]?._id || "";
|
|
1070
1087
|
}
|
|
1071
1088
|
intercomLoaded.value = false;
|
|
1072
1089
|
contactsLoaded.value = false;
|
|
1073
1090
|
await loadActiveTab();
|
|
1074
|
-
} catch (error:
|
|
1091
|
+
} catch (error: unknown) {
|
|
1075
1092
|
showMessage(getErrorMessage(error), "error");
|
|
1076
1093
|
} finally {
|
|
1077
1094
|
loading.value = false;
|
|
@@ -1178,7 +1195,7 @@ function toIntercomRow(reader: Record<string, unknown>, pjsip: Record<string, un
|
|
|
1178
1195
|
numericExtension: toFlag(getPjsipValue(pjsip, ["numeric_branch_enabled", "numericExtension", "numericExtensionEnabled"])) === "1",
|
|
1179
1196
|
extension: toText(getPjsipValue(pjsip, ["branch", "extension"]), "N/A"),
|
|
1180
1197
|
login: toText(getPjsipValue(pjsip, ["login", "username"]), "N/A"),
|
|
1181
|
-
password:
|
|
1198
|
+
password: "",
|
|
1182
1199
|
operatingMode: peerToPeer ? "Peer-to-Peer" : "SIP Client",
|
|
1183
1200
|
protocol: toText(getPjsipValue(pjsip, ["protocol"]), "UDP"),
|
|
1184
1201
|
videoEnabled: toFlag(getPjsipValue(pjsip, ["video_enabled", "videoEnabled"])) === "1",
|
|
@@ -1251,9 +1268,13 @@ function normalizeStatus(response: Record<string, unknown>, pjsip: Record<string
|
|
|
1251
1268
|
return "Not connected";
|
|
1252
1269
|
}
|
|
1253
1270
|
|
|
1254
|
-
function normalizeContacts(reader:
|
|
1255
|
-
const
|
|
1256
|
-
|
|
1271
|
+
function normalizeContacts(reader: HidReader, response: unknown): ContactRow[] {
|
|
1272
|
+
const responseRecord = toRecord(response);
|
|
1273
|
+
const responseData = toRecord(responseRecord.data);
|
|
1274
|
+
const items = responseRecord.contacts ?? responseRecord.values ?? responseData.contacts ?? responseRecord.data ?? [];
|
|
1275
|
+
return (Array.isArray(items) ? items : []).map((value, index) => {
|
|
1276
|
+
const contact = toRecord(value);
|
|
1277
|
+
return {
|
|
1257
1278
|
_rowKey: `${reader._id}-${contact.id ?? index}`,
|
|
1258
1279
|
id: toNumber(contact.id, undefined),
|
|
1259
1280
|
readerId: reader._id,
|
|
@@ -1261,7 +1282,8 @@ function normalizeContacts(reader: Record<string, any>, response: Record<string,
|
|
|
1261
1282
|
location: reader.location || "N/A",
|
|
1262
1283
|
serverAddress: toText(contact.number || contact.serverAddress, "N/A"),
|
|
1263
1284
|
dialCode: toText(contact.number || contact.serverAddress, "N/A"),
|
|
1264
|
-
|
|
1285
|
+
};
|
|
1286
|
+
});
|
|
1265
1287
|
}
|
|
1266
1288
|
|
|
1267
1289
|
function openViewDialog(row: IntercomRow) {
|
|
@@ -1515,7 +1537,7 @@ async function saveSipSettings() {
|
|
|
1515
1537
|
return;
|
|
1516
1538
|
}
|
|
1517
1539
|
|
|
1518
|
-
const
|
|
1540
|
+
const payload: Record<string, string> = {
|
|
1519
1541
|
enabled: sipForm.enabled ? "1" : "0",
|
|
1520
1542
|
server_ip: sipForm.serverIp,
|
|
1521
1543
|
server_port: sipForm.serverPort,
|
|
@@ -1524,10 +1546,15 @@ async function saveSipSettings() {
|
|
|
1524
1546
|
numeric_branch_enabled: sipForm.numericExtension ? "1" : "0",
|
|
1525
1547
|
branch: isPeerToPeer ? "" : sipForm.extension,
|
|
1526
1548
|
login: isPeerToPeer ? "" : sipForm.login,
|
|
1527
|
-
password: isPeerToPeer ? "" : sipForm.password,
|
|
1528
1549
|
peer_to_peer_enabled: isPeerToPeer ? "1" : "0",
|
|
1529
1550
|
video_enabled: sipForm.videoEnabled ? "1" : "0",
|
|
1530
|
-
}
|
|
1551
|
+
};
|
|
1552
|
+
if (isPeerToPeer) {
|
|
1553
|
+
payload.password = "";
|
|
1554
|
+
} else if (sipForm.password) {
|
|
1555
|
+
payload.password = sipForm.password;
|
|
1556
|
+
}
|
|
1557
|
+
const saved = await savePjsip(selectedRow.value.reader._id, payload);
|
|
1531
1558
|
if (saved) {
|
|
1532
1559
|
sipDialog.value = false;
|
|
1533
1560
|
}
|
|
@@ -1579,7 +1606,7 @@ async function runMakeCall() {
|
|
|
1579
1606
|
makeCallForm.status = `Calling ${target}.`;
|
|
1580
1607
|
makeCallForm.statusType = "success";
|
|
1581
1608
|
showMessage(`Calling ${target}.`, "success");
|
|
1582
|
-
} catch (error:
|
|
1609
|
+
} catch (error: unknown) {
|
|
1583
1610
|
const message = getErrorMessage(error);
|
|
1584
1611
|
makeCallForm.status = message;
|
|
1585
1612
|
makeCallForm.statusType = "error";
|
|
@@ -1602,7 +1629,7 @@ async function runHangupCall() {
|
|
|
1602
1629
|
makeCallForm.status = "Call ended.";
|
|
1603
1630
|
makeCallForm.statusType = "success";
|
|
1604
1631
|
showMessage("Intercom call ended.", "success");
|
|
1605
|
-
} catch (error:
|
|
1632
|
+
} catch (error: unknown) {
|
|
1606
1633
|
const message = getErrorMessage(error);
|
|
1607
1634
|
makeCallForm.status = message;
|
|
1608
1635
|
makeCallForm.statusType = "error";
|
|
@@ -1667,7 +1694,7 @@ async function savePjsip(readerId: string, payload: Record<string, string>, opti
|
|
|
1667
1694
|
showMessage("Intercom settings saved.", "success");
|
|
1668
1695
|
}
|
|
1669
1696
|
return true;
|
|
1670
|
-
} catch (error:
|
|
1697
|
+
} catch (error: unknown) {
|
|
1671
1698
|
showMessage(getErrorMessage(error), "error");
|
|
1672
1699
|
return false;
|
|
1673
1700
|
} finally {
|
|
@@ -1711,7 +1738,7 @@ async function saveContact() {
|
|
|
1711
1738
|
contactDialog.value = false;
|
|
1712
1739
|
await loadContacts();
|
|
1713
1740
|
showMessage("Intercom contact saved.", "success");
|
|
1714
|
-
} catch (error:
|
|
1741
|
+
} catch (error: unknown) {
|
|
1715
1742
|
showMessage(getErrorMessage(error), "error");
|
|
1716
1743
|
} finally {
|
|
1717
1744
|
contactsSaving.value = false;
|
|
@@ -1730,7 +1757,7 @@ async function deleteContact() {
|
|
|
1730
1757
|
deleteContactDialog.value = false;
|
|
1731
1758
|
await loadContacts();
|
|
1732
1759
|
showMessage("Intercom contact deleted.", "success");
|
|
1733
|
-
} catch (error:
|
|
1760
|
+
} catch (error: unknown) {
|
|
1734
1761
|
showMessage(getErrorMessage(error), "error");
|
|
1735
1762
|
} finally {
|
|
1736
1763
|
contactsSaving.value = false;
|
|
@@ -1791,6 +1818,12 @@ function toRecord(value: unknown): Record<string, unknown> {
|
|
|
1791
1818
|
return typeof value === "object" && value !== null ? value as Record<string, unknown> : {};
|
|
1792
1819
|
}
|
|
1793
1820
|
|
|
1821
|
+
function toHidReader(value: unknown): HidReader | null {
|
|
1822
|
+
const reader = toRecord(value);
|
|
1823
|
+
const id = toText(reader._id);
|
|
1824
|
+
return id ? { ...reader, _id: id } : null;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1794
1827
|
function toText(value: unknown, fallback = "") {
|
|
1795
1828
|
if (value === undefined || value === null || value === "") return fallback;
|
|
1796
1829
|
return String(value);
|
|
@@ -368,6 +368,7 @@ const {
|
|
|
368
368
|
getReaders,
|
|
369
369
|
getReaderConfiguration,
|
|
370
370
|
setReaderConfiguration,
|
|
371
|
+
setReaderOperatingMode,
|
|
371
372
|
getSitePermissions,
|
|
372
373
|
getPermissionCandidates,
|
|
373
374
|
updateSitePermissions,
|
|
@@ -779,9 +780,7 @@ async function saveOnlineMode() {
|
|
|
779
780
|
|
|
780
781
|
savingSection.value = "online-mode";
|
|
781
782
|
try {
|
|
782
|
-
await
|
|
783
|
-
general: { online: form.onlineMode ? "1" : "0" },
|
|
784
|
-
});
|
|
783
|
+
await setReaderOperatingMode(form.readerId, form.onlineMode ? "online" : "standalone");
|
|
785
784
|
await updateSitebyId(props.site, buildPayload());
|
|
786
785
|
showMessage("Online mode updated.", "success");
|
|
787
786
|
} catch (error: unknown) {
|
|
@@ -39,11 +39,15 @@
|
|
|
39
39
|
class="mb-3"
|
|
40
40
|
/>
|
|
41
41
|
|
|
42
|
-
<InputLabel title="Monitor
|
|
43
|
-
<v-btn-toggle v-model="monitorEnabled" mandatory divided class="monitor-toggle
|
|
42
|
+
<InputLabel title="Monitor Callback" required class="mb-1" />
|
|
43
|
+
<v-btn-toggle v-model="monitorEnabled" mandatory divided class="monitor-toggle">
|
|
44
44
|
<v-btn :value="true" class="text-none">Enable</v-btn>
|
|
45
45
|
<v-btn :value="false" class="text-none">Disable</v-btn>
|
|
46
46
|
</v-btn-toggle>
|
|
47
|
+
<p class="reader-discovery-hint mt-1 mb-3">
|
|
48
|
+
Enable only when this reader can reach the IP address or domain configured on iService365.
|
|
49
|
+
Disabling keeps the reader in Standalone mode and uses manual log pulls instead.
|
|
50
|
+
</p>
|
|
47
51
|
|
|
48
52
|
<InputLabel title="Username" required class="mb-1" />
|
|
49
53
|
<v-text-field
|
|
@@ -98,6 +102,22 @@
|
|
|
98
102
|
readonly
|
|
99
103
|
/>
|
|
100
104
|
|
|
105
|
+
<InputLabel title="Reader Model" required class="mb-1" />
|
|
106
|
+
<v-select
|
|
107
|
+
v-model="draft.readerModel"
|
|
108
|
+
:items="readerModelOptions"
|
|
109
|
+
aria-label="Reader Model"
|
|
110
|
+
placeholder="Select the model printed on the reader"
|
|
111
|
+
variant="outlined"
|
|
112
|
+
density="compact"
|
|
113
|
+
hide-details="auto"
|
|
114
|
+
class="mb-3"
|
|
115
|
+
/>
|
|
116
|
+
<v-alert v-if="draft.readerModel === 'unknown'" type="warning" variant="tonal" density="compact" class="mb-3">
|
|
117
|
+
The Amico system-information API does not return the hardware model. Select VL35LF or VL70LF from the
|
|
118
|
+
label on the physical reader so model-specific features are enabled correctly.
|
|
119
|
+
</v-alert>
|
|
120
|
+
|
|
101
121
|
<InputLabel title="HID Portal" required class="mb-1" />
|
|
102
122
|
<v-select
|
|
103
123
|
v-model="draft.portalId"
|
|
@@ -111,6 +131,64 @@
|
|
|
111
131
|
hide-details="auto"
|
|
112
132
|
:readonly="mode === 'edit'"
|
|
113
133
|
/>
|
|
134
|
+
|
|
135
|
+
<InputLabel title="Card Profile Configured on Reader" required class="mt-3 mb-1" />
|
|
136
|
+
<v-select
|
|
137
|
+
v-model="draft.cardReadingMode"
|
|
138
|
+
:items="cardModeOptions"
|
|
139
|
+
aria-label="Card Data Mode"
|
|
140
|
+
placeholder="Select the mode configured on the reader"
|
|
141
|
+
variant="outlined"
|
|
142
|
+
density="compact"
|
|
143
|
+
hide-details="auto"
|
|
144
|
+
class="mb-3"
|
|
145
|
+
/>
|
|
146
|
+
<v-alert type="info" variant="tonal" density="compact" class="mb-3">
|
|
147
|
+
Match Menu > Access > Identification Methods > Card Reading on the physical reader.
|
|
148
|
+
The Amico HTTP API does not expose the OMNIKEY card-profile setting for automatic verification.
|
|
149
|
+
</v-alert>
|
|
150
|
+
|
|
151
|
+
<template v-if="draft.cardReadingMode === 'csn' || draft.cardReadingMode === 'csn_for_mifare'">
|
|
152
|
+
<InputLabel title="CSN Byte Order" required class="mb-1" />
|
|
153
|
+
<v-select
|
|
154
|
+
v-model="draft.csnByteOrder"
|
|
155
|
+
:items="csnByteOrderOptions"
|
|
156
|
+
variant="outlined"
|
|
157
|
+
density="compact"
|
|
158
|
+
hide-details="auto"
|
|
159
|
+
class="mb-3"
|
|
160
|
+
/>
|
|
161
|
+
</template>
|
|
162
|
+
|
|
163
|
+
<template v-if="draft.cardReadingMode === 'pacs'">
|
|
164
|
+
<InputLabel title="PACS Output Format" required class="mb-1" />
|
|
165
|
+
<v-select
|
|
166
|
+
v-model="draft.pacsFormat"
|
|
167
|
+
:items="pacsFormatOptions"
|
|
168
|
+
variant="outlined"
|
|
169
|
+
density="compact"
|
|
170
|
+
hide-details="auto"
|
|
171
|
+
class="mb-3"
|
|
172
|
+
/>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<InputLabel title="Operating Mode" required class="mb-1" />
|
|
176
|
+
<v-select
|
|
177
|
+
v-model="draft.operatingMode"
|
|
178
|
+
:items="operatingModeOptions"
|
|
179
|
+
variant="outlined"
|
|
180
|
+
density="compact"
|
|
181
|
+
hide-details="auto"
|
|
182
|
+
:disabled="!monitorEnabled"
|
|
183
|
+
/>
|
|
184
|
+
<p v-if="!monitorEnabled" class="reader-discovery-hint mt-1 mb-0">
|
|
185
|
+
Online mode requires an enabled and verified Monitor callback.
|
|
186
|
+
</p>
|
|
187
|
+
|
|
188
|
+
<p v-if="draft.readerModel || draft.firmwareVersion" class="reader-discovery-hint mt-3">
|
|
189
|
+
Detected: {{ draft.readerModel || "Unknown model" }}
|
|
190
|
+
<template v-if="draft.firmwareVersion"> · Firmware {{ draft.firmwareVersion }}</template>
|
|
191
|
+
</p>
|
|
114
192
|
</v-card-text>
|
|
115
193
|
|
|
116
194
|
<v-card-actions class="screen-modal__footer">
|
|
@@ -125,7 +203,7 @@
|
|
|
125
203
|
class="text-none screen-btn-primary"
|
|
126
204
|
variant="flat"
|
|
127
205
|
:loading="loading"
|
|
128
|
-
:disabled="mode === 'add' && (!draft.deviceId || !draft.portalId)"
|
|
206
|
+
:disabled="mode === 'add' && (!draft.deviceId || !draft.portalId || draft.cardReadingMode === 'unconfigured')"
|
|
129
207
|
@click="submit"
|
|
130
208
|
>
|
|
131
209
|
Submit
|
|
@@ -136,6 +214,42 @@
|
|
|
136
214
|
</template>
|
|
137
215
|
|
|
138
216
|
<script setup lang="ts">
|
|
217
|
+
type HidReaderFormRecord = {
|
|
218
|
+
name?: string;
|
|
219
|
+
baseUrl?: string;
|
|
220
|
+
deviceId?: string;
|
|
221
|
+
portalId?: number;
|
|
222
|
+
portalName?: string;
|
|
223
|
+
location?: string;
|
|
224
|
+
username?: string;
|
|
225
|
+
password?: string;
|
|
226
|
+
readerModel?: "VL35LF" | "VL70LF" | "unknown" | "";
|
|
227
|
+
firmwareVersion?: string;
|
|
228
|
+
cardReadingMode?: "unconfigured" | "pacs" | "csn" | "csn_for_mifare";
|
|
229
|
+
csnByteOrder?: "msb" | "lsb";
|
|
230
|
+
pacsFormat?: "raw" | "wiegand";
|
|
231
|
+
operatingMode?: "standalone" | "online";
|
|
232
|
+
monitorStatus?: "unconfigured" | "configured" | "disabled" | "failed";
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
type HidReaderFormPayload = {
|
|
236
|
+
name: string;
|
|
237
|
+
baseUrl: string;
|
|
238
|
+
deviceId: string;
|
|
239
|
+
portalId: number | null;
|
|
240
|
+
portalName: string;
|
|
241
|
+
location: string;
|
|
242
|
+
username: string;
|
|
243
|
+
password: string;
|
|
244
|
+
readerModel: "VL35LF" | "VL70LF" | "unknown" | "";
|
|
245
|
+
firmwareVersion: string;
|
|
246
|
+
cardReadingMode: "unconfigured" | "pacs" | "csn" | "csn_for_mifare";
|
|
247
|
+
csnByteOrder: "msb" | "lsb";
|
|
248
|
+
pacsFormat: "raw" | "wiegand";
|
|
249
|
+
operatingMode: "standalone" | "online";
|
|
250
|
+
monitorEnabled: boolean;
|
|
251
|
+
};
|
|
252
|
+
|
|
139
253
|
const props = defineProps({
|
|
140
254
|
modelValue: {
|
|
141
255
|
type: Boolean,
|
|
@@ -146,9 +260,13 @@ const props = defineProps({
|
|
|
146
260
|
default: "add",
|
|
147
261
|
},
|
|
148
262
|
reader: {
|
|
149
|
-
type: Object as () =>
|
|
263
|
+
type: Object as () => HidReaderFormRecord | null,
|
|
150
264
|
default: null,
|
|
151
265
|
},
|
|
266
|
+
site: {
|
|
267
|
+
type: String,
|
|
268
|
+
required: true,
|
|
269
|
+
},
|
|
152
270
|
loading: {
|
|
153
271
|
type: Boolean,
|
|
154
272
|
default: false,
|
|
@@ -164,7 +282,7 @@ const props = defineProps({
|
|
|
164
282
|
|
|
165
283
|
const emit = defineEmits<{
|
|
166
284
|
"update:modelValue": [value: boolean];
|
|
167
|
-
submit: [payload:
|
|
285
|
+
submit: [payload: HidReaderFormPayload];
|
|
168
286
|
}>();
|
|
169
287
|
|
|
170
288
|
const dialogModel = computed({
|
|
@@ -188,8 +306,36 @@ const draft = reactive({
|
|
|
188
306
|
location: "",
|
|
189
307
|
username: "",
|
|
190
308
|
password: "",
|
|
309
|
+
readerModel: "" as "VL35LF" | "VL70LF" | "unknown" | "",
|
|
310
|
+
firmwareVersion: "",
|
|
311
|
+
cardReadingMode: "unconfigured" as "unconfigured" | "pacs" | "csn" | "csn_for_mifare",
|
|
312
|
+
csnByteOrder: "msb" as "msb" | "lsb",
|
|
313
|
+
pacsFormat: "raw" as "raw" | "wiegand",
|
|
314
|
+
operatingMode: "standalone" as "standalone" | "online",
|
|
191
315
|
});
|
|
192
316
|
|
|
317
|
+
const cardModeOptions = [
|
|
318
|
+
{ title: "PACS (facility code + card number)", value: "pacs" },
|
|
319
|
+
{ title: "CSN", value: "csn" },
|
|
320
|
+
{ title: "CSN for MIFARE", value: "csn_for_mifare" },
|
|
321
|
+
];
|
|
322
|
+
const csnByteOrderOptions = [
|
|
323
|
+
{ title: "MSB first", value: "msb" },
|
|
324
|
+
{ title: "LSB first", value: "lsb" },
|
|
325
|
+
];
|
|
326
|
+
const pacsFormatOptions = [
|
|
327
|
+
{ title: "RAW", value: "raw" },
|
|
328
|
+
{ title: "Wiegand", value: "wiegand" },
|
|
329
|
+
];
|
|
330
|
+
const operatingModeOptions = [
|
|
331
|
+
{ title: "Standalone", value: "standalone" },
|
|
332
|
+
{ title: "Online", value: "online" },
|
|
333
|
+
];
|
|
334
|
+
const readerModelOptions = [
|
|
335
|
+
{ title: "VL35LF", value: "VL35LF" },
|
|
336
|
+
{ title: "VL70LF", value: "VL70LF" },
|
|
337
|
+
];
|
|
338
|
+
|
|
193
339
|
watch(
|
|
194
340
|
() => [props.modelValue, props.reader],
|
|
195
341
|
() => {
|
|
@@ -208,7 +354,13 @@ watch(
|
|
|
208
354
|
draft.location = props.reader?.location ?? "";
|
|
209
355
|
draft.username = props.reader?.username ?? "";
|
|
210
356
|
draft.password = props.reader?.password ?? "";
|
|
211
|
-
monitorEnabled.value = props.reader?.
|
|
357
|
+
monitorEnabled.value = props.reader?.monitorStatus !== "disabled";
|
|
358
|
+
draft.readerModel = props.reader?.readerModel ?? "";
|
|
359
|
+
draft.firmwareVersion = props.reader?.firmwareVersion ?? "";
|
|
360
|
+
draft.cardReadingMode = props.reader?.cardReadingMode ?? "unconfigured";
|
|
361
|
+
draft.csnByteOrder = props.reader?.csnByteOrder ?? "msb";
|
|
362
|
+
draft.pacsFormat = props.reader?.pacsFormat ?? "raw";
|
|
363
|
+
draft.operatingMode = props.reader?.operatingMode ?? "standalone";
|
|
212
364
|
},
|
|
213
365
|
{ immediate: true },
|
|
214
366
|
);
|
|
@@ -235,11 +387,16 @@ watch(
|
|
|
235
387
|
},
|
|
236
388
|
);
|
|
237
389
|
|
|
390
|
+
watch(monitorEnabled, (enabled) => {
|
|
391
|
+
if (!enabled) draft.operatingMode = "standalone";
|
|
392
|
+
});
|
|
393
|
+
|
|
238
394
|
async function connectReader() {
|
|
239
395
|
discovering.value = true;
|
|
240
396
|
discoveryError.value = "";
|
|
241
397
|
try {
|
|
242
398
|
const response = await discoverReader({
|
|
399
|
+
site: props.site,
|
|
243
400
|
baseUrl: draft.baseUrl.trim(),
|
|
244
401
|
username: draft.username.trim(),
|
|
245
402
|
password: draft.password,
|
|
@@ -250,6 +407,13 @@ async function connectReader() {
|
|
|
250
407
|
? nestedData as Record<string, unknown>
|
|
251
408
|
: response;
|
|
252
409
|
draft.deviceId = String(data?.deviceId || "");
|
|
410
|
+
const discoveredModel = String(data?.readerModel || "unknown");
|
|
411
|
+
draft.readerModel = (
|
|
412
|
+
discoveredModel === "VL35LF" || discoveredModel === "VL70LF"
|
|
413
|
+
? discoveredModel
|
|
414
|
+
: draft.readerModel || "unknown"
|
|
415
|
+
) as typeof draft.readerModel;
|
|
416
|
+
draft.firmwareVersion = String(data?.firmwareVersion || data?.version || "");
|
|
253
417
|
portals.value = Array.isArray(data?.portals)
|
|
254
418
|
? data.portals.flatMap((portal: unknown) => {
|
|
255
419
|
if (typeof portal !== "object" || portal === null) return [];
|
|
@@ -278,13 +442,15 @@ async function connectReader() {
|
|
|
278
442
|
}
|
|
279
443
|
|
|
280
444
|
function submit() {
|
|
445
|
+
if (draft.readerModel !== "VL35LF" && draft.readerModel !== "VL70LF") {
|
|
446
|
+
discoveryError.value = "Select the model printed on the physical HID reader.";
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
281
449
|
const portal = portals.value.find((item) => item.id === Number(draft.portalId));
|
|
282
|
-
const payload:
|
|
450
|
+
const payload: HidReaderFormPayload = {
|
|
283
451
|
...draft,
|
|
284
452
|
portalName: portal?.name || draft.portalName,
|
|
285
|
-
|
|
286
|
-
enabled: monitorEnabled.value,
|
|
287
|
-
status: monitorEnabled.value ? "active" : "inactive",
|
|
453
|
+
monitorEnabled: monitorEnabled.value,
|
|
288
454
|
};
|
|
289
455
|
|
|
290
456
|
emit("submit", payload);
|