Blame view

泰额版/Food Labeling Management App UniApp/src/utils/print/templatePhysicalMm.ts 6.17 KB
59e51671   “wangming”   1
1
2
3
4
  /**
   * 与 NativeTemplateCommandBuilder.toMillimeter 一致(px 按 96dpi 转 mm),
   * 用于判断模板是否适合走 native-fast-printer 的 TSC 模板指令(常见标签幅宽约 4 英寸级)。
   */
540ac0e3   杨鑫   前端修改bug
5
  import type { SystemLabelTemplate, SystemTemplateElementBase } from './types/printer'
59e51671   “wangming”   1
6
7
  
  const DESIGN_DPI = 96
540ac0e3   杨鑫   前端修改bug
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  const PX_PER_INCH = 96
  const PX_PER_CM = 37.8
  
  function toCanvasPx (value: number, unit: string): number {
    const u = String(unit || 'inch').toLowerCase()
    if (u === 'mm') return (value / 25.4) * PX_PER_INCH
    if (u === 'cm') return value * PX_PER_CM
    if (u === 'px') return value
    return value * PX_PER_INCH
  }
  
  function fromCanvasPx (px: number, unit: string): number {
    const u = String(unit || 'inch').toLowerCase()
    if (u === 'mm') return (px * 25.4) / PX_PER_INCH
    if (u === 'cm') return px / PX_PER_CM
    if (u === 'px') return px
    return px / PX_PER_INCH
  }
  
  function roundTemplateDim (value: number, unit: string): number {
    const u = String(unit || 'inch').toLowerCase()
    if (u === 'px') return Math.max(1, Math.round(value))
    if (u === 'mm' || u === 'cm') return Math.round(value * 10) / 10
    return Math.round(value * 1000) / 1000
  }
  
  function elementBottomPx (el: SystemTemplateElementBase): number {
    const y = Number(el.y) || 0
    const h = Math.max(0, Number(el.height) || 0)
    let bottom = y + h
    const type = String(el.type || '').toUpperCase()
    const cfg = (el.config || {}) as Record<string, unknown>
    if (type === 'BARCODE') {
      const showText = String(cfg.showText ?? cfg.ShowText ?? 'true').toLowerCase() !== 'false'
      if (showText) bottom += 28
      else bottom += 4
    }
    if (type === 'QRCODE') bottom += 4
    return bottom
  }
  
  /**
   * 原生 printTemplate 的 SIZE 高度仅取自模板根 height,不会按元素自动增高;
   * 条码/日期贴在底部时易被裁掉。与 systemTemplateAdapter.buildTscTemplate 增高逻辑对齐。
   */
  /** 设计 px:元素最底边 + 留白,且不超过模板根 height(用于光栅出纸高度,避免整纸 5cm 空白) */
  export function templateContentHeightPx (
    template: Pick<SystemLabelTemplate, 'unit' | 'width' | 'height' | 'elements'>,
    extraBottomPx = 14,
  ): number {
    const unit = String(template.unit || 'inch')
    const canvasH = Math.max(40, Math.round(toCanvasPx(Number(template.height) || 0, unit)))
    const elements = template.elements || []
    if (!elements.length) return canvasH
    let maxBottom = 0
    for (const el of elements) {
      maxBottom = Math.max(maxBottom, elementBottomPx(el))
    }
    return Math.max(40, Math.min(canvasH, maxBottom + extraBottomPx))
  }
  
  export function ensureTemplateHeightCoversElements (
    template: SystemLabelTemplate,
    extraBottomPx = 14
  ): SystemLabelTemplate {
    const unit = String(template.unit || 'inch')
    const elements = template.elements || []
    if (!elements.length) return template
    let maxBottom = 0
    for (const el of elements) {
      maxBottom = Math.max(maxBottom, elementBottomPx(el))
    }
    const currentHpx = toCanvasPx(Number(template.height) || 0, unit)
    const neededPx = maxBottom + extraBottomPx
    if (neededPx <= currentHpx + 1) return template
    return {
      ...template,
      height: roundTemplateDim(fromCanvasPx(neededPx, unit), unit),
    }
  }
