Kaynağa Gözat

Merge remote-tracking branch 'origin/master'

yuhongqi 5 gün önce
ebeveyn
işleme
db0e0afee3
27 değiştirilmiş dosya ile 397 ekleme ve 106 silme
  1. 15 3
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java
  2. 14 0
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java
  3. 20 13
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  4. 12 0
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  5. 5 0
      fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java
  6. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsCoursePlaySourceConfigMapper.java
  7. 5 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigCreateParam.java
  8. 5 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java
  9. 1 0
      fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java
  10. 5 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCoursePlaySourceConfigServiceImpl.java
  11. 5 0
      fs-service/src/main/java/com/fs/course/vo/FsCoursePlaySourceConfigVO.java
  12. 1 0
      fs-service/src/main/java/com/fs/his/service/IFsIntegralGoodsService.java
  13. 48 0
      fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java
  14. 8 2
      fs-service/src/main/java/com/fs/live/domain/LiveWatchConfig.java
  15. 1 1
      fs-service/src/main/java/com/fs/live/domain/LiveWatchUser.java
  16. 151 5
      fs-service/src/main/java/com/fs/live/service/impl/LiveRedPacketLogServiceImpl.java
  17. 23 0
      fs-service/src/main/java/com/fs/live/vo/RecordTimeRangeVO.java
  18. 3 2
      fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java
  19. 11 0
      fs-service/src/main/java/com/fs/sop/mapper/QwSopTempRulesMapper.java
  20. 2 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopTempRulesService.java
  21. 1 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopTempService.java
  22. 5 0
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempRulesServiceImpl.java
  23. 22 67
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempServiceImpl.java
  24. 7 7
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  25. 3 0
      fs-service/src/main/resources/mapper/course/FsCoursePlaySourceConfigMapper.xml
  26. 20 2
      fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java
  27. 1 4
      fs-user-app/src/main/java/com/fs/app/controller/store/IndexScrmController.java

+ 15 - 3
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java

@@ -186,7 +186,7 @@ public class FsUserCourseController extends BaseController {
         if (fsUserCourse.getIsPrivate() != null && fsUserCourse.getIsPrivate() == 0) {
             redisCacheUtil.delSpringCacheAllByName(PublicCourseAppCacheNames.COURSE_PUBLIC_APP_LIST);
         }
-        
+
         return toAjax(1);
     }
 
@@ -277,7 +277,7 @@ public class FsUserCourseController extends BaseController {
         fsUserCourseService.deleteFsUserCourseByCourseIds(courseIds);
         redisCacheUtil.delRedisKey("getCourseList");
         redisCacheUtil.delSpringCacheAllByName(PublicCourseAppCacheNames.COURSE_PUBLIC_APP_LIST);
-        
+
         return toAjax(1);
     }
 
@@ -370,7 +370,7 @@ public class FsUserCourseController extends BaseController {
 
         redisCacheUtil.delSpringCacheAllByName(PublicCourseAppCacheNames.COURSE_PUBLIC_APP_LIST);
 
-        
+
         return toAjax(1);
     }
 
@@ -404,6 +404,18 @@ public class FsUserCourseController extends BaseController {
         return toAjax(1);
     }
 
+    /**
+     * 同步课程模板
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseVideo:sync')")
+    @Log(title = "同步课程模板", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @PostMapping("/syncTemplateByCompanyId/{courseId}/{companyId}")
+    public AjaxResult syncTemplateByCompanyId(@PathVariable Long courseId,@PathVariable Long companyId) {
+        sopTempService.syncTemplateByCompanyId(courseId,companyId);
+        return toAjax(1);
+    }
+
     /**
      * 课程下拉列表
      */

+ 14 - 0
fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java

@@ -8,10 +8,12 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.his.domain.FsIntegralGoods;
+import com.fs.his.param.FsIntegralGoodsListUParam;
 import com.fs.his.param.FsIntegralGoodsParam;
 import com.fs.his.service.IFsIntegralGoodsService;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.vo.FsIntegralGoodsChooseVO;
+import com.fs.his.vo.FsIntegralGoodsListUVO;
 import com.fs.his.vo.FsIntegralGoodsListVO;
 import com.fs.his.vo.FsStoreProductExcelVO;
 import com.github.pagehelper.PageHelper;
@@ -51,6 +53,18 @@ public class FsIntegralGoodsController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询积分商品列表 正常的
+     */
+    @PreAuthorize("@ss.hasPermi('his:integralGoods:list')")
+    @GetMapping("/norList")
+    public TableDataInfo norList(FsIntegralGoodsListUParam fsIntegralGoods)
+    {
+        List<FsIntegralGoodsListUVO> list=fsIntegralGoodsService.selectFsIntegralGoodsListUVO(fsIntegralGoods);
+        return getDataTable(list);
+    }
+
+
     /**
      * 导出积分商品列表
      */

+ 20 - 13
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -11,7 +11,6 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.StringUtils;
-import com.fs.company.domain.Company;
 import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.param.VcCompanyUser;
 import com.fs.company.service.ICompanyService;
@@ -20,28 +19,23 @@ import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
-import com.fs.course.param.FsCourseLinkMiniParam;
 import com.fs.course.param.newfs.FsUserCourseAddCompanyUserParam;
 import com.fs.course.service.*;
 import com.fs.course.vo.FsUserCourseVideoQVO;
