import type { LabelTemplateData, SystemLabelTemplate } from './types/printer' type NativePrinterResult = { code?: number msg?: string errMsg?: string connected?: boolean deviceId?: string deviceName?: string success?: boolean backend?: string pluginVersion?: string stage?: string lastError?: string buildMs?: number writeMs?: number commandBytes?: number lastPrintAt?: number nativeTextCount?: number rasterTextCount?: number qrCodeCount?: number barcodeCount?: number imagePatchCount?: number lineCount?: number elementCount?: number available?: boolean lastAction?: string } const nativeFastPrinterState: NativePrinterResult = { available: false, lastAction: 'idle', } function getUniApi (): any { return uni as any } function parsePluginResult (payload: any): NativePrinterResult { if (!payload) return {} if (typeof payload === 'string') { try { return JSON.parse(payload) } catch (_) { return { msg: payload } } } return payload as NativePrinterResult } function updateNativeState (patch: NativePrinterResult) { Object.assign(nativeFastPrinterState, patch, { available: isNativeFastPrinterAvailable(), }) } function getNativePlugin (): any | null { // #ifdef APP-PLUS try { const api = getUniApi() if (typeof api.requireNativePlugin !== 'function') return null const plugin = api.requireNativePlugin('native-fast-printer') return plugin || null } catch (_) { return null } // #endif // #ifndef APP-PLUS return null // #endif } function ensureNativePlugin (): any { const plugin = getNativePlugin() if (!plugin) { updateNativeState({ available: false, lastAction: 'plugin:missing', lastError: 'NATIVE_FAST_PRINTER_PLUGIN_NOT_FOUND', }) throw new Error('NATIVE_FAST_PRINTER_PLUGIN_NOT_FOUND') } return plugin } export function isNativeFastPrinterAvailable (): boolean { const plugin = getNativePlugin() return !!plugin && typeof plugin.connect === 'function' && typeof plugin.printTemplate === 'function' } export function getNativeFastPrinterState (): NativePrinterResult | null { return { ...nativeFastPrinterState, available: isNativeFastPrinterAvailable(), } } function buildTimeoutError (action: string, timeoutMs: number): Error { const snapshot = getNativeFastPrinterState() const detail = [ `action=${action}`, `timeout=${Math.round(timeoutMs / 1000)}s`, snapshot?.backend ? `backend=${snapshot.backend}` : '', snapshot?.stage ? `stage=${snapshot.stage}` : '', snapshot?.commandBytes ? `commandBytes=${snapshot.commandBytes}` : '', snapshot?.lastError ? `lastError=${snapshot.lastError}` : '', ].filter(Boolean).join('\n') return new Error(`Native printer timeout.\n${detail}`.trim()) } function wrapCallback ( action: string, timeoutMs: number, executor: (resolve: (value: NativePrinterResult) => void, reject: (reason?: any) => void) => void ) { return new Promise((resolve, reject) => { let settled = false const timer = setTimeout(() => { if (settled) return settled = true updateNativeState({ lastAction: `${action}:timeout`, }) reject(buildTimeoutError(action, timeoutMs)) }, timeoutMs) const done = (handler: () => void) => { if (settled) return settled = true clearTimeout(timer) handler() } executor( (value) => done(() => resolve(value)), (reason) => done(() => reject(reason)), ) }) } export function getNativeFastPrinterDebugInfo () { return wrapCallback('getDebugInfo', 5000, (resolve, reject) => { try { const nativePlugin = ensureNativePlugin() if (typeof nativePlugin.getDebugInfo !== 'function') { const snapshot = getNativeFastPrinterState() resolve(snapshot || {}) return } nativePlugin.getDebugInfo((payload: any) => { const res = parsePluginResult(payload) updateNativeState({ ...res, lastAction: 'getDebugInfo', }) resolve(res) }) } catch (error: any) { reject(error instanceof Error ? error : new Error(String(error || 'NATIVE_FAST_PRINTER_DEBUG_FAILED'))) } }) } export function connectNativeFastPrinter (options: { deviceId: string deviceName?: string }) { return wrapCallback('connect', 12000, (resolve, reject) => { try { const nativePlugin = ensureNativePlugin() if (typeof nativePlugin.connect !== 'function') { reject(new Error('NATIVE_FAST_PRINTER_CONNECT_METHOD_NOT_FOUND')) return } nativePlugin.connect({ deviceId: options.deviceId, deviceName: options.deviceName || '', }, (payload: any) => { const res = parsePluginResult(payload) updateNativeState({ ...res, lastAction: 'connect', }) if (res.code === 1 || res.success === true) { resolve(res) return } reject(new Error(res.msg || res.errMsg || 'NATIVE_FAST_PRINTER_CONNECT_FAILED')) }) } catch (error: any) { reject(error instanceof Error ? error : new Error(String(error || 'NATIVE_FAST_PRINTER_CONNECT_FAILED'))) } }) } export function disconnectNativeFastPrinter () { return wrapCallback('disconnect', 8000, (resolve, reject) => { try { const nativePlugin = ensureNativePlugin() if (typeof nativePlugin.disconnect !== 'function') { reject(new Error('NATIVE_FAST_PRINTER_DISCONNECT_METHOD_NOT_FOUND')) return } nativePlugin.disconnect((payload: any) => { const res = parsePluginResult(payload) updateNativeState({ ...res, lastAction: 'disconnect', }) if (res.code === 1 || res.success === true) { resolve(res) return } reject(new Error(res.msg || res.errMsg || 'NATIVE_FAST_PRINTER_DISCONNECT_FAILED')) }) } catch (error: any) { reject(error instanceof Error ? error : new Error(String(error || 'NATIVE_FAST_PRINTER_DISCONNECT_FAILED'))) } }) } export function printNativeFastTemplate (options: { deviceId: string deviceName?: string template: SystemLabelTemplate data?: LabelTemplateData dpi?: number printQty?: number }) { return wrapCallback('printTemplate', 20000, (resolve, reject) => { try { const nativePlugin = ensureNativePlugin() if (typeof nativePlugin.printTemplate !== 'function') { reject(new Error('NATIVE_FAST_PRINTER_PRINT_METHOD_NOT_FOUND')) return } nativePlugin.printTemplate({ deviceId: options.deviceId, deviceName: options.deviceName || '', templateJson: JSON.stringify(options.template), dataJson: JSON.stringify(options.data || {}), dpi: options.dpi || 203, printQty: options.printQty || 1, }, (raw: any) => { const res = parsePluginResult(raw) updateNativeState({ ...res, lastAction: 'printTemplate', }) if (res.code === 1 || res.success === true) { resolve(res) return } reject(new Error(res.msg || res.errMsg || 'NATIVE_FAST_PRINTER_PRINT_FAILED')) }) } catch (error: any) { reject(error instanceof Error ? error : new Error(String(error || 'NATIVE_FAST_PRINTER_PRINT_FAILED'))) } }) }