245 lines
7.7 KiB
Dart
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();
|
|
}
|
|
}
|