|
|
import type { AxelPlaceNetworkEvent } from "@/workers/rpa/axel-selection-bridge";
|
|
|
import type {
|
|
|
AddressCommitState,
|
|
|
AddressSelectDiagnostics,
|
|
|
AddressSelectStatus,
|
|
|
} from "@/workers/rpa/address-adapter/types";
|
|
|
|
|
|
export type PlaceNetworkDiagnostic = {
|
|
|
placeId: string;
|
|
|
status: number;
|
|
|
url: string;
|
|
|
at: number;
|
|
|
};
|
|
|
|
|
|
export type AddressNetworkDiagnostics = {
|
|
|
expectedPlaceId: string;
|
|
|
observedPlaceIds: string[];
|
|
|
placeNetworkEvents: PlaceNetworkDiagnostic[];
|
|
|
placeRequestObserved: boolean;
|
|
|
placeRequestHttpOk: boolean;
|
|
|
pickupLostAfterDelivery: boolean;
|
|
|
};
|
|
|
|
|
|
export function buildNetworkDiagnostics(
|
|
|
bridge: {
|
|
|
getObservedPlaceCommitIds: () => string[];
|
|
|
getPlaceNetworkLog: () => readonly AxelPlaceNetworkEvent[];
|
|
|
hasPlaceCommit: (placeId: string) => boolean;
|
|
|
hasSuccessfulPlaceNetworkRequest: (placeId: string) => boolean;
|
|
|
},
|
|
|
expectedPlaceId: string,
|
|
|
pickupPlaceId?: string,
|
|
|
): AddressNetworkDiagnostics {
|
|
|
return {
|
|
|
expectedPlaceId,
|
|
|
observedPlaceIds: bridge.getObservedPlaceCommitIds(),
|
|
|
placeNetworkEvents: bridge.getPlaceNetworkLog().map((event) => ({
|
|
|
placeId: event.placeId,
|
|
|
status: event.status,
|
|
|
url: event.url,
|
|
|
at: event.at,
|
|
|
})),
|
|
|
placeRequestObserved: bridge.hasPlaceCommit(expectedPlaceId),
|
|
|
placeRequestHttpOk: bridge.hasSuccessfulPlaceNetworkRequest(expectedPlaceId),
|
|
|
pickupLostAfterDelivery: false,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function createEmptyDiagnostics(
|
|
|
address: string,
|
|
|
commitState: AddressCommitState = "EMPTY",
|
|
|
): AddressSelectDiagnostics {
|
|
|
return {
|
|
|
address,
|
|
|
placeId: "",
|
|
|
method: "",
|
|
|
events: [],
|
|
|
placeRequestObserved: false,
|
|
|
status: "selection_failed",
|
|
|
commitState,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
export function formatDiagnosticsFailure(diag: AddressSelectDiagnostics): string {
|
|
|
const base = `address=${diag.address.slice(0, 64)} placeId=${diag.placeId || "—"} method=${diag.method || "—"} commitState=${diag.commitState}`;
|
|
|
switch (diag.status) {
|
|
|
case "no_place_request":
|
|
|
return `${base};失败于 place API 前:widget 未发起 GET place 请求(selection event 未触发)`;
|
|
|
case "place_http_error":
|
|
|
return `${base};失败于 place API:HTTP 非 200`;
|
|
|
case "place_id_mismatch":
|
|
|
return `${base};失败于 place API:placeId 与预期不匹配`;
|
|
|
case "timeout":
|
|
|
return `${base};失败于 place API:等待 commit 超时`;
|
|
|
case "selection_failed":
|
|
|
return `${base};失败于 selection event:候选/绑定/点选未完成`;
|
|
|
default:
|
|
|
return `${base};地址 commit 未完成`;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export function logAddressSelectDiagnostics(
|
|
|
side: "pickup" | "delivery",
|
|
|
diag: AddressSelectDiagnostics,
|
|
|
): void {
|
|
|
console.log(
|
|
|
`[rpa] address-select:${side} ${JSON.stringify({
|
|
|
address: diag.address,
|
|
|
placeId: diag.placeId,
|
|
|
method: diag.method,
|
|
|
events: diag.events,
|
|
|
placeRequestObserved: diag.placeRequestObserved,
|
|
|
status: diag.status,
|
|
|
commitState: diag.commitState,
|
|
|
})}`,
|
|
|
);
|
|
|
}
|
|
|
|
|
|
export function resolvePlaceFailureStatus(
|
|
|
placeRequestObserved: boolean,
|
|
|
placeIdMismatch: boolean,
|
|
|
httpError: boolean,
|
|
|
timedOut: boolean,
|
|
|
): AddressSelectStatus {
|
|
|
if (!placeRequestObserved) {
|
|
|
return "no_place_request";
|
|
|
}
|
|
|
if (placeIdMismatch) {
|
|
|
return "place_id_mismatch";
|
|
|
}
|
|
|
if (httpError) {
|
|
|
return "place_http_error";
|
|
|
}
|
|
|
if (timedOut) {
|
|
|
return "timeout";
|
|
|
}
|
|
|
return "selection_failed";
|
|
|
}
|