Преглед на файлове

用户次数重置;用户积分卡

zoujiajian преди 1 година
родител
ревизия
4808b9c333

+ 14 - 0
netflix-dao/src/main/java/com/cyksj/mapper/claudecode/ClaudeCodeUserCreditCardRecordMapper.java

@@ -0,0 +1,14 @@
+package com.cyksj.mapper.claudecode;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.ClaudeCodeUserCreditCardRecord;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodeUserCreditCardRecordMapper
+ * 创建者: Claude
+ * 创建时间:2025/8/26
+ * 描述: ClaudeCode用户积分卡使用记录Mapper
+ */
+public interface ClaudeCodeUserCreditCardRecordMapper extends BaseMapper<ClaudeCodeUserCreditCardRecord> {
+}

+ 14 - 0
netflix-dao/src/main/java/com/cyksj/mapper/claudecode/ClaudeCodeUserResetRecordMapper.java

@@ -0,0 +1,14 @@
+package com.cyksj.mapper.claudecode;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.ClaudeCodeUserResetRecord;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodeUserResetRecordMapper
+ * 创建者: Claude
+ * 创建时间:2025/8/26
+ * 描述: ClaudeCode用户重置次数记录Mapper
+ */
+public interface ClaudeCodeUserResetRecordMapper extends BaseMapper<ClaudeCodeUserResetRecord> {
+}

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

@@ -69,4 +69,10 @@ public class ClaudeCodeUser extends BaseEntity{
 	 * 需要重试 默认false
 	 */
 	private Boolean isRetry;
+
+	/**
+	 * 重置次数
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private Integer resetCount;
 }

+ 61 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/ClaudeCodeUserCreditCardRecord.java

@@ -0,0 +1,61 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodeUserCreditCardRecord
+ * 创建者: Claude
+ * 创建时间:2025/8/26
+ * 描述: ClaudeCode用户积分卡使用记录表
+ */
+@Getter
+@Setter
+public class ClaudeCodeUserCreditCardRecord extends BaseEntity {
+    
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    
+    /**
+     * 使用前积分值
+     */
+    private Integer beforeCodePoints;
+    
+    /**
+     * 增加的积分值
+     */
+    private Integer addCodePoints;
+    
+    /**
+     * 使用后积分值
+     */
+    private Integer afterCodePoints;
+    
+    /**
+     * 积分卡类型 1:普通积分卡 2:高级积分卡
+     */
+    private Integer cardType;
+    
+    /**
+     * 积分卡编号/批次号
+     */
+    private String cardNumber;
+    
+    /**
+     * 操作人ID
+     */
+    private Long operatorId;
+    
+    /**
+     * 操作人姓名
+     */
+    private String operatorName;
+    
+    /**
+     * 使用原因
+     */
+    private String useReason;
+}

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

@@ -0,0 +1,51 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodeUserResetRecord
+ * 创建者: Claude
+ * 创建时间:2025/8/26
+ * 描述: ClaudeCode用户重置次数记录表
+ */
+@Getter
+@Setter
+public class ClaudeCodeUserResetRecord extends BaseEntity {
+    
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    
+    /**
+     * 重置前积分值
+     */
+    private Integer beforeCodePoints;
+    
+    /**
+     * 重置后积分值
+     */
+    private Integer afterCodePoints;
+    
+    /**
+     * 重置类型 1:手动重置 2:系统重置
+     */
+    private Integer resetType;
+    
+    /**
+     * 操作人ID
+     */
+    private Long operatorId;
+    
+    /**
+     * 操作人姓名
+     */
+    private String operatorName;
+    
+    /**
+     * 重置原因
+     */
+    private String resetReason;
+}

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

@@ -98,4 +98,19 @@ public interface ClaudeCodeService {
 	 * 将指定用户的积分重置为满积分状态(used_credits设为0)
 	 */
 	CreditResetResp resetUserCredits(Long userId, CreditResetReq req);
+
+	/**
+	 * 重置用户codePoints到原始值并记录重置次数
+	 */
+	void resetUserCodePoints(Long userId, Integer resetType, Long operatorId, String operatorName, String resetReason);
+
+	/**
+	 * 使用积分卡增加用户codePoints并记录使用次数
+	 */
+	void useCreditCard(Long userId, Integer addCodePoints, Integer cardType, String cardNumber, Long operatorId, String operatorName, String useReason);
+
+	/**
+	 * 用户使用重置次数 - 保持幂等性
+	 */
+	boolean useResetCount(Long userId);
 }

+ 108 - 1
netflix-service/src/main/java/com/cyksj/service/claude/impl/ClaudeCodeServiceImpl.java

@@ -14,6 +14,8 @@ import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.mapper.*;
+import com.cyksj.mapper.claudecode.ClaudeCodeUserResetRecordMapper;
+import com.cyksj.mapper.claudecode.ClaudeCodeUserCreditCardRecordMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.GroupsRelationView;
 import com.cyksj.model.request.ClaudeCodeApiKeysReq;
@@ -68,6 +70,10 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 
 	private final OrderDonMapper orderDonMapper;
 
+	private final ClaudeCodeUserResetRecordMapper claudeCodeUserResetRecordMapper;
+
+	private final ClaudeCodeUserCreditCardRecordMapper claudeCodeUserCreditCardRecordMapper;
+
 	private final static String CLAUDE_CODE_API_PREFIX = "https://relay01.yhlxj.com/";
 
 	public static final String CLAUDE_CODE_API_ADMIN_KEY = "claudecodeyhlxjclaude";
@@ -561,7 +567,6 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		}
 	}
 
