Skip to content

TemplateEngine API

模板引擎,提供模板解析和渲染功能,支持变量替换、条件渲染、循环渲染、边框绘制和表格绘制。

导入

typescript
import { TemplateEngine, templateEngine, TemplateType } from 'taro-bluetooth-print';

// 或单独导入类型
import type {
  ReceiptData,
  LabelData,
  TemplateDefinition,
  TemplateElement,
  ValidationResult,
} from 'taro-bluetooth-print';

创建实例

推荐方式:使用单例

typescript
import { templateEngine } from 'taro-bluetooth-print';

// 直接使用单例实例
const commands = templateEngine.renderReceipt(receiptData);

手动实例化

typescript
import { TemplateEngine } from 'taro-bluetooth-print';

// 指定纸宽(默认 48 字符)
const engine = new TemplateEngine(58);

方法

模板渲染

renderReceipt(data: ReceiptData): Uint8Array

渲染小票模板,返回 ESC/POS 字节命令。

typescript
const commands = templateEngine.renderReceipt({
  store: {
    name: '我的商店',
    address: '北京市朝阳区xxx路',
    phone: '010-12345678'
  },
  order: {
    id: 'ORDER20240101001',
    date: '2024-01-01 10:30:00',
    cashier: '张三'
  },
  items: [
    { name: '商品A', quantity: 2, price: 10.00 },
    { name: '商品B', quantity: 1, price: 25.00, discount: 5.00 }
  ],
  payment: {
    subtotal: 45.00,
    discount: 5.00,
    total: 40.00,
    method: '微信支付',
    received: 50.00,
    change: 10.00
  },
  qrCode: 'https://example.com/order/123',
  footer: '如有问题请联系我店'
});

renderLabel(data: LabelData): Uint8Array

渲染标签模板,适用于商品标签、价格标签等。

typescript
const commands = templateEngine.renderLabel({
  name: '农夫山泉',
  price: 2.50,
  spec: '550ml',
  barcode: '6920236372283',
  barcodeFormat: 'EAN13',
  productionDate: '2024-01-01',
  expiryDate: '2025-01-01'
});

render(template: TemplateDefinition, data: Record<string, unknown>): Uint8Array

渲染自定义模板。

typescript
const template: TemplateDefinition = {
  type: TemplateType.CUSTOM,
  name: '自定义小票',
  width: 48,
  elements: [
    { type: 'text', content: '{{store.name}}', align: 'center', bold: true },
    { type: 'line', char: '-' },
    { type: 'loop', items: 'items', itemVar: 'item', elements: [...] },
    { type: 'condition', variable: 'showDiscount', operator: 'truthy', then: [...] }
  ]
};

const commands = templateEngine.render(template, { store: {...}, items: [...] });

模板注册

registerTemplate(name: string, template: TemplateDefinition): void

注册自定义模板供后续使用。

typescript
const myTemplate: TemplateDefinition = {
  type: TemplateType.CUSTOM,
  name: '我的模板',
  width: 48,
  elements: [
    { type: 'text', content: '=== {{store.name}} ===', align: 'center' },
    { type: 'feed', lines: 1 }
  ]
};

templateEngine.registerTemplate('myReceipt', myTemplate);

getTemplate(name: string): TemplateDefinition | undefined

获取已注册的模板。

typescript
const template = templateEngine.getTemplate('myReceipt');
if (template) {
  const commands = templateEngine.render(template, data);
}

模板验证

validate(template: TemplateDefinition, data: Record<string, unknown>): ValidationResult

验证模板数据是否完整,返回验证结果。

typescript
const result = templateEngine.validate(template, data);

if (!result.valid) {
  result.errors.forEach(error => {
    console.error(`${error.code}: ${error.message} (字段: ${error.field})`);
  });
}

数据结构

ReceiptData - 小票数据

属性类型必填说明
storeStoreInfo店铺信息
orderOrderInfo订单信息
itemsReceiptItem[]商品列表
paymentPaymentInfo支付信息
qrCodestring二维码内容
footerstring页脚文本

LabelData - 标签数据

属性类型必填说明
namestring商品名称
pricenumber商品价格
barcodestring条码内容
barcodeFormatBarcodeFormat条码格式
specstring规格
productionDatestring生产日期
expiryDatestring过期日期

StoreInfo - 店铺信息

属性类型必填说明
namestring店铺名称
addressstring店铺地址
phonestring联系电话
logoUint8ArrayLogo 图片数据

OrderInfo - 订单信息

属性类型必填说明
idstring订单号
datestring订单日期
cashierstring收银员

ReceiptItem - 商品项

属性类型必填说明
namestring商品名称
quantitynumber数量
pricenumber单价
discountnumber折扣金额

PaymentInfo - 支付信息

属性类型必填说明
subtotalnumber小计金额
taxnumber税额
discountnumber优惠金额
totalnumber合计金额
methodstring支付方式
receivednumber实收金额
changenumber找零金额

