Files
klp-oa/klp-ui/src/views/wms/delivery/components/wayBill.vue
砂糖 40383a73b9 feat(运单): 添加取货地点输入框
新增取货地点输入框及相关样式,用于记录运输单据中的取货位置信息
2025-12-01 17:53:19 +08:00

669 lines
17 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.consigneeUnit" />
</div>
<div class="header-center">
<input type="text" class="editable-input date-input transparent-input" v-model="localWaybill.deliveryYear" />
<span class="label date-label"></span>
<input type="text" class="editable-input date-input transparent-input" v-model="localWaybill.deliveryMonth" />
<span class="label date-label"></span>
<input type="text" class="editable-input date-input transparent-input" v-model="localWaybill.deliveryDay" />
<span class="label date-label"></span>
</div>
<div class="header-right">
<span class="label">发货单位</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.senderUnit" />
</div>
</div>
<div class="waybill-header">
<div class="header-left">
<span class="label">负责人</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.principal" />
</div>
<div class="header-right">
<span class="label">电话</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.principalPhone" />
</div>
<div class="header-center">
<span class="label">车牌</span>
<input type="text" class="editable-input transparent-input" v-model="localWaybill.licensePlate" />
</div>
</div>
<!-- 表格 -->
<table class="waybill-table">
<thead>
<tr>
<th>品名</th>
<th>切边</th>
<th>包装</th>
<th>结算</th>
<th>原料厂家</th>
<th>卷号</th>
<th>规格</th>
<th>材质</th>
<th>数量</th>
<th>重量kg</th>
<th>单价</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="transparent-input" v-model="item.productName" /></td>
<td><input type="text" class="table-input transparent-input" v-model="item.edgeType" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.packageType" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.settlementType" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.rawMaterialFactory" />
</td>
<td><input type="text" class="table-input transparent-input" v-model="item.coilNumber" /></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.weight"
placeholder="0.00" /></td>
<td><input type="number" class="table-input transparent-input" v-model.number="item.unitPrice"
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-remarks">
<p>1品名冷硬钢卷酸连轧冷轧钢卷脱脂退火火拉矫镀锌卷板镀锌管料镀锌分剪料2切边净边/毛边3包装裸包周三径四简包1周三径四内外护角简包2周三径四+防锈纸普包周三径四+内外护角+防锈纸+端护板精包1周三径四+内外护角+防锈纸+薄膜+端护板+内外护板精包2周三径四+内外护角+防锈纸+薄膜+端护板+内外护板+木托</p>
</div>
<div class="waybill-pickup-location">
<!-- <div class="pickup-location-item inline"> -->
<span class="label">取货地点</span>
<input type="text" class="editable-input full-input transparent-input" />
<!-- </div> -->
</div>
<!-- 签名栏 -->
<div class="waybill-footer">
<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 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';
export default {
props: {
// 组件接收完整的发货单内容, 渲染发货单,这个面板内包括一个保存为图片(已经安装了dom-to-image)和一个打印按钮(已经安装了print-js)
waybill: {
type: Object,
default: () => { }
},
waybillDetails: {
type: Array,
default: () => []
}
},
data() {
return {
// 本地可编辑的发货单数据
localWaybill: {
consigneeUnit: '',
senderUnit: '',
deliveryYear: '',
deliveryMonth: '',
deliveryDay: '',
principal: '',
principalPhone: '',
licensePlate: ''
},
// 本地可编辑的发货单明细
localWaybillDetails: []
};
},
watch: {
// 监听props变化更新本地数据
waybill: {
handler(newVal) {
if (newVal) {
this.localWaybill = {
consigneeUnit: newVal.consigneeUnit || '',
senderUnit: newVal.senderUnit || '',
deliveryYear: this.getYearFromDate(newVal.deliveryTime) || '',
deliveryMonth: this.getMonthFromDate(newVal.deliveryTime) || '',
deliveryDay: this.getDayFromDate(newVal.deliveryTime) || '',
principal: newVal.principal || '',
principalPhone: newVal.principalPhone || '',
licensePlate: newVal.licensePlate || ''
};
}
},
immediate: true,
deep: true
},
waybillDetails: {
handler(newVal) {
if (newVal && Array.isArray(newVal)) {
this.localWaybillDetails = [...newVal];
} else {
this.localWaybillDetails = [];
}
},
immediate: true,
deep: true
}
},
methods: {
// 从日期字符串中提取年份
getYearFromDate(dateStr) {
if (dateStr) {
const date = new Date(dateStr);
return date.getFullYear().toString();
}
return '';
},
// 从日期字符串中提取月份
getMonthFromDate(dateStr) {
if (dateStr) {
const date = new Date(dateStr);
return (date.getMonth() + 1).toString();
}
return '';
},
// 从日期字符串中提取日
getDayFromDate(dateStr) {
if (dateStr) {
const date = new Date(dateStr);
return date.getDate().toString();
}
return '';
},
// 添加明细
addDetail() {
this.localWaybillDetails.push({
productName: '',
edgeType: '',
packageType: '',
settlementType: '',
rawMaterialFactory: '',
coilNumber: '',
specification: '',
material: '',
quantity: 0,
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.waybillName || this.waybill.waybillNo || 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: 850px;
max-width: none;
min-width: 850px;
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: 80px; /* 品名 */
}
.waybill-table th:nth-child(2),
.waybill-table td:nth-child(2) {
width: 40px; /* 切边 */
}
.waybill-table th:nth-child(3),
.waybill-table td:nth-child(3) {
width: 40px; /* 包装 */
}
.waybill-table th:nth-child(4),
.waybill-table td:nth-child(4) {
width: 40px; /* 结算 */
}
.waybill-table th:nth-child(5),
.waybill-table td:nth-child(5) {
width: 80px; /* 原料厂家 */
}
.waybill-table th:nth-child(6),
.waybill-table td:nth-child(6) {
width: 100px; /* 卷号 */
}
.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: 40px; /* 材质 */
}
.waybill-table th:nth-child(9),
.waybill-table td:nth-child(9) {
width: 60px; /* 数量(件) */
}
.waybill-table th:nth-child(10),
.waybill-table td:nth-child(10) {
width: 60px; /* 重量kg */
}
.waybill-table th:nth-child(11),
.waybill-table td:nth-child(11) {
width: 40px; /* 单价 */
}
.waybill-table th:nth-child(12),
.waybill-table td:nth-child(12) {
width: 100px; /* 备注 */
}
.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>