Blame view

美国版/Food Labeling Management App UniApp/src/utils/print/systemTemplateAdapter.ts 21 KB
91821909   杨鑫   最新
1
  import { formatBarcodeValueForTsc, normalizeBarcodeType } from '../barcodeFormat'
43d16ca6   杨鑫   打印日志
2
  import { storedValueLooksLikeImagePath } from '../resolveMediaUrl'
a6f5c1af   “wangming”   开发了安卓基座
3
4
5
6
7
  import {
    createImageBitmapPatch,
    createTextBitmapPatch,
    shouldRasterizeTextElement,
  } from './nativeBitmapPatch'
9927b97e   “wangming”   Improve GP_R3 pri...
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
  import { applyTemplateData } from './templateRenderer'
  import type {
    EscTemplateItem,
    LabelTemplateData,
    PrinterTemplateUnit,
    StructuredLabelTemplate,
    TscTemplateItem,
    StructuredTscTemplate,
    StructuredEscTemplate,
    SystemLabelTemplate,
    SystemTemplateElementBase,
    SystemTemplateTextAlign,
  } from './types/printer'
  
  const DESIGN_DPI = 96
  
  function roundNumber (value: number, digits = 1): number {
    const factor = Math.pow(10, digits)
    return Math.round(value * factor) / factor
  }
  
  function toMillimeter (value: number, unit: PrinterTemplateUnit = 'inch'): number {
    if (unit === 'mm') return value
    if (unit === 'cm') return value * 10
    if (unit === 'px') return value / DESIGN_DPI * 25.4
    return value * 25.4
  }
  
  function templateWidthPx (template: SystemLabelTemplate): number {
    return toMillimeter(template.width, template.unit || 'inch') / 25.4 * DESIGN_DPI
  }
  
540ac0e3   杨鑫   前端修改bug
40
41
42
43
  function templateHeightPx (template: SystemLabelTemplate): number {
    return toMillimeter(template.height, template.unit || 'inch') / 25.4 * DESIGN_DPI
  }
  
9927b97e   “wangming”   Improve GP_R3 pri...
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  function pxToDots (value: number, dpi: number): number {
    return Math.max(0, Math.round((Number(value) || 0) * dpi / DESIGN_DPI))
  }
  
  function clamp (value: number, min: number, max: number): number {
    return Math.max(min, Math.min(max, Math.round(value)))
  }
  
  function sortElements (elements: SystemTemplateElementBase[]): SystemTemplateElementBase[] {
    return [...elements].sort((a, b) => {
      if (a.y !== b.y) return a.y - b.y
      return a.x - b.x
    })
  }
  
  function getConfigString (
    config: Record<string, any>,
    keys: string[],
    fallback = ''
  ): string {
    for (let i = 0; i < keys.length; i++) {
      const value = config?.[keys[i]]
      if (value != null && value !== '') return String(value)
    }
    return fallback
  }
  
  function getConfigNumber (
    config: Record<string, any>,
    keys: string[],
    fallback = 0
  ): number {
    for (let i = 0; i < keys.length; i++) {
      const value = Number(config?.[keys[i]])
      if (!Number.isNaN(value) && Number.isFinite(value)) return value
    }
    return fallback
  }
  
  function toCamelCaseKey (value: string): string {
    return value
      .toLowerCase()
      .split(/[_\s-]+/)
      .map((segment, index) => index === 0
        ? segment
        : segment.charAt(0).toUpperCase() + segment.slice(1))
      .join('')
  }
  
  function resolveBindingKey (element: SystemTemplateElementBase): string {
    const config = element.config || {}
    const explicit = getConfigString(config, ['dataKey', 'field', 'bindField', 'key', 'valueKey'])
    if (explicit) return explicit
  
    const type = String(element.type || '').toUpperCase()
    const map: Record<string, string> = {
      TEXT_PRODUCT: 'productName',
      TEXT_LABEL_ID: 'labelId',
      TEXT_CATEGORY: 'category',
      TEXT_PRICE: 'price',
      TEXT_DATE: 'date',
      TEXT_TIME: 'time',
      QRCODE: 'qrCode',
      BARCODE: 'barcode',
    }
    if (map[type]) return map[type]
  
    const pureType = type
      .replace(/^TEXT_/, '')
      .replace(/^FIELD_/, '')
      .replace(/^VALUE_/, '')
    return pureType ? toCamelCaseKey(pureType) : ''
  }
  
  function resolveTemplateFieldValue (data: LabelTemplateData, key: string): string {
    if (!key) return ''
    const candidates = [key]
    if (key === 'productName') candidates.push('product')
    if (key === 'product') candidates.push('productName')
    if (key === 'qrCode') candidates.push('labelId', 'barcode')
    if (key === 'barcode') candidates.push('labelId', 'qrCode')
  
    for (let i = 0; i < candidates.length; i++) {
      const value = data[candidates[i]]
      if (value != null) return String(value)
    }
    return ''
  }
  
