Browse Source

Merge branch 'saas_2022_05_17_activity' of http://git.dayaedu.com/yonge/mec into master_saas

zouxuan 3 years ago
parent
commit
dc09900509
24 changed files with 502 additions and 47 deletions
  1. 4 0
      audio-analysis/src/main/java/com/yonge/netty/server/service/AudioCompareHandler.java
  2. 6 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LiveGoodsDao.java
  3. 3 1
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LiveGoodsMapperDao.java
  4. 2 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/SysMusicCompareRecordDao.java
  5. 11 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/TempBuyFreeLiveTheoryCourseDao.java
  6. 11 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dto/RedisKeyConstant.java
  7. 63 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/TempBuyFreeLiveTheoryCourse.java
  8. 30 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/page/LiveGoodsQueryInfo.java
  9. 34 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomDetailVo.java
  10. 3 4
      mec-biz/src/main/java/com/ym/mec/biz/service/LiveGoodsMapperService.java
  11. 18 0
      mec-biz/src/main/java/com/ym/mec/biz/service/LiveGoodsService.java
  12. 2 0
      mec-biz/src/main/java/com/ym/mec/biz/service/SysMusicCompareRecordService.java
  13. 27 9
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/LiveGoodsMapperServiceImpl.java
  14. 122 2
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/LiveGoodsServiceImpl.java
  15. 50 18
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/MemberRankSettingServiceImpl.java
  16. 5 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/SysMusicCompareRecordServiceImpl.java
  17. 4 1
      mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomDataMapper.xml
  18. 18 3
      mec-biz/src/main/resources/config/mybatis/LiveGoodsMapper.xml
  19. 6 2
      mec-biz/src/main/resources/config/mybatis/LiveGoodsMapperMapper.xml
  20. 4 0
      mec-biz/src/main/resources/config/mybatis/SysMusicCompareRecordMapper.xml
  21. 60 0
      mec-biz/src/main/resources/config/mybatis/TempBuyFreeLiveTheoryCourseMapper.xml
  22. 10 1
      mec-student/src/main/java/com/ym/mec/student/controller/SysMusicCompareRecordController.java
  23. 3 3
      mec-web/src/main/java/com/ym/mec/web/controller/LiveGoodsController.java
  24. 6 2
      mec-web/src/main/java/com/ym/mec/web/controller/LiveGoodsMapperController.java

+ 4 - 0
audio-analysis/src/main/java/com/yonge/netty/server/service/AudioCompareHandler.java

@@ -232,6 +232,10 @@ public class AudioCompareHandler implements MessageHandler {
 					sysMusicCompareRecordService.saveMusicCompareData(sysMusicCompareRecord);
 				}
 				
+				int totalPlayTimeOfCurrentDate = sysMusicCompareRecordService.queryCurrentDatePlayTimeByUserId(sysMusicCompareRecord.getUserId());
+				
+				params.put("totalPlayTimeOfCurrentDate", totalPlayTimeOfCurrentDate);
+				
 				WebSocketResponse<Map<String, Object>> resp = new WebSocketResponse<Map<String, Object>>("overall", params);
 
 				nettyChannelManager.sendTextMessage(user, resp);

+ 6 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LiveGoodsDao.java

@@ -2,8 +2,13 @@ package com.ym.mec.biz.dal.dao;
 
 import com.ym.mec.common.dal.BaseDAO;
 import com.ym.mec.biz.dal.entity.LiveGoods;
+import org.apache.ibatis.annotations.Param;
 
 public interface LiveGoodsDao extends BaseDAO<Integer, LiveGoods> {
 
-	
+    LiveGoods getLock(Integer liveGoodsId);
+
+    int reduceStock(@Param("liveGoodsId") Integer liveGoodsId);
+
+    void addStock(@Param("liveGoodsId") Integer liveGoodsId);
 }

+ 3 - 1
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LiveGoodsMapperDao.java

@@ -19,9 +19,11 @@ public interface LiveGoodsMapperDao extends BaseDAO<Integer, LiveGoodsMapper> {
 
     List<LiveGoodsMapperDto> getLiveGoodsList(@Param("liveId") String liveId, @Param("liveGoodsId") Integer liveGoodsId, @Param("status") Boolean status);
 
-    void batchInsert(@Param("liveGoodsMappers") List<LiveGoodsMapper> liveGoodsMappers);
+    void batchInsert(@Param("liveId") String liveId, @Param("liveGoodsIds") String[] liveGoodsIds);
 
     int countLiveGoods(Map<String, Object> params);
 
     List<LiveGoodsMapperDto> queryGoodsPage(Map<String, Object> params);
+
+    List<Integer> queryGoodsIdsByLiveId(@Param("liveId") String liveId);
 }

+ 2 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/SysMusicCompareRecordDao.java

@@ -99,4 +99,6 @@ public interface SysMusicCompareRecordDao extends BaseDAO<Long, SysMusicCompareR
     Integer getUserWeekMaxMusicScoreId(@Param("userId") Integer userId,
                                        @Param("monday") String monday,
                                         @Param("heardLevel") HeardLevelEnum heardLevel);
+    
+    int queryCurrentDatePlayTimeByUserId(Integer userId);
 }

+ 11 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/TempBuyFreeLiveTheoryCourseDao.java

@@ -0,0 +1,11 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.biz.dal.entity.TempBuyFreeLiveTheoryCourse;
+import org.apache.ibatis.annotations.Param;
+
+public interface TempBuyFreeLiveTheoryCourseDao extends BaseDAO<Integer, TempBuyFreeLiveTheoryCourse> {
+
+
+    int countByUserId(@Param("userId") Integer userId);
+}

