taro-bluetooth-print 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +73 -195
  2. package/README.md +134 -386
  3. package/dist/index.cjs.js +1 -1
  4. package/dist/index.es.js +1 -1
  5. package/dist/index.umd.js +1 -1
  6. package/dist/types/config/PrinterConfigManager.d.ts +206 -0
  7. package/dist/types/config/index.d.ts +8 -0
  8. package/dist/types/core/BluetoothPrinter.d.ts +1 -1
  9. package/dist/types/core/EventEmitter.d.ts +6 -26
  10. package/dist/types/core/index.d.ts +6 -0
  11. package/dist/types/device/MultiPrinterManager.d.ts +164 -0
  12. package/dist/types/device/index.d.ts +2 -0
  13. package/dist/types/drivers/CpclDriver.d.ts +304 -0
  14. package/dist/types/drivers/GPrinterDriver.d.ts +63 -0
  15. package/dist/types/drivers/ZplDriver.d.ts +325 -0
  16. package/dist/types/drivers/index.d.ts +9 -0
  17. package/dist/types/encoding/gbk-lite.d.ts +8 -0
  18. package/dist/types/encoding/gbk-table.d.ts +8 -30
  19. package/dist/types/index.d.ts +12 -8
  20. package/dist/types/services/BatchPrintManager.d.ts +205 -0
  21. package/dist/types/services/ConnectionManager.d.ts +1 -1
  22. package/dist/types/services/PrintHistory.d.ts +142 -0
  23. package/dist/types/services/PrintJobManager.d.ts +28 -4
  24. package/dist/types/services/PrinterStatus.d.ts +97 -0
  25. package/dist/types/services/index.d.ts +11 -0
  26. package/package.json +25 -7
  27. package/src/adapters/AlipayAdapter.ts +1 -0
  28. package/src/adapters/BaiduAdapter.ts +1 -0
  29. package/src/adapters/BaseAdapter.ts +6 -8
  30. package/src/adapters/ByteDanceAdapter.ts +1 -0
  31. package/src/adapters/TaroAdapter.ts +1 -0
  32. package/src/adapters/WebBluetoothAdapter.ts +1 -1
  33. package/src/config/PrinterConfigManager.ts +519 -0
  34. package/src/config/index.ts +15 -0
  35. package/src/core/BluetoothPrinter.ts +15 -15
  36. package/src/core/EventEmitter.ts +15 -15
  37. package/src/core/index.ts +7 -0
  38. package/src/device/MultiPrinterManager.ts +470 -0
  39. package/src/device/index.ts +8 -0
  40. package/src/drivers/CpclDriver.ts +549 -0
  41. package/src/drivers/GPrinterDriver.ts +115 -0
  42. package/src/drivers/TsplDriver.ts +9 -21
  43. package/src/drivers/ZplDriver.ts +543 -0
  44. package/src/drivers/index.ts +37 -0
  45. package/src/encoding/gbk-lite.ts +113 -0
  46. package/src/encoding/gbk-table.ts +80 -58
  47. package/src/index.ts +40 -35
  48. package/src/plugins/PluginManager.ts +3 -1
  49. package/src/plugins/builtin/LoggingPlugin.ts +4 -2
  50. package/src/plugins/builtin/RetryPlugin.ts +8 -14
  51. package/src/services/BatchPrintManager.ts +500 -0
  52. package/src/services/ConnectionManager.ts +25 -22
  53. package/src/services/PrintHistory.ts +336 -0
  54. package/src/services/PrintJobManager.ts +69 -9
  55. package/src/services/PrinterStatus.ts +267 -0
  56. package/src/services/index.ts +22 -0
  57. package/src/template/TemplateEngine.ts +4 -1
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Printer Status Service
3
+ *
4
+ * Queries printer status including paper, battery, and error states.
5
+ * Works with ESC/POS printers that support status commands.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const status = new PrinterStatus(printer);
10
+ * const paperStatus = await status.getPaperStatus();
11
+ * console.log('Paper:', paperStatus);
12
+ * ```
13
+ */
14
+
15
+ import { Logger } from '@/utils/logger';
16
+ import { BluetoothPrintError, ErrorCode } from '@/errors/BluetoothError';
17
+
18
+ /**
19
+ * Paper status
20
+ */
21
+ export enum PaperStatus {
22
+ /** Paper is present and OK */
23
+ OK = 'ok',
24
+ /** Paper is low */
25
+ LOW = 'low',
26
+ /** Paper is out */
27
+ OUT = 'out',
28
+ /** Paper status unknown */
29
+ UNKNOWN = 'unknown',
30
+ }
31
+
32
+ /**
33
+ * Printer status
34
+ */
35
+ export interface PrinterStatusInfo {
36
+ /** Paper status */
37
+ paper: PaperStatus;
38
+ /** Cover open (if supported) */
39
+ coverOpen?: boolean;
40
+ /** Cutter error (if supported) */
41
+ cutterError?: boolean;
42
+ /** Motor error (if supported) */
43
+ motorError?: boolean;
44
+ /** Temperature issue (if supported) */
45
+ overTemp?: boolean;
46
+ /** Battery level (0-100, if supported) */
47
+ batteryLevel?: number;
48
+ /** Timestamp of status check */
49
+ timestamp: number;
50
+ /** Raw status bytes */
51
+ rawStatus?: Uint8Array;
52
+ }
53
+
54
+ /**
55
+ * Status query options
56
+ */
57
+ export interface StatusQueryOptions {
58
+ /** Timeout for status query in ms */
59
+ timeout?: number;
60
+ /** Include raw status bytes */
61
+ includeRaw?: boolean;
62
+ }
63
+
64
+ /**
65
+ * ESC/POS Status Commands
66
+ */
67
+ const ESCPOS_STATUS_CMD = 0x10; // DLE
68
+ const ESCPOS_STATUS_NUL = 0x04; // ENQ
69
+
70
+ /**
71
+ * Status response bit masks for common printers
72
+ */
73
+ const STATUS_BIT_PAPER_OUT = 0x20; // Bit 5: Paper out
74
+ const STATUS_BIT_PAPER_LOW = 0x40; // Bit 6: Paper low
75
+
76
+ /**
77
+ * Printer Status Service
78
+ */
79
+ export class PrinterStatus {
80
+ private readonly logger = Logger.scope('PrinterStatus');
81
+
82
+ /**
83
+ * Creates a new PrinterStatus instance
84
+ */
85
+ constructor() {}
86
+
87
+ /**
88
+ * Get printer status
89
+ *
90
+ * Sends ESC/POS status query command and parses the response.
91
+ *
92
+ * @param writeFunc - Function to write data to printer
93
+ * @param readFunc - Function to read response from printer
94
+ * @param options - Query options
95
+ * @returns Printer status info
96
+ */
97
+ async getStatus(
98
+ writeFunc: (data: ArrayBuffer) => Promise<void>,
99
+ readFunc: () => Promise<ArrayBuffer>,
100
+ options: StatusQueryOptions = {}
101
+ ): Promise<PrinterStatusInfo> {
102
+ const { timeout = 3000, includeRaw = false } = options;
103
+
104
+ try {
105
+ // Send status query: DLE ENQ
106
+ const queryCmd = new Uint8Array([ESCPOS_STATUS_CMD, ESCPOS_STATUS_NUL]);
107
+ await writeFunc(queryCmd.buffer);
108
+
109
+ // Set up timeout promise
110
+ const timeoutPromise = new Promise<ArrayBuffer>((_, reject) => {
111
+ setTimeout(() => {
112
+ reject(new BluetoothPrintError(
113
+ ErrorCode.CONNECTION_TIMEOUT,
114
+ 'Status query timed out'
115
+ ));
116
+ }, timeout);
117
+ });
118
+
119
+ // Read response with timeout
120
+ const response = await Promise.race([
121
+ readFunc(),
122
+ timeoutPromise
123
+ ]);
124
+
125
+ return this.parseStatus(new Uint8Array(response), includeRaw);
126
+ } catch (error) {
127
+ this.logger.error('Failed to get printer status:', error);
128
+
129
+ // Return unknown status on error
130
+ return {
131
+ paper: PaperStatus.UNKNOWN,
132
+ timestamp: Date.now(),
133
+ ...(includeRaw && { rawStatus: new Uint8Array(0) }),
134
+ };
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Parse status bytes from printer
140
+ *
141
+ * Different printers return different status formats.
142
+ * This implementation handles common ESC/POS status responses.
143
+ */
144
+ private parseStatus(statusBytes: Uint8Array, includeRaw: boolean): PrinterStatusInfo {
145
+ const result: PrinterStatusInfo = {
146
+ paper: PaperStatus.UNKNOWN,
147
+ timestamp: Date.now(),
148
+ };
149
+
150
+ if (includeRaw && statusBytes.length > 0) {
151
+ result.rawStatus = statusBytes;
152
+ }
153
+
154
+ if (statusBytes.length === 0) {
155
+ this.logger.warn('Empty status response');
156
+ return result;
157
+ }
158
+
159
+ // First byte typically contains printer status
160
+ const status = statusBytes[0] ?? 0;
161
+
162
+ // Check paper status
163
+ if ((status & STATUS_BIT_PAPER_OUT) !== 0) {
164
+ result.paper = PaperStatus.OUT;
165
+ } else if ((status & STATUS_BIT_PAPER_LOW) !== 0) {
166
+ result.paper = PaperStatus.LOW;
167
+ } else {
168
+ result.paper = PaperStatus.OK;
169
+ }
170
+
171
+ // Check other status bits (printer-dependent)
172
+ // Bit 0: Drawer open/closed
173
+ // Bit 1: Offline
174
+ // Bit 2: Error
175
+ // Bit 3: Printer-specific status
176
+
177
+ if ((status & 0x01) !== 0) {
178
+ this.logger.debug('Drawer open detected');
179
+ }
180
+
181
+ if ((status & 0x02) !== 0) {
182
+ result.coverOpen = true;
183
+ this.logger.debug('Cover open detected');
184
+ }
185
+
186
+ if ((status & 0x04) !== 0) {
187
+ result.cutterError = true;
188
+ this.logger.debug('Cutter error detected');
189
+ }
190
+
191
+ if ((status & 0x10) !== 0) {
192
+ result.overTemp = true;
193
+ this.logger.debug('Over temperature detected');
194
+ }
195
+
196
+ // Second byte often contains paper sensor status
197
+ if (statusBytes.length >= 2) {
198
+ const paperSensor = statusBytes[1] ?? 0;
199
+
200
+ // Paper out sensor
201
+ if ((paperSensor & 0x04) !== 0) {
202
+ result.paper = PaperStatus.OUT;
203
+ } else if ((paperSensor & 0x08) !== 0) {
204
+ result.paper = PaperStatus.LOW;
205
+ }
206
+ }
207
+
208
+ this.logger.debug('Parsed status:', result);
209
+ return result;
210
+ }
211
+
212
+ /**
213
+ * Check if paper is available
214
+ */
215
+ async checkPaper(
216
+ writeFunc: (data: ArrayBuffer) => Promise<void>,
217
+ readFunc: () => Promise<ArrayBuffer>
218
+ ): Promise<PaperStatus> {
219
+ const status = await this.getStatus(writeFunc, readFunc);
220
+ return status.paper;
221
+ }
222
+
223
+ /**
224
+ * Check if printer is ready
225
+ */
226
+ async isReady(
227
+ writeFunc: (data: ArrayBuffer) => Promise<void>,
228
+ readFunc: () => Promise<ArrayBuffer>
229
+ ): Promise<boolean> {
230
+ try {
231
+ const status = await this.getStatus(writeFunc, readFunc);
232
+ return status.paper !== PaperStatus.OUT && !status.cutterError && !status.motorError;
233
+ } catch {
234
+ return false;
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Get human-readable status string
240
+ */
241
+ static toString(status: PrinterStatusInfo): string {
242
+ const parts: string[] = [];
243
+
244
+ parts.push(`Paper: ${status.paper}`);
245
+
246
+ if (status.coverOpen) {
247
+ parts.push('Cover Open');
248
+ }
249
+ if (status.cutterError) {
250
+ parts.push('Cutter Error');
251
+ }
252
+ if (status.motorError) {
253
+ parts.push('Motor Error');
254
+ }
255
+ if (status.overTemp) {
256
+ parts.push('Over Temperature');
257
+ }
258
+ if (status.batteryLevel !== undefined) {
259
+ parts.push(`Battery: ${status.batteryLevel}%`);
260
+ }
261
+
262
+ return parts.join(', ');
263
+ }
264
+ }
265
+
266
+ // Export singleton
267
+ export const printerStatus = new PrinterStatus();
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Services Module
3
+ * 服务模块 - 提供连接管理、命令构建、任务管理等功能
4
+ */
5
+
6
+ export {
7
+ ConnectionManager,
8
+ type ConnectionManagerConfig,
9
+ type ConnectionManagerEvents,
10
+ } from './ConnectionManager';
11
+
12
+ export { CommandBuilder } from './CommandBuilder';
13
+
14
+ export { PrintJobManager } from './PrintJobManager';
15
+
16
+ export { PrintHistory, printHistory, type PrintHistoryEntry, type PrintHistoryStats, type HistoryQueryOptions } from './PrintHistory';
17
+
18
+ export { PrinterStatus, printerStatus, type PrinterStatusInfo, type StatusQueryOptions, type PaperStatus } from './PrinterStatus';
19
+
20
+ export { BatchPrintManager, batchPrintManager, type BatchJob, type BatchConfig, type BatchStats, type BatchEvents } from './BatchPrintManager';
21
+
22
+ export * from './interfaces';
@@ -510,7 +510,10 @@ export class TemplateEngine implements ITemplateEngine {
510
510
  private substituteVariables(template: string, data: Record<string, unknown>): string {
511
511
  return template.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (_, key: string) => {
512
512
  const value = this.getNestedValue(data, key);
513
- return value !== undefined ? String(value) : '';
513
+ if (value === undefined) return '';
514
+ if (typeof value === 'object') return JSON.stringify(value);
515
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
516
+ return String(value);
514
517
  });
515
518
  }
516
519