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.

753 lines
22 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/** Priority1 公开询价页演示/批量测试输入 */
import type {
ExpeditedTrailerType,
FtlAdditionalService,
FtlTrailerType,
Priority1ShipmentType,
} from "@/workers/rpa/priority1/shipment-types";
import {
EXPEDITED_TRAILER,
FTL_ADDITIONAL,
FTL_TRAILER,
getShipmentConfig,
} from "@/workers/rpa/priority1/shipment-types";
export type Priority1DemoInput = {
shipmentType: Priority1ShipmentType;
originZip: string;
destinationZip: string;
shipmentFrequency: string;
pickupDate: string;
email: string;
phone: string;
phoneCountry: string;
/** LTL */
lengthIn: string;
widthIn: string;
heightIn: string;
weightLb: string;
palletCount: string;
freightClass: string;
packaging: string;
pickupLocation: string;
deliveryLocation: string;
pickupServices: string[];
deliveryServices: string[];
/** FTL / Expedited 共用 */
commodity: string;
/** FTL */
ftlTrailer: FtlTrailerType;
ftlAdditionalServices: FtlAdditionalService[];
/** Expedited 主类型 Step 2 拖车 */
expeditedTrailer: ExpeditedTrailerType;
/** FTL Open Deck 子类型 */
openDeckSubtype: string;
/** FTL 温控 */
tempMinF: string;
tempMaxF: string;
/** FTL 选 Expedited 拖车后的子车型 */
ftlExpeditedTrailer: ExpeditedTrailerType;
/** 仅 Large Straight 可选 Liftgate */
expeditedLiftgate: boolean;
/** FTL 内嵌 Expedited — 特殊处理要求(可选) */
specialHandlingServices: string[];
};
const COMMON_STEP1 = {
shipmentFrequency: "One Time Shipment",
email: "niqijiti542@gmail.com",
};
/** P08 canonical — LTL 全附加服务11 项) */
export const P08_LTL_ALL_ACCESSORIALS = {
pickup: [
"Liftgate at Pickup",
"Inside Pickup",
"Limited Access Pickup",
"Residential Pickup",
],
delivery: [
"Liftgate at Delivery",
"Inside Delivery",
"Delivery Appointment",
"Call Before Delivery",
"Limited Access Delivery",
"Hazardous Material",
"Residential Delivery",
],
} as const;
export const P08_LTL_ACCESSORIAL_LABELS: readonly string[] = [
...P08_LTL_ALL_ACCESSORIALS.pickup,
...P08_LTL_ALL_ACCESSORIALS.delivery,
];
export const DEFAULT_PRIORITY1_DEMO: Priority1DemoInput = {
shipmentType: "ltl",
originZip: "10118",
destinationZip: "90017",
pickupDate: "07/15/2026",
phone: "2125550198",
phoneCountry: "US",
...COMMON_STEP1,
lengthIn: "48",
widthIn: "40",
heightIn: "48",
weightLb: "30",
palletCount: "2",
freightClass: "70",
packaging: "Pallet",
pickupLocation: "Residence / Home Business",
deliveryLocation: "Residence / Home Business",
pickupServices: ["Liftgate at Pickup", "Residential Pickup"],
deliveryServices: ["Liftgate at Delivery", "Residential Delivery"],
commodity: "General Freight",
ftlTrailer: "dry_van",
ftlAdditionalServices: [],
expeditedTrailer: "sprinter_van",
openDeckSubtype: "48 Foot Flatbed",
tempMinF: "32",
tempMaxF: "40",
ftlExpeditedTrailer: "sprinter_van",
expeditedLiftgate: false,
specialHandlingServices: [],
};
export const DEFAULT_FTL_DEMO: Priority1DemoInput = {
...DEFAULT_PRIORITY1_DEMO,
shipmentType: "ftl",
originZip: "32801",
destinationZip: "28202",
pickupDate: "07/14/2026",
phone: "7536407420",
commodity: "Electronics",
weightLb: "15000",
palletCount: "18",
ftlTrailer: "dry_van",
ftlAdditionalServices: ["full_ftl"],
};
/** FTL Open Deck — 见 form-logic-map FTL_CONDITIONAL_BRANCHES.ftl_open_deck */
export const DEFAULT_FTL_OPEN_DECK_DEMO: Priority1DemoInput = {
...DEFAULT_FTL_DEMO,
ftlTrailer: "open_deck",
openDeckSubtype: "48 Foot Flatbed",
ftlAdditionalServices: ["full_ftl"],
commodity: "Electronics",
weightLb: "12000",
palletCount: "14",
};
/** FTL Temperature Controlled — 见 form-logic-map FTL_CONDITIONAL_BRANCHES.ftl_temp */
export const DEFAULT_FTL_TEMP_DEMO: Priority1DemoInput = {
...DEFAULT_FTL_DEMO,
ftlTrailer: "temperature_controlled",
ftlAdditionalServices: ["full_ftl"],
commodity: "Electronics",
tempMinF: "32",
tempMaxF: "40",
weightLb: "10000",
palletCount: "16",
};
export const DEFAULT_EXPEDITED_DEMO: Priority1DemoInput = {
...DEFAULT_PRIORITY1_DEMO,
shipmentType: "expedited",
originZip: "32801",
destinationZip: "28202",
pickupDate: "07/14/2026",
phone: "7536407420",
commodity: "Electronics",
weightLb: "800",
expeditedTrailer: "sprinter_van",
};
/** FTL 内嵌 Expedited — 见 form-logic-map FTL_CONDITIONAL_BRANCHES.ftl_expedited_sub */
export const DEFAULT_FTL_FTL_EXPEDITED_DEMO: Priority1DemoInput = {
...DEFAULT_FTL_DEMO,
ftlTrailer: "ftl_expedited",
ftlAdditionalServices: [],
ftlExpeditedTrailer: "sprinter_van",
commodity: "Electronics",
weightLb: "2500",
expeditedLiftgate: false,
};
export type Priority1CanonicalPath = {
id: string;
title: string;
/** 用户画像 / 需求简述 */
persona: string;
input: Priority1DemoInput;
/** recorded=已录制或 visual chain 跑通logic-only=仅逻辑映射待录制 */
verified: "recorded" | "logic-only";
};
/**
* 全部 canonical 路径 — 覆盖 Priority1 表单各决策分支与代表性选项组合。
* 录制npm run record:priority1 -- 后按各路径 id 手动走一遍。
*/
export const PRIORITY1_CANONICAL_PATHS: Priority1CanonicalPath[] = [
{
id: "P01-ltl-residential",
title: "LTL 住宅 + 常用附加",
persona: "电商卖家,住宅提货派送,需尾板",
input: DEFAULT_PRIORITY1_DEMO,
verified: "recorded",
},
{
id: "P02-ltl-business-dock",
title: "LTL 商业有装卸台",
persona: "仓库出货,双方均有 dock/forklift",
input: {
...DEFAULT_PRIORITY1_DEMO,
pickupLocation: "Business (with loading docks or forklift)",
deliveryLocation: "Business (with loading docks or forklift)",
pickupServices: [],
deliveryServices: [],
},
verified: "recorded",
},
{
id: "P03-ltl-business-no-dock",
title: "LTL 商业无 dock",
persona: "小型门店,需尾板提货/派送",
input: {
...DEFAULT_PRIORITY1_DEMO,
pickupLocation: "Business (no loading dock, no forklift)",
deliveryLocation: "Business (no loading dock, no forklift)",
pickupServices: ["Liftgate at Pickup"],
deliveryServices: ["Liftgate at Delivery"],
},
verified: "recorded",
},
{
id: "P04-ltl-crate",
title: "LTL 包装 Crate",
persona: "机械零件,木箱包装非托盘",
input: {
...DEFAULT_PRIORITY1_DEMO,
packaging: "Crate",
freightClass: "85",
},
verified: "recorded",
},
{
id: "P05-ltl-box",
title: "LTL 包装 Box",
persona: "小件快递式纸箱散货",
input: { ...DEFAULT_PRIORITY1_DEMO, packaging: "Box", palletCount: "1" },
verified: "recorded",
},
{
id: "P06-ltl-bundle",
title: "LTL 包装 Bundle",
persona: "管材/长条物料捆扎",
input: { ...DEFAULT_PRIORITY1_DEMO, packaging: "Bundle", freightClass: "60" },
verified: "recorded",
},
{
id: "P07-ltl-not-sure-class",
title: "LTL Freight Class 不确定",
persona: "首次发货,不清楚 NMFC 等级",
input: { ...DEFAULT_PRIORITY1_DEMO, freightClass: "Not Sure" },
verified: "recorded",
},
{
id: "P08-ltl-all-accessorials",
title: "LTL 全附加服务",
persona: "限制进入区 + 室内 + 预约通知",
input: {
...DEFAULT_PRIORITY1_DEMO,
pickupServices: [...P08_LTL_ALL_ACCESSORIALS.pickup],
deliveryServices: [...P08_LTL_ALL_ACCESSORIALS.delivery],
},
verified: "recorded",
},
{
id: "P09-ltl-frequent-shipper",
title: "LTL 高频发货",
persona: "月发 11+ 票的大客户",
input: { ...DEFAULT_PRIORITY1_DEMO, shipmentFrequency: "100+" },
verified: "recorded",
},
{
id: "F01-ftl-dry-van-full",
title: "FTL Dry Van + Full FTL",
persona: "整车普货53ft 干柜",
input: DEFAULT_FTL_DEMO,
verified: "recorded",
},
{
id: "F02-ftl-dry-van-partial",
title: "FTL Dry Van + Partial PTL",
persona: "拼车/部分整车",
input: {
...DEFAULT_FTL_DEMO,
ftlAdditionalServices: ["partial_ptl"],
weightLb: "8000",
palletCount: "10",
},
verified: "recorded",
},
{
id: "F03-ftl-dry-van-team",
title: "FTL Dry Van + Team Drivers",
persona: "跨州加急,双驾不换班",
input: {
...DEFAULT_FTL_DEMO,
ftlAdditionalServices: ["team_drivers"],
weightLb: "38000",
palletCount: "22",
},
verified: "recorded",
},
{
id: "F04-ftl-open-deck-flatbed",
title: "FTL Open Deck Flatbed",
persona: "超宽设备,平板车",
input: DEFAULT_FTL_OPEN_DECK_DEMO,
verified: "recorded",
},
{
id: "F05-ftl-open-deck-step",
title: "FTL Open Deck Step Deck",
persona: "较高货物,阶梯平板",
input: {
...DEFAULT_FTL_OPEN_DECK_DEMO,
openDeckSubtype: "48 Foot Step Deck",
},
verified: "recorded",
},
{
id: "F06-ftl-open-deck-conestoga",
title: "FTL Open Deck Conestoga",
persona: "防雨布侧帘平板",
input: {
...DEFAULT_FTL_OPEN_DECK_DEMO,
openDeckSubtype: "Conestoga",
},
verified: "recorded",
},
{
id: "F07-ftl-open-deck-rgn",
title: "FTL Open Deck Goose Neck RGN",
persona: "重型机械低板",
input: {
...DEFAULT_FTL_OPEN_DECK_DEMO,
openDeckSubtype: "Removable Gooseneck",
weightLb: "35000",
},
verified: "recorded",
},
{
id: "F08-ftl-temperature",
title: "FTL Temperature Controlled",
persona: "冷链食品 3240°F",
input: DEFAULT_FTL_TEMP_DEMO,
verified: "recorded",
},
{
id: "F09-ftl-expedited-sprinter",
title: "FTL 内嵌 Expedited Sprinter",
persona: "FTL 页选第四卡 Expedited + Sprinter",
input: DEFAULT_FTL_FTL_EXPEDITED_DEMO,
verified: "recorded",
},
{
id: "F10-ftl-expedited-small",
title: "FTL 内嵌 Expedited Small Straight",
persona: "FTL Expedited 小直卡",
input: {
...DEFAULT_FTL_FTL_EXPEDITED_DEMO,
ftlExpeditedTrailer: "small_straight",
weightLb: "5000",
},
verified: "recorded",
},
{
id: "F11-ftl-expedited-large-liftgate",
title: "FTL 内嵌 Expedited Large + Liftgate",
persona: "大直卡 + 尾板卸货",
input: {
...DEFAULT_FTL_FTL_EXPEDITED_DEMO,
ftlExpeditedTrailer: "large_straight",
weightLb: "10000",
expeditedLiftgate: true,
},
verified: "recorded",
},
{
id: "E01-expedited-sprinter",
title: "Expedited 主类型 Sprinter",
persona: "加急小件 ≤3500 lb",
input: DEFAULT_EXPEDITED_DEMO,
verified: "recorded",
},
{
id: "E02-expedited-small",
title: "Expedited Small Straight",
persona: "加急中型直卡",
input: {
...DEFAULT_EXPEDITED_DEMO,
expeditedTrailer: "small_straight",
weightLb: "4500",
},
verified: "recorded",
},
{
id: "E03-expedited-large",
title: "Expedited Large Straight",
persona: "加急大型直卡",
input: {
...DEFAULT_EXPEDITED_DEMO,
expeditedTrailer: "large_straight",
weightLb: "10000",
},
verified: "recorded",
},
{
id: "E04-expedited-liftgate",
title: "Expedited Large Straight + Liftgate",
persona: "加急大直卡需尾板",
input: {
...DEFAULT_EXPEDITED_DEMO,
expeditedTrailer: "large_straight",
expeditedLiftgate: true,
weightLb: "8000",
},
verified: "recorded",
},
];
/** 24 条 canonical 路径预期 RPA 终态(批量验收结论,供系统联调) */
export const PRIORITY1_CANONICAL_EXPECTED_OUTCOME: Record<
string,
"instant_quote" | "manual_followup"
> = {
"P01-ltl-residential": "instant_quote",
"P02-ltl-business-dock": "instant_quote",
"P03-ltl-business-no-dock": "instant_quote",
"P04-ltl-crate": "instant_quote",
"P05-ltl-box": "instant_quote",
"P06-ltl-bundle": "instant_quote",
"P07-ltl-not-sure-class": "instant_quote",
"P08-ltl-all-accessorials": "instant_quote",
"P09-ltl-frequent-shipper": "instant_quote",
"F01-ftl-dry-van-full": "instant_quote",
"F02-ftl-dry-van-partial": "instant_quote",
"F03-ftl-dry-van-team": "instant_quote",
"F04-ftl-open-deck-flatbed": "instant_quote",
"F05-ftl-open-deck-step": "instant_quote",
"F06-ftl-open-deck-conestoga": "manual_followup",
"F07-ftl-open-deck-rgn": "manual_followup",
"F08-ftl-temperature": "manual_followup",
"F09-ftl-expedited-sprinter": "manual_followup",
"F10-ftl-expedited-small": "manual_followup",
"F11-ftl-expedited-large-liftgate": "manual_followup",
"E01-expedited-sprinter": "manual_followup",
"E02-expedited-small": "manual_followup",
"E03-expedited-large": "manual_followup",
"E04-expedited-liftgate": "manual_followup",
};
export type Priority1CanonicalTestCase = {
index: number;
id: string;
title: string;
category: "LTL" | "FTL" | "Expedited";
persona: string;
verified: "recorded" | "logic-only";
expectedOutcome: "instant_quote" | "manual_followup";
expectedMessage: string | null;
filter: string;
apiPayload: {
request_id: string;
customer_id: string;
priority1_input: Priority1DemoInput;
};
};
const MANUAL_FOLLOWUP_MSG = "表单已提交,站点判定需人工确认细节后报价";
/** 生成 24 条系统联调用例POST /api/priority1/quotes */
export function buildPriority1CanonicalTestCases(opts: {
customerId?: string;
requestIdPrefix?: string;
} = {}): Priority1CanonicalTestCase[] {
const customerId = opts.customerId ?? "CUST_PRIORITY1_TEST";
const prefix = opts.requestIdPrefix ?? "p1-matrix";
return PRIORITY1_CANONICAL_PATHS.map((path, index) => {
const expectedOutcome =
PRIORITY1_CANONICAL_EXPECTED_OUTCOME[path.id] ?? "instant_quote";
return {
index: index + 1,
id: path.id,
title: path.title,
category: path.id.startsWith("P")
? "LTL"
: path.id.startsWith("F")
? "FTL"
: "Expedited",
persona: path.persona,
verified: path.verified,
expectedOutcome,
expectedMessage:
expectedOutcome === "manual_followup" ? MANUAL_FOLLOWUP_MSG : null,
filter: path.id.replace(/-.*$/, ""),
apiPayload: {
request_id: `${prefix}-${path.id}`,
customer_id: customerId,
priority1_input: path.input,
},
};
});
}
const ZIP_POOL = [
"10118", "90017", "60601", "77002", "33131", "98101", "80202", "19107",
"02108", "75201", "30303", "48226", "44114", "85004", "37203", "63101",
"97201", "89101", "32801", "28202",
];
const FREIGHT_CLASSES = ["50", "55", "60", "65", "70", "77.5", "85", "92.5", "100"];
const FTL_TRAILERS = Object.keys(FTL_TRAILER) as FtlTrailerType[];
const EXP_TRAILERS = Object.keys(EXPEDITED_TRAILER) as ExpeditedTrailerType[];
const COMMODITIES = [
"General Freight",
"Palletized Goods",
"Electronics",
"Machinery",
"Furniture",
"Food Products",
];
function mulberry32(seed: number): () => number {
let s = seed >>> 0;
return () => {
s = (s + 0x6d2b79f5) >>> 0;
let t = Math.imul(s ^ (s >>> 15), 1 | s);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
function pick<T>(rng: () => number, arr: T[]): T {
return arr[Math.floor(rng() * arr.length)]!;
}
function randInt(rng: () => number, min: number, max: number): number {
return Math.floor(rng() * (max - min + 1)) + min;
}
function futurePickupDate(rng: () => number, base = new Date()): string {
const d = new Date(base);
d.setDate(d.getDate() + randInt(rng, 3, 21));
const mm = String(d.getMonth() + 1).padStart(2, "0");
const dd = String(d.getDate()).padStart(2, "0");
return `${mm}/${dd}/${d.getFullYear()}`;
}
function randomUsPhone(rng: () => number): string {
const area = randInt(rng, 201, 989);
const exchange = randInt(rng, 201, 999);
const line = randInt(rng, 1000, 9999);
return `${area}${exchange}${line}`.slice(0, 10);
}
function randomZipPair(rng: () => number): { originZip: string; destinationZip: string } {
let originZip = pick(rng, ZIP_POOL);
let destinationZip = pick(rng, ZIP_POOL);
let guard = 0;
while (destinationZip === originZip && guard < 20) {
destinationZip = pick(rng, ZIP_POOL);
guard += 1;
}
return { originZip, destinationZip };
}
function baseForType(type: Priority1ShipmentType): Priority1DemoInput {
if (type === "ftl") return { ...DEFAULT_FTL_DEMO };
if (type === "expedited") return { ...DEFAULT_EXPEDITED_DEMO };
return { ...DEFAULT_PRIORITY1_DEMO };
}
export function parsePriority1DemoFromEnv(
raw: string | undefined,
): Priority1DemoInput {
if (!raw?.trim()) return DEFAULT_PRIORITY1_DEMO;
try {
const parsed = JSON.parse(raw) as Partial<Priority1DemoInput>;
const base = baseForType(parsed.shipmentType ?? "ltl");
return { ...base, ...parsed };
} catch {
return DEFAULT_PRIORITY1_DEMO;
}
}
export function generateRandomPriority1Cases(
count: number,
seed = Date.now(),
): Array<{ id: string; input: Priority1DemoInput }> {
const rng = mulberry32(seed);
const out: Array<{ id: string; input: Priority1DemoInput }> = [];
for (let i = 0; i < count; i += 1) {
const zips = randomZipPair(rng);
const length = randInt(rng, 36, 96);
const width = randInt(rng, 36, 48);
const height = randInt(rng, 36, 72);
out.push({
id: `P${String(i + 1).padStart(2, "0")}`,
input: {
...DEFAULT_PRIORITY1_DEMO,
...zips,
pickupDate: futurePickupDate(rng),
phone: randomUsPhone(rng),
lengthIn: String(length),
widthIn: String(width),
heightIn: String(height),
weightLb: String(randInt(rng, 150, 1800)),
palletCount: String(randInt(rng, 1, 5)),
freightClass: pick(rng, FREIGHT_CLASSES),
},
});
}
return out;
}
export function generateRandomFtlCases(
count: number,
seed = Date.now(),
): Array<{ id: string; input: Priority1DemoInput }> {
const rng = mulberry32(seed);
const out: Array<{ id: string; input: Priority1DemoInput }> = [];
for (let i = 0; i < count; i += 1) {
const zips = randomZipPair(rng);
const services: FtlAdditionalService[] = [];
if (rng() > 0.5) services.push("full_ftl");
if (rng() > 0.7) services.push("partial_ptl");
out.push({
id: `F${String(i + 1).padStart(2, "0")}`,
input: {
...DEFAULT_FTL_DEMO,
...zips,
pickupDate: futurePickupDate(rng),
phone: randomUsPhone(rng),
commodity: pick(rng, COMMODITIES),
weightLb: String(randInt(rng, 5000, 42000)),
palletCount: String(randInt(rng, 4, 26)),
ftlTrailer: pick(rng, FTL_TRAILERS),
ftlAdditionalServices: services,
},
});
}
return out;
}
export function generateRandomExpeditedCases(
count: number,
seed = Date.now(),
): Array<{ id: string; input: Priority1DemoInput }> {
const rng = mulberry32(seed + 17);
const out: Array<{ id: string; input: Priority1DemoInput }> = [];
for (let i = 0; i < count; i += 1) {
const zips = randomZipPair(rng);
out.push({
id: `E${String(i + 1).padStart(2, "0")}`,
input: {
...DEFAULT_EXPEDITED_DEMO,
...zips,
pickupDate: futurePickupDate(rng),
phone: randomUsPhone(rng),
commodity: pick(rng, COMMODITIES),
weightLb: String(randInt(rng, 200, 3500)),
expeditedTrailer: pick(rng, EXP_TRAILERS),
},
});
}
return out;
}
export function formatPriority1InputSummary(input: Priority1DemoInput): string {
const cfg = getShipmentConfig(input.shipmentType);
const lines = [
`Shipment Type: ${cfg.displayName}`,
`起运 ZIP: ${input.originZip}`,
`目的 ZIP: ${input.destinationZip}`,
`发货频次: ${input.shipmentFrequency}`,
`提货日: ${input.pickupDate}`,
`邮箱: ${input.email}`,
`电话: +1 ${input.phone}`,
];
if (input.shipmentType === "ltl") {
lines.push(
`尺寸: ${input.lengthIn} × ${input.widthIn} × ${input.heightIn} in`,
`总重量: ${input.weightLb} lb`,
`托盘数: ${input.palletCount}`,
`包装: ${input.packaging}`,
`货运等级 Freight Class: ${input.freightClass}`,
`提货地点类型: ${input.pickupLocation}`,
`派送地点类型: ${input.deliveryLocation}`,
`提货附加(勾选): ${input.pickupServices.join("、")}`,
`派送附加(勾选): ${input.deliveryServices.join("、")}`,
);
}
if (input.shipmentType === "ftl") {
lines.push(
`主拖车类型: ${FTL_TRAILER[input.ftlTrailer].label}`,
);
if (input.ftlTrailer === "open_deck") {
lines.push(`Open Deck 子类型: ${input.openDeckSubtype}`);
}
if (input.ftlTrailer === "temperature_controlled") {
lines.push(`温控: ${input.tempMinF}°F ~ ${input.tempMaxF}°F`);
}
if (input.ftlTrailer === "ftl_expedited") {
lines.push(
`Expedited 子车型: ${EXPEDITED_TRAILER[input.ftlExpeditedTrailer].label}`,
);
if (input.expeditedLiftgate && input.ftlExpeditedTrailer === "large_straight") {
lines.push("附加: Liftgate");
}
}
lines.push(
`附加服务: ${
input.ftlAdditionalServices.length
? input.ftlAdditionalServices
.map((s) => FTL_ADDITIONAL[s].label)
.join("、")
: "(无)"
}`,
`货描 Commodity: ${input.commodity}`,
`总重量: ${input.weightLb} lb`,
);
if (input.ftlTrailer !== "ftl_expedited") {
lines.push(`托盘数: ${input.palletCount}`);
}
}
if (input.shipmentType === "expedited") {
lines.push(
`拖车类型: ${EXPEDITED_TRAILER[input.expeditedTrailer].label}`,
`货描 Commodity: ${input.commodity}`,
`总重量: ${input.weightLb} lb`,
);
if (input.expeditedLiftgate && input.expeditedTrailer === "large_straight") {
lines.push("附加: Liftgate");
}
}
return lines.join("\n");
}