+ 11 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/RedisKeyConstant.java

@@ -0,0 +1,11 @@
+package com.ym.mec.biz.dal.dto;
+
+public interface RedisKeyConstant {
+
+    //直播间商品库存缓存key
+    String LIVE_GOODS_STOCK_CACHE_KEY = "live_goods_stock:";
+    //直播间商品冻结库存缓存key
+    String LIVE_GOODS_FROZEN_CACHE_KEY = "live_goods_frozen_stock:";
+    //购买了0元直播课的学员
+    String LIVE_GOODS_ZERO_CACHE_KEY = "live_goods_zero:";
+}

+ 63 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/TempBuyFreeLiveTheoryCourse.java

@@ -0,0 +1,63 @@
+package com.ym.mec.biz.dal.entity;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+/**
+ * 对应数据库表(temp_buy_free_live_theory_course):
+ */
+public class TempBuyFreeLiveTheoryCourse {
+
+	/**  */
+	private Integer id;
+	
+	/**  */
+	private Integer userId;
+	
+	/**  */
+	private java.util.Date createTime;
+	
+	/**  */
+	private java.util.Date updateTime;
+
+	public TempBuyFreeLiveTheoryCourse(Integer userId) {
+		this.userId = userId;
+	}
+
+	public void setId(Integer id){
+		this.id = id;
+	}
+	
+	public Integer getId(){
+		return this.id;
+	}
+			
+	public void setUserId(Integer userId){
+		this.userId = userId;
+	}
+	
+	public Integer getUserId(){
+		return this.userId;
+	}
+			
+	public void setCreateTime(java.util.Date createTime){
+		this.createTime = createTime;
+	}
+	
+	public java.util.Date getCreateTime(){
+		return this.createTime;
+	}
+			
+	public void setUpdateTime(java.util.Date updateTime){
+		this.updateTime = updateTime;
+	}
+	
+	public java.util.Date getUpdateTime(){
+		return this.updateTime;
+	}
+			
+	@Override
+	public String toString() {
+		return ToStringBuilder.reflectionToString(this);
+	}
+
+}

+ 30 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/page/LiveGoodsQueryInfo.java

@@ -0,0 +1,30 @@
+package com.ym.mec.biz.dal.page;
+
+import com.ym.mec.common.page.QueryInfo;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.List;
+
+public class LiveGoodsQueryInfo extends QueryInfo {
+
+    @ApiModelProperty(value = "直播房间号(需要排出当前直播间的商品)",required = false)
+    private String liveId;
+
+    private List<Integer> ignoreGoodsIds;
+
+    public List<Integer> getIgnoreGoodsIds() {
+        return ignoreGoodsIds;
+    }
+
+    public void setIgnoreGoodsIds(List<Integer> ignoreGoodsIds) {
+        this.ignoreGoodsIds = ignoreGoodsIds;
+    }
+
+    public String getLiveId() {
+        return liveId;
+    }
+
+    public void setLiveId(String liveId) {
+        this.liveId = liveId;
+    }
+}

+ 34 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/vo/ImLiveBroadcastRoomDetailVo.java