-import com.fs.fastGpt.domain.FastGptPushTokenTotal;
 import com.fs.fastgptApi.vo.AudioVO;
 import com.fs.his.domain.FsIntegralCount;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsInquiryOrderService;
 import com.fs.his.service.IFsIntegralCountService;
+import com.fs.his.service.IFsIntegralGoodsService;
 import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.utils.qrcode.QRCodeUtils;
 import com.fs.qw.domain.*;
 import com.fs.qw.mapper.QwContactWayMapper;
 import com.fs.qw.mapper.QwExternalContactMapper;
-import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
 import com.fs.qw.mapper.QwUserMapper;
-import com.fs.qw.param.QwUpdateContactWayParam;
 import com.fs.qw.service.*;
 import com.fs.qw.service.impl.AsyncQwContactWayService;
-import com.fs.qwApi.domain.QwExternalContactResult;
-import com.fs.qwApi.domain.QwResult;
 import com.fs.qwApi.domain.inner.ExternalContact;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.domain.QwSopTempVoice;
@@ -62,9 +56,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.*;
-import com.fs.app.task.qwTask;
 
-import java.math.BigDecimal;
 import java.time.*;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -208,13 +200,28 @@ public class CommonController {
     @Autowired
     private CompanyMapper companyMapper;
 
+    @Autowired
+    private IFsIntegralGoodsService goodsService;
+
+    @Autowired
+    private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
 
     @GetMapping("/test")
-    public void test(){
-        Company company = companyMapper.selectCompanyById(321L);
-        BigDecimal money = company.getMoney();
-        if (money.compareTo(BigDecimal.ZERO) <= 0) {
+    public R test(){
+
+        Long userId = 10568613L;
+        String AppId = "";
+
+        if (AppId == null || AppId.isEmpty()) {
+            return goodsService.getCourseIntegralGoods(userId);
+        }
+
+        String integralGoods = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppIdGoods(AppId);
+        if (!StringUtil.strIsNullOrEmpty(integralGoods)) {
+            return goodsService.getCourseIntegralGoodsByMiniApp(AppId, userId, integralGoods);
         }
+
+        return goodsService.getCourseIntegralGoods(userId);
     }
 
     /**

+ 12 - 0
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -1631,6 +1631,12 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
                     setting.setMiniprogramPage(shortH5Link);
                     break;
+                // app发送直播IM消息
+                case "20":
+                    json = configService.selectConfigByKey("his.config");
+                    sysConfig= JSON.parseObject(json,FSSysConfig.class);
+                    createLiveWatchLogAndEnQueue(companyId,companyUserId,externalId, setting.getLiveId(),sysConfig.getAppId(),1,qwUserId,logVo.getCorpId());
+                    break;
                 default:
                     break;
             }
@@ -1958,6 +1964,12 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                         log.error("浏览器看课模板解析失败:" + e);
                     }
 
+                    break;
+                // app发送直播IM消息
+                case "20":
+                    json = configService.selectConfigByKey("his.config");
+                    sysConfig= JSON.parseObject(json,FSSysConfig.class);
+                    createLiveWatchLogAndEnQueue(companyId,companyUserId,externalId, setting.getLiveId(),sysConfig.getAppId(),1,qwUserId,logVo.getCorpId());
                     break;
                 case "21"://短信看课
                     if (sopLogs.getFsUserId() != null && !Long.valueOf(0L).equals(sopLogs.getFsUserId())) {

+ 5 - 0
fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java

@@ -117,4 +117,9 @@ public class FsCoursePlaySourceConfig {
     * 备案号
     */
     private String recordNumber;
+
+    /**
+     *  积分商品配置
+     */
+    private String integralGoods;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCoursePlaySourceConfigMapper.java

@@ -19,4 +19,7 @@ public interface FsCoursePlaySourceConfigMapper extends BaseMapper<FsCoursePlayS
 
     @DataSource(DataSourceType.SLAVE)
     FsCoursePlaySourceConfig selectCoursePlaySourceConfigByAppId(String appId);
+
+    @DataSource(DataSourceType.SLAVE)
+    String selectCoursePlaySourceConfigByAppIdGoods(@Param("appId") String appId);
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigCreateParam.java

@@ -65,4 +65,9 @@ public class FsCoursePlaySourceConfigCreateParam {
     * 备案号
     */
     private String recordNumber;
+
+    /**
+    *  积分商品配置
+    */
+    private String integralGoods;
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java

@@ -66,4 +66,9 @@ public class FsCoursePlaySourceConfigEditParam {
     * 备案号
     */
     private String recordNumber;
+
+    /**
+     *  积分商品配置
+     */
+    private String integralGoods;
 }

+ 1 - 0
fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java

@@ -22,4 +22,5 @@ public interface IFsCoursePlaySourceConfigService extends IService<FsCoursePlayS
      * @return
      */
     FsCoursePlaySourceConfig selectCoursePlaySourceConfigByAppId(String appId);
+    String selectCoursePlaySourceConfigByAppIdGoods(String appId);
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCoursePlaySourceConfigServiceImpl.java

@@ -35,4 +35,9 @@ public class FsCoursePlaySourceConfigServiceImpl extends ServiceImpl<FsCoursePla
     public FsCoursePlaySourceConfig selectCoursePlaySourceConfigByAppId(String appId) {
         return baseMapper.selectCoursePlaySourceConfigByAppId(appId);
     }
+
+    @Override
+    public String selectCoursePlaySourceConfigByAppIdGoods(String appId) {
+        return baseMapper.selectCoursePlaySourceConfigByAppIdGoods(appId);
+    }
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/vo/FsCoursePlaySourceConfigVO.java

@@ -76,4 +76,9 @@ public class FsCoursePlaySourceConfigVO {
      * 备案号
      */
     private String recordNumber;
+
+    /**
+     *  积分商品配置
+     */
+    private String integralGoods;
 }

+ 1 - 0
fs-service/src/main/java/com/fs/his/service/IFsIntegralGoodsService.java

@@ -74,6 +74,7 @@ public interface IFsIntegralGoodsService
     String importIntegralGoodsService(List<FsIntegralGoods> list);
 
     R getCourseIntegralGoods(Long userId);
+    R getCourseIntegralGoodsByMiniApp(String appId,Long userId, String integralGoods);
 
     /**
      * 获取选择积分商品列表

+ 48 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsIntegralGoodsServiceImpl.java

@@ -6,6 +6,8 @@ import com.fs.common.exception.ServiceException;
 import com.fs.common.utils.DateUtils;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseAnswerReward;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.his.domain.FsChineseMedicine;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.domain.FsUser;
@@ -19,7 +21,9 @@ import com.fs.his.service.IFsIntegralGoodsService;
 import com.fs.his.vo.FsIntegralGoodsChooseVO;
 import com.fs.his.vo.FsIntegralGoodsListUVO;
 import com.fs.his.vo.FsIntegralGoodsListVO;
+import com.fs.his.vo.FsIntegralGoodsVo;
 import com.fs.system.service.ISysConfigService;
+import io.netty.util.internal.StringUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -49,6 +53,8 @@ public class FsIntegralGoodsServiceImpl implements IFsIntegralGoodsService
     @Autowired
     private FsUserIntegralLogsMapper userIntegralLogsMapper;
 
+
+
     /**
      * 查询积分商品
      *
@@ -250,6 +256,48 @@ public class FsIntegralGoodsServiceImpl implements IFsIntegralGoodsService
         return R.ok().put("data", reward);
     }
 
+    @Override
+    public R getCourseIntegralGoodsByMiniApp(String appId,Long userId,String integralGoods) {
+
+        FsUser user = fsUserMapper.selectFsUserByUserId(userId);
+        FsUserIntegralLogs integralLog = userIntegralLogsMapper.getLast1LogByUserIdAndLogType(userId, 17);
+
+        // 1. 创建返回对象
+        FsCourseAnswerReward reward = new FsCourseAnswerReward();
+
+        // 2. 设置当前积分
+        Integer currentPoints = user.getIntegral().intValue();
+        reward.setCurrentPoints(currentPoints);
+
+        List<FsCourseAnswerReward.RewardProduct> products = new ArrayList<>();
+
+        if (!StringUtil.isNullOrEmpty(integralGoods)) {
+
+            Set<Long> goodsIds=new HashSet<>();
+            for (String id : integralGoods.split(",")) {
+                goodsIds.add(Long.parseLong(id.trim()));
+            }
+            if (!goodsIds.isEmpty()){
+                List<FsIntegralGoodsVo> goodsVoList = fsIntegralGoodsMapper.selectAllByGoodsIds(goodsIds);
+                for (FsIntegralGoodsVo goods : goodsVoList) {
+
+                    FsCourseAnswerReward.RewardProduct product = new FsCourseAnswerReward.RewardProduct();
+                    product.setProductId(goods.getGoodsId());
+                    product.setProductName(goods.getGoodsName());
+                    product.setRequiredPoints(goods.getIntegral().intValue());
+                    product.setImageUrl(goods.getImgUrl());
+                    product.setOtPrice(goods.getOtPrice());
+                    products.add(product);
+                }
+            }
+
+        }
+
+        reward.setProducts(products);
+        reward.setAvailableCoins(Objects.nonNull(integralLog) ? integralLog.getIntegral().intValue() : 0);
+        return R.ok().put("data", reward);
+    }
+
     /**
      * 随机获取当前阶段的积分商品
      */

+ 8 - 2
fs-service/src/main/java/com/fs/live/domain/LiveWatchConfig.java

@@ -110,7 +110,13 @@ public class LiveWatchConfig extends BaseEntity{
     @Excel(name = "配置json")
     private String configJson;
 
-
-
+    /**
+    * 录播可领取奖励
+    */
+    private Boolean recordRedPacketEnabled;
+    /**
+    * 录播奖励配置
+    */
+    private String recordTimeRangeStr;
 
 }

+ 1 - 1
fs-service/src/main/java/com/fs/live/domain/LiveWatchUser.java

@@ -73,7 +73,7 @@ public class LiveWatchUser extends BaseEntity {
     */
     private Integer sendType;
     /**
-    * 奖励类型 1红包 2积分
+    * 奖励类型 1红包 2积分 3 没设置奖励
     */
     private Integer rewardType;
 

+ 151 - 5
fs-service/src/main/java/com/fs/live/service/impl/LiveRedPacketLogServiceImpl.java

@@ -1,6 +1,8 @@
 package com.fs.live.service.impl;
 
 import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Objects;
@@ -42,6 +44,7 @@ import com.fs.live.mapper.LiveMapper;
 import com.fs.live.service.ILiveMsgService;
 import com.fs.live.service.ILiveService;
 import com.fs.live.service.ILiveWatchUserService;
+import com.fs.live.vo.RecordTimeRangeVO;
 import com.fs.voice.utils.StringUtil;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
 import lombok.extern.slf4j.Slf4j;
@@ -200,7 +203,7 @@ public class LiveRedPacketLogServiceImpl extends ServiceImpl<LiveRedPacketLogMap
             boolean isLocked = lock.tryLock(5, 120, TimeUnit.SECONDS);
             if (!isLocked) {
                 logger.warn("直播获取锁失败,用户ID:{},直播ID:{}", param.getUserId(), param.getLiveId());
-                return R.error("操作频繁,请后再试!");
+                return R.error("操作频繁,请2分钟后再试!");
             }
 
             // 从缓存里面更新一下时长
@@ -306,8 +309,51 @@ public class LiveRedPacketLogServiceImpl extends ServiceImpl<LiveRedPacketLogMap
                         //直播时长不满足,看录播 如果录播的时长看课时长 大于了 设定的百分比则 可以领取积分
                         if (replayUser != null && replayUser.getOnlineSeconds() != null
                                 && replayUser.getOnlineSeconds() * 100 >= duration * completionRate) {
-                            // 如果是 回放完课 发积分
-                            return sendLiveIntegralReward(param, user, watchUser, config);
+
+                            // 如果是 回放完课 发积分 //新增 时间范围 范围内可以领取红包,范围外领取积分或者不领
+                            if (config.getRecordRedPacketEnabled() && !StringUtil.strIsNullOrEmpty(config.getRecordTimeRangeStr())){
+
+                                List<RecordTimeRangeVO> ranges = parseRecordRewards(config.getRecordTimeRangeStr());
+                                RecordTimeRangeVO matched = matchCurrentTime(ranges);
+
+                                if (matched != null) {
+                                    // 根据 rewardType 发放对应奖励 1=红包 2=积分
+                                    if ("1".equals(matched.getRewardType())) {
+
+                                        WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
+
+                                        if (StringUtil.strIsNullOrEmpty(user.getAppOpenId())){
+                                            return R.error("请重新登录app");
+                                        }
+
+                                        // 用app的 appOpenId
+                                        String openId = user.getAppOpenId();
+                                        packetParam.setOpenId(openId);
+                                        BeanUtils.copyProperties(param, packetParam);
+
+                                        //重置红包数
+                                        config.setRedPacketAmount(matched.getRedPacketAmount());
+                                        return sendAppLiveRedPacketAuto(packetParam, watchUser, config, param);
+                                    }else if ("2".equals(matched.getRewardType())) {
+                                        //重置发放的积分
+                                        config.setScoreAmount(matched.getScoreAmount());
+                                        return sendLiveIntegralReward(param, user, watchUser, config);
+                                    }
+                                }else {
+                                    return R.error("当前时间段,不满足领取奖励条件");
+                                }
+                            }else {
+                                // 更新直播观看记录的奖励类型
+                                watchUser.setRewardType(3);
+                                watchUser.setSendType(1);
+
+                                watchUserMapper.updateLiveWatchUser(watchUser);
+
+                                log.error("未设置回放奖励里:{},{}",live.getLiveId(),config);
+                                return R.ok("未设置回放奖励");
+                            }
+
+
                         }else {
                             return R.error("观看时长未达到完课要求,请看继续观看回放,之后再领取");
                         }
@@ -334,8 +380,58 @@ public class LiveRedPacketLogServiceImpl extends ServiceImpl<LiveRedPacketLogMap
                         return R.error("观看时长未达到完课要求,请继续观看");
                     }
 
-                    // 如果是 回放完课 发积分
-                    return sendLiveIntegralReward(param, user, watchUser, config);
+                    //新增 时间范围 范围内可以领取红包,范围外领取积分或者不领
+                    // 如果是 回放完课 发积分 //新增 时间范围 范围内可以领取红包,范围外领取积分或者不领
+                    if (config.getRecordRedPacketEnabled() && !StringUtil.strIsNullOrEmpty(config.getRecordTimeRangeStr())){
+
+                        List<RecordTimeRangeVO> ranges = parseRecordRewards(config.getRecordTimeRangeStr());
+                        RecordTimeRangeVO matched = matchCurrentTime(ranges);
+
+                        if (matched != null) {
+                            // 根据 rewardType 发放对应奖励 1=红包 2=积分
+                            if ("1".equals(matched.getRewardType())) {
+
+                                WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
+
+                                if (StringUtil.strIsNullOrEmpty(user.getAppOpenId())){
+                                    return R.error("请重新登录app");
+                                }
+
+                                // 用app的 appOpenId
+                                String openId = user.getAppOpenId();
+                                packetParam.setOpenId(openId);
+                                BeanUtils.copyProperties(param, packetParam);
+
+                                //重置红包数
+                                config.setRedPacketAmount(matched.getRedPacketAmount());
+                                return sendAppLiveRedPacketAuto(packetParam, watchUser, config, param);
+                            }else if ("2".equals(matched.getRewardType())) {
+                                //重置发放的积分
+                                config.setScoreAmount(matched.getScoreAmount());
+                                return sendLiveIntegralReward(param, user, watchUser, config);
+                            }
+                        }else {
+                            return R.error("当前时间段,不满足领取奖励条件");
+                        }
+                    }else {
+                        // 更新直播观看记录的奖励类型
+                        watchUser.setRewardType(3);
+                        watchUser.setSendType(1);
+
+                        watchUserMapper.updateLiveWatchUser(watchUser);
+                        log.error("未设置回放奖励内:{},{}",live.getLiveId(),config);
+                        return R.ok("未设置回放奖励");
+                    }
+
+                    // 更新直播观看记录的奖励类型
+                    watchUser.setRewardType(3);
+                    watchUser.setSendType(1);
+
+                    watchUserMapper.updateLiveWatchUser(watchUser);
+                    log.error("回放未满足-奖励设置外:{},{}",live.getLiveId(),config);
+                    return R.ok("未设置回放奖励");
+//                    // 如果是 回放完课 发积分
+//                    return sendLiveIntegralReward(param, user, watchUser, config);
                 }else {
                     return R.error("未知 直播观看类型 ");
                 }
@@ -352,6 +448,56 @@ public class LiveRedPacketLogServiceImpl extends ServiceImpl<LiveRedPacketLogMap
         }
     }
 
+
+    public static List<RecordTimeRangeVO> parseRecordRewards(String recordTimeRangeStr) {
+        List<RecordTimeRangeVO> result = new ArrayList<>();
+        if (recordTimeRangeStr == null || recordTimeRangeStr.isEmpty()) {
+            return result;
+        }
+        String[] records = recordTimeRangeStr.split(",");
+        for (String record : records) {
+            String[] parts = record.split("-", 5);
+            if (parts.length < 3) continue;
+
+            RecordTimeRangeVO range = new RecordTimeRangeVO();
+            range.setStartTime(parts[0]);
+            range.setEndTime(parts[1]);
+            range.setRewardType(parts[2]);
+
+            if ("1".equals(parts[2]) && parts.length > 3 && !parts[3].isEmpty()) {
+                range.setRedPacketAmount(BigDecimal.valueOf(Double.parseDouble(parts[3])));
+            }
+            if ("2".equals(parts[2]) && parts.length > 4 && !parts[4].isEmpty()) {
+                range.setScoreAmount(Long.valueOf(parts[4]));
+            }
+
+            result.add(range);
+        }
+        return result;
+    }
+
+    private static int toMinutes(String timeStr) {
+        String[] parts = timeStr.split(":");
+        return Integer.parseInt(parts[0]) * 60 + Integer.parseInt(parts[1]);
+    }
+
+    /**
+     * 当前时间是否在某个时间段内
+     */
+    public static RecordTimeRangeVO matchCurrentTime(List<RecordTimeRangeVO> ranges) {
+        int nowMinutes = toMinutes(
+                new SimpleDateFormat("HH:mm").format(new Date())
+        );
+        for (RecordTimeRangeVO range : ranges) {
+            int start = toMinutes(range.getStartTime());
+            int end = toMinutes(range.getEndTime());
+            if (nowMinutes >= start && nowMinutes < end) {
+                return range;
+            }
+        }
+        return null;
+    }
+
     @Override
     public R syncLiveRedPacket(String outBatchNo, String batchId) {
         LiveRedPacketLog log = redPacketLogMapper.selectLiveRedPacketLogByBatchNo(outBatchNo);

+ 23 - 0
fs-service/src/main/java/com/fs/live/vo/RecordTimeRangeVO.java

@@ -0,0 +1,23 @@
+package com.fs.live.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class RecordTimeRangeVO {
+
+    private String startTime;   // "17:44"
+    private String endTime;     // "18:00"
+    private String rewardType;  // 1=红包 2=积分
+    /**
+    * 红包金额
+    */
+    private BigDecimal redPacketAmount;
+
+    /**
+    * 积分
+    */
+    private Long scoreAmount;
+
+}

+ 3 - 2
fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java

@@ -80,8 +80,9 @@ public interface QwWatchLogMapper extends BaseMapper<QwWatchLog>{
             "    COUNT(CASE WHEN qec.`level` = 4 THEN 1 END) AS D,\n" +
             "    COUNT(CASE WHEN qec.`level` = 5 THEN 1 END) AS E,\n" +
             "    COUNT(CASE WHEN qec.fs_user_id IS NOT NULL THEN 1 END) AS sign,\n" +
-            "    COUNT(CASE WHEN qec.`status` =3 THEN 1 END) AS los,\n" +
-            "    COUNT(CASE WHEN qec.`status` IN (4, 5,6) THEN 1 END) AS del,\n" +
+            "    COUNT(CASE WHEN qec.`status` in (3,6) THEN 1 END) AS los,\n" +
+            "    COUNT(CASE WHEN qec.`status` = 4 THEN 1 END) AS del,\n" +
+            "    COUNT(CASE WHEN qec.`status` in (5,7) THEN 1 END) AS black,\n" +
             "    COUNT(CASE WHEN qec.fs_user_id IS NOT NULL and qec.fs_user_id != 0 THEN 1 END) AS reg_num,\n"+
             "    COUNT(CASE WHEN qec.is_repeat = 1 THEN 1 END) AS repeat_count\n" +
             "FROM\n" +

+ 11 - 0
fs-service/src/main/java/com/fs/sop/mapper/QwSopTempRulesMapper.java

@@ -91,9 +91,20 @@ public interface QwSopTempRulesMapper extends BaseMapper<QwSopTempRules> {
             "</script>")
     List<QwSopTempRules> listByCourseIdAndTempId(@Param("courseId") Long courseId,@Param("tempId") String tempId);
 
+    @DataSource(DataSourceType.SOP)
+    @Select("<script>" +
+            "select * from qw_sop_temp_rules  " +
+            " where course_id = #{courseId}" +
+            " and temp_id in " +
+            "<foreach collection='tempIds' item='tempId' open='(' separator=',' close=')'>" +
+            "#{tempId}" +
+            "</foreach>" +
+            "</script>")
+    List<QwSopTempRules> listByCourseIdAndTempIds(@Param("courseId") Long courseId, @Param("tempIds") List<String> tempIds);
 
 
     void deleteByTempId(@Param("id") String id);
+
     void insertBatch(@Param("list") List<QwSopTempRules> list);
 
     List<QwSopTempRules> listByTempId(@Param("id") String id);

+ 2 - 0
fs-service/src/main/java/com/fs/sop/service/IQwSopTempRulesService.java

@@ -96,6 +96,8 @@ public interface IQwSopTempRulesService extends IService<QwSopTempRules>{
 
     List<QwSopTempRules> listByCourseIdAndTempId(Long courseId,String tempId);
 
+    List<QwSopTempRules> listByCourseIdAndTempIds(Long courseId,  List<String> tempIds);
+
     void removeByTempIds(Collection<String> tempIds);
 
     void removeByWrapper(LambdaQueryWrapper<QwSopTempRules> wrapper);

+ 1 - 0
fs-service/src/main/java/com/fs/sop/service/IQwSopTempService.java

@@ -103,6 +103,7 @@ public interface IQwSopTempService {
     List<String> getSelectableRange();
 
     void syncTemplate(Long courseId);
+    void syncTemplateByCompanyId(Long courseId,Long companyId);
 
     /**
      * sop模板update一键开关官方群发

+ 5 - 0
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempRulesServiceImpl.java

@@ -253,6 +253,11 @@ public class QwSopTempRulesServiceImpl extends ServiceImpl<QwSopTempRulesMapper,
         return qwSopTempRulesMapper.listByCourseIdAndTempId(courseId,tempId);
     }
 
+    @Override
+    public List<QwSopTempRules> listByCourseIdAndTempIds(Long courseId,  List<String> tempIds) {
+        return qwSopTempRulesMapper.listByCourseIdAndTempIds(courseId, tempIds);
+    }
+
     @Override
     @DataSource(DataSourceType.SOP)
     public void removeByTempIds(Collection<String> tempIds) {

+ 22 - 67
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempServiceImpl.java

@@ -804,7 +804,28 @@ public class QwSopTempServiceImpl implements IQwSopTempService {
         if (CollectionUtils.isEmpty(rulesList)) {
             return;
         }
+        syncTemplateCommon(rulesList,courseId);
+    }
+
+    @Override
+    public void syncTemplateByCompanyId(Long courseId,Long companyId) {
+
+        // 通过销售id 查询所属的 销售公司的正常 使用的 课程模板
+        QwSopTemp qwSopTemp=new QwSopTemp();
+        qwSopTemp.setCompanyId(companyId);
+        qwSopTemp.setSendType(11);
+        qwSopTemp.setStatus("1");
+        List<QwSopTemp> qwSopTemps = qwSopTempMapper.selectQwSopTempList(qwSopTemp);
+
+        List<String> tempIds = qwSopTemps.stream().map(QwSopTemp::getId).collect(Collectors.toList());
+        List<QwSopTempRules> rulesList = qwSopTempRulesService.listByCourseIdAndTempIds(courseId, tempIds);
 
+        syncTemplateCommon(rulesList,courseId);
+
+
+    }
+
+    public void syncTemplateCommon(List<QwSopTempRules> rulesList,Long courseId) {
         // 获取这些规则关联的模板ID集合
         Set<String> tempIds = rulesList.stream()
                 .map(QwSopTempRules::getTempId)
@@ -824,7 +845,6 @@ public class QwSopTempServiceImpl implements IQwSopTempService {
             qwSopTempContentService.removeByWrapper(new LambdaQueryWrapper<QwSopTempContent>().in(QwSopTempContent::getDayId, dayIdList));
         }
 
-
         tempIds.forEach(teId->{
             QwSopTemp sopTemp = qwSopTempMapper.selectQwSopTempById(teId);
             List<QwSopTempContent> contentList = qwSopTempContentService.listByTempId(teId);
@@ -880,74 +900,9 @@ public class QwSopTempServiceImpl implements IQwSopTempService {
 
             }
         });
-
-//        FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(courseId);
-//        List<FsUserCourseVideo> videoList = fsUserCourseVideoMapper.selectVideoByCourseId(fsUserCourse.getCourseId());
-//        List<QwSopTemp> tempList = qwSopTempMapper.selectListByIds(tempIds);
-//        List<QwSopTempContent> contentList = qwSopTempContentService.listByTempIds(tempIds);
-//        List<QwSopTempDay> dayList = qwSopTempDayService.listByTempIds(new LambdaQueryWrapper<QwSopTempDay>().in(QwSopTempDay::getTempId, tempIds));
-//        List<Long> videoIdList = videoList.stream().map(FsUserCourseVideo::getVideoId).collect(Collectors.toList());
-//        // videoList转Map key 为videoId value 为 courseSort
-//        Map<Long, Long> videoSortMap = videoList.stream().collect(Collectors.toMap(FsUserCourseVideo::getVideoId, FsUserCourseVideo::getCourseSort));
-
-        // 将课程中已删除的视频在规则和日期中删除
-//        Set<Long> dayIdList = rulesList.stream().filter(e -> !videoIdList.contains(e.getVideoId())).map(QwSopTempRules::getDayId).collect(Collectors.toSet());
-//        if (CollectionUtils.isNotEmpty(dayIdList)) {
-//            qwSopTempDayService.removeByWrapper(new LambdaQueryWrapper<QwSopTempDay>().in(QwSopTempDay::getId, dayIdList));
-//            qwSopTempRulesService.removeByWrapper(new LambdaQueryWrapper<QwSopTempRules>().in(QwSopTempRules::getDayId, dayIdList));
-//            qwSopTempContentService.removeByWrapper(new LambdaQueryWrapper<QwSopTempContent>().in(QwSopTempContent::getDayId, dayIdList));
-//        }
-
-        // 需要添加的课程视频
-//        List<FsUserCourseVideo> addVideoList = videoList.stream()
-//                .filter(e -> rulesList.stream().noneMatch(f -> f.getVideoId().equals(e.getVideoId()))).collect(Collectors.toList());
-
-//        if (CollectionUtils.isNotEmpty(addVideoList)) {
-//            for (QwSopTemp temp : tempList) {
-//                // 通过历史中的第一课的数据来构建
-//                Optional<QwSopTempDay> first = dayList.stream().filter(e -> e.getTempId().equals(temp.getId())).findFirst();
-//                if (!first.isPresent()) {
-//                    break;
-//                }
-//                QwSopTempDay qwSopTempDay = first.get();
-//                // 构造timeList timeDesc time
-//                temp.setTime(LocalTime.now());
-//
-//                temp.setTimeList(rulesList.stream()
-//                        .filter(e -> e.getTempId().equals(temp.getId()) && Objects.equals(e.getIsOfficial(), "0")
-//                                && Objects.equals(e.getDayId(), qwSopTempDay.getId())
-//                        ).map(QwSopTempRules::getTime)
-//                        .collect(Collectors.toList()));
-//
-//                temp.setTimeDesc(contentList.stream().filter(e -> e.getTempId().equals(temp.getId())
-//                                && Objects.isNull(e.getIsBindUrl())
-//                                && Objects.equals(qwSopTempDay.getId(), e.getDayId())
-//                        )
-//                        .map(m -> JSONObject.parseObject(m.getContent()).getString("value")).collect(Collectors.toList()));
-//                temp.setProject(fsUserCourse.getProject());
-//                temp.setCourseId(courseId);
-//                temp.setOpenOfficial("1");
-//                qwSopTempMapper.updateQwSopTemp(temp);
-//                createSopTempRules(temp, addVideoList, fsUserCourse);
-//            }
-//        }
-
-//        // 整理排序
-//        List<QwSopTempRules> afterRuleList = qwSopTempRulesService.listByCourseId(courseId);
-//        for (QwSopTemp temp : tempList) {
-//            Long[] dayIdArray = afterRuleList.stream().filter(e -> e.getTempId().equals(temp.getId())).sorted(Comparator.comparing(a -> videoSortMap.get(a.getVideoId())))
-//                    .map(QwSopTempRules::getDayId).distinct().toArray(Long[]::new);
-//            for (int i = 0; i < dayIdArray.length; i++) {
-//                qwSopTempDayService.updateByWrapper(new UpdateWrapper<QwSopTempDay>()
-//                        .eq("id", dayIdArray[i])
-//                        .set("sorts", i + 1)
-//                        .set("name", "第" + (i + 1) + "天")
-//                        .set("day_num", i + 1)
-//                );
-//            }
-//        }
     }
 
+
     /**
      * sop模板update一键开关官方群发
      * @param param

+ 7 - 7
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -1443,7 +1443,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             FSSysConfig sysConfig= JSON.parseObject(js,FSSysConfig.class);
                             //发个人看课记录处理
                             try {
-                                createLiveWatchLogAndInsert(qwUser.getCompanyId().toString(), qwUser.getCompanyUserId().toString(),item.getExternalId().toString(),Long.valueOf(st.getLiveId()),sysConfig.getAppId(),2, qwUserId,param.getCorpId());
+                                createLiveWatchLogAndInsert(qwUser.getCompanyId().toString(), qwUser.getCompanyUserId().toString(),item.getExternalId().toString(),Long.valueOf(st.getLiveId()),sysConfig.getAppId(),3, qwUserId,param.getCorpId());
 
                             } catch (Exception e) {
                                 log.error("群聊创建直播看课记录失败!", e);
@@ -1735,7 +1735,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                         item.getExternalId().toString(),
                                         Long.valueOf(st.getLiveId()),
                                         sysConfig0.getAppId(),
-                                        2,
+                                        3,
                                         String.valueOf(qwUser.getId()),
                                         param.getCorpId());
                             } catch (Exception e) {
@@ -1753,7 +1753,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                         item.getExternalId().toString(),
                                         Long.valueOf(st.getLiveId()),
                                         sysConfigLive.getAppId(),
-                                        2,
+                                        3,
                                         String.valueOf(qwUser.getId()),
                                         param.getCorpId());
                             } catch (Exception e) {
@@ -2410,7 +2410,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     FSSysConfig sysConfig= JSON.parseObject(json,FSSysConfig.class);
                     //todo 发个人看课记录处理
                     try {
-                        createLiveWatchLogAndInsert(qwUser.getCompanyId().toString(), qwUser.getCompanyUserId().toString(),item.getExternalId().toString(),Long.valueOf(st.getLiveId()),sysConfig.getAppId(),2, String.valueOf(qwUser.getId()),param.getCorpId());
+                        createLiveWatchLogAndInsert(qwUser.getCompanyId().toString(), qwUser.getCompanyUserId().toString(),item.getExternalId().toString(),Long.valueOf(st.getLiveId()),sysConfig.getAppId(),3, String.valueOf(qwUser.getId()),param.getCorpId());
                     } catch (Exception e) {
                         log.error("群聊创建直播看课记录失败!", e);
                     }
@@ -2599,7 +2599,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                     sysConfig= JSON.parseObject(json,FSSysConfig.class);
                     //todo 发个人看课记录处理
                     try {
-                        createLiveWatchLogAndInsert(qwUser.getCompanyId().toString(), qwUser.getCompanyUserId().toString(),item.getExternalId().toString(),Long.valueOf(st.getLiveId()),sysConfig.getAppId(),2, String.valueOf(qwUser.getId()),param.getCorpId());
+                        createLiveWatchLogAndInsert(qwUser.getCompanyId().toString(), qwUser.getCompanyUserId().toString(),item.getExternalId().toString(),Long.valueOf(st.getLiveId()),sysConfig.getAppId(),3, String.valueOf(qwUser.getId()),param.getCorpId());
                     } catch (Exception e) {
                         log.error("群聊创建直播看课记录失败!", e);
                     }
@@ -2692,7 +2692,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 item.getExternalId().toString(),
                                 Long.valueOf(st.getLiveId()),
                                 sysConfig0.getAppId(),
-                                2,
+                                3,
                                 String.valueOf(qwUser.getId()),
                                 param.getCorpId());
                     } catch (Exception e) {
@@ -2710,7 +2710,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 item.getExternalId().toString(),
                                 Long.valueOf(st.getLiveId()),
                                 sysConfigLive.getAppId(),
-                                2,
+                                3,
                                 String.valueOf(qwUser.getId()),
                                 param.getCorpId());
                     } catch (Exception e) {

+ 3 - 0
fs-service/src/main/resources/mapper/course/FsCoursePlaySourceConfigMapper.xml

@@ -37,4 +37,7 @@
         where fcpsc.is_del = 0 and fcpsc.appid= #{appid}
        limit 1
     </select>
+    <select id="selectCoursePlaySourceConfigByAppIdGoods" resultType="java.lang.String">
+        SELECT   integral_goods from   fs_course_play_source_config where  appid=#{appId}
+    </select>
 </mapper>

+ 20 - 2
fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java

@@ -11,6 +11,7 @@ import com.fs.app.annotation.UserOperationLog;
 import com.fs.app.controller.AppBaseController;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.core.utils.OrderCodeUtils;
@@ -103,8 +104,13 @@ public class CourseQwController extends AppBaseController {
 
     @Autowired
     private FsDepVideoShowMapper fsDepVideoShowMapper;
+
     @Autowired
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
+
+    @Autowired
+    private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
+
     @Value("${cloud_host.company_name}")
     private String companyName;
 
@@ -387,8 +393,20 @@ public class CourseQwController extends AppBaseController {
     @Login
     @ApiOperation("获取积分奖励信息")
     @GetMapping("/getCourseIntegralGoods")
-    public R getCourseIntegralGoods() {
-        return goodsService.getCourseIntegralGoods(Long.parseLong(getUserId()));
+    public R getCourseIntegralGoods(@RequestHeader(value = "AppId", required = false) String AppId) {
+
+        Long userId = Long.parseLong(getUserId());
+
+        if (AppId == null || AppId.isEmpty()) {
+            return goodsService.getCourseIntegralGoods(userId);
+        }
+
+        String integralGoods = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppIdGoods(AppId);
+        if (!StringUtil.strIsNullOrEmpty(integralGoods)) {
+            return goodsService.getCourseIntegralGoodsByMiniApp(AppId, userId, integralGoods);
+        }
+
+        return goodsService.getCourseIntegralGoods(userId);
     }
 
 

+ 1 - 4
fs-user-app/src/main/java/com/fs/app/controller/store/IndexScrmController.java

@@ -29,10 +29,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import springfox.documentation.annotations.Cacheable;
 
 import javax.servlet.http.HttpServletRequest;