zoujiajian 1 vuosi sitten
vanhempi
sitoutus
7fa347e89f

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/ClaudeCodeUserMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.ClaudeCodeUser;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodeUserMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/8/11 14:00
+ */
+public interface ClaudeCodeUserMapper extends BaseMapper<ClaudeCodeUser> {
+}

+ 51 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/ClaudeCodeUser.java

@@ -0,0 +1,51 @@
+package com.cyksj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodeUser
+ * 创建者: JavaZou
+ * 创建时间:2025/8/11 13:59
+ */
+@Getter
+@Setter
+public class ClaudeCodeUser extends BaseEntity{
+	private Long userId;
+
+	private Long relationId;
+
+	/**
+	 * claude code积分上限
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Integer codePoints;
+
+	/**
+	 * claude code每小时恢复积分
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Integer codeCreditRecovery;
+
+	/**
+	 * code 有效期
+	 */
+	private Date expiryTime;
+
+	/**
+	 * 续费升级skuid
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Long renewSkuId;
+
+	/**
+	 * 续费升级过期时间
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Date renewExpiryTime;
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/GroupsRelationView.java

@@ -143,6 +143,24 @@ public class GroupsRelationView {
     @JsonIgnore
     private String account;
 
+    /**
+     * claude code积分上限
+     */
+    @DbField("gr.code_points")
+    private Integer codePoints;
+
+    /**
+     * claude code每小时恢复积分
+     */
+    @DbField("gr.code_credit_recovery")
+    private Integer codeCreditRecovery;
+
+    /**
+     * cladue code续费规格id
+     */
+    @DbField("gr.code_sku_id")
+    private Long codeSkuId;
+
     @DbIgnore
     private Date updateExpiryTime;
 

+ 15 - 0
netflix-dao/src/main/java/com/cyksj/model/views/ClaudeCodeUserInfoView.java

@@ -0,0 +1,15 @@
+package com.cyksj.model.views;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodeUserInfoView
+ * 创建者: JavaZou
+ * 创建时间:2025/8/11 14:37
+ */
+@Getter
+@Setter
+public class ClaudeCodeUserInfoView {
+}

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

@@ -7,6 +7,7 @@ import com.cyksj.model.request.ClaudeCodeDelReq;
 import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
 import com.cyksj.model.response.claudecode.ClaudeCodeResp;
 import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
+import com.cyksj.model.views.ClaudeCodeUserInfoView;
 import com.cyksj.model.views.ClaudeCodeUserPackageView;
 
 import java.util.List;
@@ -60,4 +61,6 @@ public interface ClaudeCodeService {
 	ClaudeCodeResp getCreditsAnalytics(Long userId, String start, String end, String tz, String page, String limit, String order, String type) throws Exception;
 
 	void invalidateUserCache(Long relationUserId);
+
+	ClaudeCodeUserInfoView getClaudeCodeUserSubsInfo(Long userId);
 }

+ 87 - 12
netflix-service/src/main/java/com/cyksj/service/claude/impl/ClaudeCodeServiceImpl.java

@@ -10,8 +10,11 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.mapper.ClaudeCodeUserMapper;
 import com.cyksj.mapper.ClaudeCodeUserRenewExpiryRecordMapper;
 import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.model.entity.ClaudeCodeUser;
 import com.cyksj.model.entity.ClaudeCodeUserRenewExpiryRecord;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.entity.GroupsRelation;
@@ -22,7 +25,9 @@ import com.cyksj.model.request.ClaudeCodeDelReq;
 import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
 import com.cyksj.model.response.claudecode.ClaudeCodeResp;
 import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
+import com.cyksj.model.views.ClaudeCodeUserInfoView;
 import com.cyksj.model.views.ClaudeCodeUserPackageView;
+import com.cyksj.model.views.RenewalView;
 import com.cyksj.service.claude.ClaudeCodeService;
 import com.cyksj.service.user.UserBindRelationService;
 import com.ejlchina.searcher.BeanSearcher;
@@ -30,6 +35,7 @@ import com.ejlchina.searcher.param.Operator;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
 
 import java.util.Date;
@@ -55,6 +61,8 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 
 	private final ClaudeCodeUserRenewExpiryRecordMapper claudeCodeUserRenewExpiryRecordMapper;
 
+	private final ClaudeCodeUserMapper claudeCodeUserMapper;
+
 	private final static String CLAUDE_CODE_API_PREFIX = "https://relay01.yhlxj.com/";
 
 	public static final String CLAUDE_CODE_API_ADMIN_KEY = "claudecodeyhlxjclaude";
@@ -72,22 +80,50 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		Long skuId = sku.getId();
 		//生成claude code用户套餐
 		try {
-			createOrUpdateClaudeCodeUserPackage(relation.getUserId(), sku.getSpecVal(), codePoints, codeCreditRecovery, expiryTime);
-			//设置车位的套餐
-			relation.setCodePoints(codePoints);
-			relation.setCodeCreditRecovery(codeCreditRecovery);
-			relation.setCodeSkuId(skuId);
-			relationMapper.updateById(relation);
-			if (orderType == 2) {
-				invalidateUserCache(relationUserId);
-				//若是续费升级 记录此时续费升级的过期时间
-				if (relationCodePoints != null && relationCodePoints <= codePoints && !ObjectUtil.equal(relationCodeSkuId, skuId)) {
-					saveClaudeCodeRenewExpiryRecord(orderId, relationUserId, relationId, expiryTime, skuId);
+			Boolean isUpgrade = false;
+			//若是续费升级 记录此时续费升级的过期时间
+			if (relationCodePoints != null && relationCodePoints <= codePoints && !ObjectUtil.equal(relationCodeSkuId, skuId)) {
+				saveClaudeCodeRenewExpiryRecord(orderId, relationUserId, relationId, expiryTime, skuId);
+				isUpgrade = true;
+			}
+			ClaudeCodeResp codeUserPackage = createOrUpdateClaudeCodeUserPackage(relation.getUserId(), sku.getSpecVal(), codePoints, codeCreditRecovery, expiryTime);
+			if (codeUserPackage.getSuccess()) {
+				//设置车位的套餐
+				relation.setCodePoints(codePoints);
+				relation.setCodeCreditRecovery(codeCreditRecovery);
+				relation.setCodeSkuId(skuId);
+				relationMapper.updateById(relation);
+				if (orderType == 2) {
+					invalidateUserCache(relationUserId);
 				}
+				generateOrUpdateClaudeCodeUser(relationUserId, relationId, codePoints, codeCreditRecovery, expiryTime, isUpgrade, skuId);
 			}
 		} catch (Exception e) {
+			log.error("生成或更新claude code用户:{}套餐skuId:{} 失败,error_info:{}", userId, skuId, StringUtil.getErrorText(e));
+		}
+	}
 
+	private void generateOrUpdateClaudeCodeUser(Long relationUserId, Long relationId, Integer codePoints, Integer codeCreditRecovery, Date expiryTime, Boolean isUpgrade, Long renewSkuId) {
+		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).eq(ClaudeCodeUser::getRelationId, relationId).last("limit 1"));
+		if (claudeCodeUser == null) {
+			claudeCodeUser = new ClaudeCodeUser();
+			claudeCodeUser.setUserId(relationUserId);
+			claudeCodeUser.setRelationId(relationId);
+			claudeCodeUser.setExpiryTime(expiryTime);
+			claudeCodeUser.setCodePoints(codePoints);
+			claudeCodeUser.setCodeCreditRecovery(codeCreditRecovery);
+		}
+		if (isUpgrade) {
+			claudeCodeUser.setRenewSkuId(renewSkuId);
+			claudeCodeUser.setRenewExpiryTime(expiryTime);
 		}
+		if (claudeCodeUser.getId() == null) {
+			try {
+				claudeCodeUserMapper.insert(claudeCodeUser);
+			} catch (DuplicateKeyException e) {
+				log.info("插入claude code user 重复");
+			}
+		} else claudeCodeUserMapper.updateById(claudeCodeUser);
 	}
 
 	@Override