模板元素类型

模板引擎支持以下元素类型,可组合使用构建复杂模板:

文本元素

typescript
{ type: 'text', content: 'Hello {{name}}', align: 'center', size: 2, bold: true }
属性类型说明
type'text'元素类型
contentstring文本内容,支持 变量替换
align'left' | 'center' | 'right'文本对齐
sizenumber字体大小 (1-4)
boldboolean是否加粗

分隔线元素

typescript
{ type: 'line', char: '-', length: 48 }
属性类型说明
type'line'元素类型
charstring分隔符字符(默认 -
lengthnumber线条长度(默认纸宽)

图片元素

typescript
{ type: 'image', data: imageData, width: 200, height: 100 }
属性类型说明
type'image'元素类型
dataUint8Array图片数据
widthnumber图片宽度
heightnumber图片高度

二维码元素

typescript
{ type: 'qrcode', content: 'https://example.com', size: 6 }
属性类型说明
type'qrcode'元素类型
contentstring二维码内容,支持变量替换
sizenumber二维码大小 (1-10)

条码元素

typescript
{ type: 'barcode', content: '12345678', format: 'CODE128', height: 60 }
属性类型说明
type'barcode'元素类型
contentstring条码内容,支持变量替换
formatBarcodeFormat条码格式
heightnumber条码高度

走纸元素

typescript
{ type: 'feed', lines: 3 }
属性类型说明
type'feed'元素类型
linesnumber走纸行数

变量元素

typescript
{ type: 'variable', name: 'order.id', format: 'currency' }
属性类型说明
type'variable'元素类型
namestring变量名,支持嵌套路径 user.address.city
formatstring格式化类型('currency' 转为 ¥ 格式,'date' 转为日期)

循环元素

typescript
{
  type: 'loop',
  items: 'items',
  itemVar: 'item',
  indexVar: 'idx',
  separator: '---',
  elements: [
    { type: 'text', content: '{{item.name}} x{{item.quantity}}' }
  ]
}
属性类型说明
type'loop'元素类型
itemsstring要遍历的数组变量名
itemVarstring当前项的变量名
indexVarstring索引变量名(可选)
elementsTemplateElement[]循环体中的元素
separatorstring项之间的分隔符(可选)

条件元素

typescript
{
  type: 'condition',
  variable: 'user.vip',
  operator: 'equals',
  value: true,
  then: [
    { type: 'text', content: 'VIP用户专属优惠' }
  ],
  else: [
    { type: 'text', content: '普通用户' }
  ]
}
属性类型说明
type'condition'元素类型
variablestring要检查的变量名
operator条件操作符运算符
valueunknown比较值(二元运算符时使用)
thenTemplateElement[]条件为真时渲染的元素
elseTemplateElement[]条件为假时渲染的元素(可选)

条件操作符

操作符说明示例
exists变量存在且不为 nullvariable: 'user'
not_exists变量不存在或为 nullvariable: 'user'
equals等于variable: 'status', value: 'active'
not_equals不等于variable: 'status', value: 'disabled'
gt大于variable: 'age', value: 18
gte大于等于variable: 'age', value: 18
lt小于variable: 'stock', value: 10
lte小于等于variable: 'stock', value: 10
truthy真值variable: 'showBanner'
falsy假值variable: 'isDisabled'

边框元素

typescript
{
  type: 'border',
  style: 'double',
  drawTop: true,
  drawBottom: true,
  drawLeft: true,
  drawRight: true,
  filled: true,
  padding: 1
}
属性类型说明
type'border'元素类型
styleBorderStyle边框样式
topLeftstring自定义左上角字符
topRightstring自定义右上角字符
bottomLeftstring自定义左下角字符
bottomRightstring自定义右下角字符
topstring自定义上边框字符
bottomstring自定义下边框字符
leftstring自定义左边框字符
rightstring自定义右边框字符
drawTopboolean是否绘制上边框(默认 true)
drawBottomboolean是否绘制下边框(默认 true)
drawLeftboolean是否绘制左边框(默认 false)
drawRightboolean是否绘制右边框(默认 false)
filledboolean是否填充内部(默认 false)
paddingnumber内边距(默认 0)

边框样式 BorderStyle

样式说明示例字符
'single'单线`+ -
'double'双线╔ ═ ║
'thick'粗线┏ ━ ┃
'rounded'圆角╭ ─ │
'dashed'虚线+ - :
'none'无边框空白

表格元素

typescript
{
  type: 'table',
  columns: [
    { header: '商品', width: 20, headerAlign: 'left', cellAlign: 'left' },
    { header: '数量', width: 8, headerAlign: 'center', cellAlign: 'center' },
    { header: '金额', width: 12, headerAlign: 'right', cellAlign: 'right' }
  ],
  rowsVar: 'items',
  showHeader: true,
  borderStyle: 'single',
  alternateRows: false
}
属性类型说明
type'table'元素类型
columnsTableColumn[]列定义数组
rowsVarstring行数据数组的变量名
showHeaderboolean是否显示表头(默认 true)
borderStyleBorderStyle边框样式(默认 'single'
alternateRowsboolean是否交替行颜色(默认 false)

TableColumn - 表格列定义

属性类型说明
headerstring列标题
widthnumber列宽(字符数)
headerAlignTextAlign表头对齐方式
cellAlignTextAlign单元格对齐方式

TemplateDefinition - 模板定义

属性类型必填说明
typeTemplateType模板类型
namestring模板名称
widthnumber纸宽(字符数)
elementsTemplateElement[]模板元素数组

TemplateType - 模板类型枚举

说明
RECEIPT小票模板
LABEL标签模板
CUSTOM自定义模板

ValidationResult - 验证结果

属性类型说明
validboolean是否有效
errorsArray<{ field, message, code }>错误列表

错误码

错误码说明
MISSING_VARIABLE缺少必需的变量
INVALID_LOOP_VARIABLE循环变量必须是数组

完整示例

使用模板引擎渲染小票

typescript
import { TemplateEngine, TemplateType } from 'taro-bluetooth-print';

const engine = new TemplateEngine(48);

// 准备数据
const receiptData = {
  store: {
    name: '便利超市',
    address: '科技园店',
    phone: '400-888-8888'
  },
  order: {
    id: '20240101001',
    date: '2024-01-01 10:30:00',
    cashier: '小李'
  },
  items: [
    { name: '农夫山泉', quantity: 2, price: 2.00 },
    { name: '方便面', quantity: 1, price: 4.50 },
    { name: '火腿肠', quantity: 3, price: 2.50, discount: 1.00 }
  ],
  payment: {
    subtotal: 14.50,
    discount: 1.00,
    total: 13.50,
    method: '微信支付',
    received: 20.00,
    change: 6.50
  },
  qrCode: 'https://example.com/order/123'
};

// 渲染
const commands = engine.renderReceipt(receiptData);

// 发送到打印机
await printer.connect('device-id');
await printer.send(commands);

使用自定义模板

typescript
import { TemplateEngine, TemplateType } from 'taro-bluetooth-print';

const engine = new TemplateEngine(48);

// 定义自定义模板
const customTemplate = {
  type: TemplateType.CUSTOM,
  name: '简洁收据',
  width: 48,
  elements: [
    // 标题
    { type: 'text', content: '{{store.name}}', align: 'center', bold: true, size: 2 },
    { type: 'feed', lines: 1 },
    
    // 分隔线
    { type: 'line', char: '=' },
    
    // 订单信息
    { type: 'condition', variable: 'order', operator: 'exists', then: [
      { type: 'text', content: '订单号: {{order.id}}' },
      { type: 'text', content: '日期: {{order.date}}' },
      { type: 'line', char: '-' }
    ]},
    
    // 商品列表(循环)
    { type: 'loop', items: 'items', itemVar: 'item', elements: [
      { type: 'text', content: '{{item.name}}' },
      { type: 'text', content: 'x{{item.quantity}}  ¥{{item.price}}' }
    ]},
    
    // 边框
    {
      type: 'border',
      style: 'double',
      drawTop: true,
      drawBottom: true,
      filled: true,
      padding: 1
    },
    
    // 合计
    { type: 'text', content: '合计: ¥{{payment.total}}', align: 'right', bold: true },
    { type: 'feed', lines: 2 }
  ]
};

// 注册模板
engine.registerTemplate('simpleReceipt', customTemplate);

// 渲染
const commands = engine.render(customTemplate, receiptData);

使用表格模板

typescript
const tableTemplate = {
  type: TemplateType.CUSTOM,
  name: '库存清单',
  width: 58,
  elements: [
    { type: 'text', content: '库存清单', align: 'center', bold: true, size: 2 },
    { type: 'feed', lines: 1 },
    {
      type: 'table',
      columns: [
        { header: '商品', width: 20 },
        { header: '库存', width: 10, cellAlign: 'center' },
        { header: '单价', width: 12, cellAlign: 'right' },
        { header: '小计', width: 12, cellAlign: 'right' }
      ],
      rowsVar: 'inventory',
      showHeader: true,
      borderStyle: 'single'
    }
  ]
};

const inventoryData = {
  inventory: [
    { '商品': '农夫山泉', '库存': 100, '单价': 2.00, '小计': 200.00 },
    { '商品': '康师傅', '库存': 50, '单价': 4.50, '小计': 225.00 },
    { '商品': '火腿肠', '库存': 80, '单价': 2.50, '小计': 200.00 }
  ]
};

const commands = engine.render(tableTemplate, inventoryData);

基于 MIT 许可发布