Merge remote-tracking branch 'origin/0.8.X' into 0.8.X
This commit is contained in:
@@ -88,7 +88,7 @@
|
||||
<!-- 第八行:生产日期(跨3列) -->
|
||||
<div class="info-grid-item label-cell">生产日期</div>
|
||||
<div class="info-grid-item value-cell">
|
||||
<input type="text" class="nob" :value="content.updateTime || ''" />
|
||||
<input type="text" class="nob" :value="parseTime(content.updateTime, '{y}-{m}-{d}')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -152,6 +152,8 @@ export default {
|
||||
return {
|
||||
logo,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -557,7 +557,7 @@ export default {
|
||||
enterCoilNo: undefined,
|
||||
currentCoilNo: undefined,
|
||||
supplierCoilNo: undefined,
|
||||
dataType: undefined,
|
||||
dataType: 1,
|
||||
warehouseId: undefined,
|
||||
nextWarehouseId: undefined,
|
||||
qrcodeRecordId: undefined,
|
||||
|
||||
236
klp-ui/src/views/wms/coil/panels/tool.vue
Normal file
236
klp-ui/src/views/wms/coil/panels/tool.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<div>
|
||||
<button
|
||||
@click="handleExportAll"
|
||||
:disabled="exportLoading"
|
||||
style="padding: 8px 16px; cursor: pointer; margin-bottom: 20px;"
|
||||
>
|
||||
{{ exportLoading ? '导出中...' : '导出所有外标签' }}
|
||||
</button>
|
||||
|
||||
<!-- 进度条容器:导出时显示 -->
|
||||
<div v-if="showProgress" class="progress-container" style="margin-bottom: 20px; width: 100%; max-width: 600px;">
|
||||
<!-- 进度文本:显示当前进度/总数量 -->
|
||||
<div class="progress-text" style="margin-bottom: 8px; font-size: 14px; color: #666;">
|
||||
导出进度:{{ currentIndex }}/{{ totalCount }} ({{ progress }}%)
|
||||
</div>
|
||||
<!-- 进度条背景 -->
|
||||
<div class="progress-bar-bg" style="width: 100%; height: 8px; background: #f5f5f5; border-radius: 4px; overflow: hidden;">
|
||||
<!-- 进度条进度 -->
|
||||
<div
|
||||
class="progress-bar"
|
||||
style="height: 100%; background: #409eff; transition: width 0.3s ease;"
|
||||
:style="{ width: `${progress}%` }"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预览组件:保留预览,同时用于复用渲染逻辑 -->
|
||||
<OuterTagPreview ref="outerTagPreview" :content="current" />
|
||||
<!-- 临时渲染容器:用于逐个渲染标签并转换图片 -->
|
||||
<div ref="tempTagContainer" style="position: fixed; top: -9999px; left: -9999px; z-index: -9999;"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OuterTagPreview from './LabelRender/OuterTagPreview.vue';
|
||||
import { listMaterialCoil } from "@/api/wms/coil";
|
||||
import jsPDF from 'jspdf';
|
||||
import domtoimage from 'dom-to-image';
|
||||
|
||||
export default {
|
||||
name: 'ToolPanel',
|
||||
components: {
|
||||
OuterTagPreview,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
pos: 0,
|
||||
current: {},
|
||||
exportLoading: false,
|
||||
// 进度条相关变量
|
||||
showProgress: false, // 是否显示进度条
|
||||
progress: 0, // 进度值(0-100)
|
||||
currentIndex: 0, // 当前处理的标签索引
|
||||
totalCount: 0, // 总标签数量
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchData();
|
||||
},
|
||||
methods: {
|
||||
// 获取标签数据
|
||||
fetchData() {
|
||||
listMaterialCoil({
|
||||
status: 0,
|
||||
dataType: 1,
|
||||
materialType: '成品',
|
||||
itemType: 'product',
|
||||
selectType: 'raw_material',
|
||||
pageSize: 100,
|
||||
pageNum: 10
|
||||
}).then(res => {
|
||||
this.list = res.rows || [];
|
||||
if (this.list.length > 0) {
|
||||
this.current = this.list[0];
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取标签数据失败:', err);
|
||||
this.$message.error('获取标签数据失败,请刷新重试');
|
||||
})
|
||||
},
|
||||
|
||||
// 核心:复用OuterTagPreview组件渲染标签,再转图片导出PDF
|
||||
async handleExportAll() {
|
||||
if (this.exportLoading) return;
|
||||
if (this.list.length === 0) {
|
||||
this.$message.warning('暂无外标签数据可导出');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 初始化进度条
|
||||
this.exportLoading = true;
|
||||
this.showProgress = true; // 显示进度条
|
||||
this.totalCount = this.list.length; // 总数量
|
||||
this.currentIndex = 0; // 重置当前索引
|
||||
this.progress = 0; // 重置进度
|
||||
|
||||
const doc = new jsPDF({
|
||||
unit: 'mm',
|
||||
format: 'a4',
|
||||
orientation: 'portrait'
|
||||
});
|
||||
const tempContainer = this.$refs.tempTagContainer;
|
||||
const previewComponent = this.$refs.outerTagPreview;
|
||||
|
||||
// 循环处理每个标签
|
||||
for (let index = 0; index < this.list.length; index++) {
|
||||
const item = this.list[index];
|
||||
this.current = item; // 更新预览组件的content,触发重新渲染
|
||||
|
||||
// 等待组件渲染完成
|
||||
await this.waitForDOMRender();
|
||||
|
||||
// 复制预览组件的DOM到临时容器
|
||||
const renderedDOM = previewComponent.$el.cloneNode(true);
|
||||
tempContainer.innerHTML = '';
|
||||
tempContainer.appendChild(renderedDOM);
|
||||
|
||||
// 再次等待临时容器DOM渲染
|
||||
await this.waitForDOMRender();
|
||||
|
||||
// 检查临时容器是否有内容
|
||||
if (!tempContainer.firstChild) {
|
||||
console.warn(`第${index+1}个标签DOM为空`, item);
|
||||
// 即使当前标签为空,也更新进度
|
||||
this.updateProgress(index + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 将临时容器的DOM转为图片
|
||||
const imgData = await domtoimage.toPng(previewComponent.$el);
|
||||
|
||||
// 分页:非第一个标签新增页面
|
||||
if (index > 0) {
|
||||
doc.addPage();
|
||||
}
|
||||
|
||||
// 计算图片在PDF中的尺寸(适配A4,保持原比例)
|
||||
const a4Width = 210;
|
||||
const a4Height = 297;
|
||||
const imgRatio = (previewComponent.$el.offsetWidth || 800) / (previewComponent.$el.offsetHeight || 1100);
|
||||
const imgWidth = a4Width - 20;
|
||||
const imgHeight = imgWidth / imgRatio;
|
||||
|
||||
// 确保图片高度不超过A4高度
|
||||
const finalImgHeight = imgHeight > a4Height - 20 ? (a4Height - 20) : imgHeight;
|
||||
const finalImgWidth = finalImgHeight * imgRatio;
|
||||
// 居中显示
|
||||
const xPos = (a4Width - finalImgWidth) / 2;
|
||||
const yPos = (a4Height - finalImgHeight) / 2;
|
||||
|
||||
// 插入图片到PDF
|
||||
doc.addImage(imgData, 'PNG', xPos, yPos, finalImgWidth, finalImgHeight);
|
||||
|
||||
// 更新进度条(关键:处理完一个标签就更新)
|
||||
this.updateProgress(index + 1);
|
||||
}
|
||||
|
||||
// 保存PDF
|
||||
const fileName = `外标签导出_${new Date().toLocaleString().replace(/[/: ]/g, '-')}.pdf`;
|
||||
doc.save(fileName);
|
||||
this.$message.success('PDF导出成功!');
|
||||
|
||||
} catch (err) {
|
||||
console.error('PDF导出失败详情:', err);
|
||||
this.$message.error('PDF导出失败,详情请查看控制台');
|
||||
} finally {
|
||||
// 重置进度条和加载状态
|
||||
this.$refs.tempTagContainer.innerHTML = '';
|
||||
this.exportLoading = false;
|
||||
this.showProgress = false; // 隐藏进度条
|
||||
this.progress = 0;
|
||||
this.currentIndex = 0;
|
||||
this.totalCount = 0;
|
||||
}
|
||||
},
|
||||
|
||||
// 辅助方法:更新进度条
|
||||
updateProgress(current) {
|
||||
this.currentIndex = current;
|
||||
// 计算进度百分比(保留整数)
|
||||
this.progress = Math.round((current / this.totalCount) * 100);
|
||||
},
|
||||
|
||||
// 辅助方法:等待DOM渲染完成
|
||||
waitForDOMRender(time = 300) {
|
||||
return new Promise(resolve => setTimeout(resolve, time));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
button {
|
||||
border: 1px solid #409eff;
|
||||
background: #409eff;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
button:disabled {
|
||||
background: #a0cfff;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 进度条样式优化(可选:替换内联样式,统一管理) */
|
||||
.progress-container {
|
||||
:deep(.progress-text) {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
:deep(.progress-bar-bg) {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
:deep(.progress-bar) {
|
||||
height: 100%;
|
||||
background: #409eff;
|
||||
transition: width 0.3s ease;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 确保预览组件的DOM能被正确复制 */
|
||||
:deep(.label-container) {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user