@@ -4,6 +4,7 @@ import com.ym.mec.biz.dal.entity.ImLiveRoomVideo;
 import io.swagger.annotations.ApiModelProperty;
 
 import java.io.Serializable;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -33,8 +34,41 @@ public class ImLiveBroadcastRoomDetailVo implements Serializable {
     @ApiModelProperty(value = "直播时长")
     private Integer totalLiveTime;
 
+    @ApiModelProperty(value = "直播开始时间")
+    private Date liveStartTime;
+
+    @ApiModelProperty(value = "直播结束时间")
+    private Date liveEndTime;
+
+    @ApiModelProperty(value = "直播状态 0未开始 1开始 2已结束")
+    private Integer liveState;
+
     private List<ImLiveRoomVideo> videoList;
 
+    public Date getLiveStartTime() {
+        return liveStartTime;
+    }
+
+    public void setLiveStartTime(Date liveStartTime) {
+        this.liveStartTime = liveStartTime;
+    }
+
+    public Date getLiveEndTime() {
+        return liveEndTime;
+    }
+
+    public void setLiveEndTime(Date liveEndTime) {
+        this.liveEndTime = liveEndTime;
+    }
+
+    public Integer getLiveState() {
+        return liveState;
+    }
+
+    public void setLiveState(Integer liveState) {
+        this.liveState = liveState;
+    }
+
     public String getRoomUid() {
         return roomUid;
     }

+ 3 - 4
mec-biz/src/main/java/com/ym/mec/biz/service/LiveGoodsMapperService.java

@@ -1,20 +1,17 @@
 package com.ym.mec.biz.service;
 
-import com.ym.mec.biz.dal.dao.LiveGoodsMapperDao;
 import com.ym.mec.biz.dal.dto.LiveGoodsMapperDto;
-import com.ym.mec.biz.dal.entity.LiveGoods;
 import com.ym.mec.biz.dal.entity.LiveGoodsMapper;
 import com.ym.mec.biz.dal.page.LiveGoodsMapperQueryInfo;
 import com.ym.mec.common.page.PageInfo;
 import com.ym.mec.common.service.BaseService;
 
-import java.util.Collection;
 import java.util.List;
 
 public interface LiveGoodsMapperService extends BaseService<Integer, LiveGoodsMapper> {
 
     //新增直播间商品
-    void add(List<LiveGoodsMapper> liveGoodsMappers);
+    void add(String liveId, String liveGoodsIds);
 
     //商品下架
     void downGoods(Integer liveGoodsId);
@@ -31,4 +28,6 @@ public interface LiveGoodsMapperService extends BaseService<Integer, LiveGoodsMa
     PageInfo<LiveGoodsMapperDto> queryGoodsPage(LiveGoodsMapperQueryInfo queryInfo);
 
     List<LiveGoodsMapperDto> getLiveGoodsList(String liveId, Integer liveGoodsId, Boolean status);
+
+    List<Integer> queryGoodsIdsByLiveId(String liveId);
 }

+ 18 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/LiveGoodsService.java

@@ -1,6 +1,7 @@
 package com.ym.mec.biz.service;
 
 import com.ym.mec.biz.dal.entity.LiveGoods;
+import com.ym.mec.biz.dal.page.LiveGoodsQueryInfo;
 import com.ym.mec.common.service.BaseService;
 
 public interface LiveGoodsService extends BaseService<Integer, LiveGoods> {
@@ -8,4 +9,21 @@ public interface LiveGoodsService extends BaseService<Integer, LiveGoods> {
     void updateLiveGoods(LiveGoods liveGoods);
 
     void deleteLiveGoods(Integer goodsId);
+
+    //初始化商品缓存
+    void initGoodsStockCache(Integer liveGoodsId, String liveId);
+
+    //商品库存+1
+    void addGoodsStock(Integer liveGoodsId, String liveId);
+
+    //商品库存-1
+    void reduceGoodsStock(Integer liveGoodsId, String liveId);
+
+    //商品冻结库存+1
+    void addGoodsFreezeStock(Integer liveGoodsId, String liveId);
+
+    //商品冻结库存-1
+    void reduceGoodsFreezeStock(Integer liveGoodsId, String liveId);
+
+    Object queryGoodsPage(LiveGoodsQueryInfo queryInfo);
 }

+ 2 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/SysMusicCompareRecordService.java

@@ -90,4 +90,6 @@ public interface SysMusicCompareRecordService extends BaseService<Long, SysMusic
      * @return
      */
     PageInfo<CountStudentTrainDataDto> countStudentTrain(SysMusicCompareRecordQueryInfo queryInfo);
+    
+    int queryCurrentDatePlayTimeByUserId(Integer userId);
 }

+ 27 - 9
mec-biz/src/main/java/com/ym/mec/biz/service/impl/LiveGoodsMapperServiceImpl.java

@@ -3,12 +3,13 @@ package com.ym.mec.biz.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.ym.mec.biz.dal.dao.LiveGoodsMapperDao;
 import com.ym.mec.biz.dal.dto.LiveGoodsMapperDto;
+import com.ym.mec.biz.dal.dto.RedisKeyConstant;
 import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom;
-import com.ym.mec.biz.dal.entity.LiveGoods;
 import com.ym.mec.biz.dal.entity.LiveGoodsMapper;
 import com.ym.mec.biz.dal.page.LiveGoodsMapperQueryInfo;
 import com.ym.mec.biz.service.ImLiveBroadcastRoomService;
 import com.ym.mec.biz.service.LiveGoodsMapperService;
+import com.ym.mec.biz.service.LiveGoodsService;
 import com.ym.mec.common.dal.BaseDAO;
 import com.ym.mec.common.entity.ImRoomMessage;
 import com.ym.mec.common.exception.BizException;
@@ -16,6 +17,7 @@ import com.ym.mec.common.page.PageInfo;
 import com.ym.mec.common.service.impl.BaseServiceImpl;
 import com.ym.mec.im.ImFeignService;
 import com.ym.mec.util.collection.MapUtil;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -26,11 +28,16 @@ import java.util.*;
 public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoodsMapper>  implements LiveGoodsMapperService {
 	
 	@Autowired
+	private LiveGoodsService liveGoodsService;
+	@Autowired
 	private LiveGoodsMapperDao liveGoodsMapperDao;
 	@Autowired
 	private ImFeignService imFeignService;
 	@Autowired
 	private ImLiveBroadcastRoomService imLiveBroadcastRoomService;
+	@Autowired
+	private RedissonClient redissonClient;
+
 
 	@Override
 	public BaseDAO<Integer, LiveGoodsMapper> getDAO() {
@@ -39,11 +46,8 @@ public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoo
 
     @Override
 	@Transactional(rollbackFor = Exception.class)
-    public void add(List<LiveGoodsMapper> liveGoodsMappers) {
-		liveGoodsMapperDao.batchInsert(liveGoodsMappers);
-//		liveGoodsMapperDao.insert(liveGoodsMapper);
-//		通知上架
-//		if (liveGoodsMapper.getStatus()) this.upGoods(liveGoodsMapper.getGoodsId(),liveGoodsMapper.getLiveId());
+    public void add(String liveId, String liveGoodsIds) {
+		liveGoodsMapperDao.batchInsert(liveId,liveGoodsIds.split(","));
     }
 
 	@Override
@@ -53,8 +57,10 @@ public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoo
 		ImLiveBroadcastRoom imLiveBroadcastRoom = Optional
 				.of(imLiveBroadcastRoomService.getBaseMapper().selectOne(new QueryWrapper<ImLiveBroadcastRoom>().eq("room_uid_",liveId))).
 				orElseThrow(() -> new RuntimeException("直播间不存在"));
-		//通知直播间商品上架
+		//通知直播间商品信息变更
 		this.publishRoomMsg(imLiveBroadcastRoom);
+		//商品上架,更新缓存
+		liveGoodsService.initGoodsStockCache(liveGoodsId,liveId);
 	}
 
 	@Override
@@ -87,6 +93,11 @@ public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoo
 		return liveGoodsMapperDao.getLiveGoodsList(liveId,liveGoodsId,status);
 	}
 
+	@Override
+	public List<Integer> queryGoodsIdsByLiveId(String liveId) {
+		return liveGoodsMapperDao.queryGoodsIdsByLiveId(liveId);
+	}
+
 	private void publishRoomMsg(ImLiveBroadcastRoom imLiveBroadcastRoom) {
 		ImRoomMessage message = new ImRoomMessage();
 		message.setIsIncludeSender(1);
@@ -110,8 +121,15 @@ public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoo
 		}
 		//下架直播间商品
 		liveGoodsMapperDao.updateStatus(liveId,liveGoodsId,false);
-		//通知直播间,商品下架
+		//通知直播间,商品信息变更
 		this.publishRoomMsg(imLiveBroadcastRoom);
+		//商品下架后,将缓存的库存设置为0
+		redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_STOCK_CACHE_KEY + liveId + liveGoodsId).set(0);
+		//如果下架的是免费的直播课商品,清空购买的学员的缓存记录
+		if(liveGoodsId.equals(2)){
+			//删除当前直播间免费直播课的购买记录缓存
+			redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_ZERO_CACHE_KEY + liveId).delete();
+		}
 	}
 
 	@Override
