Browse Source

微信登录与预测成绩功能

花田厝 3 weeks ago
parent
commit
f56ed78901
20 changed files with 824 additions and 51 deletions
  1. 65 0
      jsjp-admin/src/main/java/com/miaxis/app/controller/gzpt/GzptExamInfoController.java
  2. 19 16
      jsjp-admin/src/main/java/com/miaxis/app/controller/gzpt/GzptUserInfoController.java
  3. 44 0
      jsjp-admin/src/main/java/com/miaxis/system/controller/system/SysLoginController.java
  4. 13 17
      jsjp-admin/src/test/java/com/miaxis/test/NormalTest4.java
  5. 90 0
      jsjp-admin/src/test/java/com/miaxis/test/Test09.java
  6. 55 0
      jsjp-admin/src/test/java/com/miaxis/test/Test10.java
  7. 1 1
      jsjp-framework/src/main/java/com/miaxis/framework/config/SecurityConfig.java
  8. 103 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/domain/GzptExamInfo.java
  9. 36 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptExamInfoDTO.java
  10. 25 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptUserInfoBindDTO.java
  11. 31 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptUserLoginDTO.java
  12. 28 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptUserOpenIdDTO.java
  13. 25 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/mapper/GzptExamInfoMapper.java
  14. 9 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/mapper/GzptUserInfoMapper.java
  15. 32 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/service/IGzptExamInfoService.java
  16. 14 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/service/IGzptUserInfoService.java
  17. 115 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/service/impl/GzptExamInfoServiceImpl.java
  18. 61 0
      jsjp-service/src/main/java/com/miaxis/newgzpt/service/impl/GzptUserInfoServiceImpl.java
  19. 44 0
      jsjp-service/src/main/resources/mapper/newgzpt/GzptExamInfoMapper.xml
  20. 14 17
      jsjp-service/src/main/resources/mapper/newgzpt/GzptUserInfoMapper.xml

+ 65 - 0
jsjp-admin/src/main/java/com/miaxis/app/controller/gzpt/GzptExamInfoController.java

@@ -0,0 +1,65 @@
+package com.miaxis.app.controller.gzpt;
+
+
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.core.controller.BaseController;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.core.domain.entity.UserInfo;
+import com.miaxis.common.core.page.ResponsePageInfo;
+import com.miaxis.common.exception.CustomException;
+import com.miaxis.common.utils.SecurityUtils;
+import com.miaxis.free.domain.FreeUserLog;
+import com.miaxis.free.service.IFreeUserLogService;
+import com.miaxis.newgzpt.domain.GzptUserInfo;
+import com.miaxis.newgzpt.dto.GzptExamInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserInfoDTO;
+import com.miaxis.newgzpt.dto.GzptVideoVipDTO;
+import com.miaxis.newgzpt.service.*;
+import com.miaxis.newgzpt.vo.GzptExamInfoVO;
+import com.miaxis.newgzpt.vo.GzptSchActivationVO;
+import com.miaxis.userInfo.domain.UserVip;
+import com.miaxis.userInfo.service.IUserVipService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 学员基本信息表 前端控制器
+ * </p>
+ *
+ * @since 2021-03-09
+ */
+@RestController
+@Api(tags = "【app-学员成绩信息】")
+@RequestMapping(Constants.OPEN_PREFIX + "/gzpt/examinfo")
+public class GzptExamInfoController extends BaseController {
+
+    @Autowired
+    private IGzptExamInfoService gzptExamInfoService;
+
+
+    /**
+     * 预测学员通过率
+     */
+    @PostMapping(value = "/calculatePassRate")
+    @ApiOperation("预测学员通过率")
+    public Response calculatePassRate(@RequestBody GzptExamInfoDTO gzptExamInfoDTO) {
+        Double passRate = gzptExamInfoService.calculatePassRate(gzptExamInfoDTO);
+        if (passRate == null) {
+            throw new CustomException("计算概率出错");
+        }
+        return Response.success(passRate);
+    }
+
+
+
+
+}
+

+ 19 - 16
jsjp-admin/src/main/java/com/miaxis/app/controller/gzpt/GzptUserInfoController.java

@@ -11,7 +11,9 @@ import com.miaxis.common.utils.SecurityUtils;
 import com.miaxis.free.domain.FreeUserLog;
 import com.miaxis.free.service.IFreeUserLogService;
 import com.miaxis.newgzpt.domain.GzptUserInfo;
+import com.miaxis.newgzpt.dto.GzptUserInfoBindDTO;
 import com.miaxis.newgzpt.dto.GzptUserInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserLoginDTO;
 import com.miaxis.newgzpt.dto.GzptVideoVipDTO;
 import com.miaxis.newgzpt.service.IGzptSchActivationService;
 import com.miaxis.newgzpt.service.IGzptSchPayConfigService;
@@ -19,6 +21,7 @@ import com.miaxis.newgzpt.service.IGzptSchPayLogService;
 import com.miaxis.newgzpt.service.IGzptUserInfoService;
 import com.miaxis.newgzpt.vo.GzptExamInfoVO;
 import com.miaxis.newgzpt.vo.GzptSchActivationVO;
+import com.miaxis.tms.dto.TmsCoachInfoDTO;
 import com.miaxis.userInfo.domain.UserVip;
 import com.miaxis.userInfo.service.IUserVipService;
 import io.swagger.annotations.Api;
