feat:取消系统自带软键盘设计,改为系统自用键盘组件-初步

feat:将打印分为图片打印和命令式打印-初步
This commit is contained in:
dzc committed 2026-09-20 18:24:01 +08:00
1 parent 94ee7415b1
commit e68f41375b
38 files changed
+1471 -408

No files matched your search

+43 -2
View File
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:common_utils/common_utils.dart';
import 'package:get/get.dart';
@@ -34,12 +35,14 @@ abstract class SyncPrintTool {
/// 将 MQTT 或 HTTP 待办按服务端任务 ID 转换为唯一的本地任务。
///
/// [orderId] 是服务端订单 ID,[androidOrderId] 允许线上预约订单为空;[historyId]
/// 是本地唯一去重键,[retryVersion] 只有高于本地失败版本时才允许再次进入打印队列。
/// 是本地唯一去重键,[retryVersion] 只有高于本地失败版本时才允许再次进入打印队列;
/// [printCmd] 是后端拼装的 Base64 指令流,指令打印模式直写 USB,可空。
static Future<void> addTask({
required String orderId,
String? androidOrderId,
required String historyId,
required String pic,
String? printCmd,
String printType = '1',
int printNo = 1,
int retryVersion = 0,
@@ -49,6 +52,7 @@ abstract class SyncPrintTool {
androidOrderId: androidOrderId,
historyId: historyId,
pic: pic,
printCmd: printCmd,
printType: printType,
printNo: printNo,
retryVersion: retryVersion,
@@ -67,6 +71,7 @@ abstract class SyncPrintTool {
String? androidOrderId,
required String historyId,
required String pic,
required String? printCmd,
required String printType,
required int printNo,
required int retryVersion,
@@ -90,6 +95,7 @@ abstract class SyncPrintTool {
: orderId
..serviceOrderId = orderId
..invoiceUrl = pic
..printCmd = printCmd?.trim().isNotEmpty == true ? printCmd : null
..printType = printType
..printNo = printNo
..retryVersion = retryVersion
@@ -108,6 +114,7 @@ abstract class SyncPrintTool {
serviceOrderId: orderId,
servicePrintId: historyId,
invoiceUrl: pic,
printCmd: printCmd?.trim().isNotEmpty == true ? printCmd : null,
printType: printType,
printNo: printNo,
retryVersion: retryVersion,
@@ -150,6 +157,7 @@ abstract class SyncPrintTool {
androidOrderId: task.androidOrderCode,
historyId: task.historyId!,
pic: task.pic!,
printCmd: task.printCmd,
printType: task.printType ?? '1',
printNo: task.printNo ?? 1,
retryVersion: task.retryVersion ?? 0,
@@ -207,6 +215,8 @@ abstract class SyncPrintTool {
static Future<void> _print(PrintHistoryEntity task) async {
final app = Get.find<AppControl>();
final dao = app.dataBase.getPrintHistoryDao;
// 指令解码在尝试循环外完成一次:Base64 损坏属于任务数据问题,重试不会好转,直接回退图片。
final commandBytes = await _resolveCommandBytes(task);
for (var index = 0; index < attemptDelays.length; index++) {
final delay = attemptDelays[index];
if (delay > Duration.zero) {
@@ -220,7 +230,11 @@ abstract class SyncPrintTool {
if (!opened) {
throw StateError(app.printManage.lastError ?? 'USB 打印机连接失败');
}
final accepted = await app.printManage.printImg(task.invoiceUrl);
// 指令字节可用时直写指令流;图片模式、无指令或指令损坏时走图片栅格打印。
// 指令写入失败只按原节奏重试指令,不回退图片,避免同一任务两种内容先后出纸。
final accepted = commandBytes != null
? await app.printManage.printCommand(commandBytes)
: await app.printManage.printImg(task.invoiceUrl);
if (!accepted) {
throw StateError(app.printManage.lastError ?? 'USB 未完整接收打印数据');
}
@@ -250,6 +264,33 @@ abstract class SyncPrintTool {
await _report(task);
}
/// 指令打印模式下解码任务携带的 Base64 打印指令流。
///
/// 图片模式、任务无指令、内容为空或 Base64 损坏时返回 null,调用方回退图片栅格打印;
/// 解码失败不进入 USB 重试节奏,因为重试同一份损坏数据不会改变结果。
static Future<List<int>?> _resolveCommandBytes(
PrintHistoryEntity task,
) async {
final setting = await AppSettingTool.getSysSetting();
if (setting.printerOutputMode != AppSettingTool.printerOutputModeCommand) {
return null;
}
final raw = task.printCmd?.trim() ?? '';
if (raw.isEmpty) return null;
try {
final decoded = base64.decode(raw.replaceAll(RegExp(r'\s'), ''));
if (decoded.isEmpty) {
logger.w('|$_tag|打印指令内容为空,回退图片打印|task:${task.servicePrintId}|');
return null;
}
return decoded;
} catch (error) {
logger.w(
'|$_tag|打印指令解码失败,回退图片打印|task:${task.servicePrintId}|error:$error|');
return null;
}
}
/// 向服务端提交当前重试版本的最终结果;失败时保留 resultPending 等待网络恢复补报。
static Future<void> _report(PrintHistoryEntity task) async {
if (!AppNetworkTool.isAutoNetwork()) {