From 0b82609c55e1ec355dd202ea6f2da63edd110363 Mon Sep 17 00:00:00 2001 From: yueli Date: Fri, 11 Sep 2026 14:33:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(stocktake):=20=E6=8A=BD=E7=9B=98=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8C=BA=E5=AE=9A=E9=AB=98=E4=B8=8D=E8=B7=B3=E5=8A=A8?= =?UTF-8?q?=EF=BC=8C=E5=8B=BE=E9=80=89=E5=8F=AA=E8=AE=A1=E6=9C=AB=E7=BA=A7?= =?UTF-8?q?=E5=BA=93=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【固定高度】.scope-columns 设 height: 380px + display: flex,左右两栏各自 flex:1 + overflow 独立滚动。关键点是给 flex 子项加 min-height: 0 —— 不写它 flex 子项默认不收缩,overflow 不会生效,高度照样被内容撑开。 原先树用 max-height: 300px、右栏用 height: 260px 各写各的,仍会随内容跳动。 【只计末级库位】syncSelectedPaths / buildScopeConfig 均改用 getCheckedNodes(true)(leafOnly)。勾选父级货架时右侧计数与提交给后端的 scope_config.locations 都只含末级库位,不再把父节点自身算进去 —— 符合现场「货架是容器、库位才是盘点对象」的心智模型。 上一轮我曾以「非末级库位上有库存,leafOnly 会漏」为由建议不做,该判断 是错的:我把「层级」当成了「非末级」。实测这棵库位树深度不均匀,很多 level 1/2 的节点本身就是叶子 —— 真正存放在非末级库位上的库存, IRIS 1126 行里仅 1 行(0.1%)、LICA 690 行里 0 行,排除面可忽略。 (活跃天数可编辑已在 709aeef 完成:recommendDays 默认 90、动态传参。) --- .../src/views/stock/stocktake/index.vue | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) 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;