10 KiB
Raw Permalink Blame History

系统设计文档

1. 系统架构

┌─────────────────────────────────────────────────────────┐
│                    小票打印系统 (本地服务)                   │
├─────────────────────────────────────────────────────────┤
│  ┌──────────────┐    ┌──────────────┐    ┌───────────┐ │
│  │   Web 配置页  │◄──►│   模板引擎    │◄──►│  打印机    │ │
│  │  (Vue/React) │    │  (渲染/ESC-POS)│    │ (WiFi ESC)│ │
│  └──────────────┘    └──────────────┘    └───────────┘ │
│         ▲                                            │
│         │ REST API                                   │
│         ▼                                            │
│  ┌──────────────┐                                    │
│  │  外部调用端   │  ← 脚本、IFTTT、快捷指令等           │
│  │  (curl/HTTP) │                                    │
│  └──────────────┘                                    │
└─────────────────────────────────────────────────────────┘

数据流

  1. 配置阶段: Web 页创建/编辑模板 → 保存为 YAML 配置
  2. 调用阶段: POST 数据到 /api/print/:templateId → 模板引擎渲染 → 生成 ESC/POS 指令 → 发送到打印机

2. 模板系统

2.1 模板结构

# 模板元信息
name: "每日待办"
id: "daily-todo"
width: 80mm
description: "打印今日待办事项列表"

# 页面设置
page:
  marginTop: 2
  marginBottom: 3

# 默认样式
defaults:
  fontSize: normal
  lineHeight: 1.0
  marginBottom: 0

# 内容块
blocks:
  # 文本块
  - type: text
    content: "📋 {{date}} 待办"
    align: center
    fontSize: large
    bold: true
    marginBottom: 1
    
  # 分隔线
  - type: divider
    char: "="
    marginBottom: 1
    
  # 列表循环
  - type: list
    data: "{{tasks}}"
    itemTemplate:
      - type: text
        content: "[{{status}}] {{title}}"
        fontSize: normal
        marginBottom: 0
        
  # 多列行
  - type: row
    marginBottom: 1
    columns:
      - content: "{{leftText}}"
        align: left
        width: 50%
        bold: true
      - content: "{{rightText}}"
        align: right
        width: 50%
        
  # 表格
  - type: table
    marginBottom: 1
    columns:
      - header: "商品"
        align: left
        width: 50%
      - header: "数量"
        align: center
        width: 25%
      - header: "金额"
        align: right
        width: 25%
    data: "{{items}}"
    
  # 图片
  - type: image
    src: "{{logoUrl}}"
    align: center
    maxWidth: 200
    
  # 条码
  - type: barcode
    format: "CODE128"  # CODE128 | QR | EAN13
    data: "{{orderId}}"
    align: center
    height: 64
    
  # 空行
  - type: space
    lines: 2

2.2 支持的块类型

类型 用途 关键属性
text 普通文本 content, align, fontSize, bold, italic, underline, lineHeight, marginTop, marginBottom
list 循环渲染数组 data, itemTemplate
table 多列表格 columns, data
row 多列行布局 columns
divider 分隔线 char
image 图片/Logo src, align, maxWidth
barcode 条码/二维码 format, data, height
space 空行 lines

2.3 样式属性

# 对齐
align: left | center | right

# 字体大小
fontSize: small | normal | large | xlarge

# 文本样式
bold: true | false
italic: true | false          # 打印机支持时
underline: true | false

# 间距
lineHeight: 1.0               # 行高倍数
marginTop: 0                  # 上方间距(行数)
marginBottom: 0               # 下方间距(行数)

# 列宽(仅 row/table
width: 50% | 20               # 百分比或字符数

2.4 数据绑定

使用 Mustache 语法 {{variable}}

content: "订单编号: {{orderId}}"
data: "{{items}}"              # 列表数据源

支持嵌套访问:

content: "{{customer.name}} - {{customer.phone}}"

2.5 Schema 自动生成

系统从模板的 {{变量}} 自动提取数据结构:

# 模板示例
blocks:
  - content: "{{orderType}} - {{orderId}}"
  - data: "{{items}}"

自动生成:

{
  "type": "object",
  "properties": {
    "orderType": { "type": "string" },
    "orderId": { "type": "string" },
    "items": { "type": "array" }
  }
}

通过 GET /api/templates/:id/schema 获取 Schema 和示例数据。

3. Web 配置页

