|
|
@@ -8,24 +8,39 @@ import cn.hutool.http.HttpException;
|
|
|
import cn.hutool.http.HttpResponse;
|
|
|
import cn.hutool.http.HttpUtil;
|
|
|
import cn.hutool.http.Method;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
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.*;
|
|
|
+import com.cyksj.mapper.claudecode.ClaudeCodeCreditCardMapper;
|
|
|
+import com.cyksj.mapper.claudecode.ClaudeCodeDayResetRecordMapper;
|
|
|
+import com.cyksj.mapper.claudecode.ClaudeCodeUserCreditCardRecordMapper;
|
|
|
+import com.cyksj.mapper.claudecode.ClaudeCodeUserResetRecordMapper;
|
|
|
+import com.cyksj.mapper.manage.distribute.DistributePointsExchangeMoneyMapper;
|
|
|
+import com.cyksj.mapper.manage.distribute.DistributeWaitingSendPointsMapper;
|
|
|
import com.cyksj.model.entity.*;
|
|
|
import com.cyksj.model.manage.views.GroupsRelationView;
|
|
|
import com.cyksj.model.request.ClaudeCodeApiKeysReq;
|
|
|
+import com.cyksj.model.request.ClaudeCodeCreditCardUseReq;
|
|
|
import com.cyksj.model.request.ClaudeCodeDelReq;
|
|
|
+import com.cyksj.model.request.CreditResetReq;
|
|
|
import com.cyksj.model.response.ClaudeCodePointsHistoryResp;
|
|
|
+import com.cyksj.model.response.ClaudeCodeRewardDetailsResp;
|
|
|
+import com.cyksj.model.response.CreditResetResp;
|
|
|
import com.cyksj.model.response.TimeRateConfigsResp;
|
|
|
import com.cyksj.model.response.claudecode.ClaudeCodeResp;
|
|
|
import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
|
|
|
+import com.cyksj.model.views.ClaudeCodeUserCreditCardRecordView;
|
|
|
import com.cyksj.model.views.ClaudeCodeUserInfoView;
|
|
|
+import com.cyksj.model.views.ClaudeCodeUserResetRecordView;
|
|
|
+import com.cyksj.redis.RedisService;
|
|
|
import com.cyksj.service.claude.ClaudeCodeService;
|
|
|
import com.cyksj.service.user.UserBindRelationService;
|
|
|
import com.ejlchina.searcher.BeanSearcher;
|
|
|
+import com.ejlchina.searcher.SearchResult;
|
|
|
import com.ejlchina.searcher.param.Operator;
|
|
|
import com.ejlchina.searcher.util.MapUtils;
|
|
|
import com.github.rholder.retry.*;
|
|
|
@@ -33,11 +48,11 @@ 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.util.Date;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.util.*;
|
|
|
import java.util.concurrent.ExecutionException;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
@@ -67,6 +82,24 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
|
|
|
private final OrderDonMapper orderDonMapper;
|
|
|
|
|
|
+ private final ClaudeCodeUserResetRecordMapper claudeCodeUserResetRecordMapper;
|
|
|
+
|
|
|
+ private final ClaudeCodeUserCreditCardRecordMapper claudeCodeUserCreditCardRecordMapper;
|
|
|
+
|
|
|
+ private final ClaudeCodeCreditCardMapper claudeCodeCreditCardMapper;
|
|
|
+
|
|
|
+ private final UserMapper userMapper;
|
|
|
+
|
|
|
+ private final DistributeWaitingSendPointsMapper distributeWaitingSendPointsMapper;
|
|
|
+
|
|
|
+ private final DistributePointsExchangeMoneyMapper distributePointsExchangeMoneyMapper;
|
|
|
+
|
|
|
+ private final GoodsDonMapper goodsDonMapper;
|
|
|
+
|
|
|
+ private final ClaudeCodeDayResetRecordMapper claudeCodeDayResetRecordMapper;
|
|
|
+
|
|
|
+ private final RedisService redisService;
|
|
|
+
|
|
|
private final static String CLAUDE_CODE_API_PREFIX = "https://relay01.yhlxj.com/";
|
|
|
|
|
|
public static final String CLAUDE_CODE_HEARD_KEY = "X-Admin-Key";
|
|
|
@@ -191,7 +224,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())) {
|
|
|
@@ -425,6 +458,36 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ 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);
|
|
|
+ if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
|
|
|
+ throw BusinessRuntimeException.getInstance("重置次数失败");
|
|
|
+ }
|
|
|
+ return Jsons.parseObject(claudeCodeResp.getData(), CreditResetResp.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证时间范围
|
|
|
+ */
|
|
|
+ private void validateTimeRange(Integer startHour, Integer endHour) {
|
|
|
+ if (startHour == null || endHour == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("开始和结束小时不能为空");
|
|
|
+ }
|
|
|
+ if (startHour < 0 || startHour > 23) {
|
|
|
+ throw BusinessRuntimeException.getInstance("开始小时必须在0-23之间");
|
|
|
+ }
|
|
|
+ if (endHour < 0 || endHour > 23) {
|
|
|
+ throw BusinessRuntimeException.getInstance("结束小时必须在0-23之间");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取claude code用户id
|
|
|
*/
|
|
|
@@ -558,4 +621,393 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
return build;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public void resetUserCodePoints(Long userId, Integer resetType, String resetReason) {
|
|
|
+ List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
+ ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
|
|
|
+ Wrappers.<ClaudeCodeUser>lambdaQuery().in(ClaudeCodeUser::getUserId, userIdList)
|
|
|
+ );
|
|
|
+
|
|
|
+ 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.setResetReason(resetReason);
|
|
|
+
|
|
|
+ claudeCodeUserResetRecordMapper.insert(resetRecord);
|
|
|
+
|
|
|
+ log.info("用户{}的积分已重置", userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @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) {
|
|
|
+ throw BusinessRuntimeException.getInstance("可用重置次数为0");
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+ //重置用户次数
|
|
|
+ CreditResetReq creditResetReq = new CreditResetReq();
|
|
|
+ creditResetReq.setDescription("用户使用重置次数");
|
|
|
+ //调用API重置用户次数
|
|
|
+ resetUserCredits(claudeCodeUser.getUserId(), creditResetReq);
|
|
|
+
|
|
|
+ ClaudeCodeUserResetRecord resetRecord = new ClaudeCodeUserResetRecord();
|
|
|
+ resetRecord.setUserId(userId);
|
|
|
+ resetRecord.setNum(-1);
|
|
|
+ resetRecord.setResetReason("使用重置次数");
|
|
|
+ claudeCodeUserResetRecordMapper.insert(resetRecord);
|
|
|
+
|
|
|
+ } else {
|
|
|
+ throw BusinessRuntimeException.getInstance("使用重置次数失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Throwable.class)
|
|
|
+ public void 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")
|
|
|
+ );
|
|
|
+
|
|
|
+ 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")
|
|
|
+ );
|
|
|
+
|
|
|
+ if (creditCard == null) {
|
|
|
+ throw new BusinessRuntimeException("无可用积分卡");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (creditCard.getStatus() != 0) {
|
|
|
+ if (creditCard.getStatus() == 1) {
|
|
|
+ throw new BusinessRuntimeException("积分卡已被使用");
|
|
|
+ } else if (creditCard.getStatus() == 2) {
|
|
|
+ throw new BusinessRuntimeException("积分卡已过期");
|
|
|
+ } else {
|
|
|
+ throw new BusinessRuntimeException("积分卡状态异常");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String cardNumber = creditCard.getCardNumber();
|
|
|
+
|
|
|
+ if (creditCard.getExpiryTime() != null && creditCard.getExpiryTime().before(new Date())) {
|
|
|
+ creditCard.setStatus(2);
|
|
|
+ claudeCodeCreditCardMapper.updateById(creditCard);
|
|
|
+ throw new BusinessRuntimeException("积分卡已过期");
|
|
|
+ }
|
|
|
+
|
|
|
+ ClaudeCodeResp userBalance = getUserBalance(userId);
|
|
|
+ JSONObject data = Jsons.parseObject(userBalance.getData(), JSONObject.class);
|
|
|
+ Integer availableCredits = data.getInt("available_credits");
|
|
|
+ Integer creditLimit = data.getInt("credit_limit");
|
|
|
+ //超出积分 异常
|
|
|
+ if (availableCredits + creditCard.getCreditAmount() > creditLimit) {
|
|
|
+ throw BusinessRuntimeException.getInstance("目前使用只能补充到{0},建议您消耗更多积分后再兑换使用", creditLimit);
|
|
|
+ }
|
|
|
+
|
|
|
+ Integer beforeCodePoints = availableCredits;
|
|
|
+ Integer addCodePoints = creditCard.getCreditAmount();
|
|
|
+ Integer afterCodePoints = beforeCodePoints + addCodePoints;
|
|
|
+
|
|
|
+ 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 (cardUpdateResult > 0) {
|
|
|
+ ClaudeCodeUserCreditCardRecord creditCardRecord = new ClaudeCodeUserCreditCardRecord();
|
|
|
+ creditCardRecord.setUserId(userId);
|
|
|
+ creditCardRecord.setBeforeCodePoints(beforeCodePoints);
|
|
|
+ creditCardRecord.setAddCodePoints(addCodePoints);
|
|
|
+ creditCardRecord.setAfterCodePoints(afterCodePoints);
|
|
|
+ creditCardRecord.setCardNumber(cardNumber);
|
|
|
+ //使用一次
|
|
|
+ creditCardRecord.setNum(-1);
|
|
|
+ creditCardRecord.setUseReason(creditCard.getRemark());
|
|
|
+
|
|
|
+ claudeCodeUserCreditCardRecordMapper.insert(creditCardRecord);
|
|
|
+
|
|
|
+ log.info("用户{}成功使用积分卡{},增加{}积分", userId, cardNumber, addCodePoints);
|
|
|
+ //调用API调整用户积分
|
|
|
+ adjClaudeCodeUserPoints(claudeCodeUser.getUserId(), creditCard.getCreditAmount(), "adjustment", "用户使用积分卡");
|
|
|
+ } 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)
|
|
|
+ .orderBy(ClaudeCodeUserResetRecordView::getCreatedTime).desc()
|
|
|
+ .build());
|
|
|
+ }
|
|
|
+
|
|
|
+ @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)
|
|
|
+ .orderBy(ClaudeCodeUserCreditCardRecordView::getCreatedTime).desc()
|
|
|
+ .build());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ClaudeCodeRewardDetailsResp getUserRewardDetails(Long userId, Boolean general) {
|
|
|
+ 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();
|
|
|
+ response.setResetCount(resetCount != null ? resetCount : 0);
|
|
|
+ } else {
|
|
|
+ response.setResetCount(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取可用积分卡数量
|
|
|
+ Integer availableCreditCards = claudeCodeCreditCardMapper.selectCount(
|
|
|
+ Wrappers.lambdaQuery(ClaudeCodeCreditCard.class)
|
|
|
+ .eq(ClaudeCodeCreditCard::getStatus, 0)
|
|
|
+ .in(ClaudeCodeCreditCard::getUserId, userIdList)
|
|
|
+ .isNull(ClaudeCodeCreditCard::getUsedUserId)
|
|
|
+ );
|
|
|
+ response.setAvailableCreditCards(availableCreditCards != null ? availableCreditCards : 0);
|
|
|
+ if (claudeCodeUser.getCodePoints() > 5000) {
|
|
|
+ Integer selectCount = claudeCodeDayResetRecordMapper.selectCount(Wrappers.lambdaQuery(ClaudeCodeDayResetRecord.class).in(ClaudeCodeDayResetRecord::getUserId, userIdList).gt(ClaudeCodeDayResetRecord::getCreatedTime, DateUtil.beginOfDay(DateTime.now())));
|
|
|
+ //每日可用重置次数
|
|
|
+ response.setDayRestNum(selectCount > 0 ? 0 : 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ //是否是普通推广
|
|
|
+ if (general != null && general) {
|
|
|
+ //提现门槛
|
|
|
+ DistributePointsExchangeMoney distributePointsExchangeMoney = distributePointsExchangeMoneyMapper.selectOne(Wrappers.lambdaQuery(DistributePointsExchangeMoney.class).last("limit 1"));
|
|
|
+ response.setThresholdMoney(BigDecimal.valueOf(distributePointsExchangeMoney.getMinPoints()).divide(BigDecimal.valueOf(distributePointsExchangeMoney.getPoints())).multiply(distributePointsExchangeMoney.getMoney()));
|
|
|
+
|
|
|
+ // 获取分销相关数据
|
|
|
+ try {
|
|
|
+ User user = userMapper.selectById(userId);
|
|
|
+ List<DistributeWaitingSendPoints> distributeWaitingSendPoints = distributeWaitingSendPointsMapper.selectList(Wrappers.lambdaQuery(DistributeWaitingSendPoints.class).eq(DistributeWaitingSendPoints::getSendStatus, DistributeWaitingSendPoints.Status.waiting).eq(DistributeWaitingSendPoints::getSharedId, userId).select(DistributeWaitingSendPoints::getPoints));
|
|
|
+ BigDecimal waitingPoints = BigDecimal.ZERO;
|
|
|
+ if (!distributeWaitingSendPoints.isEmpty()) {
|
|
|
+ Optional<BigDecimal> points = distributeWaitingSendPoints.stream().map(DistributeWaitingSendPoints::getPoints).reduce(BigDecimal::add);
|
|
|
+ if (points.isPresent()) {
|
|
|
+ waitingPoints = points.get();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ GoodsDon goodsDon = goodsDonMapper.selectById(Constant.CLAUDE_CODE_GOODS_ID);
|
|
|
+ //cc 分销平台比例
|
|
|
+ if (goodsDon != null) {
|
|
|
+ response.setRate(goodsDon.getRate());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (user.getPoints().compareTo(BigDecimal.ZERO) <= 0 && waitingPoints.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ response.setGotMoney(BigDecimal.ZERO);
|
|
|
+ response.setWaitingMoney(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ BigDecimal points = BigDecimal.valueOf(distributePointsExchangeMoney.getPoints());
|
|
|
+ BigDecimal money = distributePointsExchangeMoney.getMoney();
|
|
|
+ BigDecimal oneHundred = BigDecimal.valueOf(100);
|
|
|
+ if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
|
|
|
+ response.setGotMoney(user.getPoints().divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.HALF_DOWN));
|
|
|
+ }
|
|
|
+ if (user.getPoints().compareTo(BigDecimal.ZERO) >= 0) {
|
|
|
+ response.setWaitingMoney(waitingPoints.divide(points).multiply(money).divide(oneHundred, 2, RoundingMode.DOWN));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("获取用户{}分销数据异常", userId, e);
|
|
|
+ // 设置默认值
|
|
|
+ response.setGotMoney(BigDecimal.ZERO);
|
|
|
+ response.setWaitingMoney(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void sendCreditCard(Long orderId, Long userId, Integer points, String cardNumber, String remark) {
|
|
|
+ ClaudeCodeCreditCard creditCard = new ClaudeCodeCreditCard();
|
|
|
+ creditCard.setUserId(userId);
|
|
|
+ creditCard.setOrderId(orderId);
|
|
|
+ creditCard.setCardNumber(cardNumber);
|
|
|
+ creditCard.setCreditAmount(points);
|
|
|
+ creditCard.setRemark(remark);
|
|
|
+ claudeCodeCreditCardMapper.insert(creditCard);
|
|
|
+
|
|
|
+ //积分卡明细
|
|
|
+ ClaudeCodeUserCreditCardRecord creditCardRecord = new ClaudeCodeUserCreditCardRecord();
|
|
|
+ creditCardRecord.setUserId(userId);
|
|
|
+ creditCardRecord.setCardNumber(cardNumber);
|
|
|
+ creditCardRecord.setUseReason(remark);
|
|
|
+ creditCardRecord.setNum(1);
|
|
|
+ creditCardRecord.setAddCodePoints(points);
|
|
|
+ claudeCodeUserCreditCardRecordMapper.insert(creditCardRecord);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void adjUserRestNum(Long orderId, Long userId, Integer num, String remark) {
|
|
|
+ List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
+
|
|
|
+ // 获取用户Claude Code信息
|
|
|
+ ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
|
|
|
+ Wrappers.lambdaQuery(ClaudeCodeUser.class)
|
|
|
+ .in(ClaudeCodeUser::getUserId, userIdList)
|
|
|
+ .last("limit 1")
|
|
|
+ );
|
|
|
+ if (claudeCodeUser == null) {
|
|
|
+ log.info("claude code user不存在");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Integer resetCount = claudeCodeUser.getResetCount();
|
|
|
+ claudeCodeUser.setResetCount(resetCount + num);
|
|
|
+ if (claudeCodeUser.getResetCount() < 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ int update = 0;
|
|
|
+ while (update == 0) {
|
|
|
+ update = claudeCodeUserMapper.update(claudeCodeUser, Wrappers.lambdaUpdate(ClaudeCodeUser.class).eq(ClaudeCodeUser::getUserId, claudeCodeUser.getUserId()).eq(ClaudeCodeUser::getResetCount, resetCount));
|
|
|
+ if (update == 0) {
|
|
|
+ claudeCodeUser = claudeCodeUserMapper.selectOne(
|
|
|
+ Wrappers.lambdaQuery(ClaudeCodeUser.class)
|
|
|
+ .in(ClaudeCodeUser::getUserId, userIdList)
|
|
|
+ .last("limit 1")
|
|
|
+ );
|
|
|
+ if (claudeCodeUser == null) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ resetCount = claudeCodeUser.getResetCount();
|
|
|
+ claudeCodeUser.setResetCount(resetCount + num);
|
|
|
+ if (claudeCodeUser.getResetCount() < 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //记录获取重置次数记录
|
|
|
+ ClaudeCodeUserResetRecord resetRecord = new ClaudeCodeUserResetRecord();
|
|
|
+ resetRecord.setOrderId(orderId);
|
|
|
+ resetRecord.setUserId(userId);
|
|
|
+ resetRecord.setResetReason(remark);
|
|
|
+ resetRecord.setNum(num);
|
|
|
+ claudeCodeUserResetRecordMapper.insert(resetRecord);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Throwable.class)
|
|
|
+ public void useDayResetCount(Long userId) throws Exception {
|
|
|
+ List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
+ // 获取用户Claude Code信息
|
|
|
+ ClaudeCodeUser claudeCodeUser = claudeCodeUserMapper.selectOne(
|
|
|
+ Wrappers.lambdaQuery(ClaudeCodeUser.class)
|
|
|
+ .in(ClaudeCodeUser::getUserId, userIdList)
|
|
|
+ .last("limit 1")
|
|
|
+ );
|
|
|
+ if (claudeCodeUser == null) {
|
|
|
+ log.info("claude code user不存在");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //非标准版、专业版 不给使用
|
|
|
+ if (claudeCodeUser.getCodePoints() < 5000) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Integer selectCount = claudeCodeDayResetRecordMapper.selectCount(Wrappers.lambdaQuery(ClaudeCodeDayResetRecord.class).in(ClaudeCodeDayResetRecord::getUserId, userIdList).gt(ClaudeCodeDayResetRecord::getCreatedTime, DateUtil.beginOfDay(DateTime.now())));
|
|
|
+ //今日使用为0
|
|
|
+ if (selectCount == 0) {
|
|
|
+ String idxKey = "cc:uid:" + userId;
|
|
|
+ try {
|
|
|
+ if (redisService.setNx(idxKey, userId, 5l)) {
|
|
|
+ //重置用户次数
|
|
|
+ CreditResetReq creditResetReq = new CreditResetReq();
|
|
|
+ creditResetReq.setDescription("用户使用每日重置");
|
|
|
+ //调用API重置用户次数
|
|
|
+ resetUserCredits(claudeCodeUser.getUserId(), creditResetReq);
|
|
|
+
|
|
|
+ ClaudeCodeDayResetRecord claudeCodeDayResetRecord = new ClaudeCodeDayResetRecord();
|
|
|
+ claudeCodeDayResetRecord.setUserId(userId);
|
|
|
+ claudeCodeDayResetRecord.setRelationId(claudeCodeUser.getRelationId());
|
|
|
+ claudeCodeDayResetRecordMapper.insert(claudeCodeDayResetRecord);
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ if (redisService.hasKey(idxKey)) {
|
|
|
+ redisService.del(idxKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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("使用积分卡失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|