<script lang="ts" setup>
|
import type { MesWmBarcodeApi } from '#/api/mes/wm/barcode';
|
|
import { nextTick, ref } from 'vue';
|
|
import { Button, message } from 'ant-design-vue';
|
|
import { createBarcode, getBarcodeByBusiness } from '#/api/mes/wm/barcode';
|
|
import WlsBarcode from './barcode.vue';
|
|
defineOptions({ name: 'WlsPrinterLabel' });
|
|
/** 标签上附加展示的业务字段(可选,默认不展示) */
|
interface LabelField {
|
label: string;
|
value?: number | string;
|
}
|
|
const props = withDefaults(
|
defineProps<{
|
bizCode?: string;
|
bizId?: number;
|
/** 业务名称,作为标签主信息展示在条码下方 */
|
bizName?: string;
|
bizType?: number;
|
/** 标签标题 */
|
title?: string;
|
/** 按钮文案 */
|
labelText?: string;
|
/** 附加字段,一般不需要传 */
|
fields?: LabelField[];
|
}>(),
|
{
|
bizCode: undefined,
|
bizId: undefined,
|
bizName: undefined,
|
bizType: undefined,
|
title: '',
|
labelText: '标签打印',
|
fields: () => [],
|
},
|
);
|
|
const barcodeRef = ref<InstanceType<typeof WlsBarcode>>();
|
const barcode = ref<MesWmBarcodeApi.Barcode>();
|
const renderKey = ref(0);
|
const printing = ref(false);
|
/** 打印窗口:需在用户点击时同步打开,否则会被浏览器拦截 */
|
const printWindow = ref<null | Window>(null);
|
|
function escapeHtml(value: string) {
|
return value
|
.replaceAll('&', '&')
|
.replaceAll('<', '<')
|
.replaceAll('>', '>');
|
}
|
|
/** 构建标签 HTML:标题 + 条码图 + 名称(居中),附加字段可选 */
|
function buildLabelHtml(base64: string) {
|
const nameHtml = props.bizName
|
? `<div class="label-name">${escapeHtml(props.bizName)}</div>`
|
: '';
|
const infoHtml = props.fields
|
.filter((item) => item.value !== undefined && item.value !== '')
|
.map(
|
(item) =>
|
`<p><span class="info-label">${escapeHtml(item.label)}</span>${escapeHtml(String(item.value))}</p>`,
|
)
|
.join('');
|
return `<!DOCTYPE html>
|
<html><head><meta charset="UTF-8"><title>${escapeHtml(props.title || '打印标签')}</title>
|
<style>
|
*{margin:0;padding:0;box-sizing:border-box}
|
body{font-family:Arial,"Microsoft YaHei",sans-serif;display:flex;justify-content:center;padding:12px}
|
.label{width:320px;padding:8px;text-align:center}
|
.label-title{font-size:13px;color:#333;margin-bottom:6px}
|
.label-barcode{width:200px;margin:0 auto}
|
.label-barcode img{display:block;width:100%}
|
.label-name{margin-top:8px;font-size:16px;font-weight:700;line-height:1.4;word-break:break-all}
|
.label-info{margin-top:8px;font-size:12px;line-height:1.6;text-align:left;color:#333}
|
.label-info p{margin:2px 0}
|
.info-label{color:#666;margin-right:4px}
|
.info-label::after{content:":"}
|
@page{margin:5mm}
|
@media print{body{padding:0}.label{width:auto;max-width:100%}}
|
</style>
|
</head><body><div class="label">
|
${props.title ? `<div class="label-title">${escapeHtml(props.title)}</div>` : ''}
|
<div class="label-barcode"><img src="${base64}" alt="条码" /></div>
|
${nameHtml}
|
${infoHtml ? `<div class="label-info">${infoHtml}</div>` : ''}
|
</div></body></html>`;
|
}
|
|
/** 条码图渲染完成,把标签内容写入已打开的打印窗口并调起打印 */
|
function handleBarcodeDone() {
|
const win = printWindow.value;
|
const base64 = barcodeRef.value?.getImageBase64();
|
printWindow.value = null;
|
if (!win || win.closed) {
|
return;
|
}
|
if (!base64) {
|
message.warning('条码渲染失败,无法打印标签');
|
win.close();
|
return;
|
}
|
win.document.open();
|
win.document.write(buildLabelHtml(base64));
|
win.document.close();
|
setTimeout(() => win.print(), 500);
|
}
|
|
/** 打印标签:无条码时先生成,再渲染条码图后打印 */
|
async function handlePrint() {
|
if (!props.bizType || !props.bizId) {
|
message.warning('缺少业务类型或业务编号,无法打印标签');
|
return;
|
}
|
if (printing.value) {
|
return;
|
}
|
// 在用户手势内同步打开窗口,避免弹窗被拦截
|
const win = window.open('', '_blank');
|
if (!win) {
|
message.error('无法打开打印窗口,请检查浏览器设置');
|
return;
|
}
|
win.document.write(
|
'<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body style="font-family:Arial;padding:20px">正在生成标签,请稍候…</body></html>',
|
);
|
printWindow.value = win;
|
printing.value = true;
|
try {
|
let data = await getBarcodeByBusiness(props.bizType, props.bizId);
|
if (!data?.content) {
|
await createBarcode({
|
bizCode: props.bizCode || '',
|
bizId: props.bizId,
|
bizName: props.bizName || '',
|
bizType: props.bizType,
|
});
|
data = await getBarcodeByBusiness(props.bizType, props.bizId);
|
}
|
if (!data?.content) {
|
message.warning('条码生成失败,无法打印标签');
|
win.close();
|
printWindow.value = null;
|
return;
|
}
|
barcode.value = data;
|
renderKey.value += 1;
|
await nextTick();
|
} catch {
|
message.error('打印标签失败,请重试');
|
win.close();
|
printWindow.value = null;
|
} finally {
|
printing.value = false;
|
}
|
}
|
</script>
|
|
<template>
|
<Button :loading="printing" @click="handlePrint">
|
{{ labelText }}
|
</Button>
|
<!-- 隐藏的条码渲染容器,渲染完成后取出图片写入打印窗口 -->
|
<div
|
v-if="barcode?.content"
|
class="pointer-events-none fixed top-0 -left-[9999px] h-0 w-0 overflow-hidden"
|
>
|
<WlsBarcode
|
:key="renderKey"
|
ref="barcodeRef"
|
:content="barcode.content"
|
:format="barcode.format"
|
:height="150"
|
:width="280"
|
@done="handleBarcodeDone"
|
/>
|
</div>
|
</template>
|