<script lang="ts" setup>
|
import type Barcode from './barcode.vue';
|
|
import type { MesWmBarcodeApi } from '#/api/mes/wm/barcode';
|
|
import { ref } from 'vue';
|
|
import { Button, Empty, message, Modal, Tooltip } from 'ant-design-vue';
|
|
import { createBarcode, getBarcodeByBusiness } from '#/api/mes/wm/barcode';
|
import { useDescription } from '#/components/description';
|
|
import { useBarcodeDetailSchema } from '../data';
|
import WlsBarcode from './barcode.vue';
|
|
defineOptions({ name: 'WlsBarcodeDetail' });
|
|
const open = ref(false);
|
const barcodeRef = ref<InstanceType<typeof Barcode>>();
|
const barcodeData = ref<Partial<MesWmBarcodeApi.Barcode>>({});
|
|
const [Descriptions] = useDescription({
|
bordered: true,
|
column: 1,
|
schema: useBarcodeDetailSchema(),
|
useCard: false,
|
labelStyle: { width: '80px', whiteSpace: 'nowrap' },
|
});
|
|
function openModal(row: Partial<MesWmBarcodeApi.Barcode>) {
|
open.value = true;
|
barcodeData.value = { ...row };
|
}
|
|
async function openByBusiness(
|
bizId: number,
|
bizType: number,
|
bizCode?: string,
|
bizName?: string,
|
) {
|
open.value = true;
|
try {
|
const data = await getBarcodeByBusiness(bizType, bizId);
|
barcodeData.value = data || {
|
bizCode,
|
bizId,
|
bizName,
|
bizType,
|
content: '',
|
};
|
if (!data) {
|
message.warning('未找到对应条码数据');
|
}
|
} catch {
|
barcodeData.value = { bizCode, bizId, bizName, bizType, content: '' };
|
message.error('加载条码数据失败');
|
}
|
}
|
|
defineExpose({ open: openModal, openByBusiness });
|
|
function escapeHtml(value: string) {
|
return value
|
.replaceAll('&', '&')
|
.replaceAll('<', '<')
|
.replaceAll('>', '>');
|
}
|
|
function handlePrint() {
|
const base64 = barcodeRef.value?.getImageBase64();
|
if (!base64) {
|
message.warning('条码生成失败,无法打印');
|
return;
|
}
|
const printWindow = window.open('', '_blank');
|
if (!printWindow) {
|
message.error('无法打开打印窗口,请检查浏览器设置');
|
return;
|
}
|
printWindow.document.write(`<!DOCTYPE html>
|
<html><head><meta charset="UTF-8"><title>打印条码</title>
|
<style>*{margin:0;padding:0}body{font-family:Arial,sans-serif;padding:20px}.print-container{text-align:center}.barcode-img{max-width:100%;margin:20px 0}.info{margin-top:20px;text-align:left;font-size:12px}.info p{margin:5px 0}@media print{body{padding:0}.print-container{padding:20px}}</style>
|
</head><body><div class="print-container">
|
<img src="${base64}" class="barcode-img" alt="条码" />
|
<div class="info">
|
<p><strong>业务编码:</strong> ${escapeHtml(barcodeData.value.bizCode || '')}</p>
|
<p><strong>业务名称:</strong> ${escapeHtml(barcodeData.value.bizName || '')}</p>
|
<p><strong>条码内容:</strong> ${escapeHtml(barcodeData.value.content || '')}</p>
|
</div></div></body></html>`);
|
printWindow.document.close();
|
printWindow.addEventListener('load', () => {
|
setTimeout(() => printWindow.print(), 500);
|
});
|
}
|
|
function handleDownload() {
|
const base64 = barcodeRef.value?.getImageBase64();
|
if (!base64) {
|
message.warning('条码生成失败,无法下载');
|
return;
|
}
|
|
const canvas = document.createElement('canvas');
|
const ctx = canvas.getContext('2d');
|
if (!ctx) {
|
message.error('Canvas 初始化失败');
|
return;
|
}
|
|
const img = new Image();
|
img.onload = () => {
|
const padding = 20;
|
const infoX = img.width + padding * 2;
|
const infoWidth = 320;
|
canvas.width = infoX + infoWidth + padding;
|
canvas.height = Math.max(img.height + padding * 2, 360);
|
|
ctx.fillStyle = '#ffffff';
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
ctx.drawImage(img, padding, padding);
|
|
ctx.fillStyle = '#000000';
|
let y = padding + 10;
|
const lineHeight = 26;
|
|
// 获取字典文本的辅助函数
|
const getFormatText = (val?: number) => {
|
const map: Record<number, string> = { 1: 'QR_CODE', 2: 'CODE_128', 3: 'CODE_39', 4: 'EAN_13', 5: 'UPC_A' };
|
return map[val || 1] || 'QR_CODE';
|
};
|
const getBizTypeText = (val?: number) => {
|
const map: Record<number, string> = { 1: '仓库', 2: '库区', 3: '库位', 4: '物料', 5: '客户', 6: '供应商', 7: '工单', 8: '设备', 9: '工具', 10: '人员', 11: '工作站', 12: '车间', 13: '库存', 14: '流转卡', 15: '装箱单', 16: '批次' };
|
return map[val || 1] || '-';
|
};
|
const getStatusText = (val?: number) => val === 0 ? '禁用' : '启用';
|
|
const items = [
|
{ label: '条码格式', value: getFormatText(barcodeData.value.format) },
|
{ label: '业务类型', value: getBizTypeText(barcodeData.value.bizType) },
|
{ label: '业务编码', value: barcodeData.value.bizCode },
|
{ label: '业务名称', value: barcodeData.value.bizName },
|
{ label: '条码内容', value: barcodeData.value.content },
|
{ label: '状态', value: getStatusText(barcodeData.value.status) },
|
];
|
|
items.forEach((item) => {
|
ctx.font = 'bold 13px Arial, sans-serif';
|
ctx.fillText(`${item.label}:`, infoX, y);
|
y += 18;
|
ctx.font = '13px Arial, sans-serif';
|
const text = item.value || '-';
|
// 处理长文本换行
|
const maxWidth = infoWidth - 10;
|
if (ctx.measureText(text).width > maxWidth) {
|
let currentText = text;
|
while (currentText.length > 0) {
|
let line = '';
|
for (let i = 0; i < currentText.length; i++) {
|
const testLine = line + currentText[i];
|
if (ctx.measureText(testLine).width > maxWidth) break;
|
line = testLine;
|
}
|
ctx.fillText(line, infoX + 5, y);
|
y += 16;
|
currentText = currentText.slice(line.length);
|
}
|
y += 6;
|
} else {
|
ctx.fillText(text, infoX + 5, y);
|
y += lineHeight;
|
}
|
});
|
|
const link = document.createElement('a');
|
link.href = canvas.toDataURL('image/png');
|
link.download = `barcode_${barcodeData.value.bizCode || 'unknown'}_${Date.now()}.png`;
|
link.click();
|
message.success('下载成功');
|
};
|
img.src = base64;
|
}
|
|
async function handleGenerate() {
|
const { bizCode, bizId, bizName, bizType } = barcodeData.value;
|
if (!bizType || !bizId) {
|
message.warning('缺少业务类型或业务编号,无法生成条码');
|
return;
|
}
|
await createBarcode({
|
bizCode: bizCode || '',
|
bizId,
|
bizName: bizName || '',
|
bizType,
|
});
|
message.success('条码生成成功');
|
const data = await getBarcodeByBusiness(bizType, bizId);
|
if (data) {
|
barcodeData.value = { ...data };
|
}
|
}
|
</script>
|
|
<template>
|
<Modal v-model:open="open" title="查看条码" width="750px">
|
<div>
|
<div class="mb-5 flex min-h-50 items-center rounded bg-gray-100 p-5">
|
<div v-if="barcodeData.content" class="flex w-full items-center gap-6">
|
<div class="flex-shrink-0">
|
<WlsBarcode
|
ref="barcodeRef"
|
:content="barcodeData.content"
|
:format="barcodeData.format"
|
:height="150"
|
:width="280"
|
/>
|
</div>
|
<div class="flex-1">
|
<Descriptions :data="barcodeData">
|
<template #content>
|
<Tooltip :title="barcodeData.content">
|
<span
|
class="inline-block max-w-60 overflow-hidden text-ellipsis whitespace-nowrap"
|
>
|
{{ barcodeData.content }}
|
</span>
|
</Tooltip>
|
</template>
|
</Descriptions>
|
</div>
|
</div>
|
<Empty v-else description="暂无条码数据" class="flex-1" />
|
</div>
|
</div>
|
<template #footer>
|
<Button v-if="!barcodeData.content" @click="handleGenerate">
|
生成
|
</Button>
|
<Button type="primary" @click="handlePrint">打印</Button>
|
<Button @click="handleDownload">下载</Button>
|
<Button @click="open = false">关闭</Button>
|
</template>
|
</Modal>
|
</template>
|