a6f5c1af   “wangming”   开发了安卓基座
133
134
135
136
  function formatPriceValue (
    rawValue: string,
    config: Record<string, any>
  ): string {
58d2e61c   杨鑫   最新代码
137
138
139
    const prefix = getConfigString(config, ['prefix', 'Prefix'], '')
    const suffix = getConfigString(config, ['suffix', 'Suffix'], '')
    const decimal = getConfigNumber(config, ['decimal', 'Decimal'], -1)
a6f5c1af   “wangming”   开发了安卓基座
140
141
142
143
144
145
146
    const numericValue = Number(rawValue)
    const value = !Number.isNaN(numericValue) && Number.isFinite(numericValue) && decimal >= 0
      ? numericValue.toFixed(decimal)
      : rawValue
    return `${prefix}${value}${suffix}`
  }
  
143afd59   杨鑫   打印,标签
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  /** WEIGHT / DATE / TIME / DURATION:画布已把展示写入 config.text;此处兜底 value+unit、format */
  function resolvePlainTextLikeElement (
    element: SystemTemplateElementBase,
    data: LabelTemplateData
  ): string {
    const config = element.config || {}
    const t = getConfigString(config, ['text', 'Text'])
    if (t) return applyTemplateData(t, data)
    const type = String(element.type || '').toUpperCase()
    if (type === 'WEIGHT') {
      const v = getConfigString(config, ['value', 'Value'])
      const u = getConfigString(config, ['unit', 'Unit'])
      if (!v && !u) return ''
      if (v && u && !v.endsWith(u)) return `${v}${u}`
      return v || u
    }
43d16ca6   杨鑫   打印日志
163
    /** 与预览一致:展示用文案在 config.text;无 text 时不应把 format 模板(如 YYYY-MM-DD)当内容打印 */
143afd59   杨鑫   打印,标签
164
    if (type === 'DATE' || type === 'TIME' || type === 'DURATION') {
43d16ca6   杨鑫   打印日志
165
      return ''
143afd59   杨鑫   打印,标签
166
167
168
169
    }
    return ''
  }
  
