优化二维码识别

This commit is contained in:
dzc committed 2025-03-12 14:12:07 +08:00
1 parent d656ce14eb
commit ca7fda4308
9 files changed
+225 -62

No files matched your search

@@ -10,7 +10,7 @@ class MainActivity : FlutterActivity() {
// 人脸识别插件
val flutterFaceDiscernPlugin = FlutterFaceDiscernPlugin()
flutterEngine.plugins.add(flutterFaceDiscernPlugin)
// 箭头全局键盘插件
// 键盘全局键盘插件
}
}
+10 -2
View File
@@ -174,10 +174,18 @@ class ServiceQRCode {
final String? userId;
/// 订单类型
final String? orderType;
@JsonKey(
fromJson: JsonTool.stringToOrderType,
toJson: JsonTool.orderTypeToString,
)
final OrderType? orderType;
/// 支付类型
final String? payType;
@JsonKey(
fromJson: JsonTool.stringToOrderPayType,
toJson: JsonTool.orderPayTypeToString,
)
final OrderPayType? payType;
/// 过期时间 -1 代表没有限制
final int? exceedTime;
+4 -4
View File
@@ -101,8 +101,8 @@ ServiceQRCode _$ServiceQRCodeFromJson(Map<String, dynamic> json) =>
itemId: JsonTool.intToString((json['itemId'] as num?)?.toInt()),
typeId: JsonTool.intToString((json['typeId'] as num?)?.toInt()),
userId: JsonTool.intToString((json['userId'] as num?)?.toInt()),
orderType: json['orderType'] as String?,
payType: json['payType'] as String?,
orderType: JsonTool.stringToOrderType(json['orderType'] as String?),
payType: JsonTool.stringToOrderPayType(json['payType'] as String?),
exceedTime: (json['exceedTime'] as num?)?.toInt(),
extra: json['extra'] as String?,
);
@@ -113,8 +113,8 @@ Map<String, dynamic> _$ServiceQRCodeToJson(ServiceQRCode instance) =>
'itemId': JsonTool.stringToInt(instance.itemId),
'typeId': JsonTool.stringToInt(instance.typeId),
'userId': JsonTool.stringToInt(instance.userId),
'orderType': instance.orderType,
'payType': instance.payType,
'orderType': JsonTool.orderTypeToString(instance.orderType),
'payType': JsonTool.orderPayTypeToString(instance.payType),
'exceedTime': instance.exceedTime,
'extra': instance.extra,
};
+1
View File
@@ -17,6 +17,7 @@ export './keyboard/keyboard_tool.dart';
export './logger/logger_tool.dart';
export './manage/barcode_scan_manage.dart';
export './manage/base/serial_base.dart';
export './manage/base/base_facility_manage.dart';
export './manage/tool/serial_read_card_tool.dart';
+20
View File
@@ -1,3 +1,5 @@
import 'package:pj_supermarket_cloud/common/index.dart';
abstract class JsonTool {
static bool stringToBoolean(String value) {
return value == '1';
@@ -27,4 +29,22 @@ abstract class JsonTool {
if (value == null) return null;
return dynamic as Map<String, dynamic>?;
}
static OrderType? stringToOrderType(String? value) {
return OrderType.values.fromCode(value);
}
static String? orderTypeToString(OrderType? value) {
if (value == null) return null;
return value.toString();
}
static OrderPayType? stringToOrderPayType(String? value) {
return OrderPayType.values.fromCode(value);
}
static String? orderPayTypeToString(OrderPayType? value) {
if (value == null) return null;
return value.toString();
}
}
@@ -0,0 +1,177 @@
import 'dart:async';
import 'dart:convert';
import 'package:common_utils/common_utils.dart';
import 'package:flutter/services.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;
bool _isListening = false;
String _buffer = '';
Timer? _timer;
final StreamController<String> _scanController =
StreamController<String>.broadcast();
Stream<String> get scanStream => _scanController.stream;
// 开始监听USB读头输入
void startListening() {
if (_isListening) return;
_isListening = true;
RawKeyboard.instance.addListener(_handleKeyEvent);
logger.i("|$_tag|开始监听USB读头输入");
}
// 停止监听
void stopListening() {
if (!_isListening) return;
RawKeyboard.instance.removeListener(_handleKeyEvent);
_timer?.cancel();
_isListening = false;
logger.i("|$_tag|停止监听USB读头输入");
}
// 处理键盘事件
void _handleKeyEvent(RawKeyEvent event) {
if (event is! RawKeyDownEvent) return;
// 重置定时器
_timer?.cancel();
// 处理回车键,表示扫码结束
if (event.logicalKey == LogicalKeyboardKey.enter) {
if (_buffer.isNotEmpty) {
logger.i("|$_tag|扫码结果: $_buffer");
// 清理和验证 base64 字符串
final cleanedBase64 = _cleanBase64(_buffer);
_scanController.add(cleanedBase64);
_buffer = '';
}
return;
}
// 获取字符
final character = _getCharacter(event);
if (character != null) {
_buffer += character;
// 设置超时定时器,如果超过一定时间没有新输入,则清空缓冲区
_timer = Timer(Duration(milliseconds: 100), () {
_buffer = '';
});
}
}
// 清理和验证 base64 字符串
String _cleanBase64(String input) {
String cleaned = input.trim();
cleaned = cleaned.replaceAll(RegExp(r'[^A-Za-z0-9+/=]'), '');
while (cleaned.length % 4 != 0) {
cleaned += '=';
}
return cleaned;
}
// 从键盘事件中获取字符
String? _getCharacter(RawKeyEvent 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) {
// 检查是否按下了Shift键,决定返回大写还是小写字母
final isShiftPressed = event.isShiftPressed;
final charCode = event.logicalKey.keyId -
LogicalKeyboardKey.keyA.keyId +
(isShiftPressed ? 65 : 97);
return String.fromCharCode(charCode);
}
// 处理其他常见字符
switch (event.logicalKey) {
case LogicalKeyboardKey.minus:
return event.isShiftPressed ? '_' : '-';
case LogicalKeyboardKey.equal:
return event.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 event.isShiftPressed ? '?' : '/';
case LogicalKeyboardKey.add:
return '+';
case LogicalKeyboardKey.underscore:
return '_';
default:
return null;
}
}
// 尝试解码 base64 字符串
Future<ServiceQRCode?> getCodeInfo(String base64Str) async {
try {
final cleanedBase64 = _cleanBase64(base64Str);
final json = EncryptUtil.decodeBase64(cleanedBase64);
if (ObjectUtil.isEmpty(json)) {
logger.e("|$_tag|二维码解析错误base64|$json|");
await TtsManage.speak("扫码失败请重试,base64解析错误");
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;
}
return qrCode;
} catch (e) {
logger.e("|$_tag|二维码解析错误: $e");
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();
_scanController.close();
}
}
@@ -195,25 +195,6 @@ class SelectPayTypeDialogController extends GetxController {
}
}
globalQrCode = qrCode;
// 解析为enum 支付类型
if (ObjectUtil.isNotEmpty(qrCode.payType)) {
final OrderPayType? type =
OrderPayType.values.fromCode(qrCode.payType!);
if (ObjectUtil.isNotEmpty(type)) {
orderPayType.value = type!;
}
}
// 解析为enum 订单类型
if (ObjectUtil.isNotEmpty(qrCode.orderType)) {
final OrderType? type = OrderType.values.fromCode(qrCode.orderType!);
if (ObjectUtil.isNotEmpty(type)) {
orderType.value = type!;
}
}
if (orderPayType.value == null || orderType.value == null) {
logger.e("|$_tag|二维码识别,订单类型或者支付类型解析错误:|$str|");
return;
}
if (!_validateQrCodeType(orderPayType.value!)) {
logger.e("|$_tag|二维码识别,无效的二维码json:|$str|");
Toast.error(msg: "识别错误,无效的二维码");
+5 -2
View File
@@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:common_utils/common_utils.dart';
import 'package:get/get.dart';
@@ -75,8 +77,9 @@ class PanelController extends GetxController {
Get.offAndToNamed(RouteNames.login);
break;
case PanelType.test:
await TtsManage.initialize();
await TtsManage.speak("购买成功1");
// tts测试 成功
// await TtsManage.initialize();
// await TtsManage.speak("购买成功1");
break;
default:
break;
+6 -33
View File
@@ -95,39 +95,12 @@ class TakeFoodController extends GetxController {
/// 开启扫码
Future<void> startQrcode() async {
try {
final isOpen = await appC.scanCodeManage.open();
if (!isOpen) return;
appC.scanCodeManage.listen<String>((str) async {
if (ObjectUtil.isNotEmpty(str)) {
str = EncryptUtil.decodeBase64(str);
final qrCode = ServiceQRCode.fromJson(json.decode(str));
if (ObjectUtil.isEmpty(qrCode)) {
Toast.error(msg: "识别错误,无效的二维码");
return;
}
globalQrCode = qrCode;
// 二维码支付渠道
if (ObjectUtil.isNotEmpty(qrCode.payType)) {
final OrderPayType? type = OrderPayType.values.fromCode(
qrCode.payType!,
);
if (ObjectUtil.isNotEmpty(type)) {
orderPayType = type!;
}
}
if (ObjectUtil.isNotEmpty(qrCode.orderType)) {
final OrderType? type = OrderType.values.fromCode(
qrCode.orderType!,
);
if (ObjectUtil.isNotEmpty(type)) {
orderType = type!;
}
}
orderId = qrCode.id;
await getOrderDetail();
await getCarList();
Toast.success(msg: "识别二维码成功");
}
// 监听二维码测试
BarcodeScanManage.instance.startListening();
BarcodeScanManage.instance.scanStream.listen((event) async {
final serviceCode = await BarcodeScanManage.instance.getCodeInfo(event);
if (serviceCode == null) return;
globalQrCode = serviceCode;
});
} catch (e) {
doCancelPay();