diff --git a/inventory-web/src/views/stock/stocktake/index.vue b/inventory-web/src/views/stock/stocktake/index.vue index 43d4034..7c5f12d 100644 --- a/inventory-web/src/views/stock/stocktake/index.vue +++ b/inventory-web/src/views/stock/stocktake/index.vue @@ -771,10 +771,13 @@ const recLoading = ref(false) // 获取推荐中 const treeLoading = ref(false) // 库位树加载中 const locTreeData = ref([]) // 库位树(已按当前公司前缀过滤) const locTreeRef = ref() // el-tree 实例,用于 setCheckedKeys / getCheckedNodes -// ★ 当前勾选的库位路径集合 —— 它与提交给后端的 scope_config.locations 完全一致。 -// 刻意**不过滤非末级节点**:后端按 warehouse_location 精确匹配,而库存的库位 -// 可能落在层级 1/2(实测 level1 有 9 个、level2 有 57 个),只提交叶子会把 -// 这些库存静默排除在抽盘范围之外。 +// ★ 当前勾选的**末级**库位路径集合 —— 与提交给后端的 scope_config.locations 完全一致。 +// 取 leafOnly=true:勾选父级货架时只计入其下属末级库位,不含父节点自身, +// 符合现场「货架是容器、库位才是盘点对象」的心智模型。 +// +// 数据依据(实测):存放在**非末级**库位上的库存极少 —— IRIS 1126 行里仅 1 行 +// (0.1%)、LICA 690 行里 0 行。注意别把「层级」与「非末级」混为一谈:这棵库位树 +// 深度不均匀,很多 level 1/2 的节点本身就是叶子。故 leafOnly 的排除面可忽略。 const selectedLocationPaths = ref([]) const checkedLocCount = computed(() => selectedLocationPaths.value.length) @@ -810,9 +813,10 @@ const loadLocationTree = async () => { } } -// 树的勾选状态 → 响应式路径集合。唯一数据源,左右两侧都读它 +// 树的勾选状态 → 响应式路径集合。唯一数据源,左右两侧都读它。 +// ★ getCheckedNodes(true) = leafOnly,只取末级库位,不含被级联勾中的父节点 const syncSelectedPaths = () => { - const nodes = locTreeRef.value?.getCheckedNodes() || [] + const nodes = locTreeRef.value?.getCheckedNodes(true) || [] selectedLocationPaths.value = nodes.map((n: any) => n.full_path).filter(Boolean) } @@ -867,9 +871,9 @@ const fetchRecommendLocations = async () => { } } -// 收集树上勾选的库位 full_path,作为抽盘范围提交 +// 收集树上勾选的**末级**库位 full_path,作为抽盘范围提交 const buildScopeConfig = () => { - const nodes = locTreeRef.value?.getCheckedNodes() || [] + const nodes = locTreeRef.value?.getCheckedNodes(true) || [] return { locations: nodes.map((n: any) => n.full_path).filter(Boolean), recommend_days: recommendDays.value, @@ -1890,26 +1894,35 @@ const goToVarianceReview = () => { margin-bottom: 6px; } -/* 左右双栏:左 60% 库位树 | 右 40% 已选明细 */ +/* 左右双栏:**固定高度**,两栏各自独立滚动 —— 树展开或标签变多都不会撑开卡片 */ .scope-columns { display: flex; gap: 10px; - align-items: stretch; + height: 380px; +} +.scope-col-left { + flex: 0 0 60%; + max-width: 60%; + min-width: 0; + display: flex; + flex-direction: column; + overflow: hidden; } -.scope-col-left { flex: 0 0 60%; max-width: 60%; min-width: 0; } .scope-col-right { flex: 1 1 40%; min-width: 0; display: flex; flex-direction: column; + overflow: hidden; background: #fff; border: 1px solid #ebeef5; border-radius: 4px; padding: 6px 8px; } -/* 平板大屏:定高 + 滚动,避免树把表单撑得过长 */ +/* min-height:0 是关键:flex 子项默认不收缩,不写它 overflow 不会生效 */ .scope-tree { - max-height: 300px; + flex: 1 1 auto; + min-height: 0; overflow-y: auto; background: #fff; border: 1px solid #ebeef5; @@ -1929,7 +1942,7 @@ const goToVarianceReview = () => { margin-bottom: 6px; } .scope-selected-header strong { color: #409eff; font-size: 14px; } -.scope-selected-scroll { flex: 1 1 auto; height: 260px; } +.scope-selected-scroll { flex: 1 1 auto; min-height: 0; } .scope-selected-empty { font-size: 12px; color: #c0c4cc;