9927b97e   “wangming”   Improve GP_R3 pri...
170
171
172
173
174
  function resolveElementText (
    element: SystemTemplateElementBase,
    data: LabelTemplateData
  ): string {
    const config = element.config || {}
a6f5c1af   “wangming”   开发了安卓基座
175
    const type = String(element.type || '').toUpperCase()
9927b97e   “wangming”   Improve GP_R3 pri...
176
    const hasText = config.text != null && config.text !== ''
43d16ca6   杨鑫   打印日志
177
178
    const vst = String(element.valueSourceType || '').toUpperCase()
  
a6f5c1af   “wangming”   开发了安卓基座
179
180
181
    if (type === 'TEXT_PRICE') {
      const bindingKey = resolveBindingKey(element)
      const boundValue = resolveTemplateFieldValue(data, bindingKey)
58d2e61c   杨鑫   最新代码
182
183
184
185
186
187
188
189
190
191
192
193
      const rawCfg = getConfigString(config, [
        'text',
        'Text',
        'value',
        'Value',
        'displayText',
        'DisplayText',
        'displayValue',
        'DisplayValue',
        'defaultValue',
        'DefaultValue',
      ])
43d16ca6   杨鑫   打印日志
194
195
196
197
      /** FIXED:重打快照里价格已在 config.text,勿用空 data 绑定出 0 */
      if (vst === 'FIXED' && rawCfg.trim()) {
        return formatPriceValue(rawCfg, config)
      }
58d2e61c   杨鑫   最新代码
198
199
      const baseValue = boundValue || (rawCfg ? applyTemplateData(rawCfg, data) : '')
      return baseValue.trim() ? formatPriceValue(baseValue, config) : ''
a6f5c1af   “wangming”   开发了安卓基座
200
    }
43d16ca6   杨鑫   打印日志
201
202
203
204
205
206
207
208
209
210
211
212
  
    /** FIXED:TEXT_PRODUCT 等勿在 data 为空时仍走 productName 绑定(与快照 config.text 冲突) */
    if (
      vst === 'FIXED' &&
      hasText &&
      (type === 'TEXT_PRODUCT' ||
        type === 'TEXT_CATEGORY' ||
        type === 'TEXT_LABEL_ID')
    ) {
      return applyTemplateData(String(config.text), data)
    }
  
a6f5c1af   “wangming”   开发了安卓基座
213
    if (hasText && type === 'TEXT_STATIC') {
9927b97e   “wangming”   Improve GP_R3 pri...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
      return applyTemplateData(String(config.text), data)
    }
    if (hasText && String(config.text).includes('{{')) {
      return applyTemplateData(String(config.text), data)
    }
    const bindingKey = resolveBindingKey(element)
    const boundValue = resolveTemplateFieldValue(data, bindingKey)
    if (boundValue) return boundValue
    if (hasText) return applyTemplateData(String(config.text), data)
    return ''
  }
  
  function resolveElementDataValue (
    element: SystemTemplateElementBase,
    data: LabelTemplateData
  ): string {
    const config = element.config || {}
3ead62fc   杨鑫   优化
231
    const raw = getConfigString(config, ['data', 'Data', 'value', 'Value', 'src', 'Src', 'url', 'Url'])
9927b97e   “wangming”   Improve GP_R3 pri...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
    if (raw) return applyTemplateData(raw, data)
    return resolveTemplateFieldValue(data, resolveBindingKey(element))
  }
  
  function resolveElementAlign (
    element: SystemTemplateElementBase,
    pageWidthPx: number
  ): SystemTemplateTextAlign {
    const config = element.config || {}
    const align = String(config.textAlign || '').toLowerCase()
    if (align === 'left' || align === 'center' || align === 'right') return align as SystemTemplateTextAlign
    const centerX = (Number(element.x) || 0) + (Number(element.width) || 0) / 2
    if (centerX <= pageWidthPx * 0.33) return 'left'
    if (centerX >= pageWidthPx * 0.67) return 'right'
    return 'center'
  }
  
  function toEscAlign (align: SystemTemplateTextAlign): 0 | 1 | 2 {
    if (align === 'center') return 1
    if (align === 'right') return 2
    return 0
  }
  
  function resolveRotation (value?: string): number {
    return value === 'vertical' ? 90 : 0
  }
  
  function normalizeQrLevel (value?: string): 'L' | 'M' | 'Q' | 'H' {
    const key = String(value || 'M').trim().toUpperCase()
    if (key === 'L' || key === 'M' || key === 'Q' || key === 'H') return key
    return 'M'
  }
  
  function estimateTextWidthDots (text: string, fontDots: number): number {
    let total = 0
    for (let i = 0; i < text.length; i++) {
      const code = text.charCodeAt(i)
      total += code > 255 ? fontDots : fontDots * 0.6
    }
    return Math.round(total)
  }
  
  function resolveTextScale (fontSizePx: number, dpi: number): number {
    const targetDots = Math.max(12, Math.round(fontSizePx * dpi / DESIGN_DPI))
    return clamp(targetDots / 24, 1, 7)
  }
  
