|
|
|
@ -13,34 +13,25 @@ |
|
|
|
|
|
|
|
<!-- 搜索框 --> |
|
|
|
<div class="search-container"> |
|
|
|
<el-input clearable |
|
|
|
v-model="searchCode" |
|
|
|
placeholder="请输入MR号" |
|
|
|
prefix-icon="el-icon-search" |
|
|
|
@keyup.enter.native="handleSearch" |
|
|
|
ref="searchInput" |
|
|
|
/> |
|
|
|
<el-input clearable v-model="searchCode" placeholder="请输入MR号" prefix-icon="el-icon-search" |
|
|
|
@keyup.enter.native="handleSearch" ref="searchInput" /> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- MR列表 --> |
|
|
|
<div class="content-area"> |
|
|
|
<div |
|
|
|
v-for="(item, index) in mrList" |
|
|
|
:key="index" |
|
|
|
class="mr-card" |
|
|
|
@click="goToMaterialSelection(item)" |
|
|
|
> |
|
|
|
<!-- MR工单列表 --> |
|
|
|
<div class="work-order-list" v-if="mrList.length > 0"> |
|
|
|
<div v-for="(item, index) in displayMrList" :key="index" |
|
|
|
:class="['work-order-card', { selected: selectedMr && isSameMr(selectedMr, item) }]" @click="selectMr(item)"> |
|
|
|
<div class="card-title"> |
|
|
|
<span class="title-label">MR号:{{ item.orderNo }} 行号:{{ item.lineNo }}</span> |
|
|
|
<span class="title-label">MR号:{{ item.orderNo }} 客户号:{{ item.intCustomerNo }}</span> |
|
|
|
<span class="title-value">{{ item.partNo }}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 物料描述单独一行 --> |
|
|
|
<div class="part-desc-row"> |
|
|
|
<span class="desc-text">{{ item.partDesc }}</span> |
|
|
|
<span class="desc-text">目的地:{{ item.intDestDesc }}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="card-details"> |
|
|
|
<!-- <div class="card-details"> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">需求数量</div> |
|
|
|
<div class="detail-value">{{ item.qtyDue }}</div> |
|
|
|
@ -53,130 +44,233 @@ |
|
|
|
<div class="detail-label">单位</div> |
|
|
|
<div class="detail-value">{{ item.unitMeas }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> --> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 空状态 --> |
|
|
|
<div v-if="mrList.length === 0 && !loading" class="empty-state"> |
|
|
|
<i class="el-icon-box"></i> |
|
|
|
<p>暂无MR数据</p> |
|
|
|
</div> |
|
|
|
<!-- 材料列表 --> |
|
|
|
<div class="content-area" v-if="selectedMr && materialList.length > 0"> |
|
|
|
<div v-for="(material, index) in materialList" :key="index" class="material-card" |
|
|
|
@click="selectMaterial(material)"> |
|
|
|
<div class="card-title"> |
|
|
|
<span class="title-label">物料编码:{{ material.partNo }} 行号:{{ material.lineNo }}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 物料描述单独一行 --> |
|
|
|
<div class="part-desc-row"> |
|
|
|
<span class="desc-text">{{ material.partDesc }}</span> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 加载状态 --> |
|
|
|
<div v-if="loading" class="loading-state"> |
|
|
|
<i class="el-icon-loading"></i> |
|
|
|
<p>加载中...</p> |
|
|
|
<div class="card-details"> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">需求数量</div> |
|
|
|
<div class="detail-value">{{ material.qtyIssued }}</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">到期数量</div> |
|
|
|
<div class="detail-value">{{ material.qtyDue || 0 }}</div> |
|
|
|
</div> |
|
|
|
<div class="detail-item"> |
|
|
|
<div class="detail-label">单位</div> |
|
|
|
<div class="detail-value">{{ material.unitMeas }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 空状态 --> |
|
|
|
<div v-if="selectedMr && materialList.length === 0" class="empty-state"> |
|
|
|
<i class="el-icon-box"></i> |
|
|
|
<p>该MR暂无材料清单</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div v-if="mrList.length === 0 && !loading" class="empty-state"> |
|
|
|
<i class="el-icon-box"></i> |
|
|
|
<p>暂无MR数据</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 加载状态 --> |
|
|
|
<div v-if="loading" class="loading-state"> |
|
|
|
<i class="el-icon-loading"></i> |
|
|
|
<p>加载中...</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { getMrList } from '@/api/mr/mr' |
|
|
|
import moment from 'moment'; |
|
|
|
import { getMrList, getMrMaterialLines } from '@/api/mr/mr' |
|
|
|
import moment from 'moment' |
|
|
|
|
|
|
|
export default { |
|
|
|
data() { |
|
|
|
return { |
|
|
|
searchCode: '', |
|
|
|
mrList: [], |
|
|
|
loading: false |
|
|
|
}; |
|
|
|
selectedMr: null, |
|
|
|
materialList: [], |
|
|
|
loading: false, |
|
|
|
showOnlySelected: false, |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
displayMrList() { |
|
|
|
if (this.showOnlySelected && this.selectedMr) { |
|
|
|
return [this.selectedMr] |
|
|
|
} |
|
|
|
return this.mrList |
|
|
|
}, |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
formatDate(date) { |
|
|
|
return date ? moment(date).format('YYYY-MM-DD') : ''; |
|
|
|
return date ? moment(date).format('YYYY-MM-DD') : '' |
|
|
|
}, |
|
|
|
|
|
|
|
// 处理搜索 |
|
|
|
handleSearch() { |
|
|
|
if (this.searchCode.trim()) { |
|
|
|
this.searchMrList(this.searchCode.trim()); |
|
|
|
} else { |
|
|
|
this.loadMrList(); |
|
|
|
this.searchMrList(this.searchCode.trim()) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 加载MR列表 |
|
|
|
loadMrList() { |
|
|
|
this.loading = true; |
|
|
|
this.loading = true |
|
|
|
const params = { |
|
|
|
site: this.$store.state.user.site, |
|
|
|
} |
|
|
|
|
|
|
|
getMrList(params).then(({ data }) => { |
|
|
|
this.loading = false; |
|
|
|
if (data && data.code === 0) { |
|
|
|
this.mrList = data.list || []; |
|
|
|
} else { |
|
|
|
this.$message.error(data.msg || '获取数据失败'); |
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
this.loading = false; |
|
|
|
console.error('获取MR列表失败:', error); |
|
|
|
this.$message.error('获取数据失败'); |
|
|
|
}); |
|
|
|
getMrList(params) |
|
|
|
.then(({ data }) => { |
|
|
|
this.loading = false |
|
|
|
if (data && data.code === 0) { |
|
|
|
this.mrList = data.list || [] |
|
|
|
} else { |
|
|
|
this.$message.error(data.msg || '获取数据失败') |
|
|
|
} |
|
|
|
}) |
|
|
|
.catch((error) => { |
|
|
|
this.loading = false |
|
|
|
console.error('获取MR列表失败:', error) |
|
|
|
this.$message.error('获取数据失败') |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 搜索特定MR |
|
|
|
searchMrList(searchCode) { |
|
|
|
this.loading = true; |
|
|
|
this.loading = true |
|
|
|
const params = { |
|
|
|
orderNo: searchCode, |
|
|
|
site: this.$store.state.user.site, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
getMrList(params) |
|
|
|
.then(({ data }) => { |
|
|
|
this.loading = false |
|
|
|
if (data && data.code === 0) { |
|
|
|
if (data.list.length === 0) { |
|
|
|
this.$message.warning('未找到匹配的MR') |
|
|
|
} |
|
|
|
this.mrList = data.list || [] |
|
|
|
// 重置选择状态 |
|
|
|
this.selectedMr = null |
|
|
|
this.materialList = [] |
|
|
|
this.showOnlySelected = false |
|
|
|
} else { |
|
|
|
this.$message.error(data.msg || '查询失败') |
|
|
|
} |
|
|
|
}) |
|
|
|
.catch((error) => { |
|
|
|
this.loading = false |
|
|
|
this.$message.error('查询失败') |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 判断是否为同一MR |
|
|
|
isSameMr(a, b) { |
|
|
|
if (!a || !b) return false |
|
|
|
return a.orderNo === b.orderNo && a.lineNo === b.lineNo |
|
|
|
}, |
|
|
|
|
|
|
|
// 选择MR(支持再次点击切换显示所有) |
|
|
|
selectMr(mr) { |
|
|
|
if ( |
|
|
|
this.showOnlySelected && |
|
|
|
this.selectedMr && |
|
|
|
this.isSameMr(this.selectedMr, mr) |
|
|
|
) { |
|
|
|
// 再次点击同一条,恢复显示所有主数据 |
|
|
|
this.selectedMr = null |
|
|
|
this.materialList = [] |
|
|
|
this.showOnlySelected = false |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 选择并仅显示当前MR |
|
|
|
this.selectedMr = mr |
|
|
|
this.showOnlySelected = true |
|
|
|
this.loadMaterialList() |
|
|
|
}, |
|
|
|
|
|
|
|
getMrList(params).then(({ data }) => { |
|
|
|
this.loading = false; |
|
|
|
if (data && data.code === 0) { |
|
|
|
if (data.list.length === 0) { |
|
|
|
this.$message.warning('未找到匹配的MR'); |
|
|
|
// 加载材料清单 |
|
|
|
loadMaterialList() { |
|
|
|
if (!this.selectedMr) { |
|
|
|
this.materialList = [] |
|
|
|
return |
|
|
|
} |
|
|
|
let params = { |
|
|
|
orderNo: this.selectedMr.orderNo, |
|
|
|
site: this.$store.state.user.site, |
|
|
|
} |
|
|
|
getMrMaterialLines(params) |
|
|
|
.then(({ data }) => { |
|
|
|
this.loading = false |
|
|
|
if (data && data.code === 0) { |
|
|
|
if (data.list.length === 0) { |
|
|
|
this.$message.warning('未找到匹配的MR') |
|
|
|
} |
|
|
|
this.materialList = data.list || [] |
|
|
|
} else { |
|
|
|
this.$message.error(data.msg || '查询失败') |
|
|
|
} |
|
|
|
this.mrList = data.list || []; |
|
|
|
} else { |
|
|
|
this.$message.error(data.msg || '查询失败'); |
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
this.loading = false; |
|
|
|
this.$message.error('查询失败'); |
|
|
|
}); |
|
|
|
}) |
|
|
|
.catch((error) => { |
|
|
|
this.loading = false |
|
|
|
this.$message.error('查询失败') |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
// 跳转到材料选择 |
|
|
|
goToMaterialSelection(mr) { |
|
|
|
// 直接跳转到发料详情页面,传递完整的MR信息 |
|
|
|
// 选择材料,跳转到发料详情页 |
|
|
|
selectMaterial(material) { |
|
|
|
this.$router.push({ |
|
|
|
name: 'mrPickingDetail', |
|
|
|
params: { |
|
|
|
orderNo: mr.orderNo, |
|
|
|
lineNo: mr.lineNo, |
|
|
|
partNo: mr.partNo, |
|
|
|
partDesc: mr.partDesc, |
|
|
|
qtyDue: mr.qtyDue, |
|
|
|
qtyIssued: mr.qtyIssued, |
|
|
|
unitMeas: mr.unitMeas, |
|
|
|
statusCode: mr.statusCode, |
|
|
|
releaseNo: mr.releaseNo, |
|
|
|
dueDate: mr.dueDate |
|
|
|
} |
|
|
|
}); |
|
|
|
orderNo: this.selectedMr.orderNo, |
|
|
|
lineNo: material.lineNo, |
|
|
|
partNo: material.partNo, |
|
|
|
material: { |
|
|
|
partDesc: material.partDesc, |
|
|
|
qtyDue: material.qtyDue, |
|
|
|
qtyIssued: material.qtyIssued, |
|
|
|
unitMeas: material.unitMeas, |
|
|
|
statusCode: material.statusCode, |
|
|
|
releaseNo: material.releaseNo, |
|
|
|
dueDate: material.dueDate, |
|
|
|
}, |
|
|
|
}, |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
mounted() { |
|
|
|
// 聚焦搜索框 |
|
|
|
this.$nextTick(() => { |
|
|
|
if (this.$refs.searchInput) { |
|
|
|
this.$refs.searchInput.focus(); |
|
|
|
this.$refs.searchInput.focus() |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 加载数据 |
|
|
|
this.loadMrList(); |
|
|
|
} |
|
|
|
}; |
|
|
|
}) |
|
|
|
}, |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped> |
|
|
|
@ -194,7 +288,7 @@ export default { |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
padding: 8px 16px; |
|
|
|
background: #17B3A3; |
|
|
|
background: #17b3a3; |
|
|
|
color: white; |
|
|
|
height: 40px; |
|
|
|
min-height: 40px; |
|
|
|
@ -225,6 +319,38 @@ export default { |
|
|
|
background: white; |
|
|
|
} |
|
|
|
|
|
|
|
/* 工单列表 */ |
|
|
|
.work-order-list { |
|
|
|
overflow-y: auto; |
|
|
|
padding: 12px 16px; |
|
|
|
} |
|
|
|
|
|
|
|
/* 工单卡片 */ |
|
|
|
.work-order-card { |
|
|
|
background: white; |
|
|
|
border-radius: 8px; |
|
|
|
margin-bottom: 12px; |
|
|
|
padding: 16px; |
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.2s ease; |
|
|
|
border: 2px solid transparent; |
|
|
|
} |
|
|
|
|
|
|
|
.work-order-card:hover { |
|
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); |
|
|
|
transform: translateY(-1px); |
|
|
|
} |
|
|
|
|
|
|
|
.work-order-card.selected { |
|
|
|
border-color: #17b3a3; |
|
|
|
background: #f0fffe; |
|
|
|
} |
|
|
|
|
|
|
|
.work-order-card:active { |
|
|
|
transform: translateY(0); |
|
|
|
} |
|
|
|
|
|
|
|
/* 内容区域 */ |
|
|
|
.content-area { |
|
|
|
flex: 1; |
|
|
|
@ -232,8 +358,8 @@ export default { |
|
|
|
padding: 12px 16px; |
|
|
|
} |
|
|
|
|
|
|
|
/* MR卡片 */ |
|
|
|
.mr-card { |
|
|
|
/* 材料卡片 */ |
|
|
|
.material-card { |
|
|
|
background: white; |
|
|
|
border-radius: 8px; |
|
|
|
margin-bottom: 12px; |
|
|
|
@ -241,14 +367,20 @@ export default { |
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.2s ease; |
|
|
|
border: 2px solid transparent; |
|
|
|
} |
|
|
|
|
|
|
|
.mr-card:hover { |
|
|
|
.material-card:hover { |
|
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); |
|
|
|
transform: translateY(-1px); |
|
|
|
} |
|
|
|
|
|
|
|
.mr-card:active { |
|
|
|
.material-card.selected { |
|
|
|
border-color: #17b3a3; |
|
|
|
background: #f0fffe; |
|
|
|
} |
|
|
|
|
|
|
|
.material-card:active { |
|
|
|
transform: translateY(0); |
|
|
|
} |
|
|
|
|
|
|
|
@ -341,7 +473,7 @@ export default { |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
padding: 60px 20px; |
|
|
|
color: #17B3A3; |
|
|
|
color: #17b3a3; |
|
|
|
} |
|
|
|
|
|
|
|
.loading-state i { |
|
|
|
@ -351,8 +483,12 @@ export default { |
|
|
|
} |
|
|
|
|
|
|
|
@keyframes spin { |
|
|
|
from { transform: rotate(0deg); } |
|
|
|
to { transform: rotate(360deg); } |
|
|
|
from { |
|
|
|
transform: rotate(0deg); |
|
|
|
} |
|
|
|
to { |
|
|
|
transform: rotate(360deg); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.loading-state p { |
|
|
|
@ -370,11 +506,19 @@ export default { |
|
|
|
padding: 8px 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.work-order-list { |
|
|
|
padding: 8px 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.work-order-card { |
|
|
|
padding: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.content-area { |
|
|
|
padding: 8px 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.mr-card { |
|
|
|
.material-card { |
|
|
|
padding: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
|