From bc2efbdb52190fe2e7be9920bbed6902d4ee28aa Mon Sep 17 00:00:00 2001
From: shinnosuke <tantao@1hoper.com>
Date: 星期五, 21 八月 2026 11:53:37 +0800
Subject: [PATCH] fix: centralize merchant type integration
---
talent-card-server/src/main/resources/db/migration/V118__resync_premium_topic_merchant_mappings.sql | 27 +
talent-card-server/src/main/java/com/talentcard/server/mapper/ServiceApplicationMapper.java | 2
talent-card-server/src/main/java/com/talentcard/server/business/portal/ChildrenEntrustmentPortalService.java | 4
talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantTypeCatalog.java | 155 +++++++++++
talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantSettlementStatisticsMapper.java | 6
talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantDisplayPolicyMerchantMapper.java | 8
talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashCredentialMapper.java | 4
talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashServiceMapper.java | 12
talent-card-server/src/main/java/com/talentcard/server/mapper/DisplayServiceMapper.java | 87 -----
talent-card-server/src/main/java/com/talentcard/server/business/portal/CinemaPortalService.java | 4
talent-card-server/src/main/java/com/talentcard/server/service/BenefitQuotaService.java | 4
talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingCardLevelRightMapper.java | 10
talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyAdminService.java | 10
talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java | 12
talent-card-server/src/main/java/com/talentcard/server/business/portal/UsageRecordPortalService.java | 2
talent-card-server/src/test/java/com/talentcard/server/business/admin/AdminBusinessServiceTests.java | 4
talent-card-server/src/main/resources/db/migration/V119__add_canonical_merchant_type_code.sql | 53 +++
talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java | 92 ++++--
talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingPlateRegistrationMapper.java | 2
talent-card-server/src/main/java/com/talentcard/server/business/portal/SpouseEmploymentPortalService.java | 3
talent-card-server/src/main/java/com/talentcard/server/business/portal/CarWashMerchantPortalService.java | 2
talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyPortalService.java | 10
talent-card-admin/src/views/MerchantCreateView.vue | 1
talent-card-server/src/main/java/com/talentcard/server/business/portal/AdminApprovalPortalService.java | 5
talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantTypeCatalogTests.java | 65 ++++
rencaika/pages/family-card-apply/family-card-apply.uvue | 18
talent-card-server/src/main/java/com/talentcard/server/business/portal/PortalService.java | 158 +++-------
talent-card-server/src/main/java/com/talentcard/server/business/portal/FinanceMerchantPortalService.java | 3
talent-card-server/src/main/java/com/talentcard/server/business/portal/FuelMerchantPortalService.java | 4
talent-card-server/src/main/java/com/talentcard/server/business/portal/MedicalPackagePortalService.java | 8
talent-card-server/src/main/java/com/talentcard/server/business/portal/ShoppingMerchantPortalService.java | 11
talent-card-server/src/main/java/com/talentcard/server/business/portal/ParkingMerchantPortalService.java | 2
32 files changed, 503 insertions(+), 285 deletions(-)
diff --git a/rencaika/pages/family-card-apply/family-card-apply.uvue b/rencaika/pages/family-card-apply/family-card-apply.uvue
index ae872a8..4aa4fd6 100644
--- a/rencaika/pages/family-card-apply/family-card-apply.uvue
+++ b/rencaika/pages/family-card-apply/family-card-apply.uvue
@@ -15,7 +15,7 @@
<view class="input-box"><input v-model="form.name" maxlength="20" placeholder="请输入姓名" placeholder-class="input-placeholder" /></view>
<text class="field-label">身份证号</text>
- <view class="input-box"><input :value="form.idCard" maxlength="18" placeholder="请输入身份证号" placeholder-class="input-placeholder" @input="handleIdCardInput" /></view>
+ <view class="input-box"><input :value="form.idCard" type="idcard" maxlength="18" placeholder="请输入身份证号" placeholder-class="input-placeholder" @input="handleIdCardInput" /></view>
<text class="field-label">手机号</text>
<view class="input-box"><input v-model="form.phone" type="number" maxlength="11" placeholder="请输入手机号" placeholder-class="input-placeholder" /></view>
@@ -52,6 +52,14 @@
const talentCardId = ref('')
const applicationId = ref('')
const auditRemark = ref('')
+ const normalizeIdCard = (value: string): string => {
+ const raw = value.toUpperCase().replace(/[^0-9X]/g, '')
+ const xIndex = raw.indexOf('X')
+ if (xIndex >= 17) {
+ return raw.substring(0, xIndex).replace(/[^0-9]/g, '').slice(0, 17) + 'X'
+ }
+ return raw.replace(/[^0-9]/g, '').slice(0, 18)
+ }
onLoad((options: any) => {
// #ifdef MP-WEIXIN
@@ -81,7 +89,7 @@
if (data == null) return
const next = form.value
next.name = data.dependentName != null ? data.dependentName : ''
- next.idCard = data.dependentIdCardNo != null ? data.dependentIdCardNo : ''
+ next.idCard = data.dependentIdCardNo != null ? normalizeIdCard('' + data.dependentIdCardNo) : ''
next.phone = data.dependentMobile != null ? data.dependentMobile : ''
next.relation = data.relation != null ? data.relation : ''
form.value = next
@@ -98,11 +106,7 @@
form.value = next
}
const handleIdCardInput = (event: any) => {
- const raw = (event.detail.value as string).toUpperCase()
- let normalized = raw.replace(/[^0-9X]/g, '').slice(0, 18)
- if (normalized.indexOf('X') >= 0 && (normalized.length != 18 || !normalized.endsWith('X'))) {
- normalized = normalized.replace(/X/g, '')
- }
+ const normalized = normalizeIdCard(event.detail.value as string)
const next = form.value
next.idCard = normalized
form.value = next
diff --git a/talent-card-admin/src/views/MerchantCreateView.vue b/talent-card-admin/src/views/MerchantCreateView.vue
index 53f9c31..1c598b7 100644
--- a/talent-card-admin/src/views/MerchantCreateView.vue
+++ b/talent-card-admin/src/views/MerchantCreateView.vue
@@ -109,6 +109,7 @@
const supportsMerchantAppLogin = computed(() => (
isServiceMerchant.value
|| isApartmentMerchant.value
+ || isHotelMerchant.value
|| isCarWashMerchant.value
|| isHealthCheckMerchant.value
|| isParkingMerchant.value
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java b/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
index 4f05581..5a3e462 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/admin/AdminBusinessService.java
@@ -17,6 +17,8 @@
import com.alibaba.fastjson.JSON;
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.business.merchant.auth.MerchantPasswordHasher;
import com.talentcard.server.common.BusinessException;
import com.talentcard.server.common.ErrorCode;
@@ -28,12 +30,6 @@
@Service
public class AdminBusinessService {
-
- private static final Set<String> MERCHANT_APP_LOGIN_TYPES = Set.of(
- "餐饮服务", "景区服务", "免费体检", "配偶推荐就业", "金融服务", "行政审批", "子女托管",
- "酒店服务", "公寓租赁", "加油服务", "停车服务", "自助洗车", "购房优惠", "购车服务",
- "家电服务", "数码服务", "文化服务", "电信服务", "口腔治疗保健"
- );
private final JdbcTemplate jdbcTemplate;
@@ -255,9 +251,9 @@
args.add("%" + contactMobile.trim() + "%");
}
if (type != null && !type.isBlank()) {
- sql.append(" and m.merchant_type = ?");
- countSql.append(" and m.merchant_type = ?");
- args.add(type);
+ sql.append(" and m.merchant_type_code = ?");
+ countSql.append(" and m.merchant_type_code = ?");
+ args.add(MerchantTypeCatalog.canonicalCode(type));
}
if (status != null) {
sql.append(" and m.status = ?");
@@ -362,16 +358,18 @@
@Transactional
public Map<String, Object> createMerchant(MerchantCreateRequest request) {
- validateMerchantAddress(request.merchantType(), request.address());
+ MerchantType merchantType = requireMerchantType(request.merchantType());
+ validateMerchantAddress(merchantType.code(), request.address());
validateRequiredMerchantCreateFields(request);
jdbcTemplate.update("""
- insert into merchant(merchant_name, merchant_type, contact_name, contact_mobile, address,
+ insert into merchant(merchant_name, merchant_type, merchant_type_code, contact_name, contact_mobile, address,
logo_url, cover_url, business_status, longitude, latitude, can_login_merchant_app, group_buying_enabled,
usage_instructions, rights_text, merchant_rights_config, service_label, is_recommend, status, sort_no)
- values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)
""",
request.merchantName(),
- request.merchantType(),
+ merchantType.displayName(),
+ merchantType.code(),
request.contactName(),
request.contactMobile(),
request.address(),
@@ -386,11 +384,12 @@
request.rightsText(),
toJson(request.merchantRightsConfig()),
request.serviceLabel(),
- request.recommend() == null ? defaultRecommend(request.merchantType()) : request.recommend(),
+ request.recommend() == null ? defaultRecommend(merchantType.code()) : request.recommend(),
request.sortNo() == null ? 0 : request.sortNo());
Long id = jdbcTemplate.queryForObject("select last_insert_id()", Long.class);
- ensureParkingBenefit(id, request.merchantType());
- ensureFuelBenefit(id, request.merchantType(), request.serviceLabel());
+ ensureParkingBenefit(id, merchantType.code());
+ ensureFuelBenefit(id, merchantType.code(), request.serviceLabel());
+ syncPremiumTopicMerchant(id, merchantType, request.sortNo());
Long storeId = createDefaultStore(id, request.merchantName(), request.address());
syncMerchantBusinessHours(id, storeId, request.businessHours());
if (hasMerchantAppAccess(request)) {
@@ -412,7 +411,7 @@
}
void validateMerchantAddress(String merchantType, String address) {
- if (!"公寓租赁".equals(merchantType) && (address == null || address.isBlank())) {
+ if (!"apartment".equals(MerchantTypeCatalog.canonicalCode(merchantType)) && (address == null || address.isBlank())) {
throw new BusinessException(ErrorCode.BAD_REQUEST, "请输入商家地址");
}
}
@@ -423,11 +422,13 @@
}
boolean supportsMerchantAppLogin(String merchantType) {
- return MERCHANT_APP_LOGIN_TYPES.contains(merchantType);
+ return MerchantTypeCatalog.find(merchantType)
+ .map(MerchantType::supportsMerchantAppLogin)
+ .orElse(false);
}
private void validateRequiredMerchantCreateFields(MerchantCreateRequest request) {
- if (!Set.of("景区服务", "餐饮服务").contains(request.merchantType())) {
+ if (!Set.of("scenic", "food").contains(MerchantTypeCatalog.canonicalCode(request.merchantType()))) {
return;
}
if (request.loginAccount() == null || !request.loginAccount().trim().matches("^[A-Za-z0-9]{1,32}$")) {
@@ -476,21 +477,24 @@
}
private byte defaultRecommend(String merchantType) {
- return (byte) (("餐饮服务".equals(merchantType) || "景区服务".equals(merchantType)) ? 1 : 0);
+ return (byte) (("food".equals(merchantType) || "scenic".equals(merchantType)) ? 1 : 0);
}
@Transactional
public Map<String, Object> updateMerchant(Long id, MerchantUpdateRequest request) {
+ MerchantType merchantType = resolveMerchantTypeForUpdate(id, request.merchantType());
+ validateMerchantAddress(merchantType.code(), request.address());
int updated = jdbcTemplate.update("""
update merchant
- set merchant_name = ?, merchant_type = ?, contact_name = ?, contact_mobile = ?,
+ set merchant_name = ?, merchant_type = ?, merchant_type_code = ?, contact_name = ?, contact_mobile = ?,
address = ?, logo_url = ?, cover_url = ?, business_status = ?, longitude = ?, latitude = ?, can_login_merchant_app = ?,
group_buying_enabled = ?, usage_instructions = ?, rights_text = ?, merchant_rights_config = ?, service_label = ?,
is_recommend = ?, sort_no = ?, status = ?
where deleted = 0 and id = ?
""",
request.merchantName(),
- request.merchantType(),
+ merchantType.displayName(),
+ merchantType.code(),
request.contactName(),
request.contactMobile(),
request.address(),
@@ -510,8 +514,9 @@
request.status() == null ? 1 : request.status(),
id);
ensureUpdated(updated);
- ensureParkingBenefit(id, request.merchantType());
- ensureFuelBenefit(id, request.merchantType(), request.serviceLabel());
+ ensureParkingBenefit(id, merchantType.code());
+ ensureFuelBenefit(id, merchantType.code(), request.serviceLabel());
+ syncPremiumTopicMerchant(id, merchantType, request.sortNo());
Long storeId = findOrCreateDefaultStore(id, request.merchantName(), request.address());
syncMerchantBusinessHours(id, storeId, request.businessHours());
if (request.loginPassword() != null && !request.loginPassword().isBlank()) {
@@ -549,7 +554,7 @@
}
private void ensureParkingBenefit(Long merchantId, String merchantType) {
- if (!"停车服务".equals(merchantType) && !"parking".equalsIgnoreCase(merchantType)) return;
+ if (!"parking".equals(merchantType)) return;
jdbcTemplate.update("""
insert into transport_parking_benefit(merchant_id, talent_levels, benefit_text, action_mode, plate_form_mode, usage_instructions, rule_text, status, deleted)
select ?, '', '停车权益', 'plate', 'withParking',
@@ -560,7 +565,7 @@
}
private void ensureFuelBenefit(Long merchantId, String merchantType, String serviceLabel) {
- if (!"加油服务".equals(merchantType) && !"fuel".equalsIgnoreCase(merchantType)) return;
+ if (!"fuel".equals(merchantType)) return;
String discountText = serviceLabel == null || serviceLabel.isBlank() ? "请咨询商户" : serviceLabel.trim();
jdbcTemplate.update("""
insert into transport_fuel_benefit(
@@ -572,6 +577,35 @@
'具体适用油品、优惠额度、可用时段和活动规则以加油站说明为准。', 1, 0
where not exists (select 1 from transport_fuel_benefit where merchant_id = ? and deleted = 0)
""", merchantId, discountText, merchantId);
+ }
+
+ private void syncPremiumTopicMerchant(Long merchantId, MerchantType merchantType, Integer sortNo) {
+ if (merchantType.premiumCategoryKey() == null || merchantType.premiumBusinessType() == null) {
+ jdbcTemplate.update("update premium_topic_merchant set deleted = 1 where merchant_id = ? and deleted = 0", merchantId);
+ return;
+ }
+ jdbcTemplate.update("""
+ insert into premium_topic_merchant(merchant_id, category_key, business_type, sort_no, deleted)
+ values (?, ?, ?, ?, 0)
+ on duplicate key update category_key = values(category_key), business_type = values(business_type),
+ sort_no = values(sort_no), deleted = 0
+ """, merchantId, merchantType.premiumCategoryKey(), merchantType.premiumBusinessType(), sortNo == null ? 0 : sortNo);
+ }
+
+ private MerchantType requireMerchantType(String value) {
+ return MerchantTypeCatalog.find(value)
+ .orElseThrow(() -> new BusinessException(ErrorCode.BAD_REQUEST, "不支持的商家类型"));
+ }
+
+ private MerchantType resolveMerchantTypeForUpdate(Long merchantId, String value) {
+ MerchantType requested = requireMerchantType(value);
+ if (!"shopping".equals(requested.code())) return requested;
+ List<String> existingCodes = jdbcTemplate.queryForList(
+ "select merchant_type_code from merchant where id = ? and deleted = 0 limit 1",
+ String.class,
+ merchantId);
+ if (existingCodes.isEmpty()) return requested;
+ return MerchantTypeCatalog.find(existingCodes.get(0)).orElse(requested);
}
@Transactional
@@ -657,9 +691,9 @@
args.add(like);
}
if (type != null && !type.isBlank()) {
- sql.append(" and m.merchant_type = ?");
- countSql.append(" and m.merchant_type = ?");
- args.add(type);
+ sql.append(" and m.merchant_type_code = ?");
+ countSql.append(" and m.merchant_type_code = ?");
+ args.add(MerchantTypeCatalog.canonicalCode(type));
}
if (status != null) {
sql.append(" and p.audit_status = ?");
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantTypeCatalog.java b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantTypeCatalog.java
new file mode 100644
index 0000000..be8be00
--- /dev/null
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantTypeCatalog.java
@@ -0,0 +1,155 @@
+package com.talentcard.server.business.merchant;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+public final class MerchantTypeCatalog {
+
+ private static final Map<String, MerchantType> BY_ALIAS;
+ private static final List<MerchantType> TYPES;
+
+ static {
+ List<MerchantType> types = List.of(
+ type("food", "餐饮服务", "暖心食享", "MERCHANT", null, null, null, true,
+ "餐饮", "餐饮商家"),
+ type("scenic", "景区服务", "悦览花城", "MERCHANT", null, null, null, true,
+ "景区", "景点服务"),
+ type("hotel", "酒店服务", "舒心安居", "MERCHANT", null, null, null, true,
+ "酒店", "住宿服务"),
+ type("apartment", "公寓租赁", "舒心安居", "MERCHANT", null, null, null, true,
+ "公寓租赁服务", "公寓服务"),
+ type("cinema", "观影服务", "怡乐生活", "CINEMA", null, null, null, true,
+ "theatre", "电影院", "影院", "影城", "剧院"),
+ type("fuel", "加油服务", "畅行无忧", "FUEL", null, null, null, true,
+ "加油", "加油站"),
+ type("parking", "停车服务", "畅行无忧", "PARKING", null, null, null, true,
+ "停车", "停车场"),
+ type("carWash", "自助洗车", "畅行无忧", "CAR_WASH", null, null, null, true,
+ "自主洗车", "自助洗车服务", "洗车服务"),
+ type("medical", "免费体检", "臻享礼遇", "MEDICAL", "medical", "MEDICAL", null, true,
+ "healthCheck", "体检服务", "医疗体检"),
+ type("employment", "配偶推荐就业", "臻享礼遇", "SPOUSE_EMPLOYMENT", "employment", "SPOUSE_EMPLOYMENT", null, true,
+ "就业服务", "配偶就业"),
+ type("finance", "金融服务", "臻享礼遇", "FINANCE", "finance", "FINANCE", null, true,
+ "金融"),
+ type("approval", "行政审批", "臻享礼遇", "ADMIN_APPROVAL", "approval", "ADMIN_APPROVAL", null, true,
+ "行政审批服务", "政务服务"),
+ type("children", "子女托管", "臻享礼遇", "CHILD_ENTRUSTMENT", "children", "CHILD_ENTRUSTMENT", null, true,
+ "学生托付", "学生托管", "子女托管服务"),
+ type("housing", "购房优惠", "惠享好物", "SHOPPING", null, null, "housing", true,
+ "购房服务", "住房服务"),
+ type("car", "购车服务", "惠享好物", "SHOPPING", null, null, "car", true,
+ "购车优惠", "汽车服务"),
+ type("appliance", "家电服务", "惠享好物", "SHOPPING", null, null, "appliance", true,
+ "家用电器服务"),
+ type("digital", "数码服务", "惠享好物", "SHOPPING", null, null, "digital", true,
+ "数码产品服务"),
+ type("culture", "文化服务", "惠享好物", "SHOPPING", null, null, "book", true,
+ "图书服务", "文化图书服务"),
+ type("telecom", "电信服务", "惠享好物", "SHOPPING", null, null, "digital", true,
+ "通信服务"),
+ type("dental", "口腔治疗保健", "臻享礼遇", "MERCHANT", null, null, null, true,
+ "口腔服务", "口腔保健"),
+ type("shopping", "购物服务", "惠享好物", "SHOPPING", null, null, null, true,
+ "惠享好物")
+ );
+ Map<String, MerchantType> aliases = new LinkedHashMap<>();
+ for (MerchantType type : types) {
+ register(aliases, type.code(), type);
+ register(aliases, type.displayName(), type);
+ for (String alias : type.aliases()) register(aliases, alias, type);
+ }
+ TYPES = List.copyOf(types);
+ BY_ALIAS = Map.copyOf(aliases);
+ }
+
+ private MerchantTypeCatalog() {
+ }
+
+ public static Optional<MerchantType> find(String value) {
+ return Optional.ofNullable(BY_ALIAS.get(normalize(value)));
+ }
+
+ public static String canonicalCode(String value) {
+ return find(value).map(MerchantType::code).orElse("other");
+ }
+
+ public static String displayName(String value) {
+ return find(value).map(MerchantType::displayName).orElseGet(() -> value == null ? "" : value.trim());
+ }
+
+ public static List<String> codesForTopic(String topicName) {
+ return TYPES.stream()
+ .filter(type -> type.topicName().equals(topicName))
+ .map(MerchantType::code)
+ .toList();
+ }
+
+ public static List<String> codesForRequestedValue(String value) {
+ List<String> topicCodes = codesForTopic(value == null ? "" : value.trim());
+ if (!topicCodes.isEmpty()) return topicCodes;
+ return find(value).map(type -> List.of(type.code())).orElseGet(List::of);
+ }
+
+ public static List<String> codesForShoppingCategory(String categoryKey) {
+ return TYPES.stream()
+ .filter(type -> categoryKey != null && categoryKey.equals(type.shoppingCategoryKey()))
+ .map(MerchantType::code)
+ .toList();
+ }
+
+ public static Optional<MerchantType> forPremiumCategory(String categoryKey) {
+ return TYPES.stream()
+ .filter(type -> categoryKey != null && categoryKey.equals(type.premiumCategoryKey()))
+ .findFirst();
+ }
+
+ public static Collection<MerchantType> all() {
+ return TYPES;
+ }
+
+ private static MerchantType type(
+ String code,
+ String displayName,
+ String topicName,
+ String detailType,
+ String premiumCategoryKey,
+ String premiumBusinessType,
+ String shoppingCategoryKey,
+ boolean supportsMerchantAppLogin,
+ String... aliases
+ ) {
+ Set<String> values = new LinkedHashSet<>();
+ if (aliases != null) values.addAll(List.of(aliases));
+ return new MerchantType(code, displayName, topicName, detailType, premiumCategoryKey,
+ premiumBusinessType, shoppingCategoryKey, supportsMerchantAppLogin, Set.copyOf(values));
+ }
+
+ private static void register(Map<String, MerchantType> aliases, String alias, MerchantType type) {
+ String key = normalize(alias);
+ if (!key.isBlank()) aliases.put(key, type);
+ }
+
+ private static String normalize(String value) {
+ return value == null ? "" : value.trim().toLowerCase(Locale.ROOT);
+ }
+
+ public record MerchantType(
+ String code,
+ String displayName,
+ String topicName,
+ String detailType,
+ String premiumCategoryKey,
+ String premiumBusinessType,
+ String shoppingCategoryKey,
+ boolean supportsMerchantAppLogin,
+ Set<String> aliases
+ ) {
+ }
+}
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/AdminApprovalPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/AdminApprovalPortalService.java
index 0ee18d2..0a42c87 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/AdminApprovalPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/AdminApprovalPortalService.java
@@ -71,9 +71,8 @@
if (serviceId == null || serviceId <= 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "行政审批服务信息不能为空");
List<Map<String, Object>> rows = query("""
select m.id
- from merchant m left join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0
- where m.id = ? and m.deleted = 0
- and ((mapping.category_key = 'approval') or (mapping.id is null and m.merchant_type = '行政审批'))
+ from merchant m
+ where m.id = ? and m.deleted = 0 and m.merchant_type_code = 'approval'
""", serviceId);
if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "行政审批服务不存在");
return rows.get(0);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/CarWashMerchantPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/CarWashMerchantPortalService.java
index 270e1fc..b8ef75d 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/CarWashMerchantPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/CarWashMerchantPortalService.java
@@ -41,7 +41,7 @@
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);
List<Map<String, Object>> serviceRows = query("""
select id, talent_levels, service_point_text, tip_text, external_link_type,
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/ChildrenEntrustmentPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/ChildrenEntrustmentPortalService.java
index 82e5c2c..8fd4b79 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/ChildrenEntrustmentPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/ChildrenEntrustmentPortalService.java
@@ -109,8 +109,8 @@
if (serviceId == null || serviceId <= 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "学生托付服务信息不能为空");
List<Map<String, Object>> rows = query("""
select m.id, m.merchant_rights_config, m.usage_instructions
- from merchant m join premium_topic_merchant mapping on mapping.merchant_id = m.id
- where m.id = ? and m.deleted = 0 and mapping.deleted = 0 and mapping.category_key = 'children'
+ from merchant m
+ where m.id = ? and m.deleted = 0 and m.merchant_type_code = 'children'
""", serviceId);
if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "学生托付服务不存在");
return rows.get(0);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/CinemaPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/CinemaPortalService.java
index 9c81915..60878a0 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/CinemaPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/CinemaPortalService.java
@@ -205,9 +205,9 @@
private Map<String, Object> cinema(Long merchantId, boolean requireAvailable) {
List<Map<String, Object>> merchants = query("""
- select id, merchant_name, merchant_type, contact_mobile, address, cover_url, service_label, rights_text,
+ select id, merchant_name, merchant_type_code as merchant_type, contact_mobile, address, cover_url, service_label, rights_text,
merchant_rights_config, latitude, longitude, status
- from merchant where id = ? and deleted = 0 and merchant_type in ('cinema', 'theatre', '观影服务', '电影院', '影院', '影城', '剧院')
+ from merchant where id = ? and deleted = 0 and merchant_type_code = 'cinema'
""", merchantId);
if (merchants.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "影城不存在");
Map<String, Object> merchant = merchants.get(0);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/FinanceMerchantPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/FinanceMerchantPortalService.java
index 680578d..b215121 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/FinanceMerchantPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/FinanceMerchantPortalService.java
@@ -32,9 +32,8 @@
detail_config.advisor_department, detail_config.advisor_mobile, detail_config.advisor_service_time,
detail_config.advisor_available, detail_config.unavailable_reason, detail_config.status as detail_status
from merchant m
- join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.category_key = 'finance' and mapping.deleted = 0
left join finance_service_detail detail_config on detail_config.merchant_id = m.id and detail_config.deleted = 0
- where m.id = ? and m.merchant_type in ('finance', '金融服务') and m.deleted = 0
+ where m.id = ? and m.merchant_type_code = 'finance' and m.deleted = 0
order by detail_config.id asc limit 1
""", merchantId);
boolean available = number(row.get("merchantStatus")) == 1 && (row.get("detailStatus") == null || number(row.get("detailStatus")) == 1);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/FuelMerchantPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/FuelMerchantPortalService.java
index f60ec6b..257a890 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/FuelMerchantPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/FuelMerchantPortalService.java
@@ -100,9 +100,9 @@
private Map<String, Object> fuelMerchant(Long merchantId) {
return one("""
- select id, merchant_name, merchant_type, contact_mobile, address, cover_url, service_label, status, latitude, longitude
+ select id, merchant_name, merchant_type_code as merchant_type, contact_mobile, address, cover_url, service_label, status, latitude, longitude
from merchant
- where id = ? and merchant_type in ('fuel', '加油服务') and deleted = 0
+ where id = ? and merchant_type_code = 'fuel' and deleted = 0
""", merchantId);
}
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/MedicalPackagePortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/MedicalPackagePortalService.java
index 5d70a48..36e0e42 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/MedicalPackagePortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/MedicalPackagePortalService.java
@@ -88,9 +88,8 @@
private Map<String, Object> medicalMerchant(Long merchantId) {
if (merchantId == null || merchantId <= 0) throw new BusinessException(ErrorCode.BAD_REQUEST, "体检医院信息不能为空");
List<Map<String, Object>> rows = query("""
- select m.id from merchant m join premium_topic_merchant mapping on mapping.merchant_id = m.id
- where m.id = ? and m.merchant_type in ('medical', '免费体检', 'healthCheck') and m.deleted = 0
- and mapping.category_key = 'medical' and mapping.deleted = 0
+ select m.id from merchant m
+ where m.id = ? and m.merchant_type_code = 'medical' and m.deleted = 0
""", merchantId);
if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "体检医院不存在");
return rows.get(0);
@@ -111,8 +110,7 @@
m.merchant_name as hospital_name,
m.address as hospital_address, m.contact_mobile as hospital_mobile, m.latitude as hospital_latitude,
m.longitude as hospital_longitude
- from merchant_product p join merchant m on m.id = p.merchant_id and m.deleted = 0
- join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.category_key = 'medical' and mapping.deleted = 0
+ from merchant_product p join merchant m on m.id = p.merchant_id and m.deleted = 0 and m.merchant_type_code = 'medical'
where p.id = ? and p.deleted = 0 and p.audit_status = 2
""", packageId);
if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "体检套餐不存在");
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/ParkingMerchantPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/ParkingMerchantPortalService.java
index 4d91d50..8c5e7b9 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/ParkingMerchantPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/ParkingMerchantPortalService.java
@@ -137,7 +137,7 @@
select id, merchant_name, contact_mobile, address, cover_url, service_label, usage_instructions,
rights_text, merchant_rights_config, status, latitude, longitude
from merchant
- where id = ? and merchant_type in ('parking', '停车服务') and deleted = 0
+ where id = ? and merchant_type_code = 'parking' and deleted = 0
""", merchantId);
}
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/PortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/PortalService.java
index 5035b88..885a476 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/PortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/PortalService.java
@@ -6,14 +6,16 @@
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;
@@ -65,7 +67,7 @@
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
@@ -225,7 +227,7 @@
}
}
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
@@ -255,9 +257,9 @@
@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
@@ -293,9 +295,9 @@
@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
@@ -334,18 +336,16 @@
@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
@@ -399,9 +399,9 @@
@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
@@ -437,18 +437,13 @@
@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
@@ -500,26 +495,24 @@
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"), "人才专享"));
@@ -561,49 +554,27 @@
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) {
@@ -621,63 +592,30 @@
}
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) {
@@ -705,7 +643,7 @@
@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
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/ShoppingMerchantPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/ShoppingMerchantPortalService.java
index d8c82ce..66bf94f 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/ShoppingMerchantPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/ShoppingMerchantPortalService.java
@@ -24,18 +24,17 @@
Map<String, Object> row = one("""
select m.id, m.merchant_name, m.cover_url, m.service_label, m.address, m.contact_mobile, m.contact_name, m.rights_text,
m.longitude, m.latitude, m.status as merchant_status,
- coalesce(mapping.category_key, case m.merchant_type
- when '购房优惠' then 'housing' when '购车服务' then 'car'
- when '家电服务' then 'appliance' when '数码服务' then 'digital'
- when '文化服务' then 'book' when '图书服务' then 'book' end) as category_key,
+ case m.merchant_type_code
+ when 'housing' then 'housing' when 'car' then 'car'
+ when 'appliance' then 'appliance' when 'digital' then 'digital'
+ when 'culture' then 'book' when 'telecom' then 'digital' end as category_key,
detail_config.talent_levels, detail_config.benefit_detail, detail_config.advisor_id,
detail_config.advisor_name, detail_config.advisor_department, detail_config.advisor_mobile,
detail_config.advisor_service_time, detail_config.advisor_available,
detail_config.unavailable_reason, detail_config.status as detail_status
from merchant m
- left join shopping_topic_merchant mapping on mapping.merchant_id = m.id and mapping.deleted = 0
left join shopping_service_detail detail_config on detail_config.merchant_id = m.id and detail_config.deleted = 0
- where m.id = ? and m.merchant_type in ('shopping', '购房优惠', '购车服务', '家电服务', '数码服务', '文化服务', '图书服务') and m.deleted = 0
+ where m.id = ? and m.merchant_type_code in ('shopping', 'housing', 'car', 'appliance', 'digital', 'culture', 'telecom') and m.deleted = 0
order by detail_config.id asc limit 1
""", merchantId);
boolean available = number(row.get("merchantStatus")) == 1 && (row.get("detailStatus") == null || number(row.get("detailStatus")) == 1);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/SpouseEmploymentPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/SpouseEmploymentPortalService.java
index b31f21b..2ab4eba 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/SpouseEmploymentPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/SpouseEmploymentPortalService.java
@@ -114,8 +114,7 @@
m.merchant_rights_config
from merchant m
left join spouse_employment_benefit b on b.merchant_id = m.id and b.deleted = 0
- join premium_topic_merchant mapping on mapping.merchant_id = m.id and mapping.category_key = 'employment' and mapping.deleted = 0
- where m.id = ? and m.deleted = 0
+ where m.id = ? and m.deleted = 0 and m.merchant_type_code = 'employment'
""", merchantId);
if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "配偶推荐就业权益不存在");
return rows.get(0);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/portal/UsageRecordPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/business/portal/UsageRecordPortalService.java
index 6fc08bd..0bb9b48 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/portal/UsageRecordPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/portal/UsageRecordPortalService.java
@@ -76,7 +76,7 @@
o.id as target_detail_id,
o.merchant_id,
coalesce(nullif(m.merchant_name, ''), '人才权益服务') as merchant_name,
- coalesce(nullif(m.merchant_type, ''), 'service') as merchant_type,
+ coalesce(nullif(m.merchant_type_code, ''), 'service') as merchant_type,
coalesce(nullif(b.benefit_name, ''), o.order_type, '人才权益订单') as detail_name,
o.created_at as occurred_at,
case
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/DisplayServiceMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/DisplayServiceMapper.java
index 1533c4e..034f6e2 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/DisplayServiceMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/DisplayServiceMapper.java
@@ -16,15 +16,7 @@
<script>
select m.id as merchantId,
m.merchant_name as merchantName,
- case
- when m.merchant_type = 'parking' then 'parking'
- when m.merchant_type = 'medical' then 'medical'
- when m.merchant_type = 'apartment' then 'apartment'
- when exists (select 1 from shopping_topic_merchant s1 where s1.merchant_id = m.id and s1.deleted = 0 and s1.category_key = 'housing') then 'housing'
- when exists (select 1 from shopping_topic_merchant s2 where s2.merchant_id = m.id and s2.deleted = 0 and s2.category_key = 'car') then 'car'
- when exists (select 1 from shopping_topic_merchant s3 where s3.merchant_id = m.id and s3.deleted = 0 and s3.category_key = 'appliance') then 'appliance'
- else m.merchant_type
- end as category,
+ m.merchant_type_code as category,
m.merchant_type as merchantType,
m.contact_name as contactName,
m.contact_mobile as contactMobile,
@@ -45,32 +37,9 @@
m.updated_at as updatedAt
from merchant m
where m.deleted = 0
- and (
- m.merchant_type in ('parking', 'medical', 'apartment')
- or exists (
- select 1
- from shopping_topic_merchant sm
- where sm.merchant_id = m.id
- and sm.deleted = 0
- and sm.category_key in ('housing', 'car', 'appliance')
- )
- )
+ and m.merchant_type_code in ('parking', 'medical', 'apartment', 'housing', 'car', 'appliance')
<if test="category != null and category != ''">
- <choose>
- <when test="category == 'housing' or category == 'car' or category == 'appliance'">
- and m.merchant_type = 'shopping'
- and exists (
- select 1
- from shopping_topic_merchant sm
- where sm.merchant_id = m.id
- and sm.deleted = 0
- and sm.category_key = #{category}
- )
- </when>
- <otherwise>
- and m.merchant_type = #{category}
- </otherwise>
- </choose>
+ and m.merchant_type_code = #{category}
</if>
<if test="status != null">and m.status = #{status}</if>
<if test="keyword != null and keyword != ''">
@@ -93,32 +62,9 @@
select count(*)
from merchant m
where m.deleted = 0
- and (
- m.merchant_type in ('parking', 'medical', 'apartment')
- or exists (
- select 1
- from shopping_topic_merchant sm
- where sm.merchant_id = m.id
- and sm.deleted = 0
- and sm.category_key in ('housing', 'car', 'appliance')
- )
- )
+ and m.merchant_type_code in ('parking', 'medical', 'apartment', 'housing', 'car', 'appliance')
<if test="category != null and category != ''">
- <choose>
- <when test="category == 'housing' or category == 'car' or category == 'appliance'">
- and m.merchant_type = 'shopping'
- and exists (
- select 1
- from shopping_topic_merchant sm
- where sm.merchant_id = m.id
- and sm.deleted = 0
- and sm.category_key = #{category}
- )
- </when>
- <otherwise>
- and m.merchant_type = #{category}
- </otherwise>
- </choose>
+ and m.merchant_type_code = #{category}
</if>
<if test="status != null">and m.status = #{status}</if>
<if test="keyword != null and keyword != ''">
@@ -136,15 +82,7 @@
<script>
select m.id as merchantId,
m.merchant_name as merchantName,
- case
- when m.merchant_type = 'parking' then 'parking'
- when m.merchant_type = 'medical' then 'medical'
- when m.merchant_type = 'apartment' then 'apartment'
- when exists (select 1 from shopping_topic_merchant s1 where s1.merchant_id = m.id and s1.deleted = 0 and s1.category_key = 'housing') then 'housing'
- when exists (select 1 from shopping_topic_merchant s2 where s2.merchant_id = m.id and s2.deleted = 0 and s2.category_key = 'car') then 'car'
- when exists (select 1 from shopping_topic_merchant s3 where s3.merchant_id = m.id and s3.deleted = 0 and s3.category_key = 'appliance') then 'appliance'
- else m.merchant_type
- end as category,
+ m.merchant_type_code as category,
m.merchant_type as merchantType,
m.contact_name as contactName,
m.contact_mobile as contactMobile,
@@ -166,18 +104,9 @@
from merchant m
where m.deleted = 0
and m.id = #{serviceId}
- and (
- m.merchant_type in ('parking', 'medical', 'apartment')
- or exists (
- select 1
- from shopping_topic_merchant sm
- where sm.merchant_id = m.id
- and sm.deleted = 0
- and sm.category_key in ('housing', 'car', 'appliance')
- )
- )
+ and m.merchant_type_code in ('parking', 'medical', 'apartment', 'housing', 'car', 'appliance')
limit 1
</script>
""")
Map<String, Object> selectAdminDetail(@Param("serviceId") Long serviceId);
-}
\ No newline at end of file
+}
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantDisplayPolicyMerchantMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantDisplayPolicyMerchantMapper.java
index ee689f5..e997143 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantDisplayPolicyMerchantMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantDisplayPolicyMerchantMapper.java
@@ -37,7 +37,7 @@
from merchant m
where m.deleted = 0
<if test="merchantId != null">and m.id = #{merchantId}</if>
- <if test="merchantType != null and merchantType != ''">and m.merchant_type = #{merchantType}</if>
+ <if test="merchantType != null and merchantType != ''">and m.merchant_type_code = #{merchantType}</if>
<if test="status != null">and m.status = #{status}</if>
<if test="keyword != null and keyword != ''">
and (m.merchant_name like concat('%', #{keyword}, '%')
@@ -73,7 +73,7 @@
from merchant m
where m.deleted = 0
<if test="merchantId != null">and m.id = #{merchantId}</if>
- <if test="merchantType != null and merchantType != ''">and m.merchant_type = #{merchantType}</if>
+ <if test="merchantType != null and merchantType != ''">and m.merchant_type_code = #{merchantType}</if>
<if test="status != null">and m.status = #{status}</if>
<if test="keyword != null and keyword != ''">
and (m.merchant_name like concat('%', #{keyword}, '%')
@@ -164,7 +164,7 @@
)
where m.deleted = 0
and m.status = 1
- <if test="merchantType != null and merchantType != ''">and m.merchant_type = #{merchantType}</if>
+ <if test="merchantType != null and merchantType != ''">and m.merchant_type_code = #{merchantType}</if>
<if test="keyword != null and keyword != ''">
and (m.merchant_name like concat('%', #{keyword}, '%')
or m.contact_mobile like concat('%', #{keyword}, '%')
@@ -186,7 +186,7 @@
from merchant m
where m.deleted = 0
and m.status = 1
- <if test="merchantType != null and merchantType != ''">and m.merchant_type = #{merchantType}</if>
+ <if test="merchantType != null and merchantType != ''">and m.merchant_type_code = #{merchantType}</if>
<if test="keyword != null and keyword != ''">
and (m.merchant_name like concat('%', #{keyword}, '%')
or m.contact_mobile like concat('%', #{keyword}, '%')
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantSettlementStatisticsMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantSettlementStatisticsMapper.java
index a3712c1..06b430e 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantSettlementStatisticsMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/MerchantSettlementStatisticsMapper.java
@@ -68,7 +68,7 @@
and o.order_status = 1
and o.verify_status = 1
<if test="merchantId != null">and o.merchant_id = #{merchantId}</if>
- <if test="merchantType != null and merchantType != ''">and m.merchant_type = #{merchantType}</if>
+ <if test="merchantType != null and merchantType != ''">and m.merchant_type_code = #{merchantType}</if>
<if test="startTime != null">and coalesce(v.verify_time, o.updated_at, o.created_at) >= #{startTime}</if>
<if test="endTime != null">and coalesce(v.verify_time, o.updated_at, o.created_at) < #{endTime}</if>
) base
@@ -106,7 +106,7 @@
and o.order_status = 1
and o.verify_status = 1
<if test="merchantId != null">and o.merchant_id = #{merchantId}</if>
- <if test="merchantType != null and merchantType != ''">and m.merchant_type = #{merchantType}</if>
+ <if test="merchantType != null and merchantType != ''">and m.merchant_type_code = #{merchantType}</if>
<if test="startTime != null">and coalesce(v.verify_time, o.updated_at, o.created_at) >= #{startTime}</if>
<if test="endTime != null">and coalesce(v.verify_time, o.updated_at, o.created_at) < #{endTime}</if>
group by period_key, o.merchant_id
@@ -169,7 +169,7 @@
and o.order_status = 1
and o.verify_status = 1
<if test="merchantId != null">and o.merchant_id = #{merchantId}</if>
- <if test="merchantType != null and merchantType != ''">and m.merchant_type = #{merchantType}</if>
+ <if test="merchantType != null and merchantType != ''">and m.merchant_type_code = #{merchantType}</if>
<if test="startTime != null">and coalesce(v.verify_time, o.updated_at, o.created_at) >= #{startTime}</if>
<if test="endTime != null">and coalesce(v.verify_time, o.updated_at, o.created_at) < #{endTime}</if>
) base
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/ServiceApplicationMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/ServiceApplicationMapper.java
index 1ac90ab..7536768 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/ServiceApplicationMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/ServiceApplicationMapper.java
@@ -64,7 +64,7 @@
where mapping.merchant_id = m.id
and mapping.category_key = #{categoryKey}
and mapping.deleted = 0)
- or (#{categoryKey} = 'medical' and m.merchant_type in ('medical', '免费体检', 'healthCheck')))
+ or (#{categoryKey} = 'medical' and m.merchant_type_code = 'medical'))
limit 1
""")
Map<String, Object> selectPremiumMerchantSnapshot(@Param("merchantId") Long merchantId, @Param("categoryKey") String categoryKey);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashCredentialMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashCredentialMapper.java
index 8831bce..6b26202 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashCredentialMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashCredentialMapper.java
@@ -99,7 +99,7 @@
""")
Map<String, Object> selectPrimaryCard(@Param("familyCardId") Long familyCardId);
- @Select("select count(*) from merchant where id = #{merchantId} and merchant_type = 'carWash' and deleted = 0 and status = 1")
+ @Select("select count(*) from merchant where id = #{merchantId} and merchant_type_code = 'carWash' and deleted = 0 and status = 1")
Long countActiveMerchant(@Param("merchantId") Long merchantId);
@Select("""
@@ -112,4 +112,4 @@
@Select("select * from transport_car_wash_credential where id = #{id} and deleted = 0 limit 1 for update")
TransportCarWashCredential selectByIdForUpdate(@Param("id") Long id);
-}
\ No newline at end of file
+}
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashServiceMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashServiceMapper.java
index 16b74c5..3c33585 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashServiceMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportCarWashServiceMapper.java
@@ -29,7 +29,7 @@
from merchant m
left join transport_car_wash_service s on s.merchant_id = m.id and s.deleted = 0
where m.deleted = 0
- and m.merchant_type = '自助洗车'
+ and m.merchant_type_code = 'carWash'
and (#{keyword} is null or #{keyword} = '' or m.merchant_name like concat('%', #{keyword}, '%')
or m.address like concat('%', #{keyword}, '%') or m.contact_mobile like concat('%', #{keyword}, '%'))
and (#{merchantId} is null or m.id = #{merchantId})
@@ -45,7 +45,7 @@
select count(*)
from merchant m
where m.deleted = 0
- and m.merchant_type = '自助洗车'
+ and m.merchant_type_code = 'carWash'
and (#{keyword} is null or #{keyword} = '' or m.merchant_name like concat('%', #{keyword}, '%')
or m.address like concat('%', #{keyword}, '%') or m.contact_mobile like concat('%', #{keyword}, '%'))
and (#{merchantId} is null or m.id = #{merchantId})
@@ -69,7 +69,7 @@
from merchant m
left join transport_car_wash_service s on s.merchant_id = m.id and s.deleted = 0
where m.deleted = 0
- and m.merchant_type = '自助洗车'
+ and m.merchant_type_code = 'carWash'
and m.id = #{merchantId}
limit 1
""")
@@ -90,7 +90,7 @@
from merchant m
left join transport_car_wash_service s on s.merchant_id = m.id and s.deleted = 0
where m.deleted = 0
- and m.merchant_type = '自助洗车'
+ and m.merchant_type_code = 'carWash'
and m.id = #{merchantId}
limit 1
""")
@@ -99,7 +99,7 @@
@Select("""
select count(*)
from merchant
- where deleted = 0 and merchant_type = '自助洗车' and id = #{merchantId}
+ where deleted = 0 and merchant_type_code = 'carWash' and id = #{merchantId}
""")
Long countCarWashMerchant(@Param("merchantId") Long merchantId);
-}
\ No newline at end of file
+}
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingCardLevelRightMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingCardLevelRightMapper.java
index ed78013..de2ce92 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingCardLevelRightMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingCardLevelRightMapper.java
@@ -36,7 +36,7 @@
b.action_mode as actionMode,
b.status as benefitStatus
from transport_parking_card_level_right r
- join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type in ('parking', '停车服务')
+ join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type_code = 'parking'
left join transport_parking_benefit b on b.merchant_id = m.id and b.deleted = 0
where r.deleted = 0
and (#{merchantId} is null or r.merchant_id = #{merchantId})
@@ -57,7 +57,7 @@
@Select("""
select count(*)
from transport_parking_card_level_right r
- join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type in ('parking', '停车服务')
+ join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type_code = 'parking'
where r.deleted = 0
and (#{merchantId} is null or r.merchant_id = #{merchantId})
and (#{cardLevel} is null or #{cardLevel} = '' or r.card_level = #{cardLevel})
@@ -93,7 +93,7 @@
b.action_mode as actionMode,
b.status as benefitStatus
from transport_parking_card_level_right r
- join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type in ('parking', '停车服务')
+ join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type_code = 'parking'
left join transport_parking_benefit b on b.merchant_id = m.id and b.deleted = 0
where r.deleted = 0
and r.merchant_id = #{merchantId}
@@ -125,7 +125,7 @@
b.action_mode as actionMode,
b.status as benefitStatus
from transport_parking_card_level_right r
- join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type in ('parking', '停车服务') and m.status = 1
+ join merchant m on m.id = r.merchant_id and m.deleted = 0 and m.merchant_type_code = 'parking' and m.status = 1
join transport_parking_benefit b on b.merchant_id = m.id and b.deleted = 0 and b.status = 1
where r.deleted = 0
and r.enabled = 1
@@ -135,4 +135,4 @@
order by m.sort_no desc, m.id desc
""")
List<Map<String, Object>> selectAvailableForCard(@Param("cardLevel") String cardLevel, @Param("merchantId") Long merchantId);
-}
\ No newline at end of file
+}
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingPlateRegistrationMapper.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingPlateRegistrationMapper.java
index 36ac13d..504a35d 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingPlateRegistrationMapper.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/TransportParkingPlateRegistrationMapper.java
@@ -50,7 +50,7 @@
left join transport_parking_benefit b on b.merchant_id = m.id and b.deleted = 0
where m.id = #{merchantId}
and m.deleted = 0
- and m.merchant_type in ('parking', '停车服务')
+ and m.merchant_type_code = 'parking'
limit 1
""")
Map<String, Object> selectParkingMerchant(@Param("merchantId") Long merchantId);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/service/BenefitQuotaService.java b/talent-card-server/src/main/java/com/talentcard/server/service/BenefitQuotaService.java
index 3289f5d..b0bc1b1 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/service/BenefitQuotaService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/service/BenefitQuotaService.java
@@ -549,7 +549,7 @@
.or()
.apply("exists (select 1 from benefit_order o "
+ "join merchant m on m.id = o.merchant_id and m.deleted = 0 "
- + "and m.merchant_type in ('hotel', '酒店服务') "
+ + "and m.merchant_type_code = 'hotel' "
+ "where o.id = verify_record.order_id and o.deleted = 0)"));
if (merchantId != null) {
recordQuery.and(wrapper -> wrapper.eq("merchant_id", merchantId)
@@ -565,7 +565,7 @@
.eq("verify_status", 1)
.ge("updated_at", windowStart)
.apply("exists (select 1 from merchant m where m.id = benefit_order.merchant_id "
- + "and m.deleted = 0 and m.merchant_type in ('hotel', '酒店服务'))")
+ + "and m.deleted = 0 and m.merchant_type_code = 'hotel')")
.apply("not exists (select 1 from verify_record r where r.order_id = benefit_order.id and r.status = 1)");
if (merchantId != null) {
orderQuery.eq("merchant_id", merchantId);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyAdminService.java b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyAdminService.java
index e185ad6..0d913bd 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyAdminService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyAdminService.java
@@ -12,6 +12,7 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.talentcard.server.business.PageResult;
+import com.talentcard.server.business.merchant.MerchantTypeCatalog;
import com.talentcard.server.common.BusinessException;
import com.talentcard.server.common.ErrorCode;
import com.talentcard.server.entity.MerchantCardBenefit;
@@ -53,7 +54,7 @@
List<Map<String, Object>> records = merchantMapper.selectAdminPage(
merchantId,
clean(keyword),
- clean(merchantType),
+ merchantTypeCode(merchantType),
aliases,
status,
safeSize,
@@ -63,7 +64,7 @@
List<Map<String, Object>> views = records.stream()
.map(row -> adminView(row, benefits.getOrDefault(longValue(row, "merchantId"), List.of())))
.toList();
- Long total = merchantMapper.countAdminPage(merchantId, clean(keyword), clean(merchantType), aliases, status);
+ Long total = merchantMapper.countAdminPage(merchantId, clean(keyword), merchantTypeCode(merchantType), aliases, status);
return new PageResult<>(views, safePage, safeSize, total == null ? 0 : total);
}
@@ -177,6 +178,11 @@
}
}
+ private String merchantTypeCode(String value) {
+ String cleaned = clean(value);
+ return cleaned.isBlank() ? "" : MerchantTypeCatalog.canonicalCode(cleaned);
+ }
+
private void upsertPolicies(Long merchantId, List<MerchantDisplayPolicySaveRequest.CardPolicy> policies) {
if (policies == null) {
return;
diff --git a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyPortalService.java b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyPortalService.java
index 073e195..50c9963 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyPortalService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantDisplayPolicyPortalService.java
@@ -9,6 +9,7 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.talentcard.server.business.PageResult;
+import com.talentcard.server.business.merchant.MerchantTypeCatalog;
import com.talentcard.server.common.BusinessException;
import com.talentcard.server.common.ErrorCode;
import com.talentcard.server.entity.BenefitFamilyCardApplication;
@@ -49,12 +50,12 @@
List<String> aliases = cardLevelAliases(card.cardLevel());
List<Map<String, Object>> records = merchantMapper.selectPortalPage(
aliases,
- clean(merchantType),
+ merchantTypeCode(merchantType),
clean(keyword),
safeSize,
(safePage - 1) * safeSize
).stream().map(row -> portalView(row, card)).toList();
- Long total = merchantMapper.countPortalPage(aliases, clean(merchantType), clean(keyword));
+ Long total = merchantMapper.countPortalPage(aliases, merchantTypeCode(merchantType), clean(keyword));
return new PageResult<>(records, safePage, safeSize, total == null ? 0 : total);
}
@@ -69,6 +70,11 @@
return portalView(row, card);
}
+ private String merchantTypeCode(String value) {
+ String cleaned = clean(value);
+ return cleaned.isBlank() ? "" : MerchantTypeCatalog.canonicalCode(cleaned);
+ }
+
@Transactional
public Map<String, Object> recordEvent(Long merchantId, MerchantDisplayPolicyEventRequest request) {
Long id = requireMerchantId(merchantId);
diff --git a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java
index f145f34..59782e9 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java
@@ -15,6 +15,7 @@
import java.util.Map;
import com.talentcard.server.business.PageResult;
+import com.talentcard.server.business.merchant.MerchantTypeCatalog;
import com.talentcard.server.common.BusinessException;
import com.talentcard.server.common.ErrorCode;
import com.talentcard.server.mapper.MerchantSettlementStatisticsMapper;
@@ -55,7 +56,7 @@
int safeSize = Math.min(Math.max(size, 1), 100);
List<Map<String, Object>> records = mapper.selectPeriodSummaries(
merchantId,
- clean(merchantType),
+ merchantTypeCode(merchantType),
normalizedPeriod,
range.startTime(),
range.endTime(),
@@ -66,7 +67,7 @@
.toList();
Long total = mapper.countPeriodSummaries(
merchantId,
- clean(merchantType),
+ merchantTypeCode(merchantType),
normalizedPeriod,
range.startTime(),
range.endTime()
@@ -78,7 +79,7 @@
public Map<String, Object> overview(Long merchantId, String merchantType, String startDate, String endDate) {
requireMerchantIdWhenSpecified(merchantId);
DateRange range = range("DAY", startDate, endDate);
- List<Map<String, Object>> rows = mapper.selectMerchantOverviews(merchantId, clean(merchantType), range.startTime(), range.endTime());
+ List<Map<String, Object>> rows = mapper.selectMerchantOverviews(merchantId, merchantTypeCode(merchantType), range.startTime(), range.endTime());
Map<String, Object> result = new LinkedHashMap<>();
result.put("startDate", range.startDate() == null ? "" : range.startDate().toString());
result.put("endDate", range.endDateInclusive() == null ? "" : range.endDateInclusive().toString());
@@ -92,6 +93,11 @@
return overview(merchantId, null, currentMonth.atDay(1).toString(), currentMonth.atEndOfMonth().toString());
}
+ private String merchantTypeCode(String value) {
+ String cleaned = clean(value);
+ return cleaned.isBlank() ? "" : MerchantTypeCatalog.canonicalCode(cleaned);
+ }
+
@Transactional(readOnly = true)
public Map<String, Object> dashboardCards(Long merchantId) {
requireMerchantId(merchantId);
diff --git a/talent-card-server/src/main/resources/db/migration/V118__resync_premium_topic_merchant_mappings.sql b/talent-card-server/src/main/resources/db/migration/V118__resync_premium_topic_merchant_mappings.sql
new file mode 100644
index 0000000..6e85238
--- /dev/null
+++ b/talent-card-server/src/main/resources/db/migration/V118__resync_premium_topic_merchant_mappings.sql
@@ -0,0 +1,27 @@
+insert into premium_topic_merchant(merchant_id, category_key, business_type, sort_no, deleted)
+select m.id,
+ case m.merchant_type
+ when '免费体检' then 'medical'
+ when '配偶推荐就业' then 'employment'
+ when '金融服务' then 'finance'
+ when '行政审批' then 'approval'
+ when '学生托付' then 'children'
+ when '子女托管' then 'children'
+ end,
+ 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,
+ m.sort_no,
+ 0
+from merchant m
+where m.deleted = 0
+ and m.merchant_type in ('免费体检', '配偶推荐就业', '金融服务', '行政审批', '学生托付', '子女托管')
+on duplicate key update category_key = values(category_key),
+ business_type = values(business_type),
+ sort_no = values(sort_no),
+ deleted = 0;
diff --git a/talent-card-server/src/main/resources/db/migration/V119__add_canonical_merchant_type_code.sql b/talent-card-server/src/main/resources/db/migration/V119__add_canonical_merchant_type_code.sql
new file mode 100644
index 0000000..9a0fac8
--- /dev/null
+++ b/talent-card-server/src/main/resources/db/migration/V119__add_canonical_merchant_type_code.sql
@@ -0,0 +1,53 @@
+alter table merchant
+ add column merchant_type_code varchar(32) not null default 'other' after merchant_type;
+
+update merchant
+set merchant_type_code = case
+ when merchant_type in ('food', '餐饮服务', '餐饮', '餐饮商家') then 'food'
+ when merchant_type in ('scenic', '景区服务', '景区', '景点服务') then 'scenic'
+ when merchant_type in ('hotel', '酒店服务', '酒店', '住宿服务') then 'hotel'
+ when merchant_type in ('apartment', '公寓租赁', '公寓租赁服务', '公寓服务') then 'apartment'
+ when merchant_type in ('cinema', 'theatre', '观影服务', '电影院', '影院', '影城', '剧院') then 'cinema'
+ when merchant_type in ('fuel', '加油服务', '加油', '加油站') then 'fuel'
+ when merchant_type in ('parking', '停车服务', '停车', '停车场') then 'parking'
+ when merchant_type in ('carWash', 'carwash', '自主洗车', '自助洗车', '自助洗车服务', '洗车服务') then 'carWash'
+ when merchant_type in ('medical', '免费体检', 'healthCheck', 'healthcheck', '体检服务', '医疗体检') then 'medical'
+ when merchant_type in ('employment', '配偶推荐就业', '就业服务', '配偶就业') then 'employment'
+ when merchant_type in ('finance', '金融服务', '金融') then 'finance'
+ when merchant_type in ('approval', '行政审批', '行政审批服务', '政务服务') then 'approval'
+ when merchant_type in ('children', '学生托付', '学生托管', '子女托管', '子女托管服务') then 'children'
+ when merchant_type in ('housing', '购房优惠', '购房服务', '住房服务') then 'housing'
+ when merchant_type in ('car', '购车服务', '购车优惠', '汽车服务') then 'car'
+ when merchant_type in ('appliance', '家电服务', '家用电器服务') then 'appliance'
+ when merchant_type in ('digital', '数码服务', '数码产品服务') then 'digital'
+ when merchant_type in ('culture', '文化服务', '图书服务', '文化图书服务') then 'culture'
+ when merchant_type in ('telecom', '电信服务', '通信服务') then 'telecom'
+ when merchant_type in ('dental', '口腔治疗保健', '口腔服务', '口腔保健') then 'dental'
+ when merchant_type in ('shopping', '购物服务', '惠享好物') then 'shopping'
+ else 'other'
+end;
+
+-- Early demo data used a generic shopping type and stored the real type only in the
+-- topic mapping. Convert it once so the mapping is no longer required for visibility.
+update merchant m
+set m.merchant_type_code = case (
+ select mapping.category_key
+ from shopping_topic_merchant mapping
+ where mapping.merchant_id = m.id and mapping.deleted = 0
+ order by mapping.id
+ limit 1
+)
+ when 'housing' then 'housing'
+ when 'car' then 'car'
+ when 'appliance' then 'appliance'
+ when 'digital' then 'digital'
+ when 'book' then 'culture'
+ else m.merchant_type_code
+end
+where m.merchant_type_code = 'shopping'
+ and exists (
+ select 1 from shopping_topic_merchant mapping
+ where mapping.merchant_id = m.id and mapping.deleted = 0
+ );
+
+create index idx_merchant_type_code on merchant(merchant_type_code, deleted, status);
diff --git a/talent-card-server/src/test/java/com/talentcard/server/business/admin/AdminBusinessServiceTests.java b/talent-card-server/src/test/java/com/talentcard/server/business/admin/AdminBusinessServiceTests.java
index e290f4a..e98e072 100644
--- a/talent-card-server/src/test/java/com/talentcard/server/business/admin/AdminBusinessServiceTests.java
+++ b/talent-card-server/src/test/java/com/talentcard/server/business/admin/AdminBusinessServiceTests.java
@@ -39,7 +39,7 @@
}
@Test
- void doesNotSupportMerchantAppLoginForUnconfiguredServiceTypes() {
- assertThat(service.supportsMerchantAppLogin("酒店服务")).isFalse();
+ void supportsMerchantAppLoginForHotelMerchants() {
+ assertThat(service.supportsMerchantAppLogin("酒店服务")).isTrue();
}
}
diff --git a/talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantTypeCatalogTests.java b/talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantTypeCatalogTests.java
new file mode 100644
index 0000000..957093d
--- /dev/null
+++ b/talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantTypeCatalogTests.java
@@ -0,0 +1,65 @@
+package com.talentcard.server.business.merchant;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
+class MerchantTypeCatalogTests {
+
+ @Test
+ void resolvesDisplayNamesCodesAndLegacyAliasesToOneCode() {
+ assertThat(MerchantTypeCatalog.canonicalCode("免费体检")).isEqualTo("medical");
+ assertThat(MerchantTypeCatalog.canonicalCode("medical")).isEqualTo("medical");
+ assertThat(MerchantTypeCatalog.canonicalCode("healthCheck")).isEqualTo("medical");
+ assertThat(MerchantTypeCatalog.canonicalCode("影院")).isEqualTo("cinema");
+ assertThat(MerchantTypeCatalog.canonicalCode("公寓租赁服务")).isEqualTo("apartment");
+ }
+
+ @Test
+ void exposesRoutingMetadataFromTheSameCatalog() {
+ MerchantTypeCatalog.MerchantType medical = MerchantTypeCatalog.find("免费体检").orElseThrow();
+ assertThat(medical.topicName()).isEqualTo("臻享礼遇");
+ assertThat(medical.detailType()).isEqualTo("MEDICAL");
+ assertThat(medical.premiumCategoryKey()).isEqualTo("medical");
+ assertThat(medical.premiumBusinessType()).isEqualTo("MEDICAL");
+
+ assertThat(MerchantTypeCatalog.codesForShoppingCategory("book")).containsExactly("culture");
+ assertThat(MerchantTypeCatalog.find("酒店服务").orElseThrow().supportsMerchantAppLogin()).isTrue();
+ }
+
+ @Test
+ void unknownTypesHaveAnExplicitFallbackCode() {
+ assertThat(MerchantTypeCatalog.canonicalCode("未知类型")).isEqualTo("other");
+ assertThat(MerchantTypeCatalog.find("未知类型")).isEmpty();
+ }
+
+ @Test
+ void coversEveryMerchantTypeOfferedByTheAdmin() {
+ Map<String, String> adminTypes = Map.ofEntries(
+ Map.entry("免费体检", "medical"),
+ Map.entry("配偶推荐就业", "employment"),
+ Map.entry("金融服务", "finance"),
+ Map.entry("行政审批", "approval"),
+ Map.entry("子女托管", "children"),
+ Map.entry("餐饮服务", "food"),
+ Map.entry("酒店服务", "hotel"),
+ Map.entry("公寓租赁", "apartment"),
+ Map.entry("加油服务", "fuel"),
+ Map.entry("停车服务", "parking"),
+ Map.entry("自助洗车", "carWash"),
+ Map.entry("景区服务", "scenic"),
+ Map.entry("购房优惠", "housing"),
+ Map.entry("购车服务", "car"),
+ Map.entry("家电服务", "appliance"),
+ Map.entry("数码服务", "digital"),
+ Map.entry("文化服务", "culture"),
+ Map.entry("电信服务", "telecom"),
+ Map.entry("口腔治疗保健", "dental"),
+ Map.entry("观影服务", "cinema")
+ );
+ adminTypes.forEach((displayName, code) ->
+ assertThat(MerchantTypeCatalog.canonicalCode(displayName)).isEqualTo(code));
+ }
+}
--
Gitblit v1.7.1