zoujiajian vor 2 Monaten
Ursprung
Commit
6839d7ed39

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/GrokSessionMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.GrokSession;
+
+/**
+ * @author chan
+ * @date 2026/6/5
+ */
+public interface GrokSessionMapper extends BaseMapper<GrokSession> {
+}

+ 35 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GrokSession.java

@@ -0,0 +1,35 @@
+package com.cyksj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.cyksj.model.BaseEntity;
+import lombok.Data;
+
+/**
+ * Grok SSO session.
+ */
+@Data
+@TableName("grok_session")
+public class GrokSession extends BaseEntity {
+
+    private String email;
+
+    private String password;
+
+    @TableField("carID")
+    private String carId;
+
+    private String sso;
+
+    private Integer count;
+
+    private Integer status;
+
+    private String type;
+
+    private String remark;
+
+    private Long sort;
+
+    private Double score;
+}

+ 12 - 0
netflix-dao/src/main/java/com/cyksj/model/request/GrokAuthReq.java

@@ -0,0 +1,12 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class GrokAuthReq {
+    private String userToken;
+
+    private String carid;
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/model/response/GrokConversationCountResponse.java

@@ -0,0 +1,20 @@
+package com.cyksj.model.response;
+
+import lombok.Data;
+
+/**
+ * Grok conversation count response.
+ */
+@Data
+public class GrokConversationCountResponse {
+
+    private Long count;
+
+    private Integer limit;
+
+    private Long remaining;
+
+    private Long time;
+
+    private Boolean isVip;
+}

+ 59 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GrokCarInfoView.java

@@ -0,0 +1,59 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+
+import java.util.Objects;
+
+/**
+ * Grok car info view.
+ */
+@Data
+@SearchBean(
+        tables = "grok_session gs",
+        where = "gs.status is true"
+)
+public class GrokCarInfoView {
+
+    @DbField("gs.carID")
+    private String carId;
+
+    @DbIgnore
+    private String carName;
+
+    @DbIgnore
+    private String status;
+
+    @DbField("gs.score")
+    private Double score;
+
+    @DbField("gs.status")
+    private Boolean csStatus;
+
+    @DbField("gs.count")
+    private Integer use;
+
+    @DbField("gs.type")
+    private String type;
+
+    @DbField("gs.sort")
+    private Long sort;
+
+    @DbField("gs.remark")
+    private String remark;
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        GrokCarInfoView that = (GrokCarInfoView) o;
+        return Objects.equals(carId, that.carId);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(carId);
+    }
+}

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/views/GrokUserView.java

@@ -38,4 +38,6 @@ public class GrokUserView {
      */
     private Long use;
 
+    private String userToken;
+
 }

+ 10 - 0
netflix-service/src/main/java/com/cyksj/service/grok/GrokService.java

@@ -1,9 +1,13 @@
 package com.cyksj.service.grok;
 
 import com.cyksj.model.entity.GrokUser;
+import com.cyksj.model.response.GrokConversationCountResponse;
+import com.cyksj.model.views.GrokCarInfoView;
 import com.cyksj.model.views.GrokUserView;
+import com.ejlchina.searcher.SearchResult;
 
 import java.time.LocalDateTime;
