| | |
| | | import java.time.LocalDateTime; |
| | | import java.time.temporal.TemporalAdjusters; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Collections; |
| | | import java.util.Locale; |
| | | |
| | | import com.talentcard.server.business.DatabaseRows; |
| | | import com.talentcard.server.business.PageResult; |
| | | import com.talentcard.server.business.merchant.MerchantTypeCatalog; |
| | | import com.talentcard.server.business.merchant.MerchantTypeCatalog.MerchantType; |
| | | import com.talentcard.server.common.BusinessException; |
| | | import com.talentcard.server.common.ErrorCode; |
| | | import org.jsoup.Jsoup; |
| | |
| | | limit 8 |
| | | """)); |
| | | result.put("recommendedMerchants", query(""" |
| | | select id, merchant_name, merchant_type, logo_url, cover_url, address |
| | | select id, merchant_name, merchant_type_code as merchant_type, logo_url, cover_url, address |
| | | from merchant |
| | | where deleted = 0 and status = 1 and is_recommend = 1 |
| | | order by sort_no desc, id desc |
| | |
| | | } |
| | | } |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select id, merchant_name, merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | select id, merchant_name, merchant_type_code as merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | is_recommend, sort_no, longitude, latitude, business_status, |
| | | (select min(p.sale_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as sale_price, |
| | | (select min(p.original_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as original_price |
| | |
| | | |
| | | @Transactional(readOnly = true) |
| | | public PageResult<Map<String, Object>> foodMerchants(int page, int size, Long talentId) { |
| | | String merchantWhere = " where deleted = 0 and merchant_type in ('food', '餐饮服务')"; |
| | | String merchantWhere = " where deleted = 0 and merchant_type_code = 'food'"; |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select id, merchant_name, merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | select id, merchant_name, merchant_type_code as merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | status, sort_no, longitude, latitude, business_status, |
| | | (select min(p.sale_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as sale_price, |
| | | (select min(p.original_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as original_price |
| | |
| | | |
| | | @Transactional(readOnly = true) |
| | | public PageResult<Map<String, Object>> travelMerchants(int page, int size) { |
| | | String merchantWhere = " where deleted = 0 and merchant_type in ('scenic', '景区服务')"; |
| | | String merchantWhere = " where deleted = 0 and merchant_type_code = 'scenic'"; |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select id, merchant_name, merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | select id, merchant_name, merchant_type_code as merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | status, sort_no, longitude, latitude, business_status, |
| | | (select min(p.sale_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as sale_price, |
| | | (select min(p.original_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as original_price |
| | |
| | | |
| | | @Transactional(readOnly = true) |
| | | public PageResult<Map<String, Object>> stayMerchants(String type, int page, int size, Long talentId) { |
| | | String requestedType = type == null ? "" : type.trim(); |
| | | String requestedType = MerchantTypeCatalog.canonicalCode(type); |
| | | boolean apartment = switch (requestedType) { |
| | | case "hotel", "酒店服务" -> false; |
| | | case "apartment", "公寓租赁", "公寓租赁服务" -> true; |
| | | case "hotel" -> false; |
| | | case "apartment" -> true; |
| | | default -> throw new BusinessException(ErrorCode.BAD_REQUEST, "不支持的住宿服务类型"); |
| | | }; |
| | | String responseMerchantType = apartment ? "apartment" : "hotel"; |
| | | String merchantWhere = apartment |
| | | ? " where deleted = 0 and merchant_type in ('apartment', '公寓租赁', '公寓租赁服务')" |
| | | : " where deleted = 0 and merchant_type in ('hotel', '酒店服务')"; |
| | | String merchantWhere = " where deleted = 0 and merchant_type_code = '" + responseMerchantType + "'"; |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select id, merchant_name, merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | select id, merchant_name, merchant_type_code as merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | status, sort_no, longitude, latitude, business_status, group_buying_enabled, merchant_rights_config, |
| | | (select min(p.sale_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as sale_price, |
| | | (select min(p.original_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as original_price |
| | |
| | | |
| | | @Transactional(readOnly = true) |
| | | public PageResult<Map<String, Object>> entertainmentMerchants(int page, int size) { |
| | | String merchantWhere = " where deleted = 0 and merchant_type in ('cinema', 'theatre', '观影服务', '电影院', '影院', '影城', '剧院')"; |
| | | String merchantWhere = " where deleted = 0 and merchant_type_code = 'cinema'"; |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select id, merchant_name, merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | select id, merchant_name, merchant_type_code as merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | service_label, status, sort_no, longitude, latitude, business_status, |
| | | (select min(p.sale_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as sale_price, |
| | | (select min(p.original_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as original_price |
| | |
| | | |
| | | @Transactional(readOnly = true) |
| | | public PageResult<Map<String, Object>> transportMerchants(String type, int page, int size) { |
| | | if (!List.of("fuel", "parking", "carWash").contains(type)) { |
| | | String requestedType = MerchantTypeCatalog.canonicalCode(type); |
| | | if (!List.of("fuel", "parking", "carWash").contains(requestedType)) { |
| | | throw new BusinessException(ErrorCode.BAD_REQUEST, "不支持的行服务类型"); |
| | | } |
| | | String requestedType = type; |
| | | String merchantWhere = switch (type) { |
| | | case "fuel" -> " where deleted = 0 and merchant_type in ('fuel', '加油服务')"; |
| | | case "parking" -> " where deleted = 0 and merchant_type in ('parking', '停车服务')"; |
| | | case "carWash" -> " where deleted = 0 and merchant_type in ('carWash', '自助洗车', '自助洗车服务')"; |
| | | default -> throw new BusinessException(ErrorCode.BAD_REQUEST, "不支持的行服务类型"); |
| | | }; |
| | | String merchantWhere = " where deleted = 0 and merchant_type_code = '" + requestedType + "'"; |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select id, merchant_name, merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | select id, merchant_name, merchant_type_code as merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | service_label, status, sort_no, longitude, latitude, business_status, merchant_rights_config, |
| | | (select min(p.sale_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as sale_price, |
| | | (select min(p.original_price) from merchant_product p where p.merchant_id = merchant.id and p.deleted = 0 and p.status = 1 and p.audit_status = 2) as original_price |
| | |
| | | where category_key = ? and enabled = 1 and deleted = 0 |
| | | """, Integer.class, categoryId); |
| | | if (categoryCount == 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "不支持的购物服务分类"); |
| | | String merchantTypeFilter = switch (categoryId) { |
| | | case "housing" -> "('购房优惠')"; |
| | | case "car" -> "('购车服务')"; |
| | | case "appliance" -> "('家电服务')"; |
| | | case "digital" -> "('数码服务')"; |
| | | case "book" -> "('文化服务', '图书服务')"; |
| | | default -> "('')"; |
| | | }; |
| | | List<String> merchantTypeCodes = MerchantTypeCatalog.codesForShoppingCategory(categoryId); |
| | | if (merchantTypeCodes.isEmpty()) throw new BusinessException(ErrorCode.BAD_REQUEST, "该购物分类未配置商家类型"); |
| | | String placeholders = String.join(",", java.util.Collections.nCopies(merchantTypeCodes.size(), "?")); |
| | | String merchantWhere = """ |
| | | where m.deleted = 0 |
| | | and (m.merchant_type in %s or (m.merchant_type = 'shopping' and mapping.deleted = 0 and mapping.category_key = ?)) |
| | | """.formatted(merchantTypeFilter); |
| | | and m.merchant_type_code in (%s) |
| | | """.formatted(placeholders); |
| | | List<Object> args = new ArrayList<>(); |
| | | args.add(categoryId); |
| | | args.addAll(merchantTypeCodes); |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select m.id, m.merchant_name, m.merchant_type, m.contact_name, m.contact_mobile, m.logo_url, m.cover_url, m.address, |
| | | select m.id, m.merchant_name, m.merchant_type_code as merchant_type, m.contact_name, m.contact_mobile, m.logo_url, m.cover_url, m.address, |
| | | m.service_label, m.status, m.sort_no, m.longitude, m.latitude, m.business_status |
| | | from merchant m |
| | | left join shopping_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0 and mapping.category_key = ? |
| | | """ + merchantWhere + " order by mapping.sort_no asc, m.sort_no asc, m.id asc", |
| | | "select count(*) from merchant m left join shopping_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0 and mapping.category_key = ? " + merchantWhere, |
| | | page, size, categoryId, categoryId); |
| | | page, size, args.toArray()); |
| | | List<Map<String, Object>> records = result.records().stream().map(row -> { |
| | | Map<String, Object> item = enrichMerchantSearchRow(row); |
| | | item.put("discountText", textOrDefault(item.get("serviceLabel"), "人才专享")); |
| | |
| | | where category_key = ? and enabled = 1 and deleted = 0 |
| | | """, Integer.class, categoryId); |
| | | if (categoryCount == null || categoryCount == 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "不支持的臻享服务分类"); |
| | | String fallbackMerchantType = premiumFallbackMerchantType(categoryId); |
| | | String serviceWhere = """ |
| | | where m.deleted = 0 and ( |
| | | (mapping.deleted = 0 and mapping.category_key = ?) |
| | | or (mapping.id is null and m.merchant_type = ?) |
| | | ) |
| | | """; |
| | | MerchantType merchantType = MerchantTypeCatalog.forPremiumCategory(categoryId) |
| | | .orElseThrow(() -> new BusinessException(ErrorCode.BAD_REQUEST, "该臻享分类未配置商家类型")); |
| | | String serviceWhere = " where m.deleted = 0 and m.merchant_type_code = ?"; |
| | | PageResult<Map<String, Object>> result = page(""" |
| | | select m.id, m.merchant_name, m.merchant_type, m.contact_mobile, m.cover_url, m.address, |
| | | select m.id, m.merchant_name, m.merchant_type_code as merchant_type, m.contact_mobile, m.cover_url, m.address, |
| | | m.service_label, m.status, m.sort_no, m.longitude, m.latitude, |
| | | coalesce(mapping.category_key, case m.merchant_type |
| | | when '免费体检' then 'medical' when '配偶推荐就业' then 'employment' |
| | | when '金融服务' then 'finance' when '行政审批' then 'approval' |
| | | when '学生托付' then 'children' when '子女托管' then 'children' end) as category_key, |
| | | coalesce(mapping.business_type, case m.merchant_type |
| | | when '免费体检' then 'MEDICAL' when '配偶推荐就业' then 'SPOUSE_EMPLOYMENT' |
| | | when '金融服务' then 'FINANCE' when '行政审批' then 'ADMIN_APPROVAL' |
| | | when '学生托付' then 'CHILD_ENTRUSTMENT' when '子女托管' then 'CHILD_ENTRUSTMENT' end) as business_type |
| | | mapping.sort_no as topic_sort_no |
| | | from merchant m |
| | | left join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0 |
| | | left join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0 and mapping.category_key = ? |
| | | """ + serviceWhere + " order by mapping.sort_no asc, m.sort_no asc, m.id asc", |
| | | "select count(*) from merchant m left join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0 " + serviceWhere, |
| | | page, size, categoryId, fallbackMerchantType); |
| | | "select count(*) from merchant m left join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0 and mapping.category_key = ? " + serviceWhere, |
| | | page, size, categoryId, merchantType.code()); |
| | | List<Map<String, Object>> records = result.records().stream().map(row -> { |
| | | Map<String, Object> item = enrichMerchantSearchRow(row); |
| | | item.put("businessType", row.get("businessType")); |
| | | item.put("targetAction", row.get("businessType")); |
| | | item.put("businessType", merchantType.premiumBusinessType()); |
| | | item.put("targetAction", merchantType.premiumBusinessType()); |
| | | item.put("benefitText", textOrDefault(row.get("serviceLabel"), "人才专享")); |
| | | item.put("discountText", textOrDefault(row.get("serviceLabel"), "人才专享")); |
| | | return item; |
| | | }).toList(); |
| | | return new PageResult<>(records, result.page(), result.size(), result.total()); |
| | | } |
| | | |
| | | private String premiumFallbackMerchantType(String categoryId) { |
| | | return switch (categoryId) { |
| | | case "medical" -> "免费体检"; |
| | | case "employment" -> "配偶推荐就业"; |
| | | case "finance" -> "金融服务"; |
| | | case "approval" -> "行政审批"; |
| | | case "children" -> "子女托管"; |
| | | default -> ""; |
| | | }; |
| | | } |
| | | |
| | | private Map<String, Object> enrichMerchantSearchRow(Map<String, Object> row) { |
| | |
| | | } |
| | | |
| | | private String categoryName(String merchantType) { |
| | | return switch (merchantType) { |
| | | case "food", "餐饮服务" -> "暖心食享"; |
| | | case "hotel", "apartment" -> "舒心安居"; |
| | | case "cinema", "theatre" -> "怡乐生活"; |
| | | case "scenic", "景区服务" -> "悦览花城"; |
| | | case "fuel", "parking", "carWash" -> "畅行无忧"; |
| | | case "shopping" -> "惠享好物"; |
| | | case "medical", "finance" -> "臻享礼遇"; |
| | | default -> "其他权益"; |
| | | }; |
| | | return MerchantTypeCatalog.find(merchantType).map(MerchantType::topicName).orElse("其他权益"); |
| | | } |
| | | |
| | | private String appendMerchantTypeFilter(String merchantWhere, List<String> merchantTypes, List<Object> args) { |
| | | if (merchantTypes.size() == 1) { |
| | | args.add(merchantTypes.get(0)); |
| | | return merchantWhere + " and merchant_type = ?"; |
| | | return merchantWhere + " and merchant_type_code = ?"; |
| | | } |
| | | args.addAll(merchantTypes); |
| | | String placeholders = String.join(",", Collections.nCopies(merchantTypes.size(), "?")); |
| | | return merchantWhere + " and merchant_type in (" + placeholders + ")"; |
| | | return merchantWhere + " and merchant_type_code in (" + placeholders + ")"; |
| | | } |
| | | |
| | | private List<String> merchantTypesForRequestedValue(String value) { |
| | | List<String> categoryTypes = merchantTypesForCategory(value); |
| | | return categoryTypes.isEmpty() ? List.of(value) : categoryTypes; |
| | | List<String> types = MerchantTypeCatalog.codesForRequestedValue(value); |
| | | return types.isEmpty() ? List.of("other") : types; |
| | | } |
| | | |
| | | private List<String> merchantTypesForCategory(String value) { |
| | | return switch (value) { |
| | | case "暖心食享", "餐饮服务", "food" -> List.of("food", "餐饮服务"); |
| | | case "舒心安居", "hotel" -> List.of("hotel"); |
| | | case "怡乐生活", "cinema", "theatre" -> List.of("cinema", "theatre"); |
| | | case "悦览花城", "scenic", "景区服务" -> List.of("scenic", "景区服务"); |
| | | case "畅行无忧" -> List.of("fuel", "parking", "carWash"); |
| | | case "fuel" -> List.of("fuel"); |
| | | case "parking" -> List.of("parking"); |
| | | case "carWash" -> List.of("carWash"); |
| | | case "惠享好物", "shopping" -> List.of("shopping"); |
| | | case "臻享礼遇" -> List.of("medical", "finance"); |
| | | case "medical" -> List.of("medical"); |
| | | case "finance" -> List.of("finance"); |
| | | default -> List.of(); |
| | | }; |
| | | return MerchantTypeCatalog.codesForRequestedValue(value); |
| | | } |
| | | |
| | | private String detailType(String merchantType) { |
| | | return switch (merchantType) { |
| | | case "cinema" -> "CINEMA"; |
| | | case "theatre" -> "THEATRE"; |
| | | case "shopping" -> "SHOPPING"; |
| | | case "medical" -> "MEDICAL"; |
| | | case "finance" -> "FINANCE"; |
| | | case "carWash" -> "CAR_WASH"; |
| | | case "fuel" -> "FUEL"; |
| | | case "parking" -> "PARKING"; |
| | | default -> "MERCHANT"; |
| | | }; |
| | | return MerchantTypeCatalog.find(merchantType).map(MerchantType::detailType).orElse("MERCHANT"); |
| | | } |
| | | |
| | | private String targetAction(String merchantType) { |
| | |
| | | @Transactional(readOnly = true) |
| | | public Map<String, Object> merchantDetail(Long id, Long talentId) { |
| | | Map<String, Object> merchant = one(""" |
| | | select id, merchant_name, merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | select id, merchant_name, merchant_type_code as merchant_type, contact_name, contact_mobile, logo_url, cover_url, address, |
| | | business_status, longitude, latitude, group_buying_enabled, usage_instructions, rights_text, merchant_rights_config, |
| | | service_label, status, is_recommend, sort_no |
| | | from merchant |