/** * Android NativeTemplateCommandBuilder 仅处理:TEXT_*、QRCODE、BARCODE、IMAGE、 * 以及 border=line 的 BLANK;其余类型在原生路径下会被静默跳过(与画布预览不一致)。 */ import type { LabelTemplateData, SystemLabelTemplate, SystemTemplateElementBase, } from './types/printer' import { applyTemplateData } from './templateRenderer' function isElementHandledByNativeFastPrinter (el: SystemTemplateElementBase): boolean { const type = String(el.type || '').toUpperCase() if (type.startsWith('TEXT_')) return true if (type === 'NUTRITION') return true if (type === 'QRCODE' || type === 'IMAGE') return true if (type === 'BARCODE') return true if (type === 'BLANK') return true return false } /** * 将 WEIGHT / DATE / TIME / DURATION 转为 TEXT_STATIC(展示文案与合并后的 config.text 一致), * LOGO → IMAGE,使同一套模板可走 native printTemplate,避免仅因元素类型名而整页光栅(进度长期停在 ~12–14%)。 */ export function normalizeTemplateForNativeFastJob ( template: SystemLabelTemplate, data: LabelTemplateData ): SystemLabelTemplate { const now = new Date() const pad2 = (n: number): string => String(n).padStart(2, '0') const formatDateByPreset = (fmt: string, d: Date): string => { const yyyy = String(d.getFullYear()) const yy = yyyy.slice(-2) const mm = pad2(d.getMonth() + 1) const dd = pad2(d.getDate()) const hh = pad2(d.getHours()) const min = pad2(d.getMinutes()) switch (fmt) { case 'DD/MM/YYYY': return `${dd}/${mm}/${yyyy}` case 'MM/DD/YYYY': return `${mm}/${dd}/${yyyy}` case 'DD/MM/YY': return `${dd}/${mm}/${yy}` case 'MM/DD/YY': return `${mm}/${dd}/${yy}` case 'MM/YY': return `${mm}/${yy}` case 'MM/DD': return `${mm}/${dd}` case 'MM': return mm case 'DD': return dd case 'YY': return yy case 'YYYY-MM-DD': return `${yyyy}-${mm}-${dd}` case 'YYYY-MM-DD HH:mm': return `${yyyy}-${mm}-${dd} ${hh}:${min}` case 'HH:mm': return `${hh}:${min}` default: return String(fmt || '') .replace('YYYY', yyyy) .replace('YY', yy) .replace('MM', mm) .replace('DD', dd) .replace('HH', hh) .replace('mm', min) } } const elements = (template.elements || []).map((el) => { const type = String(el.type || '').toUpperCase() const config = (el.config || {}) as Record if (type === 'LOGO') { return { ...el, type: 'IMAGE' as typeof el.type } } if (type === 'WEIGHT' || type === 'DATE' || type === 'TIME' || type === 'DURATION') { let text = '' /** 与 renderLabelPreviewCanvas.previewTextForElement 一致:后端 AUTO_DB 的 DATE/TIME 常把算好的展示串写在 format 而非 text */ let raw = String(config.text ?? config.Text ?? '').trim() const vst = String(el.valueSourceType || '').toUpperCase() const inputType = String(config.inputType ?? config.InputType ?? '').toLowerCase() if (type === 'DATE') { if (raw) { text = applyTemplateData(raw, data) } else if (vst === 'PRINT_INPUT' && (inputType === 'date' || inputType === 'datetime')) { const fmt = String(config.format ?? config.Format ?? (inputType === 'datetime' ? 'YYYY-MM-DD HH:mm' : 'DD/MM/YYYY')).trim() text = fmt } else { const fmt = String(config.format ?? config.Format ?? 'DD/MM/YYYY').trim() || 'DD/MM/YYYY' const offset = Number(config.offsetDays ?? config.OffsetDays ?? 0) || 0 const d = new Date(now.getTime()) d.setDate(d.getDate() + offset) text = formatDateByPreset(fmt, d) } } else if (type === 'TIME') { if (raw) { text = applyTemplateData(raw, data) } else if (vst === 'PRINT_INPUT') { text = String(config.format ?? config.Format ?? 'HH:mm').trim() || 'HH:mm' } else { text = formatDateByPreset('HH:mm', now) } } else if (type === 'DURATION') { if (raw) { text = applyTemplateData(raw, data) } else { const unit = String(config.format ?? config.Format ?? 'Days').trim() || 'Days' const rawV = config.durationValue ?? config.value ?? config.offsetDays ?? config.DurationValue ?? config.Value ?? config.OffsetDays const val = Number.isFinite(Number(rawV)) ? Number(rawV) : 0 text = `${val} ${unit}`.trim() } } else if (type === 'WEIGHT') { if (!raw) raw = String(config.value ?? config.Value ?? '').trim() if (raw) text = applyTemplateData(raw, data) } if (!text && type === 'WEIGHT') { const v = String(config.value ?? config.Value ?? '') const u = String(config.unit ?? config.Unit ?? '') if (v && u && !v.endsWith(u)) text = `${v}${u}` else text = v || u } return { ...el, type: 'TEXT_STATIC' as typeof el.type, config: { ...config, text, nativeSourceType: type }, } } return el }) return { ...template, elements } } /** 存在任一原生不支持的元素时,预览打印应走光栅,避免「成功但缺内容/不出纸」与画布不一致 */ export function templateHasUnsupportedNativeFastElements (template: SystemLabelTemplate): boolean { for (const el of template.elements || []) { if (!isElementHandledByNativeFastPrinter(el)) return true } return false }