Selaa lähdekoodia

后台客服操作GPT代充

zoujiajian 1 vuosi sitten
vanhempi
sitoutus
b78dad4ab4

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/request/GroupsRelationRechargeReq.java

@@ -22,4 +22,6 @@ public class GroupsRelationRechargeReq {
 
 	@NotEmpty
 	private String accessToken;
+
+	private String password;
 }

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GroupsRelationRechargeView.java

@@ -73,6 +73,12 @@ public class GroupsRelationRechargeView {
 	@DbField("gr.recharge_remain_num")
 	private Integer rechargeRemainNum;
 
+	/**
+	 * 代充任务id
+	 */
+	@DbField("gr.gpt_task_id")
+	private String gptTaskId;
+
 	/**
 	 * 家庭组邀请链接
 	 */

+ 6 - 2
netflix-service/src/main/java/com/cyksj/server/recharge/impl/GptProxyRechargeServiceImpl.java

@@ -262,7 +262,11 @@ public class GptProxyRechargeServiceImpl implements GptProxyRechargeService {
 			}
 			String gptCardKey = gptRechargeCardKey.getCardKey();
 			//校验卡密是否可用
-			validateCardKey(gptCardKey);
+			CardKeyValidationResult cardKeyValidationResult = validateCardKey(gptCardKey);
+			if (!cardKeyValidationResult.getAvailable()) {
+				setRechargeRelationStatusAutoError(relation);
+				throw BusinessRuntimeException.getInstance("充值失败,请联系客服开通");
+			}
 			//提交任务
 			TaskSubmitResult result = submitTask(gptCardKey, accessToken, "auth0");
 			if (!result.getSuccess()) {
@@ -299,7 +303,7 @@ public class GptProxyRechargeServiceImpl implements GptProxyRechargeService {
 	 * 更新代充状态
 	 */
 	private void resetGroupsRelationRechargeStatus(String taskId, String status, String result) {
-		if ("completed".equals(status) || "failed".equals(status)) {
+		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"));

+ 19 - 0
netflix-service/src/main/java/com/cyksj/service/mange/gpt/GptRechargeService.java

@@ -0,0 +1,19 @@
+package com.cyksj.service.mange.gpt;
+
+import com.cyksj.model.request.GroupsRelationRechargeReq;
+import com.cyksj.server.recharge.dto.TaskResult;
+import com.cyksj.server.recharge.dto.TokenParseResult;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: GptRechargeService
+ * 创建者: JavaZou
+ * 创建时间:2025/8/4 16:34
+ */
+public interface GptRechargeService {
+	TokenParseResult parseToken(String accessToken);
+
+	String confirmRecharge(long adminId, GroupsRelationRechargeReq req);
+
+	TaskResult getTaskResult(String taskId);
+}

+ 367 - 0
netflix-service/src/main/java/com/cyksj/service/mange/gpt/impl/GptRechargeServiceImpl.java

@@ -0,0 +1,367 @@
+package com.cyksj.service.mange.gpt.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.mapper.*;
+import com.cyksj.mapper.manage.cms.CmsUserMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.request.GroupsRelationRechargeReq;
+import com.cyksj.redis.RedisService;
+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.mange.gpt.GptRechargeService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * 项目名: yhlxj11111111
+ * 文件名: GptRechargeServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2025/8/4 16:34
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GptRechargeServiceImpl implements GptRechargeService {
+	private static final String BASE_URL = "https://api.ow520.com/api";
+
+	private final CmsUserMapper cmsUserMapper;
+
+	private final GptRechargeCardKeyMapper gptRechargeCardKeyMapper;
+
+	private final GroupsRelationMapper relationMapper;
+
+	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 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);
+		}
+	}
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public String confirmRecharge(long adminId, GroupsRelationRechargeReq req) {
+		CmsUser cmsUser = cmsUserMapper.selectById(adminId);
+		Long relationId = req.getRelationId();
+		GroupsRelation relation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class)
+				.eq(GroupsRelation::getId, relationId)
+				.eq(GroupsRelation::getStatus, GroupsRelation.Status.validity));
+		if (relation == null) {
+			throw BusinessRuntimeException.getInstance("车票不存在");
+		}
+		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 rechargeRemainNum = relation.getRechargeRemainNum();
+		if (rechargeRemainNum == null || rechargeRemainNum <= 0) {
+			throw BusinessRuntimeException.getInstance("剩余可代充次数为0");
+		}
+		if (relation.getRechargeStatus() == GroupsRelation.RechargeStatus.recharging) {
+			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("剩余可代充次数为0");
+			}
+			OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
+					.eq(OrderDon::getUserId, relation.getUserId())
+					.eq(OrderDon::getRelationId, relationId)
+					.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
+					.orderByDesc(OrderDon::getId)
+					.last("limit 1"));
+			if (orderDon == null) {
+				throw BusinessRuntimeException.getInstance("代充订单不存在或已退款");
+			}
+			String accessToken = req.getAccessToken();
+			//验证用户token是否正确
+			TokenParseResult tokenParseResult = parseToken(accessToken);
+			if (!tokenParseResult.getSuccess()) {
+				throw BusinessRuntimeException.getInstance("您输入的凭证有误,请重新输入");
+			}
+			String rechargeAccount = tokenParseResult.getMessage();
+			//记录代充账号 token
+			relation.setAccount(rechargeAccount);
+			//获取GPT代充key
+			GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class)
+					.eq(GptRechargeCardKey::getStatus, Boolean.FALSE)
+					.last("order by rand() limit 1"));
+			if (gptRechargeCardKey == null) {
+				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) {
+				throw BusinessRuntimeException.getInstance("无可用卡密");
+			}
+			String gptCardKey = gptRechargeCardKey.getCardKey();
+			//校验卡密是否可用
+			CardKeyValidationResult cardKeyValidationResult = validateCardKey(gptCardKey);
+			if (!cardKeyValidationResult.getAvailable()) {
+				throw BusinessRuntimeException.getInstance("卡密:{0}已被使用", gptCardKey);
+			}
+			//提交任务
+			TaskSubmitResult result = submitTask(gptCardKey, accessToken, "auth0");
+			if (!result.getSuccess()) {
+				setRechargeRelationStatusAutoError(relation);
+				throw BusinessRuntimeException.getInstance("自动充值错误");
+			}
+			String taskId = result.getTaskId();
+			String password = req.getPassword();
+			relationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
+					//记录代充账号
+					.set(GroupsRelation::getAccount, rechargeAccount)
+					//记录操作人员
+					.set(cmsUser != null, GroupsRelation::getOperator, cmsUser.getNickname())
+					//密码
+					.set(StrUtil.isNotBlank(password), GroupsRelation::getPassword, password)
+					.set(GroupsRelation::getRechargeStatus, GroupsRelation.RechargeStatus.recharging)
+					.set(GroupsRelation::getCardKey, gptCardKey)
+					.set(GroupsRelation::getGptTaskId, taskId)
+					.eq(GroupsRelation::getId, relationId));
+			return taskId;
+		} finally {
+			if (redisService.hasKey(key)) {
+				redisService.del(key);
+			}
+		}
+	}
+
+	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")
+			);
+			log.info("任务查询结果: {}", result);
+			String status = result.getStatus();
+			String resultResult = result.getResult();
+			//更新代充状态
+			resetGroupsRelationRechargeStatus(taskId, status, resultResult);
+			return result;
+		} catch (Exception e) {
+			log.error("获取任务结果失败: {}", e.getMessage(), e);
+			throw new RuntimeException("获取任务结果失败: " + e.getMessage(), e);
+		}
+	}
+
+	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 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)
+					.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 void setRechargeRelationStatusAutoError(GroupsRelation relation) {
+		TASK_EXECUTOR.execute(()->{
+			relation.setRechargeStatus(GroupsRelation.RechargeStatus.recharge_error);
+			relationMapper.updateById(relation);
+		});
+	}
+
+
+	/**
+	 * 更新代充状态
+	 */
+	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;
+				if (rechargeStatus == GroupsRelation.RechargeStatus.recharge_error) {
+					String cardKey = relation.getCardKey();
+					GptRechargeCardKey gptRechargeCardKey = gptRechargeCardKeyMapper.selectOne(Wrappers.lambdaQuery(GptRechargeCardKey.class)
+							.eq(GptRechargeCardKey::getCardKey, cardKey)
+							.last("limit 1"));
+					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, relation.getOperator());
+				}
+			}
+		}
+	}
+
+}

