diff --git a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmHotelMidServiceImpl.java b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmHotelMidServiceImpl.java index 759ccc061..352394b91 100644 --- a/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmHotelMidServiceImpl.java +++ b/pjcloud-supermarket/pjcloud-supermarket-biz/src/main/java/com/bsd/pjcloud/supermarket/service/impl/SmHotelMidServiceImpl.java @@ -59,10 +59,11 @@ public class SmHotelMidServiceImpl implements SmHotelMidService { private static final int LOCAL_DAILY_BATCH_MAX_DAYS = 366; /** - * 环启 cityName:从「省市区」串中取地级市短名(2~4 字 + 市),再去掉「市」。 - * 例:山东省青岛市城阳区 → 青岛;恩施市 → 恩施。 + * 拆「位置区域」拼接文案为级联各层:省 / 市(州) / 区县。 + * 例:湖北省恩施土家族苗族自治州恩施市 → [湖北省, 恩施土家族苗族自治州, 恩施市] */ - private static final Pattern HUANQI_CITY_PATTERN = Pattern.compile("([\\u4e00-\\u9fa5]{2,4})市"); + private static final Pattern AREA_SEGMENT_PATTERN = Pattern.compile( + "[\\u4e00-\\u9fa5]+?(?:省|自治区|特别行政区|自治州|地区|盟|市|区|县|旗)"); private final ShangyouHotelClient upstreamClient; @@ -501,8 +502,10 @@ public class SmHotelMidServiceImpl implements SmHotelMidService { if (StrUtil.isNotBlank(hotel.getPhone())) { hotelBody.put("hotelPhone", hotel.getPhone()); } - if (StrUtil.isNotBlank(hotel.getAddress())) { - hotelBody.put("address", hotel.getAddress()); + // 环启 address 要完整:位置区域 + 详细地址(表单里 address 往往只有「航空大道188号」) + String fullAddress = buildHuanqiFullAddress(hotel.getDistrict(), hotel.getAddress()); + if (StrUtil.isNotBlank(fullAddress)) { + hotelBody.put("address", fullAddress); } if (StrUtil.isNotBlank(hotel.getDistrict())) { hotelBody.put("cityName", hotel.getDistrict()); @@ -513,11 +516,15 @@ public class SmHotelMidServiceImpl implements SmHotelMidService { if (StrUtil.isBlank(cityName)) { cityName = StrUtil.trim(hotel.getDistrict()); } - // 环启要求只传市一级短名,且不要带「市」:恩施市 → 恩施 - cityName = normalizeHuanqiCityName(cityName); + // 环启:只取位置区域里「市级」那一层,再去掉「市」(恩施市→恩施;青岛市城阳区→青岛) + cityName = extractHuanqiCityNameFromDistrict(cityName); String address = StrUtil.trim(strObj(hotelBody.get("address"))); if (StrUtil.isBlank(address)) { - address = StrUtil.trim(hotel.getAddress()); + address = buildHuanqiFullAddress(hotel.getDistrict(), hotel.getAddress()); + } + else { + // remark 里若只写了短地址,同样补全区县前缀 + address = buildHuanqiFullAddress(hotel.getDistrict(), address); } String phone = StrUtil.trim(strObj(hotelBody.get("hotelPhone"))); if (StrUtil.isBlank(phone)) { @@ -1844,31 +1851,95 @@ public class SmHotelMidServiceImpl implements SmHotelMidService { } /** - * 环启 cityName 规范化:只保留市一级短名,去掉后缀「市」。 + * 环启 address:位置区域全文 + 详细地址。 + * 表单「详细地址」常只有路名门牌(如航空大道188号),必须拼上「湖北省…恩施市」。 + */ + static String buildHuanqiFullAddress(String district, String detailAddress) { + String area = StrUtil.trim(district); + String detail = StrUtil.trim(detailAddress); + if (StrUtil.isBlank(area) && StrUtil.isBlank(detail)) { + return ""; + } + if (StrUtil.isBlank(area)) { + return detail; + } + if (StrUtil.isBlank(detail)) { + return area; + } + // 已是完整地址(含区县或已带区域前缀)则不再重复拼接 + if (detail.contains(area) || detail.startsWith(area)) { + return detail; + } + // 详细地址已含省/市/区字样,视为已写全 + if (detail.contains("省") || detail.contains("自治区") || (detail.contains("市") && detail.contains("区"))) { + return detail; + } + return area + detail; + } + + /** + * 从位置区域文案取「市级」层名称并去掉「市」。 + *

+ * 规则:先按省/市/州/区县拆层;优先取以「市」结尾的那一层(县级市如恩施市也算); + * 若只有区县(如城阳区),则退回上一层地级市(青岛市)。 + *

* */ - static String normalizeHuanqiCityName(String raw) { - if (StrUtil.isBlank(raw)) { + static String extractHuanqiCityNameFromDistrict(String district) { + if (StrUtil.isBlank(district)) { return ""; } - String s = raw.trim().replace(" ", ""); - Matcher m = HUANQI_CITY_PATTERN.matcher(s); - String last = null; + String s = district.trim().replace(" ", ""); + List segments = splitAreaSegments(s); + if (segments.isEmpty()) { + return stripCitySuffix(s); + } + // 1) 优先:名称以「市」结尾的层(青岛市 / 恩施市 / 北京市) + for (int i = segments.size() - 1; i >= 0; i--) { + String seg = segments.get(i); + if (seg.endsWith("市") && !seg.endsWith("市辖区")) { + return stripCitySuffix(seg); + } + } + // 2) 次选:地级「地区/盟」(极少);自治州不作为环启 cityName(对方要的是市短名) + for (int i = segments.size() - 1; i >= 0; i--) { + String seg = segments.get(i); + if (seg.endsWith("地区") || seg.endsWith("盟")) { + return seg.replaceAll("(地区|盟)$", ""); + } + } + // 3) 兜底:最后一层去掉区县后缀 + return stripCitySuffix(segments.get(segments.size() - 1)); + } + + /** 湖北省恩施土家族苗族自治州恩施市 → [湖北省, 恩施土家族苗族自治州, 恩施市] */ + static List splitAreaSegments(String concatenated) { + List list = new ArrayList<>(); + if (StrUtil.isBlank(concatenated)) { + return list; + } + Matcher m = AREA_SEGMENT_PATTERN.matcher(concatenated.trim()); while (m.find()) { - last = m.group(1); + list.add(m.group()); } - if (StrUtil.isNotBlank(last)) { - return last; + return list; + } + + /** 去掉末尾「市」(仅去一层后缀,不碰自治州等) */ + static String stripCitySuffix(String name) { + if (StrUtil.isBlank(name)) { + return ""; } - // 已是「xx市」整串、或误写成带市后缀 - if (s.endsWith("市") && s.length() > 1) { - return s.substring(0, s.length() - 1); + String n = name.trim(); + if (n.endsWith("市") && !n.endsWith("市辖区") && n.length() > 1) { + return n.substring(0, n.length() - 1); } - return s; + n = n.replaceAll("(区|县|旗)$", ""); + return n.trim(); } private static class DailyDraft {