Browse Source

申请单领料修改

master
shenzhouyu 3 months ago
parent
commit
1e3e687d03
  1. 2
      src/api/production/production-issue.js
  2. 2
      src/router/index.js
  3. 2
      src/views/modules/production-issue/production.vue
  4. 260
      src/views/modules/production-issue/productionPicking.vue
  5. 115
      src/views/modules/production-issue/productionPickingDetail.vue

2
src/api/production/production-issue.js

@ -41,4 +41,6 @@ export const scanMaterialLabelDirect = data => createAPI(`/pda/production/issue/
// 确认直接发料
export const confirmDirectIssue = data => createAPI(`/pda/production/issue/confirmDirectIssue`,'post',data)
export const confirmProductionPicking = data => createAPI(`/pda/production/issue/confirmProductionPicking`,'post',data)

2
src/router/index.js

@ -49,7 +49,7 @@ const globalRoutes = [
// 生产发料
{path: "/productionissue",name: "productionissue", component: resolve => require(["@/views/modules/production-issue/production.vue"], resolve), meta: { transition: 'instant' ,preload: true,keepAlive: true}},
{ path: "/productionPicking", name: "productionPicking", component: resolve => require(["@/views/modules/production-issue/productionPicking.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true } },
{ path: "/productionPickingDetail/:outboundNo", name: "productionPickingDetail", component: resolve => require(["@/views/modules/production-issue/productionPickingDetail.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true } },
{ path: "/productionPickingDetail", name: "productionPickingDetail", component: resolve => require(["@/views/modules/production-issue/productionPickingDetail.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true } },
{ path: "/directIssue", name: "directIssue", component: resolve => require(["@/views/modules/production-issue/directIssue.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true } },
{ path: "/directIssueDetail", name: "directIssueDetail", component: resolve => require(["@/views/modules/production-issue/directIssueDetail.vue"], resolve), meta: { transition: 'instant', preload: true, keepAlive: true } },
//生产退料

2
src/views/modules/production-issue/production.vue

@ -43,7 +43,7 @@ export default {
label: "申请单领料",
iconClass: "qualified",
to: "productionPicking",
disabled: true,
disabled: false,
},
{
icon: "records",

260
src/views/modules/production-issue/productionPicking.vue

@ -21,39 +21,38 @@
ref="searchInput"
/>
</div>
<!-- 工单信息卡片列表 -->
<div class="work-order-list" v-if="outboundList.length > 0">
<!-- 工单信息卡片列表对齐申请单退料样式/逻辑 -->
<div class="work-order-list" v-if="displayOutboundList.length > 0 ">
<div
v-for="(workOrder, index) in outboundList"
:key="index"
class="work-order-card"
v-for="workOrder in displayOutboundList"
:key="workOrder.orderNo || workOrder.soorderNo"
:class="['work-order-card', { selected: selectedWorkOrder && isSameWorkOrder(selectedWorkOrder, workOrder) }]"
@click="selectWorkOrder(workOrder)"
>
<div class="card-title">
<span class="title-label">工单号{{ workOrder.orderNo }}</span>
<span class="title-label">申请单号{{ currentNotifyNo }}</span>
</div>
<!-- 工单号单独一行 -->
<div class="part-desc-row">
<span class="title-value">{{ workOrder.partNo }}</span>
<span class="desc-text">工单号{{ workOrder.orderNo || workOrder.soorderNo }}</span>
</div>
<!-- 物料描述单独一行 -->
<div class="part-desc-row">
<span class="desc-text">{{ workOrder.partDesc }}</span>
<span class="desc-text">物料号{{ workOrder.fgpartNo }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">计划数量</div>
<div class="detail-value">{{ workOrder.lotSize }}</div>
<div class="detail-label">需求日期</div>
<div class="detail-value">{{ workOrder.needDate }}</div>
</div>
<div class="detail-item">
<div class="detail-label">状态</div>
<div class="detail-value">{{ workOrder.status }}</div>
<div class="detail-value">{{ workOrder.status || '待发料' }}</div>
</div>
<div class="detail-item">
<div class="detail-label">单位</div>
<div class="detail-value">{{ workOrder.uom || "个" }}</div>
<div class="detail-label">行号</div>
<div class="detail-value">{{ workOrder.itemNo }}</div>
</div>
</div>
</div>
@ -67,29 +66,26 @@
v-for="(material, index) in materialList"
:key="index"
class="material-card"
@click="openIssueList(material)"
@click="goToPickingPage(material)"
>
<div class="card-title">
<span class="title-label"
>物料编码{{ material.componentPartNo }} &nbsp;&nbsp; 行号{{
material.lineNo || index + 1
}}</span
>
>物料编码{{ material.partNo }} &nbsp;&nbsp;</span>
</div>
<!-- 物料描述单独一行 -->
<div class="part-desc-row">
<span class="desc-text">{{ material.componentPartDesc }}</span>
<span class="desc-text">{{ material.partDesc || material.componentPartDesc }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">需求数量</div>
<div class="detail-value">{{ material.qtyRequired }}</div>
<div class="detail-value">{{ material.requestQty }}</div>
</div>
<div class="detail-item">
<div class="detail-label">已发数量</div>
<div class="detail-value">{{ material.qtyIssued || 0 }}</div>
<div class="detail-label">申请物料行号</div>
<div class="detail-value">{{ material.bomItemNo }}</div>
</div>
<div class="detail-item">
<div class="detail-label">单位</div>
@ -98,59 +94,19 @@
</div>
</div>
</div>
<!-- 出库单列表 -->
<div class="content-area">
<div
v-for="(item, index) in outboundList"
:key="index"
class="outbound-card"
@click="goToPickingPage(item)"
>
<div class="card-title">
<span class="title-label">出库单号</span>
<span class="title-value">{{ item.notifyNo }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">关联单号</div>
<div class="detail-value">{{ item.workOrderNo }}</div>
</div>
<div class="detail-item">
<div class="detail-label">标签张数</div>
<div class="detail-value">
<span class="qualified">{{ item.pickedLabels }}</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.requestQty }}</span><span class="total">{{ item.remainQty }}</span>
</div>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="outboundList.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>
<!-- 加载状态 -->
<div v-if="loading" class="loading-state">
<i class="el-icon-loading"></i>
<p>加载中...</p>
</div>
</div>
</template>
<script>
import {
getIssureNotifyByNo,
getIssueNotifyHeaderInfo
getIssueNotifyHeaderInfo,
getRequestMaterials
} from '@/api/production/production-issue'
import { getCurrentWarehouse } from '@/utils'
import moment from 'moment';
@ -159,74 +115,61 @@ export default {
data() {
return {
searchCode: '',
currentNotifyNo: '',
outboundList: [],
loading: false
loading: false,
selectedWorkOrder: null,
materialList:[],
showOnlySelected: false
};
},
computed: {
displayOutboundList() {
if (this.showOnlySelected && this.selectedWorkOrder) {
return [this.selectedWorkOrder]
}
return this.outboundList
}
},
methods: {
formatDate(date) {
return date ? moment(date).format('YYYY-MM-DD') : '';
},
//
//
handleSearch() {
if (this.searchCode.trim()) {
this.searchOutboundList(this.searchCode.trim());
} else {
this.loadOutboundList();
const code = this.searchCode.trim()
if (!code) {
this.$message.warning('请扫描领料申请单号')
return
}
this.searchOutboundList(code)
},
//
//
loadOutboundList() {
/* const currentWarehouse = getCurrentWarehouse();
if (!currentWarehouse) {
this.$message.error('请先选择仓库');
return;
} */
this.loading = true;
const params = {
site: localStorage.getItem('site'),
status: '待出库',
}
console.log('params', params);
getIssueNotifyHeaderInfo(params).then(({ data }) => {
this.loading = false;
if (data && data.code === 0) {
this.outboundList = data.list || [];
} else {
this.$message.error(data.msg || '获取数据失败');
}
}).catch(error => {
this.loading = false;
console.error('获取生产出库单列表失败:', error);
this.$message.error('获取数据失败');
});
//
this.outboundList = []
},
//
//
searchOutboundList(searchCode) {
/* const currentWarehouse = getCurrentWarehouse();
if (!currentWarehouse) {
this.$message.error('请先选择仓库');
return;
} */
this.loading = true;
this.selectedWorkOrder = null
this.materialList = []
const params = {
notifyNo: searchCode,
site: localStorage.getItem('site'),
status: 'ISSUE'
site: localStorage.getItem('site')
};
getIssueNotifyHeaderInfo(params).then(({ data }) => {
this.loading = false;
if (data && data.code === 0) {
if (data.list.length === 0) {
this.$message.warning('未找到匹配的出库单');
const list = data.notify || []
if (list.length === 0) {
this.$message.warning('未找到该申请单的工单信息');
}
this.outboundList = data.list || [];
this.currentNotifyNo = searchCode
this.outboundList = list;
} else {
this.$message.error(data.msg || '查询失败');
}
@ -236,25 +179,45 @@ export default {
});
},
//
isSameWorkOrder(a, b) {
if (!a || !b) return false
return (a.orderNo || a.soorderNo) === (b.orderNo || b.soorderNo)
},
// 绿
selectWorkOrder(workOrder) {
this.selectedWorkOrder = workOrder;
this.loadMaterialList();
if (
this.showOnlySelected &&
this.selectedWorkOrder &&
this.isSameWorkOrder(this.selectedWorkOrder, workOrder)
) {
//
this.selectedWorkOrder = null
this.materialList = []
this.showOnlySelected = false
return
}
//
this.selectedWorkOrder = workOrder
this.showOnlySelected = true
this.loadMaterialList()
},
// BOM
//
loadMaterialList() {
if (!this.selectedWorkOrder) {
if (!this.selectedWorkOrder || !this.currentNotifyNo) {
this.materialList = [];
return;
}
const params = {
workOrderNo: this.selectedWorkOrder.orderNo,
notifyNo: this.currentNotifyNo,
site: localStorage.getItem('site'),
itemNo: this.selectedWorkOrder.itemNo
};
/* getWorkOrderMaterials(params)
getRequestMaterials(params)
.then(({ data }) => {
if (data && data.code === 0) {
this.materialList = (data.materials || []).map((item, index) => ({
@ -267,17 +230,27 @@ export default {
}
})
.catch((error) => {
console.error('获取材料清单失败:', error);
this.$message.error('获取材料清单失败');
}); */
this.materialList = [];
});
},
//
goToPickingPage(item) {
console.log("选中物料:", item, this.selectedWorkOrder);
this.$router.push({
name: 'productionPickingDetail',
params: {
query: {
outboundNo: item.notifyNo,
notifyInfo: {
orderNo: this.selectedWorkOrder.soorderNo,
componentPartNo: item.partNo,
qtyToIssue: item.requestQty,
lineItemNo: item.bomItemNo,
releaseNo: this.selectedWorkOrder.releaseNo,
sequenceNo: this.selectedWorkOrder.sequenceNo,
}
}
});
}
@ -350,6 +323,28 @@ export default {
padding: 12px 16px;
}
/* 物料卡片(对齐 productionReturnPDA.vue) */
.material-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;
}
.material-card:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
transform: translateY(-1px);
}
.material-card.selected {
border-color: #17b3a3;
background: #f0fffe;
}
/* 出库卡片 */
.outbound-card {
background: white;
@ -389,6 +384,19 @@ export default {
margin-left: 20px;
}
/* 物料描述行(对齐 productionReturnPDA.vue) */
.part-desc-row {
margin-bottom: 12px;
padding: 0 4px;
}
.desc-text {
font-size: 12px;
color: #666;
line-height: 1.3;
word-break: break-all;
}
/* 卡片详情 */
.card-details {
display: flex;

115
src/views/modules/production-issue/productionPickingDetail.vue

@ -33,27 +33,34 @@
</div>
<!-- 出库单信息卡片 -->
<div class="material-info-card" v-if="outboundInfo.outboundNo">
<div class="material-info-card" v-if="outboundNo">
<div class="card-title">
<span class="title-label">出库单号</span>
<span class="title-value">{{ outboundInfo.outboundNo }}</span>
<span class="title-label">出库单号:{{ outboundInfo.outboundNo }}</span>
</div>
<div class="card-title">
<span class="title-label">工单号:{{ outboundInfo.orderNo }}</span>
</div>
<div class="card-title">
<span class="title-label">物料号:{{ outboundInfo.componentPartNo }}</span>
</div>
<div class="card-details">
<div class="detail-item">
<div class="detail-label">关联单号</div>
<div class="detail-value">{{ outboundInfo.relatedNo }}</div>
<div class="detail-label">需求数量</div>
<div class="detail-value">
<span class="qualified">{{ outboundInfo.qtyToIssue }}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-label">标签张数</div>
<div class="detail-label">需求数量</div>
<div class="detail-value">
<span class="qualified">{{ outboundInfo.pickedLabels }}</span><span class="total">{{ outboundInfo.totalLabels }}</span>
<span class="qualified">{{ outboundInfo.qtyToIssue }}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-label">物料总数</div>
<div class="detail-label">需求数量</div>
<div class="detail-value">
<span class="qualified">{{ outboundInfo.pickedQty }}</span><span class="total">{{ outboundInfo.totalQty }}</span>
<span class="qualified">{{ outboundInfo.qtyToIssue }}</span>
</div>
</div>
</div>
@ -65,9 +72,9 @@
<i class="el-icon-circle-check"></i>
<span>出库信息确认</span>
</div>
<div class="title-right">
<!-- <div class="title-right">
<span class="material-list-link" @click="showMaterialListDialog">物料清单</span>
</div>
</div> -->
</div>
<!-- 标签列表 -->
@ -75,8 +82,7 @@
<div class="list-header">
<div class="col-no">NO.</div>
<div class="col-label">标签条码</div>
<div class="col-part">物料编码</div>
<div class="col-unit">单位</div>
<div class="col-part">库位</div>
<div class="col-qty">标签数量</div>
</div>
@ -87,8 +93,7 @@
>
<div class="col-no">{{ labelList.length - index }}</div>
<div class="col-label">{{ label.labelCode }}</div>
<div class="col-part">{{ label.partNo }}</div>
<div class="col-unit">{{ label.unit || '个' }}</div>
<div class="col-part">{{ label.locationId }}</div>
<div class="col-qty">{{ label.quantity }}</div>
</div>
@ -103,9 +108,9 @@
<button class="action-btn secondary" @click="confirmOutbound">
确定
</button>
<button class="action-btn secondary" style="margin-left: 10px;" @click="printLabels">
<!-- <button class="action-btn secondary" style="margin-left: 10px;" @click="printLabels">
打印
</button>
</button> -->
<button class="action-btn secondary" style="margin-left: 10px;" @click="cancelOutbound">
取消
</button>
@ -165,7 +170,7 @@
</template>
<script>
import { scanMaterialLabelIssue,getRequestMaterials } from '@/api/production/production-issue';
import { scanMaterialLabelIssue,getRequestMaterials,confirmProductionPicking } from '@/api/production/production-issue';
import moment from 'moment';
import { notify } from 'node-notifier';
@ -204,9 +209,10 @@ export default {
//
validateAndAddLabel(labelCode) {
const params = {
labelCode: labelCode,
scannedLabel: labelCode,
notifyNo: this.outboundNo,
site: localStorage.getItem('site'),
componentPartNo: this.outboundInfo.componentPartNo
};
scanMaterialLabelIssue(params).then(({ data }) => {
@ -223,9 +229,12 @@ export default {
id: Date.now(),
labelCode: labelCode,
partNo: data.labelInfo.partNo,
quantity: data.labelInfo.quantity,
quantity: data.labelInfo.availableQty,
unit: data.labelInfo.unit,
batchNo: data.labelInfo.batchNo
batchNo: data.labelInfo.batchNo,
locationId: data.labelInfo.locationId,
warehouseId: data.labelInfo.warehouseId,
wdrNo: data.labelInfo.wdrNo,
});
this.$message.success('操作成功');
@ -254,16 +263,46 @@ export default {
this.$message.warning('请先扫描标签');
return;
}
let qty = 0;
for(const label of this.labelList) {
if (label.quantity <= 0) {
this.$message.warning(`标签 ${label.labelCode} 数量无效`);
return;
}
qty += label.quantity;
}
if (qty > this.outboundInfo.qtyToIssue) {
this.$message.warning('扫描标签总数量超过需求数量');
this.$confirm('取消后将清空已扫描的标签,确定取消吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '继续操作',
type: 'warning'
}).then(() => {
this.confirmProductionPicking();
})
}else{
this.confirmProductionPicking();
}
},
confirmProductionPicking(){
const params = {
site: this.outboundInfo.site,
outboundNo: this.outboundNo,
labels: this.labelList.map(label => ({
labelCode: label.labelCode,
quantity: label.quantity,
batchNo: label.batchNo,
partNo: label.partNo
}))
site: localStorage.getItem('site'),
workOrderNo: this.outboundInfo.orderNo,
componentPartNo: this.outboundInfo.componentPartNo,
operatorName: localStorage.getItem('userName'),
itemNo: this.outboundInfo.lineItemNo,
releaseNo:this.outboundInfo.releaseNo,
sequenceNo:this.outboundInfo.sequenceNo,
selectedMaterials: this.labelList.map((l, i) => ({
labelCode: l.labelCode,
issueQty: l.quantity,
batchNo: l.batchNo,
warehouseId: l.warehouseId,
locationId: l.locationId,
materialCode: l.materialCode,
wdrNo: l.wdrNo
})),
};
confirmProductionPicking(params).then(({ data }) => {
@ -370,8 +409,16 @@ export default {
mounted() {
//
this.outboundNo = this.$route.params.outboundNo;
console.log("11111",this.outboundNo);
this.outboundNo = this.$route.query.outboundNo
this.outboundInfo.outboundNo = this.$route.query.outboundNo
this.outboundInfo.orderNo = this.$route.query.notifyInfo.orderNo
this.outboundInfo.componentPartNo = this.$route.query.notifyInfo.componentPartNo
this.outboundInfo.qtyToIssue = this.$route.query.notifyInfo.qtyToIssue
this.outboundInfo.lineItemNo = this.$route.query.notifyInfo.lineItemNo
this.outboundInfo.releaseNo = this.$route.query.notifyInfo.releaseNo
this.outboundInfo.sequenceNo = this.$route.query.notifyInfo.sequenceNo
console.log("路由参数:", this.$route.query.notifyInfo );
if (!this.outboundNo) {
@ -524,7 +571,7 @@ export default {
/* 物料信息卡片 */
.material-info-card {
background: white;
margin: 4px 16px;
margin: 4px 10px;
padding: 6px 20px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
@ -604,7 +651,7 @@ export default {
justify-content: space-between;
padding: 6px 8px;
background: white;
margin: 0 16px;
margin: 0 10px;
margin-top: 4px;
border-radius: 8px 8px 0 0;
border-bottom: 2px solid #17B3A3;

Loading…
Cancel
Save