Files
klp-oa/klp-ui/src/views/wms/receive/components/Printer.vue
砂糖 ae68b40ee6 refactor(wms): 重构物料信息展示逻辑,移除冗余组件
重构物料信息展示逻辑,统一使用itemName等字段替代原有的product和rawMaterial嵌套结构
删除不再使用的BomInfo、CategoryRenderer等冗余组件
新增report模块配置集中管理
优化代码结构,提升可维护性
2026-03-24 13:55:10 +08:00

628 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 收货单组件 -->
<template>
<div>
<div class="waybill-container" ref="waybillRef">
<!-- 头部信息 -->
<div class="waybill-header">
<div class="header-left">
<span class="label">创建人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.createBy" />
</div>
<div class="header-center">
<span class="label">计划名称</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.planName" />
</div>
<div class="header-right">
<span class="label">计划日期</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.planDate" />
</div>
</div>
<div class="waybill-header">
<div class="header-left" style="width: 100%">
<span class="label">备注</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.remark" style="width: calc(100% - 80px)" />
</div>
</div>
<!-- 表格 -->
<table class="waybill-table" v-loading="loading" loading-text="加载中...">
<thead>
<tr>
<th>卷号</th>
<th>物料类型</th>
<th>物料名称</th>
<th>厂家</th>
<th>规格</th>
<th>材质</th>
<th>数量</th>
<th>重量t</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<!-- 无明细提示 -->
<tr v-if="localWaybillDetails.length === 0">
<td colspan="12" class="no-data">
<div class="no-data-content">
<el-empty description="暂无收货单明细" />
</div>
</td>
</tr>
<!-- 明细数据 -->
<tr v-for="(item, index) in localWaybillDetails" :key="index">
<td><input type="text" class="table-input transparent-input" v-model="item.currentCoilNo" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.materialType" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.itemName" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.manufacturer" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.specification" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.material" />
</td>
<td><input type="number" class="table-input transparent-input" v-model.number="item.quantity"
placeholder="0" /></td>
<td><input type="number" class="table-input transparent-input" v-model.number="item.netWeight"
placeholder="0.00" /></td>
<td>
<div class="table-cell-with-action">
<input type="text" class="table-input transparent-input" v-model="item.remark" />
</div>
</td>
</tr>
</tbody>
</table>
<!-- 签名栏 -->
<div class="waybill-footer">
<div class="footer-item inline">
<span class="label">制单</span>
<input type="text" class="editable-input signature-input transparent-input" v-model="localWaybill.createBy" />
</div>
<div class="footer-item inline">
<span class="label">审核</span>
<input type="text" class="editable-input signature-input transparent-input" />
</div>
<div class="footer-item inline">
<span class="label">确认</span>
<input type="text" class="editable-input signature-input transparent-input" />
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="waybill-actions">
<el-button type="primary" @click="saveAsImage">保存为图片</el-button>
<el-button type="success" @click="printWaybill">打印</el-button>
</div>
</div>
</template>
<script>
import domtoimage from 'dom-to-image';
import printJS from 'print-js';
import { getMaterialCoil } from '@/api/wms/coil'
export default {
props: {
// 组件接收完整的收货单内容, 渲染收货单,这个面板内包括一个保存为图片(已经安装了dom-to-image)和一个打印按钮(已经安装了print-js)
waybill: {
type: Object,
default: () => { }
},
waybillDetails: {
type: Array,
default: () => []
}
},
data() {
return {
// 本地可编辑的收货单数据
localWaybill: {
planId: '',
planName: '',
planDate: '',
planType: 1,
remark: '',
createTime: '',
createBy: ''
},
// 本地可编辑的收货单明细
localWaybillDetails: [],
loading: false
};
},
watch: {
// 监听props变化更新本地数据
waybill: {
handler(newVal) {
if (newVal) {
this.localWaybill = {
planId: newVal.planId || '',
planName: newVal.planName || '',
planDate: newVal.planDate ? this.formatDate(newVal.planDate) : '',
planType: newVal.planType || 1,
remark: newVal.remark || '',
createTime: newVal.createTime ? this.formatDate(newVal.createTime) : '',
createBy: newVal.createBy || ''
};
}
},
immediate: true,
deep: true
},
waybillDetails: {
handler(newVal) {
if (newVal && Array.isArray(newVal)) {
this.loading = true;
// 使用getMaterialCoil获取每个卷的详细信息
Promise.all(newVal.map(item => getMaterialCoil(item.coilId)))
.then(results => {
// 合并结果到本地明细
this.localWaybillDetails = newVal.map((item, index) => ({
...item,
quantity: 1, // 默认数量为1
...results[index].data,
itemName: results[index].data.itemName || ''
}));
console.log(this.localWaybillDetails);
this.loading = false;
})
.catch(error => {
console.error('获取卷号详细信息失败:', error);
// 处理错误,例如显示提示信息
});
} else {
this.localWaybillDetails = [];
}
},
immediate: true,
deep: true
}
},
methods: {
// 格式化日期
formatDate(dateStr) {
if (dateStr) {
const date = new Date(dateStr);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
return '';
},
// 添加明细
addDetail() {
this.localWaybillDetails.push({
coilId: '',
currentCoilNo: '',
actionStatus: '',
itemType: '',
itemId: '',
actionType: '',
operationType: '',
warehouseId: this.localWaybill.planId,
quantity: 1,
weight: 0,
unitPrice: 0,
remark: ''
});
},
// 删除明细
deleteDetail(index) {
this.localWaybillDetails.splice(index, 1);
},
// 保存为图片
saveAsImage() {
const node = this.$refs.waybillRef;
// 确保容器在保存图片时能完整显示所有内容
const originalWidth = node.style.width;
const originalOverflow = node.style.overflow;
// 临时调整容器样式,确保所有内容可见
node.style.width = 'auto';
node.style.overflow = 'visible';
// 获取实际内容宽度
const contentWidth = node.scrollWidth;
const contentHeight = node.scrollHeight;
domtoimage.toPng(node, {
width: contentWidth,
height: contentHeight,
style: {
width: `${contentWidth}px`,
height: `${contentHeight}px`,
overflow: 'visible'
}
})
.then(dataUrl => {
const link = document.createElement('a');
link.download = `收货单_${this.waybill.planName || this.waybill.planId || Date.now()}.png`;
link.href = dataUrl;
link.click();
})
.catch(error => {
console.error('保存图片失败:', error);
this.$message.error('保存图片失败');
})
.finally(() => {
// 恢复原始样式
node.style.width = originalWidth;
node.style.overflow = originalOverflow;
});
},
// 打印收货单
printWaybill() {
const node = this.$refs.waybillRef;
// 确保容器在打印时能完整显示所有内容
const originalWidth = node.style.width;
const originalOverflow = node.style.overflow;
// 临时调整容器样式,确保所有内容可见
node.style.width = 'auto';
node.style.overflow = 'visible';
// 获取实际内容宽度
const contentWidth = node.scrollWidth;
printJS({
printable: node,
maxWidth: contentWidth,
type: 'html',
scanStyles: true,
style: `
@page { size: A4 landscape; margin: 1cm; }
.waybill-container { width: 100%; max-width: none; overflow: visible; }
.waybill-table { width: 100%; table-layout: auto; }
`,
targetStyles: ['*']
});
// 恢复原始样式
setTimeout(() => {
node.style.width = originalWidth;
node.style.overflow = originalOverflow;
}, 100);
}
}
}
</script>
<style scoped>
.waybill-container {
width: 870px;
max-width: none;
min-width: 870px;
margin: 0 auto;
padding: 20px;
background: white;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
font-family: SimSun, serif;
overflow-x: auto;
overflow-y: visible;
}
/* 头部样式 */
.waybill-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.header-left,
.header-right {
display: flex;
align-items: center;
}
.header-center {
display: flex;
align-items: center;
gap: 5px;
}
.label {
font-weight: bold;
display: inline-block;
width: 80px;
text-align: right;
white-space: nowrap;
}
.date-label {
width: 1em;
}
/* 可编辑输入框样式 */
.editable-input {
padding: 4px 8px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
font-family: SimSun, serif;
outline: none;
transition: all 0.2s;
border-bottom: 1px dashed #dcdfe6;
}
.editable-input:focus {
border-color: #409eff;
}
.date-input {
width: 30px;
text-align: center;
margin-right: 5px;
}
/* 透明输入框样式 */
.transparent-input {
border: none;
border-radius: 0;
background-color: transparent;
}
.transparent-input:focus {
border-bottom-color: #409eff;
background-color: rgba(64, 158, 255, 0.05);
}
/* 表格样式 */
.waybill-table {
width: 100%;
max-width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
font-size: 12px;
table-layout: fixed;
}
.waybill-table th,
.waybill-table td {
border: 1px solid #000;
box-sizing: border-box;
line-height: 24px;
text-align: center;
vertical-align: middle;
word-wrap: break-word;
word-break: break-all;
}
/* 表格列宽设置 */
.waybill-table th:nth-child(1),
.waybill-table td:nth-child(1) {
width: 120px; /* 卷ID */
}
.waybill-table th:nth-child(2),
.waybill-table td:nth-child(2) {
width: 120px; /* 卷号 */
}
.waybill-table th:nth-child(3),
.waybill-table td:nth-child(3) {
width: 80px; /* 动作状态 */
}
.waybill-table th:nth-child(4),
.waybill-table td:nth-child(4) {
width: 80px; /* 项目类型 */
}
.waybill-table th:nth-child(5),
.waybill-table td:nth-child(5) {
width: 80px; /* 项目ID */
}
.waybill-table th:nth-child(6),
.waybill-table td:nth-child(6) {
width: 80px; /* 动作类型 */
}
.waybill-table th:nth-child(7),
.waybill-table td:nth-child(7) {
width: 80px; /* 操作类型 */
}
.waybill-table th:nth-child(8),
.waybill-table td:nth-child(8) {
width: 80px; /* 仓库ID */
}
.waybill-table th:nth-child(9),
.waybill-table td:nth-child(9) {
width: 120px;
}
.waybill-table th {
background-color: #f5f7fa;
font-weight: bold;
}
.waybill-table tr:nth-child(even) {
background-color: #fafafa;
}
/* 表格输入框样式 */
.table-input {
box-sizing: border-box;
width: 100%;
height: 100%;
padding: 4px;
}
.table-input:focus {
border-color: #409eff;
}
/* 无数据样式 */
.no-data {
height: 200px;
vertical-align: middle;
}
.no-data-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
/* 表格单元格操作区 */
.table-cell-with-action {
display: flex;
align-items: center;
gap: 5px;
}
/* 备注样式 */
.waybill-remarks {
margin-bottom: 30px;
font-size: 14px;
line-height: 1.5;
text-align: justify;
}
.waybill-remarks p {
margin: 5px 0;
}
/* 底部签名样式 */
.waybill-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.waybill-pickup-location {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
}
.waybill-pickup-location label {
font-size: 14px;
margin-right: 10px;
width: 40px;
}
.footer-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
width: 200px;
}
.footer-item.inline {
flex-direction: row;
align-items: center;
width: auto;
}
.footer-item .label {
font-size: 14px;
margin-right: 10px;
width: 40px;
}
.signature-input {
min-width: 150px;
}
.full-input {
/* 占满本行的剩余空间父容器不是flex */
flex: 1;
}
/* 操作按钮样式 */
.waybill-actions {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 30px;
}
/* 添加明细按钮 */
.add-detail-btn {
display: flex;
justify-content: center;
margin-bottom: 20px;
}
/* 打印样式 */
@media print {
.waybill-container {
width: 100%;
max-width: none;
box-shadow: none;
padding: 0;
}
.waybill-header {
flex-wrap: nowrap;
justify-content: space-between;
}
.waybill-footer {
flex-wrap: nowrap;
justify-content: space-between;
}
.label {
width: 80px;
text-align: right;
white-space: nowrap;
}
.waybill-actions {
display: none;
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.waybill-header {
flex-direction: column;
gap: 15px;
align-items: flex-start;
}
.waybill-table {
font-size: 12px;
}
.waybill-table th,
.waybill-table td {
padding: 2px;
}
.waybill-footer {
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.footer-item.inline {
width: 100%;
}
.label {
width: auto;
text-align: left;
}
}
</style>