From b5d2d9e2b08d45050c418f9713e709589c23491e Mon Sep 17 00:00:00 2001
From: shinnosuke <tantao@1hoper.com>
Date: 星期二, 25 八月 2026 17:17:14 +0800
Subject: [PATCH] fix: align parking benefit actions by card level

---
 rencaika/pages/merchant/merchant.uvue                                                                    |    4 ++--
 talent-card-server/src/main/java/com/talentcard/server/business/portal/ParkingMerchantPortalService.java |   29 ++++++++++++++++++++++++-----
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/rencaika/pages/merchant/merchant.uvue b/rencaika/pages/merchant/merchant.uvue
index 5689122..57746cf 100644
--- a/rencaika/pages/merchant/merchant.uvue
+++ b/rencaika/pages/merchant/merchant.uvue
@@ -140,7 +140,7 @@
 	const isFuelMerchant = ref(false)
 	const isParkingMerchant = ref(false)
 	const isMedicalMerchant = ref(false)
-	// 后台停车权益配置:plate=填写车牌,talentCode=出示人才码。
+	// 当前人才等级的停车权益:免费填写车牌,付费出示人才码。
 	const parkingActionMode = ref('plate')
 	// 后台车牌表单配置:withParking=需搜索停车场,simple=仅填写车牌。
 	const parkingPlateMode = ref('simple')
@@ -552,7 +552,7 @@
 				? parkingRightDetail
 				: (data != null && data.rightsText != null && data.rightsText != '' ? data.rightsText as string : '请咨询商户')
 			merchantRightsText.value = data != null && data.rightsText != null ? data.rightsText as string : '请咨询商户'
-			parkingActionMode.value = data != null && (data.actionMode == 'talentCode' || data.parkingType == 'paid') ? 'talentCode' : 'plate'
+			parkingActionMode.value = data != null && data.parkingType == 'paid' ? 'talentCode' : 'plate'
 			parkingPlateMode.value = data != null && data.plateFormMode == 'withParking' ? 'withParking' : 'simple'
 			parkingBenefitId.value = data != null && data.benefit != null && data.benefit.benefitId != null ? '' + data.benefit.benefitId : ''
 			groupBuyingEnabled.value = false
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 eac9633..ded80d9 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
@@ -55,8 +55,8 @@
 		result.put("usageInstructions", usageInstructions(merchant, right));
 		result.put("rightsText", rightsText(merchant, right));
 		String parkingType = text(right == null ? null : right.get("parkingType"), "paid");
-		// 付费停车权益按到店消费规则使用,前端展示使用说明并出示人才码。
-		result.put("actionMode", "paid".equalsIgnoreCase(parkingType) || "free".equalsIgnoreCase(parkingType) ? "talentCode" : "plate");
+		// 付费权益到店出示人才码,免费权益先登记车牌。
+		result.put("actionMode", "paid".equalsIgnoreCase(parkingType) ? "talentCode" : "plate");
 		result.put("plateFormMode", text(benefit.get("plateFormMode"), "simple"));
 		result.put("benefit", benefitView(benefit));
 		result.put("applicableStores", parkingStores(merchant.get("usageInstructions")));
@@ -107,15 +107,23 @@
 				where id = ? and merchant_id = ? and deleted = 0
 				""", request.benefitId(), merchantId);
 		if (number(benefit.get("status")) != 1) throw new BusinessException(ErrorCode.CONFLICT, "停车权益当前不可用");
-		if (!"plate".equals(benefit.get("actionMode"))) throw new BusinessException(ErrorCode.CONFLICT, "当前停车权益无需登记车牌");
+		Map<String, Object> card = activeTalentCard(request.talentId());
+		String cardLevel = text(card.get("cardLevel"), "");
+		Map<String, Object> right = mergeRight(
+				matchingRight(parseList(merchant.get("merchantRightsConfig")), cardLevel),
+				parkingCardLevelRight(merchantId, cardLevel));
+		if (right == null || !booleanValue(right.get("enabled")) || !rightStatusEnabled(right)) {
+			throw new BusinessException(ErrorCode.CONFLICT, "当前人才卡暂无可用停车权益");
+		}
+		if (!"free".equalsIgnoreCase(text(right.get("parkingType"), "paid"))) {
+			throw new BusinessException(ErrorCode.CONFLICT, "付费停车权益无需登记车牌");
+		}
 		if ("withParking".equals(benefit.get("plateFormMode"))) {
 			if (request.parkingLotId() == null) throw new BusinessException(ErrorCode.BAD_REQUEST, "请选择停车场");
 			boolean matchedLot = parkingStores(merchant.get("usageInstructions")).stream()
 					.anyMatch(item -> String.valueOf(request.parkingLotId()).equals(String.valueOf(item.get("id"))));
 			if (!matchedLot) throw new BusinessException(ErrorCode.BAD_REQUEST, "停车场不可用");
 		}
-		Integer talentCount = jdbc.queryForObject("select count(*) from talent_user where id = ? and deleted = 0", Integer.class, request.talentId());
-		if (talentCount == null || talentCount == 0) throw new BusinessException(ErrorCode.NOT_FOUND, "人才用户不存在");
 		Integer duplicateCount = jdbc.queryForObject("""
 				select count(*) from transport_parking_plate_registration
 				where merchant_id = ? and talent_id = ? and plate_number = ? and deleted = 0
@@ -311,6 +319,17 @@
 		return rows.isEmpty() ? "" : text(rows.get(0).get("cardLevel"), "");
 	}
 
+	private Map<String, Object> activeTalentCard(Long talentId) {
+		List<Map<String, Object>> rows = query("""
+				select id, card_level
+				from talent_card
+				where talent_id = ? and card_type = 'PERSONAL' and status = 1 and deleted = 0
+				order by id desc limit 1
+				""", talentId);
+		if (rows.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND, "人才用户或有效人才卡不存在");
+		return rows.get(0);
+	}
+
 	private String normalizedCardLevel(String value) {
 		String raw = value == null ? "" : value.trim();
 		String upper = raw.toUpperCase(Locale.ROOT);

--
Gitblit v1.7.1