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.
chajia/scripts/batch-flock-direct-10.ts

217 lines
5.4 KiB

/**
* Flock Direct 10 组样例探针
*
* 用法:
* FLOCK_QUOTE_MODE=direct npm run batch:flock-direct-10
*/
import fs from "node:fs";
import path from "node:path";
import { runFlockQuoteRpa } from "@/workers/rpa/flock/run-quote";
import type { FlockQuoteInput } from "@/workers/rpa/flock/types";
function tomorrowMmDdYyyy(offsetDays = 1): string {
const d = new Date();
d.setDate(d.getDate() + offsetDays);
const mm = String(d.getMonth() + 1).padStart(2, "0");
const dd = String(d.getDate()).padStart(2, "0");
return `${mm}/${dd}/${d.getFullYear()}`;
}
/** 10 组差异化:跨区 ZIP + 不同托盘/总重/尺寸(硬限内) */
const CASES: Array<Omit<FlockQuoteInput, "pickupDate"> & { label: string }> = [
{
label: "LA→Dallas 6pl/10k",
pickupZip: "90001",
deliveryZip: "75201",
palletCount: 6,
totalWeightLb: 10_000,
lengthIn: 48,
widthIn: 40,
heightIn: 48,
},
{
label: "SF→Chicago 4pl/2.8k",
pickupZip: "94102",
deliveryZip: "60611",
palletCount: 4,
totalWeightLb: 2_800,
lengthIn: 48,
widthIn: 40,
heightIn: 48,
},
{
label: "Boston→Atlanta 8pl/9.2k",
pickupZip: "02109",
deliveryZip: "30326",
palletCount: 8,
totalWeightLb: 9_200,
lengthIn: 48,
widthIn: 40,
heightIn: 60,
},
{
label: "Austin→Philly 10pl/14k",
pickupZip: "78701",
deliveryZip: "19106",
palletCount: 10,
totalWeightLb: 14_000,
lengthIn: 48,
widthIn: 40,
heightIn: 72,
},
{
label: "Seattle→Miami 12pl/18.5k",
pickupZip: "98101",
deliveryZip: "33130",
palletCount: 12,
totalWeightLb: 18_500,
lengthIn: 48,
widthIn: 48,
heightIn: 96,
},
{
label: "Denver→NYC 5pl/6k",
pickupZip: "80202",
deliveryZip: "10001",
palletCount: 5,
totalWeightLb: 6_000,
lengthIn: 48,
widthIn: 40,
heightIn: 60,
},
{
label: "Phoenix→Houston 16pl/28k",
pickupZip: "85004",
deliveryZip: "77002",
palletCount: 16,
totalWeightLb: 28_000,
lengthIn: 48,
widthIn: 40,
heightIn: 96,
},
{
label: "Portland→Dallas 4pl/8k long",
pickupZip: "97201",
deliveryZip: "75201",
palletCount: 4,
totalWeightLb: 8_000,
lengthIn: 96,
widthIn: 48,
heightIn: 72,
},
{
label: "Detroit→LA 7pl/12k",
pickupZip: "48226",
deliveryZip: "90012",
palletCount: 7,
totalWeightLb: 12_000,
lengthIn: 48,
widthIn: 40,
heightIn: 84,
},
{
label: "Chicago→SF 20pl/38k",
pickupZip: "60611",
deliveryZip: "94102",
palletCount: 20,
totalWeightLb: 38_000,
lengthIn: 48,
widthIn: 40,
heightIn: 96,
},
];
type Row = {
index: number;
label: string;
ok: boolean;
ms: number;
reference: string | null;
prices: string | null;
error: string | null;
};
async function main(): Promise<void> {
process.env.RPA_MOCK_MODE = "false";
process.env.FLOCK_QUOTE_MODE ??= "direct";
process.env.FLOCK_MIN_QUOTES ??= "1";
const delayMs = Number(process.env.FLOCK_BATCH_DELAY_MS ?? "1500");
const outDir = path.join(process.cwd(), ".rpa", "flock-network-poc");
fs.mkdirSync(outDir, { recursive: true });
console.log(
`[flock-direct-10] mode=${process.env.FLOCK_QUOTE_MODE} cases=${CASES.length}`,
);
const rows: Row[] = [];
for (let i = 0; i < CASES.length; i += 1) {
const c = CASES[i]!;
const input: FlockQuoteInput = {
pickupDate: tomorrowMmDdYyyy(1 + (i % 3)),
pickupZip: c.pickupZip,
deliveryZip: c.deliveryZip,
palletCount: c.palletCount,
totalWeightLb: c.totalWeightLb,
lengthIn: c.lengthIn,
widthIn: c.widthIn,
heightIn: c.heightIn,
};
console.log(
`\n[${i + 1}/${CASES.length}] ${c.label} ` +
`${input.pickupZip}${input.deliveryZip} ${input.palletCount}pl ${input.totalWeightLb}lb`,
);
const t0 = Date.now();
const result = await runFlockQuoteRpa(input);
const ms = Date.now() - t0;
const ok = result.ok && result.quotes.length >= 1;
const prices = ok
? result.quotes.map((q) => `${q.label}:$${q.totalUsd}`).join(", ")
: null;
rows.push({
index: i + 1,
label: c.label,
ok,
ms,
reference: result.reference ?? null,
prices,
error: ok ? null : (result.errorMessage ?? "unknown"),
});
if (ok) {
console.log(`[OK] ${ms}ms ref=${result.reference ?? "-"} ${prices}`);
} else {
console.error(`[FAIL] ${ms}ms ${result.errorMessage ?? "unknown"}`);
}
if (i < CASES.length - 1 && delayMs > 0) {
await new Promise((r) => setTimeout(r, delayMs));
}
}
const passed = rows.filter((r) => r.ok).length;
const summary = {
capturedAt: new Date().toISOString(),
mode: process.env.FLOCK_QUOTE_MODE,
passed,
total: rows.length,
rows,
};
const outPath = path.join(outDir, `direct-10-${Date.now()}.json`);
fs.writeFileSync(outPath, JSON.stringify(summary, null, 2), "utf8");
console.log(`\n========== 汇总 ${passed}/${rows.length} ==========`);
for (const r of rows) {
console.log(
r.ok
? ` ✓ #${r.index} ${r.label} (${r.ms}ms) ${r.prices}`
: ` ✗ #${r.index} ${r.label} (${r.ms}ms) ${r.error}`,
);
}
console.log(`结果文件: ${outPath}`);
if (passed < rows.length) process.exitCode = 1;
}
main().catch((error) => {
console.error("[flock-direct-10] fatal:", error);
process.exit(1);
});