@@ -176,7 +179,7 @@ public class GzptUserInfoController extends BaseController {
 
     /**
      * 绑定学员账号
-     */
+
     @PutMapping(value = "/bind")
     @ApiOperation("绑定学员账号")
     public Response getUserWxlogin(@RequestBody GzptUserInfoDTO gzptUserInfoDTO) {
@@ -190,24 +193,24 @@ public class GzptUserInfoController extends BaseController {
         return Response.success();
     }
 
+     */
+
+
+    @PostMapping(value = "/bindGzptUserOpenid")
+    @ApiOperation("绑定学员账号和微信openid")
+    public Response bindGzptUserOpenid(@RequestBody GzptUserInfoBindDTO userInfoBindDTO) {
+        return userInfoService.bindGzptUserOpenid(userInfoBindDTO);
+    }
+
 
     /**
-     * 获取用户vip信息
-
-     @GetMapping
-     @ApiOperation("获取用户vip信息") public Response<GzptVideoVipVO> getVideoVip(GzptVideoVipDTO gzptVideoVipDTO) throws Exception {
-     GzptVideoVip gzptVideoVip  = gzptVideoVipService.getGzptVideoVipByUserId(gzptVideoVipDTO);
-     GzptVideoVipVO vo = new GzptVideoVipVO();
-     if(gzptVideoVip!=null) {
-     BeanUtils.copyProperties(gzptVideoVip, vo);
-     String sign = getSign(vo.getUserId(), vo.getSubject2(), vo.getSubject3());
-     vo.setSign(sign);
-     return Response.success(vo);
-     } else {
-     return Response.success(vo);
-     }
-     }
+     * 解绑学员微信绑定关系
      */
+    @PutMapping("/unBindGzptUserOpenid")
+    @ApiOperation("解绑学员微信绑定关系")
+    public Response unBindGzptUserOpenid(@RequestBody GzptUserLoginDTO GzptUserLoginDTO) {
+        return userInfoService.unBindGzptUserOpenid(GzptUserLoginDTO);
+    }
 
 
 }

+ 44 - 0
jsjp-admin/src/main/java/com/miaxis/system/controller/system/SysLoginController.java

@@ -18,6 +18,9 @@ import com.miaxis.framework.web.service.SysLoginService;
 import com.miaxis.framework.web.service.SysPermissionService;
 import com.miaxis.framework.web.service.TokenService;
 import com.miaxis.apple.IAppleService;
+import com.miaxis.newgzpt.domain.GzptUserInfo;
+import com.miaxis.newgzpt.dto.GzptUserOpenIdDTO;
+import com.miaxis.newgzpt.service.IGzptUserInfoService;
 import com.miaxis.system.dto.common.RouterDTO;
 import com.miaxis.system.dto.system.TokenDTO;
 import com.miaxis.system.dto.system.UserInfoDTO;
@@ -70,6 +73,8 @@ public class SysLoginController {
     @Autowired
     private IAppleService appleService;
 
+    @Autowired
+    private IGzptUserInfoService userInfoService;
 
     private static Logger logger = LoggerFactory.getLogger(SysLoginController.class);
 
@@ -241,6 +246,45 @@ public class SysLoginController {
     }
 
 
+    @PostMapping("/login/jsjpcode")
+    @ApiOperation("极速驾培app微信用户授权码模式登录")
+    public Response loginUserByWxAuthorizationCode(String authorizationCode) {
+        String wxResultStr = wxService.getWxToken(appid, secret, authorizationCode, "authorization_code");
+        logger.info("微信授权码登录返回值:" + wxResultStr);
+        WxResult wxResult = JSONObject.parseObject(wxResultStr, WxResult.class);
+
+        // 生成令牌
+        if (wxResult.getErrcode() != null) {
+            throw new CustomException("微信授权无效,请重新授权");
+        }
+
+        String userInfoStr = wxService.getUserInfo("zh_CN", wxResult.getAccess_token(), wxResult.getOpenid());
+        WxUserInfo wxUserInfo = JSONObject.parseObject(userInfoStr, WxUserInfo.class);
+        ServletUtils.getRequest().setAttribute("headImage", wxUserInfo.getHeadimgurl());
+        ServletUtils.getRequest().setAttribute("nickName", wxUserInfo.getNickname());
+        ServletUtils.getRequest().setAttribute("openid", wxUserInfo.getOpenid());
+
+        System.out.println(wxUserInfo.getNickname());
+        System.out.println(wxUserInfo.getHeadimgurl());
+        System.out.println(wxUserInfo.getOpenid());
+
+
+        GzptUserInfo gzptUserInfo = userInfoService.getUserInfoByOpenid(wxUserInfo.getOpenid());
+
+        Map<String, Object> resultMap = new HashMap();
+        if (gzptUserInfo == null) {
+            resultMap.put("openid", wxUserInfo.getOpenid());
+            resultMap.put("gzptUserInfo", null);
+            return Response.success(resultMap);
+        } else {
+            resultMap.put("openid", wxUserInfo.getOpenid());
+            resultMap.put("gzptUserInfo", gzptUserInfo);
+            return Response.success(resultMap);
+        }
+
+    }
+
+
     /**
      * 获取用户信息
      *

+ 13 - 17
jsjp-admin/src/test/java/com/miaxis/test/NormalTest4.java

@@ -26,7 +26,7 @@ public class NormalTest4 {
     private static String appid = "7629";
     private static String secret = "cce08fcab10ff96a863892bb6e396a9e";
 
-    public static String getSign(Map<String, Object> params,String client_secret) {
+    public static String getSign(Map<String, Object> params, String client_secret) {
         Map<String, Object> sortMap = new TreeMap<String, Object>();
         sortMap.putAll(params);
         // 以k1v1k2v2...方式拼接参数
@@ -47,7 +47,7 @@ public class NormalTest4 {
     @Test
     public void test() throws Exception {
         long timeLong = System.currentTimeMillis();
-        String timestamp = String.valueOf(timeLong/1000);
+        String timestamp = String.valueOf(timeLong / 1000);
         Wa wa = new Wa();
         //公共请救参数
         wa.setAppid(appid);
@@ -55,14 +55,14 @@ public class NormalTest4 {
         wa.setFormat("json");
         wa.setTime(timestamp);
         //sign 加密
-        Map<String,Object> param = new HashMap<String,Object>();
+        Map<String, Object> param = new HashMap<String, Object>();
         //公共参数
-        param.put("appid",wa.getAppid());
-        param.put("domain",wa.getDomain());
-        param.put("format",wa.getFormat());
-        param.put("time",wa.getTime());
+        param.put("appid", wa.getAppid());
+        param.put("domain", wa.getDomain());
+        param.put("format", wa.getFormat());
+        param.put("time", wa.getTime());
 
-        String sign = getSign(param,secret);
+        String sign = getSign(param, secret);
         System.out.println(sign);
         String md5 = MD5Utils.MD5Encode(sign);
         wa.setSign(md5);
@@ -76,15 +76,11 @@ public class NormalTest4 {
     }
 
 
-
-
-
-
-
-
-
-
-
+    @Test
+    public void test2() {
+        String md5 = MD5Utils.MD5Encode("123456");
+        System.out.println(md5);
+    }
 
 
 }

+ 90 - 0
jsjp-admin/src/test/java/com/miaxis/test/Test09.java

@@ -0,0 +1,90 @@
+package com.miaxis.test;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Test09 {
+
+
+
+
+    public static void main(String[] args) {
+        List<Integer> mockScores = Arrays.asList(92, 95, 96, 94, 98,99);
+        double rate = Test09.calculatePassRate(15, 50, 1000, mockScores);
+// 预期值:约 93.6%(需实际调参验证)
+        System.out.println(rate);
+
+    }
+
+
+
+        // 核心计算逻辑(建议结合历史数据训练调整权重参数)
+        public static double calculatePassRate(int wrongCount, int practicedCount, int totalQuestions, List<Integer> mockScores) {
+            // 1. 知识掌握度评估(权重40%)
+            double knowledgeScore = calculateKnowledgeScore(wrongCount, practicedCount, totalQuestions);
+
+            // 2. 模拟考试分析(权重55%)
+            double mockExamScore = calculateMockExamScore(mockScores);
+
+            // 3. 特殊规则修正(权重5%)
+            double adjustment = calculateSpecialAdjustment(mockScores);
+
+            // 综合计算(标准化到0-100%)
+            double passRate = (knowledgeScore * 0.4) + (mockExamScore * 0.55) + adjustment;
+            return Math.max(0, Math.min(100, passRate));
+        }
+
+        private static double calculateKnowledgeScore(int wrongCount, int practicedCount, int totalQuestions) {
+            // 防止除零异常
+            if (practicedCount == 0) return 0;
+
+            // 错题影响(非线性衰减)
+            double wrongEffect = Math.pow(wrongCount, 1.2) / (practicedCount + 1);
+
+            // 知识点覆盖率(网页2提到的练习时长与知识点关联)
+            double coverage = (double)practicedCount / totalQuestions;
+
+            // 综合计算(网页3理论考试特性参考)
+            return 80 * (1 - wrongEffect) * Math.min(1.2, coverage * 1.5); // 最高120%激励
+        }
+
+        private static double calculateMockExamScore(List<Integer> mockScores) {
+            if (mockScores.isEmpty()) return 0;
+
+            // 基础参数统计(网页1的模拟考试分析逻辑)
+            double avgScore = mockScores.stream().mapToInt(i->i).average().orElse(0);
+            int highScoreCount = (int)mockScores.stream().filter(s -> s >= 95).count();
+            int passCount = (int)mockScores.stream().filter(s -> s >= 90).count();
+
+            // 稳定性计算(网页2的方差分析简化版)
+            double variance = mockScores.stream()
+                    .mapToDouble(s -> Math.pow(s - avgScore, 2))
+                    .average().orElse(0);
+            double stability = Math.max(0, 1 - variance / 100);
+
+            // 趋势分析(最近3次加权)
+            double trendWeight = 0;
+            if (mockScores.size() >= 3) {
+                List<Integer> lastThree = mockScores.subList(mockScores.size()-3, mockScores.size());
+                double recentAvg = lastThree.stream().mapToInt(i->i).average().orElse(0);
+                trendWeight = (recentAvg > avgScore) ? 5 : 0;
+            }
+
+            // 综合评估(网页1的多次高分加成)
+            return (avgScore * 0.6) +
+                    (highScoreCount * 2.5) +
+                    (passCount * 1.2) +
+                    (stability * 10) +
+                    trendWeight;
+        }
+
+        private static double calculateSpecialAdjustment(List<Integer> mockScores) {
+            // 特殊规则处理(网页3的科目特性参考)
+            if (mockScores.size() >= 5 &&
+                    mockScores.stream().filter(s -> s >= 95).count() >= 3) {
+                return 8; // 强化高分激励
+            }
+            return 0;
+        }
+
+}

+ 55 - 0
jsjp-admin/src/test/java/com/miaxis/test/Test10.java

@@ -0,0 +1,55 @@
+package com.miaxis.test;
+
+import com.miaxis.JsjpApplication;
+import com.miaxis.newgzpt.domain.GzptExamInfo;
+import com.miaxis.newgzpt.dto.GzptExamInfoDTO;
+import com.miaxis.newgzpt.service.IGzptExamInfoService;
+import com.miaxis.newgzpt.service.IGzptSchActivationService;
+import com.miaxis.tms.dto.TmsStudentInfoDTO;
+import com.miaxis.tms.service.ITmsStudentInfoService;
+import com.miaxis.tms.vo.TmsStudentInfoVo;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@SpringBootTest(classes = JsjpApplication.class)
+@RunWith(SpringRunner.class)
+public class Test10 {
+
+
+
+
+    @Autowired
+    private IGzptExamInfoService examInfoService;
+
+    @Test
+    public void test() {
+
+        GzptExamInfoDTO gzptExamInfoDTO = new GzptExamInfoDTO();
+        gzptExamInfoDTO.setKskm("1");
+        gzptExamInfoDTO.setCarType("小车");
+        gzptExamInfoDTO.setUserId(2392789l);
+        List<GzptExamInfo> list = examInfoService.selectGzptExamInfoList(gzptExamInfoDTO);
+
+
+        List<Integer> scoreList = list.stream()
+                .map(GzptExamInfo::getScore)
+                .collect(Collectors.toList());
+
+        System.out.println(scoreList);
+        System.out.println(list);
+
+
+        List<Integer> scoreList2 =examInfoService.selectGzptExamScoreList(gzptExamInfoDTO);
+        System.out.println(scoreList2);
+
+    }
+
+
+
+}

+ 1 - 1
jsjp-framework/src/main/java/com/miaxis/framework/config/SecurityConfig.java

@@ -102,7 +102,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 // 对于app 开放页面,允许任意访问
                 .antMatchers("/**/open-api/**").permitAll()
                 // 对于登录login 验证码captchaImage 允许匿名访问
-                .antMatchers("/login", "/login/noCode","/captchaImage","/login/jscode","/login/jscode-test","/login/code","/login/code/ios").anonymous()
+                .antMatchers("/login", "/login/noCode","/captchaImage","/login/jscode","/login/jscode-test","/login/code","/login/code/ios","/login/jsjpcode").anonymous()
                 //.antMatchers("/student/open/**").permitAll()
                 .antMatchers("/student/**").hasRole("STUDENT")
                 .antMatchers(

+ 103 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/domain/GzptExamInfo.java

@@ -0,0 +1,103 @@
+package com.miaxis.newgzpt.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>
+ * 学员基本信息表
+ * </p>
+ *
+ * @author ${author}
+ * @since 2025-03-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@TableName("GZPT_EXAM_INFO")
+@ApiModel(value="GzptExamInfo对象", description="学员考试成绩表")
+public class GzptExamInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId("EI_ID")
+    private Long id;
+
+    @ApiModelProperty(value = "姓名")
+    @TableField("EI_USER_ID")
+    private Long userId;
+
+    @ApiModelProperty(value = "考试科目 1 科一 2 科二 3 科三 4 科四")
+    @TableField("EI_KSKM")
+    private String kskm;
+
+    @ApiModelProperty(value = "考试成绩")
+    @TableField("EI_SCORE")
+    private Integer score;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField("EI_CRDATE")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date crdate;
+
+    @ApiModelProperty(value = "数据来源 1 录入 2 手机上传 3 web网站考试上传")
+    @TableField("EI_SOURCE")
+    private String source;
+
+    @ApiModelProperty(value = "归属驾校编号")
+    @TableField("EI_JXBH")
+    private String jxbm;
+
+    @ApiModelProperty(value = "开始考试时间")
+    @TableField("EI_STARTDATE")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date startDate;
+
+    @ApiModelProperty(value = "开始结束时间")
+    @TableField("EI_ENDDATE")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date endDate;
+
+    @ApiModelProperty(value = "考试完成总时间")
+    @TableField("EI_TOTAL_TIME")
+    private Integer totalTime;
+
+    @ApiModelProperty(value = "地市编号")
+    @TableField("EI_DQBH")
+    private String dqbh;
+
+    @ApiModelProperty(value = "地市名称")
+    @TableField("EI_DQMC")
+    private String dqmc;
+
+    @ApiModelProperty(value = "区县编号")
+    @TableField("EI_QXBH")
+    private String qxbh;
+
+    @ApiModelProperty(value = "区县名称")
+    @TableField("EI_QXMC")
+    private String qxmc;
+
+    @ApiModelProperty(value = "车型")
+    @TableField("EI_CARTYPE")
+    private String carType;
+
+    @ApiModelProperty(value = "是否已通知 0未通知 1已通知")
+    @TableField("EI_NOTICE")
+    private Integer notice;
+
+    @ApiModelProperty(value = "用户身份证")
+    @TableField("EI_USERSFZHM")
+    private String userSfzhm;
+
+
+
+}

+ 36 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptExamInfoDTO.java

@@ -0,0 +1,36 @@
+package com.miaxis.newgzpt.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * @author zhangbin
+ * @since 2025-03-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class GzptExamInfoDTO implements Serializable {
+
+
+    @ApiModelProperty(value = "用户ID", required = true)
+    private Long userId;
+
+    @ApiModelProperty(value = "科目", required = true)
+    private String kskm;
+
+    @ApiModelProperty(value = "车型", required = true)
+    private String carType;
+
+    @ApiModelProperty(value = "错题数", required = true)
+    private Integer wrongCount;
+
+    @ApiModelProperty(value = "已做题数", required = true)
+    private Integer practicedCount;
+
+    @ApiModelProperty(value = "总题数", required = true)
+    private Integer totalQuestions;
+
+}

+ 25 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptUserInfoBindDTO.java

@@ -0,0 +1,25 @@
+package com.miaxis.newgzpt.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+
+@Data
+public class GzptUserInfoBindDTO implements Serializable {
+
+
+    @ApiModelProperty(value = "登录账号")
+    private String logincode;
+
+    @ApiModelProperty(value = "登录密码")
+    private String password;
+
+    @ApiModelProperty(value = "微信openid")
+    private String openid;
+
+
+
+
+}

+ 31 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptUserLoginDTO.java

@@ -0,0 +1,31 @@
+package com.miaxis.newgzpt.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 学员基本信息表
+ * </p>
+ *
+ * @author ${author}
+ * @since 2021-03-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class GzptUserLoginDTO implements Serializable {
+
+
+    @ApiModelProperty(value = "登录账号")
+    private String logincode;
+
+    @ApiModelProperty(value = "登录密码 MD5加密")
+    private String password;
+
+
+
+}

+ 28 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/dto/GzptUserOpenIdDTO.java

@@ -0,0 +1,28 @@
+package com.miaxis.newgzpt.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 学员基本信息表
+ * </p>
+ *
+ * @author ${author}
+ * @since 2021-03-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class GzptUserOpenIdDTO implements Serializable {
+
+
+    @ApiModelProperty(value = "微信openId")
+    private String openid;
+
+
+
+
+}

+ 25 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/mapper/GzptExamInfoMapper.java

@@ -0,0 +1,25 @@
+package com.miaxis.newgzpt.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.newgzpt.domain.GzptExamInfo;
+import com.miaxis.newgzpt.domain.GzptUserInfo;
+import com.miaxis.newgzpt.dto.*;
+import com.miaxis.newgzpt.vo.GzptExamInfoVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 学员基本信息表 Mapper 接口
+ * </p>
+ *
+ * @author ${author}
+ * @since 2021-03-09
+ */
+public interface GzptExamInfoMapper extends BaseMapper<GzptExamInfo> {
+
+
+    List<GzptExamInfo> selectGzptExamInfoList(GzptExamInfoDTO gzptExamInfoDTO);
+
+    List<Integer> selectGzptExamScoreList(GzptExamInfoDTO gzptExamInfoDTO);
+}

+ 9 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/mapper/GzptUserInfoMapper.java

@@ -3,8 +3,12 @@ package com.miaxis.newgzpt.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.miaxis.newgzpt.domain.GzptUserInfo;
 import com.miaxis.newgzpt.dto.GzptAppleInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserInfoBindDTO;
 import com.miaxis.newgzpt.dto.GzptUserInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserLoginDTO;
 import com.miaxis.newgzpt.vo.GzptExamInfoVO;
+import com.miaxis.tms.dto.TmsCoachInfoDTO;
+import com.miaxis.tms.vo.TmsCoachInfoVo;
 
 import java.util.List;
 
@@ -34,4 +38,9 @@ public interface GzptUserInfoMapper extends BaseMapper<GzptUserInfo> {
 
     Integer updateUserBindCoach(Long outId);
 
+    GzptUserInfo getUserByLoginCodeAndPw(GzptUserLoginDTO gzptUserLoginDTO);
+
+    int updateGzptUserOpenid(GzptUserInfoBindDTO userInfoBindDTO);
+
+    GzptUserInfo getUserInfoByOpenid(String openid);
 }

+ 32 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/service/IGzptExamInfoService.java

@@ -0,0 +1,32 @@
+package com.miaxis.newgzpt.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.newgzpt.domain.GzptExamInfo;
+import com.miaxis.newgzpt.domain.GzptUserInfo;
+import com.miaxis.newgzpt.dto.GzptAppleInfoDTO;
+import com.miaxis.newgzpt.dto.GzptExamInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserInfoBindDTO;
+import com.miaxis.newgzpt.dto.GzptUserInfoDTO;
+import com.miaxis.newgzpt.vo.GzptExamInfoVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 学员基本信息表 服务类
+ * </p>
+ *
+ * @author ${author}
+ * @since 2021-03-09
+ */
+public interface IGzptExamInfoService extends IService<GzptExamInfo> {
+
+
+
+    List<GzptExamInfo> selectGzptExamInfoList(GzptExamInfoDTO gzptExamInfoDTO);
+
+    List<Integer> selectGzptExamScoreList(GzptExamInfoDTO gzptExamInfoDTO);
+
+    double calculatePassRate(GzptExamInfoDTO gzptExamInfoDTO);
+}

+ 14 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/service/IGzptUserInfoService.java

@@ -1,10 +1,18 @@
 package com.miaxis.newgzpt.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.utils.StringUtils;
 import com.miaxis.newgzpt.domain.GzptUserInfo;
 import com.miaxis.newgzpt.dto.GzptAppleInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserInfoBindDTO;
 import com.miaxis.newgzpt.dto.GzptUserInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserLoginDTO;
 import com.miaxis.newgzpt.vo.GzptExamInfoVO;
+import com.miaxis.tms.dto.TmsCoachInfoBindDTO;
+import com.miaxis.tms.dto.TmsCoachInfoDTO;
+import com.miaxis.tms.vo.TmsCoachInfoVo;
+import org.springframework.beans.BeanUtils;
 
 import java.util.List;
 
@@ -34,4 +42,10 @@ public interface IGzptUserInfoService extends IService<GzptUserInfo> {
     List<GzptExamInfoVO> getUserScoreByOutId(Long stuOutId);
 
     Long saveGzptUserInfo(GzptUserInfo userInfo);
+
+    Response bindGzptUserOpenid(GzptUserInfoBindDTO userInfoBindDTO);
+
+    Response unBindGzptUserOpenid(GzptUserLoginDTO userLoginDTO);
+
+    GzptUserInfo getUserInfoByOpenid(String openid);
 }

+ 115 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/service/impl/GzptExamInfoServiceImpl.java

@@ -0,0 +1,115 @@
+package com.miaxis.newgzpt.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.miaxis.common.annotation.DataSource;
+import com.miaxis.common.enums.DataSourceTypeEnum;
+import com.miaxis.newgzpt.domain.GzptExamInfo;
+import com.miaxis.newgzpt.dto.*;
+import com.miaxis.newgzpt.mapper.GzptExamInfoMapper;
+import com.miaxis.newgzpt.service.IGzptExamInfoService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ * 学员基本信息表 服务实现类
+ * </p>
+ *
+ * @author ${author}
+ * @since 2021-03-09
+ */
+@Service
+@DataSource(value = DataSourceTypeEnum.NEWGZPT)
+public class GzptExamInfoServiceImpl extends ServiceImpl<GzptExamInfoMapper, GzptExamInfo> implements IGzptExamInfoService {
+
+    @Resource
+    private GzptExamInfoMapper mapper;
+
+
+    @Override
+    public List<GzptExamInfo> selectGzptExamInfoList(GzptExamInfoDTO gzptExamInfoDTO) {
+        return mapper.selectGzptExamInfoList(gzptExamInfoDTO);
+    }
+
+    @Override
+    public List<Integer> selectGzptExamScoreList(GzptExamInfoDTO gzptExamInfoDTO) {
+        return mapper.selectGzptExamScoreList(gzptExamInfoDTO);
+    }
+
+
+    public double calculatePassRate(GzptExamInfoDTO examInfoDTO) {
+        // 1. 知识掌握度评估(权重40%)
+        double knowledgeScore = this.calculateKnowledgeScore(examInfoDTO.getWrongCount(), examInfoDTO.getPracticedCount(), examInfoDTO.getTotalQuestions());
+
+        List scoreList = mapper.selectGzptExamScoreList(examInfoDTO);
+        // 2. 模拟考试分析(权重55%)
+        double mockExamScore = calculateMockExamScore(scoreList);
+
+        // 3. 特殊规则修正(权重5%)
+        double adjustment = calculateSpecialAdjustment(scoreList);
+
+        // 综合计算(标准化到0-100%)
+        double passRate = (knowledgeScore * 0.4) + (mockExamScore * 0.55) + adjustment;
+        return Math.max(0, Math.min(100, passRate));
+    }
+
+
+    public double calculateKnowledgeScore(Integer wrongCount, Integer practicedCount, Integer totalQuestions) {
+        // 防止除零异常
+        if (practicedCount == 0) return 0;
+
+        // 错题影响(非线性衰减)
+        double wrongEffect = Math.pow(wrongCount, 1.2) / (practicedCount + 1);
+
+        // 知识点覆盖率(网页2提到的练习时长与知识点关联)
+        double coverage = (double) practicedCount / totalQuestions;
+
+        // 综合计算(网页3理论考试特性参考)
+        return 80 * (1 - wrongEffect) * Math.min(1.2, coverage * 1.5); // 最高120%激励
+    }
+
+
+
+    private double calculateMockExamScore(List<Integer> mockScores) {
+        if (mockScores.isEmpty()) return 0;
+
+        // 基础参数统计(网页1的模拟考试分析逻辑)
+        double avgScore = mockScores.stream().mapToInt(i -> i).average().orElse(0);
+        int highScoreCount = (int) mockScores.stream().filter(s -> s >= 95).count();
+        int passCount = (int) mockScores.stream().filter(s -> s >= 90).count();
+
+        // 稳定性计算(网页2的方差分析简化版)
+        double variance = mockScores.stream()
+                .mapToDouble(s -> Math.pow(s - avgScore, 2))
+                .average().orElse(0);
+        double stability = Math.max(0, 1 - variance / 100);
+
+        // 趋势分析(最近3次加权)
+        double trendWeight = 0;
+        if (mockScores.size() >= 3) {
+            List<Integer> lastThree = mockScores.subList(mockScores.size() - 3, mockScores.size());
+            double recentAvg = lastThree.stream().mapToInt(i -> i).average().orElse(0);
+            trendWeight = (recentAvg > avgScore) ? 5 : 0;
+        }
+
+        // 综合评估(网页1的多次高分加成)
+        return (avgScore * 0.6) +
+                (highScoreCount * 2.5) +
+                (passCount * 1.2) +
+                (stability * 10) +
+                trendWeight;
+    }
+
+    private double calculateSpecialAdjustment(List<Integer> mockScores) {
+        // 特殊规则处理(网页3的科目特性参考)
+        if (mockScores.size() >= 5 &&
+                mockScores.stream().filter(s -> s >= 95).count() >= 3) {
+            return 8; // 强化高分激励
+        }
+        return 0;
+    }
+
+
+}

+ 61 - 0
jsjp-service/src/main/java/com/miaxis/newgzpt/service/impl/GzptUserInfoServiceImpl.java

@@ -2,13 +2,23 @@ package com.miaxis.newgzpt.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.miaxis.common.annotation.DataSource;
+import com.miaxis.common.core.domain.Response;
 import com.miaxis.common.enums.DataSourceTypeEnum;
+import com.miaxis.common.sms.MD5Utils;
+import com.miaxis.common.utils.StringUtils;
+import com.miaxis.common.utils.sign.Md5Utils;
 import com.miaxis.newgzpt.domain.GzptUserInfo;
 import com.miaxis.newgzpt.dto.GzptAppleInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserInfoBindDTO;
 import com.miaxis.newgzpt.dto.GzptUserInfoDTO;
+import com.miaxis.newgzpt.dto.GzptUserLoginDTO;
 import com.miaxis.newgzpt.mapper.GzptUserInfoMapper;
 import com.miaxis.newgzpt.service.IGzptUserInfoService;
 import com.miaxis.newgzpt.vo.GzptExamInfoVO;
+import com.miaxis.tms.dto.TmsCoachInfoBindDTO;
+import com.miaxis.tms.dto.TmsCoachInfoDTO;
+import com.miaxis.tms.vo.TmsCoachInfoVo;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -73,4 +83,55 @@ public class GzptUserInfoServiceImpl extends ServiceImpl<GzptUserInfoMapper, Gzp
     public Long saveGzptUserInfo(GzptUserInfo userInfo) {
         return mapper.saveGzptUserInfo(userInfo);
     }
+
+    @Override
+    public Response bindGzptUserOpenid(GzptUserInfoBindDTO userInfoBindDTO) {
+
+        GzptUserLoginDTO userLoginDto = new GzptUserLoginDTO();
+        String passMd5 = MD5Utils.MD5Encode(userInfoBindDTO.getPassword());
+        userInfoBindDTO.setPassword(passMd5);
+        BeanUtils.copyProperties(userInfoBindDTO,userLoginDto);
+        GzptUserInfo gzptUserInfo = mapper.getUserByLoginCodeAndPw(userLoginDto);  //查询帐号是否绑定过
+        if(gzptUserInfo!=null) {
+            if(!StringUtils.isEmpty(gzptUserInfo.getOpenId())) {
+                Response response = new Response(50002,"该学员账号已绑定微信,请解绑后再次绑定。");
+                return response;
+            }
+        } else {
+            Response response = new Response(50003,"用户不存在或用户密码错误");
+            return response;
+        }
+
+        int result = mapper.updateGzptUserOpenid(userInfoBindDTO);
+        if(result>0) {
+            gzptUserInfo.setOpenId(userInfoBindDTO.getOpenid());
+            return Response.success(gzptUserInfo);
+        } else {
+            return Response.success(null);
+        }
+    }
+
+
+    @Override
+    public Response unBindGzptUserOpenid(GzptUserLoginDTO userLoginDTO) {
+
+        GzptUserInfoBindDTO userInfoBindDTO = new GzptUserInfoBindDTO();
+        String passMd5 = MD5Utils.MD5Encode(userLoginDTO.getPassword());
+        userLoginDTO.setPassword(passMd5);
+        BeanUtils.copyProperties(userLoginDTO,userInfoBindDTO);
+        GzptUserInfo gzptUserInfo = mapper.getUserByLoginCodeAndPw(userLoginDTO);  //查询帐号是否绑定过
+        if(gzptUserInfo==null) {
+            Response response = new Response(50002,"用户不存在或用户密码错误");
+            return response;
+        } else {
+            int result = mapper.updateGzptUserOpenid(userInfoBindDTO);
+            return Response.success(result);
+        }
+    }
+
+    @Override
+    public GzptUserInfo getUserInfoByOpenid(String openid) {
+        return mapper.getUserInfoByOpenid(openid);
+    }
+
 }

+ 44 - 0
jsjp-service/src/main/resources/mapper/newgzpt/GzptExamInfoMapper.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.miaxis.newgzpt.mapper.GzptExamInfoMapper">
+
+
+    <resultMap type="com.miaxis.newgzpt.domain.GzptExamInfo" id="GzptExamInfoResult">
+        <result property="id" column="EI_ID"/>
+        <result property="userId" column="EI_KSKM"/>
+        <result property="score" column="EI_SCORE"/>
+        <result property="crdate" column="EI_CRDATE"/>
+        <result property="source" column="EI_SOURCE"/>
+        <result property="jxbm" column="EI_JXBH"/>
+        <result property="startDate" column="EI_STARTDATE"/>
+        <result property="endDate" column="EI_ENDDATE"/>
+        <result property="totalTime" column="EI_TOTAL_TIME"/>
+        <result property="dqbh" column="EI_DQBH"/>
+        <result property="dqmc" column="EI_DQMC"/>
+        <result property="qxbh" column="EI_QXBH"/>
+        <result property="qxmc" column="EI_QXMC"/>
+        <result property="carType" column="EI_CARTYPE"/>
+        <result property="notice" column="EI_NOTICE"/>
+        <result property="userSfzhm" column="EI_USERSFZHM"/>
+    </resultMap>
+
+
+    <select id="selectGzptExamScoreList" parameterType="com.miaxis.newgzpt.dto.GzptExamInfoDTO" resultType="Integer">
+        select ei_score from gzpt_exam_info
+        <where>
+            <if test="userId != null ">and ei_user_id = #{userId}</if>
+            <if test="kskm != null and kskm!=''">and ei_kskm = #{kskm}</if>
+            <if test="carType != null and carType!=''">and ei_cartype = #{carType}</if>
+        </where>
+    </select>
+
+    <select id="selectGzptExamInfoList" parameterType="com.miaxis.newgzpt.dto.GzptExamInfoDTO" resultMap="GzptExamInfoResult">
+        select * from gzpt_exam_info
+        <where>
+            <if test="userId != null ">and ei_user_id = #{userId}</if>
+            <if test="kskm != null and kskm!=''">and ei_kskm = #{kskm}</if>
+            <if test="carType != null and carType!=''">and ei_cartype = #{carType}</if>
+        </where>
+    </select>
+
+</mapper>

+ 14 - 17
jsjp-service/src/main/resources/mapper/newgzpt/GzptUserInfoMapper.xml

@@ -29,6 +29,12 @@
     </select>
 
 
+    <select id="getUserByLoginCodeAndPw" parameterType="com.miaxis.newgzpt.dto.GzptUserInfoDTO" resultType="com.miaxis.newgzpt.domain.GzptUserInfo">
+        select * from gzpt_user_info g where g.id =
+                                             (select max(id) from gzpt_user_info g where g.logincode=#{logincode} and g.password=#{password})
+    </select>
+
+
     <select id="getAppleUserInfo" parameterType="com.miaxis.newgzpt.dto.GzptUserInfoDTO" resultType="com.miaxis.newgzpt.domain.GzptUserInfo">
         select * from gzpt_user_info g where g.id =
                                              (select max(id) from gzpt_user_info g where g.logincode=#{logincode} and apptype=2)
@@ -68,32 +74,23 @@
         update gzpt_user_info set is_bind_coach = 1 where out_id = #{outId,jdbcType=NUMERIC}
     </update>
 
+    <update id="updateGzptUserOpenid">
+        update gzpt_user_info set open_id = #{openid,jdbcType=VARCHAR}  where id = (select max(id) from gzpt_user_info g where g.logincode=#{logincode,jdbcType=VARCHAR} and g.password=#{password,jdbcType=VARCHAR})
+    </update>
 
 
-    <delete id="removeVipByUserId" parameterType="long">
-        delete from user_vip where user_id = #{userId}
-    </delete>
 
-    <select id="getGzptVideoVipByUserId" resultType="com.miaxis.newgzpt.domain.GzptVideoVip" parameterType="com.miaxis.userInfo.dto.UserVipDTO">
-        select * from GZPT_VIDEO_VIP
-        <where>
-            and user_id = #{userId}
-        </where>
-    </select>
 
 
-    <select id="getGzptVideoVipByUserId" resultType="com.miaxis.newgzpt.domain.GzptVideoVip" parameterType="com.miaxis.userInfo.dto.UserVipDTO">
-        select * from GZPT_VIDEO_VIP
-        <where>
-            and user_id = #{userId}
-        </where>
+    <select id="getUserScoreByOutId" resultMap="GzptExamInfoVOResultMap">
+        select ei_user_id,ei_username,ei_kskm,ei_score,ei_crdate,ei_startdate,ei_enddate from gzpt_exam_info g where ei_user_id = (select id from gzpt_user_info u where u.out_id =#{stuOutId})
+        order by ei_id desc
     </select>
 
+    <select id="getUserInfoByOpenid" resultType="com.miaxis.newgzpt.domain.GzptUserInfo">
 
+        select * from GZPT_USER_INFO where open_id =#{openid,jdbcType=VARCHAR}
 
-    <select id="getUserScoreByOutId" resultMap="GzptExamInfoVOResultMap">
-        select ei_user_id,ei_username,ei_kskm,ei_score,ei_crdate,ei_startdate,ei_enddate from gzpt_exam_info g where ei_user_id = (select id from gzpt_user_info u where u.out_id =#{stuOutId})
-        order by ei_id desc
     </select>