Преглед на файлове

Merge branch 'master' of http://115.29.66.169:10080/yiyao_shop/api

lubo преди 5 месеца
родител
ревизия
1ec1307815
променени са 20 файла, в които са добавени 626 реда и са изтрити 25 реда
  1. 7 0
      pom.xml
  2. 4 6
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/shop/order/ShopOrderCommentController.java
  3. 14 0
      ruoyi-admin/src/main/resources/application-dev.yml
  4. 4 0
      ruoyi-admin/src/main/resources/application.yml
  5. 28 16
      ruoyi-api/src/main/java/com/ruoyi/api/controller/user/ApiUserLoginController.java
  6. 6 0
      ruoyi-common/pom.xml
  7. 5 0
      ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
  8. 58 0
      ruoyi-common/src/main/java/com/ruoyi/common/properties/GeTuiConfig.java
  9. 144 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/SmsFeiXinUtil.java
  10. 22 2
      ruoyi-common/src/main/java/com/ruoyi/common/utils/SmsSend.java
  11. 251 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/push/GeTuiUtils.java
  12. 52 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/push/Msg.java
  13. 4 0
      ruoyi-shop/src/main/java/com/ruoyi/shop/order/domain/ShopOrderComment.java
  14. 0 1
      ruoyi-shop/src/main/java/com/ruoyi/shop/order/domain/bo/ShopOrderCommentBo.java
  15. 5 0
      ruoyi-shop/src/main/java/com/ruoyi/shop/order/domain/vo/ShopOrderCommentVo.java
  16. 2 0
      ruoyi-shop/src/main/java/com/ruoyi/shop/order/service/impl/ShopOrderCommentServiceImpl.java
  17. 2 0
      ruoyi-shop/src/main/resources/mapper/order/ShopOrderCommentMapper.xml
  18. 6 0
      ruoyi-user/src/main/java/com/ruoyi/user/domain/bo/ThirdLoginBo.java
  19. 6 0
      ruoyi-user/src/main/java/com/ruoyi/user/domain/bo/ThirdRegisterBo.java
  20. 6 0
      ruoyi-user/src/main/java/com/ruoyi/user/domain/bo/UserLoginBo.java

+ 7 - 0
pom.xml

@@ -543,6 +543,13 @@
                 <artifactId>jwks-rsa</artifactId>
                 <version>${jwks-rsa.version}</version>
             </dependency>
+
+            <!-- 个推 -->
+            <dependency>
+                <groupId>com.getui.push</groupId>
+                <artifactId>restful-sdk</artifactId>
+                <version>1.0.0.4</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 

+ 4 - 6
ruoyi-admin/src/main/java/com/ruoyi/web/controller/shop/order/ShopOrderCommentController.java

@@ -3,16 +3,14 @@ package com.ruoyi.web.controller.shop.order;
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.core.util.ObjectUtil;
 import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.core.validate.AddGroup;
-import com.ruoyi.common.core.validate.EditGroup;
 import com.ruoyi.common.core.validate.QueryGroup;
 import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.enums.FilePathSplicingType;
+import com.ruoyi.common.filepathsplicing.FilePathSplicing;
 import com.ruoyi.shop.order.domain.bo.ShopOrderCommentBo;
 import com.ruoyi.shop.order.domain.vo.ShopOrderCommentVo;
 import com.ruoyi.shop.order.service.IShopOrderCommentService;
