From d7e2b6d0b81278f944ae9be86c2145bd7af32600 Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Tue, 19 Aug 2025 13:44:29 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=B3=BB=E7=BB=9F=E5=AD=97?= =?UTF-8?q?=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/labelSetting/label_setting.js | 2 + src/utils/zplGenerator.js | 192 ++++++++++- .../modules/labelSetting/LabelDesigner.vue | 34 +- .../components/DataSourceDialog.vue | 11 - .../components/ElementCombinationDialog.vue | 2 +- .../labelSetting/components/PropertyForm.vue | 315 +++++++++++++++++- .../labelSetting/components/PropertyPanel.vue | 20 +- .../labelSetting/components/ZPLPreview.vue | 4 +- 8 files changed, 541 insertions(+), 39 deletions(-) diff --git a/src/api/labelSetting/label_setting.js b/src/api/labelSetting/label_setting.js index 3d59b7d..48b1528 100644 --- a/src/api/labelSetting/label_setting.js +++ b/src/api/labelSetting/label_setting.js @@ -30,3 +30,5 @@ export const exportPreviewToPdf = (data) => { export const exportRealDataPreviewToPdf = (data) => { return createAPI('/label/setting/exportRealDataPreviewToPdf', 'post', data, 'download') } + +export const availableFont = data => createAPI('/font/available','post',data) diff --git a/src/utils/zplGenerator.js b/src/utils/zplGenerator.js index a9edda2..1bc03d8 100644 --- a/src/utils/zplGenerator.js +++ b/src/utils/zplGenerator.js @@ -119,15 +119,23 @@ export class ZPLGenerator { */ generateTextZPL(element, x, y) { const zpl = [] - // 设置中文字体 - zpl.push(`^CI28 ^CWJ,E:MSYH.TTF ^CFJ,${element.fontSize}`) + + // 生成字体命令 + const fontCommand = this.generateFontCommand(element) + zpl.push(fontCommand) + if (element.isChecked) { zpl.push(`^FO${x-60},${y}^GB45,45,2,B,0^FS ^FO${x-50},${y+10}^AJN,35,35^FD√^FS `) } + const lineWidth = Math.max(1, Math.round((element.lineWidth || 200) * this.dpi / 25.4)) + + // 处理文本对齐 + const alignmentParam = this.getTextAlignmentParam(element.textAlign) + // 基础文本 const textCommand = element.newline - ? `^FO${x},${y}^FB${lineWidth},${element.lineRows},0^CFJ,${element.fontSize}^FD${element.data}^FS` + ? `^FO${x},${y}^FB${lineWidth},${element.lineRows},0,${alignmentParam}^CFJ,${element.fontSize}^FD${element.data}^FS` : `^FO${x},${y}^FD${element.data}^FS` zpl.push(textCommand) @@ -135,9 +143,9 @@ export class ZPLGenerator { // 加粗效果(通过偏移重复打印实现) if (element.bold) { const boldCommands = element.newline ? [ - `^FO${x + 1},${y}^FB${lineWidth},${element.lineRows},0^CFJ,${element.fontSize}^FD${element.data}^FS`, - `^FO${x},${y + 1}^FB${lineWidth},${element.lineRows},0^CFJ,${element.fontSize}^FD${element.data}^FS`, - `^FO${x + 1},${y + 1}^FB${lineWidth},${element.lineRows},0^CFJ,${element.fontSize}^FD${element.data}^FS` + `^FO${x + 1},${y}^FB${lineWidth},${element.lineRows},0,${alignmentParam}^CFJ,${element.fontSize}^FD${element.data}^FS`, + `^FO${x},${y + 1}^FB${lineWidth},${element.lineRows},0,${alignmentParam}^CFJ,${element.fontSize}^FD${element.data}^FS`, + `^FO${x + 1},${y + 1}^FB${lineWidth},${element.lineRows},0,${alignmentParam}^CFJ,${element.fontSize}^FD${element.data}^FS` ] : [ `^FO${x + 1},${y}^FD${element.data}^FS`, `^FO${x},${y + 1}^FD${element.data}^FS`, @@ -147,9 +155,163 @@ export class ZPLGenerator { zpl.push(...boldCommands) } + // 下划线效果(通过线条实现) + if (element.fontUnderline) { + const textWidth = this.estimateTextWidth(element.data, element.fontSize) + const underlineY = y + element.fontSize + 2 + zpl.push(`^FO${x},${underlineY}^GB${textWidth},2,2,B^FS`) + } + return zpl.join('\n') } + /** + * 生成字体命令 + */ + generateFontCommand(element) { + let fontCmd = '^CI28' // 设置字符编码 + + // 根据字体族选择字体文件 + const fontFamily = element.fontFamily + if (fontFamily && fontFamily !== 'default') { + const fontFile = this.mapFontFamilyToFile(fontFamily) + if (fontFile) { + fontCmd += ` ^CWJ,E:${fontFile}` + console.log(`ZPL字体映射: ${fontFamily} -> ${fontFile}`) + } else { + fontCmd += ' ^CWJ,E:MSYH.TTF' // 默认字体 + console.warn(`未找到字体映射: ${fontFamily},使用默认字体`) + } + } else { + fontCmd += ' ^CWJ,E:MSYH.TTF' // 默认字体 + console.log('使用默认字体: MSYH.TTF') + } + + // 设置字体大小 + const fontSize = element.fontSize || 30 + fontCmd += ` ^CFJ,${fontSize}` + + // 添加调试信息 + console.log(`生成字体命令: ${fontCmd}`) + console.log(`字体族: ${fontFamily}, 字体大小: ${fontSize}`) + + return fontCmd + } + + /** + * 映射字体族到字体文件 + */ + mapFontFamilyToFile(fontFamily) { + const fontMapping = { + // 中文字体 + 'Microsoft YaHei': 'MSYH.TTF', + '微软雅黑': 'MSYH.TTF', + 'SimSun': 'SIMSUN.TTC', + '宋体': 'SIMSUN.TTC', + 'SimHei': 'SIMHEI.TTF', + '黑体': 'SIMHEI.TTF', + 'KaiTi': 'KAITI.TTF', + '楷体': 'KAITI.TTF', + 'FangSong': 'SIMFANG.TTF', + '仿宋': 'SIMFANG.TTF', + 'Microsoft JhengHei': 'MSJH.TTF', + '微軟正黑體': 'MSJH.TTF', + 'PMingLiU': 'PMINGLIU.TTF', + '新細明體': 'PMINGLIU.TTF', + 'DFKai-SB': 'DFKAI.TTF', + '標楷體': 'DFKAI.TTF', + + // 英文字体 + 'Arial': 'ARIAL.TTF', + 'Times New Roman': 'TIMES.TTF', + 'Courier New': 'COUR.TTF', + 'Helvetica': 'HELV.TTF', + 'Verdana': 'VERDANA.TTF', + 'Georgia': 'GEORGIA.TTF', + 'Tahoma': 'TAHOMA.TTF', + 'Trebuchet MS': 'TREBUC.TTF', + 'Lucida Console': 'LUCON.TTF', + 'Impact': 'IMPACT.TTF', + 'Comic Sans MS': 'COMIC.TTF', + 'Palatino': 'PALA.TTF', + 'Garamond': 'GARA.TTF', + 'Bookman': 'BOOKOS.TTF', + 'Century Gothic': 'CENTURY.TTF', + 'Franklin Gothic': 'FRANKLIN.TTF', + 'Gill Sans': 'GILLSANS.TTF', + 'Optima': 'OPTIMA.TTF', + 'Futura': 'FUTURA.TTF', + 'Bodoni': 'BODONI.TTF', + 'Didot': 'DIDOT.TTF', + + // 等宽字体 + 'Consolas': 'CONSOLAS.TTF', + 'Monaco': 'MONACO.TTF', + 'Menlo': 'MENLO.TTF', + 'Source Code Pro': 'SOURCECODE.TTF', + 'Fira Code': 'FIRACODE.TTF', + 'JetBrains Mono': 'JETBRAINS.TTF', + + // 装饰字体 + 'Brush Script MT': 'BRUSHSCRIPT.TTF', + 'Papyrus': 'PAPYRUS.TTF', + 'Chalkboard': 'CHALKBOARD.TTF', + 'Marker Felt': 'MARKERFELT.TTF', + 'Zapfino': 'ZAPFINO.TTF', + 'Snell Roundhand': 'SNELLROUND.TTF', + + // 默认字体 + 'default': 'MSYH.TTF', + 'Default': 'MSYH.TTF' + } + + // 如果找不到精确匹配,尝试模糊匹配 + if (!fontMapping[fontFamily]) { + const lowerFontFamily = fontFamily.toLowerCase() + for (const [key, value] of Object.entries(fontMapping)) { + if (key.toLowerCase().includes(lowerFontFamily) || lowerFontFamily.includes(key.toLowerCase())) { + return value + } + } + } + + return fontMapping[fontFamily] || 'MSYH.TTF' // 默认返回微软雅黑 + } + + /** + * 获取文本对齐参数 + */ + getTextAlignmentParam(textAlign) { + switch (textAlign) { + case 'center': return 'C' + case 'right': return 'R' + case 'left': + default: return 'L' + } + } + + /** + * 估算文本宽度(用于下划线) + */ + estimateTextWidth(text, fontSize) { + if (!text) return 0 + + // 简单估算:中文字符按字体大小计算,英文字符按字体大小的0.6倍计算 + let chineseCount = 0 + let englishCount = 0 + + for (let i = 0; i < text.length; i++) { + const char = text.charAt(i) + if (char.match(/[\u4e00-\u9fff]/)) { + chineseCount++ + } else { + englishCount++ + } + } + + return Math.round(chineseCount * fontSize + englishCount * fontSize * 0.6) + } + /** * 生成一维码ZPL代码 */ @@ -274,18 +436,22 @@ export class ZPLGenerator { */ generateSerialNumberZPL(element, x, y) { const zpl = [] - // 设置中文字体 - zpl.push(`^CI28 ^CWJ,E:MSYH.TTF ^CFJ,${element.fontSize}`) - const bold = element.bold || false // 加粗(可选) - const serialStr = '流水号' + + // 生成字体命令 + const fontCommand = this.generateFontCommand(element) + zpl.push(fontCommand) + + const bold = element.bold || false const base = `^FO${x},${y}^FD${element.data}^FS` zpl.push(base) + // 可选:加粗效果(重复打印) if (bold) { - zpl.push(`^FO${x + 1},${y}^FD${serialStr}^FS`) - zpl.push(`^FO${x},${y + 1}^FD${serialStr}^FS`) - zpl.push(`^FO${x + 1},${y + 1}^FD${serialStr}^FS`) + zpl.push(`^FO${x + 1},${y}^FD${element.data}^FS`) + zpl.push(`^FO${x},${y + 1}^FD${element.data}^FS`) + zpl.push(`^FO${x + 1},${y + 1}^FD${element.data}^FS`) } + return zpl.join('\n') } } diff --git a/src/views/modules/labelSetting/LabelDesigner.vue b/src/views/modules/labelSetting/LabelDesigner.vue index 6e2bb8d..86ffc22 100644 --- a/src/views/modules/labelSetting/LabelDesigner.vue +++ b/src/views/modules/labelSetting/LabelDesigner.vue @@ -126,6 +126,7 @@ @preview="handlePreview" @data-source="handleDataSource" @element-combination="handleElementCombination" + @font-changed="handleFontChanged" /> @@ -448,8 +449,10 @@ export default { // 修复:对每个元素补全属性,保证响应式 const defaultElement = { type: '', x: 0, y: 0, data: '', fontSize: 30, bold: false, newline: false, lineRows: 2, - lineWidth: 200, digits: 6, step: 1, width: 100, height: 30, previewUrl: '', barcodeType: '', showContent: true,showElement:true, - showMainSeq:false,seqName:'',isChecked:false,decimalPlaces:'',showDecimalPlaces:false,thousandsSeparator:false + lineWidth: 200, digits: 6, step: 1, width: 100, height: 30, previewUrl: '', barcodeType: '', showContent: true, showElement: true, + showMainSeq: false, seqName: '', isChecked: false, decimalPlaces: '', showDecimalPlaces: false, thousandsSeparator: false, + // 字体相关属性 + fontFamily: 'default', textAlign: 'left', letterSpacing: 0, fontItalic: false, fontUnderline: false }; this.elements = (data.data || []).map(item => { const element = Object.assign({}, defaultElement, item); @@ -512,7 +515,13 @@ export default { width: 100, height: 30, data: '', - isChecked:false, + isChecked: false, + // 字体相关属性 + fontFamily: 'default', + textAlign: 'left', + letterSpacing: 0, + fontItalic: false, + fontUnderline: false, }, onecode: { width: 2, // 默认宽度2mm @@ -899,6 +908,25 @@ export default { if (this.zplGenerator && this.zplGenerator.updatePaperId) { this.zplGenerator.updatePaperId(this.selectedPaper) } + }, + + // 处理字体变化 + handleFontChanged(fontData) { + console.log('LabelDesigner收到字体变化事件:', fontData) + + if (fontData && fontData.elementId && this.selectedElement && this.selectedElement.id === fontData.elementId) { + // 确保字体值正确设置 + this.$set(this.selectedElement, 'fontFamily', fontData.fontFamily) + console.log('字体已更新:', this.selectedElement.fontFamily) + + // 强制更新画布 + this.canvasUpdateKey++ + + // 触发ZPL预览更新 + this.$nextTick(() => { + this.$emit('font-updated', fontData) + }) + } } }, diff --git a/src/views/modules/labelSetting/components/DataSourceDialog.vue b/src/views/modules/labelSetting/components/DataSourceDialog.vue index c8b4f0f..bc9e60c 100644 --- a/src/views/modules/labelSetting/components/DataSourceDialog.vue +++ b/src/views/modules/labelSetting/components/DataSourceDialog.vue @@ -85,17 +85,6 @@ export default { foundKeys.push(key.fieldName) } }) - if (this.sourceType==='serialNumber'){ - this.dataKeys.forEach(key => { - // 构建字段匹配的正则,确保全字匹配 - const pattern = new RegExp(`\\b${key.fieldName}\\b`, 'g') - - if (pattern.test(this.currentText)) { - foundKeys.push(key.fieldName) - } - }) - - } this.selectedKeys = foundKeys }, diff --git a/src/views/modules/labelSetting/components/ElementCombinationDialog.vue b/src/views/modules/labelSetting/components/ElementCombinationDialog.vue index 0b033d7..ba9b50f 100644 --- a/src/views/modules/labelSetting/components/ElementCombinationDialog.vue +++ b/src/views/modules/labelSetting/components/ElementCombinationDialog.vue @@ -11,7 +11,7 @@ >
-
+

目标元素:{{ targetElement.type === 'onecode' ? '一维码' : '二维码' }}

当前数据:{{ targetElement.data || '(空)' }}

diff --git a/src/views/modules/labelSetting/components/PropertyForm.vue b/src/views/modules/labelSetting/components/PropertyForm.vue index 846c386..8858a4f 100644 --- a/src/views/modules/labelSetting/components/PropertyForm.vue +++ b/src/views/modules/labelSetting/components/PropertyForm.vue @@ -39,6 +39,50 @@
+ +
+ + + + + {{ font.name }} + + {{ font.description }} + + + + + + + + + + + + + +
+
+
+ +