From e2ed00c38c0e98afbcd2f08940dec0c1b7861aa0 Mon Sep 17 00:00:00 2001 From: chengma Date: Tue, 18 Aug 2026 16:40:47 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=87=AA=E7=BB=98?= =?UTF-8?q?=E9=A2=9C=E8=89=B2=E8=A1=8C=E5=AE=89=E5=85=A8=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E8=AF=AF=E5=88=A4=20(#270)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/util/select_color_size.py | 42 ++++++++++++++++++++++++++- client/test/test_select_color_size.py | 37 +++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/client/src/util/select_color_size.py b/client/src/util/select_color_size.py index 8ac02c8..23ce473 100644 --- a/client/src/util/select_color_size.py +++ b/client/src/util/select_color_size.py @@ -331,9 +331,49 @@ def _non_scrollable_target_region( heading: Bounds, screen: Bounds, ) -> Optional[Bounds]: - """用目标卡片和下一规格标题界定非滚动颜色区域。""" + """用目标卡片和下一规格标题界定非滚动颜色区域。 + + PDD 的部分自绘横向颜色行没有 ``scrollable`` 属性,颜色卡片会放在 + 一个整行可点击的父节点下。此时同一行的颜色选项可能刚好叫“款式”, + 不能把它当作规格标题;优先使用该父级行作为区域,避免标题坐标误导。 + """ parents = _parent_map(root) + matching_nodes = [ + (node, bounds) + for node in root.iter("node") + if _is_available(node) and _matches_target(node, target) + if (bounds := _parse_bounds(node.get("bounds", ""))) is not None + if _center_in(bounds, screen) + ] + if matching_nodes: + target_node, target_bounds = max( + matching_nodes, + key=lambda item: (item[1][2] - item[1][0]) + * (item[1][3] - item[1][1]), + ) + target_height = target_bounds[3] - target_bounds[1] + row_candidates: list[Bounds] = [] + current: Optional[ET.Element] = target_node + while current is not None: + bounds = _parse_bounds(current.get("bounds", "")) + if ( + bounds is not None + and current.get("clickable") == "true" + and _is_available(current) + and _contains_bounds(bounds, target_bounds) + and bounds[2] - bounds[0] >= (screen[2] - screen[0]) * 0.60 + and bounds[3] - bounds[1] + <= max(180, target_height * 3) + ): + row_candidates.append(bounds) + current = parents.get(current) + if row_candidates: + return max( + row_candidates, + key=lambda item: (item[2] - item[0]) * (item[3] - item[1]), + ) + target_bounds = [ bounds for node in root.iter("node") diff --git a/client/test/test_select_color_size.py b/client/test/test_select_color_size.py index bbbad7f..ff14f3b 100644 --- a/client/test/test_select_color_size.py +++ b/client/test/test_select_color_size.py @@ -263,6 +263,43 @@ class StaticColorSelectionTest(unittest.TestCase): self.assertTrue(selected) self.assertEqual(device.clicks, [(194, 1389)]) + def test_non_scrollable_row_ignores_same_row_style_option_as_heading(self): + simplified = "纯欲莹白【透.视蕾丝衣.免脱款】" + traditional = "純欲瑩白【透.視蕾絲衣.免脫款】" + panel_xml = f''' + + + + + + + + + + + + + ''' + device = StaticColorDevice( + panel_xml, + selected_text=simplified, + ) + + selected = select_color( + device, + panel_xml, + traditional, + action_delay=0.001, + ) + + self.assertTrue(selected) + self.assertEqual(device.swipes, []) + self.assertEqual(device.clicks, [(126, 1107)]) + self.assertEqual( + color_selection_failure_reason(panel_xml, traditional), + "selection_unconfirmed", + ) + def test_traditional_size_matches_unique_simplified_option(self): simplified = "均码【40.0-60.0公斤】" traditional = "均碼【40.0-60.0公斤】"