+import java.util.Map;
 
 /**
  * @author chan
@@ -19,4 +23,10 @@ public interface GrokService {
     Long getConversationCount(String userToken, Long limitTime);
 
     String getCarLoginUrl(String domain, Long userId, Long relationId);
+
+    String getCarLoginUrl(String domain, Long userId, Long relationId, String carId);
+
+    SearchResult<GrokCarInfoView> getCarInfoList(Map<String, String[]> parameterMap, Integer limit);
+
+    GrokConversationCountResponse getConversationCountDetail(String userToken);
 }

+ 105 - 2
netflix-service/src/main/java/com/cyksj/service/grok/impl/GrokServiceImpl.java

@@ -12,10 +12,16 @@ import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.mapper.*;
 import com.cyksj.model.entity.*;
+import com.cyksj.model.response.GrokConversationCountResponse;
+import com.cyksj.model.views.GrokCarInfoView;
 import com.cyksj.model.views.GrokUserView;
 import com.cyksj.service.grok.GrokService;
 import com.cyksj.service.sys.SysConfigService;
 import com.cyksj.service.user.UserBindRelationService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.util.MapBuilder;
+import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
@@ -24,7 +30,9 @@ import org.springframework.stereotype.Service;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDateTime;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -50,6 +58,8 @@ public class GrokServiceImpl implements GrokService {
 
     private final SysConfigService sysConfigService;
 
+    private final BeanSearcher beanSearcher;
+
     @Override
     public GrokUserView getUserInfo(long userId, Long relationId) {
         GrokUser grokUser = checkCarAccount(userId, relationId);
@@ -59,11 +69,12 @@ public class GrokServiceImpl implements GrokService {
             GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
             GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
 
-           GrokUserView view =GrokUserView.builder()
+            GrokUserView view = GrokUserView.builder()
                     .skuName(goodsDonSku.getSubTitle())
                     .expireTime(grokUser.getExpireTime())
                     .limitNum(grokUser.getLimitNum())
                     .limitTime(grokUser.getLimitTime())
+                    .userToken(grokUser.getUserToken())
 
                     //.use(Math.min(grokUser.getLimitNum(), getConversationCount(grokUser.getUserToken(),grokUser.getLimitTime())))
                     .build();
@@ -131,6 +142,62 @@ public class GrokServiceImpl implements GrokService {
         }
     }
 
+    @Override
+    public String getCarLoginUrl(String domain, Long userId, Long relationId, String carId) {
+        GroupsRelation groupsRelation = getGroupsRelation(userId, relationId);
+        GroupsTrips groupsTrips = getGroupsTrips(groupsRelation);
+        GoodsDonSku goodsDonSku = skuMapper.selectById(groupsTrips.getSkuId());
+        if (goodsDonSku != null && goodsDonSku.getIsMirror() && goodsDonSku.getIsCar()) {
+            GrokUser grokUser = getGrokUser(userId, relationId, groupsRelation, goodsDonSku);
+
+            String DOMAIN = domain;
+            if (StrUtil.isEmpty(DOMAIN)) {
+                DOMAIN = "https://groknode.goodwillus.org";
+                try {
+                    SysConfig sysConfig = sysConfigService.getOne(Wrappers.lambdaQuery(SysConfig.class).eq(SysConfig::getSysKey, "mirror_xy_grok_domain"));
+                    if (sysConfig != null) {
+                        String sysValue = sysConfig.getSysValue();
+                        if (JSONUtil.isJsonArray(sysValue)) {
+                            List<String> domainList = JSONUtil.parseArray(sysValue).toList(String.class);
+                            DOMAIN = domainList.get(RandomUtil.randomInt(domainList.size()));
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("随机抽取域名错误. msg:{}", StringUtil.getErrorText(e));
+                }
+            }
+            log.info("domain:{},用户:{},所在车次:{},座位id:{},车队id:{},在{}获取跳转Grok镜像车队的登录url", DOMAIN, userId, groupsTrips.getId(), relationId, carId, DateTime.now());
+            return DOMAIN + "/auth/login?userToken=" + grokUser.getUserToken() + "&carid=" + carId;
+        } else {
+            throw BusinessRuntimeException.getInstance("服务器出了点问题");
+        }
+    }
+
+    @Override
+    public SearchResult<GrokCarInfoView> getCarInfoList(Map<String, String[]> parameterMap, Integer limit) {
+        Map<String, String[]> params = new HashMap<>(parameterMap);
+        if (params.containsKey("status")) {
+            params.put("csStatus", params.remove("status"));
+        }
+        MapBuilder builder = MapUtils.flatBuilder(params)
+                .orderBy(GrokCarInfoView::getSort).asc()
+                .orderBy(GrokCarInfoView::getScore).asc();
+        if (!params.containsKey("limit")) {
+            builder.limit(0, limit);
+        }
+        SearchResult<GrokCarInfoView> carInfoList = beanSearcher.search(GrokCarInfoView.class, builder.build());
+        carInfoList.getDataList().forEach(this::buildGrokCarInfoView);
+        return carInfoList;
+    }
+
+    private void buildGrokCarInfoView(GrokCarInfoView view) {
+        view.setCarName(view.getCarId());
+        view.setStatus("空闲");
+        Double score = Optional.ofNullable(view.getScore()).orElse(0D);
+        view.setStatus(score >= 100 ? "繁忙" : "空闲");
+        view.setScore(Math.min(BigDecimal.valueOf(score).multiply(BigDecimal.valueOf(0.5)).setScale(0, RoundingMode.DOWN).doubleValue(), 200));
+    }
+
     /**
      * 获取车位信息
      *
@@ -138,6 +205,42 @@ public class GrokServiceImpl implements GrokService {
      * @param relationId
      * @return
      */
