@ramathibodi/nuxt-commons 0.1.74 → 0.1.75
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/README.md +115 -115
- package/dist/module.json +1 -1
- package/dist/runtime/components/Alert.vue +58 -58
- package/dist/runtime/components/BarcodeReader.vue +130 -130
- package/dist/runtime/components/ExportCSV.vue +110 -110
- package/dist/runtime/components/FileBtn.vue +79 -79
- package/dist/runtime/components/ImportCSV.vue +151 -151
- package/dist/runtime/components/MrzReader.vue +168 -168
- package/dist/runtime/components/SplitterPanel.vue +67 -67
- package/dist/runtime/components/TabsGroup.vue +39 -39
- package/dist/runtime/components/TextBarcode.vue +66 -66
- package/dist/runtime/components/device/IdCardButton.vue +95 -95
- package/dist/runtime/components/device/IdCardWebSocket.vue +207 -207
- package/dist/runtime/components/device/Scanner.vue +350 -350
- package/dist/runtime/components/dialog/Confirm.vue +112 -112
- package/dist/runtime/components/dialog/Host.vue +88 -88
- package/dist/runtime/components/dialog/Index.vue +84 -84
- package/dist/runtime/components/dialog/Loading.vue +51 -51
- package/dist/runtime/components/dialog/default/Confirm.vue +112 -112
- package/dist/runtime/components/dialog/default/Loading.vue +60 -60
- package/dist/runtime/components/dialog/default/Notify.vue +82 -82
- package/dist/runtime/components/dialog/default/Printing.vue +46 -46
- package/dist/runtime/components/dialog/default/VerifyUser.vue +144 -144
- package/dist/runtime/components/document/Form.vue +50 -50
- package/dist/runtime/components/document/TemplateBuilder.vue +536 -536
- package/dist/runtime/components/form/ActionPad.vue +156 -156
- package/dist/runtime/components/form/Birthdate.vue +116 -116
- package/dist/runtime/components/form/CheckboxGroup.vue +99 -99
- package/dist/runtime/components/form/CodeEditor.vue +45 -45
- package/dist/runtime/components/form/Date.vue +270 -270
- package/dist/runtime/components/form/DateTime.vue +220 -220
- package/dist/runtime/components/form/Dialog.vue +178 -178
- package/dist/runtime/components/form/EditPad.vue +157 -157
- package/dist/runtime/components/form/File.vue +295 -295
- package/dist/runtime/components/form/Hidden.vue +44 -44
- package/dist/runtime/components/form/Iterator.vue +538 -538
- package/dist/runtime/components/form/Login.vue +143 -143
- package/dist/runtime/components/form/Pad.vue +399 -399
- package/dist/runtime/components/form/SignPad.vue +226 -226
- package/dist/runtime/components/form/System.vue +34 -34
- package/dist/runtime/components/form/Table.vue +391 -391
- package/dist/runtime/components/form/TableData.vue +236 -236
- package/dist/runtime/components/form/Time.vue +177 -177
- package/dist/runtime/components/form/images/Capture.vue +245 -245
- package/dist/runtime/components/form/images/Edit.vue +133 -133
- package/dist/runtime/components/form/images/Field.vue +331 -331
- package/dist/runtime/components/form/images/Pad.vue +54 -54
- package/dist/runtime/components/label/Date.vue +37 -37
- package/dist/runtime/components/label/DateAgo.vue +102 -102
- package/dist/runtime/components/label/DateCount.vue +152 -152
- package/dist/runtime/components/label/Field.vue +111 -111
- package/dist/runtime/components/label/FormatMoney.vue +37 -37
- package/dist/runtime/components/label/Mask.vue +46 -46
- package/dist/runtime/components/label/Object.vue +21 -21
- package/dist/runtime/components/master/Autocomplete.vue +89 -89
- package/dist/runtime/components/master/Combobox.vue +88 -88
- package/dist/runtime/components/master/RadioGroup.vue +90 -90
- package/dist/runtime/components/master/Select.vue +70 -70
- package/dist/runtime/components/master/label.vue +55 -55
- package/dist/runtime/components/model/Autocomplete.vue +91 -91
- package/dist/runtime/components/model/Combobox.vue +90 -90
- package/dist/runtime/components/model/Pad.vue +114 -114
- package/dist/runtime/components/model/Select.vue +78 -84
- package/dist/runtime/components/model/Table.vue +370 -370
- package/dist/runtime/components/model/iterator.vue +497 -497
- package/dist/runtime/components/model/label.vue +58 -58
- package/dist/runtime/components/pdf/Print.vue +75 -75
- package/dist/runtime/components/pdf/View.vue +146 -146
- package/dist/runtime/composables/dialog.d.ts +1 -1
- package/dist/runtime/composables/graphql.d.ts +1 -1
- package/dist/runtime/composables/graphqlModel.d.ts +9 -9
- package/dist/runtime/composables/graphqlModelItem.d.ts +7 -7
- package/dist/runtime/composables/graphqlModelOperation.d.ts +6 -6
- package/dist/runtime/composables/userPermission.d.ts +1 -1
- package/dist/runtime/labs/Calendar.vue +99 -99
- package/dist/runtime/labs/form/EditMobile.vue +152 -152
- package/dist/runtime/labs/form/TextFieldMask.vue +43 -43
- package/dist/runtime/plugins/clientConfig.d.ts +1 -1
- package/dist/runtime/plugins/default.d.ts +1 -1
- package/dist/runtime/plugins/dialogManager.d.ts +1 -1
- package/dist/runtime/plugins/permission.d.ts +1 -1
- package/dist/runtime/types/alert.d.ts +11 -11
- package/dist/runtime/types/clientConfig.d.ts +13 -13
- package/dist/runtime/types/dialogManager.d.ts +35 -35
- package/dist/runtime/types/formDialog.d.ts +5 -5
- package/dist/runtime/types/graphqlOperation.d.ts +23 -23
- package/dist/runtime/types/menu.d.ts +31 -31
- package/dist/runtime/types/modules.d.ts +7 -7
- package/dist/runtime/types/permission.d.ts +13 -13
- package/package.json +131 -131
- package/scripts/enrich-vue-docs-from-ai.mjs +197 -197
- package/scripts/generate-ai-summary.mjs +321 -321
- package/scripts/generate-composables-md.mjs +129 -129
- package/scripts/postInstall.cjs +70 -70
- package/templates/.codegen/codegen.ts +32 -32
- package/templates/.codegen/plugin-schema-object.js +161 -161
|
@@ -1,207 +1,207 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
/**
|
|
3
|
-
* DeviceIdCardWebSocket bridges UI actions with host-agent hardware/device operations and emits runtime scan/read results.
|
|
4
|
-
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
5
|
-
*/
|
|
6
|
-
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
7
|
-
import { type IdCardWsServerMessage, type PatientRegisterPayload } from '../../composables/hostAgent'
|
|
8
|
-
import { useHostAgentWs } from "../../composables/hostAgentWs";
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
/** Subscribe withPhoto=true => server will push payload that includes photo when available */
|
|
12
|
-
withPhoto?: boolean // Includes portrait/photo data in ID card read results.
|
|
13
|
-
/** Optional reader name; null/undefined means "any/default" */
|
|
14
|
-
reader?: string | null // Preferred hardware reader identifier to connect or switch to.
|
|
15
|
-
/** Auto-connect on mount (default true) */
|
|
16
|
-
autoConnect?: boolean // Connects to the device WebSocket automatically on mount.
|
|
17
|
-
/** Auto-subscribe after connect (default true) */
|
|
18
|
-
autoSubscribe?: boolean // Subscribes to live reader events automatically after connect.
|
|
19
|
-
/** If true, try to reconnect when socket closes unexpectedly */
|
|
20
|
-
autoReconnect?: boolean // Retries connection automatically when the socket closes unexpectedly.
|
|
21
|
-
/** Reconnect delay in ms */
|
|
22
|
-
reconnectDelayMs?: number // Delay in milliseconds before each reconnect attempt.
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Public props accepted by DeviceIdCardWebSocket.
|
|
27
|
-
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
28
|
-
*/
|
|
29
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
30
|
-
withPhoto: false,
|
|
31
|
-
reader: null,
|
|
32
|
-
autoConnect: true,
|
|
33
|
-
autoSubscribe: true,
|
|
34
|
-
autoReconnect: false,
|
|
35
|
-
reconnectDelayMs: 1000,
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Custom events emitted by DeviceIdCardWebSocket.
|
|
40
|
-
* Parents can listen to these events to react to user actions and internal state changes.
|
|
41
|
-
*/
|
|
42
|
-
const emit = defineEmits<{
|
|
43
|
-
(e: 'connected'): void
|
|
44
|
-
(e: 'disconnected', info?: { code?: number; reason?: string }): void
|
|
45
|
-
(e: 'subscribed', info?: { reader?: string | null; withPhoto?: boolean }): void
|
|
46
|
-
(e: 'unsubscribed'): void
|
|
47
|
-
(e: 'inserted', payload: PatientRegisterPayload): void
|
|
48
|
-
(e: 'removed'): void
|
|
49
|
-
(e: 'error', err: unknown): void
|
|
50
|
-
(e: 'message', msg: IdCardWsServerMessage): void
|
|
51
|
-
}>()
|
|
52
|
-
|
|
53
|
-
const host = useHostAgentWs()
|
|
54
|
-
|
|
55
|
-
const reconnectTimer = ref<ReturnType<typeof setTimeout> | null>(null)
|
|
56
|
-
const mounted = ref(false)
|
|
57
|
-
const manuallyDisconnected = ref(false)
|
|
58
|
-
|
|
59
|
-
function clearReconnect() {
|
|
60
|
-
if (reconnectTimer.value) {
|
|
61
|
-
clearTimeout(reconnectTimer.value)
|
|
62
|
-
reconnectTimer.value = null
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function connectAndSubscribe() {
|
|
67
|
-
manuallyDisconnected.value = false
|
|
68
|
-
host.connectIdCardWs()
|
|
69
|
-
|
|
70
|
-
// subscribe immediately; safe because connectIdCardWs sets handlers then WS opens soon
|
|
71
|
-
// but we must wait until OPEN to send; so we subscribe on "open" event in handler below.
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function safeDisconnect() {
|
|
75
|
-
manuallyDisconnected.value = true
|
|
76
|
-
clearReconnect()
|
|
77
|
-
try {
|
|
78
|
-
// best-effort unsubscribe (only if connected)
|
|
79
|
-
if (host.wsConnected.value) {
|
|
80
|
-
try { host.unsubscribeIdCardWs() } catch { /* ignore */ }
|
|
81
|
-
}
|
|
82
|
-
} catch { /* ignore */ }
|
|
83
|
-
host.disconnectIdCardWs()
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const off = host.onIdCardWsEvent((ev) => {
|
|
87
|
-
if (ev.type === 'open') {
|
|
88
|
-
emit('connected')
|
|
89
|
-
|
|
90
|
-
if (props.autoSubscribe) {
|
|
91
|
-
try {
|
|
92
|
-
host.subscribeIdCardWs({ reader: props.reader ?? null, withPhoto: props.withPhoto })
|
|
93
|
-
} catch (e) {
|
|
94
|
-
emit('error', e)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (ev.type === 'close') {
|
|
101
|
-
emit('disconnected', { code: ev.code, reason: ev.reason })
|
|
102
|
-
|
|
103
|
-
if (props.autoReconnect && mounted.value && !manuallyDisconnected.value) {
|
|
104
|
-
clearReconnect()
|
|
105
|
-
reconnectTimer.value = setTimeout(() => {
|
|
106
|
-
try {
|
|
107
|
-
connectAndSubscribe()
|
|
108
|
-
} catch (e) {
|
|
109
|
-
emit('error', e)
|
|
110
|
-
}
|
|
111
|
-
}, props.reconnectDelayMs)
|
|
112
|
-
}
|
|
113
|
-
return
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (ev.type === 'error') {
|
|
117
|
-
emit('error', ev.error)
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (ev.type === 'message') {
|
|
122
|
-
const msg = ev.data
|
|
123
|
-
emit('message', msg)
|
|
124
|
-
|
|
125
|
-
switch (msg.type) {
|
|
126
|
-
case 'monitor.subscribed':
|
|
127
|
-
if (msg.ok) emit('subscribed', { reader: msg.reader ?? null, withPhoto: !!msg.withPhoto })
|
|
128
|
-
break
|
|
129
|
-
case 'monitor.unsubscribed':
|
|
130
|
-
emit('unsubscribed')
|
|
131
|
-
break
|
|
132
|
-
case 'card.inserted':
|
|
133
|
-
emit('inserted', msg.payload)
|
|
134
|
-
break
|
|
135
|
-
case 'card.removed':
|
|
136
|
-
emit('removed')
|
|
137
|
-
break
|
|
138
|
-
case 'card.error':
|
|
139
|
-
case 'error':
|
|
140
|
-
emit('error', msg)
|
|
141
|
-
break
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
onMounted(() => {
|
|
147
|
-
mounted.value = true
|
|
148
|
-
if (props.autoConnect) connectAndSubscribe()
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
onBeforeUnmount(() => {
|
|
152
|
-
mounted.value = false
|
|
153
|
-
try { off?.() } catch { /* ignore */ }
|
|
154
|
-
safeDisconnect()
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* If props change while connected, switch subscription behavior.
|
|
159
|
-
* - withPhoto changes => re-subscribe (server treats subscribe twice as error), so do unsubscribe -> subscribe
|
|
160
|
-
* - reader changes => use switchReader action when possible; if not connected, just store for next subscribe
|
|
161
|
-
*/
|
|
162
|
-
watch(
|
|
163
|
-
() => props.reader,
|
|
164
|
-
(r) => {
|
|
165
|
-
if (!mounted.value) return
|
|
166
|
-
if (!host.wsConnected.value) return
|
|
167
|
-
if (!host.wsSubscribed.value) return
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
host.switchReaderIdCardWs(r ?? null)
|
|
171
|
-
} catch (e) {
|
|
172
|
-
emit('error', e)
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
watch(
|
|
178
|
-
() => props.withPhoto,
|
|
179
|
-
(withPhoto) => {
|
|
180
|
-
if (!mounted.value) return
|
|
181
|
-
if (!host.wsConnected.value) return
|
|
182
|
-
|
|
183
|
-
// Server disallows re-subscribe without unsubscribe first.
|
|
184
|
-
// We do a clean unsubscribe -> resubscribe sequence.
|
|
185
|
-
try {
|
|
186
|
-
if (host.wsSubscribed.value) {
|
|
187
|
-
host.unsubscribeIdCardWs()
|
|
188
|
-
}
|
|
189
|
-
} catch { /* ignore */ }
|
|
190
|
-
|
|
191
|
-
// resubscribe after a tick; give server a moment to process unsubscribe
|
|
192
|
-
setTimeout(() => {
|
|
193
|
-
try {
|
|
194
|
-
if (host.wsConnected.value) {
|
|
195
|
-
host.subscribeIdCardWs({ reader: props.reader ?? null, withPhoto })
|
|
196
|
-
}
|
|
197
|
-
} catch (e) {
|
|
198
|
-
emit('error', e)
|
|
199
|
-
}
|
|
200
|
-
}, 0)
|
|
201
|
-
}
|
|
202
|
-
)
|
|
203
|
-
</script>
|
|
204
|
-
|
|
205
|
-
<template>
|
|
206
|
-
<!-- Intentionally blank (headless component) -->
|
|
207
|
-
</template>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* DeviceIdCardWebSocket bridges UI actions with host-agent hardware/device operations and emits runtime scan/read results.
|
|
4
|
+
* This doc block is consumed by vue-docgen for generated API documentation.
|
|
5
|
+
*/
|
|
6
|
+
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
7
|
+
import { type IdCardWsServerMessage, type PatientRegisterPayload } from '../../composables/hostAgent'
|
|
8
|
+
import { useHostAgentWs } from "../../composables/hostAgentWs";
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
/** Subscribe withPhoto=true => server will push payload that includes photo when available */
|
|
12
|
+
withPhoto?: boolean // Includes portrait/photo data in ID card read results.
|
|
13
|
+
/** Optional reader name; null/undefined means "any/default" */
|
|
14
|
+
reader?: string | null // Preferred hardware reader identifier to connect or switch to.
|
|
15
|
+
/** Auto-connect on mount (default true) */
|
|
16
|
+
autoConnect?: boolean // Connects to the device WebSocket automatically on mount.
|
|
17
|
+
/** Auto-subscribe after connect (default true) */
|
|
18
|
+
autoSubscribe?: boolean // Subscribes to live reader events automatically after connect.
|
|
19
|
+
/** If true, try to reconnect when socket closes unexpectedly */
|
|
20
|
+
autoReconnect?: boolean // Retries connection automatically when the socket closes unexpectedly.
|
|
21
|
+
/** Reconnect delay in ms */
|
|
22
|
+
reconnectDelayMs?: number // Delay in milliseconds before each reconnect attempt.
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Public props accepted by DeviceIdCardWebSocket.
|
|
27
|
+
* Document each prop field with intent, defaults, and side effects for clear generated docs.
|
|
28
|
+
*/
|
|
29
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
30
|
+
withPhoto: false,
|
|
31
|
+
reader: null,
|
|
32
|
+
autoConnect: true,
|
|
33
|
+
autoSubscribe: true,
|
|
34
|
+
autoReconnect: false,
|
|
35
|
+
reconnectDelayMs: 1000,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Custom events emitted by DeviceIdCardWebSocket.
|
|
40
|
+
* Parents can listen to these events to react to user actions and internal state changes.
|
|
41
|
+
*/
|
|
42
|
+
const emit = defineEmits<{
|
|
43
|
+
(e: 'connected'): void
|
|
44
|
+
(e: 'disconnected', info?: { code?: number; reason?: string }): void
|
|
45
|
+
(e: 'subscribed', info?: { reader?: string | null; withPhoto?: boolean }): void
|
|
46
|
+
(e: 'unsubscribed'): void
|
|
47
|
+
(e: 'inserted', payload: PatientRegisterPayload): void
|
|
48
|
+
(e: 'removed'): void
|
|
49
|
+
(e: 'error', err: unknown): void
|
|
50
|
+
(e: 'message', msg: IdCardWsServerMessage): void
|
|
51
|
+
}>()
|
|
52
|
+
|
|
53
|
+
const host = useHostAgentWs()
|
|
54
|
+
|
|
55
|
+
const reconnectTimer = ref<ReturnType<typeof setTimeout> | null>(null)
|
|
56
|
+
const mounted = ref(false)
|
|
57
|
+
const manuallyDisconnected = ref(false)
|
|
58
|
+
|
|
59
|
+
function clearReconnect() {
|
|
60
|
+
if (reconnectTimer.value) {
|
|
61
|
+
clearTimeout(reconnectTimer.value)
|
|
62
|
+
reconnectTimer.value = null
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function connectAndSubscribe() {
|
|
67
|
+
manuallyDisconnected.value = false
|
|
68
|
+
host.connectIdCardWs()
|
|
69
|
+
|
|
70
|
+
// subscribe immediately; safe because connectIdCardWs sets handlers then WS opens soon
|
|
71
|
+
// but we must wait until OPEN to send; so we subscribe on "open" event in handler below.
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function safeDisconnect() {
|
|
75
|
+
manuallyDisconnected.value = true
|
|
76
|
+
clearReconnect()
|
|
77
|
+
try {
|
|
78
|
+
// best-effort unsubscribe (only if connected)
|
|
79
|
+
if (host.wsConnected.value) {
|
|
80
|
+
try { host.unsubscribeIdCardWs() } catch { /* ignore */ }
|
|
81
|
+
}
|
|
82
|
+
} catch { /* ignore */ }
|
|
83
|
+
host.disconnectIdCardWs()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const off = host.onIdCardWsEvent((ev) => {
|
|
87
|
+
if (ev.type === 'open') {
|
|
88
|
+
emit('connected')
|
|
89
|
+
|
|
90
|
+
if (props.autoSubscribe) {
|
|
91
|
+
try {
|
|
92
|
+
host.subscribeIdCardWs({ reader: props.reader ?? null, withPhoto: props.withPhoto })
|
|
93
|
+
} catch (e) {
|
|
94
|
+
emit('error', e)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (ev.type === 'close') {
|
|
101
|
+
emit('disconnected', { code: ev.code, reason: ev.reason })
|
|
102
|
+
|
|
103
|
+
if (props.autoReconnect && mounted.value && !manuallyDisconnected.value) {
|
|
104
|
+
clearReconnect()
|
|
105
|
+
reconnectTimer.value = setTimeout(() => {
|
|
106
|
+
try {
|
|
107
|
+
connectAndSubscribe()
|
|
108
|
+
} catch (e) {
|
|
109
|
+
emit('error', e)
|
|
110
|
+
}
|
|
111
|
+
}, props.reconnectDelayMs)
|
|
112
|
+
}
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (ev.type === 'error') {
|
|
117
|
+
emit('error', ev.error)
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (ev.type === 'message') {
|
|
122
|
+
const msg = ev.data
|
|
123
|
+
emit('message', msg)
|
|
124
|
+
|
|
125
|
+
switch (msg.type) {
|
|
126
|
+
case 'monitor.subscribed':
|
|
127
|
+
if (msg.ok) emit('subscribed', { reader: msg.reader ?? null, withPhoto: !!msg.withPhoto })
|
|
128
|
+
break
|
|
129
|
+
case 'monitor.unsubscribed':
|
|
130
|
+
emit('unsubscribed')
|
|
131
|
+
break
|
|
132
|
+
case 'card.inserted':
|
|
133
|
+
emit('inserted', msg.payload)
|
|
134
|
+
break
|
|
135
|
+
case 'card.removed':
|
|
136
|
+
emit('removed')
|
|
137
|
+
break
|
|
138
|
+
case 'card.error':
|
|
139
|
+
case 'error':
|
|
140
|
+
emit('error', msg)
|
|
141
|
+
break
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
onMounted(() => {
|
|
147
|
+
mounted.value = true
|
|
148
|
+
if (props.autoConnect) connectAndSubscribe()
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
onBeforeUnmount(() => {
|
|
152
|
+
mounted.value = false
|
|
153
|
+
try { off?.() } catch { /* ignore */ }
|
|
154
|
+
safeDisconnect()
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* If props change while connected, switch subscription behavior.
|
|
159
|
+
* - withPhoto changes => re-subscribe (server treats subscribe twice as error), so do unsubscribe -> subscribe
|
|
160
|
+
* - reader changes => use switchReader action when possible; if not connected, just store for next subscribe
|
|
161
|
+
*/
|
|
162
|
+
watch(
|
|
163
|
+
() => props.reader,
|
|
164
|
+
(r) => {
|
|
165
|
+
if (!mounted.value) return
|
|
166
|
+
if (!host.wsConnected.value) return
|
|
167
|
+
if (!host.wsSubscribed.value) return
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
host.switchReaderIdCardWs(r ?? null)
|
|
171
|
+
} catch (e) {
|
|
172
|
+
emit('error', e)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
watch(
|
|
178
|
+
() => props.withPhoto,
|
|
179
|
+
(withPhoto) => {
|
|
180
|
+
if (!mounted.value) return
|
|
181
|
+
if (!host.wsConnected.value) return
|
|
182
|
+
|
|
183
|
+
// Server disallows re-subscribe without unsubscribe first.
|
|
184
|
+
// We do a clean unsubscribe -> resubscribe sequence.
|
|
185
|
+
try {
|
|
186
|
+
if (host.wsSubscribed.value) {
|
|
187
|
+
host.unsubscribeIdCardWs()
|
|
188
|
+
}
|
|
189
|
+
} catch { /* ignore */ }
|
|
190
|
+
|
|
191
|
+
// resubscribe after a tick; give server a moment to process unsubscribe
|
|
192
|
+
setTimeout(() => {
|
|
193
|
+
try {
|
|
194
|
+
if (host.wsConnected.value) {
|
|
195
|
+
host.subscribeIdCardWs({ reader: props.reader ?? null, withPhoto })
|
|
196
|
+
}
|
|
197
|
+
} catch (e) {
|
|
198
|
+
emit('error', e)
|
|
199
|
+
}
|
|
200
|
+
}, 0)
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
</script>
|
|
204
|
+
|
|
205
|
+
<template>
|
|
206
|
+
<!-- Intentionally blank (headless component) -->
|
|
207
|
+
</template>
|