You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
3.9 KiB
132 lines
3.9 KiB
/**
|
|
* Priority1 人机协作 — 记录人工在浏览器内的操作(至报价页)
|
|
*/
|
|
|
|
import { readFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import type { Page } from "playwright";
|
|
|
|
const BROWSER_RECORDER_JS = join(
|
|
dirname(fileURLToPath(import.meta.url)),
|
|
"human-assist-recorder.browser.js",
|
|
);
|
|
|
|
export type HumanAssistEvent = {
|
|
ts: number;
|
|
kind: "click" | "input" | "change";
|
|
tag: string;
|
|
id: string;
|
|
name: string;
|
|
inputType: string;
|
|
value: string;
|
|
label: string;
|
|
text: string;
|
|
selector: string;
|
|
url: string;
|
|
};
|
|
|
|
export async function installHumanAssistRecorder(page: Page): Promise<void> {
|
|
const script = readFileSync(BROWSER_RECORDER_JS, "utf8");
|
|
await page.addInitScript({ content: script });
|
|
await page.evaluate(script).catch(() => undefined);
|
|
}
|
|
|
|
export async function drainHumanAssistEvents(page: Page): Promise<HumanAssistEvent[]> {
|
|
if (page.isClosed()) return [];
|
|
return page.evaluate("window.__p1HumanEvents || []");
|
|
}
|
|
|
|
/** 人工已验证报价但 DOM 事件未捕获时,用清单生成可回放脚本 */
|
|
export function buildAccessorialLabelPlaywright(labels: readonly string[]): string {
|
|
const events: HumanAssistEvent[] = labels.map((label) => ({
|
|
ts: 0,
|
|
kind: "click",
|
|
tag: "label",
|
|
id: "",
|
|
name: "",
|
|
inputType: "checkbox",
|
|
value: "",
|
|
label,
|
|
text: label,
|
|
selector: "",
|
|
url: "",
|
|
}));
|
|
return formatHumanEventsAsPlaywright(events);
|
|
}
|
|
|
|
export function formatHumanEventsAsPlaywright(events: HumanAssistEvent[]): string {
|
|
const lines: string[] = [
|
|
"const { chromium } = require('playwright');",
|
|
"",
|
|
"(async () => {",
|
|
" const browser = await chromium.launch({ headless: false });",
|
|
" const page = await browser.newPage();",
|
|
" // --- 人工补录步骤(由 human-assist-recorder 生成) ---",
|
|
];
|
|
|
|
const seen = new Set<string>();
|
|
|
|
for (const ev of events) {
|
|
if (ev.kind === "click" || ev.kind === "change") {
|
|
const accessorial = ev.label || ev.text;
|
|
if (
|
|
accessorial &&
|
|
/Liftgate|Inside|Limited Access|Residential|Delivery Appointment|Call Before|Hazardous/i.test(
|
|
accessorial,
|
|
)
|
|
) {
|
|
const key = `label:${accessorial.slice(0, 60)}`;
|
|
if (!seen.has(key)) {
|
|
seen.add(key);
|
|
lines.push(
|
|
` await page.locator('#container-mh').getByLabel(${JSON.stringify(accessorial)}, { exact: false }).click({ force: true });`,
|
|
);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ev.kind === "click") {
|
|
if (ev.selector) {
|
|
const key = `sel:${ev.selector}`;
|
|
if (seen.has(key)) continue;
|
|
seen.add(key);
|
|
lines.push(` await page.locator('#container-mh ${ev.selector}').click({ force: true });`);
|
|
} else if (ev.text && ev.text.length < 40) {
|
|
const key = `text:${ev.text}`;
|
|
if (seen.has(key)) continue;
|
|
seen.add(key);
|
|
lines.push(
|
|
` await page.locator('#container-mh').getByText(${JSON.stringify(ev.text)}).first().click({ force: true });`,
|
|
);
|
|
}
|
|
continue;
|
|
}
|
|
if ((ev.kind === "change" || ev.kind === "input") && ev.selector && ev.value) {
|
|
if (ev.tag === "select") {
|
|
lines.push(
|
|
` await page.locator('#container-mh ${ev.selector}').selectOption(${JSON.stringify(ev.value)});`,
|
|
);
|
|
} else if (ev.inputType !== "checkbox") {
|
|
lines.push(
|
|
` await page.locator('#container-mh ${ev.selector}').fill(${JSON.stringify(ev.value)});`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
lines.push(" await page.locator('#container-mh').getByRole('button', { name: /GET INSTANT QUOTES/i }).click({ force: true });");
|
|
lines.push("})();");
|
|
return lines.join("\n");
|
|
}
|
|
|
|
export type HumanAccessorialRecording = {
|
|
pathId: string;
|
|
title: string;
|
|
recordedAt: string;
|
|
expectedAccessorials: readonly string[];
|
|
events: HumanAssistEvent[];
|
|
playwrightScript: string;
|
|
};
|