@@ -121,7 +139,7 @@ public class LiveGoodsMapperServiceImpl extends BaseServiceImpl<Integer, LiveGoo
 		if(liveGoodsMappers.size()>0){
 			//下架直播间商品
 			liveGoodsMapperDao.updateStatus(null,liveGoodsId,false);
-			//通知直播间,商品下架
+			//通知直播间,商品信息变更
 			for (LiveGoodsMapper liveGoodsMapper : liveGoodsMappers) {
 				ImLiveBroadcastRoom imLiveBroadcastRoom = Optional
 						.of(imLiveBroadcastRoomService.getBaseMapper().selectOne(new QueryWrapper<ImLiveBroadcastRoom>().eq("room_uid_",liveGoodsMapper.getLiveId()))).

+ 122 - 2
mec-biz/src/main/java/com/ym/mec/biz/service/impl/LiveGoodsServiceImpl.java

@@ -1,16 +1,26 @@
 package com.ym.mec.biz.service.impl;
 
 import com.ym.mec.biz.dal.dao.LiveGoodsDao;
+import com.ym.mec.biz.dal.dto.RedisKeyConstant;
 import com.ym.mec.biz.dal.entity.LiveGoods;
+import com.ym.mec.biz.dal.page.LiveGoodsQueryInfo;
 import com.ym.mec.biz.service.LiveGoodsMapperService;
 import com.ym.mec.biz.service.LiveGoodsService;
 import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.common.exception.BizException;
 import com.ym.mec.common.service.impl.BaseServiceImpl;
+import org.apache.commons.lang3.StringUtils;
+import org.redisson.api.RBucket;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.List;
 import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
 
 @Service
 public class LiveGoodsServiceImpl extends BaseServiceImpl<Integer, LiveGoods>  implements LiveGoodsService {
@@ -19,6 +29,8 @@ public class LiveGoodsServiceImpl extends BaseServiceImpl<Integer, LiveGoods>  i
 	private LiveGoodsDao liveGoodsDao;
 	@Autowired
 	private LiveGoodsMapperService liveGoodsMapperService;
+	@Autowired
+	private RedissonClient redissonClient;
 
 	@Override
 	public BaseDAO<Integer, LiveGoods> getDAO() {
@@ -29,12 +41,16 @@ public class LiveGoodsServiceImpl extends BaseServiceImpl<Integer, LiveGoods>  i
 	@Transactional(rollbackFor = Exception.class)
     public void updateLiveGoods(LiveGoods liveGoods) {
 		Optional.of(liveGoodsDao.get(liveGoods.getId())).orElseThrow(() -> new RuntimeException("商品信息不存在"));
+		//如果商品已在直播间上架,那么不允许变更商品信息
+		if (liveGoodsMapperService.findByLiveGoodsIdAndStatus(liveGoods.getId(),true).size() > 0) {
+			throw new BizException("商品已在直播间上架,不能修改");
+		}
 		//下架直播间商品,并通知直播间
 //		if (!liveGoods.getStatus()) liveGoodsMapperService.downGoods(liveGoods.getId());
 		//更新商品信息
 		liveGoodsDao.update(liveGoods);
 		//通知直播间
-		liveGoodsMapperService.downGoods(liveGoods.getId());
+//		liveGoodsMapperService.downGoods(liveGoods.getId());
 	}
 
 	@Override
@@ -42,8 +58,112 @@ public class LiveGoodsServiceImpl extends BaseServiceImpl<Integer, LiveGoods>  i
 	public void deleteLiveGoods(Integer goodsId) {
 		//如果商品没有被直播间使用,则删除商品
 		if (liveGoodsMapperService.findByLiveGoodsIdAndStatus(goodsId,null).size() > 0) {
-			throw new RuntimeException("商品已被直播间使用,不能删除");
+			throw new BizException("商品已被直播间使用,不能删除");
 		}
 		liveGoodsDao.delete(goodsId);
 	}
+
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void initGoodsStockCache(Integer liveGoodsId, String liveId) {
+		//更新缓存
+		LiveGoods liveGoods = liveGoodsDao.getLock(liveGoodsId);
+		if (liveGoods == null) throw new BizException("商品不存在");
+		redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_STOCK_CACHE_KEY + liveId + liveGoodsId).set(liveGoods.getStockCount(),1, TimeUnit.DAYS);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void addGoodsStock(Integer liveGoodsId, String liveId) {
+		liveGoodsDao.addStock(liveGoodsId);
+//		RBucket<Integer> bucket = redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_STOCK_CACHE_KEY + liveId + liveGoodsId);
+//		boolean exists = bucket.isExists();
+//		if (exists) {
+//			Integer frozenStock = bucket.get();
+//			bucket.set(++frozenStock);
+//		}else {
+//			bucket.set(1);
+//		}
+	}
+
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public void reduceGoodsStock(Integer liveGoodsId, String liveId) {
+		int i = liveGoodsDao.reduceStock(liveGoodsId);
+		if (i == 0) throw new BizException("商品库存不足");
+//		RBucket<Integer> bucket = redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_STOCK_CACHE_KEY + liveId + liveGoodsId);
+//		boolean exists = bucket.isExists();
+//		if (exists) {
+//			Integer stock = bucket.get() - 1;
+//			if (stock < 0) {
+//				throw new BizException("哎呀,手慢了,商品已经卖完了");
+//			}else if(stock == 0){
+//				//如果库存为0,则定时删除缓存
+//				bucket.set(stock,1,TimeUnit.HOURS);
+//			}else {
+//				bucket.set(stock);
+//			}
+//		}else {
+//			LiveGoods liveGoods = liveGoodsDao.getLock(liveGoodsId);
+//			redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_STOCK_CACHE_KEY + liveId + liveGoodsId).set(liveGoods.getStockCount(),1, TimeUnit.DAYS);
+//		}
+//		//增加冻结库存
+//		this.addGoodsFreezeStock(liveGoodsId,liveId);
+	}
+
+	@Override
+	public void addGoodsFreezeStock(Integer liveGoodsId, String liveId) {
+		RBucket<Integer> bucket = redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_FROZEN_CACHE_KEY + liveId + liveGoodsId);
+		boolean exists = bucket.isExists();
+		if (exists) {
+			Integer frozenStock = bucket.get();
+			bucket.set(++frozenStock);
+		}else {
+			bucket.set(1);
+		}
+	}
+
+	@Override
+	public void reduceGoodsFreezeStock(Integer liveGoodsId, String liveId) {
+		RBucket<Integer> bucket = redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_FROZEN_CACHE_KEY + liveId + liveGoodsId);
+		boolean exists = bucket.isExists();
+		if (exists) {
+			Integer frozenStock = bucket.get() - 1;
+			if (frozenStock < 0) {
+				throw new BizException("订单库存扣减失败");
+			}else if(frozenStock == 0){
+				//如果冻结库存为0,则定时删除缓存
+				bucket.set(frozenStock,1,TimeUnit.HOURS);
+			}else {
+				bucket.set(frozenStock);
+			}
+		}else {
+			throw new BizException("订单库存扣减失败");
+		}
+	}
+
+	@Override
+	public Object queryGoodsPage(LiveGoodsQueryInfo queryInfo) {
+		if(StringUtils.isNotEmpty(queryInfo.getLiveId())){
+			//获取直播间关联的商品列表
+			List<Integer> goodsIds = liveGoodsMapperService.queryGoodsIdsByLiveId(queryInfo.getLiveId());
+			queryInfo.setIgnoreGoodsIds(goodsIds);
+		}
+		return queryPage(queryInfo);
+	}
+
+	public void stockLock(String lockKey, BiConsumer<Integer,String> consumer, Integer liveGoodsId, String liveId) {
+		RLock lock = redissonClient.getLock(lockKey);
+		try{
+			lock.lock();
+			consumer.accept(liveGoodsId,liveId);
+		}catch(Exception e){
+			e.printStackTrace();
+		}finally {
+			lock.unlock();
+		}
+
+	}
+
 }

+ 50 - 18
mec-biz/src/main/java/com/ym/mec/biz/service/impl/MemberRankSettingServiceImpl.java

@@ -6,6 +6,7 @@ import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dao.*;
 import com.ym.mec.biz.dal.dto.Cloud2022ActivityDto;
 import com.ym.mec.biz.dal.dto.MemberPayParamDto;
+import com.ym.mec.biz.dal.dto.RedisKeyConstant;
 import com.ym.mec.biz.dal.entity.*;
 import com.ym.mec.biz.dal.enums.*;
 import com.ym.mec.biz.service.*;
@@ -84,6 +85,10 @@ public class MemberRankSettingServiceImpl extends BaseServiceImpl<Integer, Membe
     private MemberFeeSettingService memberFeeSettingService;
     @Autowired
     private TeacherDao teacherDao;
+    @Autowired
+    private LiveGoodsService liveGoodsService;
+    @Autowired
+    private TempBuyFreeLiveTheoryCourseDao tempBuyFreeLiveTheoryCourseDao;
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
@@ -228,22 +233,6 @@ public class MemberRankSettingServiceImpl extends BaseServiceImpl<Integer, Membe
     @Transactional(rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED)
     public HttpResponseResult activeBuy(MemberPayParamDto memberPayParamDto) throws Exception {
         SysUser sysUser = Optional.of(sysUserFeignService.queryUserInfo()).orElseThrow(()-> new BizException("请登录"));
-        String activeConfig = sysConfigDao.findConfigValue("cloud_teacher_active_config");
-        List<Cloud2022ActivityDto> cloud2022ActivityDtos = JSONArray.parseArray(activeConfig, Cloud2022ActivityDto.class);
-        Cloud2022ActivityDto activityDto = cloud2022ActivityDtos.stream().filter(e -> e.getOrganId().contains(sysUser.getOrganId().toString())).findFirst().get();
-        if(Objects.isNull(activityDto)){
-            throw new BizException("当前分部暂未开通活动");
-        }
-        //是否还有购买资格
-        Integer activityId = Integer.parseInt(activityDto.getActivityId());
-        VipGroupActivity vipGroupActivity = Optional.of(vipGroupActivityDao.get(activityId)).orElseThrow(()-> new BizException("活动不存在"));
-        if(vipGroupActivity.getStudentMaxUsedTimes() != -1){
-            //获取活动购买次数
-            int activityBuyNum = activityUserMapperDao.countActivityBuyNum(vipGroupActivity.getId(),sysUser.getId());
-            if(activityBuyNum >= vipGroupActivity.getStudentMaxUsedTimes()){
-                throw new BizException("您已达到购买次数上限");
-            }
-        }
         //判断用户是否已存在订单
         List<StudentPaymentOrder> memberIngOrders = studentPaymentOrderService.queryByCondition(GroupType.ACTIVITY,null,sysUser.getId(), DealStatusEnum.ING,OrderTypeEnum.MEMBER);
         if (CollectionUtils.isNotEmpty(memberIngOrders)) {
@@ -252,13 +241,56 @@ public class MemberRankSettingServiceImpl extends BaseServiceImpl<Integer, Membe
                 return result;
             }
         }
+        //判断当前商品是否可以购买(库存、上架状态、是否购买过)
+        //如果是云教练商品,那么只能购买一次、如果是免费直播课,那么每次上架只能买一次,总共只能买2次
+        if(memberPayParamDto.getLiveGoodsId() == 1){
+            String activeConfig = sysConfigDao.findConfigValue("cloud_teacher_active_config");
+            List<Cloud2022ActivityDto> cloud2022ActivityDtos = JSONArray.parseArray(activeConfig, Cloud2022ActivityDto.class);
+            Cloud2022ActivityDto activityDto = cloud2022ActivityDtos.stream().filter(e -> e.getOrganId().contains(sysUser.getOrganId().toString())).findFirst().get();
+            if(Objects.isNull(activityDto)){
+                throw new BizException("当前分部暂未开通活动");
+            }
+            //是否还有购买资格
+            Integer activityId = Integer.parseInt(activityDto.getActivityId());
+            VipGroupActivity vipGroupActivity = Optional.of(vipGroupActivityDao.get(activityId)).orElseThrow(()-> new BizException("活动不存在"));
+            if(vipGroupActivity.getStudentMaxUsedTimes() != -1){
+                //获取活动购买次数
+                int activityBuyNum = activityUserMapperDao.countActivityBuyNum(vipGroupActivity.getId(),sysUser.getId());
+                if(activityBuyNum >= vipGroupActivity.getStudentMaxUsedTimes()){
+                    throw new BizException("您已达到购买次数上限");
+                }
+            }
+            //扣减库存
+            liveGoodsService.reduceGoodsStock(memberPayParamDto.getLiveGoodsId(),memberPayParamDto.getLiveId());
+        } else if (memberPayParamDto.getLiveGoodsId() == 2){
+            RBucket<List<Integer>> bucket = redissonClient.getBucket(RedisKeyConstant.LIVE_GOODS_ZERO_CACHE_KEY + memberPayParamDto.getLiveId());
+            List<Integer> list = bucket.get();
+            //当前用户是否购买过免费直播课
+            if(list.contains(sysUser.getId())){
+                throw new BizException("您已购买过本轮免费直播课");
+            }
+            //购买次数是否超过2次
+            int count = tempBuyFreeLiveTheoryCourseDao.countByUserId(sysUser.getId());
+            if(count >= 2){
+                throw new BizException("免费直播课已达到购买次数上限");
+            }
+            //扣减库存
+            liveGoodsService.reduceGoodsStock(memberPayParamDto.getLiveGoodsId(),memberPayParamDto.getLiveId());
+            list.add(sysUser.getId());
+            bucket.set(list);
+            //保存购买记录
+            tempBuyFreeLiveTheoryCourseDao.insert(new TempBuyFreeLiveTheoryCourse(sysUser.getId()));
+            return BaseController.succeed();
+        }else {
+            throw new BizException("当前商品不可购买");
+        }
         //优惠券使用范围
         String[] checkCoupon = CouponDetailTypeEnum.getAllowType(MEMBER);
         //校验优惠券
-        StudentPaymentOrder studentPaymentOrder = sysCouponCodeService.use(memberPayParamDto.getCouponIdList(), vipGroupActivity.getMarketPrice(), true, checkCoupon);
+        StudentPaymentOrder studentPaymentOrder = sysCouponCodeService.use(memberPayParamDto.getCouponIdList(),BigDecimal.ZERO, true, checkCoupon);
         studentPaymentOrder.setUserId(sysUser.getId());
         studentPaymentOrder.setOrganId(sysUser.getOrganId());
-        studentPaymentOrder.setMemo("小小训练营活动购买");
+        studentPaymentOrder.setMemo("小小训练营云教练购买");
         studentPaymentOrder.setGroupType(GroupType.ACTIVITY);
         Map<String, Object> result = getMap(memberPayParamDto.getAmount(), memberPayParamDto.getUseBalancePayment(),studentPaymentOrder);
         return BaseController.succeed(result);

+ 5 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/SysMusicCompareRecordServiceImpl.java

@@ -452,4 +452,9 @@ public class SysMusicCompareRecordServiceImpl extends BaseServiceImpl<Long, SysM
 		pageInfo.setRows(dataList);
 		return pageInfo;
     }
