Browse Source

修复退料新建标签没有partdesc,在shipment发料添加校验,扫描必须是这个shipment下的物料

dev
shenzhouyu 6 days ago
parent
commit
f0f066701b
  1. 56
      src/views/modules/customerIssue/customerIssuePDA.vue
  2. 322
      src/views/modules/customerIssue/customerIssuePDAIssueList.vue
  3. 7
      src/views/modules/production-return/productionReturnPDAIssueList.vue
  4. 29
      src/views/modules/production-return/productionReturnPickingDetail.vue

56
src/views/modules/customerIssue/customerIssuePDA.vue

@ -275,22 +275,60 @@ export default {
},
// 仿 productionReturnPicking.vue openIssueList
// ShipmentLine IFS
openIssueDetail(material) {
const site = this.getMaterialSite(material) || this.requestIssueForm.site
if (!site) {
this.$message.warning('未获取到申请单站点信息')
return
}
this.$router.push({
name: 'customerIssuePDAIssueList',
query: {
state: material.STATE, //
shipmentId: material.SHIPMENT_ID, //
orderType: material.SHIPMENT_TYPE, //
site,
}
const shipmentId = material.SHIPMENT_ID
if (!shipmentId) {
this.$message.warning('未获取到发货单号')
return
}
if (this.loading) {
return
}
this.loading = true
this.loadingText = '加载发货单物料...'
getCustomerIssueNotifyHeaderOrderMaterialList({
site,
workOrderNo: shipmentId,
})
.then(({ data }) => {
if (!data || data.code !== 0) {
this.$message.error((data && data.msg) || '获取发货单物料失败')
return
}
const shipmentLineList = data.data || []
try {
sessionStorage.setItem(
`customerIssueShipmentLine_${shipmentId}`,
JSON.stringify(shipmentLineList)
)
} catch (e) {
this.$message.error('缓存发货单物料失败,请重试')
return
}
this.$router.push({
name: 'customerIssuePDAIssueList',
query: {
state: material.STATE,
shipmentId,
orderType: material.SHIPMENT_TYPE,
site,
},
})
})
.catch((error) => {
this.$message.error(
'获取发货单物料失败: ' + ((error && error.message) || error)
)
})
.finally(() => {
this.loading = false
})
},
resetRequest() {

322
src/views/modules/customerIssue/customerIssuePDAIssueList.vue

@ -466,10 +466,13 @@ export default {
},
pendingIssueParams: null,
shipmentLine: [],
// shipmentline
// shipmentline
showShipmentLineDialogVisible: false,
shipmentLineLoading: false,
shipmentLineList: [],
shipmentLineRaw: [], // IFS ShipmentLine /
shipmentPartNoSet: {}, // partNo -> true
shipmentLineInitialized: false, // ShipmentLine
}
},
computed: {
@ -551,6 +554,14 @@ export default {
//
validateAndAddLabel(labelCode) {
if (!this.shipmentLineInitialized) {
this.$message.warning('发货单物料清单未加载,请稍候再扫')
return
}
if (!Object.keys(this.shipmentPartNoSet).length) {
this.$message.warning('该发货单暂无物料行,无法添加')
return
}
const params = {
scannedLabel: labelCode,
workOrderNo: this.orderNo,
@ -564,16 +575,26 @@ export default {
return
}
//
// shipment
scanCustomerIssueMaterialLabel(params)
.then(({ data }) => {
if (data.code === 0 && data) {
//
// ShipmentHuDetail
const labelInfo = data.labelInfo
const labelInfo = data.labelInfo || {}
const partNo = String(
this.pickFieldValue(labelInfo, ['partNo', 'PART_NO', 'part_no'], '') ||
''
).trim()
if (!partNo || !this.shipmentPartNoSet[partNo]) {
this.rollbackInvalidScan(labelInfo, labelCode)
this.$message.warning(
`物料 ${partNo || '-'} 不属于当前发货单,无法添加`
)
return
}
this.labelList.push({
id: Date.now(),
labelCode: labelCode,
partNo: labelInfo.partNo || '',
partNo: partNo,
qtyToIssue: Number(labelInfo.qtyToIssue) || 0,
batchNo: labelInfo.batchNo || '',
locationId: labelInfo.locationId || '',
@ -581,7 +602,7 @@ export default {
wdrNo: labelInfo.wdr || '',
engChgLevel: labelInfo.engChgLevel || '1',
detailId: labelInfo.detailId || '',
unitId: labelInfo.unitId || '',
unitId: labelInfo.unitId || labelCode,
site: labelInfo.site || this.site,
height: labelInfo.height || null,
})
@ -596,6 +617,59 @@ export default {
})
},
// shipment
rollbackInvalidScan(labelInfo, labelCode) {
const unitId = (labelInfo && (labelInfo.unitId || labelInfo.unit_id)) || labelCode
const detailId = labelInfo && labelInfo.detailId
if (!unitId) {
return
}
removeShipmentHuDetail({
site: this.site,
unitId,
detailId,
}).catch(() => {
//
})
},
isPartBelongToShipment(partNo) {
const normalized = String(partNo || '').trim()
if (!normalized) {
return false
}
return !!this.shipmentPartNoSet[normalized]
},
// shipmentline
filterLabelsByShipmentLine(details = []) {
if (!this.shipmentLineInitialized || !Object.keys(this.shipmentPartNoSet).length) {
return details || []
}
const valid = []
const invalid = []
;(details || []).forEach((item) => {
const partNo = String(
this.pickFieldValue(item, ['partNo', 'PART_NO', 'part_no'], '') || ''
).trim()
if (this.isPartBelongToShipment(partNo)) {
valid.push(item)
} else {
invalid.push(item)
}
})
//
invalid.forEach((item) => {
this.rollbackInvalidScan(item, item.unitId)
})
if (invalid.length > 0) {
this.$message.warning(
`已自动移除 ${invalid.length} 条不属于当前发货单的历史扫描记录`
)
}
return valid
},
//
removeLabelByCode(labelCode) {
const exists = this.labelList.find((item) => item.unitId === labelCode)
@ -775,79 +849,77 @@ export default {
site: this.site,
workOrderNo: this.orderNo,
}
await getCustomerIssueNotifyHeaderOrderMaterialList(params).then(
({ data }) => {
if (!data || data.code !== 0) {
throw new Error((data && data.msg) || '获取申请单物料失败')
if (!materials.length) {
throw new Error('发货单物料清单为空,无法对比')
}
this.$set(this, 'shipmentLine', materials)
const labelMap = this.aggregateMaterials(
this.labelList,
['partNo'],
['qtyToIssue', 'quantity', 'issueQty']
)
// INVENTORY_QTY - QTY_ASSIGNED
const orderMap = {}
materials.forEach((item) => {
const partNo = this.pickFieldValue(item, ['INVENTORY_PART_NO'])
const normalizedKey =
typeof partNo === 'string' ? partNo.trim() : partNo
if (!normalizedKey) {
return
}
const inventoryQty =
Number(this.pickFieldValue(item, ['INVENTORY_QTY'], 0)) || 0
const qtyAssigned =
Number(this.pickFieldValue(item, ['QTY_ASSIGNED'], 0)) || 0
const requiredQty = this.safeAdd(inventoryQty, -qtyAssigned)
if (!orderMap[normalizedKey]) {
orderMap[normalizedKey] = {
partNo: normalizedKey,
qty: 0,
}
const materials = data.data || []
this.$set(this,'shipmentLine',data.data)
const labelMap = this.aggregateMaterials(
this.labelList,
['partNo'],
['qtyToIssue', 'quantity', 'issueQty']
)
// INVENTORY_QTY - QTY_ASSIGNED
const orderMap = {}
materials.forEach((item) => {
const partNo = this.pickFieldValue(item, ['INVENTORY_PART_NO'])
const normalizedKey =
typeof partNo === 'string' ? partNo.trim() : partNo
if (!normalizedKey) {
return
}
const inventoryQty = Number(this.pickFieldValue(item, ['INVENTORY_QTY'], 0)) || 0
const qtyAssigned = Number(this.pickFieldValue(item, ['QTY_ASSIGNED'], 0)) || 0
const requiredQty = this.safeAdd(inventoryQty, -qtyAssigned)
if (!orderMap[normalizedKey]) {
orderMap[normalizedKey] = {
partNo: normalizedKey,
qty: 0,
}
}
orderMap[normalizedKey].qty = this.safeAdd(orderMap[normalizedKey].qty, requiredQty)
})
}
orderMap[normalizedKey].qty = this.safeAdd(
orderMap[normalizedKey].qty,
requiredQty
)
})
const existing = []
const missing = []
Object.keys(orderMap).forEach((partNo) => {
console.log('Comparing partNo:', orderMap[partNo])
const requiredQty = orderMap[partNo].qty
if (labelMap[partNo]) {
const scannedQty = labelMap[partNo].qty
existing.push({
partNo,
requiredQty,
scannedQty,
difference: scannedQty - requiredQty,
})
} else {
missing.push({
partNo,
requiredQty,
})
}
const existing = []
const missing = []
Object.keys(orderMap).forEach((partNo) => {
const requiredQty = orderMap[partNo].qty
if (labelMap[partNo]) {
const scannedQty = labelMap[partNo].qty
existing.push({
partNo,
requiredQty,
scannedQty,
difference: scannedQty - requiredQty,
})
const extra = []
Object.keys(labelMap).forEach((partNo) => {
if (!orderMap[partNo]) {
extra.push({
partNo,
scannedQty: labelMap[partNo].qty,
})
}
} else {
missing.push({
partNo,
requiredQty,
})
}
})
this.comparisonData = {
existing,
missing,
extra,
}
const extra = []
Object.keys(labelMap).forEach((partNo) => {
if (!orderMap[partNo]) {
extra.push({
partNo,
scannedQty: labelMap[partNo].qty,
})
}
)
})
this.comparisonData = {
existing,
missing,
extra,
}
},
closeSummaryDialog() {
if (this.loading) {
@ -864,11 +936,70 @@ export default {
closeShipmentLineDialog() {
this.showShipmentLineDialogVisible = false
},
async loadShipmentLineList() {
applyShipmentLineMaterials(materials = []) {
const list = Array.isArray(materials) ? materials : []
this.shipmentLineRaw = list
this.$set(this, 'shipmentLine', list)
const partNoSet = {}
this.shipmentLineList = list.map((item) => {
const inventoryQty =
Number(this.pickFieldValue(item, ['INVENTORY_QTY'], 0)) || 0
const qtyAssigned =
Number(this.pickFieldValue(item, ['QTY_ASSIGNED'], 0)) || 0
const partNo = this.pickFieldValue(item, ['INVENTORY_PART_NO'], '')
const normalizedPartNo =
typeof partNo === 'string' ? partNo.trim() : partNo
if (normalizedPartNo) {
partNoSet[normalizedPartNo] = true
}
return {
lineNo: this.pickFieldValue(item, ['SHIPMENT_LINE_NO'], ''),
partNo: normalizedPartNo || '',
inventoryQty,
qtyAssigned,
remainQty: this.safeAdd(inventoryQty, -qtyAssigned),
uom: this.pickFieldValue(item, ['INVENTORY_UOM'], ''),
}
})
this.shipmentPartNoSet = partNoSet
this.shipmentLineInitialized = true
return list
},
// sessionStorage 退
async initShipmentLineCache() {
const cacheKey = `customerIssueShipmentLine_${this.orderNo}`
let cached = null
try {
const raw = sessionStorage.getItem(cacheKey)
if (raw) {
cached = JSON.parse(raw)
}
} catch (e) {
cached = null
} finally {
try {
sessionStorage.removeItem(cacheKey)
} catch (e) {
// ignore
}
}
if (Array.isArray(cached)) {
this.applyShipmentLineMaterials(cached)
if (!cached.length) {
this.$message.warning('该发货单暂无物料行,扫描将被禁止')
}
return
}
await this.ensureShipmentLineLoaded()
},
async ensureShipmentLineLoaded() {
if (this.shipmentLineRaw && this.shipmentLineRaw.length > 0) {
return this.shipmentLineRaw
}
if (!this.site || !this.orderNo) {
this.$message.error('缺少必要参数,无法获取物料清单')
this.shipmentLineList = []
return
this.applyShipmentLineMaterials([])
return []
}
this.shipmentLineLoading = true
try {
@ -878,31 +1009,26 @@ export default {
})
if (!data || data.code !== 0) {
this.$message.error((data && data.msg) || '获取物料清单失败')
this.shipmentLineList = []
return
this.applyShipmentLineMaterials([])
return []
}
const materials = data.data || []
this.shipmentLineList = materials.map((item) => {
const inventoryQty =
Number(this.pickFieldValue(item, ['INVENTORY_QTY'], 0)) || 0
const qtyAssigned =
Number(this.pickFieldValue(item, ['QTY_ASSIGNED'], 0)) || 0
return {
lineNo: this.pickFieldValue(item, ['SHIPMENT_LINE_NO'], ''),
partNo: this.pickFieldValue(item, ['INVENTORY_PART_NO'], ''),
inventoryQty,
qtyAssigned,
remainQty: this.safeAdd(inventoryQty, -qtyAssigned),
uom: this.pickFieldValue(item, ['INVENTORY_UOM'], ''),
}
})
return this.applyShipmentLineMaterials(data.data || [])
} catch (error) {
this.$message.error('获取物料清单失败')
this.shipmentLineList = []
this.applyShipmentLineMaterials([])
return []
} finally {
this.shipmentLineLoading = false
}
},
async loadShipmentLineList() {
// IFS
if (this.shipmentLineRaw && this.shipmentLineRaw.length > 0) {
this.applyShipmentLineMaterials(this.shipmentLineRaw)
return
}
await this.ensureShipmentLineLoaded()
},
proceedIssueConfirm() {
if (!this.pendingIssueParams) {
this.pendingIssueParams = this.buildIssueParams()
@ -1029,7 +1155,8 @@ export default {
getShipmentHuDetail(params)
.then(({ data }) => {
if (data.code === 0 && data) {
this.labelList = data.details || []
// shipmentline
this.labelList = this.filterLabelsByShipmentLine(data.details || [])
} else {
this.$message.error(data.msg || '获取订单详情失败')
}
@ -1181,7 +1308,7 @@ export default {
},
},
mounted() {
async mounted() {
//
console.log('路由参数:', this.$route.query)
@ -1203,7 +1330,8 @@ export default {
}
})
//
// ShipmentLine
await this.initShipmentLineCache()
this.loadOrderDetails()
},
}

7
src/views/modules/production-return/productionReturnPDAIssueList.vue

@ -644,6 +644,8 @@ export default {
id: Date.now(),
labelCode,
partNo,
partDesc: (this.newLabelForm.partDesc || (this.orderInfo && this.orderInfo.description) || '').trim(),
componentPartNo: this.partNo || partNo,
quantity: Number(this.newLabelForm.quantity),
batchNo: this.batchNo || '',
locationId: this.newLabelForm.locationId || '',
@ -733,6 +735,7 @@ export default {
orderType: this.orderType,
batchNo: this.batchNo,
componentPartNo: this.partNo,
componentPartDesc: (this.orderInfo && this.orderInfo.description) || '',
transactionId: this.transactionId,
accountingId: this.accountingId,
itemNo: this.itemNo,
@ -746,7 +749,9 @@ export default {
labelCode: label.labelCode,
issueQty: label.quantity,
batchNo: label.batchNo,
partNo: label.partNo,
partNo: label.partNo || this.partNo,
partDesc: label.partDesc || (this.orderInfo && this.orderInfo.description) || '',
componentPartNo: label.componentPartNo || label.partNo || this.partNo,
locationId: label.locationId,
warehouseId: label.warehouseId,
wdrNo: label.wdrNo || '*',

29
src/views/modules/production-return/productionReturnPickingDetail.vue

@ -611,6 +611,8 @@ export default {
id: Date.now(),
labelCode: labelCode,
partNo: this.newLabelForm.partNo.trim(),
partDesc: (this.newLabelForm.partDesc || this.componentPartDesc || '').trim(),
componentPartNo: this.componentPartNo || this.newLabelForm.partNo.trim(),
quantity: Number(this.newLabelForm.quantity),
batchNo: this.batchNo || '',
locationId: this.newLabelForm.locationId || '',
@ -699,6 +701,7 @@ export default {
orderType: this.orderType,
batchNo: this.batchNo,
componentPartNo: this.componentPartNo,
componentPartDesc: this.componentPartDesc,
transactionId: this.transactionId,
accountingId: this.accountingId,
itemNo: this.itemNo,
@ -714,7 +717,9 @@ export default {
labelCode: label.labelCode,
issueQty: label.quantity,
batchNo: label.batchNo,
partNo: label.partNo,
partNo: label.partNo || this.componentPartNo,
partDesc: label.partDesc || this.componentPartDesc || '',
componentPartNo: label.componentPartNo || label.partNo || this.componentPartNo,
locationId: label.locationId,
warehouseId: label.warehouseId,
wdrNo: label.wdrNo || '*',
@ -1158,10 +1163,10 @@ export default {
.title-label {
font-size: 11px;
color: #999;
color: #333;
display: block;
margin-bottom: 6px;
font-weight: normal;
font-weight: 500;
}
.title-value {
@ -1177,13 +1182,13 @@ export default {
justify-content: space-between;
align-items: flex-start;
gap: 4px;
width: 100%;
}
.detail-item {
flex: 1;
text-align: center;
min-width: 60px;
max-width: 60px;
min-width: 0;
}
.detail-label {
@ -1192,7 +1197,7 @@ export default {
margin-bottom: 6px;
font-weight: normal;
line-height: 1.2;
margin-left: -12px;
margin-left: 0;
}
.detail-value {
@ -1241,7 +1246,7 @@ export default {
.work-order-card {
background: white;
border-radius: 8px;
padding: 16px;
padding: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
border: 2px solid transparent;
@ -2059,14 +2064,14 @@ export default {
}
.card-details {
flex-wrap: wrap;
gap: 6px;
flex-wrap: nowrap;
gap: 8px;
}
.detail-item {
flex: 0 0 48%;
margin-bottom: 6px;
min-width: 50px;
flex: 1;
margin-bottom: 0;
min-width: 0;
}
.list-header,

Loading…
Cancel
Save