zoujiajian 11 сар өмнө
parent
commit
ac30a12e8a

+ 61 - 0
netflix-service/src/main/java/com/cyksj/service/api/ClaudeCodexApiService.java

@@ -0,0 +1,61 @@
+package com.cyksj.service.api;
+
+import com.cyksj.model.request.ClaudeCodeApiKeysReq;
+import com.cyksj.model.response.claudecode.ClaudeCodeResp;
+import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodexApiService
+ * 创建者: JavaZou
+ * 创建时间:2025/9/25 16:35
+ */
+public interface ClaudeCodexApiService {
+
+	/**
+	 * 创建keys
+	 * @param req
+	 * @return
+	 * @throws Exception
+	 */
+	ClaudeCodeResp createApiKeys(ClaudeCodeApiKeysReq req) throws Exception;
+
+	/**
+	 * 删除keys
+	 */
+	void deleteApiKeysById(Long userId, Long keyId) throws Exception;
+
+
+	/**
+	 * key列表
+	 */
+	List<ClaudeCodeUserApiKeysView> getUserApiKeys(Long codexUserId);
+
+	/**
+	 * 生成或更新codex套餐
+	 */
+	ClaudeCodeResp createOrUpdateCodexUserPackageApi(Long userId, String planName, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime) throws Exception;
+
+	/**
+	 * 删除codex用户套餐
+	 */
+	boolean delCodexUserPackages(Long userId);
+
+	/**
+	 * 获取用户OpenAI使用统计
+	 */
+	ClaudeCodeResp getCodexUserOpenAIUsage(Long userId, String period);
+
+	/**
+	 * codex 用户仪表盘
+	 */
+	ClaudeCodeResp getCodexUserDashboard(Long userId);
+
+	/**
+	 * codex用户使用量统计
+	 */
+	ClaudeCodeResp getCodexUserAnalytics(Long userId, String start, String end, Integer page, Integer limit, String order);
+}

+ 227 - 0
netflix-service/src/main/java/com/cyksj/service/api/impl/ClaudeCodexApiServiceImpl.java

