zoujiajian hace 11 meses
padre
commit
c7584abba9

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GoodsDonSkuView.java

@@ -80,6 +80,12 @@ public class GoodsDonSkuView {
 	@DbField("gdk.code_credit_recovery")
 	private Integer codeCreditRecovery;
 
+	/**
+	 * 优惠券id
+	 */
+	@DbIgnore
+	private Long couonId;
+
 	/**
 	 * 优惠价格
 	 */

+ 2 - 2
netflix-service/src/main/java/com/cyksj/service/claude/ClaudeCodeService.java

@@ -101,7 +101,7 @@ public interface ClaudeCodeService {
 	/**
 	 * 将指定用户的积分重置为满积分状态(used_credits设为0)
 	 */
-	CreditResetResp resetUserCredits(Long userId, CreditResetReq req);
+	CreditResetResp resetUserCredits(Long userId, CreditResetReq req) throws Exception;
 
 	/**
 	 * 重置用户codePoints到原始值并记录重置次数
@@ -116,7 +116,7 @@ public interface ClaudeCodeService {
 	/**
 	 * 用户使用重置次数 - 保持幂等性
 	 */
-	boolean useResetCount(Long userId);
+	void useResetCount(Long userId) throws Exception;
 
 	/**
 	 * 用户使用积分卡

+ 105 - 95
netflix-service/src/main/java/com/cyksj/service/claude/impl/ClaudeCodeServiceImpl.java

@@ -39,6 +39,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -86,6 +87,8 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 
 	private final static String CLAUDE_CODE_API_PREFIX = "https://relay01.yhlxj.com/";
 
+	public static final String CLAUDE_CODE_HEARD_KEY = "X-Admin-Key";
+
 	public static final String CLAUDE_CODE_API_ADMIN_KEY = "claudecodeyhlxjclaude";
 
 	//连接超时时间 毫秒
@@ -206,7 +209,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		if (checkClaudeCodeUser(userId)) {
 			Long claudeCodeUserId = getClaudeCodeUserId(userId);
 			String url = String.format(CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", claudeCodeUserId, keyId);
-			HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(CONNECT_MILLISECONDS).execute();
+			HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(CLAUDE_CODE_HEARD_KEY, CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(CONNECT_MILLISECONDS).execute();
 			String responseBody = execute.body();
 			ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
 			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
@@ -503,20 +506,18 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 	}
 
 	@Override
-	public CreditResetResp resetUserCredits(Long userId, CreditResetReq req) {
-		try {
-			if (userId <= 0) {
-				throw BusinessRuntimeException.getInstance("用户ID无效");
-			}
+	public CreditResetResp resetUserCredits(Long userId, CreditResetReq req) throws Exception {
+		if (userId <= 0) {
+			throw BusinessRuntimeException.getInstance("用户ID无效");
+		}
 
-			String url = CLAUDE_CODE_API_PREFIX + "api/users/" + userId + "/credits/reset";
-			String body = req != null ? Jsons.toJson(req) : "{}";
-			ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(url, body);
-			return Jsons.parseObject(claudeCodeResp.getData(), CreditResetResp.class);
-		} catch (Exception e) {
-			log.error("重置用户积分失败", e);
-			throw BusinessRuntimeException.getInstance("重置用户积分失败");
+		String url = CLAUDE_CODE_API_PREFIX + "api/users/" + userId + "/credits/reset";
+		String body = req != null ? Jsons.toJson(req) : "{}";
+		ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(url, body);
+		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
+			throw BusinessRuntimeException.getInstance("重置次数失败");
 		}
+		return Jsons.parseObject(claudeCodeResp.getData(), CreditResetResp.class);
 	}
 
 	/**
@@ -559,7 +560,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			return build.call(() -> {
 				try {
 					HttpResponse execute = HttpUtil.createGet(url)
-							.header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
+							.header(CLAUDE_CODE_HEARD_KEY, CLAUDE_CODE_API_ADMIN_KEY)
 							.setConnectionTimeout(CONNECT_MILLISECONDS)
 							.execute();
 					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
@@ -586,7 +587,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			return build.call(() -> {
 				try {
 					HttpResponse execute = HttpUtil.createPost(url)
-							.header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
+							.header(CLAUDE_CODE_HEARD_KEY, CLAUDE_CODE_API_ADMIN_KEY)
 							.setConnectionTimeout(CONNECT_MILLISECONDS)
 							.body(body)
 							.execute();
@@ -613,7 +614,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		try {
 			return build.call(() -> {
 				try {
-					HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(CONNECT_MILLISECONDS).execute();
+					HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(CLAUDE_CODE_HEARD_KEY, CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(CONNECT_MILLISECONDS).execute();
 					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
 					if (!Constant.SUCCESS.equals(resp.getMessage())) {
 						log.info("claude code DELETE URL:{}接口返回msg:{}", url, resp.getMessage());
@@ -671,7 +672,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
 			Wrappers.<ClaudeCodeUser>lambdaQuery().eq(ClaudeCodeUser::getUserId, userId)
 		);
-		
+
 		if (claudeCodeUser == null) {
 			throw new BusinessRuntimeException("用户不存在或未开通Claude Code服务");
 		}
@@ -699,7 +700,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
 			Wrappers.<ClaudeCodeUser>lambdaQuery().eq(ClaudeCodeUser::getUserId, userId)
 		);
-		
+
 		if (claudeCodeUser == null) {
 			throw new BusinessRuntimeException("用户不存在或未开通Claude Code服务");
 		}
@@ -724,71 +725,72 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 	}
 
 	@Override
-	public boolean useResetCount(Long userId) {
+	@Transactional(rollbackFor = Throwable.class)
+	public void useResetCount(Long userId) throws Exception {
 		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
-		
+
 		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
 			Wrappers.lambdaQuery(ClaudeCodeUser.class)
 				.in(ClaudeCodeUser::getUserId, userIdList)
 				.last("limit 1")
 		);
-		
+
 		if (claudeCodeUser == null) {
 			throw new BusinessRuntimeException("用户未开通Claude Code服务");
 		}
-		
+
 		Integer currentResetCount = claudeCodeUser.getResetCount();
 		if (currentResetCount == null || currentResetCount <= 0) {
-			return false;
+			throw BusinessRuntimeException.getInstance("可用重置次数为0");
 		}
-		
-		try {
-			claudeCodeUser.setResetCount(currentResetCount - 1);
-			int updateResult = claudeCodeUserMapper.update(claudeCodeUser, 
+
+		claudeCodeUser.setResetCount(currentResetCount - 1);
+		int updateResult = claudeCodeUserMapper.update(claudeCodeUser,
 				Wrappers.lambdaUpdate(ClaudeCodeUser.class)
-					.eq(ClaudeCodeUser::getId, claudeCodeUser.getId())
-					.eq(ClaudeCodeUser::getResetCount, currentResetCount)
-			);
-			
-			if (updateResult > 0) {
-				log.info("用户{}成功使用重置次数,剩余次数:{}", userId, currentResetCount - 1);
-				return true;
-			} else {
-				log.warn("用户{}使用重置次数失败,可能是并发操作", userId);
-				return false;
-			}
-		} catch (Exception e) {
-			log.error("用户{}使用重置次数异常", userId, e);
-			return false;
+						.eq(ClaudeCodeUser::getId, claudeCodeUser.getId())
+						.eq(ClaudeCodeUser::getResetCount, currentResetCount)
+		);
+
+		if (updateResult > 0) {
+			log.info("用户{}成功使用重置次数,剩余次数:{}", userId, currentResetCount - 1);
+			//重置用户次数
+			CreditResetReq creditResetReq = new CreditResetReq();
+			creditResetReq.setDescription("用户使用重置次数");
+			//调用API重置用户次数
+			resetUserCredits(claudeCodeUser.getUserId(), creditResetReq);
+
+		} else {
+			throw BusinessRuntimeException.getInstance("使用重置次数失败");
 		}
 	}
 
 	@Override
+	@Transactional(rollbackFor = Throwable.class)
 	public ClaudeCodeResp useCreditCard(ClaudeCodeCreditCardUseReq req) throws Exception {
 		Long userId = req.getUserId();
 		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
-		
+
 		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
-			Wrappers.lambdaQuery(ClaudeCodeUser.class)
-				.in(ClaudeCodeUser::getUserId, userIdList)
-				.last("limit 1")
+				Wrappers.lambdaQuery(ClaudeCodeUser.class)
+						.in(ClaudeCodeUser::getUserId, userIdList)
+						.last("limit 1")
 		);
-		
+
 		if (claudeCodeUser == null) {
 			throw new BusinessRuntimeException("用户未开通Claude Code服务");
 		}
-		
+
 		ClaudeCodeCreditCard creditCard = claudeCodeCreditCardMapper.selectOne(
-			Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
-				.eq(ClaudeCodeCreditCard::getStatus, 0)
-					.in(ClaudeCodeCreditCard::getUserId, userIdList)
-					.last("limit 1")
+				Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
+						.eq(ClaudeCodeCreditCard::getStatus, 0)
+						.in(ClaudeCodeCreditCard::getUserId, userIdList)
+						.last("limit 1")
 		);
-		
+
 		if (creditCard == null) {
 			throw new BusinessRuntimeException("无可用积分卡");
 		}
-		
+
 		if (creditCard.getStatus() != 0) {
 			if (creditCard.getStatus() == 1) {
 				throw new BusinessRuntimeException("积分卡已被使用");
@@ -799,58 +801,54 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			}
 		}
 		String cardNumber = creditCard.getCardNumber();
-		
+
 		if (creditCard.getExpiryTime() != null && creditCard.getExpiryTime().before(new Date())) {
 			creditCard.setStatus(2);
 			claudeCodeCreditCardMapper.updateById(creditCard);
 			throw new BusinessRuntimeException("积分卡已过期");
 		}
-		
+
 		Integer beforeCodePoints = claudeCodeUser.getCodePoints();
 		Integer addCodePoints = creditCard.getCreditAmount();
 		Integer afterCodePoints = beforeCodePoints + addCodePoints;
-		
-		try {
-			claudeCodeUser.setCodePoints(afterCodePoints);
-			int userUpdateResult = claudeCodeUserMapper.updateById(claudeCodeUser);
-			
-			creditCard.setStatus(1);
-			creditCard.setUsedUserId(userId);
-			creditCard.setUsedTime(new Date());
-			creditCard.setRemark("使用积分卡");
-			int cardUpdateResult = claudeCodeCreditCardMapper.update(creditCard,
-					Wrappers.lambdaUpdate(ClaudeCodeCreditCard.class)
-							.eq(ClaudeCodeCreditCard::getId, creditCard.getId())
-							.eq(ClaudeCodeCreditCard::getStatus, 0)
-			);
-			
-			if (userUpdateResult > 0 && cardUpdateResult > 0) {
-				useCreditCard(userId,addCodePoints,cardNumber,"使用积分卡");
-				
-				log.info("用户{}成功使用积分卡{},增加{}积分", userId, cardNumber, addCodePoints);
-				
-				ClaudeCodeResp resp = new ClaudeCodeResp();
-				resp.setSuccess(true);
-				resp.setMessage("积分卡使用成功");
-				resp.setData(Map.of(
+		claudeCodeUser.setCodePoints(afterCodePoints);
+		int userUpdateResult = claudeCodeUserMapper.updateById(claudeCodeUser);
+
+		creditCard.setStatus(1);
+		creditCard.setUsedUserId(userId);
+		creditCard.setUsedTime(new Date());
+		creditCard.setRemark("使用积分卡");
+		int cardUpdateResult = claudeCodeCreditCardMapper.update(creditCard,
+				Wrappers.lambdaUpdate(ClaudeCodeCreditCard.class)
+						.eq(ClaudeCodeCreditCard::getId, creditCard.getId())
+						.eq(ClaudeCodeCreditCard::getStatus, 0)
+		);
+
+		if (userUpdateResult > 0 && cardUpdateResult > 0) {
+			useCreditCard(userId, addCodePoints, cardNumber, "使用积分卡");
+
+			log.info("用户{}成功使用积分卡{},增加{}积分", userId, cardNumber, addCodePoints);
+
+			ClaudeCodeResp resp = new ClaudeCodeResp();
+			resp.setSuccess(true);
+			resp.setMessage("积分卡使用成功");
+			resp.setData(Map.of(
 					"beforeCodePoints", beforeCodePoints,
 					"addCodePoints", addCodePoints,
 					"afterCodePoints", afterCodePoints
-				));
-				return resp;
-			} else {
-				throw new BusinessRuntimeException("积分卡使用失败,请重试");
-			}
-		} catch (Exception e) {
-			log.error("用户{}使用积分卡{}异常", userId, cardNumber, e);
-			throw new BusinessRuntimeException("积分卡使用失败:" + e.getMessage());
+			));
+			//调用API调整用户积分
+			adjClaudeCodeUserPoints(claudeCodeUser.getUserId(), creditCard.getCreditAmount(), "adjustment", "用户使用积分卡");
+			return resp;
+		} else {
+			throw new BusinessRuntimeException("积分卡使用失败,请重试");
 		}
 	}
 
 	@Override
 	public SearchResult<ClaudeCodeUserResetRecordView> getUserResetRecords(Long userId, Integer page, Integer limit) {
 		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
-		
+
 		return beanSearcher.search(ClaudeCodeUserResetRecordView.class, MapUtils.builder()
 			.field(ClaudeCodeUserResetRecordView::getUserId, userIdList).op(Operator.InList)
 			.page(page, limit)
@@ -861,7 +859,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 	@Override
 	public SearchResult<ClaudeCodeUserCreditCardRecordView> getUserCreditCardRecords(Long userId, Integer page, Integer limit) {
 		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
-		
+
 		return beanSearcher.search(ClaudeCodeUserCreditCardRecordView.class, MapUtils.builder()
 			.field(ClaudeCodeUserCreditCardRecordView::getUserId, userIdList).op(Operator.InList)
 			.page(page, limit)
@@ -872,16 +870,16 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 	@Override
 	public ClaudeCodeRewardDetailsResp getUserRewardDetails(Long userId) {
 		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
-		
+
 		ClaudeCodeRewardDetailsResp response = new ClaudeCodeRewardDetailsResp();
-		
+
 		// 获取用户Claude Code信息
 		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
 			Wrappers.lambdaQuery(ClaudeCodeUser.class)
 				.in(ClaudeCodeUser::getUserId, userIdList)
 				.last("limit 1")
 		);
-		
+
 		// 设置可重置次数
 		if (claudeCodeUser != null) {
 			Integer resetCount = claudeCodeUser.getResetCount();
@@ -889,7 +887,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		} else {
 			response.setResetCount(0);
 		}
-		
+
 		// 获取可用积分卡数量
 		Integer availableCreditCards = claudeCodeCreditCardMapper.selectCount(
 			Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
@@ -898,7 +896,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 				.isNull(ClaudeCodeCreditCard::getUsedUserId)
 		);
 		response.setAvailableCreditCards(availableCreditCards != null ? availableCreditCards : 0);
-		
+
 		// 获取分销相关数据
 		try {
 			User user = userMapper.selectById(userId);
@@ -933,7 +931,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			response.setGotMoney(BigDecimal.ZERO);
 			response.setWaitingMoney(BigDecimal.ZERO);
 		}
-		
+
 		return response;
 	}
 
@@ -993,4 +991,16 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 			claudeCodeUserResetRecordMapper.insert(resetRecord);
 		}
 	}
+
+	private void adjClaudeCodeUserPoints(Long userId, Integer points, String type, String description) throws Exception {
+		String apiKeyUrl = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/credits/adjust", userId);
+		Map<String, Object> parmas = new HashMap<>();
+		parmas.put("amount", points);
+		parmas.put("type", type);
+		parmas.put("description", description);
+		ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(apiKeyUrl, Jsons.toJson(parmas));
+		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
+			throw BusinessRuntimeException.getInstance("使用积分卡失败");
+		}
+	}
 }

+ 0 - 1
netflix-service/src/main/java/com/cyksj/service/coupon/impl/CouponFontServiceImpl.java

@@ -368,7 +368,6 @@ public class CouponFontServiceImpl implements CouponFontService {
 			couponUserMapper.insert(couponUser);
 		} catch (DuplicateKeyException e) {
 			log.info("用户:{}重复领取优惠券{}插入数据错误", userId, couponId);
-			throw BusinessRuntimeException.getInstance("已领取成功");
 		}
 	}
 

+ 4 - 6
netflix-web/src/main/java/com/cyksj/web/controller/claude/ClaudeCodeController.java

@@ -459,6 +459,7 @@ public class ClaudeCodeController {
 		}
 		for (GoodsDonSkuView sku : goodsDonSkuViews) {
 			if (couponSkuIds.contains(sku.getSkuId())) {
+				sku.setCouonId(coupon.getId());
 				if (coupon.getType() == Coupon.Type.discount) {
 					sku.setDiscount(coupon.getDiscount());
 					sku.setDiscountPrice(sku.getMoney().multiply(coupon.getDiscount()));
@@ -522,7 +523,7 @@ public class ClaudeCodeController {
 	 * 将指定用户的积分重置为满积分状态(used_credits设为0)
 	 */
 	@PostMapping("/users/{userId}/credits/reset")
-	public Result<CreditResetResp> resetUserCredits(@PathVariable Long userId, @RequestBody(required = false) CreditResetReq req) {
+	public Result<CreditResetResp> resetUserCredits(@PathVariable Long userId, @RequestBody(required = false) CreditResetReq req) throws Exception {
 		CreditResetResp resp = claudeCodeService.resetUserCredits(userId, req);
 		return GatewayResponse.SUCCESS.newBuilder().toResult(resp);
 	}
@@ -540,12 +541,9 @@ public class ClaudeCodeController {
 	 * 用户使用重置次数
 	 */
 	@PostMapping("/use/reset-count")
-	public Result<Map<String, Object>> useResetCount() {
+	public Result<Map<String, Object>> useResetCount() throws Exception {
 		long userId = StpUserUtil.getLoginIdAsLong();
-		boolean success = claudeCodeService.useResetCount(userId);
-		if (!success) {
-			throw BusinessRuntimeException.getInstance("重置次数不足或使用失败");
-		}
+		claudeCodeService.useResetCount(userId);
 		return GatewayResponse.SUCCESS.newBuilder().toResult();
 	}