feat: 执行并提交 PDD 采集任务 (#32)

This commit is contained in:
chengma
2026-08-07 17:38:29 +08:00
parent 34b4b54b63
commit 2d1fdbea3f
17 changed files with 2156 additions and 108 deletions
+423
View File
@@ -0,0 +1,423 @@
<?xml version='1.0' encoding='UTF-8'?>
<hierarchy rotation="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="0" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_launch_animation_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.android.systemui:id/status_bar_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_contents" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1075,120]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_start_side_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,19][491,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_start_side_content" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][491,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_start_side_except_heads_up" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][491,110]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/clock_for_fake" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][172,110]" drawing-order="2" hint="" display-id="0">
<node index="0" text="18:10" resource-id="com.android.systemui:id/clock" class="android.widget.TextView" package="com.android.systemui" content-desc="18:10" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][172,110]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/status_bar_start_side_content_for_fake" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/notification_icon_area" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/notificationIcons" class="android.view.ViewGroup" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="红果免费短剧通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][220,110]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="抖音通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[220,19][268,110]" drawing-order="2" hint="" display-id="0"/>
<node index="2" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="拼多多通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[268,19][316,110]" drawing-order="3" hint="" display-id="0"/>
<node index="3" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="京东通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[316,19][364,110]" drawing-order="4" hint="" display-id="0"/>
<node index="4" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="小红书通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[364,19][412,110]" drawing-order="5" hint="" display-id="0"/>
<node index="5" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="千问通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[412,19][460,110]" drawing-order="6" hint="" display-id="0"/>
<node index="6" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="哔哩哔哩通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="7" hint="" display-id="0"/>
<node index="7" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="软件商店通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="11" hint="" display-id="0"/>
<node index="8" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="音乐通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="10" hint="" display-id="0"/>
<node index="9" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="淘宝通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="9" hint="" display-id="0"/>
<node index="10" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="番茄畅听通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="8" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/cutout_space_view" class="android.view.View" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[491,19][579,120]" drawing-order="2" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.android.systemui:id/status_bar_end_side_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[579,19][1075,110]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_end_side_container_for_fake" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,19][1011,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_end_side_content" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,19][1011,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/system_icons" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,34][1011,94]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/statusIcons" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,34][929,94]" drawing-order="1" hint="" display-id="0">
<node index="1" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="振铃器静音。" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[674,34][722,94]" drawing-order="11" hint="" display-id="0"/>
<node index="2" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="蓝牙未连接" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[722,34][761,94]" drawing-order="12" hint="" display-id="0"/>
<node index="3" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="勿扰" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[761,34][815,94]" drawing-order="19" hint="" display-id="0"/>
<node index="4" text="" resource-id="com.android.systemui:id/wifi_combo" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,34][881,94]" drawing-order="20" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/wifi_group" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,34][881,94]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/wifi_combo" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,40][881,88]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/wifi_signal" class="android.widget.ImageView" package="com.android.systemui" content-desc="WLAN 信号满格。" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,40][881,88]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.android.systemui:id/wifi_inout" class="android.widget.ImageView" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[821,40][881,88]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="5" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[881,34][929,94]" drawing-order="21" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/battery" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="电池 状态栏项目 剩余电量百分之35" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[929,34][1011,94]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/battery_icon_view" class="android.widget.ImageView" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[932,40][1010,88]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/seeding_card_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="com.oplus.systemui.plugins:id/seeding_capsule_container_root" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="2" text="" resource-id="com.android.systemui:id/dynamic_icon_group" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1023,0][1032,120]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="返回" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2376]" drawing-order="0" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2328]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2328]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2328]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="androidx.recyclerview.widget.RecyclerView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2166]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1080]" drawing-order="10" hint="" display-id="0">
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="androidx.viewpager.widget.ViewPager" package="com.xunmeng.pinduoduo" content-desc="【店铺热销】冰丝吊带裙女夏季薄款内搭连衣裙宽松a字裙中长款打底裙衬裙纯色" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1080]" drawing-order="3" hint="" display-id="0">
<node index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1080]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="【店铺热销】冰丝吊带裙女夏季薄款内搭连衣裙宽松a字裙中长款打底裙衬裙纯色" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,1080]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="2" text="黑色中长款" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[424,981][655,1044]" drawing-order="10" hint="" display-id="0"/>
<node index="3" text="1/16" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[953,981][1053,1044]" drawing-order="7" hint="" display-id="0"/>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1063][1080,1080]" drawing-order="13" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1080][1080,1278]" drawing-order="12" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="券后4.7大促直降10.2元已拼297件" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1080][1080,1278]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1080][1080,1278]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1080][621,1278]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1080][621,1176]" drawing-order="1" hint="" display-id="0">
<node NAF="true" index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1080][310,1176]" drawing-order="14" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1122][87,1170]" drawing-order="5" hint="" display-id="0"/>
<node index="2" text="券后 " resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[99,1123][189,1172]" drawing-order="7" hint="" display-id="0"/>
<node index="3" text="¥" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[189,1123][217,1176]" drawing-order="8" hint="" display-id="0"/>
<node index="4" text="4.7" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[223,1080][310,1173]" drawing-order="9" hint="" display-id="0"/>
<node index="5" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[322,1116][621,1167]" drawing-order="16" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[325,1116][621,1167]" drawing-order="1" hint="" display-id="0">
<node index="0" text="大促直降10.2元" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[343,1118][609,1164]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ViewSwitcher" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1200][244,1257]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1200][244,1257]" drawing-order="1" hint="" display-id="0">
<node index="0" text="已拼297件" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1200][244,1257]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[792,1080][1080,1278]" drawing-order="6" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[807,1080][1080,1278]" drawing-order="7" hint="" display-id="0"/>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[807,1113][1080,1245]" drawing-order="8" hint="" display-id="0"/>
</node>
</node>
<node index="2" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1278][1080,1454]" drawing-order="9" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.RelativeLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1278][1080,1454]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1296][1080,1436]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="androidx.recyclerview.widget.RecyclerView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1296][1080,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1296][176,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1296][176,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="商品款式图" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1296][176,1436]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1296][176,1436]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[176,1296][296,1436]" drawing-order="2" hint="" display-id="0">
<node index="0" text="颜色&#10;款式" resource-id="com.xunmeng.pinduoduo:id/tv_title" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[197,1296][275,1436]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[290,1296][442,1436]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[290,1296][442,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="商品款式图" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[290,1296][442,1436]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[290,1296][442,1436]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[454,1296][594,1436]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[454,1296][594,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="商品款式图" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[454,1296][594,1436]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[454,1296][594,1436]" drawing-order="3" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[564,1296][594,1327]" drawing-order="2" hint="" display-id="0"/>
</node>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[612,1296][752,1436]" drawing-order="5" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[612,1296][752,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="商品款式图" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[612,1296][752,1436]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[612,1296][752,1436]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
<node index="5" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[770,1296][910,1436]" drawing-order="6" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[770,1296][910,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="商品款式图" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[770,1296][910,1436]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[770,1296][910,1436]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
<node index="6" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[928,1296][1068,1436]" drawing-order="7" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[928,1296][1068,1436]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="商品款式图" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[928,1296][1068,1436]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[928,1296][1068,1436]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1452][1080,1454]" drawing-order="5" hint="" display-id="0"/>
</node>
</node>
<node index="3" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1454][1080,1568]" drawing-order="8" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1454][1080,1568]" drawing-order="2" hint="" display-id="0">
<node NAF="true" index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1454][1080,1568]" drawing-order="3" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1454][1080,1568]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1454][36,1568]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1454][1080,1568]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1482][1017,1539]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1482][397,1539]" drawing-order="1" hint="" display-id="0">
<node index="0" text="5元无门槛平台券" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1482][385,1539]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1017,1492][1053,1529]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
<node index="4" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1568][1080,1646]" drawing-order="7" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1568][1080,1646]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1568][1044,1646]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1568][1044,1646]" drawing-order="3" hint="" display-id="0"/>
<node NAF="true" index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1568][1044,1646]" drawing-order="4" hint="" display-id="0"/>
<node index="3" text=" # 先用后付 # 支持0元下单,确认收货后再付款" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1568][932,1646]" drawing-order="5" hint="" display-id="0"/>
</node>
</node>
<node index="5" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1646][1080,1664]" drawing-order="6" hint="" display-id="0"/>
<node index="6" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1664][1080,1794]" drawing-order="5" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1664][1080,1794]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/tv_title" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="【店铺热销】冰丝吊带裙女夏季薄款内搭连衣裙宽松a字裙中长款打底裙衬裙纯色" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[36,1670][1044,1788]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="图片" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1671][165,1722]" drawing-order="6" hint="" display-id="0"/>
<node index="1" text="【店铺热销】冰丝吊带裙女夏季薄款内搭连" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[177,1670][1032,1723]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="衣裙宽松a字裙中长款打底裙衬裙纯色" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1735][780,1788]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="7" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1794][1080,1812]" drawing-order="4" hint="" display-id="0"/>
<node index="8" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1812][1080,1887]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1812][1080,1887]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1812][1080,1887]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1812][1080,1887]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1818][1080,1887]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="androidx.recyclerview.widget.RecyclerView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1818][1080,1887]" drawing-order="1" hint="" display-id="0">
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[24,1818][400,1881]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[24,1818][400,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[35,1818][399,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[35,1825][399,1874]" drawing-order="1" hint="" display-id="0">
<node index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[47,1825][387,1874]" drawing-order="2" hint="" display-id="0">
<node index="0" text="好评率超99%同款" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[47,1825][387,1874]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
<node index="2" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[400,1818][604,1881]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[400,1818][604,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[411,1818][603,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[411,1825][603,1874]" drawing-order="1" hint="" display-id="0">
<node index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[423,1825][591,1874]" drawing-order="2" hint="" display-id="0">
<node index="0" text="店铺热销" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[423,1825][591,1874]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
<node index="3" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[604,1818][724,1881]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[604,1818][724,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[615,1818][723,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[627,1818][711,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[627,1825][711,1874]" drawing-order="1" hint="" display-id="0">
<node index="0" text="纯色" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[627,1825][711,1874]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
<node index="4" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[724,1818][844,1881]" drawing-order="5" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[724,1818][844,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[735,1818][843,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[747,1818][831,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[747,1825][831,1874]" drawing-order="1" hint="" display-id="0">
<node index="0" text="长款" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[747,1825][831,1874]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
<node index="5" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[844,1818][964,1881]" drawing-order="6" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[844,1818][964,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[855,1818][963,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[867,1818][951,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[867,1825][951,1874]" drawing-order="1" hint="" display-id="0">
<node index="0" text="圆领" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[867,1825][951,1874]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
<node index="6" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[964,1818][1080,1881]" drawing-order="7" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[964,1818][1080,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[975,1818][1080,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[987,1818][1071,1881]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[987,1825][1071,1874]" drawing-order="1" hint="" display-id="0">
<node index="0" text="无袖" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[987,1825][1071,1874]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="9" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1887][1080,1911]" drawing-order="2" hint="" display-id="0"/>
<node index="10" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1911][1080,2166]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1911][1044,2166]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1911][1044,2010]" drawing-order="2" hint="" display-id="0">
<node index="0" text="# # 已直降10.2元,现在拼" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[72,1911][1017,2010]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ViewSwitcher" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,2034][1044,2166]" drawing-order="6" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[72,2040][1008,2166]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[72,2040][1008,2046]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="对比后下单直接拼成" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[72,2046][1008,2166]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[72,2065][274,2165]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[72,2065][274,2165]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[72,2065][172,2165]" drawing-order="5" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[74,2067][170,2163]" drawing-order="6" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[120,2065][220,2165]" drawing-order="3" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[122,2067][218,2163]" drawing-order="4" hint="" display-id="0"/>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[168,2065][268,2165]" drawing-order="1" hint="" display-id="0"/>
<node index="5" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[170,2067][266,2163]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[289,2046][513,2166]" drawing-order="2" hint="" display-id="0">
<node index="0" text="丁戊、快…" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[289,2061][489,2110]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="对比后下单" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[289,2110][512,2166]" drawing-order="3" hint="" display-id="0"/>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[549,2046][783,2166]" drawing-order="4" hint="" display-id="0">
<node index="0" text="拼单即将结束" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[549,2067][783,2113]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[585,2113][783,2166]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[585,2113][783,2166]" drawing-order="1" hint="" display-id="0">
<node index="0" text="00" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[585,2113][633,2166]" drawing-order="2" hint="" display-id="0"/>
<node index="2" text=":" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[633,2113][643,2166]" drawing-order="3" hint="" display-id="0"/>
<node index="3" text="11" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[643,2113][691,2166]" drawing-order="4" hint="" display-id="0"/>
<node index="4" text=":" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[691,2113][701,2166]" drawing-order="5" hint="" display-id="0"/>
<node index="5" text="00" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[701,2113][749,2166]" drawing-order="6" hint="" display-id="0"/>
<node index="6" text="." resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[749,2113][759,2166]" drawing-order="7" hint="" display-id="0"/>
<node index="7" text="6" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[759,2113][783,2166]" drawing-order="8" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[804,2070][1008,2160]" drawing-order="5" hint="" display-id="0">
<node index="0" text="直接拼成" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[804,2070][1008,2160]" drawing-order="2" hint="" display-id="0"/>
</node>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[855,2046][1008,2088]" drawing-order="8" hint="" display-id="0">
<node index="0" text="立享优惠" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[855,2046][1008,2088]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1911][1044,2166]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[45,2010][1035,2166]" drawing-order="4" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.RelativeLayout" package="com.xunmeng.pinduoduo" content-desc="顶部工具栏" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,258]" drawing-order="10" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.RelativeLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,258]" drawing-order="2" hint="" display-id="0">
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="返回" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[15,120][135,258]" drawing-order="7" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[27,141][123,237]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="返回" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[57,158][117,219]" drawing-order="2" hint="" display-id="0"/>
</node>
<node NAF="true" index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[813,120][933,258]" drawing-order="5" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[825,141][921,237]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[825,141][921,237]" drawing-order="2" hint="" display-id="0"/>
</node>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="分享" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[945,120][1065,258]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[957,141][1053,237]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[975,158][1035,219]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2166][1080,2328]" drawing-order="7" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2166][1080,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2166][23,2328]" drawing-order="2" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,2166][446,2328]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="店铺" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,2166][164,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,2166][164,2168]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[23,2168][164,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[62,2190][125,2253]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="店铺" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[54,2258][132,2311]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
<node index="1" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="收藏" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[164,2166][305,2328]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[164,2166][305,2168]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[164,2168][305,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[203,2190][266,2253]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[203,2190][266,2253]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="1" text="收藏" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[195,2258][273,2311]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="客服" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[305,2166][446,2328]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[305,2166][446,2168]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[305,2168][446,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[345,2192][405,2252]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[345,2192][405,2252]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="1" text="客服" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[336,2257][414,2310]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[446,2166][1080,2328]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="false" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[446,2166][1080,2328]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="大促价券后¥4.7" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[446,2166][1080,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[446,2166][1080,2328]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[446,2166][1080,2328]" drawing-order="15" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[481,2202][685,2292]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[481,2202][685,2292]" drawing-order="1" hint="" display-id="0">
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[571,2202][661,2292]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[526,2202][616,2292]" drawing-order="3" hint="" display-id="0"/>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[481,2202][571,2292]" drawing-order="4" hint="" display-id="0"/>
</node>
</node>
<node index="3" text="大促价 券后 ¥ 4.7" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[685,2184][1046,2253]" drawing-order="8" hint="" display-id="0"/>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[685,2253][1031,2307]" drawing-order="10" hint="" display-id="0"/>
<node index="5" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[685,2253][1031,2307]" drawing-order="12" hint="" display-id="0"/>
<node index="6" text="限时直降 免拼购买" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[685,2256][1031,2305]" drawing-order="13" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="android:id/navigationBarBackground" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2328][1080,2376]" drawing-order="2" hint="" display-id="0"/>
</node>
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[801,511][1044,940]" drawing-order="0" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[801,511][1044,940]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[801,511][1044,940]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[801,511][1044,940]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/root" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[801,511][1044,940]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[803,513][1042,938]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[803,513][1042,938]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="tronplayer_view" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[803,513][1042,938]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.TextureView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[803,513][1042,938]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[803,513][1042,938]" drawing-order="7" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[803,513][1042,603]" drawing-order="5" hint="" display-id="0"/>
<node NAF="true" index="3" text="" resource-id="com.xunmeng.pinduoduo:id/iv_float_window_close" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[964,513][1042,591]" drawing-order="6" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[988,525][1030,567]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</hierarchy>
+348
View File
@@ -0,0 +1,348 @@
<?xml version='1.0' encoding='UTF-8'?>
<hierarchy rotation="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="0" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_launch_animation_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.android.systemui:id/status_bar_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_contents" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1075,120]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_start_side_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,19][491,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_start_side_content" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][491,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_start_side_except_heads_up" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][491,110]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/clock_for_fake" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][172,110]" drawing-order="2" hint="" display-id="0">
<node index="0" text="18:10" resource-id="com.android.systemui:id/clock" class="android.widget.TextView" package="com.android.systemui" content-desc="18:10" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[49,19][172,110]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/status_bar_start_side_content_for_fake" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/notification_icon_area" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/notificationIcons" class="android.view.ViewGroup" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][491,110]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="红果免费短剧通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[172,19][220,110]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="抖音通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[220,19][268,110]" drawing-order="2" hint="" display-id="0"/>
<node index="2" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="拼多多通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[268,19][316,110]" drawing-order="3" hint="" display-id="0"/>
<node index="3" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="京东通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[316,19][364,110]" drawing-order="4" hint="" display-id="0"/>
<node index="4" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="小红书通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[364,19][412,110]" drawing-order="5" hint="" display-id="0"/>
<node index="5" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="千问通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[412,19][460,110]" drawing-order="6" hint="" display-id="0"/>
<node index="6" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="哔哩哔哩通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="7" hint="" display-id="0"/>
<node index="7" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="软件商店通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="11" hint="" display-id="0"/>
<node index="8" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="音乐通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="10" hint="" display-id="0"/>
<node index="9" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="淘宝通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="9" hint="" display-id="0"/>
<node index="10" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="番茄畅听通知:" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[433,19][481,110]" drawing-order="8" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/cutout_space_view" class="android.view.View" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[491,19][579,120]" drawing-order="2" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.android.systemui:id/status_bar_end_side_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[579,19][1075,110]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_end_side_container_for_fake" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,19][1011,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/status_bar_end_side_content" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,19][1011,110]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/system_icons" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,34][1011,94]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/statusIcons" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[669,34][929,94]" drawing-order="1" hint="" display-id="0">
<node index="1" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="振铃器静音。" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[674,34][722,94]" drawing-order="11" hint="" display-id="0"/>
<node index="2" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="蓝牙未连接" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[722,34][761,94]" drawing-order="12" hint="" display-id="0"/>
<node index="3" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="勿扰" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[761,34][815,94]" drawing-order="19" hint="" display-id="0"/>
<node index="4" text="" resource-id="com.android.systemui:id/wifi_combo" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,34][881,94]" drawing-order="20" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/wifi_group" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,34][881,94]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/wifi_combo" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,40][881,88]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/wifi_signal" class="android.widget.ImageView" package="com.android.systemui" content-desc="WLAN 信号满格。" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[815,40][881,88]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.android.systemui:id/wifi_inout" class="android.widget.ImageView" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[821,40][881,88]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="5" text="" resource-id="" class="android.widget.ImageView" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[881,34][929,94]" drawing-order="21" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/battery" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="电池 状态栏项目 剩余电量百分之35" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[929,34][1011,94]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.android.systemui:id/battery_icon_view" class="android.widget.ImageView" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[932,40][1010,88]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.android.systemui:id/seeding_card_container" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="com.oplus.systemui.plugins:id/seeding_capsule_container_root" class="android.widget.FrameLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,120]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="2" text="" resource-id="com.android.systemui:id/dynamic_icon_group" class="android.widget.LinearLayout" package="com.android.systemui" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1023,0][1032,120]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2376]" drawing-order="0" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,0][1080,2328]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,2328]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,2328]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,255]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,255]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,255]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,255]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,255]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,120][1080,255]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,146][1080,230]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,255][1080,366]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ViewSwitcher" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,255][1080,366]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,255][1080,366]" drawing-order="1" hint="" display-id="0">
<node index="0" text="#早于99%同类商品送达" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[261,276][819,344]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
<node NAF="true" index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,255][1080,279]" drawing-order="2" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="关闭" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[975,273][1050,348]" drawing-order="3" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,364][1080,366]" drawing-order="4" hint="" display-id="0"/>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,2328]" drawing-order="4" hint="" display-id="0">
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,2079]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,2079]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,549]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,532]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,532]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,532]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,532]" drawing-order="1" hint="" display-id="0">
<node index="3" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,532]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,366][1080,532]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,366][1044,532]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,416][102,482]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[132,366][993,532]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[132,393][993,444]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[132,393][400,444]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[138,396][394,442]" drawing-order="1" hint="" display-id="0">
<node index="0" text="7天无理由退货" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[138,396][394,442]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="2" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[412,394][832,443]" drawing-order="3" hint="" display-id="0">
<node index="0" text="钮gre...,199****5018" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[412,394][832,443]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[132,456][993,505]" drawing-order="2" hint="" display-id="0">
<node index="0" text="扶大富力中心写字楼10楼1016房拒收韵达_green0952 XGVTPN 1/1" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[132,456][993,505]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="2" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1023,434][1044,464]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,532][1080,549]" drawing-order="6" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,549][1080,551]" drawing-order="2" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1080,1024]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.RelativeLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1080,1024]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1080,635]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1080,635]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1080,635]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1080,635]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1080,635]" drawing-order="3" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,551][1056,635]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,570][711,616]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,572][378,614]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[390,570][711,616]" drawing-order="2" hint="" display-id="0">
<node index="0" text="官方大促 限时直降" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[390,570][711,616]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,575][1080,1024]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[12,635][1068,1012]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,662][360,986]" drawing-order="2" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/iv_live_img" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="商品主图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,662][360,986]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,662][360,986]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="2" text="" resource-id="" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,662][360,986]" drawing-order="4" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,659][1044,731]" drawing-order="8" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,659][739,731]" drawing-order="1" hint="" display-id="0">
<node index="0" text="折后¥4.7" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,664][594,731]" drawing-order="2" hint="" display-id="0"/>
<node index="1" text="¥19.9" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[612,664][739,731]" drawing-order="3" hint="" display-id="0"/>
</node>
</node>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,746][525,803]" drawing-order="10" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,746][525,803]" drawing-order="1" hint="" display-id="0">
<node index="0" text="已包邮" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,746][525,803]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="5" text="已选: 黑色中长款 2XL(140-160斤)" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,815][1044,877]" drawing-order="12" hint="" display-id="0"/>
<node index="7" text="" resource-id="com.xunmeng.pinduoduo:id/gnl" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,913][633,988]" drawing-order="17" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,913][633,988]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="减少数量" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[384,913][462,988]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="1" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.EditText" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="true" password="false" selected="false" visible-to-user="true" bounds="[468,913][549,988]" drawing-order="4" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="增加数量" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[555,913][633,988]" drawing-order="6" hint="" display-id="0"/>
</node>
</node>
<node index="8" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,988][1044,1012]" drawing-order="21" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1024][1080,1159]" drawing-order="5" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1024][1080,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1024][1080,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1024][1080,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1024][1080,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1024][1080,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1024][196,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1024][196,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1059][192,1125]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1069][192,1115]" drawing-order="1" hint="" display-id="0">
<node index="0" text="活动优惠" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1069][192,1115]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1158][1080,1159]" drawing-order="3" hint="" display-id="0"/>
<node index="2" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[339,1024][1044,1159]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[339,1024][1011,1159]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[343,1059][658,1125]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[343,1066][658,1119]" drawing-order="1" hint="" display-id="0">
<node index="0" text="大促与平台优惠" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[343,1066][658,1119]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[658,1059][802,1125]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[658,1066][802,1119]" drawing-order="1" hint="" display-id="0">
<node index="0" text="-15.2元" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[658,1066][802,1119]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="2" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[802,1059][829,1125]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[802,1066][829,1119]" drawing-order="1" hint="" display-id="0">
<node index="0" text=" (" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[802,1066][829,1119]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="3" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[829,1059][886,1125]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[829,1071][886,1113]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="4" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[886,1059][994,1125]" drawing-order="5" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[886,1066][994,1119]" drawing-order="1" hint="" display-id="0">
<node index="0" text="仅1次" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[886,1066][994,1119]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="5" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[994,1059][1011,1125]" drawing-order="6" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[994,1066][1011,1119]" drawing-order="1" hint="" display-id="0">
<node index="0" text=")" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[994,1066][1011,1119]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
<node index="1" text="" resource-id="" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1023,1077][1044,1107]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="androidx.recyclerview.widget.RecyclerView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1159][1080,2079]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1159][1080,2079]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1159][1080,1270]" drawing-order="1" hint="" display-id="0">
<node index="0" text="颜色分类" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1188][192,1241]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1270][1080,2079]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,1270][1080,2079]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="androidx.recyclerview.widget.RecyclerView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1270][1080,2079]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="黑色中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[36,1270][348,1669]" drawing-order="1" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[36,1270][348,1669]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="黑色中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[36,1270][348,1582]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[36,1270][147,1381]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[36,1561][348,1669]" drawing-order="3" hint="" display-id="0">
<node index="0" text="黑色中长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="true" visible-to-user="true" bounds="[36,1561][348,1669]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc=" 白色中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1270][684,1669]" drawing-order="3" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1270][684,1669]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc=" 白色中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1270][684,1582]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1270][483,1381]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1561][684,1669]" drawing-order="3" hint="" display-id="0">
<node index="0" text=" 白色中长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1561][684,1669]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="2" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="卡其中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1270][1020,1669]" drawing-order="5" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1270][1020,1669]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="卡其中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1270][1020,1582]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1270][819,1381]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1561][1020,1669]" drawing-order="3" hint="" display-id="0">
<node index="0" text="卡其中长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1561][1020,1669]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="3" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="浅蓝色中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1270][1080,1669]" drawing-order="7" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1270][1080,1669]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="浅蓝色中长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1270][1080,1582]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1270][1080,1381]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1561][1080,1669]" drawing-order="3" hint="" display-id="0">
<node index="0" text="浅蓝色中长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1561][1080,1669]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="4" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="黑色长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1699][348,2079]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1699][348,2079]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="黑色长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1699][348,2011]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1699][147,1810]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1990][348,2079]" drawing-order="3" hint="" display-id="0">
<node index="0" text="黑色长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,1990][348,2079]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="5" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc=" 白色长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1699][684,2079]" drawing-order="4" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1699][684,2079]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc=" 白色长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1699][684,2011]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1699][483,1810]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1990][684,2079]" drawing-order="3" hint="" display-id="0">
<node index="0" text=" 白色长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[372,1990][684,2079]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="6" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="卡其长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1699][1020,2079]" drawing-order="6" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1699][1020,2079]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="卡其长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1699][1020,2011]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1699][819,1810]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1990][1020,2079]" drawing-order="3" hint="" display-id="0">
<node index="0" text="卡其长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[708,1990][1020,2079]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
<node index="7" text="" resource-id="" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="浅蓝色长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1699][1080,2079]" drawing-order="8" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1699][1080,2079]" drawing-order="4" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="浅蓝色长款" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1699][1080,2011]" drawing-order="1" hint="" display-id="0"/>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="打开大图" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1699][1080,1810]" drawing-order="2" hint="" display-id="0"/>
<node index="3" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1990][1080,2079]" drawing-order="3" hint="" display-id="0">
<node index="0" text="浅蓝色长款" resource-id="com.xunmeng.pinduoduo:id/tv_content" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[1044,1990][1080,2079]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.ViewGroup" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2079][1080,2178]" drawing-order="7" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2079][1080,2081]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[94,2100][930,2157]" drawing-order="2" hint="" display-id="0">
<node index="0" text="使用#微信支付,更换先用后付可0元下单" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[112,2100][930,2157]" drawing-order="1" hint="" display-id="0"/>
</node>
<node index="2" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ImageView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[939,2113][969,2143]" drawing-order="3" hint="" display-id="0"/>
</node>
<node index="4" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.FrameLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2181][1080,2328]" drawing-order="11" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[282,2181][798,2328]" drawing-order="2" hint="" display-id="0">
<node index="0" text="现在买,仅 ¥4.7" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[294,2225][647,2284]" drawing-order="1" hint="" display-id="0"/>
<node index="1" text=" ¥19.9" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[647,2222][786,2287]" drawing-order="2" hint="" display-id="0"/>
</node>
</node>
<node index="5" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.ViewSwitcher" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,2154][1044,2226]" drawing-order="13" hint="" display-id="0">
<node index="0" text="" resource-id="" class="android.widget.RelativeLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[36,2154][1044,2226]" drawing-order="2" hint="" display-id="0">
<node index="0" text="" resource-id="com.xunmeng.pinduoduo:id/pdd" class="android.widget.LinearLayout" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[584,2154][1044,2226]" drawing-order="1" hint="" display-id="0">
<node index="0" text="早于99%同类商品送达" resource-id="" class="android.widget.TextView" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[584,2164][1044,2215]" drawing-order="1" hint="" display-id="0"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="android:id/navigationBarBackground" class="android.view.View" package="com.xunmeng.pinduoduo" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" visible-to-user="true" bounds="[0,2328][1080,2376]" drawing-order="2" hint="" display-id="0"/>
</node>
</hierarchy>
+229
View File
@@ -0,0 +1,229 @@
"""一条采集任务的应用层流程:领取、采集、落库、提交。"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable, Optional
from .admin_gateway import (
AdminGateway,
AdminGatewayError,
AndroidDeviceInfo,
ClaimCapabilities,
ClientInfo,
)
from .pdd_collect_service import PddCollectError, PddCollectService
from .pdd_device_service import PddDeviceService
from .db import data_dir
from .task_models import OutboxEventRecord, OutboxEventType, TaskStatus, TaskType
from .task_models import NewClaimedTask
from .task_repository import DuplicateTaskError, TaskRepository
@dataclass(frozen=True)
class CollectTaskOutcome:
"""工作线程返回给界面的简短结果。"""
kind: str
message: str
task_id: str = ""
CollectServiceFactory = Callable[
[str, str, Callable[[], bool]], PddCollectService
]
class CollectTaskService:
"""一次调用只处理一条本地工作或一个待提交事件。"""
def __init__(
self,
gateway: AdminGateway,
repository: TaskRepository,
client: ClientInfo,
device_address: str,
*,
cancelled: Callable[[], bool] = lambda: False,
collect_service_factory: Optional[CollectServiceFactory] = None,
) -> None:
self._gateway = gateway
self._repository = repository
self._client = client
self._device_address = device_address
self._cancelled = cancelled
self._factory = collect_service_factory or self._default_factory
def execute_one(self) -> CollectTaskOutcome:
"""先补交已有结果,再执行最早的本地任务,最后才领取新任务。"""
pending = self._repository.next_pending_outbox()
if pending is not None:
return self._submit(pending)
if not self._device_address.strip():
raise ValueError("请先在设置页选择并保存 Android 设备")
task = self._repository.next_collect_task()
if task is None:
remote = self._gateway.claim_next(
self._client,
ClaimCapabilities(
device=AndroidDeviceInfo(self._device_address),
supported_types=(TaskType.COLLECT,),
purchase_mode="dry_run",
schema_versions=(1,),
),
)
if remote is None:
return CollectTaskOutcome("no_task", "暂无可领取的采集任务")
try:
self._repository.add_claimed_task(
NewClaimedTask(
remote_task_id=remote.task_id,
task_type=remote.task_type,
goods_url=str(remote.payload.get("goods_url") or ""),
goods_id=(
str(remote.payload["goods_id"])
if remote.payload.get("goods_id") is not None
else None
),
priority=remote.priority,
version=remote.version,
admin_payload={
"id": remote.task_id,
"type": remote.task_type.value,
"version": remote.version,
"priority": remote.priority,
"payload": dict(remote.payload),
"created_at": remote.created_at,
"updated_at": remote.updated_at,
},
)
)
except DuplicateTaskError:
pass
except Exception as exc:
raise RuntimeError(
f"任务 {remote.task_id} 已领取,但本地保存失败:{exc}"
) from exc
task = self._repository.get_task(remote.task_id)
if task is None:
raise RuntimeError(f"任务 {remote.task_id} 未能保存到本地")
if self._cancelled():
return CollectTaskOutcome("cancelled", "本次采集已取消", task.remote_task_id)
started = self._repository.start_collect_run(
task.remote_task_id, self._device_address
)
collector = self._factory(
self._device_address, self._client.client_id, self._cancelled
)
try:
result = collector.collect(started.task)
event = self._repository.save_collect_result(
task.remote_task_id, started.attempt_id, result.to_pdd_data()
)
except PddCollectError as exc:
status, retryable = self._classify_error(exc.code)
report_code = self._report_error_code(exc.code)
event = self._repository.save_collect_failure(
task.remote_task_id,
started.attempt_id,
status,
report_code,
exc.message,
retryable,
exc.diagnostics,
)
return self._submit(event)
def _submit(self, event: OutboxEventRecord) -> CollectTaskOutcome:
task_id = self._repository.outbox_task_id(event.id)
self._repository.mark_outbox_sending(event.id)
try:
if event.event_type is OutboxEventType.TASK_FAILURE:
receipt = self._gateway.submit_failure(
task_id, event.idempotency_key, event.payload_json
)
else:
receipt = self._gateway.submit_result(
task_id, event.idempotency_key, event.payload_json
)
if not receipt.accepted:
raise AdminGatewayError(
"ADMIN_RESULT_NOT_ACCEPTED", "Admin 未确认接收结果", False
)
except AdminGatewayError as exc:
message = str(exc)
if exc.retryable:
self._repository.mark_outbox_retry(event.id, message)
return CollectTaskOutcome(
"result_pending",
f"任务 {task_id} 数据已保存在本地,等待重新提交 Admin:{message}",
task_id,
)
self._repository.mark_outbox_failed(event.id, message)
return CollectTaskOutcome(
"manual_review",
f"任务 {task_id} 提交被 Admin 拒绝:{message}",
task_id,
)
self._repository.mark_outbox_sent(event.id)
if event.event_type is OutboxEventType.TASK_FAILURE:
return CollectTaskOutcome(
"failed",
f"任务 {task_id} 采集未完成,失败信息已提交 Admin",
task_id,
)
return CollectTaskOutcome(
"succeeded", f"任务 {task_id} 采集完成并已提交 Admin", task_id
)
@staticmethod
def _classify_error(code: str) -> tuple[TaskStatus, bool]:
if code == "PDD_CANCELLED":
return TaskStatus.CANCELLED, False
if code in {
"PDD_PAGE_LOGIN_REQUIRED",
"PDD_PAGE_CAPTCHA",
"PDD_DATA_SPEC_INCOMPLETE",
"PDD_DATA_TITLE_MISSING",
"PDD_DATA_PRICE_MISSING",
"PDD_DATA_SKU_NAME_TRUNCATED",
}:
return TaskStatus.MANUAL_REVIEW, False
if code.startswith("PDD_DATA_GOODS_"):
return TaskStatus.FAILED, False
return TaskStatus.RETRY_WAIT, True
@staticmethod
def _report_error_code(code: str) -> str:
"""把内部解析代码映射为 Admin 可枚举的稳定代码。"""
return {
"PDD_DATA_SKU_NAME_TRUNCATED": "SKU_NAME_TRUNCATED",
"PDD_PAGE_SPEC_ENTRY_MISSING": "SKU_PANEL_NOT_FOUND",
"PDD_DATA_TITLE_MISSING": "TITLE_TOO_SHORT",
"PDD_PAGE_OVERALL_TIMEOUT": "COLLECT_TIMEOUT",
"DEVICE_OFFLINE": "DEVICE_DISCONNECTED",
"DEVICE_CONNECT_FAILED": "DEVICE_DISCONNECTED",
"DEVICE_DISCONNECTED": "DEVICE_DISCONNECTED",
}.get(code, code)
@staticmethod
def _default_factory(
device_address: str,
client_id: str,
cancelled: Callable[[], bool],
) -> PddCollectService:
return PddCollectService(
PddDeviceService(),
device_address,
client_id,
cancelled=cancelled,
overall_timeout=600.0,
artifact_directory=data_dir() / "artifacts",
)
+107 -5
View File
@@ -3,20 +3,20 @@
import json import json
import socket import socket
from http.client import RemoteDisconnected from http.client import RemoteDisconnected
from typing import Callable, Mapping, Optional from typing import Any, Callable, Mapping, Optional
from urllib.error import HTTPError, URLError from urllib.error import HTTPError, URLError
from urllib.parse import urlparse from urllib.parse import urlparse
from urllib.request import ProxyHandler, Request, build_opener from urllib.request import ProxyHandler, Request, build_opener
from uuid import uuid4 from uuid import uuid4
from .admin_gateway import ( from .admin_gateway import (
AdminGateway,
AdminTask, AdminTask,
AdminGatewayError, AdminGatewayError,
ClaimCapabilities, ClaimCapabilities,
ClientInfo, ClientInfo,
ClientRegistrationGateway,
RegistrationReceipt, RegistrationReceipt,
TaskClaimGateway, SubmissionReceipt,
) )
from .task_models import TaskType from .task_models import TaskType
@@ -24,8 +24,8 @@ from .task_models import TaskType
DEFAULT_ADMIN_BASE_URL = "http://127.0.0.1:8080" DEFAULT_ADMIN_BASE_URL = "http://127.0.0.1:8080"
class HttpAdminGateway(ClientRegistrationGateway, TaskClaimGateway): class HttpAdminGateway(AdminGateway):
"""通过 HTTP 登记 Client 和领取采集任务;令牌只保存在内存。""" """通过 HTTP 登记、领取和提交任务;令牌只保存在内存。"""
def __init__( def __init__(
self, self,
@@ -33,6 +33,7 @@ class HttpAdminGateway(ClientRegistrationGateway, TaskClaimGateway):
token: str = "", token: str = "",
timeout_seconds: float = 3.0, timeout_seconds: float = 3.0,
opener: Optional[Callable] = None, opener: Optional[Callable] = None,
client_id: str = "",
): ):
normalized_url = base_url.strip().rstrip("/") normalized_url = base_url.strip().rstrip("/")
parsed = urlparse(normalized_url) parsed = urlparse(normalized_url)
@@ -44,6 +45,7 @@ class HttpAdminGateway(ClientRegistrationGateway, TaskClaimGateway):
self._base_url = normalized_url self._base_url = normalized_url
self._token = token.strip() self._token = token.strip()
self._timeout_seconds = timeout_seconds self._timeout_seconds = timeout_seconds
self._client_id = client_id.strip()
# Admin 通常运行在本机或局域网。明确禁用环境代理,避免 # Admin 通常运行在本机或局域网。明确禁用环境代理,避免
# HTTP_PROXY 把 127.0.0.1 请求错误转发到代理服务器。 # HTTP_PROXY 把 127.0.0.1 请求错误转发到代理服务器。
self._opener = opener or build_opener(ProxyHandler({})).open self._opener = opener or build_opener(ProxyHandler({})).open
@@ -54,6 +56,7 @@ class HttpAdminGateway(ClientRegistrationGateway, TaskClaimGateway):
"""调用独立登记接口,不领取或修改任务。""" """调用独立登记接口,不领取或修改任务。"""
request_id = str(uuid4()) request_id = str(uuid4())
self._client_id = client.client_id.strip()
payload = { payload = {
"client": {"name": client.name.strip()}, "client": {"name": client.name.strip()},
"supported_types": [ "supported_types": [
@@ -146,6 +149,7 @@ class HttpAdminGateway(ClientRegistrationGateway, TaskClaimGateway):
"""领取一个采集任务;Admin 返回 204 时返回 ``None``。""" """领取一个采集任务;Admin 返回 204 时返回 ``None``。"""
request_id = str(uuid4()) request_id = str(uuid4())
self._client_id = client.client_id.strip()
payload = { payload = {
"client": {"name": client.name.strip()}, "client": {"name": client.name.strip()},
# #30 只允许领取采集任务。采购能力必须由安全门禁工单开启。 # #30 只允许领取采集任务。采购能力必须由安全门禁工单开启。
@@ -219,6 +223,104 @@ class HttpAdminGateway(ClientRegistrationGateway, TaskClaimGateway):
) )
return self._parse_claim_response(body, request_id) return self._parse_claim_response(body, request_id)
def submit_result(
self,
task_id: str,
idempotency_key: str,
result: Mapping[str, Any],
) -> SubmissionReceipt:
"""幂等提交成功结果。"""
return self._submit(task_id, idempotency_key, result, "result")
def submit_failure(
self,
task_id: str,
idempotency_key: str,
failure: Mapping[str, Any],
) -> SubmissionReceipt:
"""幂等提交失败或人工处理结果。"""
return self._submit(task_id, idempotency_key, failure, "failure")
def _submit(
self,
task_id: str,
idempotency_key: str,
payload: Mapping[str, Any],
endpoint: str,
) -> SubmissionReceipt:
if not task_id.strip():
raise ValueError("task_id 不能为空")
if not idempotency_key.strip():
raise ValueError("Idempotency-Key 不能为空")
if not self._client_id:
raise AdminGatewayError(
"CLIENT_ID_MISSING",
"提交结果前必须先配置 Client 设备号",
False,
)
request_id = str(uuid4())
headers = {
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
"Idempotency-Key": idempotency_key.strip(),
"X-Request-Id": request_id,
"X-Client-Id": self._client_id,
}
if self._token:
headers["Authorization"] = f"Bearer {self._token}"
request = Request(
f"{self._base_url}/api/v1/client/tasks/{task_id.strip()}/{endpoint}",
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
headers=headers,
method="POST",
)
try:
with self._opener(request, timeout=self._timeout_seconds) as response:
status = getattr(response, "status", None)
if status is None:
status = response.getcode()
body = response.read()
except HTTPError as exc:
self._raise_http_error(exc, request_id, "提交任务")
except (
URLError,
RemoteDisconnected,
ConnectionError,
socket.timeout,
TimeoutError,
) as exc:
reason = getattr(exc, "reason", exc)
code = "ADMIN_TIMEOUT" if isinstance(reason, (socket.timeout, TimeoutError)) else "ADMIN_UNAVAILABLE"
message = "Admin 提交请求超时,请稍后重试" if code == "ADMIN_TIMEOUT" else "无法连接 Admin,结果已保存在本地"
raise AdminGatewayError(code, message, True, request_id) from exc
if status not in (200, 201):
raise AdminGatewayError(
"ADMIN_UNEXPECTED_RESPONSE",
f"Admin 返回了未预期的状态码 {status}",
status >= 500,
request_id,
)
data = self._decode_json(body, request_id)
accepted = data.get("accepted")
result_id = data.get("result_id")
accepted_at = data.get("accepted_at")
if (
accepted is not True
or not isinstance(result_id, str)
or not result_id.strip()
or not isinstance(accepted_at, str)
or not accepted_at.strip()
):
raise AdminGatewayError(
"ADMIN_INVALID_RESPONSE",
"Admin 提交响应字段不完整",
False,
request_id,
)
return SubmissionReceipt(True, result_id, accepted_at)
@classmethod @classmethod
def _parse_claim_response( def _parse_claim_response(
cls, cls,
+197 -35
View File
@@ -14,6 +14,7 @@ import xml.etree.ElementTree as ET
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timezone from datetime import datetime, timezone
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
from pathlib import Path
from typing import Any, Callable, Iterable, Mapping, Optional, Sequence from typing import Any, Callable, Iterable, Mapping, Optional, Sequence
from urllib.parse import parse_qs, urlparse from urllib.parse import parse_qs, urlparse
@@ -31,13 +32,32 @@ _CAPTCHA_MARKERS = ("请完成验证", "拖动滑块", "安全验证", "点击
_READY_MARKERS = ("发起拼单", "立即购买", "单独购买", "免拼购买", "快要抢光") _READY_MARKERS = ("发起拼单", "立即购买", "单独购买", "免拼购买", "快要抢光")
def _is_device_disconnect(error: BaseException) -> bool:
details = str(error).lower()
return any(
marker in details
for marker in (
"device not found",
"device offline",
"disconnected",
"closed transport",
)
)
class PddCollectError(RuntimeError): class PddCollectError(RuntimeError):
"""采集失败,并携带稳定错误码。""" """采集失败,并携带稳定错误码。"""
def __init__(self, code: str, message: str) -> None: def __init__(
self,
code: str,
message: str,
diagnostics: Optional[Mapping[str, Any]] = None,
) -> None:
super().__init__(message) super().__init__(message)
self.code = code self.code = code
self.message = message self.message = message
self.diagnostics = dict(diagnostics or {})
@dataclass(frozen=True) @dataclass(frozen=True)
@@ -85,11 +105,15 @@ class SkuResult:
price_cent: Optional[int] price_cent: Optional[int]
available: bool available: bool
raw_price: Optional[str] raw_price: Optional[str]
price_observed_at: Mapping[str, str]
list_price_cent: Optional[int] = None
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, Any]:
return { return {
"options": dict(self.options), "options": dict(self.options),
"price_cent": self.price_cent, "price_cent": self.price_cent,
"list_price_cent": self.list_price_cent,
"price_observed_at": dict(self.price_observed_at),
"currency": "CNY", "currency": "CNY",
"available": self.available, "available": self.available,
"raw_price": self.raw_price, "raw_price": self.raw_price,
@@ -110,6 +134,7 @@ class SpecSnapshot:
selected_text: Optional[str] selected_text: Optional[str]
price_cent: Optional[int] price_cent: Optional[int]
raw_price: Optional[str] raw_price: Optional[str]
list_price_cent: Optional[int]
@dataclass(frozen=True) @dataclass(frozen=True)
@@ -127,16 +152,16 @@ class CollectResult:
captured_at: str captured_at: str
client_id: str client_id: str
device_address: str device_address: str
artifacts: tuple[Mapping[str, Any], ...] = ()
def to_pdd_data(self) -> dict[str, Any]: def to_pdd_data(self) -> dict[str, Any]:
return { return {
"schema_version": 1, "schema_version": 1,
"goods": { "goods_id": self.goods_id,
"goods_id": self.goods_id, "goods_url": self.goods_url,
"url": self.goods_url, "title": self.title,
"title": self.title, "shop_name": self.shop_name,
}, "price_granularity": "color",
"shop": {"name": self.shop_name},
"metrics": { "metrics": {
"sales": self.sales.to_dict(), "sales": self.sales.to_dict(),
"reviews": self.reviews.to_dict(), "reviews": self.reviews.to_dict(),
@@ -150,7 +175,7 @@ class CollectResult:
"device_address": self.device_address, "device_address": self.device_address,
"pdd_package": PDD_PACKAGE_NAME, "pdd_package": PDD_PACKAGE_NAME,
}, },
"artifacts": [], "artifacts": [dict(item) for item in self.artifacts],
} }
@@ -182,6 +207,14 @@ def _node_label(node: ET.Element) -> str:
) )
def _preferred_node_label(node: ET.Element) -> str:
"""规格名被 text 截断时,优先采用完整的无障碍描述。"""
text = (node.get("text") or "").strip()
description = (node.get("content-desc") or "").strip()
return description or text
def _own_or_descendant_label(node: ET.Element) -> str: def _own_or_descendant_label(node: ET.Element) -> str:
own = _node_label(node) own = _node_label(node)
if own: if own:
@@ -193,6 +226,17 @@ def _own_or_descendant_label(node: ET.Element) -> str:
return "" return ""
def _preferred_or_descendant_label(node: ET.Element) -> str:
own = _preferred_node_label(node)
if own:
return own
for child in node.iter("node"):
label = _preferred_node_label(child)
if label and label != "打开大图":
return label
return ""
def _all_labels(root: ET.Element) -> list[str]: def _all_labels(root: ET.Element) -> list[str]:
return [label for node in root.iter("node") if (label := _node_label(node))] return [label for node in root.iter("node") if (label := _node_label(node))]
@@ -250,9 +294,21 @@ def parse_goods_page(xml_data: str | bytes) -> GoodsSnapshot:
title = candidate title = candidate
break break
if title is None: if title is None:
line_parts: dict[int, list[tuple[int, str]]] = {}
for node in root.iter("node"):
label = _preferred_node_label(node)
bounds = _parse_bounds(node.get("bounds", ""))
if not label or bounds is None:
continue
line_key = bounds[1] // 24
line_parts.setdefault(line_key, []).append((bounds[0], label))
joined_lines = [
"".join(text for _, text in sorted(parts))
for parts in line_parts.values()
]
candidates = [ candidates = [
label label
for label in labels for label in labels + joined_lines
if len(label) >= 12 if len(label) >= 12
and not any(word in label for word in ("通知", "支付", "已拼", "评价")) and not any(word in label for word in ("通知", "支付", "已拼", "评价"))
] ]
@@ -347,7 +403,7 @@ def _top_level_clickable_options(
def _price_from_nodes( def _price_from_nodes(
nodes: Iterable[ET.Element], nodes: Iterable[ET.Element],
spec_top: int, spec_top: int,
) -> tuple[Optional[int], Optional[str]]: ) -> tuple[Optional[int], Optional[str], Optional[int]]:
candidates: list[tuple[int, int, str]] = [] candidates: list[tuple[int, int, str]] = []
for node in nodes: for node in nodes:
label = _node_label(node) label = _node_label(node)
@@ -366,9 +422,12 @@ def _price_from_nodes(
continue continue
candidates.append((bounds[1], cents, match.group(0).replace(" ", ""))) candidates.append((bounds[1], cents, match.group(0).replace(" ", "")))
if not candidates: if not candidates:
return None, None return None, None, None
_, cents, raw = min(candidates, key=lambda item: (item[0], item[1])) first_top = min(item[0] for item in candidates)
return cents, raw first_row = [item for item in candidates if abs(item[0] - first_top) <= 12]
_, cents, raw = min(first_row, key=lambda item: item[1])
list_prices = [item[1] for item in first_row if item[1] > cents]
return cents, raw, max(list_prices, default=None)
def parse_spec_panel(xml_data: str | bytes) -> SpecSnapshot: def parse_spec_panel(xml_data: str | bytes) -> SpecSnapshot:
@@ -446,7 +505,12 @@ def parse_spec_panel(xml_data: str | bytes) -> SpecSnapshot:
values: list[DimensionValue] = [] values: list[DimensionValue] = []
seen: set[str] = set() seen: set[str] = set()
for node in option_nodes: for node in option_nodes:
text = _own_or_descendant_label(node).strip() text = _preferred_or_descendant_label(node).strip()
if text.endswith(("…", "...")):
raise PddCollectError(
"PDD_DATA_SKU_NAME_TRUNCATED",
f"规格名称被截断,无法安全采集:{text}",
)
if not text or text in seen: if not text or text in seen:
continue continue
seen.add(text) seen.add(text)
@@ -458,8 +522,12 @@ def parse_spec_panel(xml_data: str | bytes) -> SpecSnapshot:
dimensions.append(SpecDimension(key, name, tuple(values))) dimensions.append(SpecDimension(key, name, tuple(values)))
selected_text = next((label for label in labels if label.startswith("已选")), None) selected_text = next((label for label in labels if label.startswith("已选")), None)
price_cent, raw_price = _price_from_nodes(root.iter("node"), outer_bounds[1]) price_cent, raw_price, list_price_cent = _price_from_nodes(
return SpecSnapshot(tuple(dimensions), selected_text, price_cent, raw_price) root.iter("node"), outer_bounds[1]
)
return SpecSnapshot(
tuple(dimensions), selected_text, price_cent, raw_price, list_price_cent
)
def _ancestors( def _ancestors(
@@ -561,9 +629,11 @@ class PddCollectService:
now: Callable[[], datetime] = lambda: datetime.now(timezone.utc), now: Callable[[], datetime] = lambda: datetime.now(timezone.utc),
cancelled: Callable[[], bool] = lambda: False, cancelled: Callable[[], bool] = lambda: False,
page_timeout: float = 30.0, page_timeout: float = 30.0,
overall_timeout: float = 600.0,
max_page_swipes: int = 12, max_page_swipes: int = 12,
max_spec_swipes: int = 12, max_spec_swipes: int = 12,
max_sku_count: int = 200, max_sku_count: int = 200,
artifact_directory: Optional[Path] = None,
) -> None: ) -> None:
self._device_service = device_service self._device_service = device_service
self._device_address = device_address self._device_address = device_address
@@ -573,9 +643,15 @@ class PddCollectService:
self._now = now self._now = now
self._cancelled = cancelled self._cancelled = cancelled
self._page_timeout = page_timeout self._page_timeout = page_timeout
self._overall_timeout = overall_timeout
self._overall_deadline: Optional[float] = None
self._max_page_swipes = max_page_swipes self._max_page_swipes = max_page_swipes
self._max_spec_swipes = max_spec_swipes self._max_spec_swipes = max_spec_swipes
self._max_sku_count = max_sku_count self._max_sku_count = max_sku_count
self._artifact_directory = artifact_directory
self._last_goods_xml: Optional[str] = None
self._goods_screens_checked = 0
self._artifacts: list[Mapping[str, Any]] = []
def collect(self, task: Any) -> CollectResult: def collect(self, task: Any) -> CollectResult:
"""执行采集;``task`` 至少提供 ``goods_url`` 和可选 ``goods_id``。""" """执行采集;``task`` 至少提供 ``goods_url`` 和可选 ``goods_id``。"""
@@ -585,6 +661,7 @@ class PddCollectService:
raise PddCollectError("PDD_DATA_GOODS_URL_MISSING", "采集任务缺少商品链接") raise PddCollectError("PDD_DATA_GOODS_URL_MISSING", "采集任务缺少商品链接")
goods_id = str(getattr(task, "goods_id", "") or "").strip() goods_id = str(getattr(task, "goods_id", "") or "").strip()
goods_id = _validate_goods_url(goods_url, goods_id) goods_id = _validate_goods_url(goods_url, goods_id)
self._overall_deadline = self._monotonic() + self._overall_timeout
self._check_cancelled() self._check_cancelled()
try: try:
@@ -593,12 +670,14 @@ class PddCollectService:
goods = self._collect_goods_details(device) goods = self._collect_goods_details(device)
if not goods.title: if not goods.title:
raise PddCollectError("PDD_DATA_TITLE_MISSING", "商品页没有可识别的标题") raise PddCollectError("PDD_DATA_TITLE_MISSING", "商品页没有可识别的标题")
if not goods.shop_name:
raise PddCollectError("PDD_DATA_SHOP_MISSING", "商品页没有采集到店铺名称")
if not goods.sales.raw: if not goods.sales.raw:
raise PddCollectError("PDD_DATA_SALES_MISSING", "商品页没有采集到已拼数量") raise PddCollectError("PDD_DATA_SALES_MISSING", "商品页没有采集到已拼数量")
if not goods.reviews.raw: if not goods.reviews.raw:
raise PddCollectError("PDD_DATA_REVIEWS_MISSING", "商品页没有采集到评价数量") raise PddCollectError("PDD_DATA_REVIEWS_MISSING", "商品页没有采集到评价数量")
if not goods.shop_name and self._last_goods_xml:
artifact = self._save_xml("shop-not-found", self._last_goods_xml)
if artifact:
self._artifacts.append(artifact)
home_xml = device.dump_hierarchy() home_xml = device.dump_hierarchy()
coordinate = get_size_panel_coord(home_xml) coordinate = get_size_panel_coord(home_xml)
@@ -623,11 +702,23 @@ class PddCollectService:
) )
if not skus or not has_available_price: if not skus or not has_available_price:
raise PddCollectError("PDD_DATA_PRICE_MISSING", "没有采集到可用 SKU 的价格") raise PddCollectError("PDD_DATA_PRICE_MISSING", "没有采集到可用 SKU 的价格")
except PddCollectError: except PddCollectError as exc:
if not exc.diagnostics and self._last_goods_xml:
artifact = self._save_xml("collect-failed", self._last_goods_xml)
if artifact:
exc.diagnostics = {
"artifacts": [artifact],
"goods_screens_checked": self._goods_screens_checked,
}
raise raise
except PddDeviceError as exc: except PddDeviceError as exc:
raise PddCollectError(exc.code, exc.message) from exc raise PddCollectError(exc.code, exc.message) from exc
except Exception as exc: except Exception as exc:
if _is_device_disconnect(exc):
raise PddCollectError(
"DEVICE_DISCONNECTED",
f"Android 设备在采集过程中断开:{exc}",
) from exc
raise PddCollectError("PDD_PAGE_UNKNOWN", f"PDD 采集过程中发生未知错误:{exc}") from exc raise PddCollectError("PDD_PAGE_UNKNOWN", f"PDD 采集过程中发生未知错误:{exc}") from exc
return CollectResult( return CollectResult(
@@ -642,11 +733,17 @@ class PddCollectService:
captured_at=self._now().astimezone(timezone.utc).isoformat().replace("+00:00", "Z"), captured_at=self._now().astimezone(timezone.utc).isoformat().replace("+00:00", "Z"),
client_id=self._client_id, client_id=self._client_id,
device_address=self._device_address, device_address=self._device_address,
artifacts=tuple(self._artifacts),
) )
def _check_cancelled(self) -> None: def _check_cancelled(self) -> None:
if self._cancelled(): if self._cancelled():
raise PddCollectError("PDD_CANCELLED", "采集任务已安全取消") raise PddCollectError("PDD_CANCELLED", "采集任务已安全取消")
if (
self._overall_deadline is not None
and self._monotonic() >= self._overall_deadline
):
raise PddCollectError("PDD_PAGE_OVERALL_TIMEOUT", "PDD 采集超过 10 分钟")
def _open_goods(self, device: Any, goods_url: str) -> None: def _open_goods(self, device: Any, goods_url: str) -> None:
try: try:
@@ -659,6 +756,11 @@ class PddCollectService:
except PddCollectError: except PddCollectError:
raise raise
except Exception as exc: except Exception as exc:
if _is_device_disconnect(exc):
raise PddCollectError(
"DEVICE_DISCONNECTED",
f"Android 设备在打开商品页时断开:{exc}",
) from exc
raise PddCollectError("DEVICE_APP_START_FAILED", f"无法打开 PDD 商品链接:{exc}") from exc raise PddCollectError("DEVICE_APP_START_FAILED", f"无法打开 PDD 商品链接:{exc}") from exc
deadline = self._monotonic() + self._page_timeout deadline = self._monotonic() + self._page_timeout
@@ -686,13 +788,14 @@ class PddCollectService:
for _ in range(self._max_page_swipes + 1): for _ in range(self._max_page_swipes + 1):
self._check_cancelled() self._check_cancelled()
xml_data = device.dump_hierarchy() xml_data = device.dump_hierarchy()
self._last_goods_xml = str(xml_data)
self._goods_screens_checked += 1
root = _parse_xml(xml_data) root = _parse_xml(xml_data)
labels = tuple(_all_labels(root)) labels = tuple(_all_labels(root))
snapshots.append(parse_goods_page(xml_data)) snapshots.append(parse_goods_page(xml_data))
combined = _combine_goods_snapshots(snapshots) combined = _combine_goods_snapshots(snapshots)
is_complete = ( is_complete = (
combined.title combined.title
and combined.shop_name
and combined.sales.raw and combined.sales.raw
and combined.reviews.raw and combined.reviews.raw
) )
@@ -720,6 +823,27 @@ class PddCollectService:
self._sleep(0.35) self._sleep(0.35)
return _combine_goods_snapshots(snapshots) return _combine_goods_snapshots(snapshots)
def _save_xml(self, label: str, xml_data: str) -> Optional[Mapping[str, Any]]:
"""保存本地诊断 XML;测试未提供目录时不写文件。"""
if self._artifact_directory is None:
return None
try:
digest = hashlib.sha256(xml_data.encode("utf-8")).hexdigest()
directory = self._artifact_directory / self._client_id
directory.mkdir(parents=True, exist_ok=True)
path = directory / f"{label}-{digest[:12]}.xml"
if not path.exists():
path.write_text(xml_data, encoding="utf-8")
return {
"kind": "accessibility_xml",
"path": str(path.resolve()),
"sha256": digest,
"screens_checked": self._goods_screens_checked,
}
except OSError:
return None
def _discover_dimensions(self, device: Any) -> list[SpecSnapshot]: def _discover_dimensions(self, device: Any) -> list[SpecSnapshot]:
snapshots: list[SpecSnapshot] = [] snapshots: list[SpecSnapshot] = []
@@ -768,28 +892,66 @@ class PddCollectService:
f"规格组合共 {len(combinations)} 个,超过安全上限 {self._max_sku_count}", f"规格组合共 {len(combinations)} 个,超过安全上限 {self._max_sku_count}",
) )
results: list[SkuResult] = [] color_index = next(
for values in combinations: (index for index, item in enumerate(dimensions) if item.key == "color"),
None,
)
if color_index is None:
raise PddCollectError(
"PDD_DATA_SPEC_INCOMPLETE", "规格面板没有可识别的颜色分类"
)
samples: dict[
str,
tuple[Optional[int], Optional[str], Optional[int], dict[str, str]],
] = {}
color_dimension = dimensions[color_index]
for color in color_dimension.values:
self._check_cancelled() self._check_cancelled()
options = {dimension.key: value.text for dimension, value in zip(dimensions, values)} if not color.available:
pairs = list(zip(dimensions, values)) samples[color.text] = (None, None, None, {"color": color.text})
selected = self._select_combination(device, pairs) continue
if not selected and len(pairs) > 1: selected = self._select_option(device, color.text, color_dimension.key)
# 某个选项可能只是在当前搭配下禁用。反向选择一次,可以先改变
# 依赖维度,再重新判断目标组合是否真的缺货。
selected = self._select_combination(device, list(reversed(pairs)))
if not selected: if not selected:
results.append(SkuResult(options, None, False, None)) samples[color.text] = (None, None, None, {"color": color.text})
continue continue
snapshot = parse_spec_panel(device.dump_hierarchy()) snapshot = parse_spec_panel(device.dump_hierarchy())
summary = snapshot.selected_text or "" summary = snapshot.selected_text or ""
confirmed = all(value.text in summary for value in values) observed: dict[str, str] = {}
for dimension in dimensions:
match = next(
(value.text for value in dimension.values if value.text in summary),
None,
)
if match:
observed[dimension.key] = match
confirmed = (
observed.get(color_dimension.key) == color.text
and len(observed) == len(dimensions)
)
samples[color.text] = (
snapshot.price_cent if confirmed else None,
snapshot.raw_price if confirmed else None,
snapshot.list_price_cent if confirmed else None,
observed,
)
results: list[SkuResult] = []
for values in combinations:
options = {
dimension.key: value.text
for dimension, value in zip(dimensions, values)
}
price, raw_price, list_price, observed = samples[values[color_index].text]
available = all(value.available for value in values) and price is not None
results.append( results.append(
SkuResult( SkuResult(
options, options,
snapshot.price_cent if confirmed else None, price if available else None,
confirmed and snapshot.price_cent is not None, available,
snapshot.raw_price if confirmed else None, raw_price if available else None,
observed,
list_price if available else None,
) )
) )
return tuple(results) return tuple(results)
@@ -864,7 +1026,7 @@ class PddCollectService:
] ]
screen_right = max(right_edges, default=0) screen_right = max(right_edges, default=0)
for node in root.iter("node"): for node in root.iter("node"):
if _own_or_descendant_label(node).strip() != target: if _preferred_or_descendant_label(node).strip() != target:
continue continue
bounds = _parse_bounds(node.get("bounds", "")) bounds = _parse_bounds(node.get("bounds", ""))
if node.get("clickable") != "true" or bounds is None: if node.get("clickable") != "true" or bounds is None:
+46 -46
View File
@@ -13,7 +13,7 @@
- 窗口关闭时要断开信号并置标志位,否则迟到的后台结果会访问 - 窗口关闭时要断开信号并置标志位,否则迟到的后台结果会访问
已经销毁的控件、直接崩溃。做法见同文档 §5.2。 已经销毁的控件、直接崩溃。做法见同文档 §5.2。
- 数据库读写走 Repository,**不要在这里拼业务 SQL**。 - 数据库读写走 Repository,**不要在这里拼业务 SQL**。
- “获取任务”会真的去操作手机、可能下单;“搜索”只读本地数据库。 - “获取任务”会真的去操作手机采集商品;“搜索”只读本地数据库。
两者必须分开,不得共用入口。 两者必须分开,不得共用入口。
- 普通成功不弹窗,更新界面即可;可恢复错误用 `InfoBar` - 普通成功不弹窗,更新界面即可;可恢复错误用 `InfoBar`
(模板见 `docs/client/05-ui-specification.md` §9.1); (模板见 `docs/client/05-ui-specification.md` §9.1);
@@ -28,11 +28,10 @@ from qfluentwidgets import InfoBar, InfoBarPosition
from .admin_gateway import ( from .admin_gateway import (
AdminGatewayError, AdminGatewayError,
AdminTask, AdminTask,
AndroidDeviceInfo,
ClaimCapabilities,
ClientInfo, ClientInfo,
TaskClaimGateway, AdminGateway,
) )
from .collect_task_service import CollectServiceFactory, CollectTaskService
from .current_client_service import CurrentClientService from .current_client_service import CurrentClientService
from .http_admin_gateway import DEFAULT_ADMIN_BASE_URL, HttpAdminGateway from .http_admin_gateway import DEFAULT_ADMIN_BASE_URL, HttpAdminGateway
from .pdd_ui import PDDTaskPage, TaskRow from .pdd_ui import PDDTaskPage, TaskRow
@@ -45,7 +44,7 @@ from .task_models import (
TaskSummary, TaskSummary,
TaskType, TaskType,
) )
from .task_repository import DuplicateTaskError, TaskRepository from .task_repository import TaskRepository
TASK_TYPE_BY_TEXT = { TASK_TYPE_BY_TEXT = {
@@ -116,21 +115,23 @@ def admin_task_to_new_claimed_task(task: AdminTask) -> NewClaimedTask:
class ClaimTaskWorker(QObject): class ClaimTaskWorker(QObject):
"""在后台领取至多一个采集任务,并先写入本地数据库。""" """在后台补交或执行至多一条采集任务。"""
noTask = pyqtSignal() noTask = pyqtSignal()
taskSaved = pyqtSignal(str) taskSaved = pyqtSignal(str)
duplicateTask = pyqtSignal(str) duplicateTask = pyqtSignal(str)
localSaveFailed = pyqtSignal(str, str) localSaveFailed = pyqtSignal(str, str)
failed = pyqtSignal(str) failed = pyqtSignal(str)
outcome = pyqtSignal(str, str, str)
completed = pyqtSignal() completed = pyqtSignal()
def __init__( def __init__(
self, self,
gateway: TaskClaimGateway, gateway: AdminGateway,
task_repository: TaskRepository, task_repository: TaskRepository,
client_service: CurrentClientService, client_service: CurrentClientService,
android_device_service: SelectedAndroidDeviceService, android_device_service: SelectedAndroidDeviceService,
collect_service_factory: Optional[CollectServiceFactory] = None,
) -> None: ) -> None:
super().__init__() super().__init__()
self._gateway = gateway self._gateway = gateway
@@ -138,6 +139,7 @@ class ClaimTaskWorker(QObject):
self._client_service = client_service self._client_service = client_service
self._android_device_service = android_device_service self._android_device_service = android_device_service
self._cancelled = False self._cancelled = False
self._collect_service_factory = collect_service_factory
def cancel(self) -> None: def cancel(self) -> None:
"""阻止尚未开始的领取;已领取的任务仍必须保存到本地。""" """阻止尚未开始的领取;已领取的任务仍必须保存到本地。"""
@@ -146,7 +148,6 @@ class ClaimTaskWorker(QObject):
@pyqtSlot() @pyqtSlot()
def run(self) -> None: def run(self) -> None:
claimed_task: Optional[AdminTask] = None
try: try:
if self._cancelled: if self._cancelled:
return return
@@ -155,42 +156,20 @@ class ClaimTaskWorker(QObject):
self.failed.emit("请先在设置页保存当前设备号和设备名") self.failed.emit("请先在设置页保存当前设备号和设备名")
return return
android_serial = self._android_device_service.load() android_serial = self._android_device_service.load()
if not android_serial:
self.failed.emit("请先在设置页选择并保存 Android 设备")
return
capabilities = ClaimCapabilities( result = CollectTaskService(
device=AndroidDeviceInfo(android_serial), self._gateway,
supported_types=(TaskType.COLLECT,), self._task_repository,
purchase_mode="dry_run",
schema_versions=(1,),
)
claimed_task = self._gateway.claim_next(
ClientInfo( ClientInfo(
client_settings.client_id, client_settings.client_id,
client_settings.client_name, client_settings.client_name,
), ),
capabilities, android_serial or "",
) cancelled=lambda: self._cancelled,
if claimed_task is None: collect_service_factory=self._collect_service_factory,
if not self._cancelled: ).execute_one()
self.noTask.emit() if not self._cancelled or result.kind == "cancelled":
return self.outcome.emit(result.kind, result.message, result.task_id)
local_task = admin_task_to_new_claimed_task(claimed_task)
try:
self._task_repository.add_claimed_task(local_task)
except DuplicateTaskError:
if not self._cancelled:
self.duplicateTask.emit(claimed_task.task_id)
return
except Exception as exc:
if not self._cancelled:
self.localSaveFailed.emit(claimed_task.task_id, str(exc))
return
if not self._cancelled:
self.taskSaved.emit(claimed_task.task_id)
except AdminGatewayError as exc: except AdminGatewayError as exc:
if not self._cancelled: if not self._cancelled:
request_hint = ( request_hint = (
@@ -199,10 +178,7 @@ class ClaimTaskWorker(QObject):
self.failed.emit(f"{exc}{request_hint}") self.failed.emit(f"{exc}{request_hint}")
except Exception as exc: except Exception as exc:
if not self._cancelled: if not self._cancelled:
if claimed_task is not None: self.failed.emit(f"执行采集任务失败:{exc}")
self.localSaveFailed.emit(claimed_task.task_id, str(exc))
else:
self.failed.emit(f"领取任务失败:{exc}")
finally: finally:
self.completed.emit() self.completed.emit()
@@ -215,8 +191,9 @@ class PDDTaskPageEvent(QObject):
page: PDDTaskPage, page: PDDTaskPage,
repository: Optional[TaskRepository] = None, repository: Optional[TaskRepository] = None,
parent=None, parent=None,
claim_gateway: Optional[TaskClaimGateway] = None, claim_gateway: Optional[AdminGateway] = None,
settings_repository: Optional[SettingsRepository] = None, settings_repository: Optional[SettingsRepository] = None,
collect_service_factory: Optional[CollectServiceFactory] = None,
): ):
super().__init__(parent or page) super().__init__(parent or page)
self._page = page self._page = page
@@ -226,6 +203,13 @@ class PDDTaskPageEvent(QObject):
self._claim_busy = False self._claim_busy = False
self._claim_thread: Optional[QThread] = None self._claim_thread: Optional[QThread] = None
self._claim_worker: Optional[ClaimTaskWorker] = None self._claim_worker: Optional[ClaimTaskWorker] = None
self._collect_service_factory = collect_service_factory
try:
self._repository.recover_interrupted_work()
except AttributeError:
# 测试用的只读 Repository 可以不实现恢复接口。
pass
settings = settings_repository or SettingsRepository() settings = settings_repository or SettingsRepository()
self._client_service = CurrentClientService(settings) self._client_service = CurrentClientService(settings)
@@ -242,6 +226,7 @@ class PDDTaskPageEvent(QObject):
self._claim_gateway = HttpAdminGateway( self._claim_gateway = HttpAdminGateway(
base_url if isinstance(base_url, str) else "", base_url if isinstance(base_url, str) else "",
timeout_seconds=timeout_seconds, timeout_seconds=timeout_seconds,
client_id=self._client_service.load().client_id,
) )
except (TypeError, ValueError) as exc: except (TypeError, ValueError) as exc:
self._claim_gateway_error = str(exc) self._claim_gateway_error = str(exc)
@@ -290,7 +275,7 @@ class PDDTaskPageEvent(QObject):
self._claim_busy = True self._claim_busy = True
self._page.autoFetchButton.setEnabled(False) self._page.autoFetchButton.setEnabled(False)
self._page.set_engine_status("正在领取一个采集任务,请稍候…") self._page.set_engine_status("正在处理一条采集任务,请稍候…")
thread = QThread(self) thread = QThread(self)
worker = ClaimTaskWorker( worker = ClaimTaskWorker(
@@ -298,6 +283,7 @@ class PDDTaskPageEvent(QObject):
self._repository, self._repository,
self._client_service, self._client_service,
self._selected_android_device_service, self._selected_android_device_service,
self._collect_service_factory,
) )
worker.moveToThread(thread) worker.moveToThread(thread)
thread.started.connect(worker.run) thread.started.connect(worker.run)
@@ -306,6 +292,7 @@ class PDDTaskPageEvent(QObject):
worker.duplicateTask.connect(self._on_duplicate_claimed_task) worker.duplicateTask.connect(self._on_duplicate_claimed_task)
worker.localSaveFailed.connect(self._on_claimed_task_save_failed) worker.localSaveFailed.connect(self._on_claimed_task_save_failed)
worker.failed.connect(self._on_claim_failed) worker.failed.connect(self._on_claim_failed)
worker.outcome.connect(self._on_collect_outcome)
worker.completed.connect(thread.quit) worker.completed.connect(thread.quit)
worker.completed.connect(worker.deleteLater) worker.completed.connect(worker.deleteLater)
thread.finished.connect(thread.deleteLater) thread.finished.connect(thread.deleteLater)
@@ -352,6 +339,15 @@ class PDDTaskPageEvent(QObject):
self._page.set_engine_status(content) self._page.set_engine_status(content)
self._show_claim_error("领取任务失败", content) self._show_claim_error("领取任务失败", content)
@pyqtSlot(str, str, str)
def _on_collect_outcome(self, kind: str, message: str, _task_id: str) -> None:
if self._closing:
return
self._page.set_engine_status(message)
self._reload()
if kind in {"result_pending", "manual_review", "failed"}:
self._show_claim_error("采集任务需要处理", message)
def _show_claim_error(self, title: str, content: str) -> None: def _show_claim_error(self, title: str, content: str) -> None:
"""显示不会自动消失的可恢复错误,同时保留底部状态文字。""" """显示不会自动消失的可恢复错误,同时保留底部状态文字。"""
@@ -413,6 +409,7 @@ class PDDTaskPageEvent(QObject):
self._on_claimed_task_save_failed, self._on_claimed_task_save_failed,
), ),
(worker.failed, self._on_claim_failed), (worker.failed, self._on_claim_failed),
(worker.outcome, self._on_collect_outcome),
) )
except RuntimeError: except RuntimeError:
signal_slots = () signal_slots = ()
@@ -424,7 +421,10 @@ class PDDTaskPageEvent(QObject):
if thread is not None and thread.isRunning(): if thread is not None and thread.isRunning():
thread.quit() thread.quit()
thread.wait(10_000) # uiautomator2/ADB 的单次调用可能需要数秒才返回。先通过
# cancelled 标志让采集在下一个安全点退出,再等待工作线程收尾,
# 避免窗口销毁时出现 "QThread destroyed while running"。
thread.wait(60_000)
def summary_to_row(summary: TaskSummary) -> TaskRow: def summary_to_row(summary: TaskSummary) -> TaskRow:
+9
View File
@@ -184,6 +184,15 @@ class OutboxEventRecord:
sent_at: Optional[str] sent_at: Optional[str]
@dataclass(frozen=True)
class StartedTaskRun:
"""已进入执行状态的一次采集尝试。"""
task: TaskDetail
attempt_id: str
attempt_no: int
@dataclass(frozen=True) @dataclass(frozen=True)
class AppSettingRecord: class AppSettingRecord:
"""一条非敏感应用设置。""" """一条非敏感应用设置。"""
+353
View File
@@ -8,10 +8,16 @@ import sqlite3
from datetime import datetime, timezone from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from typing import Dict, List, Optional, Tuple, Union from typing import Dict, List, Optional, Tuple, Union
from uuid import uuid4
from .db import initialize_database, open_database from .db import initialize_database, open_database
from .task_models import ( from .task_models import (
NewClaimedTask, NewClaimedTask,
OutboxEventRecord,
OutboxEventType,
OutboxStatus,
RunStatus,
StartedTaskRun,
TaskDetail, TaskDetail,
TaskFilters, TaskFilters,
TaskStatus, TaskStatus,
@@ -145,6 +151,353 @@ class TaskRepository:
connection.close() connection.close()
return self._to_detail(row) if row is not None else None return self._to_detail(row) if row is not None else None
def recover_interrupted_work(self) -> None:
"""恢复上次异常退出留下的可重试状态。"""
now = utc_now_iso()
connection = open_database(self._db_path)
try:
with connection:
connection.execute(
"UPDATE outbox_events SET status = 'pending', updated_at = ?"
" WHERE status = 'sending'",
(now,),
)
connection.execute(
"UPDATE pdd_tasks SET status = 'retry_wait',"
" current_step = 'interrupted', retry_count = retry_count + 1,"
" last_error_code = 'CLIENT_INTERRUPTED',"
" last_error_message = '客户端上次执行期间退出', updated_at = ?"
" WHERE status = 'running' AND task_type = 'collect'",
(now,),
)
connection.execute(
"UPDATE task_runs SET run_status = 'failed',"
" error_code = 'CLIENT_INTERRUPTED',"
" error_message = '客户端上次执行期间退出',"
" finished_at = ?, updated_at = ?"
" WHERE run_status = 'running' AND irreversible_action_at IS NULL"
" AND task_id IN (SELECT id FROM pdd_tasks WHERE task_type = 'collect')",
(now, now),
)
finally:
connection.close()
def next_collect_task(self) -> Optional[TaskDetail]:
"""返回最早的本地待执行采集任务。"""
connection = open_database(self._db_path)
try:
row = connection.execute(
"SELECT * FROM pdd_tasks"
" WHERE task_type = 'collect' AND status IN ('claimed', 'retry_wait')"
" ORDER BY received_at ASC, id ASC LIMIT 1"
).fetchone()
finally:
connection.close()
return self._to_detail(row) if row is not None else None
def start_collect_run(
self, remote_task_id: str, device_address: str
) -> StartedTaskRun:
"""原子地把待执行任务改为执行中,并创建一次运行记录。"""
now = utc_now_iso()
attempt_id = str(uuid4())
connection = open_database(self._db_path)
try:
with connection:
row = connection.execute(
"SELECT * FROM pdd_tasks WHERE remote_task_id = ?",
(remote_task_id,),
).fetchone()
if row is None:
raise ValueError(f"任务 {remote_task_id} 不存在")
if row["task_type"] != TaskType.COLLECT.value:
raise ValueError("当前只能执行采集任务")
if row["status"] not in {
TaskStatus.CLAIMED.value,
TaskStatus.RETRY_WAIT.value,
}:
raise ValueError(f"任务状态 {row['status']} 不能开始采集")
attempt_no = int(
connection.execute(
"SELECT COALESCE(MAX(attempt_no), 0) + 1"
" FROM task_runs WHERE task_id = ?",
(row["id"],),
).fetchone()[0]
)
connection.execute(
"UPDATE pdd_tasks SET status = 'running',"
" current_step = 'collecting', started_at = COALESCE(started_at, ?),"
" last_error_code = NULL, last_error_message = NULL, updated_at = ?"
" WHERE id = ?",
(now, now, row["id"]),
)
connection.execute(
"INSERT INTO task_runs (task_id, attempt_id, attempt_no,"
" device_address, run_status, current_step, started_at,"
" created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
row["id"], attempt_id, attempt_no, device_address,
RunStatus.RUNNING.value, "collecting", now, now, now,
),
)
task = self.get_task(remote_task_id)
assert task is not None
return StartedTaskRun(task, attempt_id, attempt_no)
finally:
connection.close()
def save_collect_result(
self,
remote_task_id: str,
attempt_id: str,
pdd_data: Dict[str, object],
) -> OutboxEventRecord:
"""在一个事务中保存采集结果并创建待提交事件。"""
now = utc_now_iso()
connection = open_database(self._db_path)
try:
with connection:
task = connection.execute(
"SELECT id, version FROM pdd_tasks WHERE remote_task_id = ?",
(remote_task_id,),
).fetchone()
if task is None:
raise ValueError(f"任务 {remote_task_id} 不存在")
payload = {
"task_version": task["version"],
"attempt_id": attempt_id,
"result_type": "collect",
"completed_at": now,
"pdd_data": pdd_data,
}
idempotency_key = f"{remote_task_id}:{attempt_id}:result-v1"
connection.execute(
"UPDATE pdd_tasks SET status = 'result_pending',"
" current_step = 'submit_result', pdd_data = ?, goods_id = ?,"
" title = ?, price_cent = ?, finished_at = ?, updated_at = ?"
" WHERE id = ?",
(
json.dumps(pdd_data, ensure_ascii=False),
pdd_data.get("goods_id"), pdd_data.get("title"),
self._summary_price(pdd_data), now, now, task["id"],
),
)
connection.execute(
"UPDATE task_runs SET run_status = 'succeeded',"
" current_step = 'submit_result', finished_at = ?, updated_at = ?"
" WHERE attempt_id = ?",
(now, now, attempt_id),
)
cursor = connection.execute(
"INSERT INTO outbox_events (task_id, event_type, idempotency_key,"
" payload_json, status, created_at, updated_at)"
" VALUES (?, 'collect_result', ?, ?, 'pending', ?, ?)",
(
task["id"], idempotency_key,
json.dumps(payload, ensure_ascii=False), now, now,
),
)
event_id = int(cursor.lastrowid)
event = self.get_outbox_event(event_id)
assert event is not None
return event
finally:
connection.close()
def save_collect_failure(
self,
remote_task_id: str,
attempt_id: str,
status: TaskStatus,
error_code: str,
error_message: str,
retryable: bool,
diagnostics: Optional[Dict[str, object]] = None,
) -> OutboxEventRecord:
"""保存结构化失败,并可靠排队提交 Admin。"""
if status not in {
TaskStatus.RETRY_WAIT, TaskStatus.MANUAL_REVIEW,
TaskStatus.FAILED, TaskStatus.CANCELLED,
}:
raise ValueError("失败状态无效")
now = utc_now_iso()
connection = open_database(self._db_path)
try:
with connection:
task = connection.execute(
"SELECT id, version FROM pdd_tasks WHERE remote_task_id = ?",
(remote_task_id,),
).fetchone()
if task is None:
raise ValueError(f"任务 {remote_task_id} 不存在")
payload = {
"task_version": task["version"],
"attempt_id": attempt_id,
"status": status.value,
"error": {
"code": error_code,
"message": error_message,
"retryable": retryable,
"step": "collecting",
},
"diagnostics": diagnostics or {"artifacts": []},
"reported_at": now,
}
idempotency_key = f"{remote_task_id}:{attempt_id}:failure-v1"
connection.execute(
"UPDATE pdd_tasks SET status = ?, current_step = 'failed',"
" retry_count = retry_count + ?, last_error_code = ?,"
" last_error_message = ?, finished_at = ?, updated_at = ?"
" WHERE id = ?",
(
status.value, 1 if status is TaskStatus.RETRY_WAIT else 0,
error_code, error_message, now, now, task["id"],
),
)
run_status = {
TaskStatus.CANCELLED: RunStatus.CANCELLED,
TaskStatus.MANUAL_REVIEW: RunStatus.MANUAL_REVIEW,
}.get(status, RunStatus.FAILED)
connection.execute(
"UPDATE task_runs SET run_status = ?, current_step = 'failed',"
" error_code = ?, error_message = ?, finished_at = ?, updated_at = ?"
" WHERE attempt_id = ?",
(run_status.value, error_code, error_message, now, now, attempt_id),
)
cursor = connection.execute(
"INSERT INTO outbox_events (task_id, event_type, idempotency_key,"
" payload_json, status, created_at, updated_at)"
" VALUES (?, 'task_failure', ?, ?, 'pending', ?, ?)",
(
task["id"], idempotency_key,
json.dumps(payload, ensure_ascii=False), now, now,
),
)
event_id = int(cursor.lastrowid)
event = self.get_outbox_event(event_id)
assert event is not None
return event
finally:
connection.close()
def next_pending_outbox(self) -> Optional[OutboxEventRecord]:
connection = open_database(self._db_path)
try:
row = connection.execute(
"SELECT o.* FROM outbox_events o JOIN pdd_tasks t ON t.id = o.task_id"
" WHERE o.status = 'pending'"
" AND (o.next_retry_at IS NULL OR o.next_retry_at <= ?)"
" ORDER BY o.id ASC LIMIT 1",
(utc_now_iso(),),
).fetchone()
finally:
connection.close()
return self._to_outbox(row) if row is not None else None
def get_outbox_event(self, event_id: int) -> Optional[OutboxEventRecord]:
connection = open_database(self._db_path)
try:
row = connection.execute(
"SELECT * FROM outbox_events WHERE id = ?", (event_id,)
).fetchone()
finally:
connection.close()
return self._to_outbox(row) if row is not None else None
def outbox_task_id(self, event_id: int) -> str:
connection = open_database(self._db_path)
try:
row = connection.execute(
"SELECT t.remote_task_id FROM outbox_events o"
" JOIN pdd_tasks t ON t.id = o.task_id WHERE o.id = ?",
(event_id,),
).fetchone()
finally:
connection.close()
if row is None:
raise ValueError(f"Outbox {event_id} 不存在")
return str(row[0])
def mark_outbox_sending(self, event_id: int) -> None:
self._update_outbox(event_id, "sending", None)
def mark_outbox_retry(self, event_id: int, message: str) -> None:
self._update_outbox(event_id, "pending", message, increment=True)
def mark_outbox_failed(self, event_id: int, message: str) -> None:
self._update_outbox(event_id, "failed", message, increment=True)
def mark_outbox_sent(self, event_id: int) -> None:
now = utc_now_iso()
connection = open_database(self._db_path)
try:
with connection:
row = connection.execute(
"SELECT task_id, event_type FROM outbox_events WHERE id = ?",
(event_id,),
).fetchone()
if row is None:
raise ValueError(f"Outbox {event_id} 不存在")
connection.execute(
"UPDATE outbox_events SET status = 'sent', sent_at = ?,"
" updated_at = ?, attempt_count = attempt_count + 1"
" WHERE id = ?",
(now, now, event_id),
)
if row["event_type"] == OutboxEventType.COLLECT_RESULT.value:
connection.execute(
"UPDATE pdd_tasks SET status = 'succeeded',"
" current_step = 'completed', updated_at = ? WHERE id = ?",
(now, row["task_id"]),
)
finally:
connection.close()
def _update_outbox(
self, event_id: int, status: str, message: Optional[str], increment: bool = False
) -> None:
connection = open_database(self._db_path)
try:
with connection:
cursor = connection.execute(
"UPDATE outbox_events SET status = ?, last_error = ?, updated_at = ?,"
f" attempt_count = attempt_count + {1 if increment else 0} WHERE id = ?",
(status, message, utc_now_iso(), event_id),
)
if cursor.rowcount != 1:
raise ValueError(f"Outbox {event_id} 不存在")
finally:
connection.close()
@staticmethod
def _summary_price(pdd_data: Dict[str, object]) -> Optional[int]:
skus = pdd_data.get("skus")
if not isinstance(skus, list):
return None
prices = [
item.get("price_cent") for item in skus
if isinstance(item, dict) and isinstance(item.get("price_cent"), int)
]
return min(prices) if prices else None
@staticmethod
def _to_outbox(row: sqlite3.Row) -> OutboxEventRecord:
return OutboxEventRecord(
id=row["id"], task_id=row["task_id"],
event_type=OutboxEventType(row["event_type"]),
idempotency_key=row["idempotency_key"],
payload_json=TaskRepository._load_json_object(row["payload_json"]),
status=OutboxStatus(row["status"]), attempt_count=row["attempt_count"],
next_retry_at=row["next_retry_at"], last_error=row["last_error"],
created_at=row["created_at"], updated_at=row["updated_at"],
sent_at=row["sent_at"],
)
@staticmethod @staticmethod
def _validate_page(limit: int, offset: int) -> None: def _validate_page(limit: int, offset: int) -> None:
if not 1 <= limit <= MAX_PAGE_SIZE: if not 1 <= limit <= MAX_PAGE_SIZE:
+164
View File
@@ -0,0 +1,164 @@
"""采集任务应用流程测试,不连接真机和网络。"""
import tempfile
import unittest
from pathlib import Path
from src.admin_gateway import AdminTask, ClaimCapabilities, ClientInfo
from src.collect_task_service import CollectTaskService
from src.mock_admin_gateway import MockAdminGateway
from src.pdd_collect_service import PddCollectError
from src.task_models import NewClaimedTask, TaskStatus, TaskType
from src.task_repository import TaskRepository
class FakeResult:
def to_pdd_data(self):
return {
"schema_version": 1,
"goods_id": "737116531267",
"title": "测试商品",
"shop_name": "测试店铺",
"price_granularity": "color",
"dimensions": [
{"key": "color", "name": "颜色分类"},
{"key": "size", "name": "尺码"},
],
"skus": [
{
"options": {"color": "黑色", "size": "M"},
"price_cent": 990,
"price_observed_at": {"color": "黑色", "size": "M"},
"available": True,
}
],
}
class FakeCollector:
def __init__(self, calls, error=None):
self.calls = calls
self.error = error
def collect(self, task):
self.calls.append(task.remote_task_id)
if self.error is not None:
raise self.error
return FakeResult()
class CollectTaskServiceTest(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.repository = TaskRepository(Path(self.temporary.name) / "client.db")
self.gateway = MockAdminGateway()
self.client = ClientInfo("CLIENT-001", "测试电脑")
self.task = AdminTask(
task_id="COL-001",
task_type=TaskType.COLLECT,
version=1,
priority=0,
payload={
"goods_id": "737116531267",
"goods_url": "https://mobile.yangkeduo.com/goods.html?goods_id=737116531267",
},
created_at="2026-08-07T08:00:00Z",
updated_at="2026-08-07T08:00:00Z",
)
self.gateway.enqueue_task(self.task, self.client.client_id)
def tearDown(self):
self.temporary.cleanup()
def _service(self, calls, error=None):
return CollectTaskService(
self.gateway,
self.repository,
self.client,
"USB-001",
collect_service_factory=lambda *_args: FakeCollector(calls, error),
)
def test_claim_collect_persist_submit_completes_one_task(self):
calls = []
outcome = self._service(calls).execute_one()
self.assertEqual(outcome.kind, "succeeded")
self.assertEqual(calls, ["COL-001"])
detail = self.repository.get_task("COL-001")
self.assertEqual(detail.status, TaskStatus.SUCCEEDED)
self.assertEqual(detail.pdd_data["price_granularity"], "color")
self.assertEqual(self.gateway.submission_count, 1)
def test_submit_timeout_retries_stored_outbox_without_recollecting(self):
remote = self.gateway.claim_next(
self.client,
ClaimCapabilities(supported_types=(TaskType.COLLECT,)),
)
self.repository.add_claimed_task(
NewClaimedTask(
remote_task_id=remote.task_id,
task_type=remote.task_type,
goods_url=remote.payload["goods_url"],
goods_id=remote.payload["goods_id"],
version=remote.version,
admin_payload={"payload": dict(remote.payload)},
)
)
calls = []
self.gateway.timeout_next_call()
first = self._service(calls).execute_one()
second = self._service(calls).execute_one()
self.assertEqual(first.kind, "result_pending")
self.assertEqual(second.kind, "succeeded")
self.assertEqual(calls, ["COL-001"])
self.assertEqual(self.gateway.submission_count, 1)
def test_pending_outbox_can_submit_without_android_device(self):
remote = self.gateway.claim_next(
self.client,
ClaimCapabilities(supported_types=(TaskType.COLLECT,)),
)
self.repository.add_claimed_task(
NewClaimedTask(
remote_task_id=remote.task_id,
task_type=remote.task_type,
goods_url=remote.payload["goods_url"],
goods_id=remote.payload["goods_id"],
version=remote.version,
)
)
started = self.repository.start_collect_run(remote.task_id, "USB-001")
self.repository.save_collect_result(
remote.task_id, started.attempt_id, FakeResult().to_pdd_data()
)
outcome = CollectTaskService(
self.gateway, self.repository, self.client, ""
).execute_one()
self.assertEqual(outcome.kind, "succeeded")
self.assertEqual(
self.repository.get_task(remote.task_id).status,
TaskStatus.SUCCEEDED,
)
def test_captcha_becomes_manual_review_and_is_reported(self):
calls = []
outcome = self._service(
calls, PddCollectError("PDD_PAGE_CAPTCHA", "需要验证")
).execute_one()
self.assertEqual(outcome.kind, "failed")
self.assertEqual(
self.repository.get_task("COL-001").status,
TaskStatus.MANUAL_REVIEW,
)
self.assertEqual(self.gateway.submission_count, 1)
if __name__ == "__main__":
unittest.main()
+66 -1
View File
@@ -104,7 +104,7 @@ class HttpAdminGatewayTest(unittest.TestCase):
}, },
) )
) )
gateway = HttpAdminGateway(opener=opener) gateway = HttpAdminGateway(opener=opener, client_id="CLIENT-001")
gateway.register_client( gateway.register_client(
ClientInfo("CLIENT-001"), self._capabilities(False) ClientInfo("CLIENT-001"), self._capabilities(False)
@@ -116,6 +116,71 @@ class HttpAdminGatewayTest(unittest.TestCase):
key.lower(): value for key, value in opener.request.header_items() key.lower(): value for key, value in opener.request.header_items()
}) })
def test_submit_result_sends_idempotency_key_and_parses_receipt(self):
opener = RecordingOpener(
FakeResponse(
200,
{
"accepted": True,
"result_id": "RESULT-001",
"accepted_at": "2026-08-07T08:00:01Z",
},
)
)
gateway = HttpAdminGateway(opener=opener, client_id="CLIENT-001")
payload = {
"task_version": 1,
"attempt_id": "ATTEMPT-001",
"result_type": "collect",
"completed_at": "2026-08-07T08:00:00Z",
"pdd_data": {"goods_id": "123"},
}
receipt = gateway.submit_result(
"COL-001", "COL-001:ATTEMPT-001:result-v1", payload
)
self.assertTrue(receipt.accepted)
self.assertEqual(
opener.request.full_url,
"http://127.0.0.1:8080/api/v1/client/tasks/COL-001/result",
)
headers = {
key.lower(): value for key, value in opener.request.header_items()
}
self.assertEqual(
headers["idempotency-key"], "COL-001:ATTEMPT-001:result-v1"
)
self.assertEqual(headers["x-client-id"], "CLIENT-001")
self.assertEqual(json.loads(opener.request.data), payload)
def test_submit_failure_uses_failure_endpoint(self):
opener = RecordingOpener(
FakeResponse(
201,
{
"accepted": True,
"result_id": "FAILURE-001",
"accepted_at": "2026-08-07T08:00:01Z",
},
)
)
gateway = HttpAdminGateway(opener=opener, client_id="CLIENT-001")
gateway.submit_failure(
"COL-001",
"COL-001:ATTEMPT-001:failure-v1",
{
"task_version": 1,
"attempt_id": "ATTEMPT-001",
"status": "manual_review",
"error": {"code": "PDD_PAGE_CAPTCHA"},
"reported_at": "2026-08-07T08:00:00Z",
},
)
self.assertTrue(opener.request.full_url.endswith("/COL-001/failure"))
def test_claim_maps_real_admin_payload_and_only_reports_collect(self): def test_claim_maps_real_admin_payload_and_only_reports_collect(self):
opener = RecordingOpener( opener = RecordingOpener(
FakeResponse( FakeResponse(
+78 -8
View File
@@ -62,6 +62,18 @@ class LoadingDevice(FakeCollectDevice):
return '<hierarchy><node text="正在加载" /></hierarchy>' return '<hierarchy><node text="正在加载" /></hierarchy>'
class DisconnectingDevice(FakeCollectDevice):
def __init__(self, home_xml, spec_xml):
super().__init__(home_xml, spec_xml)
self.current_calls = 0
def app_current(self):
self.current_calls += 1
if self.current_calls > 1:
raise RuntimeError("device not found")
return super().app_current()
def keep_only_one_sku(xml_data: str) -> str: def keep_only_one_sku(xml_data: str) -> str:
"""从脱敏固件中删除蓝色和 L,只保留一个组合。""" """从脱敏固件中删除蓝色和 L,只保留一个组合。"""
@@ -114,6 +126,19 @@ class PddCollectParserTest(unittest.TestCase):
["M", "L"], ["M", "L"],
) )
def test_truncated_spec_name_prefers_full_content_description(self):
xml_data = self.spec_xml.replace(
'content-desc="红色" clickable="true"',
'text="红…" content-desc="红色" clickable="true"',
)
result = parse_spec_panel(xml_data)
self.assertEqual(result.dimensions[0].values[0].text, "红色")
without_description = xml_data.replace(' content-desc="红色"', "")
with self.assertRaises(PddCollectError) as raised:
parse_spec_panel(without_description)
self.assertEqual(raised.exception.code, "PDD_DATA_SKU_NAME_TRUNCATED")
def test_login_and_invalid_xml_have_different_error_codes(self): def test_login_and_invalid_xml_have_different_error_codes(self):
with self.assertRaises(PddCollectError) as login: with self.assertRaises(PddCollectError) as login:
parse_goods_page('<hierarchy><node text="手机号登录" /></hierarchy>') parse_goods_page('<hierarchy><node text="手机号登录" /></hierarchy>')
@@ -150,14 +175,46 @@ class PddCollectParserTest(unittest.TestCase):
data = result.to_pdd_data() data = result.to_pdd_data()
self.assertEqual(data["schema_version"], 1) self.assertEqual(data["schema_version"], 1)
self.assertEqual(data["goods"]["goods_id"], "123") self.assertEqual(data["goods_id"], "123")
self.assertEqual(data["title"], "测试纯棉短袖商品")
self.assertEqual(data["shop_name"], "测试服饰旗舰店")
self.assertEqual(data["price_granularity"], "color")
self.assertEqual(data["metrics"]["sales"]["value"], 12000) self.assertEqual(data["metrics"]["sales"]["value"], 12000)
self.assertEqual(data["dimensions"][0]["key"], "color") self.assertEqual(data["dimensions"][0]["key"], "color")
self.assertEqual(data["skus"][0]["options"], {"color": "红色", "size": "M"}) self.assertEqual(data["skus"][0]["options"], {"color": "红色", "size": "M"})
self.assertEqual(data["skus"][0]["price_cent"], 1000) self.assertEqual(data["skus"][0]["price_cent"], 1000)
self.assertEqual(
data["skus"][0]["price_observed_at"],
{"color": "红色", "size": "M"},
)
self.assertEqual(data["source"]["device_address"], "USB-001") self.assertEqual(data["source"]["device_address"], "USB-001")
self.assertIsNone(data["purchase"]) self.assertIsNone(data["purchase"])
def test_price_is_sampled_once_per_available_color(self):
device = FakeCollectDevice(self.home_xml, self.spec_xml)
service = PddCollectService(
PddDeviceService(lambda _serial: device),
"USB-001",
"client-001",
sleeper=lambda _seconds: None,
max_page_swipes=0,
max_spec_swipes=0,
)
data = service.collect(
FakeTask("https://mobile.yangkeduo.com/goods.html?goods_id=123")
).to_pdd_data()
self.assertEqual(len(data["skus"]), 4)
red_skus = [
item for item in data["skus"] if item["options"]["color"] == "红色"
]
self.assertEqual(
{item["price_observed_at"]["size"] for item in red_skus}, {"M"}
)
# 1 次打开规格面板,另有红色点 1 次;尺码只读不点击。
self.assertEqual(len(device.clicks), 2)
def test_missing_goods_id_is_structured_error(self): def test_missing_goods_id_is_structured_error(self):
service = PddCollectService( service = PddCollectService(
PddDeviceService(lambda _serial: object()), PddDeviceService(lambda _serial: object()),
@@ -195,7 +252,7 @@ class PddCollectParserTest(unittest.TestCase):
def test_page_timeout_has_specific_error_code(self): def test_page_timeout_has_specific_error_code(self):
device = LoadingDevice(self.home_xml, self.spec_xml) device = LoadingDevice(self.home_xml, self.spec_xml)
ticks = iter((0.0, 2.0)) ticks = iter((0.0, 0.0, 0.0, 2.0))
service = PddCollectService( service = PddCollectService(
PddDeviceService(lambda _serial: device), PddDeviceService(lambda _serial: device),
"USB-001", "USB-001",
@@ -211,7 +268,21 @@ class PddCollectParserTest(unittest.TestCase):
) )
self.assertEqual(raised.exception.code, "PDD_PAGE_TIMEOUT") self.assertEqual(raised.exception.code, "PDD_PAGE_TIMEOUT")
def test_incomplete_goods_data_does_not_return_partial_success(self): def test_runtime_device_disconnect_has_stable_error_code(self):
service = PddCollectService(
PddDeviceService(
lambda _serial: DisconnectingDevice(self.home_xml, self.spec_xml)
),
"USB-001",
"client-001",
)
with self.assertRaises(PddCollectError) as raised:
service.collect(
FakeTask("https://mobile.yangkeduo.com/goods.html?goods_id=123")
)
self.assertEqual(raised.exception.code, "DEVICE_DISCONNECTED")
def test_missing_shop_name_is_allowed(self):
incomplete_home = self.home_xml.replace( incomplete_home = self.home_xml.replace(
'<node class="android.widget.TextView" text="店铺:测试服饰旗舰店" ' '<node class="android.widget.TextView" text="店铺:测试服饰旗舰店" '
'bounds="[30,1050][600,1110]" visible-to-user="true" ' 'bounds="[30,1050][600,1110]" visible-to-user="true" '
@@ -227,11 +298,10 @@ class PddCollectParserTest(unittest.TestCase):
max_page_swipes=0, max_page_swipes=0,
) )
with self.assertRaises(PddCollectError) as raised: result = service.collect(
service.collect( FakeTask("https://mobile.yangkeduo.com/goods.html?goods_id=123")
FakeTask("https://mobile.yangkeduo.com/goods.html?goods_id=123") )
) self.assertIsNone(result.shop_name)
self.assertEqual(raised.exception.code, "PDD_DATA_SHOP_MISSING")
if __name__ == "__main__": if __name__ == "__main__":
+35
View File
@@ -0,0 +1,35 @@
"""用真机导出的控件树验证真实页面结构。"""
from pathlib import Path
import unittest
from src.pdd_collect_service import parse_goods_page, parse_spec_panel
REAL_XML = Path(__file__).parents[1] / "image_xml"
class PddRealXmlFixtureTest(unittest.TestCase):
def test_split_title_is_joined_from_real_goods_page(self):
result = parse_goods_page(
(REAL_XML / "737116531267_home.xml").read_text(encoding="utf-8")
)
self.assertEqual(
result.title,
"【店铺热销】冰丝吊带裙女夏季薄款内搭连衣裙宽松a字裙中长款打底裙衬裙纯色",
)
def test_real_spec_panel_has_all_colors_and_two_prices(self):
result = parse_spec_panel(
(REAL_XML / "737116531267_size.xml").read_text(encoding="utf-8")
)
colors = next(item for item in result.dimensions if item.key == "color")
self.assertEqual(len(colors.values), 8)
self.assertIn("浅蓝色中长款", [item.text for item in colors.values])
self.assertEqual(result.price_cent, 470)
self.assertEqual(result.list_price_cent, 1990)
if __name__ == "__main__":
unittest.main()
+43 -2
View File
@@ -12,7 +12,7 @@ os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
from src.pdd_ui import PDDTaskPage from src.pdd_ui import PDDTaskPage
from src.admin_gateway import AdminTask from src.admin_gateway import AdminTask, SubmissionReceipt
from src.pdd_ui_event import ( from src.pdd_ui_event import (
PDDTaskPageEvent, PDDTaskPageEvent,
admin_task_to_new_claimed_task, admin_task_to_new_claimed_task,
@@ -38,6 +38,12 @@ class BrokenSaveRepository(BrokenRepository):
def add_claimed_task(self, _task): def add_claimed_task(self, _task):
raise RuntimeError("disk is full") raise RuntimeError("disk is full")
def next_pending_outbox(self):
return None
def next_collect_task(self):
return None
class RecordingClaimGateway: class RecordingClaimGateway:
"""记录领取参数并返回预设结果。""" """记录领取参数并返回预设结果。"""
@@ -52,6 +58,12 @@ class RecordingClaimGateway:
self.thread_ids.append(threading.get_ident()) self.thread_ids.append(threading.get_ident())
return self.response return self.response
def submit_result(self, task_id, idempotency_key, result):
return SubmissionReceipt(True, "RESULT-001", "2026-08-07T08:00:00Z")
def submit_failure(self, task_id, idempotency_key, failure):
return SubmissionReceipt(True, "FAILURE-001", "2026-08-07T08:00:00Z")
class SlowClaimGateway(RecordingClaimGateway): class SlowClaimGateway(RecordingClaimGateway):
"""让关闭测试能稳定发生在 HTTP 返回之前。""" """让关闭测试能稳定发生在 HTTP 返回之前。"""
@@ -66,6 +78,28 @@ class SlowClaimGateway(RecordingClaimGateway):
return super().claim_next(client, capabilities) return super().claim_next(client, capabilities)
class FakeCollectResult:
def to_pdd_data(self):
return {
"schema_version": 1,
"goods_id": "737116531267",
"title": "测试商品",
"shop_name": "测试店铺",
"price_granularity": "color",
"dimensions": [],
"skus": [{"price_cent": 990}],
}
class FakeCollector:
def collect(self, _task):
return FakeCollectResult()
def fake_collect_factory(*_args):
return FakeCollector()
def collect_admin_task(task_id="COL-001"): def collect_admin_task(task_id="COL-001"):
return AdminTask( return AdminTask(
task_id=task_id, task_id=task_id,
@@ -246,6 +280,7 @@ class PDDTaskPageEventTest(unittest.TestCase):
self.repository, self.repository,
claim_gateway=gateway, claim_gateway=gateway,
settings_repository=self._saved_settings(), settings_repository=self._saved_settings(),
collect_service_factory=fake_collect_factory,
) )
page.autoFetchRequested.emit() page.autoFetchRequested.emit()
@@ -276,6 +311,7 @@ class PDDTaskPageEventTest(unittest.TestCase):
self.repository, self.repository,
claim_gateway=gateway, claim_gateway=gateway,
settings_repository=self._saved_settings(), settings_repository=self._saved_settings(),
collect_service_factory=fake_collect_factory,
) )
page.autoFetchRequested.emit() page.autoFetchRequested.emit()
@@ -295,6 +331,7 @@ class PDDTaskPageEventTest(unittest.TestCase):
self.repository, self.repository,
claim_gateway=gateway, claim_gateway=gateway,
settings_repository=self._saved_settings(), settings_repository=self._saved_settings(),
collect_service_factory=fake_collect_factory,
) )
page.autoFetchRequested.emit() page.autoFetchRequested.emit()
@@ -316,12 +353,14 @@ class PDDTaskPageEventTest(unittest.TestCase):
self.repository, self.repository,
claim_gateway=gateway, claim_gateway=gateway,
settings_repository=self._saved_settings(), settings_repository=self._saved_settings(),
collect_service_factory=fake_collect_factory,
) )
page.autoFetchRequested.emit() page.autoFetchRequested.emit()
self.assertTrue(wait_until(self.app, lambda: not events._claim_busy)) self.assertTrue(wait_until(self.app, lambda: not events._claim_busy))
self.assertIn("本地已有", page.statusLabel.text()) self.assertIn("采集完成", page.statusLabel.text())
self.assertEqual(gateway.calls, [])
self.assertEqual(self.repository.count_tasks(), 1) self.assertEqual(self.repository.count_tasks(), 1)
events.shutdown() events.shutdown()
page.deleteLater() page.deleteLater()
@@ -334,6 +373,7 @@ class PDDTaskPageEventTest(unittest.TestCase):
BrokenSaveRepository(), BrokenSaveRepository(),
claim_gateway=gateway, claim_gateway=gateway,
settings_repository=self._saved_settings(), settings_repository=self._saved_settings(),
collect_service_factory=fake_collect_factory,
) )
page.autoFetchRequested.emit() page.autoFetchRequested.emit()
@@ -371,6 +411,7 @@ class PDDTaskPageEventTest(unittest.TestCase):
self.repository, self.repository,
claim_gateway=gateway, claim_gateway=gateway,
settings_repository=self._saved_settings(), settings_repository=self._saved_settings(),
collect_service_factory=fake_collect_factory,
) )
page.autoFetchRequested.emit() page.autoFetchRequested.emit()
self.assertTrue(wait_until(self.app, gateway.started.is_set)) self.assertTrue(wait_until(self.app, gateway.started.is_set))
+47
View File
@@ -183,6 +183,53 @@ class TaskRepositoryTests(unittest.TestCase):
with self.assertRaisesRegex(ValueError, "offset"): with self.assertRaisesRegex(ValueError, "offset"):
self.repository.list_tasks(offset=-1) self.repository.list_tasks(offset=-1)
def test_result_and_outbox_are_saved_together_then_marked_succeeded(self):
self.repository.add_claimed_task(self._task("TASK-RUN"))
started = self.repository.start_collect_run("TASK-RUN", "USB-001")
event = self.repository.save_collect_result(
"TASK-RUN",
started.attempt_id,
{
"goods_id": "10001",
"title": "测试商品",
"price_granularity": "color",
"dimensions": [],
"skus": [{"price_cent": 990}],
},
)
self.assertEqual(
self.repository.get_task("TASK-RUN").status,
TaskStatus.RESULT_PENDING,
)
self.assertEqual(event.status, OutboxStatus.PENDING)
self.repository.mark_outbox_sent(event.id)
self.assertEqual(
self.repository.get_task("TASK-RUN").status,
TaskStatus.SUCCEEDED,
)
def test_recovery_restores_sending_and_interrupted_running(self):
self.repository.add_claimed_task(self._task("TASK-RECOVER"))
started = self.repository.start_collect_run("TASK-RECOVER", "USB-001")
self.repository.save_collect_failure(
"TASK-RECOVER",
started.attempt_id,
TaskStatus.RETRY_WAIT,
"DEVICE_OFFLINE",
"设备离线",
True,
)
event = self.repository.next_pending_outbox()
self.repository.mark_outbox_sending(event.id)
self.repository.recover_interrupted_work()
self.assertEqual(
self.repository.get_outbox_event(event.id).status,
OutboxStatus.PENDING,
)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
+5 -5
View File
@@ -87,11 +87,11 @@ client/
|---|---|---| |---|---|---|
| 主窗口文件 | `src/ui/main_window.py` | `src/ui_main.py`。**注意**:`client/AGENTS.md` 已按 `src/ui_main.py` 写规则,两处不一致,见下方说明 | | 主窗口文件 | `src/ui/main_window.py` | `src/ui_main.py`。**注意**:`client/AGENTS.md` 已按 `src/ui_main.py` 写规则,两处不一致,见下方说明 |
| 目录分层 | domain / application / infrastructure / workers / ui | 平铺在 `src/` 下:`db.py`、`db_schema.py`、`task_repository.py`、`settings_repository.py`、`task_models.py` 等,另有 `src/util/`、`src/demo1/` | | 目录分层 | domain / application / infrastructure / workers / ui | 平铺在 `src/` 下:`db.py`、`db_schema.py`、`task_repository.py`、`settings_repository.py`、`task_models.py` 等,另有 `src/util/`、`src/demo1/` |
| 主按钮文案 | 「获取任务」⇄「停止获取」 | 构造时是「获取任务」,但状态机(`pdd_ui.py` 470/472 行)仍是「开始自动获取」/「停止自动获取」,会覆盖掉,**待修** | | 主按钮文案 | 「获取任务」⇄「停止获取」 | #32 暂为「获取任务」单次模式,运行期间禁用 |
| Admin 网关 | `AdminGateway` + Mock/HTTP 两实现 | 尚未实现 | | Admin 网关 | `AdminGateway` + Mock/HTTP 两实现 | 登记、领取、结果和失败提交已实现 |
| 任务协调器 | `TaskCoordinator` / `TaskDispatcher` / `ResultSubmissionService` | 尚未实现 | | 采集任务协调器 | `CollectTaskService` | 已实现单条采集任务流程;采购仍未接入 |
| Outbox 提交 | 从 `outbox_events` 取件重试 | 表已建好,提交逻辑尚未实现 | | Outbox 提交 | 从 `outbox_events` 取件重试 | 采集结果与失败已实现,重试不重复采集 |
| PDD 自动化 | `infrastructure/pdd/` 适配层 | `src/util/` 下的独立函数 + `src/demo1/` 演示脚本 | | PDD 自动化 | `infrastructure/pdd/` 适配层 | `pdd_device_service.py` 与 `pdd_collect_service.py` 已接入采集主链 |
已经对齐、不再是差异的(保留在这里做个记录,下次可删): 已经对齐、不再是差异的(保留在这里做个记录,下次可删):
+2 -2
View File
@@ -200,8 +200,8 @@ POST /api/v1/client/tasks/claim
无可领取任务时返回 `204 No Content`。 无可领取任务时返回 `204 No Content`。
Client 的 `HttpAdminGateway.claim_next` 已实现本接口。当前只声明 Client 的 `HttpAdminGateway.claim_next` 已实现本接口。当前只声明
`supported_types: ["collect"]`,一次调用最多领取一个采集任务;结果提交和失败提交 `supported_types: ["collect"]`,一次调用最多领取一个采集任务;采集结束后通过
仍由后续工单实现。 本页 §6 或 §7 提交,完整请求会先进入本地 Outbox。
`[必须]` **`204` 不是错误。** Client 要把它当"暂时没活干"处理, `[必须]` **`204` 不是错误。** Client 要把它当"暂时没活干"处理,
不要报错,也不要因此触发重试风暴。首次 claim 通常返回 204;如果该编号已经预先分配任务,也可以直接返回 200。 不要报错,也不要因此触发重试风暴。首次 claim 通常返回 204;如果该编号已经预先分配任务,也可以直接返回 200。
+4 -4
View File
@@ -60,10 +60,10 @@
- 停止表示不再领取新任务;当前任务进入安全停止流程。 - 停止表示不再领取新任务;当前任务进入安全停止流程。
- 如果设备、Admin 或必要设置无效,按钮可禁用,但附近必须说明缺少的条件。 - 如果设备、Admin 或必要设置无效,按钮可禁用,但附近必须说明缺少的条件。
**当前过渡状态(#30):**任务执行器尚未接入时,按钮文字固定为“获取任务”,每次 **当前单任务模式(#32):**按钮文字固定为“获取任务”,每次点击先补交一条本地
点击只在后台领取一个采集任务、保存到 SQLite 并刷新表格。领取期间禁用重复点击, Outbox;若无待提交结果则执行最早的本地采集任务,再没有才向 Admin 领取一条。
底部状态区显示进度;不循环领取,也不显示“停止获取”。接入领取—执行闭环后再恢复 领取、手机采集和提交都在工作线程完成,运行期间按钮禁用,结束后刷新任务表。
本节上面的最终交互。 当前不循环领取,也不执行采购任务。
### 4.2 搜索与筛选 ### 4.2 搜索与筛选