@@ -259,7 +295,45 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		executeClaudeCodeGetApi(url);
 	}
 
-	public void createOrUpdateClaudeCodeUserPackage(Long userId, String planName, Integer codePoints, Integer codeCreditRecovery, Date expiryTime) throws Exception {
+	@Override
+	public ClaudeCodeUserInfoView getClaudeCodeUserSubsInfo(Long userId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		//是否有该车票
+		GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
+				.field(GroupsRelationView::getUserId, userIdList).op(Operator.InList)
+				.field(GroupsRelationView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
+				.field(GroupsRelationView::getExpiryTime, DateTime.now())
+				.build());
+		if (groupsRelationView == null) {
+			return null;
+		}
+		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeCodeUser.class).in(ClaudeCodeUser::getUserId, userIdList).last("limit 1"));
+		if (claudeCodeUser == null) {
+			if (groupsRelationView != null) {
+				claudeCodeUser = new ClaudeCodeUser();
+				claudeCodeUser.setCodePoints(groupsRelationView.getCodePoints());
+				claudeCodeUser.setCodeCreditRecovery(groupsRelationView.getCodeCreditRecovery());
+				claudeCodeUser.setRelationId(groupsRelationView.getId());
+				claudeCodeUser.setUserId(groupsRelationView.getUserId());
+				claudeCodeUser.setRenewSkuId(groupsRelationView.getCodeSkuId());
+				claudeCodeUser.setExpiryTime(groupsRelationView.getExpiryTime());
+				claudeCodeUser.setRenewExpiryTime(groupsRelationView.getExpiryTime());
+				claudeCodeUserMapper.insert(claudeCodeUser);
+			}
+		} else {
+			Integer codePoints = claudeCodeUser.getCodePoints();
+			Integer relationViewCodePoints = groupsRelationView.getCodePoints();
+			if (codePoints < relationViewCodePoints) {
+				claudeCodeUser.setCodePoints(relationViewCodePoints);
+				claudeCodeUser.setCodeCreditRecovery(groupsRelationView.getCodeCreditRecovery());
+				claudeCodeUser.setRenewExpiryTime(groupsRelationView.getExpiryTime());
+				claudeCodeUser.setRenewSkuId(groupsRelationView.getSkuId());
+			}
+			claudeCodeUser.setExpiryTime(groupsRelationView.getExpiryTime());
+		}
+	}
+
+	public ClaudeCodeResp createOrUpdateClaudeCodeUserPackage(Long userId, String planName, Integer codePoints, Integer codeCreditRecovery, Date expiryTime) throws Exception {
 		Map<String, Object> parmas = new HashMap<>();
 		parmas.put("plan_name", planName.replaceAll(";", ""));
 		parmas.put("credit_limit", codePoints);
@@ -271,6 +345,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		if (claudeCodeResp.getSuccess()) {
 			log.info("用户claude code用户:{}套餐:{}创建或更新成功", userId, planName);
 		}
+		return claudeCodeResp;
 	}
 
 

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

