import { DeviceDriver } from '../../drivers/types'; import { sleep, waitForSource } from './element.helper'; import { extractTicketId, setSharedTicketId } from './zendesk.helper'; async function tapText(driver: DeviceDriver, t: string): Promise { const el = driver.platform === 'android' ? await driver.findElementRaw('-android uiautomator', `new UiSelector().textContains("${t}")`) : await driver.findElementRaw('name', t); if (el) { await driver.tapElement(el); return true; } return false; } /** Profile → Support → Feedback 页(我的反馈工单列表 + Create a New Ticket)。 */ export async function navigateToFeedback(driver: DeviceDriver): Promise { const prof = await driver.findElementRaw('-android uiautomator', 'new UiSelector().descriptionContains("Profile")'); if (prof) { await driver.tapElement(prof); await sleep(2000); } if (!(await tapText(driver, 'Support'))) return false; await sleep(2000); if (!(await tapText(driver, 'Feedback'))) return false; await sleep(2000); return true; } /** * 提交一条 feedback 工单(Android 实测 2026-06)。流程: * Feedback 页 → Create a New Ticket → Question Type 滚轮(从 Product Issues 起第 typeIndex 个) * → 填 Question Details → Submit → "My Feedback" 成功页(含 Ticket ID)。 * * Question Type 滚轮选项无障碍不可见,只能盲滑:**先重置到顶(Product Issues),再上滑 typeIndex 格**。 * 顺序:0 Product Issues / 1 Order Tracking / 2 Buying Guide / 3 App issues / 4 Rapid Replacement / 5 B2B Enquiry。 * 坐标按 1080×2280;换机型需调。 * @returns 是否到达成功页 */ export async function submitFeedback( driver: DeviceDriver, opts: { details?: string; typeIndex?: number } = {} ): Promise { const details = opts.details || '内测问题直接关闭插件热更校验'; const typeIndex = opts.typeIndex ?? 3; // App issues if (!(await tapText(driver, 'Create a New Ticket'))) { // 已无工单时按钮文案可能不同,兜底找 "Create" if (!(await tapText(driver, 'Create'))) return false; } await waitForSource(driver, 'Question Type', 8000).catch(() => {}); // 选 Question Type:开 picker → 重置到顶 → 上滑 typeIndex 格 → Confirm // 开选择器:优先点字段文字 "Please select"(跨分辨率稳),找不到再坐标兜底。 if (!(await tapText(driver, 'Please select'))) { await driver.tap(540, 460); } await sleep(1200); // 类型轮选项无障碍不可见,只能盲滑;与时间轮(automation.helper spinWheel)同一套方式: // 单格慢滑 ~95px、duration 0.5、无惯性(1 次=1 格)。列居中 x≈540、选中带中心 y≈2090。 const COL_X = 540, MID = 2090, TOP = 1995; for (let i = 0; i < 8; i++) { await driver.swipe(COL_X, TOP, COL_X, MID, 0.5); await sleep(250); } // 下滑到顶=Product Issues await sleep(300); for (let i = 0; i < typeIndex; i++) { await driver.swipe(COL_X, MID, COL_X, TOP, 0.5); await sleep(250); } // 上滑 N 格 await sleep(300); // Confirm:文字定位(实测在 y≈1714,旧硬编码 y1511 点空),坐标兜底。 if (!(await tapText(driver, 'Confirm'))) { await driver.tap(947, 1714); } await sleep(2000); // 填 Question Details(末个 EditText) const eds = await driver.findElementsRaw('-android uiautomator', 'new UiSelector().className("android.widget.EditText")'); if (!eds.length) return false; await driver.typeText(eds[eds.length - 1], details); await sleep(500); try { await driver.goBack(); } catch { /* 收键盘 */ } // Submit if (!(await tapText(driver, 'Submit'))) return false; await sleep(4000); // 成功页:My Feedback / Ticket ID return waitForSource(driver, 'Ticket ID', 8000).catch(() => false) as Promise; } /** * feedback 提交成功后,从结果页抓取工单号并持久化(供「获取RN插件 / 插件热更」用例消费)。 * 返回工单号;未抓到返回 null。 */ export async function captureFeedbackTicketId(driver: DeviceDriver): Promise { let ticketId: string | null = null; for (let i = 0; i < 3 && !ticketId; i++) { const source = await driver.getSource(); ticketId = extractTicketId(source); if (!ticketId) await sleep(1500); } if (ticketId) { setSharedTicketId(ticketId); console.log(`feedback 工单号已捕获并保存: ${ticketId}`); } else { console.log('feedback 提交页未解析到工单号(检查 extractTicketId 规则与实际 UI)'); } return ticketId; }