import 'dart:io'; import 'package:dio/dio.dart' as dio; import 'package:pj_supermarket_cloud/common/index.dart'; abstract class HardApi { /// 按终端订单号或服务端订单 ID 对账识别证据状态;后台任务失败不弹业务 Toast。 static Future resolveOrderEvidence({ required String hardId, String? androidOrderCode, String? orderId, }) async { final res = await HttpManage().dio.get( '/hard/hard-order-evidence/ad/resolve', queryParameters: { if (androidOrderCode != null) 'androidOrderCode': androidOrderCode, if (orderId != null) 'orderId': orderId, }, options: dio.Options( headers: {'DEVICE-ID': hardId}, extra: {HttpManage.silentRequestKey: true}, ), ); if (res.data == null) return null; return ServiceOrderEvidenceResolve.fromJson(res.data); } /// 提交识别元数据、触发参考图复制或报告本地图片永久缺失。 static Future submitOrderEvidence({ required String hardId, required OrderEvidenceRequest request, }) async { final res = await HttpManage().dio.post( '/hard/hard-order-evidence/ad/submit', data: request.toJson(), options: dio.Options( headers: {'DEVICE-ID': hardId}, extra: {HttpManage.silentRequestKey: true}, ), ); if (res.data == null) return null; return ServiceOrderEvidenceUploadResult.fromJson(res.data); } /// 使用统一 Dio 鉴权和租户头上传现场图片,multipart 文件名不包含终端完整路径。 static Future uploadOrderEvidence({ required String hardId, required OrderEvidenceRequest request, required String filePath, }) async { final file = File(filePath); final fileName = file.uri.pathSegments.last; final form = dio.FormData.fromMap({ ...request.toJson(), 'file': await dio.MultipartFile.fromFile(filePath, filename: fileName), }); final res = await HttpManage().dio.post( '/hard/hard-order-evidence/ad/upload', data: form, options: dio.Options( headers: {'DEVICE-ID': hardId}, contentType: 'multipart/form-data', extra: {HttpManage.silentRequestKey: true}, ), ); if (res.data == null) return null; return ServiceOrderEvidenceUploadResult.fromJson(res.data); } /// 静默上报食堂、超市 Android 终端最新运行状态;后台失败不得弹出业务 Toast。 static Future terminalHeartbeat({ required String hardId, required Map data, }) async { await HttpManage().dio.post( '/hard/hard-api/ad/terminal-heartbeat', data: data, options: dio.Options( headers: {'DEVICE-ID': hardId}, extra: {HttpManage.silentRequestKey: true}, ), ); } /// 获取硬件配置信息 static Future bind(dynamic pa) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/bind", data: pa, ); if (res.data == null) return null; return ServiceHardware.fromJson(res.data); } /// 获取硬件配置信息 static Future get(dynamic pa) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/get", queryParameters: pa, ); if (res.data == null) return null; return ServiceHardware.fromJson(res.data); } /// 获取用户信息 static Future getUserInfoById( dynamic formData, ) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/get-user", queryParameters: formData, ); if (res.data == null) return null; return ServiceUser.fromJson(res.data); } /// 获取用户信息 static Future getUserByCard( dynamic formData, ) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/get-user-by-card", queryParameters: formData, ); if (res.data == null) return null; return ServiceUser.fromJson(res.data); } /// 仅按当前终端和识别身份查询本人预约,调用方不得补充商户或其他用户参数。 static Future queryReservationMenu( ReservationMenuQueryRequest request, ) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/reservation-menu/query", data: request.toJson(), ); if (res.data == null) return null; return ServiceReservationMenuQuery.fromJson(res.data); } /// 只按查询结果中的订单 ID 核销一笔预约订单。 static Future cancelReservationOrder({ required int orderId, }) async { final setting = await AppSettingTool.getSysSetting(); final res = await HttpManage().dio.post( '/hard/hard-api/ad/reservation-menu/cancel', data: {'orderId': orderId}, options: dio.Options( headers: { if (setting.serviceId != null) 'DEVICE-ID': setting.serviceId, }, ), ); return res.data == true; } /// 一次提交多笔同一用户预约订单,服务端在同一事务内核销并合并生成一张兑换券。 static Future cancelReservationOrders({ required List orderIds, }) async { final setting = await AppSettingTool.getSysSetting(); final hardId = setting.serviceId; if (hardId == null || hardId.isEmpty) { throw StateError('当前业务终端尚未绑定'); } final res = await HttpManage().dio.post( '/hard/hard-api/ad/reservation-menu/cancel-batch', data: {'orderIds': orderIds}, options: dio.Options(headers: {'DEVICE-ID': hardId}), ); return res.data == true; } /// 分页查询当前设备的预约核销记录,设备范围由服务端再次校验。 static Future verificationRecordPage({ required int current, required int size, required VerificationRecordQueryRequest request, }) async { final res = await HttpManage().dio.post( '/hard/hard-api/ad/verification-record/page', queryParameters: {'current': current, 'size': size}, data: request.toJson(), options: dio.Options(headers: {'DEVICE-ID': request.hardId}), ); if (res.data == null) return null; return ServiceVerificationRecordPage.fromJson(res.data); } /// 分页查询当前设备的交易记录;scope=MERCHANT 时按终端所属商户查询全部设备。 static Future terminalOrderRecordPage({ required int current, required int size, required TerminalOrderRecordQueryRequest request, }) async { final res = await HttpManage().dio.post( '/hard/hard-api/ad/order-record/page', queryParameters: {'current': current, 'size': size}, data: request.toJson(), options: dio.Options(headers: {'DEVICE-ID': '${request.hardId}'}), ); if (res.data == null) return null; return ServiceTerminalOrderRecordPage.fromJson(res.data); } /// 创建硬件订单 static Future createHardwareOrder(dynamic formData) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/create-order", data: formData, options: dio.Options( extra: {HttpManage.rejectBusinessErrorKey: true}, ), ); if (res.data == null) return null; return res.data; } /// 创建硬件订单 static Future createHardQrCodeScanOrder(dynamic formData) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/create-hard-qr-code-order", data: formData, options: dio.Options( extra: {HttpManage.rejectBusinessErrorKey: true}, ), ); if (res.data == null) return null; return ServiceHardCreateHardQrCodeScanOrder.fromJson(res.data); } /// 创建与 Hardware 业务订单绑定的支付宝、微信聚合订单码。 static Future createAggregateOrderCodePay( dynamic formData) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/create-aggregate-order-code-pay", data: formData, options: dio.Options( extra: {HttpManage.rejectBusinessErrorKey: true}, ), ); if (res.data == null) return null; return ServiceHardAggregateOrderCodePay.fromJson(res.data); } /// 查询聚合支付状态;成功响应表示 Hardware 业务订单已同步完成结算。 static Future getAggregateOrderCodePayStatus({ required String orderId, required String aggregateNo, }) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/aggregate-order-code-pay/status", queryParameters: { "orderId": orderId, "aggregateNo": aggregateNo, }, ); if (res.data == null) return null; return ServiceHardAggregateOrderCodePayStatus.fromJson(res.data); } /// 根据订单id,获取订单详情 static Future getOrder(dynamic formData) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/get-order", queryParameters: formData, ); if (res.data == null) return null; return ServiceHardOrder.fromJson(res.data); } /// 获取订单购物车 static Future?> getCarByOrderId( dynamic formData, ) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/get-by-order-id", queryParameters: formData, ); if (res.data == null) return null; return res.data?.map((e) => ServiceCar.fromJson(e)).toList(); } /// 核销订单 static Future cancelQrCode(dynamic formData) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/cancel-code", data: formData, ); if (res.data == null) return false; return true; } /// 核销活动订单 static Future cancelActQrCode(dynamic formData) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/cancel-act-code", data: formData, ); if (res.data == null) return false; return true; } /// 生成发票 static Future generateInvoice( dynamic formData, ) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/generate-invoice", queryParameters: formData, ); if (res.data == null) return null; return ServiceGenerateInvoice.fromJson(res.data); } /// 业务终端按 DEVICE-ID 创建打印任务,目标打印机只由服务端绑定关系决定。 static Future createPrinterTask({ required String orderId, String printType = '1', }) async { final setting = await AppSettingTool.getSysSetting(); final hardId = setting.serviceId; if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定'); final res = await HttpManage().dio.post( '/hard/hard-api/ad/printer/task', data: { 'orderId': int.parse(orderId), 'printType': printType, }, options: dio.Options(headers: {'DEVICE-ID': hardId}), ); return res.data != null; } /// 在线查询当前业务终端为指定订单生成的打印凭证,不读取终端本地打印记录。 static Future> getPrinterRecords({ required String orderId, }) async { final setting = await AppSettingTool.getSysSetting(); final hardId = setting.serviceId; if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定'); final res = await HttpManage().dio.get( '/hard/hard-api/ad/printer/records', queryParameters: {'orderId': int.parse(orderId)}, options: dio.Options(headers: {'DEVICE-ID': hardId}), ); if (res.data == null) return const []; if (res.data is! List) throw const FormatException('打印凭证记录格式错误'); return (res.data as List) .map((item) => ServicePrintRecord.fromJson( Map.from(item as Map), )) .toList(growable: false); } /// 提交当前业务终端已打印兑换券的人工重打原因并取得新任务。 static Future reprintVoucher({ required String historyId, required String reason, }) async { final setting = await AppSettingTool.getSysSetting(); final hardId = setting.serviceId; if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定'); final res = await HttpManage().dio.post( '/hard/hard-api/ad/printer/reprint', data: { 'historyId': int.parse(historyId), 'reprintReason': reason, }, options: dio.Options(headers: {'DEVICE-ID': hardId}), ); if (res.data == null) return null; if (res.data is! Map) throw const FormatException('兑换券重打任务格式错误'); return ServicePrintRecord.fromJson( Map.from(res.data as Map), ); } /// 打印成功 static Future printInvoice(dynamic formData) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/print-invoice", queryParameters: formData, ); if (res.data == null) return false; return true; } /// 读取当前食堂或超市终端绑定的逻辑打印机及 USB/ESC-POS 参数。 static Future?> getPrinterBinding() async { final setting = await AppSettingTool.getSysSetting(); final hardId = setting.serviceId; if (hardId == null || hardId.isEmpty) throw StateError('当前业务终端尚未绑定设备 ID'); final res = await HttpManage().dio.get( '/hard/hard-api/ad/printer/bootstrap', options: dio.Options(headers: {'DEVICE-ID': hardId}), ); if (res.data == null) return null; if (res.data is! Map) throw const FormatException('打印机绑定配置格式错误'); return Map.from(res.data as Map); } /// 由当前业务终端把实际枚举到的 USB 打印机型号和 VID/PID 上报到绑定的 EY_PRINT 配置。 static Future> reportPrinterInfo({ required String hardId, required PrinterInfoReportRequest request, }) async { final res = await HttpManage().dio.post( '/hard/hard-api/ad/printer/info', data: request.toJson(), options: dio.Options(headers: {'DEVICE-ID': hardId}), ); if (res.data is! Map) throw const FormatException('打印机信息上报响应格式错误'); return Map.from(res.data as Map); } /// 拉取当前业务终端所绑定打印机的未完成任务,补偿 MQTT 离线窗口。 static Future> getPrinterTasks() async { final setting = await AppSettingTool.getSysSetting(); final hardId = setting.serviceId; if (hardId == null || hardId.isEmpty) return const []; final res = await HttpManage().dio.get( '/hard/hard-api/ad/printer/tasks', options: dio.Options( headers: {'DEVICE-ID': hardId}, extra: {HttpManage.silentRequestKey: true}, ), ); if (res.data is! List) return const []; return (res.data as List).whereType().map((item) { final json = Map.from(item); json['historyId'] ??= json['id']; return MqttInvoiceMsg.fromJson(json); }).toList(growable: false); } /// 由当前业务终端上报完整 USB 写入结果;请求失败由本地队列保留并在网络恢复后补报。 static Future reportPrinterResult({ required String taskId, required String orderId, required int retryVersion, required bool success, required int attemptCount, String? errorMessage, }) async { final setting = await AppSettingTool.getSysSetting(); final hardId = setting.serviceId; if (hardId == null || hardId.isEmpty) throw StateError('业务终端设备 ID 缺失'); final res = await HttpManage().dio.post( '/hard/hard-api/ad/printer/result', data: { 'taskId': int.parse(taskId), 'orderId': int.parse(orderId), 'retryVersion': retryVersion, 'success': success, 'attemptCount': attemptCount, if (errorMessage != null && errorMessage.isNotEmpty) 'errorMessage': errorMessage, }, options: dio.Options( headers: {'DEVICE-ID': hardId}, extra: {HttpManage.silentRequestKey: true}, ), ); return res.data == true; } /// 离线同步 static Future?> syncOfflineOrder(dynamic formData) async { final res = await HttpManage().dio.post( "/hard/hard-api/ad/sync-offline-order", data: formData, ); if (res.data == null) return null; return res.data?.map((e) => e.toString()).toList(); } /// 统计每天、每周、每月、每年的交易人数和次数 static Future chartLatitude( dynamic formData, ) async { final res = await HttpManage().dio.get( "/hard/hard-api/ad/chart-latitude", queryParameters: formData, ); if (res.data == null) return null; return ServiceChartLatitude.fromJson(res.data); } /// android查询今日的广播 static Future broadcastToday( dynamic formData, ) async { final res = await HttpManage().dio.get( "/hard/hard-broadcast/ad/today", queryParameters: formData, data: {"hardId": formData["hardId"]}, ); if (res.data == null) return null; return ServiceBroadcastTodayPage.fromJson(res.data); } /// android完成一轮广播 static Future broadcast( dynamic formData, ) async { final res = await HttpManage() .dio .post("/hard/hard-broadcast/ad/broadcast", data: formData); if (res.data == null) return null; return ServiceBroadcastTodayPage.fromJson(res.data); } /// 消费机限时退款 static Future timeLimitRefund( dynamic formData, ) async { final res = await HttpManage().dio.get( "/hard/hard-after-sale/ad/time-limit-refund", queryParameters: formData, ); if (res.data == null) return false; return true; } }