3.1 核心功能

  1. 模板编辑器

    • 左侧YAML 代码编辑(语法高亮 + 错误提示)
    • 右侧实时预览HTML 模拟小票效果)
  2. 块类型选择器

    • 快捷插入按钮(文本、表格、图片、分隔线等)
    • 点击后插入模板代码片段
  3. 数据模拟器

    • 基于 Schema 生成表单
    • 输入模拟数据测试渲染
    • 保存测试数据集
  4. 打印机设置

    • IP 地址配置
    • 打印测试页
    • 打印队列状态

3.2 界面布局

┌─────────────────────────────────────────────────────────┐
│  [Logo] 小票打印机                    [打印机状态 ●]     │
├────────────┬────────────────────────┬───────────────────┤
│            │                        │                   │
│  模板列表   │      YAML 编辑器        │    实时预览        │
│  ───────   │                        │                   │
│  daily-todo│                        │    ┌─────────┐    │
│  food-order│  - type: text          │    │ 📋 待办  │    │
│  ticket    │    content: "..."      │    │ ======= │    │
│            │                        │    │ [☐] ... │    │
│ [+ 新建]   │                        │    └─────────┘    │
│            │                        │                   │
├────────────┴────────────────────────┴───────────────────┤
│  块类型: [文本] [表格] [图片] [分隔线] [条码] [空行]     │
└─────────────────────────────────────────────────────────┘

4. 设计参考

4.1 餐饮小票(麦当劳风格)

blocks:
  # 顶部双栏
  - type: row
    columns:
      - content: "外带"
        align: left
      - content: "订单编号: {{orderId}}"
        align: right
  - type: divider
    char: "-"
    
  # 商品列表(带缩进备注)
  - type: list
    data: "{{items}}"
    itemTemplate:
      - type: text
        content: "{{quantity}} {{name}}"
      - type: list
        data: "{{notes}}"
        itemTemplate:
          - type: text
            content: "  {{.}}"
            fontSize: small
      - type: divider
        char: "-"
        
  # 取餐号(超大)
  - type: text
    content: "取餐柜取餐"
    align: center
    marginBottom: 0
  - type: text
    content: "{{pickupNumber}}"
    align: center
    fontSize: xlarge
    bold: true
    marginBottom: 1
    
  # 条码
  - type: barcode
    format: "CODE128"
    data: "{{pickupNumber}}"
    align: center
    
  # 时间戳
  - type: row
    columns:
      - content: "MOBILE"
        align: left
        fontSize: small
      - content: "{{timestamp}}"
        align: right
        fontSize: small

4.2 精致小票(铁板烧风格)

blocks:
  # Logo 图片
  - type: image
    src: "{{logoUrl}}"
    align: center
    maxWidth: 150
    marginBottom: 0
    
  # 英文小字
  - type: text
    content: "THE SOURCE OF THIS DESIGN MATERIAL IS TEPPANYAKI DESIGN"
    align: center
    fontSize: small
    
  # 中文标题
  - type: text
    content: "铁板烧设计"
    align: center
    bold: true
    marginBottom: 1
    
  # 装饰分隔线
  - type: divider
    char: "="
    marginBottom: 1
    
  # 表头
  - type: row
    columns:
      - content: "商品名称"
        align: left
        bold: true
        width: 50%
      - content: "数量"
        align: center
        bold: true
        width: 25%
      - content: "金额"
        align: right
        bold: true
        width: 25%
        
  # 表格数据
  - type: table
    columns:
      - align: left
        width: 50%
      - align: center
        width: 25%
      - align: right
        width: 25%
    data: "{{items}}"
    
  # 汇总
  - type: divider
    char: "="
  - type: row
    columns:
      - content: "小计"
        align: left
      - content: "¥{{subtotal}}"
        align: right

5. 技术决策

5.1 为什么选择 YAML

  • 比 JSON 更易手写(支持注释、多行字符串)
  • 比纯代码更声明式(专注"是什么"而非"怎么做"
  • 主流编辑器支持语法高亮和验证

5.2 为什么自动生成 Schema

  • 降低用户负担(无需学习 JSON Schema
  • 保持数据和模板同步(一处修改,处处生效)
  • 自动生成文档和表单

5.3 为什么用 HTML 预览?

  • 无需连接真实打印机即可调试
  • 跨平台、易实现
  • 样式可精确还原CSS

6. 待决策事项

  • 是否支持模板继承/复用?
  • 是否支持条件渲染if/else
  • 是否支持自定义字体?
  • 是否支持打印历史记录?
  • 是否支持多打印机管理?