59e51671   “wangming”   1
88
89
90
91
92
  
  /** 常见 4″ 标签机安全上限(mm),略放宽 */
  const NATIVE_FAST_MAX_WIDTH_MM = 112
  const NATIVE_FAST_MAX_HEIGHT_MM = 320
  
540ac0e3   杨鑫   前端修改bug
93
94
95
96
97
98
99
100
101
102
103
  /** 打印/预览统一:模板根 width/height + unit → 物理毫米(与 NativeTemplateCommandBuilder.toMillimeter 一致) */
  export function getTemplatePhysicalSizeMm (
    template: Pick<SystemLabelTemplate, 'unit' | 'width' | 'height'>
  ): { widthMm: number; heightMm: number; unit: string } {
    const unit = String(template.unit || 'inch')
    const w = Number(template.width) || 0
    const h = Number(template.height) || 0
    const { widthMm, heightMm } = templateSizeToMillimeters(unit, w, h)
    return { widthMm, heightMm, unit }
  }
  
59e51671   “wangming”   1
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  export function templateSizeToMillimeters (
    unit: string | undefined,
    width: number,
    height: number
  ): { widthMm: number; heightMm: number } {
    const u = String(unit || 'inch').toLowerCase()
    let widthMm = 0
    let heightMm = 0
    if (u === 'mm') {
      widthMm = width
      heightMm = height
    } else if (u === 'cm') {
      widthMm = width * 10
      heightMm = height * 10
    } else if (u === 'px') {
      widthMm = (width / DESIGN_DPI) * 25.4
      heightMm = (height / DESIGN_DPI) * 25.4
    } else {
      widthMm = width * 25.4
      heightMm = height * 25.4
    }
    return { widthMm, heightMm }
  }
  
5a192b24   杨鑫   最新同步
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  /** 设计画布像素(96dpi 坐标系)→ 物理毫米,与 Web unitToPx / App toCanvasPx 一致 */
  export function designCanvasPxToMillimeters (
    cw: number,
    ch: number,
  ): { widthMm: number; heightMm: number } {
    return {
      widthMm: Math.round(((cw / DESIGN_DPI) * 25.4) * 10) / 10,
      heightMm: Math.round(((ch / DESIGN_DPI) * 25.4) * 10) / 10,
    }
  }
  
  /** 光栅出纸像素(printDpi)→ 物理毫米,SIZE 与位图一致,各机型比例统一 */
  export function rasterDotsToMillimeters (
    widthDots: number,
    heightDots: number,
    printDpi: number,
  ): { widthMm: number; heightMm: number } {
    const dpi = Math.max(1, printDpi)
    return {
      widthMm: Math.round(((widthDots / dpi) * 25.4) * 10) / 10,
      heightMm: Math.round(((heightDots / dpi) * 25.4) * 10) / 10,
    }
  }
  
  /**
   * 预览 / 打印共用设计画布尺寸(与后台 LabelCanvas unitToPx 同一坐标系)。
   * 默认用模板根 height,与后台预览一致;不再对 ESC 单独裁 content 高度。
   */
  export function resolveLabelDesignCanvasPx (
    template: Pick<SystemLabelTemplate, 'unit' | 'width' | 'height'>,
  ): { cw: number; ch: number } {
    const unit = String(template.unit || 'inch')
    const cw = Math.max(40, Math.round(toCanvasPx(Number(template.width) || 2, unit)))
    const ch = Math.max(40, Math.round(toCanvasPx(Number(template.height) || 2, unit)))
    return { cw, ch }
  }
  
59e51671   “wangming”   1
165
166
167
168
169
170
171
172
173
  export function isTemplateWithinNativeFastPrintBounds (
    template: Pick<SystemLabelTemplate, 'unit' | 'width' | 'height'>
  ): boolean {
    const w = Number(template.width) || 0
    const h = Number(template.height) || 0
    if (w <= 0 || h <= 0) return false
    const { widthMm, heightMm } = templateSizeToMillimeters(template.unit, w, h)
    return widthMm <= NATIVE_FAST_MAX_WIDTH_MM && heightMm <= NATIVE_FAST_MAX_HEIGHT_MM
  }