/** * 根据运单号前缀推断快递公司(用于发货表单自动选中) * 匹配关键字同时支持公司名与 code(如 shunfeng) */ export type ExpressMatchOption = { id?: number; name?: string; code?: string; }; /** 常见单号前缀 → 公司名 / code 关键字(按前缀长度降序匹配,避免短前缀误伤) */ const PREFIX_RULES: Array<{ prefixes: string[]; keywords: string[] }> = [ { prefixes: ['SF'], keywords: ['顺丰', 'shunfeng', 'sf'] }, { prefixes: ['ZTO', 'ZT'], keywords: ['中通', 'zhongtong', 'zto'] }, { prefixes: ['STO'], keywords: ['申通', 'shentong', 'sto'] }, { prefixes: ['YTO', 'YT'], keywords: ['圆通', 'yuantong', 'yto'] }, { prefixes: ['YD'], keywords: ['韵达', 'yunda', 'yd'] }, { prefixes: ['JD'], keywords: ['京东', 'jd', 'jingdong'] }, { prefixes: ['JT'], keywords: ['极兔', 'jitu', 'jt'] }, { prefixes: ['EMS', 'E'], keywords: ['ems', '邮政'] }, { prefixes: ['HHTT', 'HT'], keywords: ['百世', 'baishi', 'huitong'] }, { prefixes: ['UC'], keywords: ['优速', 'uc'] }, { prefixes: ['DBL'], keywords: ['德邦', 'debang', 'dbl'] }, ]; /** * 按运单号前缀在 options 中找最可能的快递公司 * @returns 匹配到的 option,未匹配返回 null */ export function matchExpressByTrackingNo( trackingNo: string | undefined | null, options: ExpressMatchOption[], ): ExpressMatchOption | null { const no = String(trackingNo || '') .trim() .toUpperCase() .replace(/\s+/g, ''); if (!no || !Array.isArray(options) || !options.length) { return null; } const sortedRules = [...PREFIX_RULES].sort( (a, b) => Math.max(...b.prefixes.map((p) => p.length)) - Math.max(...a.prefixes.map((p) => p.length)), ); let matchedKeywords: string[] | null = null; for (const rule of sortedRules) { if (rule.prefixes.some((p) => no.startsWith(p))) { matchedKeywords = rule.keywords; break; } } if (!matchedKeywords) { return null; } const keywords = matchedKeywords.map((k) => k.toLowerCase()); for (const opt of options) { const name = String(opt.name || '').toLowerCase(); const code = String(opt.code || '').toLowerCase(); if (keywords.some((k) => name.includes(k) || code === k || code.includes(k))) { return opt; } } return null; }