|
|
|
@ -22,60 +22,158 @@ |
|
|
|
/> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 物料列表 --> |
|
|
|
<div class="content-area"> |
|
|
|
<!-- 入库单列表 --> |
|
|
|
<div class="inbound-list"> |
|
|
|
<!-- 当没有选中入库单时,显示所有入库单 --> |
|
|
|
<template v-if="!selectedInbound"> |
|
|
|
<div |
|
|
|
v-for="(item, index) in qualifiedList" |
|
|
|
:key="index" |
|
|
|
class="inbound-card" |
|
|
|
@click="selectInbound(item)" |
|
|
|
> |
|
|
|
<div class="card-title"> |
|
|
|
<span class="title-label">入库单号:{{ item.inboundNo }}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="card-details"> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">标签张数</div> |
|
|
|
<div class="detail-value"> |
|
|
|
<span class="qualified">{{ item.labelinCount }}</span><span class="total">{{ item.totalLabels }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">物料总数</div> |
|
|
|
<div class="detail-value"> |
|
|
|
<span class="qualified">{{ item.totalinLabels }}</span><span class="total">{{ item.labelCount }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">批次号</div> |
|
|
|
<div class="detail-value">{{ item.batchNo }}</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">创建日期</div> |
|
|
|
<div class="detail-value">{{ formatDate(item.inspectionDate) }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 空状态 --> |
|
|
|
<div v-if="qualifiedList.length === 0 && !loading" class="empty-state"> |
|
|
|
<i class="el-icon-box"></i> |
|
|
|
<p>暂无生产待入库物料</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 加载状态 --> |
|
|
|
<div v-if="loading" class="loading-state"> |
|
|
|
<i class="el-icon-loading"></i> |
|
|
|
<p>加载中...</p> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- 当选中入库单时,只显示选中的入库单 --> |
|
|
|
<div |
|
|
|
v-for="(item, index) in qualifiedList" |
|
|
|
:key="index" |
|
|
|
class="inbound-card" |
|
|
|
@click="goToInboundPage(item)" |
|
|
|
v-else |
|
|
|
class="inbound-card selected" |
|
|
|
@click="deselectInbound" |
|
|
|
> |
|
|
|
<div class="card-title"> |
|
|
|
<span class="title-label">入库单号</span> |
|
|
|
<span class="title-value">{{ item.inboundNo }}</span> |
|
|
|
<span class="title-label">入库单号:{{ selectedInbound.inboundNo }}</span> |
|
|
|
<i class="el-icon-arrow-left back-icon" title="返回列表"></i> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="card-details"> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">标签张数</div> |
|
|
|
<div class="detail-value"> |
|
|
|
<span class="qualified">{{ item.labelinCount }}</span><span class="total">{{ item.totalLabels }}</span> |
|
|
|
<span class="qualified">{{ selectedInbound.labelinCount }}</span><span class="total">{{ selectedInbound.totalLabels }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">物料总数</div> |
|
|
|
<div class="detail-value"> |
|
|
|
<span class="qualified">{{ item.totalinLabels }}</span><span class="total">{{ item.labelCount }}</span> |
|
|
|
<span class="qualified">{{ selectedInbound.totalinLabels }}</span><span class="total">{{ selectedInbound.labelCount }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">批次号</div> |
|
|
|
<div class="detail-value">{{ item.batchNo }}</div> |
|
|
|
<div class="detail-value">{{ selectedInbound.batchNo }}</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">创建日期</div> |
|
|
|
<div class="detail-value">{{ formatDate(item.inspectionDate) }}</div> |
|
|
|
<div class="detail-value">{{ formatDate(selectedInbound.inspectionDate) }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 空状态 --> |
|
|
|
<div v-if="qualifiedList.length === 0 && !loading" class="empty-state"> |
|
|
|
<i class="el-icon-box"></i> |
|
|
|
<p>暂无生产待入库物料</p> |
|
|
|
</div> |
|
|
|
<!-- 物料详情列表(小卡片) --> |
|
|
|
<div |
|
|
|
class="content-area" |
|
|
|
v-if="selectedInbound && detailList.length > 0" |
|
|
|
> |
|
|
|
<div |
|
|
|
v-for="(detail, index) in detailList" |
|
|
|
:key="index" |
|
|
|
class="detail-card" |
|
|
|
@click="selectDetail(detail)" |
|
|
|
> |
|
|
|
<!-- 第一行:关联单号(左)| 需求数量(右) --> |
|
|
|
<div class="card-row"> |
|
|
|
<span class="field-item"> |
|
|
|
<span class="field-label">关联单号:</span> |
|
|
|
<span class="field-value">{{ detail.relatedOrderNo }}</span> |
|
|
|
</span> |
|
|
|
<span class="field-item"> |
|
|
|
<span class="field-label">需求数量:</span> |
|
|
|
<span class="field-value">{{ detail.requiredQty || 0 }}</span> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 第二行:物料编码(左)| 单位(右) --> |
|
|
|
<div class="card-row"> |
|
|
|
<span class="field-item"> |
|
|
|
<span class="field-label">物料编码:</span> |
|
|
|
<span class="field-value">{{ detail.partNo }}</span> |
|
|
|
</span> |
|
|
|
<span class="field-item"> |
|
|
|
<span class="field-label">单位:</span> |
|
|
|
<span class="field-value">{{ detail.umName }}</span> |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 第三行:物料名称(全宽) --> |
|
|
|
<div class="card-row-full"> |
|
|
|
<span class="field-label">物料名称:</span> |
|
|
|
<span class="field-value">{{ detail.partDesc }}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 加载状态 --> |
|
|
|
<div v-if="loading" class="loading-state"> |
|
|
|
<i class="el-icon-loading"></i> |
|
|
|
<p>加载中...</p> |
|
|
|
<!-- 第四行:订单数量(全宽) --> |
|
|
|
<div class="card-row-full"> |
|
|
|
<span class="field-label">订单数量:</span> |
|
|
|
<span class="field-value">{{ detail.orderQty || 0 }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 物料详情加载状态 --> |
|
|
|
<div v-if="selectedInbound && detailListLoading" class="loading-state"> |
|
|
|
<i class="el-icon-loading"></i> |
|
|
|
<p>加载物料详情中...</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 物料详情空状态 --> |
|
|
|
<div v-if="selectedInbound && !detailListLoading && detailList.length === 0" class="empty-state"> |
|
|
|
<i class="el-icon-document"></i> |
|
|
|
<p>暂无物料详情</p> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { getQualifiedInboundList } from "@/api/production/production-inbound.js"; |
|
|
|
import { getQualifiedInboundList, getInboundNotificationDetails } from "@/api/production/production-inbound.js"; |
|
|
|
import { getCurrentWarehouse } from '@/utils' |
|
|
|
import moment from 'moment'; |
|
|
|
|
|
|
|
@ -84,7 +182,10 @@ export default { |
|
|
|
return { |
|
|
|
searchCode: '', |
|
|
|
qualifiedList: [], |
|
|
|
loading: false |
|
|
|
loading: false, |
|
|
|
selectedInbound: null, |
|
|
|
detailList: [], |
|
|
|
detailListLoading: false |
|
|
|
}; |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
@ -163,13 +264,66 @@ export default { |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
// 跳转到生产入库上架页面 |
|
|
|
goToInboundPage(item) { |
|
|
|
// 选择入库单 |
|
|
|
selectInbound(item) { |
|
|
|
this.selectedInbound = item; |
|
|
|
this.loadDetailList(item); |
|
|
|
}, |
|
|
|
|
|
|
|
// 取消选择入库单 |
|
|
|
deselectInbound() { |
|
|
|
this.selectedInbound = null; |
|
|
|
this.detailList = []; |
|
|
|
}, |
|
|
|
|
|
|
|
// 加载物料详情列表(小卡片) |
|
|
|
loadDetailList(item) { |
|
|
|
this.detailListLoading = true; |
|
|
|
|
|
|
|
const params = { |
|
|
|
site: localStorage.getItem('site'), |
|
|
|
buNo: item.buNo, |
|
|
|
orderNo: item.inboundNo |
|
|
|
}; |
|
|
|
|
|
|
|
getInboundNotificationDetails(params).then(({ data }) => { |
|
|
|
this.detailListLoading = false; |
|
|
|
if (data && data.code === 0) { |
|
|
|
this.detailList = (data.data || []).map((detail) => ({ |
|
|
|
...detail, |
|
|
|
// 映射后端字段到前端字段 |
|
|
|
orderNo: detail.orderNo, |
|
|
|
orderQty: detail.orderQty, |
|
|
|
requiredQty: detail.requiredQty, |
|
|
|
partNo: detail.partNo, |
|
|
|
partDesc: detail.partDesc, |
|
|
|
umName: detail.umName, |
|
|
|
relatedOrderNo: detail.relatedOrderNo, |
|
|
|
relatedOrderLineNo: detail.relatedOrderLineNo |
|
|
|
})); |
|
|
|
} else { |
|
|
|
this.$message.error(data.msg || '获取物料明细失败'); |
|
|
|
this.detailList = []; |
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
this.detailListLoading = false; |
|
|
|
console.error('获取物料明细失败:', error); |
|
|
|
this.$message.error('获取物料明细失败'); |
|
|
|
this.detailList = []; |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
// 选择物料详情,跳转到入库页面 |
|
|
|
selectDetail(detail) { |
|
|
|
this.$router.push({ |
|
|
|
name: 'productionInboundStorage', |
|
|
|
params: { |
|
|
|
buNo: item.buNo, |
|
|
|
inboundNo: item.inboundNo |
|
|
|
buNo: this.selectedInbound.buNo, |
|
|
|
inboundNo: this.selectedInbound.inboundNo, |
|
|
|
relatedOrderNo: detail.relatedOrderNo, |
|
|
|
relatedOrderLineNo: detail.relatedOrderLineNo, |
|
|
|
partNo: detail.partNo, |
|
|
|
partDesc: detail.partDesc |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
@ -235,40 +389,20 @@ export default { |
|
|
|
background: white; |
|
|
|
} |
|
|
|
|
|
|
|
.search-box { |
|
|
|
position: relative; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
background: #f8f9fa; |
|
|
|
border: 1px solid #e0e0e0; |
|
|
|
border-radius: 8px; |
|
|
|
padding: 0 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.search-icon { |
|
|
|
color: #999; |
|
|
|
font-size: 16px; |
|
|
|
margin-right: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.search-box input { |
|
|
|
flex: 1; |
|
|
|
border: none; |
|
|
|
background: transparent; |
|
|
|
padding: 12px 0; |
|
|
|
font-size: 14px; |
|
|
|
outline: none; |
|
|
|
} |
|
|
|
|
|
|
|
.search-box input::placeholder { |
|
|
|
color: #999; |
|
|
|
/* 入库单列表 */ |
|
|
|
.inbound-list { |
|
|
|
overflow-y: auto; |
|
|
|
padding: 12px 16px; |
|
|
|
} |
|
|
|
|
|
|
|
/* 内容区域 */ |
|
|
|
/* 内容区域(物料详情列表) */ |
|
|
|
.content-area { |
|
|
|
flex: 1; |
|
|
|
overflow-y: auto; |
|
|
|
padding: 12px 16px; |
|
|
|
padding: 8px 0 12px 0; |
|
|
|
background: #f8f9fa; |
|
|
|
margin: 0 16px 12px 16px; |
|
|
|
border-radius: 0 0 8px 8px; |
|
|
|
} |
|
|
|
|
|
|
|
/* 入库卡片 */ |
|
|
|
@ -280,6 +414,7 @@ export default { |
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.2s ease; |
|
|
|
border: 2px solid transparent; |
|
|
|
} |
|
|
|
|
|
|
|
.inbound-card:hover { |
|
|
|
@ -287,13 +422,56 @@ export default { |
|
|
|
transform: translateY(-1px); |
|
|
|
} |
|
|
|
|
|
|
|
.inbound-card.selected { |
|
|
|
border-color: #17B3A3; |
|
|
|
background: #f0fffe; |
|
|
|
} |
|
|
|
|
|
|
|
.inbound-card:active { |
|
|
|
transform: translateY(0); |
|
|
|
} |
|
|
|
|
|
|
|
/* 物料详情卡片(小卡片) */ |
|
|
|
.detail-card { |
|
|
|
background: white; |
|
|
|
border-radius: 6px; |
|
|
|
margin-bottom: 8px; |
|
|
|
margin-left: 20px; |
|
|
|
margin-right: 16px; |
|
|
|
padding: 12px; |
|
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.2s ease; |
|
|
|
border: 1px solid #e8f4f3; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card::before { |
|
|
|
content: ''; |
|
|
|
position: absolute; |
|
|
|
left: -12px; |
|
|
|
top: 50%; |
|
|
|
transform: translateY(-50%); |
|
|
|
width: 4px; |
|
|
|
height: 20px; |
|
|
|
background: #17B3A3; |
|
|
|
border-radius: 2px; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card:hover { |
|
|
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12); |
|
|
|
transform: translateY(-1px); |
|
|
|
border-color: #17B3A3; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card:active { |
|
|
|
transform: translateY(0); |
|
|
|
} |
|
|
|
|
|
|
|
/* 卡片标题 */ |
|
|
|
.card-title { |
|
|
|
margin-bottom: 12px; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.title-label { |
|
|
|
@ -307,7 +485,59 @@ export default { |
|
|
|
font-size: 16px; |
|
|
|
font-weight: bold; |
|
|
|
color: #333; |
|
|
|
margin-left: 20px; |
|
|
|
margin-left: 16px; |
|
|
|
} |
|
|
|
|
|
|
|
.back-icon { |
|
|
|
position: absolute; |
|
|
|
right: 16px; |
|
|
|
top: 50%; |
|
|
|
transform: translateY(-50%); |
|
|
|
font-size: 18px; |
|
|
|
color: #17B3A3; |
|
|
|
cursor: pointer; |
|
|
|
transition: color 0.2s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.back-icon:hover { |
|
|
|
color: #0d8f7f; |
|
|
|
} |
|
|
|
|
|
|
|
/* 物料详情卡片内的字段行样式 */ |
|
|
|
.detail-card .card-row { |
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
margin-bottom: 6px; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card .card-row-full { |
|
|
|
margin-bottom: 6px; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card .field-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
flex: 1; |
|
|
|
min-width: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card .field-label { |
|
|
|
font-size: 11px; |
|
|
|
color: #666; |
|
|
|
white-space: nowrap; |
|
|
|
margin-right: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card .field-value { |
|
|
|
font-size: 12px; |
|
|
|
color: #333; |
|
|
|
font-weight: 500; |
|
|
|
word-break: break-all; |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* 卡片详情 */ |
|
|
|
@ -411,14 +641,24 @@ export default { |
|
|
|
padding: 8px 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.inbound-list { |
|
|
|
padding: 8px 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.content-area { |
|
|
|
padding: 8px 12px; |
|
|
|
margin: 0 12px 8px 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.inbound-card { |
|
|
|
padding: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card { |
|
|
|
margin-left: 16px; |
|
|
|
margin-right: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-details { |
|
|
|
flex-wrap: wrap; |
|
|
|
gap: 6px; |
|
|
|
@ -429,5 +669,10 @@ export default { |
|
|
|
margin-bottom: 6px; |
|
|
|
min-width: 50px; |
|
|
|
} |
|
|
|
|
|
|
|
.detail-card .field-item { |
|
|
|
flex: 0 0 45%; |
|
|
|
min-width: 40px; |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |