package com.cyksj.server.recharge.impl; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.cyksj.common.constant.Constant; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.task.GlobalThreadPoolTaskExecutor; import com.cyksj.common.util.Jsons; import com.cyksj.mapper.*; import com.cyksj.model.dto.GptCardTokenDto; import com.cyksj.model.entity.*; import com.cyksj.model.request.GroupsRelationRechargeReq; import com.cyksj.redis.RedisService; import com.cyksj.server.recharge.GptProxyRechargeService; import com.cyksj.server.recharge.dto.CardKeyValidationResult; import com.cyksj.server.recharge.dto.TaskResult; import com.cyksj.server.recharge.dto.TaskSubmitResult; import com.cyksj.server.recharge.dto.TokenParseResult; import com.cyksj.service.chatgpt.GptUserRechargeRecordService; import com.cyksj.service.user.UserBindRelationService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; import java.util.Optional; /** * @author chan * @date 2025/7/30 18:55 */ @Slf4j @Service @RequiredArgsConstructor public class GptProxyRechargeServiceImpl implements GptProxyRechargeService { private static final String BASE_URL = "https://api.987ai.vip/api"; private final GptRechargeCardKeyMapper gptRechargeCardKeyMapper; private final GroupsRelationMapper relationMapper; private final UserBindRelationService userBindRelationService; private final GroupsMapper groupsMapper; private final GoodsDonSkuMapper skuMapper; private final OrderDonMapper orderDonMapper; private final GptUserRechargeRecordService gptUserRechargeRecordService; private final RedisService redisService; private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance(); private HttpRequest createBaseRequest(String uri) { return HttpRequest.get(BASE_URL + uri) .header("accept", "application/json, text/plain, */*") .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8") .header("origin", "https://www.ow520.com") .header("referer", "https://www.ow520.com/") .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"); } public CardKeyValidationResult validateCardKey(String cardKey) { log.info("开始验证卡密: {}", cardKey); try { HttpResponse response = createBaseRequest("/card-keys/" + cardKey) .execute(); String body = response.body(); log.info("卡密验证响应: {}", body); JSONObject jsonResponse = JSONUtil.parseObj(body); CardKeyValidationResult result = new CardKeyValidationResult( jsonResponse.getBool("available") ); //{"available":false,"error":"卡密已被使用"} log.info("卡密验证结果: {}", result); return result; } catch (Exception e) { log.error("验证卡密失败: {}", e.getMessage(), e); throw new RuntimeException("验证卡密失败: " + e.getMessage(), e); } } public TokenParseResult parseToken(String accessToken) { log.info("开始验证凭证: {}", accessToken.substring(0, Math.min(20, accessToken.length())) + "..."); try { String url = BASE_URL + "/parse-token"; JSONObject requestBody = new JSONObject(); requestBody.put("access_token", accessToken); HttpResponse response = HttpRequest.post(url) .header("accept", "application/json, text/plain, */*") .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8") .header("content-type", "application/json") .header("origin", "https://www.ow520.com") .header("referer", "https://www.ow520.com/") .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36") .body(requestBody.toString()) .execute(); String body = response.body(); log.info("凭证验证响应: {}", body); JSONObject jsonResponse = JSONUtil.parseObj(body); TokenParseResult result = new TokenParseResult( jsonResponse.getStr("message"), jsonResponse.getBool("success") ); log.info("凭证验证结果: {}", result); return result; } catch (Exception e) { log.error("验证凭证失败: {}", e.getMessage(), e); throw new RuntimeException("验证凭证失败: " + e.getMessage(), e); } } public TaskSubmitResult submitTask(String cardKey, String accessToken, String idp) { log.info("开始提交任务 - 卡密: {}, idp: {}", cardKey, idp); try { String url = BASE_URL + "/tasks"; JSONObject requestBody = new JSONObject(); requestBody.put("card_key", cardKey); requestBody.put("access_token", accessToken); requestBody.put("idp", idp); HttpResponse response = HttpRequest.post(url) .setConnectionTimeout(60000) .header("accept", "application/json, text/plain, */*") .header("accept-language", "zh-CN,zh;q=0.9,en;q=0.8") .header("content-type", "application/json") .header("origin", "https://www.ow520.com") .header("referer", "https://www.ow520.com/") .header("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36") .body(requestBody.toString()) .execute(); String body = response.body(); log.info("任务提交响应: {}", body); JSONObject jsonResponse = JSONUtil.parseObj(body); TaskSubmitResult result = new TaskSubmitResult( jsonResponse.getStr("task_id"), jsonResponse.getBool("success") ); log.info("任务提交结果: {}", result); return result; } catch (Exception e) { log.error("提交任务失败: {}", e.getMessage(), e); throw new RuntimeException("提交任务失败: " + e.getMessage(), e); } } public TaskResult getTaskResult(String taskId) { log.info("开始查询任务结果: {}", taskId); try { String uri = "/tasks/" + taskId; HttpResponse response = createBaseRequest(uri) .execute(); String body = response.body(); log.info("任务查询响应: {}", body); JSONObject jsonResponse = JSONUtil.parseObj(body); TaskResult result = new TaskResult( jsonResponse.getStr("status"), jsonResponse.getStr("result"), jsonResponse.getStr("error") ); log.info("任务查询结果: {}", result); String status = result.getStatus(); String resultResult = Optional.ofNullable(result.getError()).orElse(result.getResult()); //更新代充状态 resetGroupsRelationRechargeStatus(taskId, status, resultResult); return result; } catch (Exception e) { log.error("获取任务结果失败: {}", e.getMessage(), e); throw new RuntimeException("获取任务结果失败: " + e.getMessage(), e); } } @Override @Transactional(rollbackFor = Throwable.class) public String confirmRecharge(GroupsRelationRechargeReq req) { Long relationId = req.getRelationId(); Long userId = req.getUserId(); List userIdList = userBindRelationService.getRelationUserIdList(userId, null); GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class) .in(GroupsRelation::getUserId, userIdList) .eq(GroupsRelation::getId, relationId) .eq(GroupsRelation::getStatus, GroupsRelation.Status.validity)); if (relation == null) { throw BusinessRuntimeException.getInstance("车票不存在"); } String userAccount = relation.getAccount(); GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId()); GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId()); // //GPT 代充 // if (sku.getGoodsId() != Constant.GPT_RECHARGE_GOODS_ID) { // throw BusinessRuntimeException.getInstance("车票类型错误"); // } Integer rechargeNum = relation.getRechargeNum(); Integer rechargeRemainNum = relation.getRechargeRemainNum(); if (rechargeRemainNum == null || rechargeRemainNum <= 0) { throw BusinessRuntimeException.getInstance("剩余可代充次数为0"); } if (relation.getRechargeStatus() == GroupsRelation.RechargeStatus.recharging) { throw BusinessRuntimeException.getInstance("确认充值中"); } if (relation.getRechargeStatus() == GroupsRelation.RechargeStatus.recharge_error) { throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通"); } String key = RedisService.key.GPT_RECHARGE_KEY.getName() + relationId; boolean b = redisService.setNx(key, relationId, RedisService.key.GPT_RECHARGE_KEY.getTimeout()); if (!b) { throw BusinessRuntimeException.getInstance("确认充值中"); } try { int updateRemainNum = relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(GroupsRelation::getRechargeRemainNum, rechargeRemainNum - 1) .eq(GroupsRelation::getId, relationId) .eq(GroupsRelation::getUserId, relation.getUserId()) .eq(GroupsRelation::getRechargeRemainNum, rechargeRemainNum)); if (updateRemainNum == 0) { throw BusinessRuntimeException.getInstance("代充异常,请重试"); } OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class) .in(OrderDon::getUserId, userIdList) .eq(OrderDon::getRelationId, relationId) .notIn(OrderDon::getStatus, Constant.noOrderAllStatus) .orderByDesc(OrderDon::getId) .last("limit 1")); if (orderDon == null) { throw BusinessRuntimeException.getInstance("代充订单不存在或已退款"); } //入库token json String saveTokenJson = req.getAccessToken(); String accessToken; try { GptCardTokenDto gptCardTokenDto = Jsons.parseObject(saveTokenJson, GptCardTokenDto.class); accessToken = gptCardTokenDto.getAccessToken(); } catch (Exception e) { accessToken = saveTokenJson; } //验证用户token是否正确 TokenParseResult tokenParseResult = parseToken(accessToken); if (!tokenParseResult.getSuccess()) { throw BusinessRuntimeException.getInstance("您输入的凭证有误,请重新输入"); } String rechargeAccount = tokenParseResult.getMessage(); //月付校验前后账号是否一致 if (sku.getMonths() == 1 && !StrUtil.equals(rechargeAccount, userAccount)) { throw BusinessRuntimeException.getInstance("请填入绑定账号的token"); } //记录代充账号 token relation.setGptToken(saveTokenJson); relation.setAccount(rechargeAccount); //获取GPT代充key //代充卡密类型 Integer gptRechargeCardKeyType = 0; //若是季、年付 且首月代充 if (sku.getMonths() > 1 && rechargeNum == rechargeRemainNum) { gptRechargeCardKeyType = 1; } GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class) .eq(GptRechargeCardKey::getType, gptRechargeCardKeyType) .eq(GptRechargeCardKey::getStatus, Boolean.FALSE) .last("order by rand() limit 1")); //季、年付卡密不存在 从月付代充卡密中获取 if (gptRechargeCardKey == null && gptRechargeCardKeyType == 1) { gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class) .eq(GptRechargeCardKey::getType, 0) .eq(GptRechargeCardKey::getStatus, Boolean.FALSE) .last("order by rand() limit 1")); } if (gptRechargeCardKey == null) { setRechargeRelationStatusAutoError(relation); throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通"); } int update = gptRechargeCardKeyMapper.update(null, Wrappers.lambdaUpdate(GptRechargeCardKey.class) .set(GptRechargeCardKey::getStatus, Boolean.TRUE) .set(GptRechargeCardKey::getOrderId, orderDon.getId()) .set(GptRechargeCardKey::getOrderNo, orderDon.getOrderNo()) .eq(GptRechargeCardKey::getId, gptRechargeCardKey.getId()) .eq(GptRechargeCardKey::getStatus, Boolean.FALSE)); if (update == 0) { setRechargeRelationStatusAutoError(relation); throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通"); } String gptCardKey = gptRechargeCardKey.getCardKey(); //校验卡密是否可用 CardKeyValidationResult cardKeyValidationResult = validateCardKey(gptCardKey); if (!cardKeyValidationResult.getAvailable()) { setRechargeRelationStatusAutoError(relation); throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通"); } //提交任务 TaskSubmitResult result = submitTask(gptCardKey, accessToken, "auth0"); if (!result.getSuccess()) { setRechargeRelationStatusAutoError(relation); throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通"); } String taskId = result.getTaskId(); relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) //记录代充账号 .set(GroupsRelation::getAccount, rechargeAccount) .set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging) .set(GroupsRelation::getCardKey, gptCardKey) .set(GroupsRelation::getGptToken, saveTokenJson) .set(GroupsRelation::getGptTaskId, taskId) .eq(GroupsRelation::getId, relationId)); return taskId; } finally { if (redisService.hasKey(key)) { redisService.del(key); } } } /** * 设置代充自动充值异常 */ public void setRechargeRelationStatusAutoError(GroupsRelation relation) { TASK_EXECUTOR.execute(()->{ relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(GroupsRelation::getAccount, relation.getAccount()) .set(GroupsRelation::getGptToken, relation.getGptToken()) .set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharge_error) .eq(GroupsRelation::getId, relation.getId())); }); } /** * 更新代充状态 */ private void resetGroupsRelationRechargeStatus(String taskId, String status, String result) { if ("completed".equals(status) || "failed".equals(status) || "unknown".equals(status)) { GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class) .eq(GroupsRelation::getGptTaskId, taskId) .last("limit 1")); if (relation != null && relation.getRechargeStatus() == GroupsRelation.RechargeStatus.recharging) { Integer rechargeRemainNum = relation.getRechargeRemainNum(); GroupsRelation.RechargeStatus rechargeStatus = "completed".equals(status) ? GroupsRelation.RechargeStatus.complete : GroupsRelation.RechargeStatus.recharge_error; String cardKey = relation.getCardKey(); GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class) .eq(GptRechargeCardKey::getCardKey, cardKey) .last("limit 1")); if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error) { if (gptRechargeCardKey != null) { gptRechargeCardKeyMapper.update(null, Wrappers.lambdaUpdate(GptRechargeCardKey.class) .set(GptRechargeCardKey::getStatus, Boolean.FALSE) .set(GptRechargeCardKey::getOrderId, null) .set(GptRechargeCardKey::getOrderNo, null) .eq(GptRechargeCardKey::getId, gptRechargeCardKey.getId()) .eq(GptRechargeCardKey::getStatus, Boolean.TRUE)); } } if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error) { if (!redisService.setNx(RedisService.key.GPT_RECHARGE_RECOVER_KEY.getName() + taskId, taskId, RedisService.key.GPT_RECHARGE_RECOVER_KEY.getTimeout())) { return; } } Date startTime = relation.getStartTime(); DateTime expiryTime = null; if (rechargeStatus == GroupsRelation.RechargeStatus.complete && startTime == null) { GroupsTrips groupsTrips = groupsMapper.selectById(relation.getGroupsId()); if (groupsTrips != null) { startTime = DateTime.now(); GoodsDonSku sku = skuMapper.selectById(groupsTrips.getSkuId()); if (sku.getDays() != null && sku.getDays() > 0) { expiryTime = DateUtil.offsetDay(startTime, sku.getDays()); } else { expiryTime = DateUtil.offsetMonth(startTime, sku.getMonths()); } } } String rechargeErrorInfo = null; if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error) { rechargeErrorInfo = result; } relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class) .set(rechargeStatus == GroupsRelation.RechargeStatus.recharge_error, GroupsRelation::getRechargeRemainNum, rechargeRemainNum + 1) .set(GroupsRelation::getRechargeStatus, rechargeStatus) .set(expiryTime != null, GroupsRelation::getStartTime, startTime) .set(expiryTime != null, GroupsRelation::getExpiryTime, expiryTime) .set(StrUtil.isNotEmpty(rechargeErrorInfo), GroupsRelation::getRechargeErrorInfo, rechargeErrorInfo) .eq(GroupsRelation::getId, relation.getId()) .le(GroupsRelation::getRechargeRemainNum, relation.getRechargeNum()) .eq(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging)); //记录代充记录 if (rechargeStatus == GroupsRelation.RechargeStatus.complete) { gptUserRechargeRecordService.recordGptUserRechargeNum(relation.getUserId(), relation.getId(), relation.getAccount(), -1, null, "自动代充"); //修改对应订单状态 if (gptRechargeCardKey != null) { Long orderId = gptRechargeCardKey.getOrderId(); OrderDon orderDon = orderDonMapper.selectById(orderId); if (orderDon != null && orderDon.getStatus() == OrderDon.Status.hasPayment) { orderDon.setStatus(OrderDon.Status.complete); orderDonMapper.updateById(orderDon); } } } } } } }