From 749b314cebf249fd9a648aa6643bdd667f2ad80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Wed, 14 Oct 2026 13:06:09 +0800 Subject: [PATCH] =?UTF-8?q?:bug:=20=E8=A1=A5=E5=85=85=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E9=81=97=E6=BC=8F=E7=9A=84=20region-address=20=E4=B8=8E=20rout?= =?UTF-8?q?e-change=20=E5=B7=A5=E5=85=B7=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/region-address.js | 89 +++++++++++++++++++++++++++++++++++++ src/utils/route-change.js | 29 ++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/utils/region-address.js create mode 100644 src/utils/route-change.js diff --git a/src/utils/region-address.js b/src/utils/region-address.js new file mode 100644 index 0000000..28c8ef5 --- /dev/null +++ b/src/utils/region-address.js @@ -0,0 +1,89 @@ +/** + * 行政区划展示格式化(仅展示层,不改动后端存储值)。 + * + * 需求:省 / 市 / 区县之间要有空格隔开,避免「上海市浦东新区」「广西壮族自治区南宁市邕宁区」挤成一坨。 + * 与全站既有规则保持一致(公路地址按「市 区县」展示,省/自治区不重复展示): + * 上海市浦东新区 -> 上海市 浦东新区 + * 广西壮族自治区南宁市邕宁区 -> 南宁市 邕宁区 + * 梅州市梅县区 -> 梅州市 梅县区 + * + * 非纯行政区划串(站点名「南宁站」「广州南站」、含街道门牌的详细地址等)原样返回,不做任何改动。 + */ + +// 行政区划后缀:长后缀在前,避免「自治区」被截成「区」、「自治州」被截成「州」 +const REGION_SUFFIXES = [ + '特别行政区', + '自治区', + '自治州', + '自治县', + '自治旗', + '开发区', + '新区', + '林区', + '矿区', + '地区', + '省', + '市', + '州', + '盟', + '区', + '县', + '旗', +]; + +// 省级区划:展示时不在区划链首重复(「广西壮族自治区南宁市邕宁区」-> 「南宁市 邕宁区」) +const PROVINCE_SUFFIX = /(?:省|自治区|特别行政区)$/; + +/** + * 从文本头部匹配第一个行政区划片段。 + * 特例:「梅州市」州后紧跟市,并入同一片段;「梅县区」县/旗后紧跟区,并入同一片段。 + * @param {string} text 已去除空白的文本 + * @returns {string} 片段,未匹配到返回 '' + */ +function matchRegionToken(text) { + for (let end = 0; end < text.length; end += 1) { + const prefix = text.slice(0, end + 1); + const suffix = REGION_SUFFIXES.find(item => prefix.endsWith(item)); + if (!suffix) continue; + const next = text[end + 1] || ''; + if ((suffix === '州' || suffix === '盟') && next === '市') continue; + if ((suffix === '县' || suffix === '旗') && next === '区') return text.slice(0, end + 2); + return prefix; + } + return ''; +} + +/** + * 按行政区划后缀把文本切成区划片段。 + * @param {string} value 原值 + * @returns {string[]|null} 整串都是行政区划时返回片段数组,否则返回 null + */ +export function splitRegionTokens(value) { + const text = String(value ?? '').replace(/\s+/g, ''); + if (!text) return null; + const tokens = []; + let rest = text; + while (rest) { + const token = matchRegionToken(rest); + if (!token) return null; + tokens.push(token); + rest = rest.slice(token.length); + } + return tokens; +} + +/** + * 行政区划串按「市 区县」展示,省/自治区不重复展示。 + * @param {string} value 原值 + * @returns {string} 含空格的展示值;非纯行政区划串原样返回 + */ +export function formatRegionAddress(value) { + const text = String(value ?? '').trim(); + if (!text) return ''; + const tokens = splitRegionTokens(text); + if (!tokens || !tokens.length) return text; + const display = PROVINCE_SUFFIX.test(tokens[0]) ? tokens.slice(1) : tokens; + return (display.length ? display : tokens).join(' '); +} + +export default formatRegionAddress; diff --git a/src/utils/route-change.js b/src/utils/route-change.js new file mode 100644 index 0000000..4f59fbf --- /dev/null +++ b/src/utils/route-change.js @@ -0,0 +1,29 @@ +/** + * 路线变更记录内容格式化 + * + * 存储格式(单行): + * YD-20260904-0022:发货地 A → B;到货地 C → D;YD-20260904-0025:发货地 E → F;到货地 G → H + * + * 展示格式(变更前 / 变更后分行): + * YD-20260904-0022:发货地 A → + * B + * 到货地 C → + * D + * + * 说明:仅用于展示层,不改变已存储的 content 文本(历史数据同样适用)。 + */ +export const formatRouteChangeContent = (content, emptyText = '-') => { + if (content === undefined || content === null) return emptyText; + const text = String(content).trim(); + if (!text) return emptyText; + + return text + .replace(/\r\n?/g, '\n') + // 多条记录之间换行 + .replace(/[ \t]*[;;][ \t]*/g, '\n') + // 变更前地址 / 变更后地址分行(箭头保留在上一行行尾) + .replace(/[ \t]*[-—]+>[ \t]*|[ \t]*→[ \t]*/g, ' →\n') + .replace(/\n{2,}/g, '\n') + .replace(/[ \t]+\n/g, '\n') + .trim(); +};