@@ -23,11 +21,9 @@ import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import javax.servlet.http.HttpServletResponse;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * 订单评论Controller
@@ -47,6 +43,7 @@ public class ShopOrderCommentController extends BaseController {
     /**
      * 分页查询订单评论列表
      */
+    @FilePathSplicing(type = FilePathSplicingType.RESPONSE)
     @ApiOperation("查询订单评论列表")
     @SaCheckPermission("order:shopOrderComment:list")
     @GetMapping("/page")
@@ -58,6 +55,7 @@ public class ShopOrderCommentController extends BaseController {
     /**
      * 获取订单评论详细信息
      */
+    @FilePathSplicing(type = FilePathSplicingType.RESPONSE)
     @ApiOperation("获取订单评论详细信息")
     @GetMapping("/info/{commentId}")
     public R<ShopOrderCommentVo> getInfo(@ApiParam("主键")

+ 14 - 0
ruoyi-admin/src/main/resources/application-dev.yml

@@ -231,3 +231,17 @@ kuaidi:
   customer: FA0A0DCEF64D3439594AB122788A85D0
   secret: 43da2479c09e4586a28721c75ee57b06
   userId: 79d831c2dbac43dbab51528e1666a2d8
+
+# 个推
+getui:
+  baseUrl: https://restapi.getui.com/v2/
+  # 配置管理、应用配置中获取
+  appId: eADQzBtEi47oOX4l0TXw
+  appKey: 4uKDqSxC4d5jdTwBRHCTs8
+  appSecret: iGj6JOqsPp6UOQ8xyjpNe8
+  masterSecret: HSs1OFyUEp8wbWTCdGaNA1
+
+feixin:
+  appkey: j18Ldd
+  appsecret: h5TjYE
+  appcode: 1000

+ 4 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -366,6 +366,10 @@ aliyunsample:
 sms:
   redisKey: "vercode:key:"
   verCodeTm: 60
+  # 应用上架的手机号,验证码固定
+  appListing:
+    phone: 18688888888
+    code: 1024
 
 # 阿里云账号AK信息
 # 内容安全接口地址:https://green-cip.cn-shanghai.aliyuncs.com(47.116.84.226)

+ 28 - 16
ruoyi-api/src/main/java/com/ruoyi/api/controller/user/ApiUserLoginController.java

@@ -5,24 +5,22 @@ import cn.hutool.core.util.ObjectUtil;
 import com.ruoyi.api.controller.common.AbstractApiController;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.core.validate.RegGroup;
+import com.ruoyi.common.utils.push.GeTuiUtils;
+import com.ruoyi.common.utils.redis.RedisUtils;
 import com.ruoyi.framework.web.service.ApiTokenService;
-import com.ruoyi.shop.config.domain.ShopSaleConfig;
-import com.ruoyi.shop.config.service.IShopSaleConfigService;
-import com.ruoyi.shop.coupon.service.ICouponReceiveRecordService;
 import com.ruoyi.user.domain.User;
 import com.ruoyi.user.domain.bo.ThirdLoginBo;
 import com.ruoyi.user.domain.bo.ThirdRegisterBo;
-import com.ruoyi.user.domain.bo.UserIntegralRecordBo;
 import com.ruoyi.user.domain.bo.UserLoginBo;
 import com.ruoyi.user.domain.vo.UserLoginVo;
-import com.ruoyi.user.enums.IntegralSourceType;
-import com.ruoyi.user.service.IUserIntegralRecordService;
 import com.ruoyi.user.service.IUserService;
 import com.ruoyi.weixin.domain.WxUserDto;
 import com.ruoyi.weixin.service.WxUserService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -44,6 +42,7 @@ import java.util.Map;
 @RequiredArgsConstructor
 @RestController
 @RequestMapping("/api/miniapp/user")
+@Slf4j
 public class ApiUserLoginController extends AbstractApiController {
     @Autowired
     private IUserService userService;
@@ -53,11 +52,6 @@ public class ApiUserLoginController extends AbstractApiController {
 
     private final WxUserService wxUserService;
 
-    private final IUserIntegralRecordService userIntegralRecordService;
-
-    private final IShopSaleConfigService shopSaleConfigService;
-
-    private final ICouponReceiveRecordService couponReceiveRecordService;
     /**
      * 获取小程序openId
      */
@@ -105,7 +99,7 @@ public class ApiUserLoginController extends AbstractApiController {
         User user = userService.authorization(wxUserDto);
 
         HashMap<String, Object> result = new HashMap<>();
-        result.put("token", loginSuccess(user, true));
+        result.put("token", loginSuccess(user, true, null));
         return R.ok(result);
     }
 
@@ -116,7 +110,7 @@ public class ApiUserLoginController extends AbstractApiController {
     @PostMapping("/captcha")
     public R<UserLoginVo> loginByCaptcha(@Validated @RequestBody UserLoginBo bo) {
         UserLoginVo userLoginVo = userService.loginByCaptcha(bo);
-        userLoginVo.setToken(loginSuccess(userLoginVo.getUser(), userLoginVo.getIsReg()));
+        userLoginVo.setToken(loginSuccess(userLoginVo.getUser(), userLoginVo.getIsReg(), bo.getCid()));
         return R.ok(userLoginVo);
     }
 
@@ -127,7 +121,7 @@ public class ApiUserLoginController extends AbstractApiController {
     @PostMapping("/third")
     public R<UserLoginVo> loginByThird(@Validated @RequestBody ThirdLoginBo bo) {
         UserLoginVo userLoginVo = userService.loginByThird(bo);
-        userLoginVo.setToken(loginSuccess(userLoginVo.getUser(), false));
+        userLoginVo.setToken(loginSuccess(userLoginVo.getUser(), false, bo.getCid()));
         return R.ok(userLoginVo);
     }
 
@@ -138,11 +132,29 @@ public class ApiUserLoginController extends AbstractApiController {
     @PostMapping("/third/register")
     public R<UserLoginVo> registerByThird(@Validated @RequestBody ThirdRegisterBo bo) {
         UserLoginVo userLoginVo = userService.registerByThird(bo);
-        userLoginVo.setToken(loginSuccess(userLoginVo.getUser(), userLoginVo.getIsReg()));
+        userLoginVo.setToken(loginSuccess(userLoginVo.getUser(), userLoginVo.getIsReg(), bo.getCid()));
         return R.ok(userLoginVo);
     }
 
-    private String loginSuccess(User user, Boolean isReg) {
+    /**
+     * 退出登录
+     **/
+    @ApiOperation("退出登录")
+    @PostMapping("/logout")
+    public R<Void> logout() {
+        Long userId = getUserId(false);
+        if (ObjectUtil.isNotNull(userId)) {
+            RedisUtils.deleteObject(GeTuiUtils.getPushCid(String.valueOf(userId)));
+        }
+        return R.ok();
+    }
+
+    private String loginSuccess(User user, Boolean isReg, String cid) {
+//        //将unipush的客户端ID存入缓存
+        log.info(String.format("个推客户端ID:%s", cid));
+        if (StringUtils.isNotEmpty(cid)) {
+            RedisUtils.setCacheObject(GeTuiUtils.getPushCid(String.valueOf(user.getId())), cid);
+        }
         return apiTokenService.generateToken(user);
     }
 }

+ 6 - 0
ruoyi-common/pom.xml

@@ -261,6 +261,12 @@
             <groupId>com.auth0</groupId>
             <artifactId>jwks-rsa</artifactId>
         </dependency>
+
+        <!-- 个推 -->
+        <dependency>
+            <groupId>com.getui.push</groupId>
+            <artifactId>restful-sdk</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 5 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java

@@ -153,5 +153,10 @@ public interface Constants {
      *  默认维权天数3天
      */
     public static final Integer defaultRightsDays = 3;
+
+    /**
+     * 飞信短信 redis key
+     */
+    String FX_SMS_CAPTCHA_CODE_KEY = "fei_xin_captcha_code:";
 }
 

+ 58 - 0
ruoyi-common/src/main/java/com/ruoyi/common/properties/GeTuiConfig.java

@@ -0,0 +1,58 @@
+package com.ruoyi.common.properties;
+
+import com.getui.push.v2.sdk.ApiHelper;
+import com.getui.push.v2.sdk.GtApiConfiguration;
+import com.getui.push.v2.sdk.api.PushApi;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+/**
+ * 个推配置
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "getui")
+public class GeTuiConfig {
+    private String baseUrl;
+
+    private String appId;
+
+    private String appKey;
+
+    private String appSecret;
+
+    private String masterSecret;
+
+//    @Bean
+    public PushApi pushApi() {
+        GtApiConfiguration apiConfiguration = new GtApiConfiguration();
+        //填写应用配置
+        apiConfiguration.setAppId(appId);
+        apiConfiguration.setAppKey(appKey);
+        apiConfiguration.setMasterSecret(masterSecret);
+        // 接口调用前缀,请查看文档: 接口调用规范 -> 接口前缀, 可不填写appId
+        apiConfiguration.setDomain(baseUrl);
+        // 实例化ApiHelper对象,用于创建接口对象
+        ApiHelper apiHelper = ApiHelper.build(apiConfiguration);
+        // 创建对象,建议复用。目前有PushApi、StatisticApi、UserApi
+        PushApi pushApi = apiHelper.creatApi(PushApi.class);
+        return pushApi;
+    }
+
+    @Bean
+    public ApiHelper apiHelper() {
+        GtApiConfiguration apiConfiguration = new GtApiConfiguration();
+        //填写应用配置
+        apiConfiguration.setAppId(appId);
+        apiConfiguration.setAppKey(appKey);
+        apiConfiguration.setMasterSecret(masterSecret);
+        // 接口调用前缀,请查看文档: 接口调用规范 -> 接口前缀, 可不填写appId
+        apiConfiguration.setDomain(baseUrl);
+        // 实例化ApiHelper对象,用于创建接口对象
+        // 创建对象,建议复用。目前有PushApi、StatisticApi、UserApi
+        return ApiHelper.build(apiConfiguration);
+    }
+
+}

+ 144 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/SmsFeiXinUtil.java

@@ -0,0 +1,144 @@
+package com.ruoyi.common.utils;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.digest.MD5;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.redis.RedisUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Component
+public class SmsFeiXinUtil {
+
+    @Value("${feixin.appkey}")
+    private String appkey;
+
+    @Value("${feixin.appsecret}")
+    private String appsecret;
+
+    @Value("${feixin.appcode}")
+    private String appcode;
+
+    @Value("${sms.appListing.phone}")
+    private String appListingPhone;
+
+    @Value("${sms.appListing.code}")
+    private String appListingCode;
+
+    private String queryMoney = "http://api.feixinyun.com:9090/sms/balance/v1";
+
+    private String sendUrl = "http://api.feixinyun.com:9090/sms/batch/v1";
+
+    /**
+     * 生成sign
+     *
+     * @param timestamp
+     * @return
+     */
+    private String generateSign(String appkey, String appsecret, Long timestamp) {
+        return MD5.create().digestHex(appkey + appsecret + timestamp);
+    }
+
+    /**
+     * 获取账户余额
+     *
+     * @return
+     */
+    public Integer queryFeiXinMoney() {
+        long timestamp = System.currentTimeMillis();
+        Map<String, Object> params = new HashMap<>();
+        params.put("appkey", appkey);
+        params.put("appcode", appcode);
+        params.put("sign", generateSign(appkey, appsecret, timestamp));
+        params.put("timestamp", timestamp);
+        String resultStr = HttpUtil.get(queryMoney, params);
+
+        JSONObject resultJson = JSONObject.parseObject(resultStr);
+        String code = resultJson.getString("code");
+        if (StrUtil.isNotEmpty(code)) {
+            throw new ServiceException(resultJson.getString("desc"), 900001);
+        }
+        return resultJson.getInteger("balance");
+    }
+
+    /**
+     * 短信发送
+     *
+     * @return
+     */
+    public Boolean sendSmsCode(String phone, String code) {
+        long timestamp = System.currentTimeMillis();
+        JSONObject params = new JSONObject();
+        params.put("appkey", appkey);
+        params.put("appcode", appcode);
+        params.put("sign", generateSign(appkey, appsecret, timestamp));
+        params.put("timestamp", timestamp);
+        params.put("phone", phone);
+        String content = String.format("【宜格服务】验证码:%s,请尽快返回完成验证。如非本人使用,敬请忽略本信息。", code);
+        params.put("msg", content);
+        String resultStr = HttpUtil.post(sendUrl, params.toString());
+        System.out.println(" -----> " + resultStr);
+        JSONObject resultJson = JSONObject.parseObject(resultStr);
+        String resuldCode = resultJson.getString("code");
+        if (resuldCode.equals("00000")) {
+            return true;
+        }
+        throw new ServiceException(resultJson.getString("desc"), 90002);
+    }
+
+    /**
+     * 检验验证码是否正确
+     *
+     * @param phone
+     * @param codeOld
+     */
+    public void checkSmsCode(String phone, String codeOld) {
+        //return;
+        String code;
+        //如果手机号是18688888888,则验证码是1024
+        if (appListingPhone.equals(phone)) {
+            code = appListingCode;
+        } else {
+            //获取验证码
+            code = RedisUtils.getCacheObject(Constants.FX_SMS_CAPTCHA_CODE_KEY + phone);
+        }
+
+        if (StrUtil.isEmpty(code)) {
+            throw new ServiceException("验证码已过期");
+        } else {
+            if (!code.equals(codeOld)) {
+                throw new ServiceException("验证码不正确");
+            }
+        }
+    }
+
+    public static void main(String[] args) {
+        String appkey = "j18Ldd";
+        String appcode = "1000";
+        String appsecret = "h5TjYE";
+        String phone = "15014059100";
+        String code = "9999";
+        String content = String.format("【宜格服务】验证码:%s,请尽快返回完成验证。如非本人使用,敬请忽略本信息。", code);
+        String sendUrl = "http://api.feixinyun.com:9090/sms/batch/v1";
+        long timestamp = System.currentTimeMillis();
+
+        JSONObject params = new JSONObject();
+        params.put("appkey", appkey);
+        params.put("appcode", appcode);
+        params.put("sign", MD5.create().digestHex(appkey + appsecret + timestamp));
+        params.put("timestamp", timestamp);
+        params.put("phone", phone);
+        params.put("msg", content);
+        String resultStr = HttpUtil.post(sendUrl, params.toString());
+        System.out.println(" -----> " + resultStr);
+    }
+
+}

+ 22 - 2
ruoyi-common/src/main/java/com/ruoyi/common/utils/SmsSend.java

@@ -21,6 +21,15 @@ public class SmsSend {
     @Resource
     private Sample sample;
 
+    @Resource
+    private SmsFeiXinUtil smsFeiXinUtil;
+
+    @Value("${sms.appListing.phone}")
+    private String appListingPhone;
+
+    @Value("${sms.appListing.code}")
+    private String appListingCode;
+
     @Value("${sms.redisKey}")
     private String redisKey;  //验证码缓存KEY
 
@@ -38,6 +47,9 @@ public class SmsSend {
             String code = RandomStringUtils.randomNumeric(4);
             String mode = sendSmsCodeMode();
             switch (mode) {
+                case "0":
+                    smsFeiXinUtil.sendSmsCode(phone, code);
+                    break;
                 case "1":
                     sample.sendCode(phone, code);
                     break;
@@ -57,7 +69,15 @@ public class SmsSend {
      */
     public void check(String phone, String checkCode) {
         if (openSmsCode()) {
-            String code = RedisUtils.getCacheObject(redisKey + phone);
+            String code;
+            //如果手机号是18688888888,则验证码是1024
+            if (appListingPhone.equals(phone)) {
+                code = appListingCode;
+            } else {
+                //获取验证码
+                code = RedisUtils.getCacheObject(redisKey + phone);
+            }
+
             if (StrUtil.isEmpty(code)) {
                 throw new ServiceException("手机验证码已过期");
             } else {
@@ -91,7 +111,7 @@ public class SmsSend {
     private String sendSmsCodeMode() {
         String mode = RedisUtils.getCacheObject(Constants.SYS_CONFIG_KEY + "send:sms:code:mode");
         if (StringUtils.isEmpty(mode)) {
-            return "1";
+            return "0";
         }
         return mode;
     }

+ 251 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/push/GeTuiUtils.java

@@ -0,0 +1,251 @@
+package com.ruoyi.common.utils.push;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.getui.push.v2.sdk.ApiHelper;
+import com.getui.push.v2.sdk.api.PushApi;
+import com.getui.push.v2.sdk.api.UserApi;
+import com.getui.push.v2.sdk.common.ApiResult;
+import com.getui.push.v2.sdk.dto.req.Audience;
+import com.getui.push.v2.sdk.dto.req.AudienceDTO;
+import com.getui.push.v2.sdk.dto.req.Settings;
+import com.getui.push.v2.sdk.dto.req.Strategy;
+import com.getui.push.v2.sdk.dto.req.message.PushChannel;
+import com.getui.push.v2.sdk.dto.req.message.PushDTO;
+import com.getui.push.v2.sdk.dto.req.message.PushMessage;
+import com.getui.push.v2.sdk.dto.req.message.android.AndroidDTO;
+import com.getui.push.v2.sdk.dto.req.message.android.ThirdNotification;
+import com.getui.push.v2.sdk.dto.req.message.android.Ups;
+import com.getui.push.v2.sdk.dto.req.message.ios.Alert;
+import com.getui.push.v2.sdk.dto.req.message.ios.Aps;
+import com.getui.push.v2.sdk.dto.req.message.ios.IosDTO;
+import com.getui.push.v2.sdk.dto.res.CidStatusDTO;
+import com.getui.push.v2.sdk.dto.res.TaskIdDTO;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.ruoyi.common.utils.ClassConvertUtils;
+import com.ruoyi.common.utils.redis.RedisUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author wuchao
+ */
+@Slf4j
+@Component
+public class GeTuiUtils {
+
+    private PushApi pushApi;
+    private UserApi userApi;
+
+    public GeTuiUtils(ApiHelper apiHelper) {
+        pushApi = apiHelper.creatApi(PushApi.class);
+        userApi = apiHelper.creatApi(UserApi.class);
+    }
+
+    public boolean pushToSingleByCid(Msg msg) {
+        PushDTO<Audience> pushDTO = this.buildPushDTO(msg);
+        // 设置接收人信息
+        Audience audience = new Audience();
+        pushDTO.setAudience(audience);
+        audience.addCid(msg.getCid());// cid
+        // 进行cid单推
+        ApiResult<Map<String, Map<String, String>>> apiResult = pushApi.pushToSingleByCid(pushDTO);
+        //successed_offline: 离线下发(包含厂商通道下发),successed_online: 在线下发,successed_ignore: 最近90天内不活跃用户不下发
+        log.info(String.format("单推[%s],返回结果:%s", apiResult.getMsg(), apiResult.getData()));
+        return apiResult.isSuccess();
+    }
+
+    /**
+     * cid批量推
+     *
+     * @param msg
+     */
+    public boolean pushListByCid(Msg msg) {
+        //批量发送
+        AudienceDTO audienceDTO = new AudienceDTO();
+        PushDTO<Audience> pushDTO = this.buildPushDTO(msg);
+
+        ApiResult<TaskIdDTO> createApiResult = pushApi.createMsg(pushDTO);
+        if (!createApiResult.isSuccess()) {
+            log.error("推送:创建消息失败:" + createApiResult.getMsg());
+            return false;
+        }
+        // 设置接收人信息
+        Audience audience = new Audience();
+        pushDTO.setAudience(audience);
+        audience.setCid(msg.getCidList());
+
+        audienceDTO.setAudience(audience);
+        audienceDTO.setTaskid(createApiResult.getData().getTaskId());
+        audienceDTO.setAsync(true);
+
+        ApiResult<Map<String, Map<String, String>>> apiResult = pushApi.pushListByCid(audienceDTO);
+        log.info(String.format("批量推[%s],返回结果:%s", apiResult.getMsg(), apiResult.getData()));
+        return apiResult.isSuccess();
+    }
+
+    private PushDTO<Audience> buildPushDTO(Msg msg) {
+        PushDTO<Audience> pushDTO = new PushDTO<>();
+        //前端接收的消息
+        Map<String, Object> map = new HashMap<>();
+        map.put("title", msg.getTitle());
+        map.put("content", msg.getContent());
+        map.put("payload", msg.getMsg());
+        String payload = ClassConvertUtils.transformJSONToSnake(map);
+
+        // 设置推送参数
+        //requestid需要每次变化唯一
+        pushDTO.setRequestId(System.currentTimeMillis() + "");
+        pushDTO.setGroupName("wxb-group");
+
+        //配置推送条件
+        // 1: 表示该消息在用户在线时推送个推通道,用户离线时推送厂商通道;
+        // 2: 表示该消息只通过厂商通道策略下发,不考虑用户是否在线;
+        // 3: 表示该消息只通过个推通道下发,不考虑用户是否在线;
+        // 4: 表示该消息优先从厂商通道下发,若消息内容在厂商通道代发失败后会从个推通道下发。
+        Strategy strategy = new Strategy();
+        strategy.setDef(1);
+        strategy.setSt(1);
+        Settings settings = new Settings();
+        settings.setStrategy(strategy);
+        pushDTO.setSettings(settings);
+        //消息有效期,走厂商消息需要设置该值
+        settings.setTtl(3600000);
+
+        //推送苹果离线通知标题内容
+        Alert alert = new Alert();
+        //苹果离线通知栏标题
+        alert.setTitle(msg.getTitle());
+        //苹果离线通知栏内容
+        alert.setBody(msg.getContent());
+        Aps aps = new Aps();
+        //1表示静默推送(无通知栏消息),静默推送时不需要填写其他参数。
+        //苹果建议1小时最多推送3条静默消息
+        aps.setContentAvailable(0);
+        aps.setSound("default");
+        aps.setAlert(alert);
+        IosDTO iosDTO = new IosDTO();
+        iosDTO.setAps(aps);
+        iosDTO.setType("notify");
+        iosDTO.setPayload(payload);
+        PushChannel pushChannel = new PushChannel();
+        pushChannel.setIos(iosDTO);
+        //安卓离线厂商通道推送消息体
+        AndroidDTO androidDTO = new AndroidDTO();
+        Ups ups = new Ups();
+        ThirdNotification notification1 = new ThirdNotification();
+        ups.setNotification(notification1);
+        //安卓离线展示的标题
+        notification1.setTitle(msg.getTitle());
+        //安卓离线展示的内容
+        notification1.setBody(msg.getContent());
+        notification1.setClickType("intent");
+        notification1.setIntent("intent:#Intent;action=android.intent.action.oppopush;launchFlags=0x14000000;component=com.weixiaobao/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title=" + msg.getTitle() + ";S.content=" + msg.getContent() + ";S.payload=" + msg.getMsg() + ";end");
+        //各厂商自有功能单项设置
+        //ups.addOption("HW", "/message/android/notification/badge/class", "io.dcloud.PandoraEntry ");
+        //ups.addOption("HW", "/message/android/notification/badge/add_num", 1);
+        //ups.addOption("HW", "/message/android/notification/importance", "HIGH");
+        //ups.addOption("VV","classification",1);
+        androidDTO.setUps(ups);
+        pushChannel.setAndroid(androidDTO);
+        pushDTO.setPushChannel(pushChannel);
+
+        // PushMessage在线走个推通道才会起作用的消息体
+        PushMessage pushMessage = new PushMessage();
+        pushDTO.setPushMessage(pushMessage);
+        pushMessage.setTransmission(payload);
+        return pushDTO;
+    }
+
+    /**
+     * 单推
+     *
+     * @param msg
+     * @return
+     */
+    public void pushByUserId(Msg msg) {
+        try {
+            if (ObjectUtils.isEmpty(msg.getUid())) {
+                log.error("用户ID不能为空");
+                return;
+            }
+            //获取Push客户端ID:6a67d611f29e233492223e2de4d7a0c7
+            String clientId = RedisUtils.getCacheObject(getPushCid(String.valueOf(msg.getUid())));
+            if (StringUtils.isEmpty(clientId)) {
+                log.error("客户端ID没有获取到");
+                return;
+            }
+            msg.setCid(clientId);
+            //单推
+            this.pushToSingleByCid(msg);
+        } catch (Exception e) {
+            log.error("单推异常");
+        }
+    }
+
+    /**
+     * 批量推
+     *
+     * @param msg
+     * @return
+     */
+    public void pushByUserIds(Msg msg) {
+        try {
+            if (CollectionUtils.isEmpty(msg.getUidList())) {
+                log.error("用户ID不能为空");
+                return;
+            }
+            List<String> cidList = new ArrayList<>();
+            msg.getUidList().forEach(u -> {
+                //获取Push客户端ID:6a67d611f29e233492223e2de4d7a0c7
+                String clientId = RedisUtils.getCacheObject(getPushCid(String.valueOf(u)));
+                //去重
+                if (!StringUtils.isEmpty(clientId) && !cidList.contains(clientId)) {
+                    cidList.add(clientId);
+                }
+            });
+
+            if (CollectionUtils.isEmpty(cidList)) {
+                log.error("客户端ID没有获取到");
+                return;
+            }
+
+            if (cidList.size() > 0) {
+                //按每200个一组分割
+                List<List<String>> parts = Lists.partition(cidList, 200);
+                parts.forEach(list -> {
+                    msg.setCidList(list);
+                    //批量推
+                    this.pushListByCid(msg);
+                });
+            }
+
+        } catch (Exception e) {
+            log.error("批量推异常");
+        }
+    }
+
+    /**
+     * 查询用户状态
+     *
+     * @param cid 客户端标识
+     */
+    public void queryUserStatus(String cid) {
+        ApiResult<Map<String, CidStatusDTO>> mapApiResult = userApi.queryUserStatus(Sets.newHashSet(cid));
+        log.info(String.format("用户状态:%s", mapApiResult));//online在线 offline离线
+    }
+
+    /**
+     * 个推客户端ID
+     **/
+    public static String getPushCid(String key) {
+        return "push:cid:" + key;
+    }
+}

+ 52 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/push/Msg.java

@@ -0,0 +1,52 @@
+package com.ruoyi.common.utils.push;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Data
+public class Msg {
+
+    /**
+     * 单推
+     */
+    private String cid;
+
+    /**
+     * 批量推
+     */
+    private List<String> cidList;
+
+    /**
+     * 用户ID
+     */
+    private Long uid;
+
+    /**
+     * 用户ID
+     */
+    private List<Long> uidList;
+
+    /**
+     * 标题
+     */
+    private String title;
+
+    /**
+     * 内容
+     */
+    private String content;
+
+    /**
+     * 消息
+     */
+    private Object msg;
+
+    private int type;
+}

+ 4 - 0
ruoyi-shop/src/main/java/com/ruoyi/shop/order/domain/ShopOrderComment.java

@@ -35,6 +35,10 @@ public class ShopOrderComment implements Serializable {
      * 订单ID
      */
     private Long orderId;
+    /**
+     * 订单详情ID
+     */
+    private Long orderDetailId;
     /**
      * 订单编号
      */

+ 0 - 1
ruoyi-shop/src/main/java/com/ruoyi/shop/order/domain/bo/ShopOrderCommentBo.java

@@ -82,7 +82,6 @@ public class ShopOrderCommentBo extends BaseEntity {
      * 用户ID
      */
     @ApiModelProperty(value = "用户ID", required = true)
-    @NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long userId;
 
     /**

+ 5 - 0
ruoyi-shop/src/main/java/com/ruoyi/shop/order/domain/vo/ShopOrderCommentVo.java

@@ -44,6 +44,11 @@ public class ShopOrderCommentVo implements Serializable {
     @ApiModelProperty("订单ID")
     private Long orderId;
 
+    /**
+     * 订单详情ID
+     */
+    private Long orderDetailId;
+
     /**
      * 商家id
      */

+ 2 - 0
ruoyi-shop/src/main/java/com/ruoyi/shop/order/service/impl/ShopOrderCommentServiceImpl.java

@@ -168,6 +168,7 @@ public class ShopOrderCommentServiceImpl implements IShopOrderCommentService {
         UserVo user = iUserService.getUserById(bo.getUserId(), true);
         ShopOrderComment shopOrderComment = new ShopOrderComment();
         shopOrderComment.setOrderId(shopOrderDetail.getOrderId());
+        shopOrderComment.setOrderDetailId(shopOrderDetail.getOrderDetailId());
         shopOrderComment.setOrderNo(shopOrderDetail.getOrderNo());
         shopOrderComment.setProductId(shopOrderDetail.getProductId());
         shopOrderComment.setBusinessId(shopOrderDetail.getBusinessId());
@@ -232,6 +233,7 @@ public class ShopOrderCommentServiceImpl implements IShopOrderCommentService {
         UserVo user = iUserService.getUserById(order.getUserId(), false);
         ShopOrderComment shopOrderComment = new ShopOrderComment();
         shopOrderComment.setOrderId(shopOrderDetail.getOrderId());
+        shopOrderComment.setOrderDetailId(shopOrderDetail.getOrderDetailId());
         shopOrderComment.setOrderNo(shopOrderDetail.getOrderNo());
         shopOrderComment.setProductId(shopOrderDetail.getProductId());
         shopOrderComment.setProductTitle(shopOrderDetail.getProductTitle());

+ 2 - 0
ruoyi-shop/src/main/resources/mapper/order/ShopOrderCommentMapper.xml

@@ -7,6 +7,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="com.ruoyi.shop.order.domain.ShopOrderComment" id="ShopOrderCommentResult">
         <result property="commentId" column="comment_id"/>
         <result property="orderId" column="order_id"/>
+        <result property="orderDetailId" column="order_detail_id"/>
         <result property="orderNo" column="order_no"/>
         <result property="businessId" column="business_id"/>
         <result property="productId" column="product_id"/>
@@ -25,6 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="com.ruoyi.shop.order.domain.vo.ShopOrderCommentVo" id="ShopOrderCommentResultVo">
         <result property="commentId" column="comment_id"/>
         <result property="orderId" column="order_id"/>
+        <result property="orderDetailId" column="order_detail_id"/>
         <result property="orderNo" column="order_no"/>
         <result property="productId" column="product_id"/>
         <result property="productTitle" column="product_title"/>

+ 6 - 0
ruoyi-user/src/main/java/com/ruoyi/user/domain/bo/ThirdLoginBo.java

@@ -23,4 +23,10 @@ public class ThirdLoginBo implements Serializable {
     @ApiModelProperty(value = "第三方code", required = true)
     @NotBlank(message = "第三方code不能为空")
     private String code;
+
+    /**
+     * unipush的客户端ID,这个id定位了你的手机
+     */
+    @ApiModelProperty(value = "unipush的客户端ID")
+    private String cid;
 }

+ 6 - 0
ruoyi-user/src/main/java/com/ruoyi/user/domain/bo/ThirdRegisterBo.java

@@ -37,4 +37,10 @@ public class ThirdRegisterBo implements Serializable {
     @ApiModelProperty(value = "标识码", required = true)
     @NotBlank(message = "标识码不能为空")
     private String identityCode;
+
+    /**
+     * unipush的客户端ID,这个id定位了你的手机
+     */
+    @ApiModelProperty(value = "unipush的客户端ID")
+    private String cid;
 }

+ 6 - 0
ruoyi-user/src/main/java/com/ruoyi/user/domain/bo/UserLoginBo.java

@@ -22,4 +22,10 @@ public class UserLoginBo implements Serializable {
      */
     @ApiModelProperty(value = "验证码")
     private String captcha;
+
+    /**
+     * unipush的客户端ID,这个id定位了你的手机
+     */
+    @ApiModelProperty(value = "unipush的客户端ID")
+    private String cid;
 }