c6b01def4c
CI / verify (push) Has been cancelled
拦截伪区县写入与下单;推单失败挂 fulfillmentHold,HQ 可见超区/推单失败。 Co-authored-by: Cursor <cursoragent@cursor.com>
76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
/** 门店筛选用伪区县,禁止写入收货地址 */
|
|
export const PSEUDO_SHIPPING_DISTRICTS = ['全市', '全部'] as const;
|
|
|
|
export const SHIPPING_DETAIL_MIN_LEN = 8;
|
|
|
|
export const SHIPPING_REGION_REQUIRED_MSG = '请选择具体区县';
|
|
export const SHIPPING_DETAIL_REQUIRED_MSG = '请填写详细地址';
|
|
export const SHIPPING_DETAIL_TOO_SHORT_MSG = '请填写更详细的收货地址(含街道门牌)';
|
|
|
|
export type ShippingAddressFields = {
|
|
province?: string | null;
|
|
city?: string | null;
|
|
district?: string | null;
|
|
detail?: string | null;
|
|
};
|
|
|
|
export type ShippingAddressValidation = {
|
|
ok: boolean;
|
|
message?: string;
|
|
};
|
|
|
|
function trim(v: string | null | undefined): string {
|
|
return String(v ?? '').trim();
|
|
}
|
|
|
|
export function isPseudoShippingDistrict(district: string | null | undefined): boolean {
|
|
const d = trim(district);
|
|
if (!d) return true;
|
|
return (PSEUDO_SHIPPING_DISTRICTS as readonly string[]).includes(d);
|
|
}
|
|
|
|
/** 区县是否可作为收货地址(非空且非全市/全部) */
|
|
export function isConcreteShippingDistrict(district: string | null | undefined): boolean {
|
|
return !isPseudoShippingDistrict(district);
|
|
}
|
|
|
|
/**
|
|
* 校验收货省市区 + 详细地址。
|
|
* - 现场取货等特殊值请勿调用本函数
|
|
* - 不依赖完整省市区树;前端另做树内白名单
|
|
*/
|
|
export function validateShippingAddress(
|
|
input: ShippingAddressFields,
|
|
options?: { requireDetail?: boolean },
|
|
): ShippingAddressValidation {
|
|
const province = trim(input.province);
|
|
const city = trim(input.city);
|
|
const district = trim(input.district);
|
|
const detail = trim(input.detail);
|
|
const requireDetail = options?.requireDetail !== false;
|
|
|
|
if (!province || !city) {
|
|
return { ok: false, message: '请选择所在地区' };
|
|
}
|
|
if (!isConcreteShippingDistrict(district)) {
|
|
return { ok: false, message: SHIPPING_REGION_REQUIRED_MSG };
|
|
}
|
|
if (requireDetail) {
|
|
if (!detail) {
|
|
return { ok: false, message: SHIPPING_DETAIL_REQUIRED_MSG };
|
|
}
|
|
if (detail.length < SHIPPING_DETAIL_MIN_LEN) {
|
|
return { ok: false, message: SHIPPING_DETAIL_TOO_SHORT_MSG };
|
|
}
|
|
}
|
|
return { ok: true };
|
|
}
|
|
|
|
/** 详细地址含「全市」时的软提示(不单独作为硬失败条件) */
|
|
export function shippingDetailCityWideHint(detail: string | null | undefined): string | null {
|
|
const d = trim(detail);
|
|
if (!d.includes('全市')) return null;
|
|
if (/路|街|巷|号|大厦|广场|小区|村|镇|乡/.test(d)) return null;
|
|
return '详细地址含「全市」,建议改为具体街道门牌,以免配送拒单';
|
|
}
|