+    @Override
+    public GrokConversationCountResponse getConversationCountDetail(String userToken) {
+        GrokUser grokUser = grokUserMapper.selectOne(Wrappers.lambdaQuery(GrokUser.class)
+                .eq(GrokUser::getUserToken, userToken)
+                .last("limit 1"));
+        if (grokUser == null) {
+            throw BusinessRuntimeException.getInstance("用户不存在或已过期");
+        }
+        try {
+            JSONObject json = getConversationCount(userToken);
+            if (json.containsKey("message")) {
+                throw BusinessRuntimeException.getInstance(json.getStr("message"));
+            }
+
+            Long count = Optional.ofNullable(json.getLong("count")).orElse(0L);
+            Integer limit = Optional.ofNullable(json.getInt("limit")).orElse(grokUser.getLimitNum());
+            Long time = Optional.ofNullable(json.getLong("time")).orElse(grokUser.getLimitTime());
+            Boolean isVip = Optional.ofNullable(json.getBool("isVip")).orElse(Boolean.TRUE.equals(grokUser.getIsVip()));
+            Long remaining = Optional.ofNullable(json.getLong("remaining"))
+                    .orElse(limit == null ? 0L : Math.max(0L, limit - count));
+
+            GrokConversationCountResponse response = new GrokConversationCountResponse();
+            response.setCount(count);
+            response.setLimit(limit);
+            response.setRemaining(remaining);
+            response.setTime(time);
+            response.setIsVip(isVip);
+            return response;
+        } catch (BusinessRuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            log.error("调用Grok getConversationCount接口失败: {}", StringUtil.getErrorText(e));
+            throw BusinessRuntimeException.getInstance("获取对话次数失败");
+        }
+    }
+
     private GroupsRelation getGroupsRelation(Long userId, Long relationId) {
         List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
         GroupsRelation groupsRelation = groupsRelationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).in(GroupsRelation::getUserId, userIdList).eq(GroupsRelation::getId, relationId));
