优化二维码识别
This commit is contained in:
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)
|
||||
|
||||
// 箭头全局键盘插件
|
||||
|
||||
// 键盘全局键盘插件
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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: "识别错误,无效的二维码");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user