+
+	@Override
+	public int queryCurrentDatePlayTimeByUserId(Integer userId) {
+		return sysMusicCompareRecordDao.queryCurrentDatePlayTimeByUserId(userId);
+	}
 }

+ 4 - 1
mec-biz/src/main/resources/config/mybatis/ImLiveBroadcastRoomDataMapper.xml

@@ -35,7 +35,10 @@
                r.live_remark_              AS liveRemark,
                ifnull(a.total_user_num_, 0) AS totalLookNum,
                ifnull(a.like_num_, 0)      as totalLikeNum,
-               ifnull(a.live_time_, 0)     as totalLiveTime
+               ifnull(a.live_time_, 0)     as totalLiveTime,
+               r.live_start_time_      as liveStartTime,
+               r.live_end_time_      as liveEndTime,
+               r.live_state_      as liveState
         from im_live_broadcast_room_data as a
                  left join im_live_broadcast_room AS r on a.room_uid_ = r.room_uid_
                  left join sys_user AS b on r.speaker_id_ = b.id_

+ 18 - 3
mec-biz/src/main/resources/config/mybatis/LiveGoodsMapper.xml

@@ -40,7 +40,10 @@
 		VALUES(#{name},#{image},#{stockCount},#{sellCount},#{currentPrice},
 		       #{originalPrice},#{goodsDetailUrl},#{desc},NOW(),NOW(),#{tenantId})
 	</insert>
-	
+	<insert id="addStock">
+		UPDATE live_goods SET stock_count_ = stock_count_ + 1 WHERE id_ = #{liveGoodsId}
+	</insert>
+
 	<!-- 根据主键查询一条记录 -->
 	<update id="update" parameterType="com.ym.mec.biz.dal.entity.LiveGoods">
 		UPDATE live_goods <set>
@@ -74,7 +77,10 @@
 		update_time_ = NOW()
 	</set> WHERE id_ = #{id}
 	</update>
-	
+	<update id="reduceStock">
+		UPDATE live_goods SET stock_count_ = stock_count_ - 1 WHERE id_ = #{liveGoodsId} AND stock_count_ > 0
+	</update>
+
 	<!-- 根据主键删除一条记录 -->
 	<delete id="delete" >
 		DELETE FROM live_goods WHERE id_ = #{id} 
@@ -82,7 +88,13 @@
 	<sql id="queryPageSql">
 		<where>
 			<if test="search != null and search != ''">
-				(name_ like '%${search}%' OR id_ = #{search})
+				AND (name_ like '%${search}%' OR id_ = #{search})
+			</if>
+			<if test="ignoreGoodsIds != null and ignoreGoodsIds.size > 0">
+				AND id_ NOT IN
+				<foreach collection="ignoreGoodsIds" item="ignoreGoodsId" open="(" separator="," close=")">
+					#{ignoreGoodsId}
+				</foreach>
 			</if>
 		</where>
 	</sql>
@@ -100,4 +112,7 @@
 		SELECT COUNT(*) FROM live_goods
 		<include refid="queryPageSql" />
 	</select>
+	<select id="getLock" resultMap="LiveGoods">
+		SELECT * FROM live_goods WHERE id_ = #{id} FOR UPDATE LIMIT 1
+	</select>
 </mapper>

+ 6 - 2
mec-biz/src/main/resources/config/mybatis/LiveGoodsMapperMapper.xml

@@ -34,8 +34,8 @@
 	<insert id="batchInsert">
 		INSERT INTO live_goods_mapper (goods_id_,live_id_,create_time_,update_time_)
 		VALUES
-		<foreach collection="liveGoodsMappers" item="item" index="index" separator=",">
-			(#{item.goodsId},#{item.liveId},NOW(),NOW())
+		<foreach collection="liveGoodsIds" item="goodsId" index="index" separator=",">
+			(#{goodsId},#{liveId},NOW(),NOW())
 		</foreach>
 		ON DUPLICATE KEY UPDATE
 		goods_id_ = VALUES(goods_id_),
@@ -154,4 +154,8 @@
 		ORDER BY lgm.id_
 		<include refid="global.limit"/>
 	</select>
+	<select id="queryGoodsIdsByLiveId" resultType="java.lang.Integer">
+		SELECT DISTINCT lgm.goods_id_ FROM live_goods_mapper lgm
+		WHERE lgm.live_id_ = #{liveId}
+	</select>
 </mapper>

+ 4 - 0
mec-biz/src/main/resources/config/mybatis/SysMusicCompareRecordMapper.xml

@@ -429,4 +429,8 @@
 		WHERE user_id_=#{userId} AND monday_ = #{monday} AND heard_level_ = #{heardLevel, typeHandler=com.ym.mec.common.dal.CustomEnumTypeHandler}
 		ORDER BY score_ DESC LIMIT 1
 	</select>
+
+	<select id="queryCurrentDatePlayTimeByUserId" resultType="int">
+		SELECT sum(ifnull(cr.`play_time_`,0))  FROM `sys_music_compare_record` cr WHERE date(cr.`create_time_`) = CURDATE() AND cr.`user_id_` = #{userId}
+	</select>
 </mapper>

+ 60 - 0
mec-biz/src/main/resources/config/mybatis/TempBuyFreeLiveTheoryCourseMapper.xml

@@ -0,0 +1,60 @@
+<?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.ym.mec.biz.dal.dao.TempBuyFreeLiveTheoryCourseDao">
+	
+	<resultMap type="com.ym.mec.biz.dal.entity.TempBuyFreeLiveTheoryCourse" id="TempBuyFreeLiveTheoryCourse">
+		<result column="id_" property="id" />
+		<result column="user_id_" property="userId" />
+		<result column="create_time_" property="createTime" />
+		<result column="update_time_" property="updateTime" />
+	</resultMap>
+	
+	<!-- 根据主键查询一条记录 -->
+	<select id="get" resultMap="TempBuyFreeLiveTheoryCourse" >
+		SELECT * FROM temp_buy_free_live_theory_course WHERE id_ = #{id} 
+	</select>
+	
+	<!-- 全查询 -->
+	<select id="findAll" resultMap="TempBuyFreeLiveTheoryCourse">
+		SELECT * FROM temp_buy_free_live_theory_course ORDER BY id_
+	</select>
+	
+	<!-- 向数据库增加一条记录 -->
+	<insert id="insert" parameterType="com.ym.mec.biz.dal.entity.TempBuyFreeLiveTheoryCourse" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
+		INSERT INTO temp_buy_free_live_theory_course (user_id_,create_time_,update_time_) VALUES(#{userId},NOW(),NOW())
+	</insert>
+	
+	<!-- 根据主键查询一条记录 -->
+	<update id="update" parameterType="com.ym.mec.biz.dal.entity.TempBuyFreeLiveTheoryCourse">
+		UPDATE temp_buy_free_live_theory_course <set>
+		<if test="userId != null">
+		user_id_ = #{userId},
+		</if>
+		<if test="updateTime != null">
+		update_time_ = #{updateTime},
+		</if>
+		</set> WHERE id_ = #{id}
+	</update>
+	
+	<!-- 根据主键删除一条记录 -->
+	<delete id="delete" >
+		DELETE FROM temp_buy_free_live_theory_course WHERE id_ = #{id} 
+	</delete>
+	
+	<!-- 分页查询 -->
+	<select id="queryPage" resultMap="TempBuyFreeLiveTheoryCourse" parameterType="map">
+		SELECT * FROM temp_buy_free_live_theory_course ORDER BY id_ <include refid="global.limit"/>
+	</select>
+	
+	<!-- 查询当前表的总记录数 -->
+	<select id="queryCount" resultType="int">
+		SELECT COUNT(*) FROM temp_buy_free_live_theory_course
+	</select>
+	<select id="countByUserId" resultType="java.lang.Integer">
+		SELECT COUNT(user_id_) FROM temp_buy_free_live_theory_course WHERE user_id_ = #{userId}
+	</select>
+</mapper>

+ 10 - 1
mec-student/src/main/java/com/ym/mec/student/controller/SysMusicCompareRecordController.java

@@ -8,9 +8,12 @@ import com.ym.mec.biz.service.SysMusicCompareRecordService;
 import com.ym.mec.common.controller.BaseController;
 import com.ym.mec.common.entity.HttpResponseResult;
 import com.ym.mec.common.exception.BizException;
+
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ui.ModelMap;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -45,7 +48,13 @@ public class SysMusicCompareRecordController extends BaseController {
         }
         record.setUserId(sysUser.getId());
         record.setClientId("student");
-        return succeed(sysMusicCompareRecordService.insert(record));
+        
+        sysMusicCompareRecordService.insert(record);
+        
+        ModelMap model = new ModelMap();
+        model.put("totalPlayTimeOfCurrentDate", sysMusicCompareRecordService.queryCurrentDatePlayTimeByUserId(sysUser.getId()));
+        
+        return succeed(model);
     }
 
     @ApiOperation(value = "用户最后一次评测数据")

+ 3 - 3
mec-web/src/main/java/com/ym/mec/web/controller/LiveGoodsController.java

@@ -1,10 +1,10 @@
 package com.ym.mec.web.controller;
 
 import com.ym.mec.biz.dal.entity.LiveGoods;
+import com.ym.mec.biz.dal.page.LiveGoodsQueryInfo;
 import com.ym.mec.biz.service.LiveGoodsService;
 import com.ym.mec.common.controller.BaseController;
 import com.ym.mec.common.entity.HttpResponseResult;
-import com.ym.mec.common.page.QueryInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,8 +29,8 @@ public class LiveGoodsController extends BaseController {
     @ApiOperation("分页查询直播间商品")
     @PostMapping(value = "/page")
     @PreAuthorize("@pcs.hasPermissions('liveGoods/page')")
-    public HttpResponseResult page(QueryInfo queryInfo) {
-        return succeed(liveGoodsService.queryPage(queryInfo));
+    public HttpResponseResult page(LiveGoodsQueryInfo queryInfo) {
+        return succeed(liveGoodsService.queryGoodsPage(queryInfo));
     }
 
     @ApiOperation("新增直播间商品")

+ 6 - 2
mec-web/src/main/java/com/ym/mec/web/controller/LiveGoodsMapperController.java

@@ -38,8 +38,12 @@ public class LiveGoodsMapperController extends BaseController {
     @ApiOperation("新增直播间商品关联")
     @PostMapping("/add")
     @PreAuthorize("@pcs.hasPermissions('liveGoodsMapper/add')")
-    public HttpResponseResult add(@RequestBody List<LiveGoodsMapper> liveGoodsMappers) {
-        liveGoodsMapperService.add(liveGoodsMappers);
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "liveGoodsIds", value = "商品编号列表", required = true, dataType = "String"),
+            @ApiImplicitParam(name = "liveId", value = "房间号", required = true,dataType = "String")
+    })
+    public HttpResponseResult add(String liveId, String liveGoodsIds) {
+        liveGoodsMapperService.add(liveId,liveGoodsIds);
         return succeed();
     }