a6f5c1af   “wangming”   开发了安卓基座
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  function estimateQrModuleCount (value: string, level: 'L' | 'M' | 'Q' | 'H'): number {
    const capacities: Record<'L' | 'M' | 'Q' | 'H', number[]> = {
      L: [17, 32, 53, 78, 106, 134, 154, 192, 230, 271],
      M: [14, 26, 42, 62, 84, 106, 122, 152, 180, 213],
      Q: [11, 20, 32, 46, 60, 74, 86, 108, 130, 151],
      H: [7, 14, 24, 34, 44, 58, 64, 84, 98, 119],
    }
    const length = Math.max(1, String(value || '').length)
    const versions = capacities[level] || capacities.M
    let version = versions.length
    for (let i = 0; i < versions.length; i++) {
      if (length <= versions[i]) {
        version = i + 1
        break
      }
    }
    return 21 + (version - 1) * 4
  }
  
  function resolveQrModuleSize (
    widthPx: number,
    heightPx: number,
    dpi: number,
    value: string,
    level: 'L' | 'M' | 'Q' | 'H'
  ): number {
    const targetDots = Math.max(24, Math.min(
      pxToDots(widthPx, dpi),
      pxToDots(heightPx, dpi)
    ))
    const moduleCount = Math.max(21, estimateQrModuleCount(value, level))
    return clamp(Math.floor(targetDots / moduleCount), 3, 12)
  }
  
9927b97e   “wangming”   Improve GP_R3 pri...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  function resolveTextX (params: {
    align: SystemTemplateTextAlign
    xPx: number
    widthPx: number
    dpi: number
    text: string
    scale: number
  }): number {
    const left = pxToDots(params.xPx, params.dpi)
    if (params.align === 'left') return left
  
    const boxWidth = pxToDots(params.widthPx, params.dpi)
    const fontDots = Math.max(24, params.scale * 24)
    const textWidth = estimateTextWidthDots(params.text, fontDots)
    if (params.align === 'center') {
      return Math.max(0, left + Math.round(Math.max(0, boxWidth - textWidth) / 2))
    }
    return Math.max(0, left + Math.max(0, boxWidth - textWidth))
  }
  
b04bc3a5   杨鑫   打印日志 重新打印
333
  /** 全角人民币符在 TSC 内置字库常成「?」;规范为半角 ¥(U+00A5),与 tscLabelBuilder 单字节编码一致,勿再用字母 Y */
43d16ca6   杨鑫   打印日志
334
335
  function sanitizeTextForTscBuiltinFont (text: string): string {
    return String(text || '')
b04bc3a5   杨鑫   打印日志 重新打印
336
337
      .replace(/\uFFE5/g, '\u00A5')
      .replace(/¥/g, '\u00A5')
43d16ca6   杨鑫   打印日志
338
339
  }
  
58d2e61c   杨鑫   最新代码
340
  /** 估算 TSC 项底部点坐标,用于避免 SIZE 高度略小于内容时裁掉最后一行(常见于底部价格) */
540ac0e3   杨鑫   前端修改bug
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  /** 整标签纸外框(配置区 Border,与元素 border 不同) */
  function pushTemplatePaperBorderIfNeeded (
    items: TscTemplateItem[],
    template: SystemLabelTemplate,
    dpi: number
  ) {
    const border = String(template.border || '').toLowerCase()
    if (border !== 'line' && border !== 'dotted') return
    items.push({
      type: 'box',
      x: 0,
      y: 0,
      width: Math.max(1, pxToDots(templateWidthPx(template), dpi)),
      height: Math.max(1, pxToDots(templateHeightPx(template), dpi)),
      lineWidth: border === 'dotted' ? 1 : 2,
    })
  }
  
