✨ feat:
修改二维码生成逻辑,改为一次性二维码,存储更多信息
This commit is contained in:
295
klp-ui/src/views/wms/print/components/CodeRenderer.vue
Normal file
295
klp-ui/src/views/wms/print/components/CodeRenderer.vue
Normal file
@@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<div class="barcode-simple-layout">
|
||||
<!-- 仅保留预览区 -->
|
||||
<div class="barcode-preview-area">
|
||||
<div class="iframe-wrapper">
|
||||
<iframe ref="previewIframe" class="barcode-iframe" frameborder="0" :style="iframeStyle"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QRCode from 'qrcode';
|
||||
export default {
|
||||
name: 'BarcodeRenderer',
|
||||
props: {
|
||||
barcodes: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
// 可通过props传入配置,保持一定灵活性
|
||||
layoutConfig: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
perRow: 3,
|
||||
barcodeWidth: 180,
|
||||
paperSize: 'A4',
|
||||
paperOrientation: 'portrait',
|
||||
customPaperWidth: 210,
|
||||
customPaperHeight: 297
|
||||
})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
barcodeConfigs: [], // 二维码配置数组 [{code, count, textTpl}]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// 从传入的配置中获取参数
|
||||
perRow() {
|
||||
return this.layoutConfig.perRow || 3;
|
||||
},
|
||||
barcodeWidth() {
|
||||
return this.layoutConfig.barcodeWidth || 180;
|
||||
},
|
||||
barcodeHeight() {
|
||||
return this.layoutConfig.barcodeWidth || 180; // 保持宽高一致
|
||||
},
|
||||
paperSize() {
|
||||
return this.layoutConfig.paperSize || 'A4';
|
||||
},
|
||||
paperOrientation() {
|
||||
return this.layoutConfig.paperOrientation || 'portrait';
|
||||
},
|
||||
customPaperWidth() {
|
||||
return this.layoutConfig.customPaperWidth || 210;
|
||||
},
|
||||
customPaperHeight() {
|
||||
return this.layoutConfig.customPaperHeight || 297;
|
||||
},
|
||||
// 展开后的二维码列表(考虑生成数量)
|
||||
expandedBarcodes() {
|
||||
let arr = [];
|
||||
this.barcodeConfigs.forEach(cfg => {
|
||||
for (let i = 0; i < (cfg.count || 1); i++) {
|
||||
arr.push(cfg.code);
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
},
|
||||
// 展开后的文字列表
|
||||
expandedBarcodeTexts() {
|
||||
let arr = [];
|
||||
this.barcodeConfigs.forEach(cfg => {
|
||||
for (let i = 0; i < (cfg.count || 1); i++) {
|
||||
let text = cfg.textTpl || cfg.code;
|
||||
text = text.replace(/\{\{n\}\}/g, i + 1); // 替换序号变量
|
||||
arr.push(text);
|
||||
}
|
||||
});
|
||||
return arr;
|
||||
},
|
||||
// 按行分组的二维码
|
||||
barcodeRows() {
|
||||
const rows = [];
|
||||
const arr = this.expandedBarcodes;
|
||||
for (let i = 0; i < arr.length; i += this.perRow) {
|
||||
rows.push(arr.slice(i, i + this.perRow));
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
// 按行分组的文字
|
||||
barcodeTextRows() {
|
||||
const rows = [];
|
||||
const arr = this.expandedBarcodeTexts;
|
||||
for (let i = 0; i < arr.length; i += this.perRow) {
|
||||
rows.push(arr.slice(i, i + this.perRow));
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
// iframe样式
|
||||
iframeStyle() {
|
||||
const { width, height } = this.getPaperPx();
|
||||
return {
|
||||
width: width + 'px',
|
||||
minHeight: height + 'px',
|
||||
height: height + 'px',
|
||||
background: '#fff',
|
||||
border: 'none',
|
||||
display: 'block',
|
||||
margin: 0,
|
||||
padding: 0
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听barcodes变化,重新初始化和渲染
|
||||
barcodes: {
|
||||
handler(newVal) {
|
||||
this.barcodeConfigs = newVal.map(b => ({
|
||||
code: b.code || b,
|
||||
count: b.count || 1,
|
||||
textTpl: b.textTpl || (b.code || b)
|
||||
}));
|
||||
this.$nextTick(this.renderPreviewIframe);
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
},
|
||||
// 监听配置变化,重新渲染
|
||||
layoutConfig: {
|
||||
handler() {
|
||||
this.$nextTick(this.renderPreviewIframe);
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
// 监听二维码配置变化,重新渲染
|
||||
barcodeConfigs: {
|
||||
handler() {
|
||||
this.$nextTick(this.renderPreviewIframe);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 生成二维码ID
|
||||
getBarcodeId(row, col) {
|
||||
return `barcode-canvas-${row}-${col}`;
|
||||
},
|
||||
// 获取二维码下方文字
|
||||
getBarcodeText(row, col, code) {
|
||||
if (
|
||||
this.barcodeTextRows[row] &&
|
||||
typeof this.barcodeTextRows[row][col] !== 'undefined' &&
|
||||
this.barcodeTextRows[row][col] !== null &&
|
||||
this.barcodeTextRows[row][col] !== ''
|
||||
) {
|
||||
return this.barcodeTextRows[row][col];
|
||||
}
|
||||
return code;
|
||||
},
|
||||
// 将纸张尺寸从mm转换为px(1mm ≈ 3.78px)
|
||||
getPaperPx() {
|
||||
let width, height;
|
||||
if (this.paperSize === 'A4') {
|
||||
width = 210 * 3.78;
|
||||
height = 297 * 3.78;
|
||||
} else if (this.paperSize === 'A5') {
|
||||
width = 148 * 3.78;
|
||||
height = 210 * 3.78;
|
||||
} else if (this.paperSize === 'A6') {
|
||||
width = 105 * 3.78;
|
||||
height = 148 * 3.78;
|
||||
} else {
|
||||
width = this.customPaperWidth * 3.78;
|
||||
height = this.customPaperHeight * 3.78;
|
||||
}
|
||||
// 处理横向/纵向
|
||||
if (this.paperOrientation === 'landscape') {
|
||||
return { width: height, height: width };
|
||||
}
|
||||
return { width, height };
|
||||
},
|
||||
// 生成打印用的HTML
|
||||
getPrintHtml() {
|
||||
const { width, height } = this.getPaperPx();
|
||||
let html = `
|
||||
<html>
|
||||
<head>
|
||||
<title>二维码预览</title>
|
||||
<style>
|
||||
body { margin: 0; padding: 0; background: #fff; }
|
||||
.barcode-list { width: ${width}px; min-height: ${height}px; margin: 0 auto; background: #fff; padding: 20px; box-sizing: border-box; }
|
||||
.barcode-row { display: flex; margin-bottom: 24px; justify-content: space-around; }
|
||||
.barcode-item { flex: 1; text-align: center; padding: 0 10px; box-sizing: border-box; }
|
||||
.barcode-text { margin-top: 8px; font-size: 14px; word-break: break-all; }
|
||||
html, body { overflow-x: hidden; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="barcode-list">
|
||||
`;
|
||||
// 生成二维码行
|
||||
this.barcodeRows.forEach((row, rowIndex) => {
|
||||
html += '<div class="barcode-row">';
|
||||
row.forEach((code, colIndex) => {
|
||||
const id = this.getBarcodeId(rowIndex, colIndex);
|
||||
const text = this.getBarcodeText(rowIndex, colIndex, code);
|
||||
html += `<div class="barcode-item">
|
||||
<canvas id="${id}" width="${this.barcodeWidth}" height="${this.barcodeHeight}"></canvas>
|
||||
<div class="barcode-text">${text}</div>
|
||||
</div>`;
|
||||
});
|
||||
html += '</div>';
|
||||
});
|
||||
html += '</div></body></html>';
|
||||
return html;
|
||||
},
|
||||
// 渲染预览iframe
|
||||
async renderPreviewIframe() {
|
||||
const iframe = this.$refs.previewIframe;
|
||||
if (!iframe) return;
|
||||
|
||||
const doc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
doc.open();
|
||||
doc.write(this.getPrintHtml());
|
||||
doc.close();
|
||||
|
||||
// 绘制二维码
|
||||
setTimeout(async () => {
|
||||
for (let rowIndex = 0; rowIndex < this.barcodeRows.length; rowIndex++) {
|
||||
const row = this.barcodeRows[rowIndex];
|
||||
for (let colIndex = 0; colIndex < row.length; colIndex++) {
|
||||
const code = row[colIndex];
|
||||
const id = this.getBarcodeId(rowIndex, colIndex);
|
||||
const el = doc.getElementById(id);
|
||||
if (el) {
|
||||
await QRCode.toCanvas(el, code, {
|
||||
width: this.barcodeWidth,
|
||||
height: this.barcodeHeight,
|
||||
margin: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 初始化二维码配置
|
||||
this.barcodeConfigs = this.barcodes.map(b => ({
|
||||
code: b.code || b,
|
||||
count: b.count || 1,
|
||||
textTpl: b.textTpl || (b.code || b)
|
||||
}));
|
||||
this.renderPreviewIframe();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.barcode-simple-layout {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.barcode-preview-area {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.iframe-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
background: #f8f8f8;
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.barcode-iframe {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user