From 7fe0d0111e04def01abbe12badad8e527c6cfab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=B8=85?= Date: Sat, 23 Aug 2025 19:18:15 +0800 Subject: [PATCH] =?UTF-8?q?1.bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hezhi/api/kaoshi/ApiPCController.java | 9 + .../hezhi/api/kaoshi/ApiPayController.java | 82 +++-- .../hezhi/controller/TbCourseController.java | 32 +- ruoyi-common/pom.xml | 7 + .../weixin/config/WeiXinH5PayConfig.java | 57 +++ .../weixin/utils/WeiXinPayV3NewUtils.java | 330 ++++++++++++++++++ .../common/weixin/utils/WeiXinPayV3Utils.java | 4 +- .../java/com/ruoyi/hezhi/domain/TbExam.java | 8 + .../com/ruoyi/hezhi/mapper/TbExamMapper.java | 7 + .../hezhi/service/impl/TbExamServiceImpl.java | 49 ++- .../impl/TbExamSubjectServiceImpl.java | 12 +- .../TbMemberExamSimulateAllServiceImpl.java | 6 +- .../TbMemberSubjectCollectServiceImpl.java | 5 + .../resources/mapper/hezhi/TbExamMapper.xml | 15 +- .../mapper/hezhi/TbExamNoticeMapper.xml | 1 + .../mapper/hezhi/TbMajorClassMapper.xml | 3 +- .../mapper/hezhi/TbStudyCenterMapper.xml | 1 + ruoyi-ui/src/api/hezhi/link.js | 3 +- ruoyi-ui/src/views/hezhi/exam/index.vue | 47 ++- 19 files changed, 616 insertions(+), 62 deletions(-) create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/weixin/config/WeiXinH5PayConfig.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3NewUtils.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPCController.java b/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPCController.java index 2597370..8ca7b72 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPCController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPCController.java @@ -475,6 +475,15 @@ public class ApiPCController { return AjaxResult.success(evaluateAgencyMajorClass); } + /** + * 查询专业分类列表-下拉框树列表 + */ + @GetMapping("/getAllMajorClassList") + public AjaxResult getAllMajorClassList() + { + return AjaxResult.success(majorClassService.getAllMajorClassList()); + } + /** * 专业课程详情 * diff --git a/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPayController.java b/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPayController.java index 28e0a49..30f616c 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPayController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/hezhi/api/kaoshi/ApiPayController.java @@ -9,6 +9,7 @@ import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.common.weixin.config.WeiXinPayConfig; +import com.ruoyi.common.weixin.utils.WeiXinPayV3NewUtils; import com.ruoyi.common.weixin.utils.WeiXinPayV3Utils; import com.ruoyi.hezhi.api.entity.AliPayConfig; import com.ruoyi.hezhi.api.entity.AlipayService; @@ -18,6 +19,7 @@ import com.ruoyi.hezhi.domain.dto.ExamPayInfoDto; import com.ruoyi.hezhi.service.ITbExamRegistrationService; import com.ruoyi.hezhi.service.ITbMemberOrderService; import com.ruoyi.hezhi.service.IWxPayService; +import com.wechat.pay.java.service.payments.model.Transaction; import io.swagger.annotations.Api; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +58,8 @@ public class ApiPayController { private IWxPayService wxPayService; @Resource private ITbExamRegistrationService examRegistrationService; + @Resource + private WeiXinPayV3NewUtils weiXinPayV3NewUtils; /** * alipay扫码支付 @@ -205,6 +209,8 @@ public class ApiPayController { } } + + /*** * 获取微信支付H5 * @param orderNo 订单号 @@ -212,7 +218,6 @@ public class ApiPayController { */ @GetMapping("/createH5PayParam") public AjaxResult createH5PayParam(String orderNo) { - //todo 检测考试报名时间是否过了(微信)【待测试】 if (StrUtil.isBlank(orderNo)) { throw new ServiceException("参数错误"); } @@ -234,46 +239,53 @@ public class ApiPayController { memberOrderService.orderPayNotify(orderNo, 1); return AjaxResult.success(data); } else { - //单位为人民币(分) - JSONObject amount = new JSONObject(); - amount.put("total", order.getPayPrice().multiply(new BigDecimal("100")).intValue()); - amount.put("currency", "CNY"); - - // H5场景信息 - JSONObject h5_info = new JSONObject(); - amount.put("type", "Wap");// 场景类型,使用H5支付的场景:Wap、iOS、Android - // 场景信息 - JSONObject scene_info = new JSONObject(); - amount.put("payer_client_ip  ", IpUtils.getIpAddr()); - amount.put("h5_info  ", h5_info); - - JSONObject postData = new JSONObject(); - postData.put("appid", weiXinPayConfig.getAppId()); - postData.put("mchid", weiXinPayConfig.getMchId()); - postData.put("description", order.getRemarks()); - postData.put("out_trade_no", orderNo); - postData.put("notify_url", weiXinPayConfig.getH5NotifyUrl()); - postData.put("amount", amount); - postData.put("scene_info", scene_info); - - log.info("H5下单-参数 => {}", postData.toJSONString()); - - // 发送请求 - JSONObject result = weiXinPayV3Utils.sendPost("https://api.mch.weixin.qq.com/v3/pay/transactions/h5", postData); - log.info("H5下单-结果 => {}", postData.toJSONString()); - if (result.containsKey("h5_url")) { - // 支付二维码 - Map map = new HashMap<>(); - map.put("h5_url", result.getString("h5_url")); - map.put("isNeedPay", 1); - return AjaxResult.success(map); + String h5PayUrl = weiXinPayV3NewUtils.createH5PayParam(order.getPayPrice(), orderNo, order.getRemarks()); + log.info("H5下单-结果 => {}", h5PayUrl); + if (null != h5PayUrl) { + return AjaxResult.success("操作成功", h5PayUrl); } else { - log.error("H5下单调起失败 <{}> 参数:{},结果:{}", DateUtils.getTime(), postData.toJSONString(), result.toJSONString()); throw new ServiceException("H5下单调起失败"); } } } + @GetMapping("/createH5PayParamNotify") + private AjaxResult createH5PayParamNotify(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) { + String code = "FAIL"; + String message = ""; + try { + // 以支付通知回调为例,验签、解密并转换成 Transaction + Transaction transaction = weiXinPayV3NewUtils.getNotifyData(httpServletRequest); + if ("SUCCESS".equals(transaction.getTradeState().name())) { + log.error("订单回调 <{}> 订单参数 <{}> ", DateUtils.getTime(), transaction); + // 支付成功 + String orderSn = transaction.getOutTradeNo(); + String msg = ""; + try { + TbMemberOrder tbMemberOrder = new TbMemberOrder(); + tbMemberOrder.setOrderNo(orderSn); + tbMemberOrder.setPayStatus(1); + memberOrderService.updateTbMemberOrderByOrderNo(tbMemberOrder); + message = "回调成功"; + } catch (Exception e) { + log.error("锅炉订单回调 <{}> 订单号 <{}> 订单处理异常", DateUtils.getTime(), orderSn); + msg = "FAIL"; + } + if ("SUCCESS".equals(msg)) { + code = "SUCCESS"; + } else { + message = "商户业务处理异常"; + } + } else { + message = "回调参数异常"; + } + } catch (Exception e) { + log.error("订单回调 <{}> 解析异常", DateUtils.getTime()); + message = "回调参数解析异常"; + } + return AjaxResult.success(message); + } + /** * 微信支付回调 * diff --git a/ruoyi-admin/src/main/java/com/ruoyi/hezhi/controller/TbCourseController.java b/ruoyi-admin/src/main/java/com/ruoyi/hezhi/controller/TbCourseController.java index f7b2627..e613e11 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/hezhi/controller/TbCourseController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/hezhi/controller/TbCourseController.java @@ -7,8 +7,11 @@ import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.hezhi.domain.TbCourse; +import com.ruoyi.hezhi.domain.TbExam; import com.ruoyi.hezhi.domain.TbTypeCourse; import com.ruoyi.hezhi.domain.vo.CaseTypeVO; +import com.ruoyi.hezhi.mapper.TbExamMapper; +import com.ruoyi.hezhi.service.ITbCaseService; import com.ruoyi.hezhi.service.ITbCaseTypeService; import com.ruoyi.hezhi.service.ITbCourseService; import com.ruoyi.hezhi.service.ITbTypeCourseService; @@ -17,7 +20,9 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; /** @@ -36,6 +41,8 @@ public class TbCourseController extends BaseController private ITbTypeCourseService tbTypeCourseService; @Autowired private ITbCaseTypeService tbCaseTypeService; + @Autowired + private TbExamMapper tbExamMapper; /** * 查询课程列表 @@ -140,7 +147,28 @@ public class TbCourseController extends BaseController * @return */ @GetMapping("/getAllCourseList") - public AjaxResult getAllCourseList() { - return AjaxResult.success(tbCourseService.getAllCourseList()); + public AjaxResult getAllCourseList(TbCourse tbCourse) { + List courseList = tbCourseService.getAllCourseList(); + if (courseList == null || courseList.isEmpty()) { + return AjaxResult.success(new ArrayList<>()); + } + + List tbExamList = tbExamMapper.selectTbExamListAll(); + // 使用Set提高查找效率 + Set careerIdSet = tbExamList.stream() + .map(TbExam::getCareerId) + .collect(Collectors.toSet()); + + // 如果tbCourse参数中的CareerId不为空,从careerIdSet中移除该值 + if (tbCourse != null && tbCourse.getCareerId() != null) { + careerIdSet.remove(tbCourse.getCareerId()); + } + + // 过滤掉在careerIdSet中存在的课程 + List result = courseList.stream() + .filter(course -> !careerIdSet.contains(course.getCourseId())) + .collect(Collectors.toList()); + + return AjaxResult.success(result); } } diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 465adcc..5eda1cd 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -154,6 +154,13 @@ 0.4.8 + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.17 + + cn.hutool hutool-all diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/weixin/config/WeiXinH5PayConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/weixin/config/WeiXinH5PayConfig.java new file mode 100644 index 0000000..429c3c4 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/weixin/config/WeiXinH5PayConfig.java @@ -0,0 +1,57 @@ +package com.ruoyi.common.weixin.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * 微信支付V3相关参数配置 + * + * @author Wzp + */ +@Getter +@Setter +@Configuration +public class WeiXinH5PayConfig { + + @Value("${wx.pay.h5.appId}") + private String appId; + + @Value("${wx.pay.h5.mchId}") + private String mchId; + + @Value("${wx.pay.h5.mchSerialNum}") + private String mchSerialNum; + + @Value("${wx.pay.h5.apiV3Key}") + private String apiV3Key; + + //微信回调地址 + @Value("${wx.pay.h5.notifyUrl}") + private String notifyUrl; + + //微信H5回调地址 + @Value("${wx.pay.h5.h5NotifyUrl}") + private String h5NotifyUrl; + + //支付宝回调地址 + @Value("${wx.pay.h5.notifyZfbUrl}") + private String notifyZfbUrl; + + @Value("${wx.pay.h5.description}") + private String description; + + @Value("${wx.pay.h5.apiClientKey}") + private String apiClientKey; + + @Value("${wx.login.appId}") + private String appIdLogin; + + @Value("${wx.login.appSecret}") + private String appSecretLogin; + + @Value("${wx.login.redirectUrl}") + private String redirectUrl; + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3NewUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3NewUtils.java new file mode 100644 index 0000000..7ea5e33 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3NewUtils.java @@ -0,0 +1,330 @@ +package com.ruoyi.common.weixin.utils; + +import cn.hutool.core.net.URLEncodeUtil; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.ip.IpUtils; +import com.ruoyi.common.utils.uuid.IdUtils; +import com.ruoyi.common.weixin.config.WeiXinH5PayConfig; +import com.ruoyi.common.weixin.config.WeiXinPayConfig; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import com.wechat.pay.java.core.cipher.SignatureResult; +import com.wechat.pay.java.core.cipher.Signer; +import com.wechat.pay.java.core.http.*; +import com.wechat.pay.java.core.notification.NotificationConfig; +import com.wechat.pay.java.core.notification.NotificationParser; +import com.wechat.pay.java.service.payments.h5.model.H5Info; +import com.wechat.pay.java.service.payments.h5.model.SceneInfo; +import com.wechat.pay.java.service.payments.jsapi.JsapiService; +import com.wechat.pay.java.service.payments.jsapi.model.Amount; +import com.wechat.pay.java.service.payments.jsapi.model.Payer; +import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest; +import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse; +import com.wechat.pay.java.service.payments.h5.H5Service; +import com.wechat.pay.java.service.payments.model.Transaction; +import com.wechat.pay.java.service.refund.model.AmountReq; +import com.wechat.pay.java.service.refund.model.CreateRequest; +import com.wechat.pay.java.service.refund.model.Refund; +import com.wechat.pay.java.service.refund.model.Status; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigDecimal; + +/** + * 微信V3支付 + * + * @author Wzp + */ +@Component +public class WeiXinPayV3NewUtils { + + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Resource + private WeiXinH5PayConfig weiXinH5PayConfig; + + + /*** + * 请求JSAPI下单 + * @param total 金额 + * @param openId 支付用户 + * @param orderSn 订单号 + * @param description 描述 + * @param notifyApi 回调接口名称 + * @return 结果 + */ + public JSONObject createPayParam(BigDecimal total, String openId, String orderSn, String description, String notifyApi) { + + //更新证书配置,这里用官方sdk,不需要考虑时效性问题 + Config config = new RSAAutoCertificateConfig.Builder() + .merchantId(weiXinH5PayConfig.getMchId()) + .privateKey(weiXinH5PayConfig.getApiClientKey())//微信v3-私钥 + .merchantSerialNumber(weiXinH5PayConfig.getMchSerialNum())//微信v3证书序列号 + .apiV3Key(weiXinH5PayConfig.getApiV3Key())//微信v3-apiV3Key + .build(); + + Amount amount = new Amount(); + amount.setTotal(total.multiply(new BigDecimal("100")).intValue()); + amount.setCurrency("CNY"); + + Payer payer = new Payer(); + payer.setOpenid(openId); + + PrepayRequest prepayRequest = new PrepayRequest(); + prepayRequest.setMchid(weiXinH5PayConfig.getMchId()); + prepayRequest.setOutTradeNo(orderSn); + prepayRequest.setAppid(weiXinH5PayConfig.getAppId()); + prepayRequest.setDescription(description); + prepayRequest.setNotifyUrl(weiXinH5PayConfig.getNotifyUrl() + notifyApi); + + prepayRequest.setAmount(amount); + prepayRequest.setPayer(payer); + logger.info("JSAPI下单-参数 => {}", prepayRequest.toString()); + + // 构建请求 + JsapiService jsapiService = new JsapiService.Builder().config(config).build(); + PrepayResponse prepay = jsapiService.prepay(prepayRequest); + logger.info("JSAPI下单-结果 => {}", prepay.toString()); + String prepayId = prepay.getPrepayId(); + + JSONObject payInfo = new JSONObject(); + if (StringUtils.isNotBlank(prepayId)) { + // 小程序ID + payInfo.put("appId", weiXinH5PayConfig.getAppId()); + // 时间戳 + payInfo.put("timeStamp", String.valueOf((int) (System.currentTimeMillis() / 1000))); + // 随机字符串 + payInfo.put("nonceStr", IdUtils.fastSimpleUUID()); + // 订单详情扩展字符串 + payInfo.put("package", "prepay_id=" + prepayId); + // 签名方式 + payInfo.put("signType", "RSA"); + // 加密字符串,每行一个参数 + String paySignParam = payInfo.get("appId") + "\n" + payInfo.get("timeStamp") + "\n" + payInfo.get("nonceStr") + "\n" + payInfo.get("package") + "\n"; + // 签名 + String paySign = this.signRSA(paySignParam, config); + payInfo.put("paySign", paySign); + payInfo.put("orderNumber", orderSn); + + return payInfo; + } else { + throw new ServiceException("JSAPI下单调起失败"); + } + } + + /*** + * 请求H5下单 + * @param total 金额 + * @param orderSn 订单号 + * @param description 描述 + * @return 结果 + */ + public String createH5PayParam(BigDecimal total, String orderSn, String description) { + + //更新证书配置,这里用官方sdk,不需要考虑时效性问题 + Config config = new RSAAutoCertificateConfig.Builder() + .merchantId(weiXinH5PayConfig.getMchId()) + .privateKey(weiXinH5PayConfig.getApiClientKey())//微信v3-私钥 + .merchantSerialNumber(weiXinH5PayConfig.getMchSerialNum())//微信v3证书序列号 + .apiV3Key(weiXinH5PayConfig.getApiV3Key())//微信v3-apiV3Key + .build(); + + com.wechat.pay.java.service.payments.h5.model.PrepayRequest prepayRequest = new com.wechat.pay.java.service.payments.h5.model.PrepayRequest(); + prepayRequest.setMchid(weiXinH5PayConfig.getMchId()); + prepayRequest.setOutTradeNo(orderSn); + prepayRequest.setAppid(weiXinH5PayConfig.getAppId()); + prepayRequest.setDescription("学信考试"); + prepayRequest.setNotifyUrl(weiXinH5PayConfig.getH5NotifyUrl()); + SceneInfo sceneInfo = new SceneInfo(); + sceneInfo.setPayerClientIp(IpUtils.getIpAddr()); + H5Info h5Info = new H5Info(); + h5Info.setType("Wap"); + sceneInfo.setH5Info(h5Info); + prepayRequest.setSceneInfo(sceneInfo); + com.wechat.pay.java.service.payments.h5.model.Amount amount = new com.wechat.pay.java.service.payments.h5.model.Amount(); + amount.setTotal(total.multiply(new BigDecimal("100")).intValue()); + amount.setCurrency("CNY"); + prepayRequest.setAmount(amount); + logger.info("H5下单-参数 => {}", prepayRequest); + // 构建请求 + H5Service h5Service = new H5Service.Builder().config(config).build(); + com.wechat.pay.java.service.payments.h5.model.PrepayResponse response = h5Service.prepay(prepayRequest); + String h5Url = response.getH5Url(); + if (StringUtils.isNotBlank(h5Url)) { + // h5Url += "&redirect_url="+ URLEncodeUtil.encode("https://h5.chsie.com.cn"); + return h5Url; + } else { + throw new ServiceException("H5下单调起失败"); + } + } + + /** + * 微信支付v3签名 RSA签名 + * + * @param message 需要签名的内容 + * @return 结果 + */ + public String signRSA(String message, Config config) { + try { + Signer signer = config.createSigner(); + SignatureResult sign = signer.sign(message); + return sign.getSign(); + } catch (Exception e) { + e.printStackTrace(); + return ""; + } + } + + /** + * 微信退款(app和小程序通用) + * + * @param out_trade_no 商户订单号 + * @param out_refund_no 商户退款单号 + * @param refund 退款金额 + * @param total 原订单金额 + * @return 结果 + */ + public String weiXinRefund(String out_trade_no, String out_refund_no, int refund, int total) { + + try { + + //更新证书配置,这里用官方sdk,不需要考虑时效性问题 + Config wxConfig = new RSAAutoCertificateConfig.Builder() + .merchantId(weiXinH5PayConfig.getMchId()) + .privateKey(weiXinH5PayConfig.getApiClientKey()) + .merchantSerialNumber(weiXinH5PayConfig.getMchSerialNum()) + .apiV3Key(weiXinH5PayConfig.getApiV3Key()) + .build(); + + + AmountReq amountReq = new AmountReq(); + amountReq.setRefund((long) refund); + amountReq.setTotal((long) total); + amountReq.setCurrency("CNY"); + + CreateRequest createRequest = new CreateRequest(); + createRequest.setAmount(amountReq); + + createRequest.setOutRefundNo(out_refund_no); + createRequest.setOutTradeNo(out_trade_no); + + logger.info("JSAPI退款-参数 => " + createRequest.toString()); + // 发送请求 + HttpHeaders headers = new HttpHeaders(); + headers.addHeader(com.wechat.pay.java.core.http.Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue()); + headers.addHeader(com.wechat.pay.java.core.http.Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue()); + HttpRequest httpRequest = + new HttpRequest.Builder() + .httpMethod(HttpMethod.POST) + .url("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds") + .headers(headers) + .body(new JsonRequestBody.Builder().body(com.wechat.pay.java.core.util.GsonUtil.toJson(createRequest)).build()) + .build(); + + HttpClient httpClient = new DefaultHttpClientBuilder().config(wxConfig).build(); + + HttpResponse httpResponse = httpClient.execute(httpRequest, Refund.class); + Refund serviceResponse = httpResponse.getServiceResponse(); + + Status status = serviceResponse.getStatus(); + String name = status.name(); + + if (("SUCCESS".equals(name) || "PROCESSING".equals(name))) { + return "SUCCESS"; + } else { + return "FAIL"; + } + } catch (Exception e) { + e.printStackTrace(); + return "FAIL"; + } + } + + /** + * 解析支付回调参数 + * + * @param httpServletRequest 请求 + * @return 结果 + */ + public Transaction getNotifyData(HttpServletRequest httpServletRequest) { + + try { + // 请求头Wechatpay-Signature + String signature = httpServletRequest.getHeader("Wechatpay-Signature"); + // 请求头Wechatpay-nonce + String nonce = httpServletRequest.getHeader("Wechatpay-Nonce"); + // 请求头Wechatpay-Timestamp + String timestamp = httpServletRequest.getHeader("Wechatpay-Timestamp"); + // 微信支付证书序列号 + String serial = httpServletRequest.getHeader("Wechatpay-Serial"); + // 签名方式 + String signType = httpServletRequest.getHeader("Wechatpay-Signature-Type"); + + // 获取报文 + String body = getRequestBody(httpServletRequest); + + // 1.构造 RequestParam + com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder() + .serialNumber(serial) + .nonce(nonce) + .signature(signature) + .timestamp(timestamp) + .signType(signType) + .body(body) + .build(); + + // 2. 如果你仍在使用微信支付平台证书,则使用 RSAAutoCertificateConfig + NotificationConfig wxConfig = new RSAAutoCertificateConfig.Builder() + .merchantId(weiXinH5PayConfig.getMchId()) + .privateKey(weiXinH5PayConfig.getApiClientKey()) + .merchantSerialNumber(weiXinH5PayConfig.getMchSerialNum()) + .apiV3Key(weiXinH5PayConfig.getApiV3Key()) + .build(); + + // 初始化 NotificationParser + NotificationParser parser = new NotificationParser(wxConfig); + // 以支付通知回调为例,验签、解密并转换成 Transaction + return parser.parse(requestParam, Transaction.class); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 读取请求数据流 + * + * @param request 请求 + * @return 结果 + */ + private String getRequestBody(HttpServletRequest request) { + + StringBuilder sb = new StringBuilder(); + + try (ServletInputStream inputStream = request.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + ) { + String line; + + while ((line = reader.readLine()) != null) { + sb.append(line); + } + + } catch (IOException e) { + e.printStackTrace(); + } + + return sb.toString(); + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3Utils.java b/ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3Utils.java index d62374f..8a4d250 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3Utils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/weixin/utils/WeiXinPayV3Utils.java @@ -68,9 +68,9 @@ public class WeiXinPayV3Utils { * @throws Exception 异常 */ private void setVerifier() throws Exception { - if (merchantPrivateKey == null) { +// if (merchantPrivateKey == null) { setMerchantPrivateKey(); - } +// } // 获取证书管理器实例 CertificatesManager certificatesManager = CertificatesManager.getInstance(); // 向证书管理器增加需要自动更新平台证书的商户信息 diff --git a/ruoyi-system/src/main/java/com/ruoyi/hezhi/domain/TbExam.java b/ruoyi-system/src/main/java/com/ruoyi/hezhi/domain/TbExam.java index 7f51dec..cf23254 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/hezhi/domain/TbExam.java +++ b/ruoyi-system/src/main/java/com/ruoyi/hezhi/domain/TbExam.java @@ -47,6 +47,14 @@ public class TbExam extends BaseEntity @Excel(name = "专业名") private String majorName; + /** 机构ID */ + @Excel(name = "机构ID") + private Long evaluateAgencyId; + + /** 机构名称 */ + @Excel(name = "机构名称") + private String evaluateAgencyName; + /** 职业ID */ @Excel(name = "职业ID") private Long careerId; diff --git a/ruoyi-system/src/main/java/com/ruoyi/hezhi/mapper/TbExamMapper.java b/ruoyi-system/src/main/java/com/ruoyi/hezhi/mapper/TbExamMapper.java index 50257be..df070ac 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/hezhi/mapper/TbExamMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/hezhi/mapper/TbExamMapper.java @@ -31,6 +31,13 @@ public interface TbExamMapper */ public List selectTbExamList(TbExam tbExam); + /** + * 查询考试列表 + * + * @return 考试集合 + */ + public List selectTbExamListAll(); + /** * 查询考试列表 * diff --git a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamServiceImpl.java index 3482ea8..5a6a5b7 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamServiceImpl.java @@ -51,6 +51,8 @@ public class TbExamServiceImpl implements ITbExamService private TbExamBatchMapper tbExamBatchMapper; @Resource private ThreadPoolTaskExecutor threadPoolTaskExecutor; + @Resource + private TbEvaluateAgencyMapper tbEvaluateAgencyMapper; /** * 查询考试 @@ -127,6 +129,22 @@ public class TbExamServiceImpl implements ITbExamService tbExamCourseMapper.insertTbExamCourse(tbExamCourse); } } + if (null != tbExam.getEvaluateAgencyId()) { + TbEvaluateAgency evaluateAgency = tbEvaluateAgencyMapper.selectTbEvaluateAgencyByEvaluateAgencyId(tbExam.getEvaluateAgencyId()); + tbExam.setEvaluateAgencyName(evaluateAgency.getEvaluateAgencyName()); + } + + if (null != tbExam.getCareerId()) { + TbCourse tbCourse = tbCourseMapper.selectTbCourseByCourseId(tbExam.getCareerId()); + tbExam.setCareerName(tbCourse.getCourseName()); + } + + if (null != tbExam.getExamId()) { + TbCourse course = new TbCourse(); + course.setCareerId(tbExam.getCareerId()); + course.setExamId(tbExam.getExamId()); + tbCourseMapper.updateTbCourse(course); + } // 考试批次 List tbExamBatchList = tbExam.getExamBatchList(); @@ -244,6 +262,22 @@ public class TbExamServiceImpl implements ITbExamService // tbExamBatchMapper.updateTbExamBatchBatch(toUpdate); // 你需要写批量 update 逻辑 // } + if (null != tbExam.getEvaluateAgencyId()) { + TbEvaluateAgency evaluateAgency = tbEvaluateAgencyMapper.selectTbEvaluateAgencyByEvaluateAgencyId(tbExam.getEvaluateAgencyId()); + tbExam.setEvaluateAgencyName(evaluateAgency.getEvaluateAgencyName()); + } + + if (null != tbExam.getCareerId()) { + TbCourse tbCourse = tbCourseMapper.selectTbCourseByCourseId(tbExam.getCareerId()); + tbExam.setCareerName(tbCourse.getCourseName()); + } + + if (null != tbExam.getExamId()) { + TbCourse course = new TbCourse(); + course.setCourseId(tbExam.getCareerId()); + course.setExamId(tbExam.getExamId()); + tbCourseMapper.updateTbCourse(course); + } // 考试批次 List tbExamBatchList = tbExam.getExamBatchList(); if (!tbExamBatchList.isEmpty()){ @@ -347,13 +381,16 @@ public class TbExamServiceImpl implements ITbExamService if (ObjectUtils.isNotEmpty(tbExamCourse)){ Long examId = tbExamCourse.getExamId(); TbExam tbExam = tbExamMapper.selectTbExamByExamId(examId); - List enableByExamId = tbExamBatchMapper.getEnableByExamId(examId, tbExam.getExamBatchEarly()); - if (!enableByExamId.isEmpty()){ - TbExamBatch tbExamBatch = enableByExamId.get(0); - courseListVO.setExamBatch(tbExamBatch.getExamBatch()); - courseListVO.setExamId(tbExam.getExamId()); - courseListVO.setLevel(getLevel(tbExam.getLevel()));//等级也查出来 + if (tbExam != null) { + List enableByExamId = tbExamBatchMapper.getEnableByExamId(examId, tbExam.getExamBatchEarly()); + if (!enableByExamId.isEmpty()){ + TbExamBatch tbExamBatch = enableByExamId.get(0); + courseListVO.setExamBatch(tbExamBatch.getExamBatch()); + courseListVO.setExamId(tbExam.getExamId()); + courseListVO.setLevel(getLevel(tbExam.getLevel()));//等级也查出来 + } } + } countDownLatch.countDown(); }); diff --git a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamSubjectServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamSubjectServiceImpl.java index fc1fbd1..5a58132 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamSubjectServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbExamSubjectServiceImpl.java @@ -180,12 +180,12 @@ public class TbExamSubjectServiceImpl implements ITbExamSubjectService { */ @Override public List> queryByParam(Map params) { - Long courseId = MapUtils.getLong(params, "courseId"); - TbExamCourse examCourseDetail = tbExamCourseMapper.getSubjectWarehouseClassIdByCourseId(courseId); - if (ObjectUtils.isEmpty(examCourseDetail)) { - throw new ServiceException("此课程未添加题库"); - } - params.put("subjectWarehouseClassId", examCourseDetail.getSubjectWarehouseClassId()); +// Long courseId = MapUtils.getLong(params, "courseId"); +// TbExamCourse examCourseDetail = tbExamCourseMapper.getSubjectWarehouseClassIdByCourseId(courseId); +// if (ObjectUtils.isEmpty(examCourseDetail)) { +// throw new ServiceException("此课程未添加题库"); +// } +// params.put("subjectWarehouseClassId", examCourseDetail.getSubjectWarehouseClassId()); return tbExamSubjectMapper.queryByParam(params); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberExamSimulateAllServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberExamSimulateAllServiceImpl.java index 1570165..8d73c80 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberExamSimulateAllServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberExamSimulateAllServiceImpl.java @@ -356,9 +356,9 @@ public class TbMemberExamSimulateAllServiceImpl implements ITbMemberExamSimulate try { endTimeCompare = dateFormat.parse(endTime); // 比较时间 - if (currentTime.after(endTimeCompare)) { - return AjaxResult.error("做题时间【" + tbExamSimulateInfo.getStartTime() + "至" + tbExamSimulateInfo.getEndTime() + "】,考试已结束"); - } +// if (currentTime.after(endTimeCompare)) { +// return AjaxResult.error("做题时间【" + tbExamSimulateInfo.getStartTime() + "至" + tbExamSimulateInfo.getEndTime() + "】,考试已结束"); +// } if (currentTime.after(examEndTimeCompare)) { return AjaxResult.error("考试时间【" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamStartTime()) + "至" + DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", tbExamBatch.getExamEndTime()) + "】,考试已结束"); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberSubjectCollectServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberSubjectCollectServiceImpl.java index 38b1831..515e81f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberSubjectCollectServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/hezhi/service/impl/TbMemberSubjectCollectServiceImpl.java @@ -6,6 +6,7 @@ import com.ruoyi.hezhi.domain.TbMemberSubjectCollect; import com.ruoyi.hezhi.domain.dto.MemberSubjectCollectDTO; import com.ruoyi.hezhi.mapper.TbExamSubjectAnswerMapper; import com.ruoyi.hezhi.mapper.TbMemberSubjectCollectMapper; +import com.ruoyi.hezhi.mapper.TbMemberSubjectWrongMapper; import com.ruoyi.hezhi.service.ITbMemberSubjectCollectService; import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +29,8 @@ public class TbMemberSubjectCollectServiceImpl implements ITbMemberSubjectCollec private TbMemberSubjectCollectMapper tbMemberSubjectCollectMapper; @Autowired private TbExamSubjectAnswerMapper examSubjectAnswerMapper; + @Autowired + private TbMemberSubjectWrongMapper memberSubjectWrongMapper; /** * 查询我的收藏题目 @@ -146,6 +149,8 @@ public class TbMemberSubjectCollectServiceImpl implements ITbMemberSubjectCollec // 选项列表 List> subjectSelectList = examSubjectAnswerMapper.selectSelectList(null, examSubjectNo); examSubjectInfo.put("subjectSelectList", subjectSelectList); + // 我的答案 +// memberSubjectWrongMapper.selectTbMemberSubjectWrongByMemberSubjectWrongId(); // 处理answer字段 String answer = examSubjectInfo.get("answer").toString(); String[] answerOptions = answer.split(","); diff --git a/ruoyi-system/src/main/resources/mapper/hezhi/TbExamMapper.xml b/ruoyi-system/src/main/resources/mapper/hezhi/TbExamMapper.xml index e0d32c4..409d82c 100644 --- a/ruoyi-system/src/main/resources/mapper/hezhi/TbExamMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/hezhi/TbExamMapper.xml @@ -11,6 +11,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -60,11 +62,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select exam_id, exam_no, class_id, class_name, major_id, major_name, career_id, career_name, logo, file_url, name, title, content, introduce, single_select_num, single_select_score, many_select_num, many_select_score, judge_num, judge_score, discuss_num, discuss_score, total_score, pass_score, exam_minute, exam_batch_early, exam_batch, tips, exam_start_time, exam_end_time, sign_start_time, sign_end_time, price, exam_status, is_change, change_day, type, examine_status, examine_feedback, sort, remarks, status, publication_time, publisher, create_time, create_by, update_time, update_by, delete_time, delete_by, del_flag, level from tb_exam + select exam_id, exam_no, class_id, class_name, major_id, major_name, evaluate_agency_id, evaluate_agency_name, career_id, career_name, logo, file_url, name, title, content, introduce, single_select_num, single_select_score, many_select_num, many_select_score, judge_num, judge_score, discuss_num, discuss_score, total_score, pass_score, exam_minute, exam_batch_early, exam_batch, tips, exam_start_time, exam_end_time, sign_start_time, sign_end_time, price, exam_status, is_change, change_day, type, examine_status, examine_feedback, sort, remarks, status, publication_time, publisher, create_time, create_by, update_time, update_by, delete_time, delete_by, del_flag, level from tb_exam + diff --git a/ruoyi-system/src/main/resources/mapper/hezhi/TbExamNoticeMapper.xml b/ruoyi-system/src/main/resources/mapper/hezhi/TbExamNoticeMapper.xml index 5fdcbcc..5a63fff 100644 --- a/ruoyi-system/src/main/resources/mapper/hezhi/TbExamNoticeMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/hezhi/TbExamNoticeMapper.xml @@ -176,6 +176,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" diff --git a/ruoyi-ui/src/api/hezhi/link.js b/ruoyi-ui/src/api/hezhi/link.js index b3f0c23..c819687 100644 --- a/ruoyi-ui/src/api/hezhi/link.js +++ b/ruoyi-ui/src/api/hezhi/link.js @@ -62,9 +62,10 @@ export function listLinkLiveBroadcastTeacher(query) { } // 所有课程列表 -export function getAllCourseList() { +export function getAllCourseList(query) { return request({ url: '/hezhi/course/getAllCourseList', method: 'get', + params: query }) } diff --git a/ruoyi-ui/src/views/hezhi/exam/index.vue b/ruoyi-ui/src/views/hezhi/exam/index.vue index 556a28c..505a973 100644 --- a/ruoyi-ui/src/views/hezhi/exam/index.vue +++ b/ruoyi-ui/src/views/hezhi/exam/index.vue @@ -280,9 +280,30 @@ > + + + + + + + - + + + + + + + @@ -474,6 +495,8 @@ import {addExam, delExam, getExam, listExam, updateExam, updateExamConfig} from "@/api/hezhi/exam"; import ExamCourse from "@/components/ExamCourse/index.vue"; import ExamBatch from "@/views/hezhi/exam/examBatch.vue"; +import {getSelectList} from "@/api/hezhi/evaluateAgency"; +import {getAllCourseList} from "@/api/hezhi/link"; export default { name: "Exam", @@ -508,6 +531,8 @@ export default { daterangeSignStartTime: [], // 删除标记时间范围 daterangeSignEndTime: [], + evaluateAgencyOptions:[], + courseOptions:[], // 查询参数 queryParams: { pageNum: 1, @@ -600,11 +625,21 @@ export default { getSelectList().then(response => { this.evaluateAgencyOptions = response.data; }); - getAllCourseList().then(response => { - this.courseOptions = response.data; - }); }, methods: { + getAllCourse(careerId) { + getAllCourseList({careerId}).then(response => { + this.courseOptions = response.data; + }) + }, + // 重选机构清空对应课程 + handleAgencyChange() { + this.form.careerId = undefined; + }, + getCourseOptions() { + let evaluateAgencyId = this.form.evaluateAgencyId; + return this.courseOptions.filter(item => item.evaluateAgencyId === evaluateAgencyId); + }, /** * 处理价格输入,限制最多两位小数 */ @@ -683,6 +718,8 @@ export default { className: null, majorId: null, majorName: null, + evaluateAgencyId: null, + evaluateAgencyName: null, careerId: null, careerName: null, logo: null, @@ -757,6 +794,7 @@ export default { this.reset(); this.open = true; this.title = "添加考试"; + this.getAllCourse() }, /** 修改按钮操作 */ handleUpdate(row) { @@ -764,6 +802,7 @@ export default { const examId = row.examId || this.ids getExam(examId).then(response => { this.form = response.data; + this.getAllCourse(this.form.careerId) this.open = true; this.title = "修改考试"; }); -- 2.22.0