From 0714fb8a1b6b0eabfea597f044e3319fc7f2937f Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Sat, 13 Jun 2026 20:42:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(client):=20=E6=A0=87=E7=AD=BE=20TSPL=20?= =?UTF-8?q?=E8=A3=B8=E5=8F=91=E6=94=AF=E6=8C=81=20Windows=EF=BC=88winspool?= =?UTF-8?q?=20WritePrinter=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 抽出 _findThermalPrinter(macOS: lpstat -e;Windows: Printing.listPrinters) 与 _sendRaw(macOS/Linux: lp -o raw;Windows: winspool WritePrinter RAW) - 新增 _winRawPrint:OpenPrinter/StartDocPrinter(RAW)/WritePrinter 直送裸字节 - 位图渲染与 TSPL 生成跨平台复用;macOS 行为不变 - 依赖新增 win32/ffi(仅 Windows 运行时调用,已 Platform.isWindows 守卫) Co-Authored-By: Claude Opus 4.8 --- client/lib/core/utils/print_util_stub.dart | 138 ++++++++++--- client/pubspec.lock | 222 ++++++++++----------- client/pubspec.yaml | 3 + 3 files changed, 225 insertions(+), 138 deletions(-) diff --git a/client/lib/core/utils/print_util_stub.dart b/client/lib/core/utils/print_util_stub.dart index 9d4573c..9e1f03c 100644 --- a/client/lib/core/utils/print_util_stub.dart +++ b/client/lib/core/utils/print_util_stub.dart @@ -2,6 +2,18 @@ import 'dart:io' show Platform, Process, File, Directory; import 'dart:convert' show ascii; import 'dart:typed_data'; import 'dart:ui' as ui; +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; +import 'package:win32/win32.dart' + show + OpenPrinter, + StartDocPrinter, + StartPagePrinter, + WritePrinter, + EndPagePrinter, + EndDocPrinter, + ClosePrinter, + DOC_INFO_1; import 'package:flutter/foundation.dart' show kIsWeb, debugPrint; import 'package:flutter/services.dart'; import '../errors/error_reporter.dart'; @@ -39,26 +51,105 @@ const _ink = PdfColor(0.067, 0.067, 0.067); // #111 body text // 得力 DL-888B 等热敏机走系统打印(CUPS 通用驱动)会多走纸/空白,必须发原生 TSPL。 // 直接画位图而非走 PDF 光栅化:避免二维码渲染丢失、SIZE 用整数避免多走纸。 -/// 查找热敏标签机的 CUPS 队列名(名字含 DL-888 / 888B / Deli) -Future _findThermalQueue() async { - try { - final r = await Process.run('lpstat', ['-e']); - if (r.exitCode != 0) return null; - for (final raw in (r.stdout as String).split('\n')) { - final q = raw.trim(); - if (q.isEmpty) continue; - final lo = q.toLowerCase(); - if (lo.contains('dl-888') || lo.contains('dl_888') || - lo.contains('888b') || lo.contains('deli')) { - return q; +bool _isThermalName(String n) { + final lo = n.toLowerCase(); + return lo.contains('dl-888') || + lo.contains('dl_888') || + lo.contains('888b') || + lo.contains('deli'); +} + +/// 查找热敏标签机(名字含 DL-888 / 888B / Deli)。 +/// macOS: CUPS 队列名(lpstat -e);Windows: 打印机名(Printing.listPrinters)。 +Future _findThermalPrinter() async { + if (Platform.isMacOS) { + try { + final r = await Process.run('lpstat', ['-e']); + if (r.exitCode == 0) { + for (final raw in (r.stdout as String).split('\n')) { + final q = raw.trim(); + if (q.isNotEmpty && _isThermalName(q)) return q; + } } + } catch (e) { + debugPrint('[label] lpstat 失败: $e'); } - } catch (e) { - debugPrint('[label] lpstat 失败: $e'); + return null; + } + if (Platform.isWindows) { + try { + for (final p in await Printing.listPrinters()) { + if (_isThermalName(p.name)) return p.name; + } + } catch (e) { + debugPrint('[label] listPrinters 失败: $e'); + } + return null; } return null; } +/// 把裸 TSPL 字节发送到打印机: +/// macOS/Linux 用 `lp -o raw`;Windows 用 winspool WritePrinter。失败抛异常。 +Future _sendRaw(String printer, Uint8List tspl) async { + if (Platform.isWindows) { + if (!_winRawPrint(printer, tspl)) { + throw Exception('Windows 裸发失败: $printer'); + } + return; + } + final f = File( + '${Directory.systemTemp.path}/label_${DateTime.now().millisecondsSinceEpoch}.tspl'); + await f.writeAsBytes(tspl, flush: true); + final r = await Process.run('lp', ['-d', printer, '-o', 'raw', f.path]); + debugPrint('[label] lp exit=${r.exitCode} out=${r.stdout} err=${r.stderr}'); + if (r.exitCode != 0) { + throw Exception('lp 裸发失败(exit ${r.exitCode}): ${r.stderr}'); + } +} + +/// Windows: 通过 winspool 以 RAW 数据类型把字节直接送进打印队列 +bool _winRawPrint(String printerName, Uint8List data) { + final pName = printerName.toNativeUtf16(); + final phPrinter = calloc(); + final docName = 'jiu label'.toNativeUtf16(); + final dataType = 'RAW'.toNativeUtf16(); + final docInfo = calloc(); + final pcWritten = calloc(); + final pData = calloc(data.length); + try { + if (OpenPrinter(pName, phPrinter, nullptr) == 0) { + debugPrint('[label] OpenPrinter 失败: $printerName'); + return false; + } + final h = phPrinter.value; + docInfo.ref + ..pDocName = docName + ..pOutputFile = nullptr + ..pDatatype = dataType; + if (StartDocPrinter(h, 1, docInfo) == 0) { + ClosePrinter(h); + return false; + } + StartPagePrinter(h); + pData.asTypedList(data.length).setAll(0, data); + final ok = WritePrinter(h, pData.cast(), data.length, pcWritten); + EndPagePrinter(h); + EndDocPrinter(h); + ClosePrinter(h); + debugPrint('[label] WritePrinter ok=$ok written=${pcWritten.value}'); + return ok != 0; + } finally { + calloc.free(pName); + calloc.free(phPrinter); + calloc.free(docName); + calloc.free(dataType); + calloc.free(docInfo); + calloc.free(pcWritten); + calloc.free(pData); + } +} + /// 在 canvas 上画一行文字(黑色,单行不换行,CJK 走系统字体回退) void _drawText(ui.Canvas canvas, String s, double x, double y, double size, double maxW, {bool bold = false, bool center = false}) { @@ -107,10 +198,10 @@ Future _printFlatLabelThermal({ required String date, required Uint8List qrBytes, }) async { - if (kIsWeb || !Platform.isMacOS) return false; // 目前仅 macOS(Windows 待加) - final queue = await _findThermalQueue(); - debugPrint('[label] thermal queue = $queue'); - if (queue == null) return false; + if (kIsWeb || !(Platform.isMacOS || Platform.isWindows)) return false; + final printer = await _findThermalPrinter(); + debugPrint('[label] thermal printer = $printer'); + if (printer == null) return false; const w = 320, h = 160; // 40×20mm @203dpi final recorder = ui.PictureRecorder(); @@ -182,15 +273,8 @@ Future _printFlatLabelThermal({ out.add(ascii.encode('\r\nPRINT 1,1\r\n')); final tspl = out.toBytes(); - final f = File( - '${Directory.systemTemp.path}/label_${DateTime.now().millisecondsSinceEpoch}.tspl'); - await f.writeAsBytes(tspl, flush: true); - debugPrint('[label] flat tspl ${tspl.length}B -> lp -d $queue -o raw ${f.path}'); - final r = await Process.run('lp', ['-d', queue, '-o', 'raw', f.path]); - debugPrint('[label] lp exit=${r.exitCode} out=${r.stdout} err=${r.stderr}'); - if (r.exitCode != 0) { - throw Exception('lp 裸发失败(exit ${r.exitCode}): ${r.stderr}'); - } + debugPrint('[label] flat tspl ${tspl.length}B -> $printer'); + await _sendRaw(printer, tspl); return true; } diff --git a/client/pubspec.lock b/client/pubspec.lock index eabe1c6..d050c45 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: archive sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.6.1" args: @@ -14,7 +14,7 @@ packages: description: name: args sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.7.0" async: @@ -22,7 +22,7 @@ packages: description: name: async sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.13.1" barcode: @@ -30,7 +30,7 @@ packages: description: name: barcode sha256: "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.9" bidi: @@ -38,7 +38,7 @@ packages: description: name: bidi sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.13" boolean_selector: @@ -46,7 +46,7 @@ packages: description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" characters: @@ -54,7 +54,7 @@ packages: description: name: characters sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.1" clock: @@ -62,7 +62,7 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" code_assets: @@ -70,7 +70,7 @@ packages: description: name: code_assets sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.1" collection: @@ -78,7 +78,7 @@ packages: description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.19.1" cross_file: @@ -86,7 +86,7 @@ packages: description: name: cross_file sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.3.5+2" crypto: @@ -94,7 +94,7 @@ packages: description: name: crypto sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.7" dio: @@ -102,7 +102,7 @@ packages: description: name: dio sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.9.2" dio_web_adapter: @@ -110,7 +110,7 @@ packages: description: name: dio_web_adapter sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" equatable: @@ -118,7 +118,7 @@ packages: description: name: equatable sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.8" excel: @@ -126,7 +126,7 @@ packages: description: name: excel sha256: "1a15327dcad260d5db21d1f6e04f04838109b39a2f6a84ea486ceda36e468780" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.6" fake_async: @@ -134,15 +134,15 @@ packages: description: name: fake_async sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.3" ffi: - dependency: transitive + dependency: "direct main" description: name: ffi sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" file: @@ -150,7 +150,7 @@ packages: description: name: file sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.1" file_picker: @@ -158,7 +158,7 @@ packages: description: name: file_picker sha256: ab13ae8ef5580a411c458d6207b6774a6c237d77ac37011b13994879f68a8810 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.3.7" file_selector_linux: @@ -166,7 +166,7 @@ packages: description: name: file_selector_linux sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.4" file_selector_macos: @@ -174,7 +174,7 @@ packages: description: name: file_selector_macos sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.5" file_selector_platform_interface: @@ -182,7 +182,7 @@ packages: description: name: file_selector_platform_interface sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.7.0" file_selector_windows: @@ -190,7 +190,7 @@ packages: description: name: file_selector_windows sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.9.3+5" flutter: @@ -203,7 +203,7 @@ packages: description: name: flutter_lints sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.0" flutter_localizations: @@ -216,7 +216,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.35" flutter_riverpod: @@ -224,7 +224,7 @@ packages: description: name: flutter_riverpod sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.6.1" flutter_test: @@ -242,7 +242,7 @@ packages: description: name: go_router sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "14.8.1" hooks: @@ -250,7 +250,7 @@ packages: description: name: hooks sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.2" http: @@ -258,7 +258,7 @@ packages: description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.6.0" http_mock_adapter: @@ -266,7 +266,7 @@ packages: description: name: http_mock_adapter sha256: "46399c78bd4a0af071978edd8c502d7aeeed73b5fb9860bca86b5ed647a63c1b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.1" http_parser: @@ -274,7 +274,7 @@ packages: description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.2" image: @@ -282,7 +282,7 @@ packages: description: name: image sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.3.0" image_picker: @@ -290,7 +290,7 @@ packages: description: name: image_picker sha256: "91c025426c2881c551100bce834e201c835a170151545f58d17da5180ca7d9ac" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.2" image_picker_android: @@ -298,7 +298,7 @@ packages: description: name: image_picker_android sha256: "6f3a1995eafb000333174fae92202622033b0ee7fd917a6cd3730295264df84a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.13+19" image_picker_for_web: @@ -306,7 +306,7 @@ packages: description: name: image_picker_for_web sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.1" image_picker_ios: @@ -314,7 +314,7 @@ packages: description: name: image_picker_ios sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.8.13+6" image_picker_linux: @@ -322,7 +322,7 @@ packages: description: name: image_picker_linux sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2" image_picker_macos: @@ -330,7 +330,7 @@ packages: description: name: image_picker_macos sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2+1" image_picker_platform_interface: @@ -338,7 +338,7 @@ packages: description: name: image_picker_platform_interface sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.11.1" image_picker_windows: @@ -346,7 +346,7 @@ packages: description: name: image_picker_windows sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.2.2" intl: @@ -354,7 +354,7 @@ packages: description: name: intl sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.20.2" jni: @@ -362,7 +362,7 @@ packages: description: name: jni sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" jni_flutter: @@ -370,7 +370,7 @@ packages: description: name: jni_flutter sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" leak_tracker: @@ -378,7 +378,7 @@ packages: description: name: leak_tracker sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "11.0.2" leak_tracker_flutter_testing: @@ -386,7 +386,7 @@ packages: description: name: leak_tracker_flutter_testing sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.10" leak_tracker_testing: @@ -394,7 +394,7 @@ packages: description: name: leak_tracker_testing sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.2" lints: @@ -402,7 +402,7 @@ packages: description: name: lints sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.0" logger: @@ -410,7 +410,7 @@ packages: description: name: logger sha256: "25aee487596a6257655a1e091ec2ae66bc30e7af663592cc3a27e6591e05035c" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.7.0" logging: @@ -418,7 +418,7 @@ packages: description: name: logging sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" lpinyin: @@ -426,7 +426,7 @@ packages: description: name: lpinyin sha256: "0bb843363f1f65170efd09fbdfc760c7ec34fc6354f9fcb2f89e74866a0d814a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.3" matcher: @@ -434,7 +434,7 @@ packages: description: name: matcher sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.19" material_color_utilities: @@ -442,7 +442,7 @@ packages: description: name: material_color_utilities sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.13.0" meta: @@ -450,7 +450,7 @@ packages: description: name: meta sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.18.0" mime: @@ -458,7 +458,7 @@ packages: description: name: mime sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" objective_c: @@ -466,7 +466,7 @@ packages: description: name: objective_c sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "9.4.1" package_config: @@ -474,7 +474,7 @@ packages: description: name: package_config sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" package_info_plus: @@ -482,7 +482,7 @@ packages: description: name: package_info_plus sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.3.1" package_info_plus_platform_interface: @@ -490,7 +490,7 @@ packages: description: name: package_info_plus_platform_interface sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" path: @@ -498,7 +498,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.9.1" path_parsing: @@ -506,7 +506,7 @@ packages: description: name: path_parsing sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" path_provider: @@ -514,7 +514,7 @@ packages: description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.5" path_provider_android: @@ -522,7 +522,7 @@ packages: description: name: path_provider_android sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.1" path_provider_foundation: @@ -530,7 +530,7 @@ packages: description: name: path_provider_foundation sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.6.0" path_provider_linux: @@ -538,7 +538,7 @@ packages: description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -546,7 +546,7 @@ packages: description: name: path_provider_platform_interface sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" path_provider_windows: @@ -554,7 +554,7 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" pdf: @@ -562,7 +562,7 @@ packages: description: name: pdf sha256: e47a275b267873d5944ad5f5ff0dcc7ac2e36c02b3046a0ffac9b72fd362c44b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.12.0" pdf_widget_wrapper: @@ -570,7 +570,7 @@ packages: description: name: pdf_widget_wrapper sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" petitparser: @@ -578,7 +578,7 @@ packages: description: name: petitparser sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.2" platform: @@ -586,7 +586,7 @@ packages: description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.6" plugin_platform_interface: @@ -594,7 +594,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.8" printing: @@ -602,7 +602,7 @@ packages: description: name: printing sha256: "689170c9ddb1bda85826466ba80378aa8993486d3c959a71cd7d2d80cb606692" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.14.3" pub_semver: @@ -610,7 +610,7 @@ packages: description: name: pub_semver sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" qr: @@ -618,7 +618,7 @@ packages: description: name: qr sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.2" record_use: @@ -626,7 +626,7 @@ packages: description: name: record_use sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.0" riverpod: @@ -634,7 +634,7 @@ packages: description: name: riverpod sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.6.1" shared_preferences: @@ -642,23 +642,23 @@ packages: description: name: shared_preferences sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: a2c49fc1fed7140cadd892d765bd47edbe4ac0b9c7e7e3c493dcb58126f99cf0 - url: "https://pub.dev" + sha256: "93ae5884a9df5d3bb696825bceb3a17590754548b5d740eba51500afc8d088f5" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.25" + version: "2.4.26" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.5.6" shared_preferences_linux: @@ -666,7 +666,7 @@ packages: description: name: shared_preferences_linux sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" shared_preferences_platform_interface: @@ -674,7 +674,7 @@ packages: description: name: shared_preferences_platform_interface sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.2" shared_preferences_web: @@ -682,7 +682,7 @@ packages: description: name: shared_preferences_web sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.3" shared_preferences_windows: @@ -690,7 +690,7 @@ packages: description: name: shared_preferences_windows sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" sky_engine: @@ -703,7 +703,7 @@ packages: description: name: source_span sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.10.2" stack_trace: @@ -711,7 +711,7 @@ packages: description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.12.1" state_notifier: @@ -719,7 +719,7 @@ packages: description: name: state_notifier sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" stream_channel: @@ -727,7 +727,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" string_scanner: @@ -735,7 +735,7 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.1" term_glyph: @@ -743,7 +743,7 @@ packages: description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.2" test_api: @@ -751,7 +751,7 @@ packages: description: name: test_api sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.7.11" typed_data: @@ -759,7 +759,7 @@ packages: description: name: typed_data sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" url_launcher: @@ -767,7 +767,7 @@ packages: description: name: url_launcher sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.3.2" url_launcher_android: @@ -775,7 +775,7 @@ packages: description: name: url_launcher_android sha256: b413d49b73867ac08dd2f9890efd3cc11f2a0e577618d50843440a1fb3776c32 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.3.32" url_launcher_ios: @@ -783,7 +783,7 @@ packages: description: name: url_launcher_ios sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.4.1" url_launcher_linux: @@ -791,7 +791,7 @@ packages: description: name: url_launcher_linux sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.2" url_launcher_macos: @@ -799,7 +799,7 @@ packages: description: name: url_launcher_macos sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.5" url_launcher_platform_interface: @@ -807,7 +807,7 @@ packages: description: name: url_launcher_platform_interface sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.2" url_launcher_web: @@ -815,7 +815,7 @@ packages: description: name: url_launcher_web sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.3" url_launcher_windows: @@ -823,7 +823,7 @@ packages: description: name: url_launcher_windows sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.5" vector_math: @@ -831,7 +831,7 @@ packages: description: name: vector_math sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" vm_service: @@ -839,7 +839,7 @@ packages: description: name: vm_service sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "15.2.0" web: @@ -847,15 +847,15 @@ packages: description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" win32: - dependency: transitive + dependency: "direct main" description: name: win32 sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.15.0" xdg_directories: @@ -863,7 +863,7 @@ packages: description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" xml: @@ -871,7 +871,7 @@ packages: description: name: xml sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.6.1" yaml: @@ -879,7 +879,7 @@ packages: description: name: yaml sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.3" sdks: diff --git a/client/pubspec.yaml b/client/pubspec.yaml index 5bc9745..5d5f5a6 100644 --- a/client/pubspec.yaml +++ b/client/pubspec.yaml @@ -26,6 +26,9 @@ dependencies: pdf: ^3.10.8 web: ^1.1.0 image_picker: ^1.2.2 + # Windows 热敏机 TSPL 裸发(winspool WritePrinter),仅 Windows 运行时调用 + win32: ^5.5.0 + ffi: ^2.1.3 dev_dependencies: flutter_test: