|
|
@@ -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("使用积分卡失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|