@@ -0,0 +1,227 @@
+package com.cyksj.service.api.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.http.HttpException;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.http.Method;
+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.model.request.ClaudeCodeApiKeysReq;
+import com.cyksj.model.response.claudecode.ClaudeCodeResp;
+import com.cyksj.model.views.ClaudeCodeUserApiKeysView;
+import com.cyksj.service.api.ClaudeCodexApiService;
+import com.github.rholder.retry.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: ClaudeCodexApiServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2025/9/25 16:35
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class ClaudeCodexApiServiceImpl implements ClaudeCodexApiService {
+
+	@Override
+	public ClaudeCodeResp createApiKeys(ClaudeCodeApiKeysReq req) throws Exception {
+		String apiKeyUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", req.getUserId());
+		Map<String, Object> parmas = new HashMap<>();
+		parmas.put("name", req.getName());
+		Integer expiresDays = req.getExpiresDays();
+		if (expiresDays != null) {
+			parmas.put("expires_days", expiresDays);
+		}
+		ClaudeCodeResp claudeCodeResp = executePostApi(apiKeyUrl, Jsons.toJson(parmas));
+		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
+			throw BusinessRuntimeException.getInstance("创建失败");
+		}
+		return claudeCodeResp;
+	}
+
+	@Override
+	public void deleteApiKeysById(Long userId, Long keyId) throws Exception {
+		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", userId, keyId);
+		HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
+		String responseBody = execute.body();
+		ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
+		if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
+			log.error("删除key失败:{}", claudeCodeResp.getMessage());
+			throw BusinessRuntimeException.getInstance("删除失败");
+		}
+	}
+
+	@Override
+	public List<ClaudeCodeUserApiKeysView> getUserApiKeys(Long codexUserId) {
+		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", codexUserId);
+		ClaudeCodeResp claudeCodeResp = executeGetApi(url);
+		return Jsons.parseList(claudeCodeResp.getData(), ClaudeCodeUserApiKeysView.class);
+	}
+
+	@Override
+	public ClaudeCodeResp createOrUpdateCodexUserPackageApi(Long userId, String planName, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime) throws Exception {
+		Map<String, Object> params = new HashMap<>();
+		params.put("plan_name", planName.replaceAll(";", ""));
+		params.put("openai_daily_limit", openaiDailyLimit);
+		params.put("openai_quota", openaiQuota);
+		params.put("expire_time", DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss"));
+		//claude 类型
+		params.put("service_type", "openai");
+
+		String planUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
+		ClaudeCodeResp codexResp = executePostApi(planUrl, Jsons.toJson(params));
+
+		if (!"success".equals(codexResp.getMessage())) {
+			log.info("用户codex用户:{}套餐:{}创建或更新失败,info:{}", userId, planName, codexResp.getMessage());
+			throw BusinessRuntimeException.getInstance("调用codex 套餐接口失败");
+		}
+
+		return codexResp;
+	}
+
+	@Override
+	public boolean delCodexUserPackages(Long userId) {
+		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan?service_type=openai", userId);
+		try {
+			ClaudeCodeResp claudeCodeResp = executeDeletedApi(url);
+			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
+				log.error("删除用户:{} codex套餐失败:{}", userId, claudeCodeResp.getMessage());
+				return Boolean.FALSE;
+			}
+			return Boolean.TRUE;
+		} catch (Exception e) {
+			log.error("删除用户:{} codex套餐报错:{}", userId, StringUtil.getErrorText(e));
+		}
+		return Boolean.FALSE;
+	}
+
+	@Override
+	public ClaudeCodeResp getCodexUserOpenAIUsage(Long userId, String period) {
+		// 调用Codex API获取实时使用统计
+		String usageUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/usage?period=%s", userId, period);
+		ClaudeCodeResp codexResp = executeGetApi(usageUrl);
+		return codexResp;
+	}
+
+	@Override
+	public ClaudeCodeResp getCodexUserDashboard(Long userId) {
+		// 调用Codex API获取用户控制台数据
+		String dashboardUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/dashboard", userId);
+		ClaudeCodeResp codexResp = executeGetApi(dashboardUrl);
+		return codexResp;
+	}
+
+	@Override
+	public ClaudeCodeResp getCodexUserAnalytics(Long userId, String start, String end, Integer page, Integer limit, String order) {
+		// 调用Codex API获取用户分析数据
+		String analyticsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/analytics?start=%s&end=%s&page=%s&limit=%s&order=%s", userId, start, end, page, limit, order);
+		ClaudeCodeResp codexResp = executeGetApi(analyticsUrl);
+		return codexResp;
+	}
+
+	/**
+	 * GET请求
+	 */
+	public ClaudeCodeResp executeGetApi(String url) {
+		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
+		try {
+			return build.call(() -> {
+				try {
+					HttpResponse execute = HttpUtil.createGet(url)
+							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
+							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
+							.execute();
+					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
+					if (!Constant.SUCCESS.equals(resp.getMessage())) {
+						log.error("GET URL:{}接口返回msg:{}", url, resp.getMessage());
+					}
+					return resp;
+				} catch (HttpException e) {
+					return null;
+				}
+			});
+		} catch (ExecutionException | RetryException e) {
+			log.error("重试调用GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
+			throw BusinessRuntimeException.getInstance("接口请求失败");
+		}
+	}
+
+	/**
+	 * Post请求
+	 */
+	public ClaudeCodeResp executePostApi(String url, String body) {
+		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
+		try {
+			return build.call(() -> {
+				try {
+					HttpResponse execute = HttpUtil.createPost(url)
+							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
+							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
+							.body(body)
+							.execute();
+					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
+					if (!Constant.SUCCESS.equals(resp.getMessage())) {
+						log.error("POST URL:{}接口返回msg:{}", url, resp.getMessage());
+					}
+					return resp;
+				} catch (Exception e) {
+					return null;
+				}
+			});
+		} catch (ExecutionException | RetryException e) {
+			log.info("重试调用 POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
+			throw BusinessRuntimeException.getInstance("接口请求失败");
+		}
+	}
+
+	/**
+	 * claude code DELETE请求
+	 */
+	public ClaudeCodeResp executeDeletedApi(String url) {
+		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
+		try {
+			return build.call(() -> {
+				try {
+					HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
+					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
+					if (!Constant.SUCCESS.equals(resp.getMessage())) {
+						log.error("DELETE URL:{}接口返回msg:{}", url, resp.getMessage());
+					}
+					return resp;
+				} catch (HttpException e) {
+					return null;
+				}
+			});
+		} catch (ExecutionException | RetryException e) {
+			log.error("重试调用DELETE请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
+			throw BusinessRuntimeException.getInstance("接口请求失败");
+		}
+	}
+
+	public Retryer getApiRetryer(Integer sleepSecond, Integer attemptNum) {
+		Retryer build = RetryerBuilder.newBuilder()
+				.retryIfException()
+				//运行时异常重试
+				.retryIfRuntimeException()
+				//false重试
+				.retryIfResult(res -> res == null)
+				//1s 间隔
+				.withWaitStrategy(WaitStrategies.fixedWait(sleepSecond, TimeUnit.SECONDS))
+				//停止策略 : 尝试请求3次
+				.withStopStrategy(StopStrategies.stopAfterAttempt(attemptNum)).build();
+		return build;
+	}
+}

+ 8 - 23
netflix-service/src/main/java/com/cyksj/service/claude/impl/ClaudeCodeServiceImpl.java

@@ -34,6 +34,7 @@ import com.cyksj.model.response.TimeRateConfigsResp;
 import com.cyksj.model.response.claudecode.ClaudeCodeResp;
 import com.cyksj.model.views.*;
 import com.cyksj.redis.RedisService;
+import com.cyksj.service.api.ClaudeCodexApiService;
 import com.cyksj.service.claude.ClaudeCodeService;
 import com.cyksj.service.codex.CodexService;
 import com.cyksj.service.user.UserBindRelationService;
@@ -102,6 +103,8 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 	
 	private final CodexUserMapper codexUserMapper;
 
+	private final ClaudeCodexApiService claudeCodexApiService;
+
 	@Override
 	public void generateOrUpdateClaudeCodeUserInfo(Long orderId, Long relationId, Long userId, GoodsDonSku sku, Integer orderType) {
 		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
@@ -199,18 +202,9 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		if (checkClaudeCodeUser(userId)) {
 			Long claudeCodeUserId = getClaudeCodeUserId(userId);
 			Assert.notNull(claudeCodeUserId, "您的claude code账号已过期");
-			String apiKeyUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", claudeCodeUserId);
-			Map<String, Object> parmas = new HashMap<>();
-			parmas.put("name", req.getName());
-			Integer expiresDays = req.getExpiresDays();
-			if (expiresDays != null) {
-				parmas.put("expires_days", expiresDays);
-			}
-			ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(apiKeyUrl, Jsons.toJson(parmas));
-			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
-				throw BusinessRuntimeException.getInstance("创建失败");
-			}
-			return claudeCodeResp;
+
+			req.setUserId(claudeCodeUserId);
+			return claudeCodexApiService.createApiKeys(req);
 		}
 		throw new BusinessRuntimeException("您还没有claudecode账号");
 	}
@@ -221,14 +215,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 		Long keyId = delReq.getKeyId();
 		if (checkClaudeCodeUser(userId)) {
 			Long claudeCodeUserId = getClaudeCodeUserId(userId);
-			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", claudeCodeUserId, keyId);
-			HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
-			String responseBody = execute.body();
-			ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
-			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
-				log.error("删除key失败:{}", claudeCodeResp.getMessage());
-				throw BusinessRuntimeException.getInstance("删除失败");
-			}
+			claudeCodexApiService.deleteApiKeysById(claudeCodeUserId, keyId);
 		}
 	}
 
