|
|
@@ -0,0 +1,171 @@
|
|
|
+/**
|
|
|
+ * 地址解析工具 - 使用关键词匹配方式解析省市区地址
|
|
|
+ * 思路:通过省市区关键词截取,去两边留中间
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * 解析连续文本格式的地址
|
|
|
+ * @param {string} fullAddress 完整地址字符串,如:山西省太原市迎泽区庙前街道劲松北路9号院
|
|
|
+ * @returns {Object|null} 解析后的地址信息
|
|
|
+ */
|
|
|
+export const parseAddress = (fullAddress) => {
|
|
|
+ if (!fullAddress || typeof fullAddress !== 'string') {
|
|
|
+ console.warn('地址不能为空且必须为字符串');
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 定义省市区关键词
|
|
|
+ const provinceKeywords = /省|自治区|特别行政区/;
|
|
|
+ const cityKeywords = /市|自治州|地区|盟/;
|
|
|
+ const districtKeywords = /区|县|旗|自治县|自治旗|特区|林区/;
|
|
|
+
|
|
|
+ // 1. 解析省份
|
|
|
+ const provinceEndIndex = fullAddress.search(provinceKeywords);
|
|
|
+ if (provinceEndIndex === -1) {
|
|
|
+ // 处理直辖市情况
|
|
|
+ const cityStartIndex = fullAddress.search(cityKeywords);
|
|
|
+ if (cityStartIndex === -1) {
|
|
|
+ console.warn('无法识别省份或城市');
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // 直辖市情况:如北京市海淀区
|
|
|
+ const province = fullAddress.substring(0, cityStartIndex + 1);
|
|
|
+ const city = province;
|
|
|
+
|
|
|
+ // 解析区县
|
|
|
+ const districtEndIndex = fullAddress.search(districtKeywords);
|
|
|
+ if (districtEndIndex === -1) {
|
|
|
+ console.warn('无法识别区县');
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const district = fullAddress.substring(city.length, districtEndIndex + 1);
|
|
|
+ const street = fullAddress.substring(districtEndIndex + 1).trim();
|
|
|
+
|
|
|
+ return {
|
|
|
+ province,
|
|
|
+ city,
|
|
|
+ district,
|
|
|
+ street: street || undefined
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 解析城市
|
|
|
+ const province = fullAddress.substring(0, provinceEndIndex + 1);
|
|
|
+ const remainingAfterProvince = fullAddress.substring(provinceEndIndex + 1);
|
|
|
+
|
|
|
+ const cityEndIndex = remainingAfterProvince.search(cityKeywords);
|
|
|
+ if (cityEndIndex === -1) {
|
|
|
+ console.warn('无法识别城市');
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const city = remainingAfterProvince.substring(0, cityEndIndex + 1);
|
|
|
+ const remainingAfterCity = remainingAfterProvince.substring(cityEndIndex + 1);
|
|
|
+
|
|
|
+ // 3. 解析区县
|
|
|
+ const districtEndIndex = remainingAfterCity.search(districtKeywords);
|
|
|
+ if (districtEndIndex === -1) {
|
|
|
+ console.warn('无法识别区县');
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ const district = remainingAfterCity.substring(0, districtEndIndex + 1);
|
|
|
+ const street = remainingAfterCity.substring(districtEndIndex + 1).trim();
|
|
|
+
|
|
|
+ return {
|
|
|
+ province,
|
|
|
+ city,
|
|
|
+ district,
|
|
|
+ street: street || undefined
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 仅获取省份名称
|
|
|
+ * @param {string} fullAddress 完整地址字符串
|
|
|
+ * @returns {string|null} 省份名称
|
|
|
+ */
|
|
|
+export const getProvince = (fullAddress) => {
|
|
|
+ const result = parseAddress(fullAddress);
|
|
|
+ return result?.province || null;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 仅获取城市名称
|
|
|
+ * @param {string} fullAddress 完整地址字符串
|
|
|
+ * @returns {string|null} 城市名称
|
|
|
+ */
|
|
|
+export const getCity = (fullAddress) => {
|
|
|
+ const result = parseAddress(fullAddress);
|
|
|
+ return result?.city || null;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 仅获取区县名称
|
|
|
+ * @param {string} fullAddress 完整地址字符串
|
|
|
+ * @returns {string|null} 区县名称
|
|
|
+ */
|
|
|
+export const getDistrict = (fullAddress) => {
|
|
|
+ const result = parseAddress(fullAddress);
|
|
|
+ return result?.district || null;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取解析后的省市区数组(用于回显)
|
|
|
+ * @param {string} fullAddress 完整地址字符串
|
|
|
+ * @returns {Array} 省市区数组
|
|
|
+ */
|
|
|
+export const getAddressTree = (fullAddress) => {
|
|
|
+ const result = parseAddress(fullAddress);
|
|
|
+ if (!result) return [];
|
|
|
+ return [result.province, result.city, result.district];
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 递归查找城市名称对应的areaCode
|
|
|
+ * @param {string} cityName 城市名称
|
|
|
+ * @param {Array} areaTree 省市区联级列表数据
|
|
|
+ * @returns {string} 匹配到的areaCode,匹配不到返回空字符串
|
|
|
+ */
|
|
|
+export const findCityCodeByCname = (cityName, areaTree) => {
|
|
|
+ // 边界条件检查
|
|
|
+ if (!cityName || !areaTree || !Array.isArray(areaTree)) {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ // 遍历当前层级
|
|
|
+ for (const area of areaTree) {
|
|
|
+ // 匹配到城市名称,返回areaCode
|
|
|
+ if (area.areaCname == cityName) {
|
|
|
+ return area.areaCode;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有子节点,递归查找
|
|
|
+ if (area.children && area.children.length > 0) {
|
|
|
+ const foundCode = findCityCodeByCname(cityName, area.children);
|
|
|
+ if (foundCode) {
|
|
|
+ return foundCode;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 所有节点都遍历完,没有匹配到
|
|
|
+ return '';
|
|
|
+};
|
|
|
+
|
|
|
+// Vue 2 插件形式
|
|
|
+const AddressParserPlugin = {
|
|
|
+ install(Vue) {
|
|
|
+ Vue.prototype.$parseAddress = parseAddress;
|
|
|
+ Vue.prototype.$getProvince = getProvince;
|
|
|
+ Vue.prototype.$getCity = getCity;
|
|
|
+ Vue.prototype.$getDistrict = getDistrict;
|
|
|
+ Vue.prototype.$getAddressTree = getAddressTree;
|
|
|
+ Vue.prototype.$findCityCodeByCname = findCityCodeByCname;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 如果是在浏览器环境下直接使用
|
|
|
+if (typeof window !== 'undefined' && window.Vue) {
|
|
|
+ window.Vue.use(AddressParserPlugin);
|
|
|
+}
|
|
|
+
|
|
|
+// 导出插件形式
|
|
|
+export default AddressParserPlugin;
|