+ 2 - 2
netflix-service/src/main/java/com/cyksj/service/vip/impl/VipFrontServiceImpl.java

@@ -168,7 +168,7 @@ public class VipFrontServiceImpl implements VipFrontService {
 					//获取抵扣金额
 					deductMoney = deductMoney.add(getFinalDeductMoney(relationId, relation.getSkuId(), chatgptUser.getRenewSkuId(), chatgptUser.getRenewOrderId(), chatgptUser.getRenewExpiryTime(), relation.getStartTime(), relationExpiryTime, now, userIdList));
 				} else {
-					throw BusinessRuntimeException.getInstance("请先前往车票页");
+					throw BusinessRuntimeException.getInstance("请先前往AI镜像专区使用");
 				}
 			} else if (goodsId == Constant.CLAUDE_PRO_GID) {
 				ClaudeUser claudeUser = claudeUserMapper.selectOne(Wrappers.lambdaQuery(ClaudeUser.class).eq(ClaudeUser::getRelationId, relationId).last("limit 1"));
@@ -176,7 +176,7 @@ public class VipFrontServiceImpl implements VipFrontService {
 					//获取抵扣金额
 					deductMoney = deductMoney.add(getFinalDeductMoney(relationId, relation.getSkuId(), claudeUser.getRenewSkuId(), claudeUser.getRenewOrderId(), claudeUser.getRenewExpiryTime(), relation.getStartTime(), relationExpiryTime, now, userIdList));
 				} else {
-					throw BusinessRuntimeException.getInstance("请先前往车票页");
+					throw BusinessRuntimeException.getInstance("请先前往AI镜像专区使用");
 				}
 			} else {
 				//该车票抵扣金额

+ 60 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/group/CmsGroupRelationController.java

@@ -20,14 +20,19 @@ import com.cyksj.mapper.manage.cms.CmsUserMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.views.AccountView;
 import com.cyksj.model.manage.views.GroupsRelationBackView;
+import com.cyksj.model.request.GroupsRelationRechargeReq;
 import com.cyksj.model.request.RechargeRemainNumReq;
 import com.cyksj.model.views.DisableAccountView;
 import com.cyksj.model.views.GroupsRelationIndependentView;
 import com.cyksj.model.views.GroupsRelationRechargeView;
 import com.cyksj.model.views.OrderDonRenewView;
+import com.cyksj.server.recharge.dto.TaskResult;
+import com.cyksj.server.recharge.dto.TokenParseResult;
 import com.cyksj.service.chatgpt.GptUserRechargeRecordService;
+import com.cyksj.service.mange.gpt.GptRechargeService;
 import com.cyksj.service.relation.GroupRelationClearService;
 import com.cyksj.service.scheduler.SchedulerService;
+import com.cyksj.web.controller.recharge.req.ParseTokenRequest;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.param.Operator;
@@ -37,6 +42,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
@@ -45,6 +51,7 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
+ * admin/用户代充值列表
  * @author chan
  * @date 2022/9/27 6:45 PM
  */
@@ -76,6 +83,8 @@ public class CmsGroupRelationController {
 
     private final GptUserRechargeRecordService gptUserRechargeRecordService;
 
+    private final GptRechargeService gptRechargeService;
+
     @GetMapping("/get")
     public Result<List<GroupsRelationBackView>> get(){
         List<GroupsRelationBackView> search = beanSearcher.searchAll(GroupsRelationBackView.class, MapUtils.flatBuilder(request.getParameterMap())
@@ -140,6 +149,8 @@ public class CmsGroupRelationController {
     public Result<String> updateRechargeStatus(@RequestBody GroupsRelationRechargeView rechargeView) {
         long adminId = StpUtil.getLoginIdAsLong();
         Long relationId = rechargeView.getRelationId();
+        String account = rechargeView.getAccount();
+        String password = rechargeView.getPassword();
         GroupsRelation relation = groupsRelationMapper.selectById(relationId);
         Assert.notNull(relation, "代充车票不存在");
         if (relation.getRenewStatus() == null || relation.getRechargeStatus() == GroupsRelation.RechargeStatus.complete) {
@@ -155,6 +166,12 @@ public class CmsGroupRelationController {
         relation.setOperator(cmsUser.getNickname());
         //邀请制家庭组链接
         relation.setInviteLink(rechargeView.getInviteLink());
+        if (StrUtil.isNotEmpty(account)) {
+            relation.setAccount(account);
+        }
+        if (StrUtil.isNotEmpty(password)) {
+            relation.setPassword(password);
+        }
         OrderDon orderDon = null;
         if (rechargeStatus == GroupsRelation.RechargeStatus.complete) {
             relation.setSendTime(DateTime.now());
@@ -304,6 +321,49 @@ public class CmsGroupRelationController {
         return GatewayResponse.SUCCESS.newBuilder().toResult();
     }
 
+    /**
+     * GPT代充操作记录
+     */
+    @GetMapping("/get/recharge/operate/record")
+    public Result<List<GptUserRechargeNumRecord>> getGptUserRechargeNumRecord(Long relationId, Long userId) {
+        OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getRelationId, relationId).notIn(OrderDon::getStatus, Constant.noOrderAllStatus).orderByDesc(OrderDon::getId).last("limit 1"));
+        List<GptUserRechargeNumRecord> gptUserRechargeNumRecords = beanSearcher.searchAll(GptUserRechargeNumRecord.class, MapUtils.flatBuilder(request.getParameterMap())
+                .field(GptUserRechargeNumRecord::getRelationId, relationId)
+                .field(GptUserRechargeNumRecord::getUserId, userId)
+                .field(GptUserRechargeNumRecord::getCreatedTime, orderDon.getCreatedTime()).op(Operator.GreaterThan)
+                .build());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(gptUserRechargeNumRecords);
+    }
+
+    /**
+     * 验证GPT代充凭证
+     */
+    @PostMapping("/parse-token")
+    public Result<TokenParseResult> parseToken(@RequestBody ParseTokenRequest request) {
+        TokenParseResult tokenParseResult = gptRechargeService.parseToken(request.getAccessToken());
+        return GatewayResponse.SUCCESS.newBuilder().toResult(tokenParseResult);
+    }
+
+    /**
+     * 确认充值
+     */
+    @PostMapping("/confirm")
+    public Result<String> confirmRecharge(@RequestBody @Validated GroupsRelationRechargeReq req) {
+        long adminId = StpUtil.getLoginIdAsLong();
+        String taskId = gptRechargeService.confirmRecharge(adminId, req);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(taskId);
+    }
+
+
+    /**
+     * 查询任务状态
+     */
+    @GetMapping("/task-status/{taskId}")
+    public Result<TaskResult> getTaskStatus(@PathVariable String taskId) {
+        return GatewayResponse.SUCCESS.newBuilder().toResult(gptRechargeService.getTaskResult(taskId));
+    }
+
+
     /**
      * Chat GPT独立规格续费 列表
      */