|
|
import { roundHalfUp } from "@/lib/math";
|
|
|
|
|
|
const KG_TO_LB = 2.20462;
|
|
|
const CM_TO_IN = 2.54;
|
|
|
|
|
|
/** API 可接受的重量单位(canonical) */
|
|
|
export type ApiWeightUnit = "lb" | "kg" | "t";
|
|
|
|
|
|
/** API 可接受的尺寸单位(canonical) */
|
|
|
export type ApiDimUnit = "in" | "cm" | "m";
|
|
|
|
|
|
/**
|
|
|
* 重量单位别名。
|
|
|
* 刻意不收录 ton/tons:北美常指 short ton(2000lb),与公制吨(1000kg)歧义。
|
|
|
* 公制吨请用 t / tonne / tonnes。
|
|
|
*/
|
|
|
const WEIGHT_UNIT_ALIASES: Record<string, ApiWeightUnit> = {
|
|
|
lb: "lb",
|
|
|
lbs: "lb",
|
|
|
pound: "lb",
|
|
|
pounds: "lb",
|
|
|
kg: "kg",
|
|
|
kilogram: "kg",
|
|
|
kilograms: "kg",
|
|
|
t: "t",
|
|
|
tonne: "t",
|
|
|
tonnes: "t",
|
|
|
};
|
|
|
|
|
|
/** ton/tons 歧义提示(不参与换算) */
|
|
|
export function weightUnitAmbiguousMessage(raw: string): string | null {
|
|
|
const key = raw.trim().toLowerCase();
|
|
|
if (key === "ton" || key === "tons") {
|
|
|
return "重量单位 ton/tons 有歧义(美制短吨 vs 公制吨),请使用 t 或 tonne";
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
const DIM_UNIT_ALIASES: Record<string, ApiDimUnit> = {
|
|
|
in: "in",
|
|
|
inch: "in",
|
|
|
inches: "in",
|
|
|
cm: "cm",
|
|
|
centimeter: "cm",
|
|
|
centimeters: "cm",
|
|
|
m: "m",
|
|
|
meter: "m",
|
|
|
meters: "m",
|
|
|
};
|
|
|
|
|
|
/** 解析 API 重量单位(大小写不敏感,支持常见别名) */
|
|
|
export function normalizeWeightUnit(raw: string): ApiWeightUnit | null {
|
|
|
return WEIGHT_UNIT_ALIASES[raw.trim().toLowerCase()] ?? null;
|
|
|
}
|
|
|
|
|
|
/** 解析 API 尺寸单位(大小写不敏感,支持常见别名) */
|
|
|
export function normalizeDimUnit(raw: string): ApiDimUnit | null {
|
|
|
return DIM_UNIT_ALIASES[raw.trim().toLowerCase()] ?? null;
|
|
|
}
|
|
|
|
|
|
/** kg → lb,ROUND_HALF_UP 保留 2 位(GD-13) */
|
|
|
export function kgToLb(kg: number): number {
|
|
|
return roundHalfUp(kg * KG_TO_LB, 2);
|
|
|
}
|
|
|
|
|
|
/** 公制吨 → lb(1 t = 1000 kg) */
|
|
|
export function tToLb(t: number): number {
|
|
|
return kgToLb(t * 1000);
|
|
|
}
|
|
|
|
|
|
/** lb → kg */
|
|
|
export function lbToKg(lb: number): number {
|
|
|
return roundHalfUp(lb / KG_TO_LB, 2);
|
|
|
}
|
|
|
|
|
|
/** cm → in,ROUND_HALF_UP 保留 2 位(GD-13,内部哈希/展示用) */
|
|
|
export function cmToIn(cm: number): number {
|
|
|
return roundHalfUp(cm / CM_TO_IN, 2);
|
|
|
}
|
|
|
|
|
|
/** m → in(经 cm 换算) */
|
|
|
export function mToIn(m: number): number {
|
|
|
return cmToIn(m * 100);
|
|
|
}
|
|
|
|
|
|
/** in → cm */
|
|
|
export function inToCm(inches: number): number {
|
|
|
return roundHalfUp(inches * CM_TO_IN, 2);
|
|
|
}
|
|
|
|
|
|
/** 任意 API 重量单位 → lb(未取整,供 toAxelWholePounds 使用) */
|
|
|
export function weightValueToLb(value: number, unit: ApiWeightUnit): number {
|
|
|
if (unit === "kg") {
|
|
|
return kgToLb(value);
|
|
|
}
|
|
|
if (unit === "t") {
|
|
|
return tToLb(value);
|
|
|
}
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
/** 任意 API 尺寸单位 → in(未取整,供 toAxelWholeInches 使用) */
|
|
|
export function dimValueToIn(value: number, unit: ApiDimUnit): number {
|
|
|
if (unit === "cm") {
|
|
|
return cmToIn(value);
|
|
|
}
|
|
|
if (unit === "m") {
|
|
|
return mToIn(value);
|
|
|
}
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
/** MotherShip axel/quote 与 RPA 表单要求英寸为正整数(向上取整) */
|
|
|
export function toAxelWholeInches(inches: number): number {
|
|
|
return Math.max(1, Math.ceil(inches - Number.EPSILON));
|
|
|
}
|
|
|
|
|
|
/** MotherShip axel/quote 要求磅为正整数(向上取整) */
|
|
|
export function toAxelWholePounds(lb: number): number {
|
|
|
return Math.max(1, Math.ceil(lb - Number.EPSILON));
|
|
|
}
|