|
|
|
|
@ -140,6 +140,7 @@ |
|
|
|
|
style="width: 100%" |
|
|
|
|
border |
|
|
|
|
ref="groupTable" |
|
|
|
|
@expand-change="handleExpandChange" |
|
|
|
|
> |
|
|
|
|
<!-- 展开行详情 --> |
|
|
|
|
<el-table-column type="expand"> |
|
|
|
|
@ -153,12 +154,26 @@ |
|
|
|
|
(val) => handleSelectionChange(val, props.row) |
|
|
|
|
" |
|
|
|
|
border |
|
|
|
|
:row-key="getRowKeyId" |
|
|
|
|
ref="nestedTable" |
|
|
|
|
> |
|
|
|
|
<el-table-column |
|
|
|
|
<!-- <el-table-column |
|
|
|
|
type="selection" |
|
|
|
|
width="55" |
|
|
|
|
:selectable="isRowSelectable" |
|
|
|
|
/> |
|
|
|
|
/> --> |
|
|
|
|
<el-table-column label="选择" width="55"> |
|
|
|
|
<template slot-scope="scope"> |
|
|
|
|
<el-checkbox |
|
|
|
|
v-model="scope.row._selected" |
|
|
|
|
:disabled="!isRowSelectable(scope.row)" |
|
|
|
|
@change=" |
|
|
|
|
(checked) => |
|
|
|
|
handleRowSelect(checked, scope.row, props.row) |
|
|
|
|
" |
|
|
|
|
/> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column type="index" label="#" width="55" /> |
|
|
|
|
<el-table-column label="物料名称" prop="materialName" /> |
|
|
|
|
<el-table-column label="物料编码" prop="materialCode" /> |
|
|
|
|
@ -513,6 +528,56 @@ export default { |
|
|
|
|
this.getOutGroupName(); |
|
|
|
|
}, |
|
|
|
|
methods: { |
|
|
|
|
handleExpandChange(row, expandedRows) { |
|
|
|
|
// 只处理展开的情况 |
|
|
|
|
if (expandedRows.includes(row)) { |
|
|
|
|
this.$nextTick(() => { |
|
|
|
|
// 获取该分组对应的嵌套表格实例(需要给嵌套表格加 ref) |
|
|
|
|
// 但动态 ref 难以获取,改用数据驱动方式:我们不在 UI 上依赖 selection,而是靠 selectedGroupMap 渲染 checkbox 状态 |
|
|
|
|
// 所以更推荐:不依赖 el-table 的 selection UI,而是自己控制 checked 状态 |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
handleRowSelect(checked, childRow, parentRow) { |
|
|
|
|
const key = |
|
|
|
|
parentRow.materialId || parentRow.materialCode || parentRow.id; |
|
|
|
|
let currentSelection = this.selectedGroupMap[key] || []; |
|
|
|
|
|
|
|
|
|
if (checked) { |
|
|
|
|
// 添加(去重) |
|
|
|
|
if ( |
|
|
|
|
!currentSelection.some( |
|
|
|
|
(item) => item.materialId === childRow.materialId |
|
|
|
|
) |
|
|
|
|
) { |
|
|
|
|
currentSelection = [...currentSelection, { ...childRow }]; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// 移除 |
|
|
|
|
currentSelection = currentSelection.filter( |
|
|
|
|
(item) => item.materialId !== childRow.materialId |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.$set(this.selectedGroupMap, key, currentSelection); |
|
|
|
|
|
|
|
|
|
// 重建明细列表 |
|
|
|
|
let allDetails = []; |
|
|
|
|
Object.values(this.selectedGroupMap).forEach((selectedList) => { |
|
|
|
|
allDetails = allDetails.concat( |
|
|
|
|
selectedList.map((item) => ({ |
|
|
|
|
...item, |
|
|
|
|
num: item.num || (item.type === "NY" ? 1 : 0), |
|
|
|
|
})) |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
this.sizeForm.ldTwoOutStorageDetailList = allDetails; |
|
|
|
|
this.getStatistics(); |
|
|
|
|
}, |
|
|
|
|
// 用于 el-table 的 row-key,确保每行有唯一 key |
|
|
|
|
getRowKeyId(row) { |
|
|
|
|
return row.materialId || row.id || row.materialCode; |
|
|
|
|
}, |
|
|
|
|
isRowSelectable(row) { |
|
|
|
|
// 确保 materialName 是非空字符串,materialId 是非空值(字符串或数字) |
|
|
|
|
return ( |
|
|
|
|
@ -560,16 +625,25 @@ export default { |
|
|
|
|
getGroupMaterial(this.sizeForm.ldTwoOutStorage).then((res) => { |
|
|
|
|
this.groupTableData = res.data.result; |
|
|
|
|
this.groupTableData.forEach((group) => { |
|
|
|
|
// 初始化每个分组的选中项为当前已选的明细项 |
|
|
|
|
if (group.twoInventoryVOList.length > 0) { |
|
|
|
|
group.twoInventoryVOList.forEach((element) => { |
|
|
|
|
element.applyNum = group.applyNum; |
|
|
|
|
element.goodsCode = group.applyNum; |
|
|
|
|
if (element.type === "NY") { |
|
|
|
|
element.num = 1; |
|
|
|
|
if ( |
|
|
|
|
group.twoInventoryVOList && |
|
|
|
|
group.twoInventoryVOList.length > 0 |
|
|
|
|
) { |
|
|
|
|
group.twoInventoryVOList.forEach((item) => { |
|
|
|
|
item.applyNum = group.applyNum; |
|
|
|
|
item.goodsCode = group.applyNum; |
|
|
|
|
if (item.type === "NY") { |
|
|
|
|
item.num = 1; |
|
|
|
|
} else { |
|
|
|
|
element.num = group.applyNum; |
|
|
|
|
item.num = group.applyNum; |
|
|
|
|
} |
|
|
|
|
// 初始化选中状态 |
|
|
|
|
const key = group.materialId || group.materialCode || group.id; |
|
|
|
|
const previouslySelected = this.selectedGroupMap[key] || []; |
|
|
|
|
const isSelected = previouslySelected.some( |
|
|
|
|
(sel) => sel.materialId === item.materialId |
|
|
|
|
); |
|
|
|
|
this.$set(item, "_selected", isSelected); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
@ -779,56 +853,60 @@ export default { |
|
|
|
|
this.$refs.dynamicValidateForm.validate((valid) => { |
|
|
|
|
if (valid) { |
|
|
|
|
// ===== 非自由出库:校验分组物资勾选数量是否匹配申请数量 ===== |
|
|
|
|
if (this.sizeForm.ldTwoOutStorage.groupName !== "自由出库") { |
|
|
|
|
let hasError = false; |
|
|
|
|
|
|
|
|
|
for (const group of this.groupTableData) { |
|
|
|
|
const key = group.materialId || group.materialCode || group.id; |
|
|
|
|
if (!key) continue; |
|
|
|
|
|
|
|
|
|
// 获取该分组下用户勾选的子项 |
|
|
|
|
const selectedItems = this.selectedGroupMap[key] || []; |
|
|
|
|
if (this.sizeForm.ldTwoOutStorage.groupName !== "自由出库") { |
|
|
|
|
let hasError = false; |
|
|
|
|
|
|
|
|
|
for (const group of this.groupTableData) { |
|
|
|
|
const key = group.materialId || group.materialCode || group.id; |
|
|
|
|
if (!key) continue; |
|
|
|
|
|
|
|
|
|
// 获取该分组下用户勾选的子项 |
|
|
|
|
const selectedItems = this.selectedGroupMap[key] || []; |
|
|
|
|
|
|
|
|
|
// 如果没有勾选任何子项,跳过(或可视为错误,根据业务) |
|
|
|
|
if (selectedItems.length === 0) { |
|
|
|
|
this.$message.error( |
|
|
|
|
`分组【${ |
|
|
|
|
group.materialName || group.materialCode |
|
|
|
|
}】未选择任何物资` |
|
|
|
|
); |
|
|
|
|
hasError = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 计算勾选项的 num 总和 |
|
|
|
|
const totalSelectedNum = selectedItems.reduce((sum, item) => { |
|
|
|
|
return sum + (Number(item.num) || 0); |
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
|
|
const applyNum = Number(group.applyNum) || 0; |
|
|
|
|
|
|
|
|
|
if (totalSelectedNum !== applyNum) { |
|
|
|
|
this.$message.error( |
|
|
|
|
`分组【${ |
|
|
|
|
group.materialName || group.materialCode |
|
|
|
|
}】:已选物资出库数量总和(${totalSelectedNum})与申请数量(${applyNum})不一致` |
|
|
|
|
); |
|
|
|
|
hasError = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 如果没有勾选任何子项,跳过(或可视为错误,根据业务) |
|
|
|
|
if (selectedItems.length === 0) { |
|
|
|
|
this.$message.error(`分组【${group.materialName || group.materialCode}】未选择任何物资`); |
|
|
|
|
hasError = true; |
|
|
|
|
break; |
|
|
|
|
if (hasError) { |
|
|
|
|
return; // 阻止提交 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 计算勾选项的 num 总和 |
|
|
|
|
const totalSelectedNum = selectedItems.reduce((sum, item) => { |
|
|
|
|
return sum + (Number(item.num) || 0); |
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
|
|
const applyNum = Number(group.applyNum) || 0; |
|
|
|
|
|
|
|
|
|
if (totalSelectedNum !== applyNum) { |
|
|
|
|
this.$message.error( |
|
|
|
|
`分组【${group.materialName || group.materialCode}】:已选物资出库数量总和(${totalSelectedNum})与申请数量(${applyNum})不一致` |
|
|
|
|
); |
|
|
|
|
hasError = true; |
|
|
|
|
break; |
|
|
|
|
// ===== 自由出库:校验是否有明细 ===== |
|
|
|
|
if (this.sizeForm.ldTwoOutStorage.groupName === "自由出库") { |
|
|
|
|
if ( |
|
|
|
|
!this.sizeForm.ldTwoOutStorageDetailList || |
|
|
|
|
this.sizeForm.ldTwoOutStorageDetailList.length === 0 |
|
|
|
|
) { |
|
|
|
|
this.$message.error("请至少选择一项物资"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (hasError) { |
|
|
|
|
return; // 阻止提交 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ===== 自由出库:校验是否有明细 ===== |
|
|
|
|
if (this.sizeForm.ldTwoOutStorage.groupName === "自由出库") { |
|
|
|
|
if ( |
|
|
|
|
!this.sizeForm.ldTwoOutStorageDetailList || |
|
|
|
|
this.sizeForm.ldTwoOutStorageDetailList.length === 0 |
|
|
|
|
) { |
|
|
|
|
this.$message.error("请至少选择一项物资"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
submit(this.sizeForm).then((res) => { |
|
|
|
|
this.$message({ |
|
|
|
|
|