From 077d36ebdf699961b9e66dd21e13b509240f8f79 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期五, 23 十月 2026 15:43:31 +0800
Subject: [PATCH] feat: 完善设备数采与标签打印功能
---
src/views/wls/barcode/components/printer-label.vue | 200 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 195 insertions(+), 5 deletions(-)
diff --git a/src/views/wls/barcode/components/printer-label.vue b/src/views/wls/barcode/components/printer-label.vue
index 7fbeee5..84b4149 100644
--- a/src/views/wls/barcode/components/printer-label.vue
+++ b/src/views/wls/barcode/components/printer-label.vue
@@ -1,30 +1,220 @@
<script lang="ts" setup>
+import type { MesWmBarcodeApi } from '#/api/mes/wm/barcode';
+
+import { ref } from 'vue';
+
+import { BarcodeBizTypeEnum } from '@vben/constants';
+
import { Button, message } from 'ant-design-vue';
+
+import {
+ getBarcodeByBusiness,
+ renderBarcodeImage,
+} from '#/api/mes/wm/barcode';
defineOptions({ name: 'WlsPrinterLabel' });
-withDefaults(
+const props = withDefaults(
defineProps<{
bizCode?: string;
bizId?: number;
- bizType?: string;
+ bizName?: string;
+ bizType?: number | string;
labelText?: string;
}>(),
{
bizCode: undefined,
bizId: undefined,
+ bizName: undefined,
bizType: undefined,
labelText: '鏍囩鎵撳嵃',
},
);
-function handlePrint() {
- message.warning('鏍囩鎵撳嵃鍔熻兘鏆傛湭瀹炵幇锛屾暚璇锋湡寰�');
+const printing = ref(false);
+
+function resolveBizType(value?: number | string) {
+ if (typeof value === 'number') {
+ return value;
+ }
+ const normalized = value?.trim().toUpperCase();
+ if (!normalized) {
+ return undefined;
+ }
+ // ITEM_BATCH 鏄儴鍒嗗叆搴撻〉闈㈡部鐢ㄧ殑鏃у埆鍚嶏紝瀹為檯浠嶅搴斺�滄壒娆♀�濄��
+ if (normalized === 'ITEM_BATCH') {
+ return BarcodeBizTypeEnum.BATCH;
+ }
+ const numericValue = Number(normalized);
+ if (Number.isInteger(numericValue)) {
+ return numericValue;
+ }
+ const enumValue =
+ BarcodeBizTypeEnum[
+ normalized as keyof typeof BarcodeBizTypeEnum
+ ];
+ return typeof enumValue === 'number' ? enumValue : undefined;
+}
+
+function getBizTypeLabel(bizType: number) {
+ const labels: Partial<Record<BarcodeBizTypeEnum, string>> = {
+ [BarcodeBizTypeEnum.AREA]: '搴撲綅',
+ [BarcodeBizTypeEnum.BATCH]: '鎵规',
+ [BarcodeBizTypeEnum.CLIENT]: '瀹㈡埛',
+ [BarcodeBizTypeEnum.ITEM]: '鐗╂枡',
+ [BarcodeBizTypeEnum.LOCATION]: '搴撳尯',
+ [BarcodeBizTypeEnum.MACHINERY]: '璁惧',
+ [BarcodeBizTypeEnum.PACKAGE]: '瑁呯鍗�',
+ [BarcodeBizTypeEnum.PROCARD]: '娴佽浆鍗�',
+ [BarcodeBizTypeEnum.SN]: 'SN 鐮�',
+ [BarcodeBizTypeEnum.STOCK]: '搴撳瓨',
+ [BarcodeBizTypeEnum.TOOL]: '宸ュ叿',
+ [BarcodeBizTypeEnum.USER]: '浜哄憳',
+ [BarcodeBizTypeEnum.VENDOR]: '渚涘簲鍟�',
+ [BarcodeBizTypeEnum.WAREHOUSE]: '浠撳簱',
+ [BarcodeBizTypeEnum.WORKORDER]: '宸ュ崟',
+ [BarcodeBizTypeEnum.WORKSHOP]: '杞﹂棿',
+ [BarcodeBizTypeEnum.WORKSTATION]: '宸ヤ綔绔�',
+ };
+ return labels[bizType as BarcodeBizTypeEnum] || '涓氬姟';
+}
+
+function escapeHtml(value?: null | string) {
+ return (value || '')
+ .replaceAll('&', '&')
+ .replaceAll('<', '<')
+ .replaceAll('>', '>')
+ .replaceAll('"', '"')
+ .replaceAll("'", ''');
+}
+
+async function getBarcodeForPrint(bizType: number) {
+ const barcode = await getBarcodeByBusiness(bizType, props.bizId!);
+ if (barcode?.content) {
+ return barcode;
+ }
+ if (!props.bizCode) {
+ throw new Error('缂哄皯涓氬姟缂栫爜锛屾棤娉曟墦鍗版爣绛�');
+ }
+
+ // 鍘嗗彶鎵规鍙兘鏈厤缃潯鐮佽鍒欍�傛鏃朵娇鐢ㄤ笟鍔$紪鐮佸嵆鏃剁敓鎴� CODE128锛�
+ // 鍙敤浜庢湰娆℃墦鍗帮紝涓嶅啓鍏ユ潯鐮佽〃锛岄伩鍏嶁�滄潯鐮侀厤缃笉瀛樺湪鈥濋樆鏂笟鍔°��
+ return {
+ bizCode: props.bizCode,
+ bizId: props.bizId,
+ bizName: props.bizName || props.bizCode,
+ bizType,
+ content: props.bizCode,
+ } satisfies MesWmBarcodeApi.Barcode;
+}
+
+function writePrintDocument(
+ printWindow: Window,
+ barcode: MesWmBarcodeApi.Barcode,
+ imageBase64: string,
+ bizType: number,
+) {
+ const typeLabel = getBizTypeLabel(bizType);
+ const isQrCode = barcode.format === 1;
+ printWindow.document.open();
+ printWindow.document.write(`<!doctype html>
+<html lang="zh-CN">
+<head>
+ <meta charset="UTF-8" />
+ <title>${escapeHtml(typeLabel)}鏍囩</title>
+ <style>
+ @page { size: 80mm 55mm; margin: 0; }
+ * { box-sizing: border-box; }
+ html, body { width: 80mm; height: 55mm; margin: 0; color: #000; font-family: "Microsoft YaHei", Arial, sans-serif; }
+ .label { width: 80mm; height: 55mm; padding: 3mm; border: .35mm solid #000; display: grid; grid-template-columns: ${isQrCode ? '31mm 1fr' : '1fr'}; gap: 3mm; overflow: hidden; }
+ .barcode { display: flex; align-items: center; justify-content: center; min-width: 0; }
+ .barcode img { display: block; max-width: 100%; max-height: ${isQrCode ? '38mm' : '22mm'}; object-fit: contain; }
+ .info { min-width: 0; display: flex; flex-direction: column; justify-content: center; }
+ .title { margin-bottom: 2mm; padding-bottom: 1.5mm; border-bottom: .3mm solid #000; font-size: 15pt; font-weight: 700; text-align: center; }
+ .row { margin: .8mm 0; font-size: 9.5pt; line-height: 1.35; overflow-wrap: anywhere; }
+ .key { font-weight: 700; }
+ .content { margin-top: 1mm; font-family: Consolas, monospace; font-size: 7.5pt; text-align: center; overflow-wrap: anywhere; }
+ ${isQrCode ? '' : '.label { grid-template-rows: auto 1fr; } .barcode { order: 2; } .info { order: 1; } .title { margin-bottom: 1mm; } .row { display: inline-block; margin-right: 4mm; }'}
+ @media screen { body { margin: 8px; } }
+ </style>
+</head>
+<body>
+ <main class="label">
+ <section class="barcode">
+ <img src="${imageBase64}" alt="${escapeHtml(typeLabel)}鏉$爜" />
+ </section>
+ <section class="info">
+ <div class="title">${escapeHtml(typeLabel)}鏍囩</div>
+ <div class="row"><span class="key">涓氬姟缂栫爜锛�</span>${escapeHtml(barcode.bizCode || props.bizCode)}</div>
+ <div class="row"><span class="key">涓氬姟鍚嶇О锛�</span>${escapeHtml(barcode.bizName || props.bizName || '-')}</div>
+ <div class="content">${escapeHtml(barcode.content)}</div>
+ </section>
+ </main>
+ <script>
+ window.addEventListener('load', function () {
+ window.focus();
+ window.onafterprint = function () { window.close(); };
+ setTimeout(function () { window.print(); }, 150);
+ });
+ <\/script>
+</body>
+</html>`);
+ printWindow.document.close();
+}
+
+async function handlePrint() {
+ if (printing.value) {
+ return;
+ }
+ const bizType = resolveBizType(props.bizType);
+ if (!props.bizId || !bizType) {
+ message.warning('缂哄皯涓氬姟绫诲瀷鎴栦笟鍔$紪鍙凤紝鏃犳硶鎵撳嵃鏍囩');
+ return;
+ }
+
+ // 鍦ㄧ敤鎴风偣鍑讳簨浠朵腑鍚屾鎵撳紑绐楀彛锛岄伩鍏嶅紓姝ヨ姹傜粨鏉熷悗琚祻瑙堝櫒鎷︽埅銆�
+ const printWindow = window.open('', '_blank', 'width=900,height=650');
+ if (!printWindow) {
+ message.error('鏃犳硶鎵撳紑鎵撳嵃绐楀彛锛岃鍏佽娴忚鍣ㄥ脊鍑虹獥鍙e悗閲嶈瘯');
+ return;
+ }
+ printWindow.opener = null;
+ printWindow.document.write(
+ '<!doctype html><html><head><meta charset="UTF-8"><title>鐢熸垚鏍囩</title></head><body style="font-family:Microsoft YaHei;padding:24px">姝e湪鐢熸垚鏍囩锛岃绋嶅�欌�︹��</body></html>',
+ );
+ printWindow.document.close();
+
+ printing.value = true;
+ try {
+ const barcode = await getBarcodeForPrint(bizType);
+ const isQrCode = barcode.format === 1;
+ const imageBase64 = await renderBarcodeImage(
+ barcode.content!,
+ barcode.format,
+ isQrCode ? 360 : 720,
+ isQrCode ? 360 : 220,
+ );
+ if (!imageBase64?.startsWith('data:image/png;base64,')) {
+ throw new Error('鏈嶅姟绔湭杩斿洖鏈夋晥鐨勬爣绛惧浘鐗�');
+ }
+ if (!printWindow.closed) {
+ writePrintDocument(printWindow, barcode, imageBase64, bizType);
+ }
+ } catch (error) {
+ if (!printWindow.closed) {
+ printWindow.close();
+ }
+ const errorMessage =
+ error instanceof Error ? error.message : '鏍囩鎵撳嵃澶辫触锛岃绋嶅悗閲嶈瘯';
+ message.error(errorMessage);
+ } finally {
+ printing.value = false;
+ }
}
</script>
<template>
- <Button type="link" @click="handlePrint">
+ <Button :loading="printing" type="link" @click="handlePrint">
{{ labelText }}
</Button>
</template>
--
Gitblit v1.9.3