@@ -11,6 +11,7 @@ import com.cyksj.model.request.ClaudeCodeDelReq;
 import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
 import com.cyksj.model.response.claudecode.ClaudeCodeResp;
 import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
+import com.cyksj.model.views.ClaudeCodeUserInfoView;
 import com.cyksj.model.views.ClaudeCodeUserPackageView;
 import com.cyksj.model.views.RenewalView;
 import com.cyksj.service.claude.ClaudeCodeService;
@@ -105,15 +106,10 @@ public class ClaudeCodeController {
 	 * 用户订阅车票信息
 	 */
 	@GetMapping("/get/user/subs/info")
-	public Result<RenewalView> getUserSubsInfo() {
+	public Result<ClaudeCodeUserInfoView> getUserSubsInfo() {
 		long userId = StpUserUtil.getLoginIdAsLong();
-		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
-		RenewalView renewalView = beanSearcher.searchFirst(RenewalView.class, MapUtils.flatBuilder(request.getParameterMap())
-				.field(RenewalView::getUserId, userIdList).op(Operator.InList)
-				.field(RenewalView::getGoodsId, Constant.CLAUDE_CODE_GOODS_ID)
-				.field(RenewalView::getExpiryTime, DateTime.now()).op(Operator.GreaterThan)
-				.build());
-		return GatewayResponse.SUCCESS.newBuilder().toResult(renewalView);
+		ClaudeCodeUserInfoView claudeCodeUserInfoView = claudeCodeService.getClaudeCodeUserSubsInfo(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(claudeCodeUserInfoView);
 	}
 
 	/**