@@ -236,9 +223,7 @@ public class ClaudeCodeServiceImpl implements ClaudeCodeService {
 	public List<ClaudeCodeUserApiKeysView> getUserApiKeys(long userId) throws Exception {
 		Long claudeCodeUserId = getClaudeCodeUserId(userId);
 		if (claudeCodeUserId != null) {
-			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", claudeCodeUserId);
-			ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
-			return Jsons.parseList(claudeCodeResp.getData(), ClaudeCodeUserApiKeysView.class);
+			return claudeCodexApiService.getUserApiKeys(claudeCodeUserId);
 		}
 		return null;
 	}

+ 0 - 10
netflix-service/src/main/java/com/cyksj/service/codex/CodexService.java

@@ -25,11 +25,6 @@ import java.util.List;
  */
 public interface CodexService {
     
-    /**
-     * 获取用户Codex信息
-     */
-    CodexUserInfoView getCodexUserInfo(Long userId);
-    
     /**
      * 创建或更新用户套餐
      */
@@ -45,11 +40,6 @@ public interface CodexService {
      */
     ClaudeCodeResp updateUserOpenAIDailyLimit(Long userId, UpdateDailyLimitRequest request);
     
-    /**
-     * 获取系统OpenAI指标统计
-     */
-    ClaudeCodeResp getSystemMetrics(String period, String metric);
-    
     /**
      * 获取Java系统专用的用户OpenAI控制台数据
      */

+ 17 - 271
netflix-service/src/main/java/com/cyksj/service/codex/impl/CodexServiceImpl.java

@@ -6,7 +6,6 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HttpException;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.http.Method;
@@ -40,6 +39,7 @@ import com.cyksj.model.views.CodexUserInfoView;
 import com.cyksj.model.views.CouponNewUserView;
 import com.cyksj.model.views.CouponUserView;
 import com.cyksj.redis.RedisService;
+import com.cyksj.service.api.ClaudeCodexApiService;
 import com.cyksj.service.codex.CodexService;
 import com.cyksj.service.coupon.CouponFontService;
 import com.cyksj.service.groups.GroupsFuncService;
@@ -48,7 +48,10 @@ import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.param.Operator;
 import com.ejlchina.searcher.util.MapBuilder;
 import com.ejlchina.searcher.util.MapUtils;
-import com.github.rholder.retry.*;
+import com.github.rholder.retry.Retryer;
+import com.github.rholder.retry.RetryerBuilder;
+import com.github.rholder.retry.StopStrategies;
+import com.github.rholder.retry.WaitStrategies;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
@@ -114,69 +117,8 @@ public class CodexServiceImpl implements CodexService {
 	private final CouponFontService couponFontService;
 
 	private static final Sequence SEQUENCE = new Sequence(0);
-	@Override
-	public CodexUserInfoView getCodexUserInfo(Long userId) {
-		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
-		CodexUser codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
-		// 查询Claude Code信息
-		CodexUserInfoView.ClaudeCodeInfo claudeCodeInfo = getClaudeCodeInfo(userId);
-
-		if (codexUser == null) {
-			//是否有claude code
-			if (claudeCodeInfo != null && claudeCodeInfo.getClaudeDailyLimit() != null) {
-				GoodsDonSku sku = null;
-				if (claudeCodeInfo.getRenewSkuId() != null) {
-					sku = skuMapper.selectById(claudeCodeInfo.getRenewSkuId());
-				}
-				//续费升级规格不存在 或者 不赠送codex
-				if (sku == null || !sku.getIsCodex()) {
-					GroupsRelation relation = relationMapper.selectById(claudeCodeInfo.getRelationId());
-					GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId());
-					sku = skuMapper.selectById(groupsTrips.getSkuId());
-				}
-
-				//sku 存在并且开启赠送codex
-				if (sku != null && sku.getIsCodex()) {
-					CodexUserPackageReq codexPackageReq = CodexUserPackageReq.builder()
-							.userId(claudeCodeInfo.getUserId())
-							.planName(sku.getCodexPlanName())
-							.openaiDailyLimit(sku.getOpenaiDailyLimit())
-							.openaiQuota(sku.getOpenaiQuota())
-							.expiryTime(claudeCodeInfo.getExpiryTime())
-							.build();
-					createOrUpdateUserPackage(codexPackageReq);
-					codexUser = codexUserMapper.selectOne(Wrappers.lambdaQuery(CodexUser.class).in(CodexUser::getUserId, userIdList).last("limit 1"));
-				}
-			}
-			if (codexUser == null) {
-				return null;
-			}
-		}
 
-
-		return CodexUserInfoView.builder().planName(codexUser.getPlanName()).openaiDailyLimit(codexUser.getOpenaiDailyLimit()).openaiQuota(codexUser.getOpenaiQuota()).relationId(codexUser.getRelationId()).claudeCodeInfo(claudeCodeInfo).build();
-	}
-
-	private CodexUserInfoView.ClaudeCodeInfo getClaudeCodeInfo(Long userId) {
-		// 获取用户关联的ID列表
-		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) {
-			return null;
-		}
-
-		return CodexUserInfoView.ClaudeCodeInfo.builder()
-				.userId(claudeCodeUser.getUserId())
-				.planName(claudeCodeUser.getPlanName())
-				.relationId(claudeCodeUser.getRelationId())
-				.claudeDailyLimit(claudeCodeUser.getClaudeDailyLimit())
-				.claudeQuota(claudeCodeUser.getClaudeQuota())
-				.expiryTime(claudeCodeUser.getExpiryTime())
-				.renewSkuId(claudeCodeUser.getRenewSkuId())
-				.renewExpiryTime(claudeCodeUser.getRenewExpiryTime()).build();
-	}
+	private final ClaudeCodexApiService claudeCodexApiService;
 
 	@Override
 	public void createOrUpdateUserPackage(CodexUserPackageReq req) {
@@ -213,23 +155,7 @@ public class CodexServiceImpl implements CodexService {
 	 */
 	@Override
 	public ClaudeCodeResp createOrUpdateCodexUserPackageApi(Long userId, String planName, Integer openaiDailyLimit, Integer openaiQuota, Date expiryTime) throws Exception {
-		Map<String, Object> params = new HashMap<>();
-		params.put("plan_name", planName.replaceAll(";", ""));
-		params.put("openai_daily_limit", openaiDailyLimit);
-		params.put("openai_quota", openaiQuota);
-		params.put("expire_time", DateUtil.format(expiryTime, "yyyy-MM-dd HH:mm:ss"));
-		//claude 类型
-		params.put("service_type", "openai");
-
-		String planUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan", userId);
-		ClaudeCodeResp codexResp = executeCodexPostApi(planUrl, Jsons.toJson(params));
-
-		if (!"success".equals(codexResp.getMessage())) {
-			log.info("用户codex用户:{}套餐:{}创建或更新失败,info:{}", userId, planName, codexResp.getMessage());
-			throw BusinessRuntimeException.getInstance("调用codex 套餐接口失败");
-		}
-
-		return codexResp;
+		return claudeCodexApiService.createOrUpdateCodexUserPackageApi(userId, planName, openaiDailyLimit, openaiQuota, expiryTime);
 	}
 
 	@Override
@@ -468,17 +394,9 @@ public class CodexServiceImpl implements CodexService {
 		if (checkCodexUser(userId)) {
 			Long codexUserId = getCodexUserId(userId);
 			Assert.notNull(codexUserId, "您的codex账号已过期");
-			String apiKeyUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", codexUserId);
-			Map<String, Object> parmas = new HashMap<>();
-			parmas.put("name", req.getName());
-			Integer expiresDays = req.getExpiresDays();
-			if (expiresDays != null) {
-				parmas.put("expires_days", expiresDays);
-			}
-			ClaudeCodeResp claudeCodeResp = executeClaudeCodePostApi(apiKeyUrl, Jsons.toJson(parmas));
-			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
-				throw BusinessRuntimeException.getInstance("创建失败");
-			}
+
+			req.setUserId(codexUserId);
+			ClaudeCodeResp claudeCodeResp = claudeCodexApiService.createApiKeys(req);
 			return claudeCodeResp;
 		}
 		throw new BusinessRuntimeException("您还没有codex账号");
@@ -490,14 +408,7 @@ public class CodexServiceImpl implements CodexService {
 		Long keyId = delReq.getKeyId();
 		if (checkCodexUser(userId)) {
 			Long codexUserId = getCodexUserId(userId);
-			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/keys/%s/%s", codexUserId, keyId);
-			HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
-			String responseBody = execute.body();
-			ClaudeCodeResp claudeCodeResp = Jsons.parseObject(responseBody, ClaudeCodeResp.class);
-			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
-				log.error("删除key失败:{}", claudeCodeResp.getMessage());
-				throw BusinessRuntimeException.getInstance("删除失败");
-			}
+			claudeCodexApiService.deleteApiKeysById(codexUserId, keyId);
 		}
 	}
 
@@ -505,9 +416,8 @@ public class CodexServiceImpl implements CodexService {
 	public List<ClaudeCodeUserApiKeysView> getUserApiKeys(long userId) throws Exception {
 		Long codexUserId = getCodexUserId(userId);
 		if (codexUserId != null) {
-			String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/keys", codexUserId);
-			ClaudeCodeResp claudeCodeResp = executeClaudeCodeGetApi(url);
-			return Jsons.parseList(claudeCodeResp.getData(), ClaudeCodeUserApiKeysView.class);
+			List<ClaudeCodeUserApiKeysView> keysViews = claudeCodexApiService.getUserApiKeys(codexUserId);
+			return keysViews;
 		}
 		return null;
 	}
@@ -699,10 +609,7 @@ public class CodexServiceImpl implements CodexService {
 		if (codexUser == null) {
 			return null;
 		}
-		// 调用Codex API获取实时使用统计
-		String usageUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/usage?period=%s", codexUser.getUserId(), period);
-		ClaudeCodeResp codexResp = executeCodexGetApi(usageUrl);
-		return codexResp;
+		return claudeCodexApiService.getCodexUserOpenAIUsage(codexUser.getUserId(), period);
 	}
 
 	@Override
@@ -756,42 +663,6 @@ public class CodexServiceImpl implements CodexService {
 			throw new BusinessRuntimeException("更新每日限额失败");
 		}
 	}
-
-	@Override
-	public ClaudeCodeResp getSystemMetrics(String period, String metric) {
-		try {
-			// 构建系统指标API URL
-			String metricsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/system/metrics");
-			
-			// 添加查询参数
-			List<String> queryParams = new ArrayList<>();
-			if (period != null && !period.isEmpty()) {
-				queryParams.add("period=" + period);
-			}
-			if (metric != null && !metric.isEmpty()) {
-				queryParams.add("metric=" + metric);
-			}
-			
-			if (!queryParams.isEmpty()) {
-				metricsUrl += "?" + String.join("&", queryParams);
-			}
-			
-			// 调用Codex API获取系统指标
-			ClaudeCodeResp codexResp = executeCodexGetApi(metricsUrl);
-			
-			if (codexResp == null) {
-				log.error("获取系统指标失败: API返回null");
-				throw new BusinessRuntimeException("获取系统指标失败");
-			}
-			
-			log.info("成功获取系统指标, period={}, metric={}", period, metric);
-			return codexResp;
-			
-		} catch (Exception e) {
-			log.error("获取系统指标异常, period={}, metric={}, error={}", period, metric, StringUtil.getErrorText(e));
-			throw new BusinessRuntimeException("获取系统指标失败");
-		}
-	}
 	
 	@Override
 	public ClaudeCodeResp getJavaUserDashboard(Long userId) {
@@ -801,11 +672,7 @@ public class CodexServiceImpl implements CodexService {
 		if (codexUser == null) {
 			return null;
 		}
-
-		// 调用Codex API获取用户控制台数据
-		String dashboardUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/dashboard", codexUser.getUserId());
-		ClaudeCodeResp codexResp = executeCodexGetApi(dashboardUrl);
-		return codexResp;
+		return claudeCodexApiService.getCodexUserDashboard(codexUser.getUserId());
 	}
 	
 	@Override
@@ -822,12 +689,7 @@ public class CodexServiceImpl implements CodexService {
 			start = DateUtil.offsetDay(now, -1).toString();
 			end = now.toString();
 		}
-
-		// 调用Codex API获取用户分析数据
-		String analyticsUrl = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/openai/users/%s/analytics?start=%s&end=%s&page=%s&limit=%s&order=%s", codexUser.getUserId(), start, end, page, limit, order);
-		ClaudeCodeResp codexResp = executeCodexGetApi(analyticsUrl);
-
-		return codexResp;
+		return claudeCodexApiService.getCodexUserAnalytics(codexUser.getUserId(), start, end, page, limit, order);
 	}
 
 	@Override
@@ -975,34 +837,6 @@ public class CodexServiceImpl implements CodexService {
 		}
 	}
 
-	/**
-	 * Codex GET请求
-	 */
-	public ClaudeCodeResp executeCodexGetApi(String url) {
-		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
-		try {
-			return build.call(() -> {
-				try {
-					HttpResponse execute = HttpUtil.createGet(url)
-							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
-							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
-							.execute();
-					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
-					if (!"success".equals(resp.getMessage())) {
-						log.error("codex GET URL:{}接口返回msg:{}", url, resp.getMessage());
-					}
-					return resp;
-				} catch (Exception e) {
-					log.error("codex GET请求异常: url={}, error={}", url, StringUtil.getErrorText(e));
-					return null;
-				}
-			});
-		} catch (ExecutionException | com.github.rholder.retry.RetryException e) {
-			log.error("重试调用codex GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
-			throw BusinessRuntimeException.getInstance("获取codex使用统计失败");
-		}
-	}
-
 	/**
 	 * 获取订单单价
 	 */
@@ -1325,18 +1159,7 @@ public class CodexServiceImpl implements CodexService {
 
 	@Override
 	public boolean delUserPackages(Long userId) {
-		String url = String.format(Constant.CLAUDE_CODE_API_PREFIX + "api/users/%s/plan?service_type=openai", userId);
-		try {
-			ClaudeCodeResp claudeCodeResp = executeClaudeCodeDeletedApi(url);
-			if (!Constant.SUCCESS.equals(claudeCodeResp.getMessage())) {
-				log.error("删除用户:{} claude code套餐失败:{}", userId, claudeCodeResp.getMessage());
-				return Boolean.FALSE;
-			}
-			return Boolean.TRUE;
-		} catch (Exception e) {
-			log.error("删除用户:{} claude code套餐报错:{}", userId, StringUtil.getErrorText(e));
-		}
-		return Boolean.FALSE;
+		return claudeCodexApiService.delCodexUserPackages(userId);
 	}
 
 	@Override
@@ -1345,30 +1168,6 @@ public class CodexServiceImpl implements CodexService {
 		createOrUpdateCodexUserInfo(orderId, relation.getId(), relation.getUserId(), sku, 2);
 	}
 
-	/**
-	 * claude code DELETE请求
-	 */
-	public ClaudeCodeResp executeClaudeCodeDeletedApi(String url) {
-		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
-		try {
-			return build.call(() -> {
-				try {
-					HttpResponse execute = HttpUtil.createRequest(Method.DELETE, url).header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY).setConnectionTimeout(Constant.CONNECT_MILLISECONDS).execute();
-					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
-					if (!Constant.SUCCESS.equals(resp.getMessage())) {
-						log.error("claude code DELETE URL:{}接口返回msg:{}", url, resp.getMessage());
-					}
-					return resp;
-				} catch (HttpException e) {
-					return null;
-				}
-			});
-		} catch (ExecutionException | RetryException e) {
-			log.error("重试调用claude code DELETE请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
-			throw BusinessRuntimeException.getInstance("接口请求失败");
-		}
-	}
-
 	/**
 	 * 校验是否是codex用户
 	 * @param userId
@@ -1395,57 +1194,4 @@ public class CodexServiceImpl implements CodexService {
 		}
 		return null;
 	}
-
-
-	/**
-	 * GET请求
-	 */
-	public ClaudeCodeResp executeClaudeCodeGetApi(String url) {
-		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
-		try {
-			return build.call(() -> {
-				try {
-					HttpResponse execute = HttpUtil.createGet(url)
-							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
-							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
-							.execute();
-					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
-					if (!Constant.SUCCESS.equals(resp.getMessage())) {
-						log.error("claude code GET URL:{}接口返回msg:{}", url, resp.getMessage());
-					}
-					return resp;
-				} catch (HttpException e) {
-					return null;
-				}
-			});
-		} catch (ExecutionException | RetryException e) {
-			log.error("重试调用claude code GET请求url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
-			throw BusinessRuntimeException.getInstance("接口请求失败");
-		}
-	}
-
-	public ClaudeCodeResp executeClaudeCodePostApi(String url, String body) {
-		Retryer<ClaudeCodeResp> build = getApiRetryer(1, 3);
-		try {
-			return build.call(() -> {
-				try {
-					HttpResponse execute = HttpUtil.createPost(url)
-							.header(Constant.CLAUDE_CODE_HEARD_KEY, Constant.CLAUDE_CODE_API_ADMIN_KEY)
-							.setConnectionTimeout(Constant.CONNECT_MILLISECONDS)
-							.body(body)
-							.execute();
-					ClaudeCodeResp resp = Jsons.parseObject(execute.body(), ClaudeCodeResp.class);
-					if (!Constant.SUCCESS.equals(resp.getMessage())) {
-						log.error("claude code POST URL:{}接口返回msg:{}", url, resp.getMessage());
-					}
-					return resp;
-				} catch (Exception e) {
-					return null;
-				}
-			});
-		} catch (ExecutionException | RetryException e) {
-			log.info("重试调用claude code POST请求 url->{}失败,msg->{}", url, StringUtil.getErrorText(e));
-			throw BusinessRuntimeException.getInstance("接口请求失败");
-		}
-	}
 }