he2802 3 năm trước cách đây
mục cha
commit
0bc42a1eae

+ 14 - 8
zhongzheng-api/src/main/java/com/zhongzheng/controller/course/CourseController.java

@@ -7,14 +7,8 @@ import com.zhongzheng.common.core.page.TableDataInfo;
 import com.zhongzheng.common.enums.BusinessType;
 import com.zhongzheng.common.utils.ServletUtils;
 import com.zhongzheng.framework.web.service.WxTokenService;
-import com.zhongzheng.modules.course.bo.CourseAddBo;
-import com.zhongzheng.modules.course.bo.CourseEditBo;
-import com.zhongzheng.modules.course.bo.CourseMenuQueryBo;
-import com.zhongzheng.modules.course.bo.CourseQueryBo;
-import com.zhongzheng.modules.course.service.ICourseChapterSectionService;
-import com.zhongzheng.modules.course.service.ICourseMenuService;
-import com.zhongzheng.modules.course.service.ICourseModuleChapterService;
-import com.zhongzheng.modules.course.service.ICourseService;
+import com.zhongzheng.modules.course.bo.*;
+import com.zhongzheng.modules.course.service.*;
 import com.zhongzheng.modules.course.vo.*;
 import com.zhongzheng.modules.goods.vo.GoodsUserVo;
 import com.zhongzheng.modules.goods.vo.GoodsVo;
@@ -45,6 +39,7 @@ public class CourseController extends BaseController {
     private final ICourseModuleChapterService iCourseModuleChapterService;
     private final ICourseMenuService iCourseMenuService;
     private final ICourseChapterSectionService iCourseChapterSectionService;
+    private final ICourseSectionWatchPerService iCourseSectionWatchPerService;
 
     /**
      * 查询课程列表
@@ -124,5 +119,16 @@ public class CourseController extends BaseController {
         return AjaxResult.success(list);
     }
 
+    /**
+     * 课程节观看权限校验
+     */
+    @ApiOperation("课程节观看权限校验")
+    @GetMapping("/check/watch/per")
+    public AjaxResult<CheckSectionWatchVo> checkSectionWatchPer(SectionWatchQueryBo bo) {
+        ClientLoginUser loginUser = wxTokenService.getLoginUser(ServletUtils.getRequest());
+        bo.setUserId(loginUser.getUser().getUserId());
+        CheckSectionWatchVo vo = iCourseSectionWatchPerService.checkSectionWatchPer(bo);
+        return AjaxResult.success(vo);
+    }
 
 }

+ 16 - 0
zhongzheng-common/src/main/java/com/zhongzheng/common/utils/http/HttpUtils.java

@@ -12,6 +12,7 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
 
+import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson.JSONObject;
 import org.apache.http.Consts;
 import org.apache.http.Header;
@@ -34,6 +35,7 @@ import org.apache.http.util.EntityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.http.HttpEntity;
+import sun.misc.BASE64Encoder;
 
 
 /**
@@ -140,6 +142,20 @@ public class HttpUtils
             post.addHeader("content-type", "application/json");
             HttpResponse res = client.execute(post);
             if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                if (res.getEntity().getContentType().getValue().equalsIgnoreCase("image/jpeg")) {
+                    InputStream inputStream = res.getEntity().getContent();
+                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+                    byte[] buffer = new byte[1024];
+                    int len = 0;
+                    while ((len = inputStream.read(buffer)) != -1){
+                        outputStream.write(buffer, 0, len);
+                    }
+                    inputStream.close();
+                    java.util.Base64.Encoder encoder1 = java.util.Base64.getEncoder();
+                    String encoder = "data:image/jpeg;base64,"
+                            + encoder1.encodeToString(outputStream.toByteArray());
+                    return encoder;
+                }
                 String result = EntityUtils.toString(res.getEntity());// 返回json格式
                 System.out.println("推送成功" + result);
                 return result;

+ 150 - 108
zhongzheng-framework/src/main/java/com/zhongzheng/framework/web/service/WxLoginService.java

@@ -2,6 +2,7 @@ package com.zhongzheng.framework.web.service;
 
 
 import cn.hutool.core.lang.Validator;
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
@@ -20,7 +21,9 @@ import com.zhongzheng.common.utils.*;
 import com.zhongzheng.common.utils.http.HttpUtils;
 import com.zhongzheng.common.utils.ip.IpUtils;
 import com.zhongzheng.modules.alisms.service.IAliSmsService;
+import com.zhongzheng.modules.course.bo.SectionWatchPerBo;
 import com.zhongzheng.modules.course.domain.CourseMenu;
+import com.zhongzheng.modules.course.domain.CourseSectionWatchPer;
 import com.zhongzheng.modules.course.mapper.CourseSectionMapper;
 import com.zhongzheng.modules.user.bo.UserAddBo;
 import com.zhongzheng.modules.user.bo.UserWxFollowAddBo;
@@ -64,8 +67,7 @@ import java.util.concurrent.TimeUnit;
  * @author zhongzheng
  */
 @Component
