|
|
|
@ -161,7 +161,13 @@ |
|
|
|
<div class="col-picked-qty">{{ item.pickedQty || 0 }}</div> |
|
|
|
<div class="col-picked-qty">{{ item.scansQty || 0 }}</div> |
|
|
|
<div class="col-action"> |
|
|
|
<span class="row-action-link" @click.stop="openAlternativeDialog(item)">替代</span> |
|
|
|
<span |
|
|
|
v-if="shouldShowAlternativeAction(item)" |
|
|
|
class="row-action-link" |
|
|
|
@click.stop="openAlternativeDialog(item)" |
|
|
|
> |
|
|
|
替代 |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
@ -296,6 +302,8 @@ export default { |
|
|
|
alternativeMaterialList: [], |
|
|
|
alternativeListLoading: false, |
|
|
|
substituteSourcePartNo: '', |
|
|
|
alternativeAvailabilityMap: {}, |
|
|
|
alternativeAvailabilityReqId: 0, |
|
|
|
isRemoveMode: false, // 默认为添加模式 |
|
|
|
relatedNo: '', |
|
|
|
showStockDialog: false, |
|
|
|
@ -459,15 +467,18 @@ export default { |
|
|
|
this.materialListLoading = false; |
|
|
|
if (data && data.code === 0) { |
|
|
|
this.materialList = data.data || []; |
|
|
|
this.prefetchAlternativeAvailability(this.materialList); |
|
|
|
} else { |
|
|
|
this.$message.error(data.msg || '获取物料清单失败'); |
|
|
|
this.materialList = []; |
|
|
|
this.alternativeAvailabilityMap = {}; |
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
this.materialListLoading = false; |
|
|
|
console.error('获取物料清单失败:', error); |
|
|
|
this.$message.error('获取物料清单失败'); |
|
|
|
this.materialList = []; |
|
|
|
this.alternativeAvailabilityMap = {}; |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
@ -477,8 +488,153 @@ export default { |
|
|
|
this.hidePartNameTip(); |
|
|
|
}, |
|
|
|
|
|
|
|
getMaterialPartNo(item) { |
|
|
|
return item.materialCode || item.partNo || ''; |
|
|
|
}, |
|
|
|
|
|
|
|
normalizeAlternativeIndicator(rawValue) { |
|
|
|
if (rawValue === null || rawValue === undefined) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
if (Array.isArray(rawValue)) { |
|
|
|
return rawValue.length > 0; |
|
|
|
} |
|
|
|
if (typeof rawValue === 'boolean') { |
|
|
|
return rawValue; |
|
|
|
} |
|
|
|
if (typeof rawValue === 'number') { |
|
|
|
return rawValue > 0; |
|
|
|
} |
|
|
|
if (typeof rawValue === 'string') { |
|
|
|
const normalized = rawValue.trim().toLowerCase(); |
|
|
|
if (!normalized) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
if (/^-?\d+(\.\d+)?$/.test(normalized)) { |
|
|
|
return Number(normalized) > 0; |
|
|
|
} |
|
|
|
if (['y', 'yes', 'true', '1'].includes(normalized)) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
if (['n', 'no', 'false', '0'].includes(normalized)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (['null', 'none', 'n/a', 'na', '-'].includes(normalized)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (/[|,;]/.test(normalized)) { |
|
|
|
return normalized.split(/[|,;]/).some(Boolean); |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
if (typeof rawValue === 'object') { |
|
|
|
return Object.keys(rawValue).length > 0; |
|
|
|
} |
|
|
|
return null; |
|
|
|
}, |
|
|
|
|
|
|
|
getAlternativeIndicatorFromRow(item) { |
|
|
|
const candidateKeys = [ |
|
|
|
'hasAlternative', |
|
|
|
'hasSubstitute', |
|
|
|
'alternativeFlag', |
|
|
|
'substituteFlag', |
|
|
|
'allowAlternative', |
|
|
|
'alternativeCount', |
|
|
|
'substituteCount', |
|
|
|
'alternativeQty', |
|
|
|
'substituteQty', |
|
|
|
'alternativePartNo', |
|
|
|
'alternativePartno', |
|
|
|
'substitutePartNo', |
|
|
|
'substitutePartno', |
|
|
|
'alternativePartList', |
|
|
|
'substitutePartList', |
|
|
|
'alternativeParts', |
|
|
|
'substituteParts' |
|
|
|
]; |
|
|
|
|
|
|
|
for (const key of candidateKeys) { |
|
|
|
if (!Object.prototype.hasOwnProperty.call(item, key)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
const normalized = this.normalizeAlternativeIndicator(item[key]); |
|
|
|
if (normalized !== null) { |
|
|
|
return normalized; |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
}, |
|
|
|
|
|
|
|
shouldShowAlternativeAction(item) { |
|
|
|
const directIndicator = this.getAlternativeIndicatorFromRow(item); |
|
|
|
if (directIndicator !== null) { |
|
|
|
return directIndicator; |
|
|
|
} |
|
|
|
|
|
|
|
const partNo = this.getMaterialPartNo(item); |
|
|
|
if (!partNo) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// 未预检完成前默认显示,避免因临时查询失败导致误隐藏 |
|
|
|
return this.alternativeAvailabilityMap[partNo] !== false; |
|
|
|
}, |
|
|
|
|
|
|
|
prefetchAlternativeAvailability(materialList) { |
|
|
|
this.alternativeAvailabilityReqId += 1; |
|
|
|
const currentReqId = this.alternativeAvailabilityReqId; |
|
|
|
this.alternativeAvailabilityMap = {}; |
|
|
|
|
|
|
|
const uniquePartNosToQuery = new Set(); |
|
|
|
(materialList || []).forEach(item => { |
|
|
|
const partNo = this.getMaterialPartNo(item); |
|
|
|
if (!partNo) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const directIndicator = this.getAlternativeIndicatorFromRow(item); |
|
|
|
if (directIndicator !== null) { |
|
|
|
this.$set(this.alternativeAvailabilityMap, partNo, directIndicator); |
|
|
|
return; |
|
|
|
} |
|
|
|
uniquePartNosToQuery.add(partNo); |
|
|
|
}); |
|
|
|
const uniquePartNos = Array.from(uniquePartNosToQuery); |
|
|
|
|
|
|
|
if (uniquePartNos.length === 0) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const baseParams = { |
|
|
|
site: this.outboundInfo.site, |
|
|
|
buNo: this.buNo, |
|
|
|
outboundNo: this.outboundNo, |
|
|
|
warehouseId: getCurrentWarehouse(), |
|
|
|
relatedNo: this.relatedNo |
|
|
|
}; |
|
|
|
|
|
|
|
uniquePartNos.forEach(partNo => { |
|
|
|
getBomAlternativePartDetails({ |
|
|
|
...baseParams, |
|
|
|
partNo |
|
|
|
}).then(({ data }) => { |
|
|
|
if (currentReqId !== this.alternativeAvailabilityReqId) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const hasAlternative = !!(data && data.code === 0 && Array.isArray(data.data) && data.data.length > 0); |
|
|
|
this.$set(this.alternativeAvailabilityMap, partNo, hasAlternative); |
|
|
|
}).catch(() => { |
|
|
|
if (currentReqId !== this.alternativeAvailabilityReqId) { |
|
|
|
return; |
|
|
|
} |
|
|
|
// 查询失败时不隐藏,避免误伤可替代行 |
|
|
|
this.$set(this.alternativeAvailabilityMap, partNo, true); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
openAlternativeDialog(rowItem) { |
|
|
|
this.substituteSourcePartNo = rowItem.materialCode || rowItem.partNo; |
|
|
|
this.substituteSourcePartNo = this.getMaterialPartNo(rowItem); |
|
|
|
if (!this.substituteSourcePartNo) { |
|
|
|
this.$message.error('无法识别物料编码'); |
|
|
|
return; |
|
|
|
|