From a2c7ba01ae6c2f3f16d03a0fadee0cdad8c6f0d1 Mon Sep 17 00:00:00 2001 From: ck-chenkang Date: Wed, 17 Jun 2026 16:39:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8A=BD=E5=8F=96=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E6=89=AB=E7=A0=81=E8=BE=93=E5=85=A5=E7=9B=91=E5=90=AC=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BE=E5=A4=87=E5=8F=B0=E8=B4=A6=E6=89=AB?= =?UTF-8?q?=E7=A0=81=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useScannerInput.js | 203 ++++++++++++++++++ .../pages/equipmentLedger/index.vue | 46 ++-- 2 files changed, 236 insertions(+), 13 deletions(-) create mode 100644 src/hooks/useScannerInput.js diff --git a/src/hooks/useScannerInput.js b/src/hooks/useScannerInput.js new file mode 100644 index 0000000..4de89c9 --- /dev/null +++ b/src/hooks/useScannerInput.js @@ -0,0 +1,203 @@ +import { onHide, onShow, onUnload } from '@dcloudio/uni-app' + +const androidKeyCodeMap = { + 7: '0', + 8: '1', + 9: '2', + 10: '3', + 11: '4', + 12: '5', + 13: '6', + 14: '7', + 15: '8', + 16: '9', + 29: 'A', + 30: 'B', + 31: 'C', + 32: 'D', + 33: 'E', + 34: 'F', + 35: 'G', + 36: 'H', + 37: 'I', + 38: 'J', + 39: 'K', + 40: 'L', + 41: 'M', + 42: 'N', + 43: 'O', + 44: 'P', + 45: 'Q', + 46: 'R', + 47: 'S', + 48: 'T', + 49: 'U', + 50: 'V', + 51: 'W', + 52: 'X', + 53: 'Y', + 54: 'Z', + 55: ',', + 56: '.', + 69: '-', + 70: '=', + 71: '[', + 72: ']', + 73: '\\', + 74: ';', + 75: "'", + 76: '/', + 81: '+' +} + +export function useScannerInput(options = {}) { + const minLength = Number(options.minLength ?? 3) + const commitDelay = Number(options.commitDelay ?? 120) + const uppercase = options.uppercase !== false + const ignoreInputTarget = options.ignoreInputTarget !== false + const hideKeyboardOnScan = options.hideKeyboardOnScan !== false + const hideKeyboardOnLeave = options.hideKeyboardOnLeave !== false + const onScan = typeof options.onScan === 'function' ? options.onScan : () => {} + + let scannerBuffer = '' + let scannerTimer = null + let scannerListening = false + let plusKeyListening = false + + function getScannerEventTarget() { + if (typeof document !== 'undefined') return document + if (typeof window !== 'undefined') return window + return null + } + + function registerScannerListener() { + if (scannerListening) return + const target = getScannerEventTarget() + if (target?.addEventListener) { + target.addEventListener('keydown', handleScannerKeydown) + scannerListening = true + } + registerPlusKeyListener() + } + + function unregisterScannerListener() { + const target = getScannerEventTarget() + if (scannerListening && target?.removeEventListener) { + target.removeEventListener('keydown', handleScannerKeydown) + } + scannerListening = false + unregisterPlusKeyListener() + clearScannerBuffer() + if (hideKeyboardOnLeave) hideSoftKeyboard() + } + + function registerPlusKeyListener() { + if (plusKeyListening) return + if (typeof plus === 'undefined' || !plus?.key?.addEventListener) return + plus.key.addEventListener('keydown', handlePlusScannerKeydown) + plusKeyListening = true + } + + function unregisterPlusKeyListener() { + if (!plusKeyListening) return + if (typeof plus !== 'undefined' && plus?.key?.removeEventListener) { + plus.key.removeEventListener('keydown', handlePlusScannerKeydown) + } + plusKeyListening = false + } + + function handlePlusScannerKeydown(event) { + handleScannerKeydown({ ...event, isPlusKeyEvent: true }) + } + + function handleScannerKeydown(event) { + if (ignoreInputTarget) { + const targetTag = String(event?.target?.tagName || '').toLowerCase() + if (targetTag === 'input' || targetTag === 'textarea') return + } + + const key = normalizeScannerKey(event) + if (!key) return + if (key === 'Enter') { + commitScannerBuffer() + return + } + + scannerBuffer += key + if (scannerTimer) clearTimeout(scannerTimer) + scannerTimer = setTimeout(() => { + commitScannerBuffer() + }, commitDelay) + } + + function normalizeScannerKey(event) { + if (event?.ctrlKey || event?.altKey || event?.metaKey) return '' + if (isAndroidPlusKeyEvent(event)) return normalizeAndroidKeyCode(event) + + const key = event?.key + if (key === 'Enter' || key === 'Tab') return 'Enter' + if (typeof key === 'string' && key.length === 1) return uppercase ? key.toUpperCase() : key + + const code = Number(event?.keyCode || event?.which || 0) + if (code === 13 || code === 9) return 'Enter' + if (code >= 48 && code <= 90) { + const value = String.fromCharCode(code) + return uppercase ? value.toUpperCase() : value + } + if (code >= 96 && code <= 105) return String(code - 96) + if (code === 189 || code === 109) return '-' + if (code === 190 || code === 110) return '.' + return '' + } + + function isAndroidPlusKeyEvent(event) { + return Boolean(event?.isPlusKeyEvent) + } + + function normalizeAndroidKeyCode(event) { + const code = Number(event?.keyCode || event?.which || 0) + if (code === 66 || code === 61 || code === 160) return 'Enter' + const value = androidKeyCodeMap[code] || '' + return uppercase ? value.toUpperCase() : value.toLowerCase() + } + + function clearScannerBuffer() { + scannerBuffer = '' + if (scannerTimer) { + clearTimeout(scannerTimer) + scannerTimer = null + } + } + + async function commitScannerBuffer() { + const value = scannerBuffer.trim() + clearScannerBuffer() + if (value.length < minLength) return + if (hideKeyboardOnScan) hideSoftKeyboard() + await onScan(value) + } + + function hideSoftKeyboard() { + try { + uni.hideKeyboard() + } catch (e) {} + } + + onShow(() => { + registerScannerListener() + }) + + onHide(() => { + unregisterScannerListener() + }) + + onUnload(() => { + unregisterScannerListener() + }) + + return { + clearScannerBuffer, + registerScannerListener, + unregisterScannerListener + } +} diff --git a/src/pages_function/pages/equipmentLedger/index.vue b/src/pages_function/pages/equipmentLedger/index.vue index a3662a1..d8ea078 100644 --- a/src/pages_function/pages/equipmentLedger/index.vue +++ b/src/pages_function/pages/equipmentLedger/index.vue @@ -7,14 +7,14 @@ {{ selectedLineLabel }} - + @@ -82,7 +82,7 @@