923d50c0   杨鑫   更新bug
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  function pushElementBorderBoxIfNeeded (
    items: TscTemplateItem[],
    element: SystemTemplateElementBase,
    dpi: number
  ) {
    const type = String(element.type || '').toUpperCase()
    if (type === 'BLANK') return
    const border = String(element.border || '').toLowerCase()
    if (border !== 'line' && border !== 'dotted') return
    items.push({
      type: 'box',
      x: pxToDots(element.x, dpi),
      y: pxToDots(element.y, dpi),
      width: Math.max(1, pxToDots(element.width, dpi)),
      height: Math.max(1, pxToDots(element.height, dpi)),
      lineWidth: border === 'dotted' ? 1 : 2,
    })
  }
  
58d2e61c   杨鑫   最新代码
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  function estimateTscItemBottomDots (item: TscTemplateItem): number {
    switch (item.type) {
      case 'bitmap':
        return item.y + item.image.height
      case 'text': {
        const scale = item.yScale || 1
        return item.y + Math.round(24 * scale * 2)
      }
      case 'qrcode': {
        const cw = item.cellWidth || 4
        return item.y + cw * 72
      }
      case 'barcode':
        return item.y + Math.max(20, Math.round(item.height || 80))
      case 'bar':
        return item.y + item.height
      case 'box':
        return item.y + item.height
      default:
        return 0
    }
  }
  
