yeg
2026-09-28 85bfb9351803d97a33329d507f30a2f78bf1fc75
talent-card-server/src/main/java/com/talentcard/server/business/portal/CarWashMerchantPortalService.java
@@ -41,9 +41,9 @@
      Map<String, Object> merchant = one("""
            select id, merchant_name, contact_mobile, address, cover_url, service_label, rights_text, merchant_rights_config, status
            from merchant
            where id = ? and merchant_type in ('carWash', '自主洗车') and deleted = 0
            where id = ? and merchant_type_code = 'carWash' and deleted = 0
            """, merchantId);
      Map<String, Object> service = one("""
      List<Map<String, Object>> serviceRows = query("""
            select id, talent_levels, service_point_text, tip_text, external_link_type,
                   external_mini_program_app_id, external_mini_program_path, external_web_url,
                   unavailable_reason, status
@@ -51,10 +51,14 @@
            where merchant_id = ? and deleted = 0
            order by id asc limit 1
            """, merchantId);
      Map<String, Object> service = serviceRows.isEmpty() ? Map.of() : serviceRows.get(0);
      String cardLevel = talentCardId == null ? "" : talentCardLevel(talentCardId);
      Map<String, Object> right = matchingRight(merchant.get("merchantRightsConfig"), cardLevel);
      List<Map<String, Object>> rights = parseList(merchant.get("merchantRightsConfig"));
      Map<String, Object> right = matchingRight(rights, cardLevel);
      boolean hasCardRightsConfig = !rights.isEmpty() && !cardLevel.isBlank();
      boolean available = number(merchant.get("status")) == 1
            && number(service.get("status")) == 1
            && (serviceRows.isEmpty() || number(service.get("status")) == 1)
            && (!hasCardRightsConfig || right != null)
            && (right == null || booleanValue(right.get("enabled")));
      Map<String, Object> result = new LinkedHashMap<>();
      result.put("merchantId", merchant.get("id"));
@@ -67,27 +71,61 @@
      result.put("servicePointText", servicePointText(right, service));
      result.put("tipText", tipText(right, service));
      result.put("rightsText", rightsText(merchant, right, service));
      applyExternalLink(result, service);
      applyExternalLink(result, merchant, service);
      return result;
   }
   private void applyExternalLink(Map<String, Object> result, Map<String, Object> service) {
      String type = text(service.get("externalLinkType"), "");
      if ("miniProgram".equals(type)) {
         String appId = text(service.get("externalMiniProgramAppId"), "");
         if (appId.matches("^wx[a-zA-Z0-9]{16}$")) {
   private void applyExternalLink(Map<String, Object> result, Map<String, Object> merchant, Map<String, Object> service) {
      Map<String, Object> config = carWashJumpConfig(merchant);
      if (config != null) {
         String type = text(config.get("externalLinkType"), "");
         if ("miniProgram".equals(type)) {
            String shortLink = text(config.get("externalMiniProgramShortLink"), "");
            if (!shortLink.isBlank()) {
               result.put("externalLinkType", "miniProgram");
               result.put("externalMiniProgramAppId", "");
               result.put("externalMiniProgramShortLink", shortLink);
               result.put("externalMiniProgramPath", text(config.get("externalMiniProgramPath"), ""));
               result.put("externalWebUrl", "");
               return;
            }
         }
         if ("web".equals(type)) {
            String webUrl = text(config.get("externalWebUrl"), "");
            if (isAllowedWebUrl(webUrl)) {
               result.put("externalLinkType", "web");
               result.put("externalMiniProgramAppId", "");
               result.put("externalMiniProgramShortLink", "");
               result.put("externalMiniProgramPath", "");
               result.put("externalWebUrl", webUrl);
               return;
            }
         }
         result.put("externalLinkType", "");
         result.put("externalMiniProgramAppId", "");
         result.put("externalMiniProgramShortLink", "");
         result.put("externalMiniProgramPath", "");
         result.put("externalWebUrl", "");
         return;
      }
      String legacyType = text(service.get("externalLinkType"), "");
      if ("miniProgram".equals(legacyType)) {
         String shortLink = text(service.get("externalMiniProgramShortLink"), "");
         if (!shortLink.isBlank()) {
            result.put("externalLinkType", "miniProgram");
            result.put("externalMiniProgramAppId", appId);
            result.put("externalMiniProgramAppId", "");
            result.put("externalMiniProgramShortLink", shortLink);
            result.put("externalMiniProgramPath", text(service.get("externalMiniProgramPath"), ""));
            result.put("externalWebUrl", "");
            return;
         }
      }
      if ("web".equals(type)) {
      if ("web".equals(legacyType)) {
         String webUrl = text(service.get("externalWebUrl"), "");
         if (isAllowedWebUrl(webUrl)) {
            result.put("externalLinkType", "web");
            result.put("externalMiniProgramAppId", "");
            result.put("externalMiniProgramShortLink", "");
            result.put("externalMiniProgramPath", "");
            result.put("externalWebUrl", webUrl);
            return;
@@ -95,6 +133,7 @@
      }
      result.put("externalLinkType", "");
      result.put("externalMiniProgramAppId", "");
      result.put("externalMiniProgramShortLink", "");
      result.put("externalMiniProgramPath", "");
      result.put("externalWebUrl", "");
   }
@@ -120,7 +159,7 @@
         String consumeDesc = text(right.get("consumeDesc"), "");
         if (!consumeDesc.isBlank()) return consumeDesc;
      }
      return text(service.get("tipText"), "请按现场指引操作");
      return text(service.get("tipText"), "到店后按现场指引操作,可直接享受洗车权益。");
   }
   private String rightsText(Map<String, Object> merchant, Map<String, Object> right, Map<String, Object> service) {
@@ -144,12 +183,10 @@
      return "洗车权益当前不可用";
   }
   private Map<String, Object> matchingRight(Object rightsConfig, String cardLevel) {
      List<Map<String, Object>> rights = parseList(rightsConfig);
   private Map<String, Object> matchingRight(List<Map<String, Object>> rights, String cardLevel) {
      if (rights.isEmpty() || cardLevel == null || cardLevel.isBlank()) return null;
      String normalizedCardLevel = normalizedCardLevel(cardLevel);
      for (Map<String, Object> right : rights) {
         if (!booleanValue(right.get("enabled"))) continue;
         if (normalizedCardLevel.equals(normalizedCardLevel(text(right.get("level"), "")))) return right;
      }
      return null;
@@ -180,6 +217,19 @@
         result.put(String.valueOf(entry.getKey()), entry.getValue());
      }
      return result;
   }
   private Map<String, Object> carWashJumpConfig(Map<String, Object> merchant) {
      List<Map<String, Object>> rights = parseList(merchant.get("merchantRightsConfig"));
      for (Map<String, Object> right : rights) {
         if (right.containsKey("externalLinkType")
               || right.containsKey("externalMiniProgramShortLink")
               || right.containsKey("externalMiniProgramPath")
               || right.containsKey("externalWebUrl")) {
            return right;
         }
      }
      return null;
   }
   private String normalizedCardLevel(String value) {
@@ -229,4 +279,4 @@
      String text = String.valueOf(value).trim();
      return text.isEmpty() ? fallback : text;
   }
}
}