更正前端内容
This commit is contained in:
@@ -61,6 +61,7 @@
|
|||||||
"konva": "^10.0.2",
|
"konva": "^10.0.2",
|
||||||
"mqtt": "^5.13.3",
|
"mqtt": "^5.13.3",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfjs-dist": "^3.6.172",
|
"pdfjs-dist": "^3.6.172",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
|
|||||||
@@ -63,6 +63,9 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExportAll">导出</el-button>
|
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExportAll">导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="2">
|
||||||
|
<el-button type="info" plain icon="el-icon-printer" size="mini" :disabled="multiple" @click="handleBatchPrintLabel">批量打印标签</el-button>
|
||||||
|
</el-col>
|
||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@@ -229,6 +232,24 @@
|
|||||||
<el-dialog title="标签预览" :visible.sync="labelRender.visible" append-to-body>
|
<el-dialog title="标签预览" :visible.sync="labelRender.visible" append-to-body>
|
||||||
<label-render :content="labelRender.data" :labelType="labelType" />
|
<label-render :content="labelRender.data" :labelType="labelType" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 批量导出标签PDF弹窗 -->
|
||||||
|
<el-dialog title="批量导出标签PDF" :visible.sync="batchPrint.visible" width="520px" append-to-body>
|
||||||
|
<div style="line-height: 22px; font-size: 12px; color: #909399; margin-bottom: 10px;">
|
||||||
|
已选择 <b>{{ batchPrint.list.length }}</b> 个钢卷。点击“生成PDF并打开”将每个标签作为一页(180mm × 100mm)。
|
||||||
|
</div>
|
||||||
|
<div style="text-align:right;">
|
||||||
|
<el-button size="mini" @click="batchPrint.visible = false">取消</el-button>
|
||||||
|
<el-button type="primary" size="mini" :loading="batchPrint.loading" @click="handleBatchExportLabelPdf">生成PDF并打开</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 渲染容器:屏幕隐藏,仅用于截图生成PDF -->
|
||||||
|
<div ref="batchPdfContainer" class="batch-pdf-root" aria-hidden="true">
|
||||||
|
<div v-for="(item, idx) in batchPrint.list" :key="item.coilId || idx" class="batch-pdf-page">
|
||||||
|
<OuterTagPreview :content="item" :paperWidthMm="180" :paperHeightMm="100" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -247,12 +268,16 @@ import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
|
|||||||
// 引入封装的追溯结果组件
|
// 引入封装的追溯结果组件
|
||||||
import CoilTraceResult from "./CoilTraceResult.vue";
|
import CoilTraceResult from "./CoilTraceResult.vue";
|
||||||
import LabelRender from './LabelRender/index.vue'
|
import LabelRender from './LabelRender/index.vue'
|
||||||
|
import OuterTagPreview from './LabelRender/OuterTagPreview.vue'
|
||||||
import MaterialSelect from "@/components/KLPService/MaterialSelect";
|
import MaterialSelect from "@/components/KLPService/MaterialSelect";
|
||||||
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
|
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
|
||||||
import { findItemWithBom } from "@/store/modules/category";
|
import { findItemWithBom } from "@/store/modules/category";
|
||||||
import CoilNo from "@/components/KLPService/Renderer/CoilNo.vue";
|
import CoilNo from "@/components/KLPService/Renderer/CoilNo.vue";
|
||||||
import MemoInput from "@/components/MemoInput";
|
import MemoInput from "@/components/MemoInput";
|
||||||
import MutiSelect from "@/components/MutiSelect";
|
import MutiSelect from "@/components/MutiSelect";
|
||||||
|
import html2canvas from 'html2canvas';
|
||||||
|
import { PDFDocument } from 'pdf-lib';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -272,6 +297,7 @@ export default {
|
|||||||
CoilNo,
|
CoilNo,
|
||||||
MemoInput,
|
MemoInput,
|
||||||
MutiSelect,
|
MutiSelect,
|
||||||
|
OuterTagPreview,
|
||||||
},
|
},
|
||||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||||
props: {
|
props: {
|
||||||
@@ -407,6 +433,12 @@ export default {
|
|||||||
data: {},
|
data: {},
|
||||||
type: '2'
|
type: '2'
|
||||||
},
|
},
|
||||||
|
batchPrint: {
|
||||||
|
visible: false,
|
||||||
|
loading: false,
|
||||||
|
list: [],
|
||||||
|
},
|
||||||
|
__printOldTitle: document.title,
|
||||||
floatLayerConfig: {
|
floatLayerConfig: {
|
||||||
columns: [
|
columns: [
|
||||||
{ label: '入场钢卷号', prop: 'enterCoilNo' },
|
{ label: '入场钢卷号', prop: 'enterCoilNo' },
|
||||||
@@ -736,6 +768,136 @@ export default {
|
|||||||
...this.queryParams
|
...this.queryParams
|
||||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** 批量打印标签按钮 */
|
||||||
|
handleBatchPrintLabel() {
|
||||||
|
if (!this.ids || this.ids.length === 0) {
|
||||||
|
this.$message.warning('请先勾选要打印标签的钢卷');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取出选中行数据,并补齐标签渲染需要的字段
|
||||||
|
const selectedData = this.materialCoilList
|
||||||
|
.filter(item => this.ids.includes(item.coilId))
|
||||||
|
.map(row => {
|
||||||
|
const item = row.itemType === 'product' ? row.product : row.rawMaterial;
|
||||||
|
const itemName = row.itemType === 'product' ? item?.productName || '' : item?.rawMaterialName || '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
...row,
|
||||||
|
itemName,
|
||||||
|
// OuterTagPreview.vue 里字段名使用了 specification/material(而列表里是 itemSpecification/itemMaterial)
|
||||||
|
specification: row.itemSpecification || row.specification || '',
|
||||||
|
material: row.itemMaterial || row.material || '',
|
||||||
|
updateTime: row.updateTime?.split(' ')[0] || row.updateTime || '',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.batchPrint.list = selectedData;
|
||||||
|
this.batchPrint.visible = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** 批量导出标签PDF:每个标签一页(180mm × 100mm) */
|
||||||
|
async handleBatchExportLabelPdf() {
|
||||||
|
if (!this.batchPrint.list || this.batchPrint.list.length === 0) {
|
||||||
|
this.$message.warning('没有可导出的数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = this.$refs.batchPdfContainer;
|
||||||
|
if (!container) {
|
||||||
|
this.$message.error('PDF渲染容器未初始化');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.batchPrint.loading = true;
|
||||||
|
|
||||||
|
await this.$nextTick();
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
const mmToPt = 72 / 25.4;
|
||||||
|
// 纸张尺寸
|
||||||
|
const paperWidthMm = 180;
|
||||||
|
const paperHeightMm = 100;
|
||||||
|
// 留白:左右约 4mm;上下更小一些,避免底部空得太多
|
||||||
|
const marginXmm = 4;
|
||||||
|
const marginTopMm = 2;
|
||||||
|
const marginBottomMm = 1;
|
||||||
|
|
||||||
|
const pageWidthPt = paperWidthMm * mmToPt;
|
||||||
|
const pageHeightPt = paperHeightMm * mmToPt;
|
||||||
|
const marginXPt = marginXmm * mmToPt;
|
||||||
|
const marginTopPt = marginTopMm * mmToPt;
|
||||||
|
const marginBottomPt = marginBottomMm * mmToPt;
|
||||||
|
|
||||||
|
const contentWidthPt = pageWidthPt - marginXPt * 2;
|
||||||
|
const contentHeightPt = pageHeightPt - marginTopPt - marginBottomPt;
|
||||||
|
|
||||||
|
const pdfDoc = await PDFDocument.create();
|
||||||
|
|
||||||
|
// 关键:只截取标签自身(OuterTagPreview),不要把页面菜单/弹窗带进去
|
||||||
|
const pageEls = container.querySelectorAll('.batch-pdf-page');
|
||||||
|
|
||||||
|
for (let i = 0; i < pageEls.length; i++) {
|
||||||
|
const el = pageEls[i];
|
||||||
|
|
||||||
|
// 强制用标签的mm尺寸作为截图基准,避免被外层布局影响
|
||||||
|
const canvas = await html2canvas(el, {
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
// 让 html2canvas 为频繁读回优化 Canvas(浏览器会提示 willReadFrequently)
|
||||||
|
willReadFrequently: true,
|
||||||
|
// 确保按元素尺寸截图
|
||||||
|
width: el.offsetWidth,
|
||||||
|
height: el.offsetHeight,
|
||||||
|
windowWidth: el.scrollWidth,
|
||||||
|
windowHeight: el.scrollHeight,
|
||||||
|
});
|
||||||
|
|
||||||
|
const imgDataUrl = canvas.toDataURL('image/png');
|
||||||
|
const pngImage = await pdfDoc.embedPng(imgDataUrl);
|
||||||
|
|
||||||
|
const page = pdfDoc.addPage([pageWidthPt, pageHeightPt]);
|
||||||
|
|
||||||
|
// 图片铺满页面(保持比例,居中)
|
||||||
|
const imgW = pngImage.width;
|
||||||
|
const imgH = pngImage.height;
|
||||||
|
// 按“内容区域(去掉边距)”计算缩放,让四周留下约 4mm 空白
|
||||||
|
const scale = Math.min(contentWidthPt / imgW, contentHeightPt / imgH);
|
||||||
|
const drawW = imgW * scale;
|
||||||
|
const drawH = imgH * scale;
|
||||||
|
|
||||||
|
// 内容区域内居中 + 外层边距
|
||||||
|
const x = marginXPt + (contentWidthPt - drawW) / 2;
|
||||||
|
const y = marginBottomPt + (contentHeightPt - drawH) / 2;
|
||||||
|
|
||||||
|
page.drawImage(pngImage, { x, y, width: drawW, height: drawH });
|
||||||
|
}
|
||||||
|
|
||||||
|
const pdfBytes = await pdfDoc.save();
|
||||||
|
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
// 尽量避免被浏览器拦截弹窗:优先在当前tab打开;如仍被策略限制,可改为下载
|
||||||
|
const win = window.open(url, '_blank');
|
||||||
|
if (!win) {
|
||||||
|
// fallback:触发下载
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `钢卷标签_${new Date().getTime()}.pdf`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
this.$message.error('生成PDF失败,请重试');
|
||||||
|
} finally {
|
||||||
|
this.batchPrint.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
/** 导出选中数据操作 */
|
/** 导出选中数据操作 */
|
||||||
handleExport() {
|
handleExport() {
|
||||||
// 1. 判断是否有选中数据
|
// 1. 判断是否有选中数据
|
||||||
@@ -792,4 +954,22 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 批量导出PDF:渲染容器屏幕隐藏,但保留真实布局尺寸给 html2canvas 截图 */
|
||||||
|
.batch-pdf-root {
|
||||||
|
position: fixed;
|
||||||
|
left: -100000px;
|
||||||
|
top: 0;
|
||||||
|
width: 180mm;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-pdf-page {
|
||||||
|
width: 180mm;
|
||||||
|
height: 100mm;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user