|
|
@@ -1,22 +1,30 @@
|
|
|
package com.cyksj.service.claude.impl;
|
|
|
|
|
|
import cn.hutool.core.date.DateTime;
|
|
|
+import cn.hutool.core.lang.Assert;
|
|
|
import cn.hutool.http.HttpResponse;
|
|
|
import cn.hutool.http.HttpUtil;
|
|
|
+import cn.hutool.http.Method;
|
|
|
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.mapper.GroupsRelationMapper;
|
|
|
import com.cyksj.model.entity.GoodsDonSku;
|
|
|
import com.cyksj.model.entity.GroupsRelation;
|
|
|
+import com.cyksj.model.manage.views.GroupsRelationView;
|
|
|
import com.cyksj.model.request.ClaudeCodeApiKeysReq;
|
|
|
import com.cyksj.model.request.ClaudeCodeApiKeysStatusReq;
|
|
|
+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.ClaudeCodeUserPackageView;
|
|
|
import com.cyksj.service.claude.ClaudeCodeService;
|
|
|
import com.cyksj.service.user.UserBindRelationService;
|
|
|
+import com.ejlchina.searcher.BeanSearcher;
|
|
|
+import com.ejlchina.searcher.param.Operator;
|
|
|
+import com.ejlchina.searcher.util.MapUtils;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
@@ -40,12 +48,14 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
|
|
|
private final GroupsRelationMapper relationMapper;
|
|
|
|
|
|
+ private final BeanSearcher beanSearcher;
|
|
|
+
|
|
|
private final static String CLAUDE_CODE_API_PREFIX = "https://relay01.yhlxj.com/";
|
|
|
|
|
|
public static final String CLAUDE_CODE_API_ADMIN_KEY = "claudecodeyhlxjclaude";
|
|
|
|
|
|
@Override
|
|
|
- public void generateClaudeCodeUserInfo(Long relationId, Long userId, GoodsDonSku sku) {
|
|
|
+ public void generateOrUpdateClaudeCodeUserInfo(Long relationId, Long userId, GoodsDonSku sku, Integer orderType) {
|
|
|
List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getId, relationId).in(GroupsRelation::getUserId, userIdList));
|
|
|
Date expiryTime = relation.getExpiryTime();
|
|
|
@@ -53,17 +63,26 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
Integer codeCreditRecovery = sku.getCodeCreditRecovery();
|
|
|
//生成claude code用户套餐
|
|
|
try {
|
|
|
- createOrUpdateClaudeCodeUserPackage(userId, sku.getSpecVal(), codePoints, codeCreditRecovery, expiryTime);
|
|
|
+ createOrUpdateClaudeCodeUserPackage(relation.getUserId(), sku.getSpecVal(), codePoints, codeCreditRecovery, expiryTime);
|
|
|
+ //设置车位的套餐
|
|
|
+ relation.setCodePoints(codePoints);
|
|
|
+ relation.setCodeCreditRecovery(codeCreditRecovery);
|
|
|
+ relationMapper.updateById(relation);
|
|
|
+ if (orderType == 2) {
|
|
|
+ invalidateUserCache(userId);
|
|
|
+ }
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void createApiKeys(ClaudeCodeApiKeysReq req) {
|
|
|
+ public void createApiKeys(ClaudeCodeApiKeysReq req) throws Exception {
|
|
|
Long userId = req.getUserId();
|
|
|
if (checkClaudeCodeUser(userId)) {
|
|
|
- String apiKeyUrl = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", userId);
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ Assert.notNull(claudeCodeUserId, "您的claude code账号已过期");
|
|
|
+ String apiKeyUrl = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", claudeCodeUserId);
|
|
|
Map<String, Object> parmas = new HashMap<>();
|
|
|
parmas.put("name", req.getName());
|
|
|
Integer expiresDays = req.getExpiresDays();
|
|
|
@@ -71,62 +90,159 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
parmas.put("expires_days", expiresDays);
|
|
|
}
|
|
|
String responseBody = executeClaudeCodePostApi(apiKeyUrl, parmas.toString());
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ if (!claudeCodeResp.getSuccess()) {
|
|
|
+ throw BusinessRuntimeException.getInstance("创建失败");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void updateApiKeysStatus(ClaudeCodeApiKeysStatusReq req) {
|
|
|
-
|
|
|
+ public void updateApiKeysStatus(ClaudeCodeApiKeysStatusReq req) throws Exception {
|
|
|
+ Long userId = req.getUserId();
|
|
|
+ Integer keyId = req.getId();
|
|
|
+ String status = req.getStatus();
|
|
|
+ String keyValue = req.getKeyValue();
|
|
|
+ if (checkClaudeCodeUser(userId)) {
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ Assert.notNull(claudeCodeUserId, "您的claude code账号已过期");
|
|
|
+ String apiKeyUrl = String.format(CLAUDE_CODE_API_PREFIX + "api/keys/{userId}/{keyId}", claudeCodeUserId, keyId);
|
|
|
+ Map<String, Object> parmas = new HashMap<>();
|
|
|
+ parmas.put("status", status);
|
|
|
+ String responseBody = executeClaudeCodePostApi(apiKeyUrl, parmas.toString());
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ if (claudeCodeResp.getSuccess()) {
|
|
|
+ //更新用户apikey缓存
|
|
|
+ updateUserApiKeysCache(keyValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void deleteApiKeysById(Long userId, Long keyId) {
|
|
|
+ public void deleteApiKeysById(ClaudeCodeDelReq delReq) throws Exception {
|
|
|
+ Long userId = delReq.getUserId();
|
|
|
+ Long keyId = delReq.getKeyId();
|
|
|
+ String keyValue = delReq.getKeyValue();
|
|
|
+ if (checkClaudeCodeUser(userId)) {
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/keys/{userId}/{keyId}", claudeCodeUserId, keyId);
|
|
|
+ HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).execute();
|
|
|
+ String responseBody = execute.body();
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ if (claudeCodeResp.getSuccess()) {
|
|
|
+ //更新用户apikey缓存
|
|
|
+ updateUserApiKeysCache(keyValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * 更新api key缓存
|
|
|
+ * @param keyValue
|
|
|
+ */
|
|
|
+ private void updateUserApiKeysCache(String keyValue) {
|
|
|
+ String url = CLAUDE_CODE_API_PREFIX + "api/cache/invalidate/apikey";
|
|
|
+ Map<String, Object> parmas = new HashMap<>();
|
|
|
+ parmas.put("api_key", keyValue);
|
|
|
+ executeClaudeCodePostApi(url,parmas.toString());
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public List<ClaudeCodeUserApiKeysView> getUserApiKeys(long userId) throws Exception {
|
|
|
- String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", userId);
|
|
|
- String responseBody = executeClaudeCodeGetApi(url);
|
|
|
- ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
- if (claudeCodeResp.getSuccess()) {
|
|
|
- return Jsons.parseList(claudeCodeResp.getData(), ClaudeCodeUserApiKeysView.class);
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ if (claudeCodeUserId != null) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", userId);
|
|
|
+ String responseBody = executeClaudeCodeGetApi(url);
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ if (claudeCodeResp.getSuccess()) {
|
|
|
+ return Jsons.parseList(claudeCodeResp.getData(), ClaudeCodeUserApiKeysView.class);
|
|
|
+ }
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public ClaudeCodeUserPackageView getUserPackage(long userId) throws Exception {
|
|
|
- String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
|
|
|
- String responseBody = executeClaudeCodeGetApi(url);
|
|
|
- ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
- if (claudeCodeResp.getSuccess()) {
|
|
|
- return Jsons.parseObject(responseBody, ClaudeCodeUserPackageView.class);
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ if (claudeCodeUserId != null) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
|
|
|
+ String responseBody = executeClaudeCodeGetApi(url);
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ if (claudeCodeResp.getSuccess()) {
|
|
|
+ return Jsons.parseObject(responseBody, ClaudeCodeUserPackageView.class);
|
|
|
+ }
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public ClaudeCodePointsHistoryResp getUserPointsDetail(Long userId, String type, Integer page, Integer limit) throws Exception {
|
|
|
- String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/{userId}/credits/history?page=%s&limit=%s&type=%s", userId, page, limit, type);
|
|
|
- String responseBody = executeClaudeCodeGetApi(url);
|
|
|
- ClaudeCodePointsHistoryResp historyResp = Jsons.parseObject(responseBody, ClaudeCodePointsHistoryResp.class);
|
|
|
- return historyResp;
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ if (claudeCodeUserId != null) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/{userId}/credits/history?page=%s&limit=%s&type=%s", claudeCodeUserId, page, limit, type);
|
|
|
+ String responseBody = executeClaudeCodeGetApi(url);
|
|
|
+ ClaudeCodePointsHistoryResp historyResp = Jsons.parseObject(responseBody, ClaudeCodePointsHistoryResp.class);
|
|
|
+ return historyResp;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void getUserPointsStatisticsData(Long userId) throws Exception {
|
|
|
- String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/usage/stats", userId);
|
|
|
- String responseBody = executeClaudeCodeGetApi(url);
|
|
|
- ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ public ClaudeCodeResp getUserPointsStatisticsData(Long userId) throws Exception {
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ if (claudeCodeUserId != null) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/usage/stats", userId);
|
|
|
+ String responseBody = executeClaudeCodeGetApi(url);
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ return claudeCodeResp;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public ClaudeCodeResp getUserDashboard(Long userId) throws Exception {
|
|
|
- String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/dashboard", userId);
|
|
|
- String responseBody = executeClaudeCodeGetApi(url);
|
|
|
- ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
- return claudeCodeResp;
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ if (claudeCodeUserId != null) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/dashboard", userId);
|
|
|
+ String responseBody = executeClaudeCodeGetApi(url);
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ return claudeCodeResp;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ClaudeCodeResp getUserBalance(Long userId) throws Exception {
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ if (claudeCodeUserId != null) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/balance", userId);
|
|
|
+ String responseBody = executeClaudeCodeGetApi(url);
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ return claudeCodeResp;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ClaudeCodeResp getCreditsAnalytics(Long userId, String start, String end, String tz, String page, String limit, String order, String type) throws Exception {
|
|
|
+ Long claudeCodeUserId = getClaudeCodeUserId(userId);
|
|
|
+ if (claudeCodeUserId != null) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/users/%s/credits/analytics", userId);
|
|
|
+ String responseBody = executeClaudeCodeGetApi(url);
|
|
|
+ ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
|
|
|
+ return claudeCodeResp;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 用户缓存失效
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public void invalidateUserCache(Long userId) {
|
|
|
+ String url = String.format(CLAUDE_CODE_API_PREFIX + "api/cache/invalidate/user/%s", userId);
|
|
|
+ executeClaudeCodeGetApi(url);
|
|
|
}
|
|
|
|
|
|
public void createOrUpdateClaudeCodeUserPackage(Long userId, String planName, Integer codePoints, Integer codeCreditRecovery, Date expiryTime) throws Exception {
|
|
|
@@ -155,6 +271,21 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
return count > 0;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取claude code用户id
|
|
|
+ */
|
|
|
+ public Long getClaudeCodeUserId(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 groupsRelationView.getUserId();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* claude code GET请求
|
|
|
@@ -168,6 +299,18 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
|
|
|
return execute.body();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * claude code GET请求
|
|
|
+ */
|
|
|
+ public String executeClaudeCodeDeleteApi(String url) {
|
|
|
+ HttpResponse execute = HttpUtil.createPost(url)
|
|
|
+ .header("X-Admin-Key", CLAUDE_CODE_API_ADMIN_KEY)
|
|
|
+ .setConnectionTimeout(3000)
|
|
|
+ .setReadTimeout(3000)
|
|
|
+ .execute();
|
|
|
+ return execute.body();
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* claude code Post请求
|