Files
biz_xfj_cloud/lib/common/utils/manage/barcode_scan_manage.dart
T

245 lines
7.7 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:common_utils/common_utils.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
class BarcodeScanManage {
static const String _tag = "条码扫描管理";
BarcodeScanManage._privateConstructor();
static final BarcodeScanManage _instance =
BarcodeScanManage._privateConstructor();
static BarcodeScanManage get instance => _instance;
// 添加白名单焦点节点列表
final Set<FocusNode> _whitelistNodes = {};
bool _isListening = false;
final _buffer = StringBuffer();
Timer? _timer;
// 二维码扫码结果
StreamController<String>? _qrcodeScanController;
Stream<String> get qrcodeScanStream {
_qrcodeScanController ??= StreamController<String>.broadcast();
return _qrcodeScanController!.stream;
}
// 扫码枪扫码结果
StreamController<String>? _gunScanController;
Stream<String> get gunScanStream {
_gunScanController ??= StreamController<String>.broadcast();
return _gunScanController!.stream;
}
// 添加白名单焦点
void addWhitelistNode(FocusNode node) {
_whitelistNodes.add(node);
}
// 移除白名单焦点
void removeWhitelistNode(FocusNode node) {
_whitelistNodes.remove(node);
}
// 开始监听USB读头输入
void startListening() {
if (_isListening) return;
if (_qrcodeScanController?.isClosed ?? true) {
_qrcodeScanController = StreamController<String>.broadcast();
}
if (_gunScanController?.isClosed ?? true) {
_gunScanController = StreamController<String>.broadcast();
}
if (AppRuntimeTool.useManualHardwareInput) return;
_isListening = true;
// 只有当当前焦点不在白名单中时才取消焦点
final currentFocus = FocusManager.instance.primaryFocus;
if (currentFocus != null && !_whitelistNodes.contains(currentFocus)) {
currentFocus.unfocus();
}
HardwareKeyboard.instance.addHandler(_handleKeyEvent);
}
/// 人工提交二维码结果,继续复用真实扫码后的业务订阅。
void addManualQrCode(String code) {
if (code.trim().isEmpty) return;
_qrcodeScanController ??= StreamController<String>.broadcast();
_qrcodeScanController?.add(code.trim());
}
/// 人工提交商品条码或付款码,继续复用扫码枪业务订阅。
void addManualGunCode(String code) {
if (code.trim().isEmpty) return;
_gunScanController ??= StreamController<String>.broadcast();
_gunScanController?.add(code.trim());
}
// 停止监听
void stopListening() {
if (!_isListening) return;
HardwareKeyboard.instance.removeHandler(_handleKeyEvent);
_timer?.cancel();
_isListening = false;
logger.i("|$_tag|停止监听USB读头输入");
}
// 处理键盘事件
bool _handleKeyEvent(KeyEvent event) {
final currentFocus = FocusManager.instance.primaryFocus;
if (currentFocus != null && _whitelistNodes.contains(currentFocus)) {
return false;
}
FocusManager.instance.primaryFocus?.unfocus();
if (event is! KeyDownEvent) return false;
try {
_timer?.cancel();
// 处理回车键,表示扫码结束
if (event.logicalKey.keyId == 0x10000000d) {
if (_buffer.isNotEmpty) {
final result = _buffer.toString();
logger.i("|$_tag|扫码结果: $result");
result.length == 32
? _qrcodeScanController?.add(result)
: _gunScanController?.add(result);
_buffer.clear();
return true;
}
}
final character = _getCharacter(event);
if (character != null) {
_buffer.write(character);
// 设置超时定时器,如果超过一定时间没有新输入,则清空缓冲区
_timer = Timer(Duration(milliseconds: 100), () {
if (_buffer.isNotEmpty) {
_buffer.clear();
}
});
return true;
}
return false;
} catch (e, stack) {
logger.e("|$_tag|处理键盘事件错误error|$e|stack|$stack|");
_buffer.clear();
_timer?.cancel();
return false;
}
}
// 从键盘事件中获取字符
String? _getCharacter(KeyEvent event) {
// 处理数字键
if (event.logicalKey.keyId >= LogicalKeyboardKey.digit0.keyId &&
event.logicalKey.keyId <= LogicalKeyboardKey.digit9.keyId) {
return String.fromCharCode(
event.logicalKey.keyId - LogicalKeyboardKey.digit0.keyId + 48);
}
// 处理小写字母键
if (event.logicalKey.keyId >= LogicalKeyboardKey.keyA.keyId &&
event.logicalKey.keyId <= LogicalKeyboardKey.keyZ.keyId) {
final isShiftPressed = HardwareKeyboard.instance.isShiftPressed;
final charCode = event.logicalKey.keyId -
LogicalKeyboardKey.keyA.keyId +
(isShiftPressed ? 65 : 97);
return String.fromCharCode(charCode);
}
// 处理其他常见字符
switch (event.logicalKey) {
case LogicalKeyboardKey.minus:
return HardwareKeyboard.instance.isShiftPressed ? '_' : '-';
case LogicalKeyboardKey.equal:
return HardwareKeyboard.instance.isShiftPressed ? '+' : '=';
case LogicalKeyboardKey.bracketLeft:
return '[';
case LogicalKeyboardKey.bracketRight:
return ']';
case LogicalKeyboardKey.backslash:
return '\\';
case LogicalKeyboardKey.semicolon:
return ';';
case LogicalKeyboardKey.quote:
return '\'';
case LogicalKeyboardKey.comma:
return ',';
case LogicalKeyboardKey.period:
return '.';
case LogicalKeyboardKey.slash:
return HardwareKeyboard.instance.isShiftPressed ? '?' : '/';
case LogicalKeyboardKey.add:
return '+';
case LogicalKeyboardKey.underscore:
return '_';
default:
return null;
}
}
// 尝试解码 base64 字符串
Future<ServiceQRCode?> getCodeInfo(String str) async {
try {
// 根据短码查询
final pa = {"shortCode": str};
final encryptString = await WalletApi.getByShortCode(pa);
if (ObjectUtil.isEmpty(encryptString)) {
logger.e("|$_tag|getByShortCode错误shortCode|$str|");
await TtsManage.speak("扫码失败请重试");
return null;
}
final json = EncryptUtil.decodeBase64(encryptString!);
if (ObjectUtil.isEmpty(json)) {
logger.e("|$_tag|二维码base64解析错误|$json|");
await TtsManage.speak("扫码失败请重试");
return null;
}
final qrCode = ServiceQRCode.fromJson(jsonDecode(json));
if (ObjectUtil.isEmpty(qrCode)) {
logger.e("|$_tag|无效的二维码,json|$json|");
await TtsManage.speak("无效的二维码");
return null;
}
// 支付方式
if (ObjectUtil.isEmpty(qrCode.payType) ||
ObjectUtil.isEmpty(qrCode.orderType)) {
logger.e("|$_tag|无效的二维码,支付方式或者订单类型错误,json|$json|");
await TtsManage.speak("无效的二维码");
return null;
}
TtsManage.speak("扫码成功");
return qrCode;
} catch (e) {
logger.e("|$_tag|二维码解析意外的错误: $e");
await TtsManage.speak("扫码失败请重试");
return null;
}
}
// 尝试解析 JSON
Map<String, dynamic>? parseJson(String jsonStr) {
try {
return json.decode(jsonStr) as Map<String, dynamic>;
} catch (e) {
logger.e("|$_tag|JSON解析错误: $e");
return null;
}
}
// 释放资源
void dispose() {
stopListening();
_qrcodeScanController?.close();
_gunScanController?.close();
}
void disposeQrCodeScan() {
_qrcodeScanController?.close();
}
void disposeGunScan() {
_gunScanController?.close();
}
}