-
 	/**
 	 * claude code Post请求
 	 */
@@ -651,4 +656,106 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		return build;
 	}
 
+	@Override
+	public void resetUserCodePoints(Long userId, Integer resetType, Long operatorId, String operatorName, String resetReason) {
+		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
+			Wrappers.<ClaudeCodeUser>lambdaQuery().eq(ClaudeCodeUser::getUserId, userId)
+		);
+		
+		if (claudeCodeUser == null) {
+			throw new BusinessRuntimeException("用户不存在或未开通Claude Code服务");
+		}
+
+		Integer beforeCodePoints = claudeCodeUser.getCodePoints();
+		Integer afterCodePoints = claudeCodeUser.getOriCodePoints();
+
+		claudeCodeUser.setCodePoints(afterCodePoints);
+		claudeCodeUserMapper.updateById(claudeCodeUser);
+
+		ClaudeCodeUserResetRecord resetRecord = new ClaudeCodeUserResetRecord();
+		resetRecord.setUserId(userId);
+		resetRecord.setBeforeCodePoints(beforeCodePoints);
+		resetRecord.setAfterCodePoints(afterCodePoints);
+		resetRecord.setResetType(resetType);
+		resetRecord.setOperatorId(operatorId);
+		resetRecord.setOperatorName(operatorName);
+		resetRecord.setResetReason(resetReason);
+
+		claudeCodeUserResetRecordMapper.insert(resetRecord);
+		
+		log.info("用户{}的积分已重置,操作人:{}", userId, operatorName);
+	}
+
+	@Override
+	public void useCreditCard(Long userId, Integer addCodePoints, Integer cardType, String cardNumber, Long operatorId, String operatorName, String useReason) {
+		ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
+			Wrappers.<ClaudeCodeUser>lambdaQuery().eq(ClaudeCodeUser::getUserId, userId)
+		);
+		
+		if (claudeCodeUser == null) {
+			throw new BusinessRuntimeException("用户不存在或未开通Claude Code服务");
+		}
+
+		Integer beforeCodePoints = claudeCodeUser.getCodePoints();
+		Integer afterCodePoints = beforeCodePoints + addCodePoints;
+
+		claudeCodeUser.setCodePoints(afterCodePoints);
+		claudeCodeUserMapper.updateById(claudeCodeUser);
+
+		ClaudeCodeUserCreditCardRecord creditCardRecord = new ClaudeCodeUserCreditCardRecord();
+		creditCardRecord.setUserId(userId);
+		creditCardRecord.setBeforeCodePoints(beforeCodePoints);
+		creditCardRecord.setAddCodePoints(addCodePoints);
+		creditCardRecord.setAfterCodePoints(afterCodePoints);
+		creditCardRecord.setCardType(cardType);
+		creditCardRecord.setCardNumber(cardNumber);
+		creditCardRecord.setOperatorId(operatorId);
+		creditCardRecord.setOperatorName(operatorName);
+		creditCardRecord.setUseReason(useReason);
+
+		claudeCodeUserCreditCardRecordMapper.insert(creditCardRecord);
+		
+		log.info("用户{}使用积分卡增加{}积分,操作人:{}", userId, addCodePoints, operatorName);
+	}
+
+	@Override
+	public boolean useResetCount(Long userId) {
+		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;
+		}
+		
+		try {
+			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;
+		}
+	}
+
 }

+ 15 - 0
netflix-web/src/main/java/com/cyksj/web/controller/claude/ClaudeCodeController.java

@@ -533,4 +533,19 @@ public class ClaudeCodeController {
 		List<ClaudeCodeMultiplier> claudeCodeMultipliers = beanSearcher.searchAll(ClaudeCodeMultiplier.class, MapUtils.builder().build());
 		return GatewayResponse.SUCCESS.newBuilder().toResult(claudeCodeMultipliers);
 	}
+
+	/**
+	 * 用户使用重置次数
+	 */
+	@PostMapping("/use/reset-count")
+	public Result<Map<String, Object>> useResetCount() {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		boolean success = claudeCodeService.useResetCount(userId);
+		
+		Map<String, Object> result = new HashMap<>();
+		result.put("success", success);
+		result.put("message", success ? "重置次数使用成功" : "重置次数不足或使用失败");
+		
+		return GatewayResponse.SUCCESS.newBuilder().toResult(result);
+	}
 }