@@ -205,7 +308,7 @@ public class GrokServiceImpl implements GrokService {
 
     public JSONObject getConversationCount(String userToken) {
         try {
-            String res = HttpUtil.get("http://147.79.20.183:9611/grok/getConversationCount?userToken=" + userToken);
+            String res = HttpUtil.get("http://208.98.56.214:9611/grok/getConversationCount?userToken=" + userToken);
             return new JSONObject(res);
         }catch (Exception e){
             return new JSONObject("{\"count\": 0}");

+ 72 - 6
netflix-web/src/main/java/com/cyksj/web/controller/mirror/MirrorController.java

@@ -20,8 +20,9 @@ import com.cyksj.mapper.renew.RenewUpgradePackageMapper;
 import com.cyksj.model.dto.ChatgptUserVerifyDto;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.request.GeminiOauthReq;
-import com.cyksj.model.response.ConversationLimitResponse;
+import com.cyksj.model.request.GrokAuthReq;
 import com.cyksj.model.response.GeminiConversationCountResponse;
+import com.cyksj.model.response.GrokConversationCountResponse;
 import com.cyksj.model.views.*;
 import com.cyksj.service.chatgpt.ChatGptAccountService;
 import com.cyksj.service.claude.ClaudeService;
@@ -40,6 +41,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.Cookie;
@@ -572,19 +574,32 @@ public class MirrorController {
      * Grok车票跳转登录
      *
      */
-    @RequestMapping("/grok/oauth")
-    public String grokOauth(String userToken) {
+    @PostMapping(value = "/grok/oauth", consumes = MediaType.APPLICATION_JSON_VALUE)
+    public String grokOauth(@RequestBody GrokAuthReq authReq) {
+        return doGrokOauth(authReq.getUserToken());
+    }
+
+    @PostMapping(value = "/grok/oauth", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    public String grokOauthForm(GrokAuthReq authReq) {
+        String userToken = authReq.getUserToken();
+        if (StringUtils.isBlank(userToken)) {
+            userToken = request.getParameter("usertoken");
+        }
+        return doGrokOauth(userToken);
+    }
+
+    private String doGrokOauth(String userToken) {
         try {
             log.info("用户通过userToken:{}访问grok镜像", userToken);
             GrokUser user = grokService.findByUserTokenAndExpireTimeAfter(userToken, LocalDateTime.now());
             JSONObject result = new JSONObject();
 
             if (user == null) {
-                result.putOpt("code",0);
+                result.putOpt("code",1);
                 result.putOpt("msg","用户不存在或已过期");
                 return result.toString();
             }
-            result.putOpt("code",1);
+            result.putOpt("code",0);
             result.putOpt("msg","登陆成功");
             result.putOpt("isPro",true);
             result.putOpt("usertoken",userToken);
@@ -594,7 +609,7 @@ public class MirrorController {
         } catch (Exception e) {
             log.error("服务器错误", e);
             JSONObject result = new JSONObject();
-            result.putOpt("code",0);
+            result.putOpt("code",1);
             result.putOpt("msg","服务器错误");
             return result.toString();
         }
@@ -622,6 +637,57 @@ public class MirrorController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(url);
     }
 
+    /**
+     * grok根据车队id跳转登录
+     *
+     * @param carId 车队id
+     */
+    @GetMapping("/grok/{relationId}/{carId}")
+    public Result<String> grokCarLoginByCarId(String domain, @PathVariable Long relationId, @PathVariable String carId) throws IOException {
+        Long userId = StpUserUtil.getLoginIdAsLong();
+        grokService.checkCarAccount(userId, relationId);
+        String url = grokService.getCarLoginUrl(domain, userId, relationId, carId);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(url);
+    }
+
+    /**
+     * Grok car list.
+     */
+    @GetMapping("/grok/cars")
+    public Result<SearchResult<GrokCarInfoView>> grokCarInfoList(Long relationId, @RequestParam(defaultValue = "11") Integer limit) {
+        Long userId = StpUserUtil.getUserIdAfterLogin();
+        if (relationId != null) {
+            GrokUser grokUser = grokService.checkCarAccount(userId, relationId);
+            if (grokUser == null) {
+                throw BusinessRuntimeException.getInstance("您还未购买车票");
+            }
+        }
+        SearchResult<GrokCarInfoView> carInfoList = grokService.getCarInfoList(request.getParameterMap(), limit);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(carInfoList);
+    }
+
+    /**
+     * Grok 查询用户对话次数
+     */
+    @GetMapping("/grok/getConversationCount")
+    public String grokGetConversationCount(String userToken) {
+        try {
+            GrokConversationCountResponse response = grokService.getConversationCountDetail(userToken);
+            JSONObject result = new JSONObject();
+            result.put("count", response.getCount());
+            result.put("limit", response.getLimit());
+            result.put("remaining", response.getRemaining());
+            result.put("time", response.getTime());
+            result.put("isVip", response.getIsVip());
+            return result.toString();
+        } catch (Exception e) {
+            log.error("Grok getConversationCount error", e);
+            JSONObject result = new JSONObject();
+            result.put("message", e.getMessage());
+            return result.toString();
+        }
+    }
+
 
     //------------------------ Gemini -------------------------------