AI_UIAutomation/scripts/probe-light-popup.ts

68 lines
3.4 KiB
TypeScript

import { createDriver } from '../drivers/factory';
import * as fs from 'fs';
(async () => {
const d = createDriver();
await d.createSession();
const KW = process.env.LIGHT_CARD || 'Permanent Outdoor Lights';
try {
await d.dismissPopupIfPresent(); await d.goBackToHomepage();
await new Promise((r) => setTimeout(r, 1000));
let el: string | null = null;
for (let i = 0; i < 10; i++) {
el = await d.findElementRaw('-android uiautomator', `new UiSelector().textContains("${KW}")`).catch(() => null);
if (el) break;
await d.swipe(540, 1500, 540, 700, 0.4).catch(() => {});
await new Promise((r) => setTimeout(r, 800));
}
if (!el) throw new Error('找不到灯卡片');
const rect = await d.getElementRect(el);
console.log(`卡片文本 rect=(${rect.x},${rect.y}) ${rect.width}x${rect.height}`);
await d.tap(rect.x + rect.width / 2, rect.y + rect.height / 2);
await new Promise((r) => setTimeout(r, 2500));
const size = await d.getWindowSize();
console.log(`屏幕 ${size.width}x${size.height}`);
const src = await d.getSource();
const texts = [...new Set(Array.from(src.matchAll(/text="([^"]+)"/g)).map((m) => m[1]).filter((t) => t.trim()))];
console.log('TEXTS=' + JSON.stringify(texts));
// clickable 节点
const clk = Array.from(src.matchAll(/clickable="true"[^>]*?bounds="(\[\d+,\d+\]\[\d+,\d+\])"/g)).map((m) => m[1]);
console.log('CLICKABLE=' + JSON.stringify(clk.slice(0, 30)));
// 滑条类节点(SeekBar/ProgressBar/Slider) — 找 class 含 SeekBar/Slider 或 scrollable
const sliders = Array.from(src.matchAll(/<[^>]*class="([^"]*(?:SeekBar|Slider|ProgressBar)[^"]*)"[^>]*bounds="(\[\d+,\d+\]\[\d+,\d+\])"[^>]*>/g)).map((m) => `${m[1]} ${m[2]}`);
console.log('SLIDERS=' + JSON.stringify(sliders));
// 浮层下半区(y>1300)所有"宽"节点(width>400):RN 自绘滑条候选
const wide: string[] = [];
for (const m of src.matchAll(/<[^>]*class="([^"]+)"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*>/g)) {
const [cls, x1, y1, x2, y2] = [m[1], +m[2], +m[3], +m[4], +m[5]];
const w = x2 - x1, h = y2 - y1;
if (y1 > 1300 && w > 400 && h < 300) wide.push(`${cls.split('.').pop()} [${x1},${y1}][${x2},${y2}] w${w}h${h}`);
}
console.log('WIDE_NODES=' + JSON.stringify(wide.slice(0, 20)));
// 开灯后再看滑条填充条:点电源 → dump 滑条 y 区间(1620-1850)内所有节点(找蓝色填充 View 的右边缘=亮度)
await d.tap(540, 1455); // 电源键
await new Promise((r) => setTimeout(r, 3500));
const src2 = await d.getSource();
const inTrack: string[] = [];
for (const m of src2.matchAll(/<[^>]*class="([^"]+)"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*>/g)) {
const [cls, x1, y1, x2, y2] = [m[1], +m[2], +m[3], +m[4], +m[5]];
if (y1 >= 1600 && y2 <= 1860 && x2 - x1 > 30) inTrack.push(`${cls.split('.').pop()} [${x1},${y1}][${x2},${y2}] w${x2 - x1}`);
}
const st = [...new Set(Array.from(src2.matchAll(/text="([^"]+)"/g)).map((m) => m[1]))].slice(0, 8);
console.log('AFTER_ON_TEXTS=' + JSON.stringify(st));
console.log('TRACK_NODES=' + JSON.stringify(inTrack.slice(0, 15)));
const ss = await d.screenshot();
fs.writeFileSync('/tmp/light_popup.png', Buffer.from(ss, 'base64'));
console.log('截图: /tmp/light_popup.png');
} catch (e: any) {
console.error('探针失败:', e.message);
} finally {
await d.destroySession();
}
})();