9927b97e   “wangming”   Improve GP_R3 pri...
401
402
403
404
  function buildTscTemplate (
    template: SystemLabelTemplate,
    data: LabelTemplateData,
    dpi: number,
4ad9ae43   “wangming”   1111
405
406
407
    printQty: number,
    options: {
      disableBitmapText?: boolean
58d2e61c   杨鑫   最新代码
408
      allowCurrencyBitmapWhenDisabled?: boolean
4ad9ae43   “wangming”   1111
409
    } = {}
9927b97e   “wangming”   Improve GP_R3 pri...
410
411
  ): StructuredTscTemplate {
    const widthMm = roundNumber(toMillimeter(template.width, template.unit || 'inch'))
58d2e61c   杨鑫   最新代码
412
    let heightMm = roundNumber(toMillimeter(template.height, template.unit || 'inch'))
9927b97e   “wangming”   Improve GP_R3 pri...
413
414
    const items: TscTemplateItem[] = []
  
a6f5c1af   “wangming”   开发了安卓基座
415
    const pageWidth = templateWidthPx(template)
540ac0e3   杨鑫   前端修改bug
416
    pushTemplatePaperBorderIfNeeded(items, template, dpi)
a6f5c1af   “wangming”   开发了安卓基座
417
  
9927b97e   “wangming”   Improve GP_R3 pri...
418
419
420
    sortElements(template.elements).forEach((element) => {
      const config = element.config || {}
      const type = String(element.type || '').toUpperCase()
923d50c0   杨鑫   更新bug
421
      pushElementBorderBoxIfNeeded(items, element, dpi)
9927b97e   “wangming”   Improve GP_R3 pri...
422
  
143afd59   杨鑫   打印,标签
423
424
425
426
427
428
429
430
431
432
433
      const renderAsTextBlock =
        type.startsWith('TEXT_') ||
        type === 'WEIGHT' ||
        type === 'DATE' ||
        type === 'TIME' ||
        type === 'DURATION'
  
      if (renderAsTextBlock) {
        const text = type.startsWith('TEXT_')
          ? resolveElementText(element, data)
          : resolvePlainTextLikeElement(element, data)
9927b97e   “wangming”   Improve GP_R3 pri...
434
435
        if (!text) return
        const scale = resolveTextScale(getConfigNumber(config, ['fontSize'], 14), dpi)
a6f5c1af   “wangming”   开发了安卓基座
436
437
        const align = resolveElementAlign(element, pageWidth)
  
b04bc3a5   杨鑫   打印日志 重新打印
438
        /**
58d2e61c   杨鑫   最新代码
439
440
         * gp-d320fx / d320fax 等 disableBitmapText 时:内置字库对 ¥ 与 TEXT_PRICE 整行常异常。
         * 在 allowCurrencyBitmapWhenDisabled 下对 TEXT_PRICE 一律尝试位图(不仅限于含货币符),与预览一致。
b04bc3a5   杨鑫   打印日志 重新打印
441
442
         */
        const currencyGlyph = /[\u00A5\uFFE5€£¥]/.test(text)
58d2e61c   杨鑫   最新代码
443
444
445
        const allowBitmapWhenDisabled =
          options.allowCurrencyBitmapWhenDisabled !== false &&
          (currencyGlyph || type === 'TEXT_PRICE')
b04bc3a5   杨鑫   打印日志 重新打印
446
        const tryTextBitmap =
540ac0e3   杨鑫   前端修改bug
447
          shouldRasterizeTextElement(text, type, config) &&
58d2e61c   杨鑫   最新代码
448
          (!options.disableBitmapText || allowBitmapWhenDisabled)
b04bc3a5   杨鑫   打印日志 重新打印
449
        if (tryTextBitmap) {
a6f5c1af   “wangming”   开发了安卓基座
450
451
452
453
454
455
456
457
458
459
460
461
          const bitmapPatch = createTextBitmapPatch({
            element,
            text,
            dpi,
            align,
          })
          if (bitmapPatch) {
            items.push(bitmapPatch)
            return
          }
        }
  
43d16ca6   杨鑫   打印日志
462
463
        const textForTsc = sanitizeTextForTscBuiltinFont(text)
  
9927b97e   “wangming”   Improve GP_R3 pri...
464
465
466
467
468
469
470
        items.push({
          type: 'text',
          x: resolveTextX({
            align,
            xPx: element.x,
            widthPx: element.width,
            dpi,
43d16ca6   杨鑫   打印日志
471
            text: textForTsc,
9927b97e   “wangming”   Improve GP_R3 pri...
472
473
474
            scale,
          }),
          y: pxToDots(element.y, dpi),
43d16ca6   杨鑫   打印日志
475
          text: textForTsc,
9927b97e   “wangming”   Improve GP_R3 pri...
476
477
478
479
480
481
482
483
484
485
486
          font: 'TSS24.BF2',
          rotation: resolveRotation(element.rotation),
          xScale: scale,
          yScale: scale,
        })
        return
      }
  
      if (type === 'QRCODE') {
        const value = resolveElementDataValue(element, data)
        if (!value) return
43d16ca6   杨鑫   打印日志
487
488
489
490
491
492
493
494
495
496
497
        if (storedValueLooksLikeImagePath(value)) {
          const bitmapPatch = createImageBitmapPatch({
            element: {
              ...element,
              config: { ...config, src: value, url: value, Src: value, Url: value },
            },
            dpi,
          })
          if (bitmapPatch) items.push(bitmapPatch)
          return
        }
a6f5c1af   “wangming”   开发了安卓基座
498
        const level = normalizeQrLevel(getConfigString(config, ['errorLevel'], 'M'))
9927b97e   “wangming”   Improve GP_R3 pri...
499
500
501
502
503
        items.push({
          type: 'qrcode',
          x: pxToDots(element.x, dpi),
          y: pxToDots(element.y, dpi),
          value,
a6f5c1af   “wangming”   开发了安卓基座
504
505
          level,
          cellWidth: resolveQrModuleSize(element.width, element.height, dpi, value, level),
9927b97e   “wangming”   Improve GP_R3 pri...
506
507
508
509
510
511
          mode: 'A',
        })
        return
      }
  
      if (type === 'BARCODE') {
923d50c0   杨鑫   更新bug
512
        const symbology = normalizeBarcodeType(getConfigString(config, ['barcodeType'], ''))
91821909   杨鑫   最新
513
514
        const value = formatBarcodeValueForTsc(resolveElementDataValue(element, data), symbology)
        if (!value) return
923d50c0   杨鑫   更新bug
515
516
517
        const rotation = resolveRotation(
          element.rotation || getConfigString(config, ['orientation'], 'horizontal')
        )
9927b97e   “wangming”   Improve GP_R3 pri...
518
519
520
521
522
        items.push({
          type: 'barcode',
          x: pxToDots(element.x, dpi),
          y: pxToDots(element.y, dpi),
          value,
923d50c0   杨鑫   更新bug
523
          symbology,
9927b97e   “wangming”   Improve GP_R3 pri...
524
525
          height: Math.max(20, pxToDots(element.height, dpi)),
          readable: config.showText !== false,
923d50c0   杨鑫   更新bug
526
          rotation,
9927b97e   “wangming”   Improve GP_R3 pri...
527
528
529
          narrow: clamp(element.width / Math.max(40, value.length * 6), 1, 4),
          wide: clamp(element.width / Math.max(24, value.length * 3), 2, 6),
        })
a6f5c1af   “wangming”   开发了安卓基座
530
531
532
533
        return
      }
  
      if (type === 'IMAGE') {
58d2e61c   杨鑫   最新代码
534
        let bitmapPatch = createImageBitmapPatch({
a6f5c1af   “wangming”   开发了安卓基座
535
536
537
          element,
          dpi,
        })
58d2e61c   杨鑫   最新代码
538
539
540
541
542
543
544
545
546
547
548
549
        if (!bitmapPatch) {
          const boundImage = resolveElementDataValue(element, data)
          if (storedValueLooksLikeImagePath(boundImage)) {
            bitmapPatch = createImageBitmapPatch({
              element: {
                ...element,
                config: { ...config, src: boundImage, url: boundImage, Src: boundImage, Url: boundImage },
              },
              dpi,
            })
          }
        }
a6f5c1af   “wangming”   开发了安卓基座
550
551
552
553
554
555
556
557
558
559
560
561
        if (bitmapPatch) items.push(bitmapPatch)
        return
      }
  
      if (type === 'BLANK' && String(element.border || '').toLowerCase() === 'line') {
        items.push({
          type: 'bar',
          x: pxToDots(element.x, dpi),
          y: pxToDots(element.y, dpi),
          width: Math.max(1, pxToDots(element.width, dpi)),
          height: Math.max(1, pxToDots(element.height || 1, dpi)),
        })
9927b97e   “wangming”   Improve GP_R3 pri...
562
563
564
      }
    })
  
58d2e61c   杨鑫   最新代码
565
566
567
568
569
570
571
572
573
    const maxBottomDots = items.reduce(
      (acc, it) => Math.max(acc, estimateTscItemBottomDots(it)),
      0
    )
    const templateHeightDots = Math.max(1, Math.round((heightMm / 25.4) * dpi))
    if (maxBottomDots > templateHeightDots - 2) {
      heightMm = roundNumber(Math.max(heightMm, (maxBottomDots / dpi) * 25.4 + 2))
    }
  
9927b97e   “wangming”   Improve GP_R3 pri...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
    return {
      widthMm,
      heightMm,
      gapMm: 0,
      density: 14,
      speed: 5,
      printQty,
      items,
    }
  }
  
  function buildEscTemplate (
    template: SystemLabelTemplate,
    data: LabelTemplateData,
    printQty: number
  ): StructuredEscTemplate {
    const pageWidth = templateWidthPx(template)
    const items: EscTemplateItem[] = []
  
    sortElements(template.elements).forEach((element) => {
      const config = element.config || {}
      const type = String(element.type || '').toUpperCase()
      const align = toEscAlign(resolveElementAlign(element, pageWidth))
  
143afd59   杨鑫   打印,标签
598
599
600
601
602
603
604
605
606
607
608
      const renderAsTextBlockEsc =
        type.startsWith('TEXT_') ||
        type === 'WEIGHT' ||
        type === 'DATE' ||
        type === 'TIME' ||
        type === 'DURATION'
  
      if (renderAsTextBlockEsc) {
        const text = type.startsWith('TEXT_')
          ? resolveElementText(element, data)
          : resolvePlainTextLikeElement(element, data)
9927b97e   “wangming”   Improve GP_R3 pri...
609
610
611
612
613
        if (!text) return
        const fontSize = getConfigNumber(config, ['fontSize'], 14)
        const scale = fontSize >= 28 ? 2 : 1
        items.push({
          type: 'text',
43d16ca6   杨鑫   打印日志
614
          text: sanitizeTextForTscBuiltinFont(text),
9927b97e   “wangming”   Improve GP_R3 pri...
615
616
617
618
619
620
621
622
623
624
625
          align,
          bold: String(config.fontWeight || '').toLowerCase() === 'bold',
          widthScale: scale,
          heightScale: scale,
        })
        return
      }
  
      if (type === 'QRCODE') {
        const value = resolveElementDataValue(element, data)
        if (!value) return
a6f5c1af   “wangming”   开发了安卓基座
626
        const level = normalizeQrLevel(getConfigString(config, ['errorLevel'], 'M'))
9927b97e   “wangming”   Improve GP_R3 pri...
627
628
629
630
        items.push({
          type: 'qrcode',
          value,
          align,
a6f5c1af   “wangming”   开发了安卓基座
631
632
          size: resolveQrModuleSize(element.width, element.height, 203, value, level),
          level,
9927b97e   “wangming”   Improve GP_R3 pri...
633
634
635
636
637
        })
        return
      }
  
      if (type === 'BARCODE') {
91821909   杨鑫   最新
638
639
        const symbology = normalizeBarcodeType(getConfigString(config, ['barcodeType'], ''))
        const value = formatBarcodeValueForTsc(resolveElementDataValue(element, data), symbology)
9927b97e   “wangming”   Improve GP_R3 pri...
640
641
642
643
644
        if (!value) return
        items.push({
          type: 'barcode',
          value,
          align,
923d50c0   杨鑫   更新bug
645
          symbology: normalizeBarcodeType(getConfigString(config, ['barcodeType'], '')),
9927b97e   “wangming”   Improve GP_R3 pri...
646
647
648
649
          height: clamp(element.height * 2, 48, 180),
          width: clamp(element.width / Math.max(48, value.length * 4), 2, 6),
          showText: config.showText !== false,
        })
a6f5c1af   “wangming”   开发了安卓基座
650
651
652
653
654
655
656
657
        return
      }
  
      if (type === 'BLANK' && String(element.border || '').toLowerCase() === 'line') {
        items.push({
          type: 'rule',
          width: clamp(element.width / 8, 8, 48),
        })
9927b97e   “wangming”   Improve GP_R3 pri...
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
      }
    })
  
    return {
      printQty,
      feedLines: 3,
      items,
    }
  }
  
  export function adaptSystemLabelTemplate (
    template: SystemLabelTemplate,
    data: LabelTemplateData = {},
    options: {
      dpi?: number
      printQty?: number
4ad9ae43   “wangming”   1111
674
      disableBitmapText?: boolean
58d2e61c   杨鑫   最新代码
675
      allowCurrencyBitmapWhenDisabled?: boolean
9927b97e   “wangming”   Improve GP_R3 pri...
676
677
678
679
680
681
    } = {}
  ): StructuredLabelTemplate {
    const dpi = options.dpi || 203
    const printQty = Math.max(1, Math.round(options.printQty || 1))
    return {
      key: template.id || template.name || 'system-label-template',
4ad9ae43   “wangming”   1111
682
683
      tsc: buildTscTemplate(template, data, dpi, printQty, {
        disableBitmapText: options.disableBitmapText,
58d2e61c   杨鑫   最新代码
684
        allowCurrencyBitmapWhenDisabled: options.allowCurrencyBitmapWhenDisabled,
4ad9ae43   “wangming”   1111
685
      }),
9927b97e   “wangming”   Improve GP_R3 pri...
686
687
688
      esc: buildEscTemplate(template, data, printQty),
    }
  }