-public class WxLoginService implements IWxLoginService
-{
+public class WxLoginService implements IWxLoginService {
     private static final Logger log = LoggerFactory.getLogger(WxLoginService.class);
 
     @Autowired
@@ -117,6 +119,10 @@ public class WxLoginService implements IWxLoginService
 
     private String small_wxSendTpParam = "access_token=%s";
 
+    private String small_wxEnCodeUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit";
+
+    private String small_wxEnCodeParam = "access_token=%s";
+
     @Autowired
     private IUserService iUserService;
 
@@ -133,23 +139,23 @@ public class WxLoginService implements IWxLoginService
     private IUserWxFollowService iUserWxFollowService;
 
 
-    public Map<String,String> test_login() {
+    public Map<String, String> test_login() {
         String unionId = "oQ2yp56PgQ-PfwN4vxTZhR5eTpzk";
         User user = iUserService.queryByUnionId(unionId);
         ClientLoginUser loginUser = new ClientLoginUser();
         loginUser.setUser(user);
 
-        Map<String,String> map = new HashMap<>();
-        map.put(Constants.TOKEN,wxTokenService.createToken(loginUser));
-        map.put("union_id",loginUser.getUser().getUnionId());
+        Map<String, String> map = new HashMap<>();
+        map.put(Constants.TOKEN, wxTokenService.createToken(loginUser));
+        map.put("union_id", loginUser.getUser().getUnionId());
         return map;
     }
 
-    public Map<String,Object> pcLoginUrl(){
+    public Map<String, Object> pcLoginUrl() {
         String scanCode = ToolsUtils.getCharAndNumr(6);
-        String key = "SCAN_LOGIN_"+scanCode;
-        String keyStatus = "SCAN_LOGIN_STATUS_"+scanCode; //0未扫码 1已扫码 2已登录
-        String codeUrl = scanLoginHost+"pc/login/"+scanCode;
+        String key = "SCAN_LOGIN_" + scanCode;
+        String keyStatus = "SCAN_LOGIN_STATUS_" + scanCode; //0未扫码 1已扫码 2已登录
+        String codeUrl = scanLoginHost + "pc/login/" + scanCode;
         String urlBase64 = null;
         try {
             QRCodeWriter qrCodeWriter = new QRCodeWriter();
@@ -164,90 +170,89 @@ public class WxLoginService implements IWxLoginService
         } catch (Exception e) {
             e.printStackTrace();
         }
-        redisCache.setCacheObject(key, 0L,180, TimeUnit.SECONDS);//180秒锁定
-        redisCache.setCacheObject(keyStatus, 0L,180, TimeUnit.SECONDS);//180秒锁定
-        Map<String,Object> map = new HashMap<>();
-        map.put("scanCode",scanCode);
-        map.put("urlBase64",urlBase64);
-        return  map;
+        redisCache.setCacheObject(key, 0L, 180, TimeUnit.SECONDS);//180秒锁定
+        redisCache.setCacheObject(keyStatus, 0L, 180, TimeUnit.SECONDS);//180秒锁定
+        Map<String, Object> map = new HashMap<>();
+        map.put("scanCode", scanCode);
+        map.put("urlBase64", urlBase64);
+        return map;
     }
 
     /**
      * PC检查是否小程序登录成功
+     *
      * @param scanCode
      * @return
      */
-    public Map<String,Object> checkPcLogin(String scanCode) {
-        String key = "SCAN_LOGIN_"+scanCode;
-        String keyStatus = "SCAN_LOGIN_STATUS_"+scanCode; //0未扫码 1已扫码 2已登录
+    public Map<String, Object> checkPcLogin(String scanCode) {
+        String key = "SCAN_LOGIN_" + scanCode;
+        String keyStatus = "SCAN_LOGIN_STATUS_" + scanCode; //0未扫码 1已扫码 2已登录
         Long userId = redisCache.getCacheObject(key);
         Long status = redisCache.getCacheObject(keyStatus);
-        if(Validator.isNotEmpty(status)&&status.equals(1L)){
+        if (Validator.isNotEmpty(status) && status.equals(1L)) {
             throw new CustomException("小程序已扫码");
-        }
-        else if(Validator.isNotEmpty(status)&&status.equals(2L)){
+        } else if (Validator.isNotEmpty(status) && status.equals(2L)) {
             User user = iUserService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserId, userId).last("limit 1"));
-            if(Validator.isEmpty(user)){
+            if (Validator.isEmpty(user)) {
                 throw new CustomException("暂未登录");
             }
             ClientLoginUser loginUser = new ClientLoginUser();
             loginUser.setUser(user);
-            Map<String,Object> map = new HashMap<>();
-            map.put(Constants.TOKEN,wxTokenService.createToken(loginUser));
-            map.put("user_account",loginUser.getUser().getUserAccount());
-            map.put("full_info",Validator.isEmpty(user.getIdCard())?false:true); //是否完善身份信息
+            Map<String, Object> map = new HashMap<>();
+            map.put(Constants.TOKEN, wxTokenService.createToken(loginUser));
+            map.put("user_account", loginUser.getUser().getUserAccount());
+            map.put("full_info", Validator.isEmpty(user.getIdCard()) ? false : true); //是否完善身份信息
             return map;
-        }
-        else{
+        } else {
             throw new CustomException("暂未登录");
         }
     }
 
     @Transactional(rollbackFor = Exception.class)
-    public Map<String,Object> login(WxLoginBody loginBody) {
+    public Map<String, Object> login(WxLoginBody loginBody) {
         User user = getWxUnionIdUser(loginBody);
-        if(user==null){
+        if (user == null) {
             throw new CustomException("登录错误");
         }
         ClientLoginUser loginUser = new ClientLoginUser();
         loginUser.setUser(user);
-        Map<String,Object> map = new HashMap<>();
-        map.put(Constants.TOKEN,wxTokenService.createToken(loginUser));
-        map.put("user_account",loginUser.getUser().getUserAccount());
-        map.put("full_info",Validator.isEmpty(user.getIdCard())?false:true); //是否完善身份信息
+        Map<String, Object> map = new HashMap<>();
+        map.put(Constants.TOKEN, wxTokenService.createToken(loginUser));
+        map.put("user_account", loginUser.getUser().getUserAccount());
+        map.put("full_info", Validator.isEmpty(user.getIdCard()) ? false : true); //是否完善身份信息
         return map;
     }
 
 
-    public Map<String,String> smallTel(WxLoginBody loginBody) {
+    public Map<String, String> smallTel(WxLoginBody loginBody) {
         User user = getWxUnionIdUser(loginBody);
-        if(user==null){
+        if (user == null) {
             throw new CustomException("登录错误");
         }
         ClientLoginUser loginUser = new ClientLoginUser();
         loginUser.setUser(user);
-        Map<String,String> map = new HashMap<>();
-        map.put(Constants.TOKEN,wxTokenService.createToken(loginUser));
-        map.put("union_id",loginUser.getUser().getUnionId());
+        Map<String, String> map = new HashMap<>();
+        map.put(Constants.TOKEN, wxTokenService.createToken(loginUser));
+        map.put("union_id", loginUser.getUser().getUnionId());
         return map;
     }
 
-    public Map<String,String> gzh_login(WxLoginBody loginBody) {
+    public Map<String, String> gzh_login(WxLoginBody loginBody) {
         User user = getWxGzhUnionIdUser(loginBody);
-        if(user==null){
+        if (user == null) {
             throw new CustomException("登录错误");
         }
         ClientLoginUser loginUser = new ClientLoginUser();
         loginUser.setUser(user);
-        Map<String,String> map = new HashMap<>();
-        map.put(Constants.TOKEN,wxTokenService.createToken(loginUser));
-        map.put("union_id",loginUser.getUser().getUnionId());
+        Map<String, String> map = new HashMap<>();
+        map.put(Constants.TOKEN, wxTokenService.createToken(loginUser));
+        map.put("union_id", loginUser.getUser().getUnionId());
         return map;
     }
 
     public String refreshToken(String userAccount) {
         User user = iUserService.queryByAccount(userAccount);
-        if(user==null){
+        if (user == null) {
             throw new CustomException("userAccount不存在");
         }
         user.setLastLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
@@ -260,12 +265,13 @@ public class WxLoginService implements IWxLoginService
 
     /**
      * 小程序注册
+     *
      * @param openId
      * @param unionId
      * @param tel
      * @return
      */
-    public Boolean register_small(String openId,String unionId,String tel,String inviteCode) {
+    public Boolean register_small(String openId, String unionId, String tel, String inviteCode) {
         User bo = new User();
         bo.setOpenId(openId);
         bo.setUnionId(unionId);
@@ -283,21 +289,22 @@ public class WxLoginService implements IWxLoginService
         bo.setLastLoginTime(DateUtils.getNowTime());
         bo.setCreateTime(DateUtils.getNowTime());
         bo.setUpdateTime(DateUtils.getNowTime());
-        String pwd =  ToolsUtils.getSmsCode(); // 随机密码
+        String pwd = ToolsUtils.getSmsCode(); // 随机密码
         bo.setPassword(SecurityUtils.encryptPassword(pwd));
-        if(inviteCode!=null){
+        if (inviteCode != null) {
             User inviteUser = iUserService.queryByAccount(inviteCode);
-            if(inviteUser!=null){
+            if (inviteUser != null) {
                 bo.setInviteUserAccount(inviteCode);
             }
         }
-        if(iUserService.save(bo)){
-            iSmsService.sendPwdSms(bo.getTelphone(),pwd);
+        if (iUserService.save(bo)) {
+            iSmsService.sendPwdSms(bo.getTelphone(), pwd);
         }
         return true;
     }
+
     //小程序获取用户openid
-    public String getWxOpenId(WxLoginBody loginBody,Long userId) {
+    public String getWxOpenId(WxLoginBody loginBody, Long userId) {
         LambdaQueryWrapper<User> lqw = Wrappers.lambdaQuery();
         lqw.eq(User::getUserId, userId);
         User user = iUserService.getOne(lqw);
@@ -305,7 +312,7 @@ public class WxLoginService implements IWxLoginService
 
         //每次更新最新openid
         String param = String.format(wxAuthParam, appid, appsrcret, loginBody.getCode());
-        String resultString  = HttpUtils.sendGet(wxAuthUrl,param);
+        String resultString = HttpUtils.sendGet(wxAuthUrl, param);
         //解析json
         JSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);
         String session_key = String.valueOf(jsonObject.get("session_key"));
@@ -319,32 +326,32 @@ public class WxLoginService implements IWxLoginService
     //小程序获取用户信息
     public User getWxUnionIdUser(WxLoginBody loginBody) {
         String param = String.format(wxAuthParam, appid, appsrcret, loginBody.getCode());
-        String resultString  = HttpUtils.sendGet(wxAuthUrl,param);
+        String resultString = HttpUtils.sendGet(wxAuthUrl, param);
         //解析json
         JSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);
         String session_key = String.valueOf(jsonObject.get("session_key"));
         String openId = String.valueOf(jsonObject.get("openid"));
         String unionId = null;
-        if(jsonObject.containsKey("unionid")){ //当没绑定开放平台
+        if (jsonObject.containsKey("unionid")) { //当没绑定开放平台
             unionId = String.valueOf(jsonObject.get("unionid"));
         }
-        String phoneNumber = obtainWxPhone(loginBody.getIv(),loginBody.getEncryptedData(),session_key);
-        if(Validator.isEmpty(phoneNumber)){
-            throw new CustomException("该微信没有绑定手机号码"+resultString);
+        String phoneNumber = obtainWxPhone(loginBody.getIv(), loginBody.getEncryptedData(), session_key);
+        if (Validator.isEmpty(phoneNumber)) {
+            throw new CustomException("该微信没有绑定手机号码" + resultString);
         }
         User user = iUserService.getOne(new LambdaQueryWrapper<User>()
-                .eq(User::getTelphone,phoneNumber).last("limit 1"));
-        if(Validator.isNotEmpty(user)){
+                .eq(User::getTelphone, phoneNumber).last("limit 1"));
+        if (Validator.isNotEmpty(user)) {
             user.setOpenId(openId);
             user.setUnionId(unionId);
             user.setLastLoginTime(DateUtils.getNowTime());
             user.setUpdateTime(DateUtils.getNowTime());
             iUserService.updateById(user);
-        }else{
+        } else {
             //手机匹配不上再匹配openid
             user = iUserService.getOne(new LambdaQueryWrapper<User>()
-                    .eq(User::getOpenId,openId).last("limit 1"));
-            if(Validator.isNotEmpty(user)){
+                    .eq(User::getOpenId, openId).last("limit 1"));
+            if (Validator.isNotEmpty(user)) {
                 user.setTelphone(phoneNumber);
                 user.setUnionId(unionId);
                 user.setUpdateTime(DateUtils.getNowTime());
@@ -352,12 +359,12 @@ public class WxLoginService implements IWxLoginService
                 iUserService.updateById(user);
             }
         }
-        if(user==null){
-            if(!register_small(openId,unionId,phoneNumber,loginBody.getInviteCode())){
+        if (user == null) {
+            if (!register_small(openId, unionId, phoneNumber, loginBody.getInviteCode())) {
                 throw new CustomException("注册失败");
             }
             user = iUserService.getOne(new LambdaQueryWrapper<User>()
-                    .eq(User::getTelphone,phoneNumber).last("limit 1"));
+                    .eq(User::getTelphone, phoneNumber).last("limit 1"));
         }
         return user;
     }
@@ -365,17 +372,17 @@ public class WxLoginService implements IWxLoginService
     public String getWxSmallAccessToken() {
         String key = "WX_SMALL_ACCESS_TOKEN";
         String accessToken = redisCache.getCacheObject(key);
-        if(Validator.isEmpty(accessToken)||accessToken.equals("null")){
+        if (Validator.isEmpty(accessToken) || accessToken.equals("null")) {
             String param = String.format(gzh_wxTokenParam, appid, appsrcret);
-            String resultString  = HttpUtils.sendGet(gzh_wxTokenUrl,param);
+            String resultString = HttpUtils.sendGet(gzh_wxTokenUrl, param);
             //解析json
             JSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);
-            if(jsonObject.containsKey("access_token")){
+            if (jsonObject.containsKey("access_token")) {
                 accessToken = String.valueOf(jsonObject.get("access_token"));
-                if(Validator.isNotEmpty(accessToken)&&!accessToken.equals("null")){
-                    redisCache.setCacheObject(key, accessToken,7100, TimeUnit.SECONDS);//7200有效期
+                if (Validator.isNotEmpty(accessToken) && !accessToken.equals("null")) {
+                    redisCache.setCacheObject(key, accessToken, 7100, TimeUnit.SECONDS);//7200有效期
                 }
-            }else{
+            } else {
                 return null;
             }
         }
@@ -385,18 +392,18 @@ public class WxLoginService implements IWxLoginService
     public String getWxGzhAccessToken() {
         String key = "WX_GZH_ACCESS_TOKEN";
         String accessToken = redisCache.getCacheObject(key);
-        if(Validator.isEmpty(accessToken)||accessToken.equals("null")){
+        if (Validator.isEmpty(accessToken) || accessToken.equals("null")) {
             String param = String.format(gzh_wxTokenParam, gzh_appid, gzh_appsrcret);
-            String resultString  = HttpUtils.sendGet(gzh_wxTokenUrl,param);
+            String resultString = HttpUtils.sendGet(gzh_wxTokenUrl, param);
             System.out.println(resultString);
             //解析json
             JSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);
-            if(jsonObject.containsKey("access_token")){
+            if (jsonObject.containsKey("access_token")) {
                 accessToken = String.valueOf(jsonObject.get("access_token"));
-                if(Validator.isNotEmpty(accessToken)&&!accessToken.equals("null")){
-                    redisCache.setCacheObject(key, accessToken,7100, TimeUnit.SECONDS);//7200有效期
+                if (Validator.isNotEmpty(accessToken) && !accessToken.equals("null")) {
+                    redisCache.setCacheObject(key, accessToken, 7100, TimeUnit.SECONDS);//7200有效期
                 }
-            }else{
+            } else {
                 return null;
             }
         }
@@ -405,49 +412,50 @@ public class WxLoginService implements IWxLoginService
 
     public String getWxGzhUserList(String nextOpenid) {
         String accessToken = getWxGzhAccessToken();
-        if(Validator.isEmpty(accessToken)){
+        if (Validator.isEmpty(accessToken)) {
             throw new CustomException("accessToken 错误");
         }
         String param = String.format(gzh_wxUserListParam, accessToken);
-        if(Validator.isNotEmpty(nextOpenid)){
-            param += "&next_openid="+nextOpenid;
-        }else{
+        if (Validator.isNotEmpty(nextOpenid)) {
+            param += "&next_openid=" + nextOpenid;
+        } else {
             iUserWxFollowService.cleanAllData();
         }
-        String resultString  = HttpUtils.sendGet(gzh_wxUserListUrl,param);
-        if(Validator.isNotEmpty(resultString)){
+        String resultString = HttpUtils.sendGet(gzh_wxUserListUrl, param);
+        if (Validator.isNotEmpty(resultString)) {
             JSONObject userInfoJSON = null;
             userInfoJSON = JSON.parseObject(resultString);
-            if(userInfoJSON.containsKey("total")){
+            if (userInfoJSON.containsKey("total")) {
                 Integer total = Integer.valueOf(String.valueOf(userInfoJSON.get("total")));
                 Integer count = Integer.valueOf(String.valueOf(userInfoJSON.get("count")));
                 String nextOpenidBack = String.valueOf(userInfoJSON.get("next_openid"));
-                if(Validator.isNotEmpty(nextOpenidBack)&&!nextOpenidBack.equals("")){
+                if (Validator.isNotEmpty(nextOpenidBack) && !nextOpenidBack.equals("")) {
                     getWxGzhUserList(nextOpenidBack);
                 }
-                if(userInfoJSON.containsKey("data")){
-                    List<String> openIdList = JSONArray.parseArray(userInfoJSON.getJSONObject("data").getJSONArray("openid").toJSONString(),String.class);
+                if (userInfoJSON.containsKey("data")) {
+                    List<String> openIdList = JSONArray.parseArray(userInfoJSON.getJSONObject("data").getJSONArray("openid").toJSONString(), String.class);
                     List<List<String>> lists = ToolsUtils.splitListBycapacity(openIdList, 1000);
-                    for (List<String> listSub:lists) {
+                    for (List<String> listSub : lists) {
                         iUserWxFollowService.insertByBatchAddBo(listSub);
                     }
                 }
             }
         }
+        //    System.out.println(resultString);
         return resultString;
     }
 
     public String getWxGzhUserCgiInfo(String openid) {
         String accessToken = getWxGzhAccessToken();
-        if(Validator.isEmpty(accessToken)){
+        if (Validator.isEmpty(accessToken)) {
             throw new CustomException("accessToken 错误");
         }
-        String param = String.format(gzh_wxUserCgiInfoParam, accessToken,openid);
-        String resultString  = HttpUtils.sendGet(gzh_wxUserCgiInfoUrl,param);
-        if(Validator.isNotEmpty(resultString)){
+        String param = String.format(gzh_wxUserCgiInfoParam, accessToken, openid);
+        String resultString = HttpUtils.sendGet(gzh_wxUserCgiInfoUrl, param);
+        if (Validator.isNotEmpty(resultString)) {
             JSONObject userInfoJSON = null;
             userInfoJSON = JSON.parseObject(resultString);
-            if(userInfoJSON.containsKey("unionid")){
+            if (userInfoJSON.containsKey("unionid")) {
                 return String.valueOf(userInfoJSON.get("unionid"));
             }
         }
@@ -455,9 +463,9 @@ public class WxLoginService implements IWxLoginService
     }
 
     @Override
-    public String sendSmallTpMsg(String openId,Map<String,String> paramMap)  {
+    public String sendSmallTpMsg(String openId, Map<String, String> paramMap) {
         String accessToken = getWxSmallAccessToken();
-        if(Validator.isEmpty(accessToken)){
+        if (Validator.isEmpty(accessToken)) {
             throw new CustomException("小程序accessToken 错误");
         }
         String param = String.format(small_wxSendTpParam, accessToken);
@@ -467,7 +475,7 @@ public class WxLoginService implements IWxLoginService
         JSONObject miniprogram = new JSONObject();
 
         obj.put("touser", openId);
-        paramMap.put("access_token",accessToken);
+        paramMap.put("access_token", accessToken);
         mp_template_msg.put("appid", gzh_appid);
         mp_template_msg.put("template_id", studyNoteTpId);
         mp_template_msg.put("url", "http://weixin.qq.com/download");  //公众号模板消息所要跳转的url
@@ -504,9 +512,43 @@ public class WxLoginService implements IWxLoginService
         return result;
     }
 
-    public Boolean subGzh(String openId){
+    @Override
+    public String getLiveEnCode(SectionWatchPerBo watchPer) {
+        String wxGzhAccessToken = getWxSmallAccessToken();
+        String param = String.format(small_wxEnCodeParam, wxGzhAccessToken);
+        String url = small_wxEnCodeUrl + "?" + param;
+        JSONObject obj = new JSONObject();
+        obj.put("page", "pages/webview/index");
+        StringBuilder sceneParam = new StringBuilder();
+        sceneParam.append("gid=").append(watchPer.getGoodsId()).append("&");
+        sceneParam.append("cid=").append(watchPer.getCourseId()).append("&");
+        sceneParam.append("sid=").append(watchPer.getSectionId()).append("&");
+        sceneParam.append("a=1");
+        obj.put("scene",sceneParam.toString());
+        String result = HttpUtils.sendPost(url, obj);
+        return result;
+    }
+
+    @Override
+    public String getBackEnCode(SectionWatchPerBo watchPer) {
+        String wxGzhAccessToken = getWxSmallAccessToken();
+        String param = String.format(small_wxEnCodeParam, wxGzhAccessToken);
+        String url = small_wxEnCodeUrl + "?" + param;
+        JSONObject obj = new JSONObject();
+        obj.put("page", "/pages3/live/detail");
+        StringBuilder sceneParam = new StringBuilder();
+        sceneParam.append("gid=").append(watchPer.getGoodsId()).append("&");
+        sceneParam.append("cid=").append(watchPer.getCourseId()).append("&");
+        sceneParam.append("sid=").append(watchPer.getSectionId()).append("&");
+        sceneParam.append("a=1");
+        obj.put("scene",sceneParam.toString());
+        String result = HttpUtils.sendPost(url, obj);
+        return result;
+    }
+
+    public Boolean subGzh(String openId) {
         String unionId = getWxGzhUserCgiInfo(openId);
-        if(Validator.isNotEmpty(unionId)){
+        if (Validator.isNotEmpty(unionId)) {
             unsubGzh(openId);
             UserWxFollowAddBo addBo = new UserWxFollowAddBo();
             addBo.setGzhOpenId(openId);
@@ -516,36 +558,36 @@ public class WxLoginService implements IWxLoginService
         return false;
     }
 
-    public Boolean unsubGzh(String openId){
+    public Boolean unsubGzh(String openId) {
         return iUserWxFollowService.unsubGzh(openId);
     }
 
     //公众号获取用户信息
     public User getWxGzhUnionIdUser(WxLoginBody loginBody) {
         String param = String.format(gzh_wxAuthParam, gzh_appid, gzh_appsrcret, loginBody.getCode());
-        String resultString  = HttpUtils.sendGet(gzh_wxAuthUrl,param);
+        String resultString = HttpUtils.sendGet(gzh_wxAuthUrl, param);
         //解析json
         JSONObject jsonObject = (JSONObject) JSONObject.parse(resultString);
         String access_token = String.valueOf(jsonObject.get("access_token"));
         String openId = String.valueOf(jsonObject.get("openid"));
 
         String userInfoParam = String.format(gzh_wxUserInfoParam, access_token, openId);
-        String userInfoResultString  = HttpUtils.sendGet(gzh_wxUserInfoUrl,userInfoParam);
+        String userInfoResultString = HttpUtils.sendGet(gzh_wxUserInfoUrl, userInfoParam);
         //解析json
         JSONObject jsonObject1 = (JSONObject) JSONObject.parse(userInfoResultString);
         String unionId = String.valueOf(jsonObject1.get("unionid"));
         User user = iUserService.queryByUnionId(unionId);
-        if(user==null){
+        if (user == null) {
             throw new CustomException("您尚未注册,请前往小程序注册");
         }
-        if(!Validator.isNotNull(user.getGzhOpenId())){
+        if (!Validator.isNotNull(user.getGzhOpenId())) {
             user.setGzhOpenId(openId);
             iUserService.updateById(user);
         }
         return user;
     }
 
-    public String obtainWxPhone(String iv, String encryptedData,String session_key){
+    public String obtainWxPhone(String iv, String encryptedData, String session_key) {
         String userInfo = null;
         JSONObject userInfoJSON = null;
         try {
@@ -555,9 +597,9 @@ public class WxLoginService implements IWxLoginService
 
             userInfo = new String(resultByte, "UTF-8");
             userInfoJSON = JSON.parseObject(userInfo);
-            if(userInfoJSON.containsKey("phoneNumber")){
+            if (userInfoJSON.containsKey("phoneNumber")) {
                 return String.valueOf(userInfoJSON.get("phoneNumber"));
-            }else{
+            } else {
                 return null;
             }
         } catch (Exception e) {

+ 37 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/course/bo/CheckSectionWatchVo.java

@@ -0,0 +1,37 @@
+package com.zhongzheng.modules.course.bo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author yangdamao
+ * @date 2022年08月17日 10:03
+ */
+@Data
+@ApiModel("课程节观看权限校验VO")
+public class CheckSectionWatchVo implements Serializable {
+
+    @ApiModelProperty("商品ID")
+    private Long goodsId;
+
+    @ApiModelProperty("订单商品ID")
+    private Long orderGoodsId;
+
+    @ApiModelProperty("课程ID")
+    private Long courseId;
+
+    @ApiModelProperty("模块ID")
+    private Long moduleId;
+
+    @ApiModelProperty("章ID")
+    private Long chapterId;
+
+    @ApiModelProperty("节id")
+    private Long sectionId;
+
+    @ApiModelProperty("用户ID")
+    private Long userId;
+}

+ 3 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/course/bo/SectionWatchPerBo.java

@@ -29,4 +29,7 @@ public class SectionWatchPerBo implements Serializable {
     @ApiModelProperty("节id")
     private Long sectionId;
 
+    /** 节类型 1录播 2直播 3回放 */
+    private Integer sectionType;
+
 }

+ 34 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/course/bo/SectionWatchQueryBo.java

@@ -0,0 +1,34 @@
+package com.zhongzheng.modules.course.bo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author yangdamao
+ * @date 2022年08月17日 10:01
+ */
+@Data
+@ApiModel("观看权限查询BO")
+public class SectionWatchQueryBo implements Serializable {
+
+    @ApiModelProperty("商品ID")
+    private Long goodsId;
+
+    @ApiModelProperty("课程ID")
+    private Long courseId;
+
+    @ApiModelProperty("模块ID")
+    private Long moduleId;
+
+    @ApiModelProperty("章ID")
+    private Long chapterId;
+
+    @ApiModelProperty("节id")
+    private Long sectionId;
+
+    @ApiModelProperty("用户ID")
+    private Long userId;
+}

+ 29 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/course/mapper/CourseSectionWatchPerMapper.java

@@ -1,8 +1,12 @@
 package com.zhongzheng.modules.course.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zhongzheng.modules.course.bo.CheckSectionWatchVo;
+import com.zhongzheng.modules.course.bo.SectionWatchQueryBo;
 import com.zhongzheng.modules.course.domain.CourseSectionWatchPer;
 
+import java.util.List;
+
 /**
  * 业务层次Mapper接口
  *
@@ -10,5 +14,30 @@ import com.zhongzheng.modules.course.domain.CourseSectionWatchPer;
  * @date 2021-10-08
  */
 public interface CourseSectionWatchPerMapper extends BaseMapper<CourseSectionWatchPer> {
+    /**
+     * 获取购买该商品的userId
+     * @author change
+     * @date 2022/8/17 10:32
+     * @param bo
+     * @return java.util.List<java.lang.Long>
+     */
+    List<Long> getUserIdByGoods(SectionWatchQueryBo bo);
+
+    /**
+     * 获取课程的所有层次ID
+     * @author change
+     * @date 2022/8/17 11:50
+     * @param bo
+     * @return java.util.List<com.zhongzheng.modules.course.bo.CheckSectionWatchVo>
+     */
+    List<CheckSectionWatchVo> getCourseLevel(SectionWatchQueryBo bo);
 
+    /**
+     * 查询商品订单ID
+     * @author change
+     * @date 2022/8/17 13:37
+     * @param bo
+     * @return java.lang.Long
+     */
+    Long getOrderGoodsIdByUser(SectionWatchQueryBo bo);
 }

+ 11 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/course/service/ICourseSectionWatchPerService.java

@@ -1,8 +1,10 @@
 package com.zhongzheng.modules.course.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.zhongzheng.modules.course.bo.CheckSectionWatchVo;
 import com.zhongzheng.modules.course.bo.SectionWatchPerAddBo;
 import com.zhongzheng.modules.course.bo.SectionWatchPerBo;
+import com.zhongzheng.modules.course.bo.SectionWatchQueryBo;
 import com.zhongzheng.modules.course.domain.CourseSectionWatchPer;
 import com.zhongzheng.modules.course.vo.CourseSectionWatchPerVo;
 
@@ -25,4 +27,13 @@ public interface ICourseSectionWatchPerService extends IService<CourseSectionWat
      * @return int
      */
     Boolean insertByAddBo(SectionWatchPerAddBo bo);
+
+    /**
+     * 课程节观看权限校验
+     * @author change
+     * @date 2022/8/17 10:19
+     * @param bo
+     * @return com.zhongzheng.modules.course.bo.CheckSectionWatchVo
+     */
+    CheckSectionWatchVo checkSectionWatchPer(SectionWatchQueryBo bo);
 }

+ 71 - 2
zhongzheng-system/src/main/java/com/zhongzheng/modules/course/service/impl/CourseSectionWatchPerServiceImpl.java

@@ -3,18 +3,28 @@ package com.zhongzheng.modules.course.service.impl;
 import cn.hutool.core.bean.BeanUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zhongzheng.common.exception.CustomException;
 import com.zhongzheng.common.utils.DateUtils;
+import com.zhongzheng.modules.course.bo.CheckSectionWatchVo;
 import com.zhongzheng.modules.course.bo.SectionWatchPerAddBo;
 import com.zhongzheng.modules.course.bo.SectionWatchPerBo;
+import com.zhongzheng.modules.course.bo.SectionWatchQueryBo;
 import com.zhongzheng.modules.course.domain.CourseSection;
 import com.zhongzheng.modules.course.domain.CourseSectionWatchPer;
 import com.zhongzheng.modules.course.mapper.CourseSectionWatchPerMapper;
 import com.zhongzheng.modules.course.service.ICourseSectionWatchPerService;
 import com.zhongzheng.modules.course.vo.CourseSectionWatchPerVo;
+import com.zhongzheng.modules.goods.domain.Goods;
+import com.zhongzheng.modules.goods.service.IGoodsService;
+import com.zhongzheng.modules.wx.service.IWxLoginService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 /**
  * @author tanzh
  * @date 2022年08月16日 11:05
@@ -22,8 +32,26 @@ import org.springframework.stereotype.Service;
 @Service
 public class CourseSectionWatchPerServiceImpl extends ServiceImpl<CourseSectionWatchPerMapper, CourseSectionWatchPer> implements ICourseSectionWatchPerService {
 
+    @Autowired
+    private IWxLoginService wxLoginService;
+
+    @Autowired
+    private IGoodsService goodsService;
+
     @Override
     public CourseSectionWatchPerVo getSectionWatchPer(SectionWatchPerBo bo) {
+        CourseSectionWatchPerVo vo = new CourseSectionWatchPerVo();
+        //生成微信小程序码
+        switch (bo.getSectionType()){
+            case 2://直播
+                vo.setEnCode(wxLoginService.getLiveEnCode(bo));
+                break;
+            case 3://回放
+                vo.setEnCode(wxLoginService.getBackEnCode(bo));
+                break;
+            default:
+                throw new CustomException("课程节类型不正确,请检查");
+        }
         CourseSectionWatchPer watchPer = getOne(new LambdaQueryWrapper<CourseSectionWatchPer>()
                 .eq(ObjectUtils.isNotNull(bo.getCourseId()), CourseSectionWatchPer::getCourseId, bo.getCourseId())
                 .eq(ObjectUtils.isNotNull(bo.getChapterId()), CourseSectionWatchPer::getChapterId, bo.getChapterId())
@@ -33,9 +61,8 @@ public class CourseSectionWatchPerServiceImpl extends ServiceImpl<CourseSectionW
                 .eq(CourseSectionWatchPer::getStatus, 1)
                 .last("LIMIT 1"));
         if (ObjectUtils.isNull(watchPer)){
-            return null;
+            return vo;
         }
-        CourseSectionWatchPerVo vo = new CourseSectionWatchPerVo();
         BeanUtil.copyProperties(watchPer,vo,true);
         return vo;
     }
@@ -48,4 +75,46 @@ public class CourseSectionWatchPerServiceImpl extends ServiceImpl<CourseSectionW
         add.setUpdateTime(DateUtils.getNowTime());
         return saveOrUpdate(add);
     }
+
+    @Override
+    public CheckSectionWatchVo checkSectionWatchPer(SectionWatchQueryBo bo) {
+        //校验商品有效期
+        Goods goods = goodsService.getById(bo.getGoodsId());
+        if (ObjectUtils.isNotNull(goods.getValidityStartTime()) && ObjectUtils.isNotNull(goods.getValidityEndTime())){
+            Long validityStartTime = goods.getValidityStartTime();
+            Long validityEndTime = goods.getValidityEndTime();
+            if (System.currentTimeMillis() < validityStartTime || System.currentTimeMillis() > validityEndTime){
+                throw new CustomException("该商品不在有效期");
+            }
+        }
+        CheckSectionWatchVo watchVo = new CheckSectionWatchVo();
+        watchVo.setGoodsId(bo.getGoodsId());
+        watchVo.setCourseId(bo.getCourseId());
+        watchVo.setSectionId(bo.getSectionId());
+        //获取观看权限
+        CourseSectionWatchPer watchPer = getOne(new LambdaQueryWrapper<CourseSectionWatchPer>()
+                .eq(CourseSectionWatchPer::getCourseId, bo.getCourseId())
+                .eq(CourseSectionWatchPer::getGoodsId, bo.getGoodsId())
+                .eq(CourseSectionWatchPer::getSectionId, bo.getSectionId())
+                .last("LIMIT 1"));
+        if (ObjectUtils.isNull(watchPer) || watchPer.getWatchPer() == 1){
+            //没有配观看权限或者观看权限为开通课程的学员
+            //获取购买该商品的userId
+            List<Long> userIds = baseMapper.getUserIdByGoods(bo);
+            if (CollectionUtils.isEmpty(userIds) || !userIds.contains(bo.getUserId())){
+                throw new CustomException("该学员没有观看权限");
+            }
+        }
+        //所有人可以看或者有权限的学员
+        List<CheckSectionWatchVo> vos = baseMapper.getCourseLevel(bo);
+        if (CollectionUtils.isNotEmpty(vos)){
+            CheckSectionWatchVo vo = vos.stream().findFirst().get();
+            watchVo.setChapterId(ObjectUtils.isNotNull(vo.getChapterId())?vo.getChapterId():null);
+            watchVo.setModuleId(ObjectUtils.isNotNull(vo.getModuleId())?vo.getModuleId():null);
+        }
+        //查询商品订单ID
+        Long orderGoodsId = baseMapper.getOrderGoodsIdByUser(bo);
+        watchVo.setOrderGoodsId(orderGoodsId);
+        return watchVo;
+    }
 }

+ 4 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/course/vo/CourseSectionWatchPerVo.java

@@ -55,4 +55,8 @@ public class CourseSectionWatchPerVo implements Serializable {
     /** 状态 1有效 0无效 */
     @ApiModelProperty("状态 1有效 0无效")
     private Integer status;
+
+    /** 小程序二维码 */
+    @ApiModelProperty("小程序二维码")
+    private String enCode;
 }

+ 24 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/goods/service/impl/GoodsServiceImpl.java

@@ -5,17 +5,21 @@ import cn.hutool.core.lang.Validator;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.zhongzheng.common.annotation.DataScope;
 import com.zhongzheng.common.exception.CustomException;
 import com.zhongzheng.common.utils.DateUtils;
 import com.zhongzheng.common.utils.ServletUtils;
+import com.zhongzheng.modules.course.bo.CourseMenuAddBo;
 import com.zhongzheng.modules.course.bo.CourseMenuListAddBo;
 import com.zhongzheng.modules.course.bo.CourseMenuQueryBo;
 import com.zhongzheng.modules.course.bo.CourseQueryBo;
+import com.zhongzheng.modules.course.domain.CourseSectionWatchPer;
 import com.zhongzheng.modules.course.mapper.CourseMapper;
 import com.zhongzheng.modules.course.service.ICourseChapterSectionService;
 import com.zhongzheng.modules.course.service.ICourseMenuService;
 import com.zhongzheng.modules.course.service.ICourseModuleChapterService;
+import com.zhongzheng.modules.course.service.ICourseSectionWatchPerService;
 import com.zhongzheng.modules.course.vo.*;
 import com.zhongzheng.modules.exam.bo.ExamNumberGoodsQueryBo;
 import com.zhongzheng.modules.exam.vo.ExamNumberGoodsVo;
@@ -83,6 +87,9 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
     @Autowired
     private ICourseModuleChapterService iCourseModuleChapterService;
 
+    @Autowired
+    private ICourseSectionWatchPerService iCourseSectionWatchPerService;
+
     @Override
     public GoodsVo queryById(Long goodsId){
         Goods db = this.baseMapper.selectById(goodsId);
@@ -377,6 +384,23 @@ public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements
                 iCourseMenuService.updateByEditBo(menuListAddBo);
             }
         }
+
+        //修改商品课程节观看权限
+        List<CourseMenuAddBo> menuList = bo.getMenuList();
+        if (CollectionUtils.isEmpty(menuList)){
+            //商品下没有课程/节
+            iCourseSectionWatchPerService.update(new LambdaUpdateWrapper<CourseSectionWatchPer>()
+                        .set(CourseSectionWatchPer::getStatus,0)
+                        .eq(CourseSectionWatchPer::getGoodsId,bo.getGoodsId()));
+        }else {
+            //对比观看权限
+            List<Long> courseIds = menuList.stream().map(CourseMenuAddBo::getCourseId).collect(Collectors.toList());
+            iCourseSectionWatchPerService.update(new LambdaUpdateWrapper<CourseSectionWatchPer>()
+                        .set(CourseSectionWatchPer::getStatus,0)
+                        .eq(CourseSectionWatchPer::getGoodsId,bo.getGoodsId())
+                        .notIn(CourseSectionWatchPer::getCourseId,courseIds));
+        }
+
         return this.updateById(update);
     }
 

+ 6 - 0
zhongzheng-system/src/main/java/com/zhongzheng/modules/wx/service/IWxLoginService.java

@@ -18,6 +18,8 @@ import com.zhongzheng.common.utils.*;
 import com.zhongzheng.common.utils.http.HttpUtils;
 import com.zhongzheng.common.utils.ip.IpUtils;
 import com.zhongzheng.modules.alisms.service.IAliSmsService;
+import com.zhongzheng.modules.course.bo.SectionWatchPerBo;
+import com.zhongzheng.modules.course.domain.CourseSectionWatchPer;
 import com.zhongzheng.modules.user.bo.UserWxFollowAddBo;
 import com.zhongzheng.modules.user.domain.User;
 import com.zhongzheng.modules.user.entity.ClientLoginUser;
@@ -45,4 +47,8 @@ import java.util.concurrent.TimeUnit;
 public interface IWxLoginService
 {
     String sendSmallTpMsg(String openId,Map<String,String> paramMap);
+
+    String getLiveEnCode(SectionWatchPerBo watchPer);
+
+    String getBackEnCode(SectionWatchPerBo watchPer);
 }

+ 67 - 0
zhongzheng-system/src/main/resources/mapper/modules/course/CourseSectionWatchPerMapper.xml

@@ -0,0 +1,67 @@
+<?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.zhongzheng.modules.course.mapper.CourseSectionWatchPerMapper">
+
+    <select id="getUserIdByGoods" parameterType="com.zhongzheng.modules.course.bo.SectionWatchQueryBo" resultType="java.lang.Long">
+        SELECT
+            o.user_id
+        FROM
+            `order` o
+                LEFT JOIN order_goods og ON o.order_sn = og.order_sn
+        WHERE
+            og.pay_status IN ( 2, 3, 4 )
+            AND og.refund_status != 2
+            AND og.STATUS = 1
+            AND o.`status` = 1
+            AND g.`status` = 1
+            AND og.goods_id = #{goodsId}
+    </select>
+
+    <select id="getCourseLevel" parameterType="com.zhongzheng.modules.course.bo.SectionWatchQueryBo" resultType="com.zhongzheng.modules.course.bo.CheckSectionWatchVo">
+        SELECT
+            cs.course_id as courseId, cm.module_id as moduleId,cm.chapter_id as chapterId, ccs.section_id AS sectionId
+        FROM
+            course_menu cs
+                LEFT JOIN course_module_chapter cm ON cs.menu_id = cm.module_id
+                LEFT JOIN course_chapter_section ccs ON cm.chapter_id = ccs.chapter_id
+        WHERE
+            cs.course_id = #{courseId} AND
+            ccs.section_id = #{sectionId}
+          AND type = 1
+          AND `status` = 1 UNION
+        SELECT
+            cs.course_id as courseId, '' as moduleId,ccs.chapter_id as chapterId, ccs.section_id AS sectionId
+        FROM
+            course_menu cs
+                LEFT JOIN course_chapter_section ccs ON cs.menu_id = ccs.chapter_id
+        WHERE
+            cs.course_id = #{courseId} AND
+            ccs.section_id = #{sectionId}
+          AND type = 2
+          AND `status` = 1 UNION
+        SELECT
+            cs.course_id as courseId, '' as moduleId,'' as chapterId, cs.menu_id AS sectionId
+        FROM
+            course_menu cs
+        WHERE
+            cs.course_id = #{courseId} AND
+            cs.menu_id = #{sectionId}
+          AND type = 3
+          AND `status` = 1
+    </select>
+
+    <select id="getOrderGoodsIdByUser" parameterType="com.zhongzheng.modules.course.bo.SectionWatchQueryBo" resultType="java.lang.Long">
+        SELECT FROM `order` o
+                        LEFT JOIN order_goods og ON o.order_sn = og.order_sn
+        WHERE  og.pay_status IN ( 2, 3, 4 )
+          AND og.refund_status != 2
+		          AND og.STATUS = 1
+		          AND o.`status` = 1
+		          AND g.`status` = 1
+							AND og.goods_id = #{goodsId}
+							AND o.user_id = #{userId}
+        ORDER BY o.create_time DESC LIMIT 1
+    </select>
+</mapper>