/** 门店筛选用伪区县,禁止写入收货地址 */ 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 '详细地址含「全市」,建议改为具体街道门牌,以免配送拒单'; }